commit 24c704c667ca06ccf9182bbf68bf507976e6c3dc Author: ETWen Date: Mon Aug 17 08:52:11 2026 +0800 docs(arch): Add ARCHITECTURE.md and CLAUDE.md, init repo Bring the Blanton Tera Term TTL test suite under version control and document how the pieces fit together. - ARCHITECTURE.md: A/B/C script roles, host-to-DUT-to-FPGA data path, config/settings/profile data models, PCIe AER + EDAC topology table, 10 key constraints, and 6 development phases derived from the Status_20260814 spreadsheet's On-Going items - CLAUDE.md: stack, smoke-test commands, conventions, and the hardware footguns (per-unit BDF, VSPI vs VI2C timing, repeated START, STORE_USER_ALL, ARB_LOST false positives) - secret/: gitignored credential store with README + .example template, so the DUT login stops living in 1_Blanton_Script_A.ttl - .gitignore: secret/*, For_AI/, *.log, publish/, *.DSN Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014RetWKFZFG1ZHcitQAyhwM diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8af875b --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# secret/ 全部忽略,但保留 README 與範本 +secret/* +!secret/README.md +!secret/*.example +!secret/.gitkeep + +# AI 協作素材不入 git +For_AI/ + +# 測試 log(含 DUT 序號 / MAC / 韌體版本,保留目錄結構即可) +*.log +!**/logs/.gitkeep +!**/Logs/.gitkeep + +# 打包輸出 +publish/* +!publish/.gitkeep + +# Office 暫存檔 +~$* + +# 客戶板 schematic 原始檔(機密,勿入 repo) +*.DSN +*.dsn diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..28864a6 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,548 @@ +# ARCHITECTURE — Blanton TTL Script + +## Overview + +**Blanton_TTL_Script** 是 Blanton(Project Helios)交換器平台的**系統層可靠性測試自動化腳本組**。 +測試工程師在 Windows 端用 **Tera Term (TTL macro)** 透過 COM port 連上 DUT 的 SONiC console, +由 A / B / C 三支腳本依序驅動一整輪 stress + margin + error-counter 測試,全程自動存 log。 + +三支腳本的分工就是一輪測試的三個階段: + +| Script | 階段 | 做什麼 | +|--------|------|--------| +| `1_Blanton_Script_A.ttl` | **Pre-test / Baseline** | 登入、對時、載入 shell 工具、清 PCIe AER、抓 PCIe tree / margin / PMON / dmesg 基線 | +| `2_Blanton_Script_B.ttl` | **Stress / Soak** | 開 CPU / DDR / SSD / USB / PCIe / I2C 壓力程序,之後進無限迴圈每輪抓 fan / temp / margin | +| `3_Blanton_Script_C.ttl` | **Post-test / Verdict** | 殺掉壓力程序、再抓一次 PMON / dmesg / PCIe AER,比對 stress log 判定 | + +DUT 端的實際取數能力則來自一組 **bash 工具庫**(`Blanton_Script/`),這一層才是真正碰硬體的地方: +CB FPGA 的 PCIe BAR(`pcimem`)→ FPGA 內建 I2C / VI2C master → 板上 VRM、溫度感測器、 +LTC2980 margin 控制器。TTL 只負責「按順序 `sendln` 並把畫面收進 log」,硬體語意全在 bash 這層。 + +**使用者**:硬體 / 系統驗證工程師(ETWen、KC、Alan)。 +**核心價值**:把一輪要跑數小時、跨 PCIe / DDR / I2C / 電源多個子系統的 reliability run, +壓縮成「開 Tera Term → 跑 A → 跑 B 泡著 → 跑 C 收工」三個動作,且每一筆數據都有 log 可回溯。 + +--- + +## Tech Stack + +| Layer | Technology | +|-------|-----------| +| 測試控制端(Host) | Tera Term 5.x **TTL macro**(`.ttl`),Windows | +| Host ↔ DUT 通道 | RS-232 / USB-Serial COM port(SONiC console) | +| DUT OS | SONiC(Debian-based network OS),bash + busybox/mawk | +| DUT 端工具語言 | Bash Shell Script | +| 暫存器存取後端 | `pcimem`(mmap PCI sysfs `resource0` + BAR 相對 offset) | +| I2C / PMBus 路徑 | CB FPGA F3 OpenCores I2C master、CB FPGA F3 VI2C proxy、CPU 原生 bus(`i2cset`/`i2cget`) | +| 電源 margin | LTC2980(= 2 × LTC2977)over PMBus,LINEAR16 編碼 | +| 錯誤計數來源 | Linux PCIe AER sysfs(`aer_dev_*`)、EDAC sysfs(`dimm_ce/ue_count`) | +| 平台監控 | SONiC `show platform *`(pmon container) | +| 壓力測試 | `mlucas-avx2`(AMD CPU)、`~/hammer/tools/stress_*.py`(DDR / SSD / USB / PCIe / I2C) | +| 版本控制 | Git(NAS + Gitea 私有 remote;**不推 GitHub,含客戶 NDA 資料**) | + +> ⚠️ **無編譯步驟。** TTL 與 bash 都是直譯執行,「build」等同「把 `src/Script_ABC_Blanton/` 複製到 +> Tera Term 工作目錄,並把 `Blanton_Script/` scp 到 DUT 的 `~/`」。 + +--- + +## Architecture Diagram + +``` +┌──────────────────────────────────────────────────────────────┐ +│ Windows Host — Tera Term 5.x │ +│ │ +│ 1_Blanton_Script_A.ttl ──┐ │ +│ 2_Blanton_Script_B.ttl ──┼─→ include "config.ttl" │ +│ 3_Blanton_Script_C.ttl ──┘ (prompt / EN_* 旗標) │ +│ │ │ +│ └─→ include "utils/*.ttl" (可重用取數片段) │ +│ │ +│ logopen → Logs/Blanton_Margin_.log (整段 console 存檔) │ +└───────────────────────┬──────────────────────────────────────┘ + │ COM port:sendln "" / wait "" + ▼ +┌──────────────────────────────────────────────────────────────┐ +│ DUT — SONiC console (root@sonic:~#) │ +│ │ +│ ~/Blanton_Script/ (source 進 shell 後成為一組函數) │ +│ ├ blanton_fpga_pcimem.sh cb_fpga / pmc_fpga / swb0_fpga │ +│ ├ blanton_cb_i2c.sh cb_i2c_* / cb_pmbus_* │ +│ ├ blanton_icb_vi2c.sh vi2c_* (ICB/PDB proxy) │ +│ ├ blanton_temp_sensor.sh temp_cb / temp_icb / temp_all │ +│ ├ blanton_pwr_data.sh pwr_data / pwr_data_pdb │ +│ └ LTC2980_Margin_Script/ margin_init / margin_status ... │ +│ │ +│ ~/hammer/tools/ 壓力程序(mlucas-avx2, stress_*.py) │ +│ SONiC CLI show platform fan/temperature/... │ +│ Linux sysfs aer_dev_* / edac mc0/rank* │ +└───────────────────────┬──────────────────────────────────────┘ + │ pcimem /sys/bus/pci/devices/0000:03:00./resource0 + ▼ +┌──────────────────────────────────────────────────────────────┐ +│ CB FPGA (PCIe EP,4 個 Function) │ +│ F0 local regs:RST_CAUSE_REG 0xD90 / SWB 0xD94,0xD98 │ +│ F3 I2C master Ch0..Ch17 (base 0x300, stride 0x20) │ +│ F3 VI2C→ICB Ch0..Ch4 (base 0x780, stride 0x20) │ +│ F2 VSPI 橋接 PMC/ICB/SWB(慢,~18ms/reg,本專案不走) │ +└───────────────────────┬──────────────────────────────────────┘ + │ I2C / PMBus + ▼ + TCA9546/9543 mux · MP29816/MP2985B VRM · TMP75/TMP432 溫感 + MAX31790 風扇 · LTC2980 margin (CONN13~16 × CB/SWB0/SWB1) + PDB:Hotswap / Power brick / EFUSE(走 VI2C ch3/ch4) +``` + +--- + +## Project Structure + +``` +Blanton_TTL_Script/ +│ +├── CLAUDE.md # 專案記憶 & 給 Claude 的指令 +├── ARCHITECTURE.md # 本架構文件 +├── .gitignore # secret/ + For_AI/ + logs 規則 +│ +├── docs/ # 規格與狀態文件(客戶提供 / 專案產出) +│ ├── Blantons_FPGA_Registers.md # FPGA 暫存器規格(markdown 正本,查 offset 用) +│ ├── Blantons_FPGA_Registers_draft.docx # 同上,客戶原始 docx +│ ├── Blantons_FPGA_Registers_Map_draft.xlsx +│ ├── Blantons_PCIe_AER_and_DDR_EDAC_checks.pdf # AER / EDAC 檢查點依據 +│ └── TTL_Script_Blanton_Status_20260814.xlsx # ⭐ 三支腳本逐項 Status(OK / On-Going + Owner) +│ +├── tools/ # Host 端輔助腳本(log 解析、報表產生) +│ +├── secret/ # 🚫 gitignored — DUT 密碼、per-unit BDF、COM 設定 +│ ├── README.md # ✅ committed — 用途索引 +│ ├── config_secret.ttl.example # ✅ committed — 帳密範本(__CHANGE_ME__) +│ └── config_secret.ttl # 🚫 實際帳密,由 config.ttl include +│ +├── For_AI/ # 🚫 gitignored — AI 協作素材(波形截圖、草稿) +│ +├── publish/ # 可交付的打包輸出(Blanton_Script_ABC_v_/ + zip) +│ +└── src/ + └── Script_ABC_Blanton/ # ← Tera Term 的工作目錄(整包給測試員) + │ + ├── config.ttl # 全域設定:testcase 名、EN_Margin / EN_log、三個 prompt 字串 + ├── 1_Blanton_Script_A.ttl # Pre-test:登入 → 對時 → source 工具 → 清 AER → 抓基線 + ├── 2_Blanton_Script_B.ttl # Stress:開壓力程序 → while 1 每輪抓 fan/temp/margin + ├── 3_Blanton_Script_C.ttl # Post-test:kill → 再抓一次 → 比對 stress log + │ + ├── utils/ # 可 include 的取數片段(TTL,無狀態、只 wait+sendln) + │ ├── pcie_bus.ttl # lspci -tvvv / -vv + │ ├── setup_pmon.ttl # show platform summary/fan/temperature/psu/voltage/current/ssd + │ ├── show_dmesg.ttl # date + dmesg grep error/fail/warning + │ ├── show_margin_status.ttl # source margin_status_all.sh(掃 9 顆 LTC2980) + │ ├── kill_all_process.ttl # kill $(jobs -p) + │ ├── show_pcie_error_reg.ttl # 舊的合併版(已被下列 per-device 版取代) + │ ├── show_pcie_error_reg_TH6_SWB0.ttl # EP 01:00.0 + RP 00:01.1 + │ ├── show_pcie_error_reg_TH6_SWB1.ttl # EP 02:00.0 + RP 00:01.2 + │ ├── show_pcie_error_reg_FPGA.ttl # RP 00:01.5(共用上游) + │ ├── show_pcie_error_reg_BMC.ttl # EP 03:00.0 + RP 00:01.4 + │ ├── show_pcie_error_reg_I210.ttl # EP 07:00.0 + RP 00:02.4 + │ ├── show_pcie_error_reg_SSD.ttl # EP 06:00.0 + RP 00:02.1 + │ └── show_pcie_error_reg_DDR.ttl # EDAC mc0 rank0~3 CE/UE + │ + ├── logs/ # Tera Term logopen 輸出(*.log gitignored) + │ + └── Blanton_Script/ # ← scp 到 DUT ~/ 的單位(bash 工具庫) + ├── blanton_fpga_pcimem.sh # pcimem 後端:cb_fpga/pmc_fpga/icb_fpga/swb0_fpga/swb1_fpga + ├── blanton_cb_i2c.sh # CB FPGA F3 I2C master(Ch0~Ch17)+ PMBus helper + ├── blanton_icb_vi2c.sh # CB F3 VI2C proxy → ICB/PDB(Ch0~Ch4) + ├── blanton_temp_sensor.sh # TMP75 / TMP432 讀溫(CB Ch10 mux + ICB VI2C Ch2) + ├── blanton_pwr_data.sh # SWB VRM + PDB brick 的 Vin/Vout/Iout/Temp 表 + └── LTC2980_Margin_Script/ # 電壓 margin 子專案(另有獨立 repo) + ├── margin.sh # margin_init/status/set/apply_profile/save + ├── settings/*.conf # 一個 .conf = 一顆 LTC2980(CB + SWB0/1 × CONN13~16) + ├── profiles/*.conf # 16-ch 批次組合(comboA/B、high3/5、low3/5、normal、off) + ├── script/*_all.sh # 跨 9 顆 LTC2980 的批次 status / apply / save + └── logs/ # margin 操作 log +``` + +--- + +## Data Models + +本專案沒有資料庫,「資料模型」是**設定檔格式**與**暫存器 / sysfs 語意**。 + +### 1. `config.ttl` — 全域測試參數(TTL 變數) + +```ini +strTestcase = "Margin" ; 測項名,進 log 檔名 +project_name = "Blanton" ; 專案名,進 log 檔名 +EN_Margin = 1 ; 1=跑 margin 掃描, 0=跳過 +EN_log = 1 ; 1=logopen 存檔, 0=不存 +prompt_login = "sonic login:" +prompt_sonic = "admin@sonic:~$" +prompt_sonic_root = "root@sonic:~#" +``` + +Log 檔名規則:`\Logs\__.log` + +### 2. `settings/.conf` — 一顆 LTC2980(16 channel) + +| 欄位 | 型別 | 說明 | +|------|------|------| +| `TRANSPORT` | string | `""`/`"i2c"` = CPU 原生 bus(`i2cset`);`"swb"` = 走 CB FPGA F3 I2C | +| `CB_I2C_CH` | int | `TRANSPORT="swb"` 時的 FPGA I2C 通道(6/7/8/9) | +| `CHIPS[]` | string[2] | `"bus:addr"`,index 0 → CH0~7、index 1 → CH8~15 | +| `CHIP_PRE_CMD[]` / `CHIP_POST_CMD[]` | string[1] | mux 切換等前後置指令,`;` 分隔多筆 | +| `CH_VNOM` | string | 標稱電壓(`"-"` = 未使用 / NC) | +| `CH_NET` | string | 電路 net name(對照 schematic) | + +Channel 定址:`ch / 8` → `CHIPS[]` index,`ch % 8` → LTC2977 PMBus PAGE(0x00~0x07)。 + +### 3. `profiles/*.conf` — 16-ch 批次 margin 組合 + +```bash +PROFILE_CHANNELS=( "0:high:8" "1:low:8" ... ) # "channel:operation:change_percent" +``` + +| operation | PMBus `OPERATION`(0x01) | 說明 | +|-----------|------------------------|------| +| `high` | `0xA8` | Margin high | +| `low` | `0x98` | Margin low | +| `nominal` | `0x80` | 回標稱值(跟隨 VOUT_COMMAND) | +| `off` | `0x00` | 關閉輸出 | + +### 4. FPGA / I2C 暫存器語意(工具庫依賴) + +| 區塊 | 位置 | 關鍵欄位 | +|------|------|----------| +| CB F0 local | `cb_fpga 0 0xD90` | `RST_CAUSE_REG`;`0xD94`/`0xD98` = SWB0/SWB1 | +| CB F3 I2C(每 ch 0x20 stride,base 0x300) | `+00/04` PRSCL, `+08` CTRL(b7 MOD_EN), `+0C` TX/RX, `+10` CMD/STAT, `+14` MUX_SEL, `+18` RST, `+1C` SEM | +| CB F3 VI2C(base 0x780,ICB/PDB) | 同上,但 **`+1C` 無 SEM** | +| I2C CMD | `STA=0x80 STO=0x40 RD=0x20 WR=0x10 NACK=0x08 IACK=0x01` | +| I2C STAT | `RX_ACK=0x80(1=NACK) BUSY=0x40 ARB_LOST=0x20 TIP=0x02 INT=0x01` | +| Prescale @75MHz | `0x88` = 100 kHz、`0x24` = 400 kHz | + +### 5. 錯誤計數 sysfs(判定依據) + +| 類別 | 路徑 | 判定 | +|------|------|------| +| PCIe AER(EP + 上游 RP 都要看) | `/sys/bus/pci/devices//aer_dev_{correctable,nonfatal,fatal}` | test 前後差值 > 0 即 fail(correctable 需依 spec 設門檻) | +| DDR EDAC | `/sys/devices/system/edac/mc/mc0/rank<0-3>/dimm_{ce,ue}_count` | UE > 0 直接 fail;CE 依門檻 | + +**Blanton PCIe 拓樸對照**(`show_pcie_error_reg_*.ttl` 的來源): + +| 裝置 | Endpoint BDF | Upstream Root Port | +|------|--------------|--------------------| +| TH6 SWB0 | `0000:01:00.0` | `0000:00:01.1` | +| TH6 SWB1 | `0000:02:00.0` | `0000:00:01.2` | +| CB FPGA | (F0~F3 @ `0000:03:00.x`) | `0000:00:01.5` | +| BMC | `0000:03:00.0` | `0000:00:01.4` | +| I210 1G NIC | `0000:07:00.0` | `0000:00:02.4` | +| NVMe SSD | `0000:06:00.0` | `0000:00:02.1` | + +> ⚠️ **BDF 是 per-unit 的**。`blanton_fpga_pcimem.sh` 的 `FUNCT0..3_RES` 已經改過三次 +> (04:00.x → 03:00.x → 05:00.x → 03:00.x)。換 DUT 一定要先 `lspci -Dnn | grep -i fpga` 重新確認, +> 同理 `show_pcie_error_reg_*.ttl` 裡的 BDF 也要跟著校。 + +--- + +## Key Features + +| 模組 | 進入點 | 功能 | +|------|--------|------| +| **Script A(Pre-test)** | `1_Blanton_Script_A.ttl` | root 登入 → `mkdir ./logs` → `date -s` 對時 → source 五個 bash 工具 → 清/讀 7 組 PCIe AER → `lspci -tvvv/-vv` → margin 全掃 → PMON 七項 → dmesg 三 grep → `messagebox` 提示接 Script B | +| **Script B(Stress)** | `2_Blanton_Script_B.ttl` | `mlucas-avx2 -cpu 0:15` + 5 份 `stress_mem.py` + `stress_hhmd/ssd/pcie/usb.py` 全部背景執行 → `jobs` 確認 → `while 1` 每輪 `show platform fan` / `temperature` / margin | +| **Script C(Post-test)** | `3_Blanton_Script_C.ttl` | `kill $(jobs -p)` → PMON + dmesg 再抓一次 → 7 組 AER 再抓一次 → `cat` mlucas / stress_ssd log → 完成 messagebox | +| **FPGA 暫存器存取** | `cb_fpga [data]` | pcimem 打 `resource0` + BAR 相對 offset,32-bit word;`pmc/icb/swb0/swb1_fpga` 走 VSPI 窗口 | +| **CB I2C / PMBus** | `cb_i2c_init/scan/read/write`、`cb_pmbus_read/write/linear16` | FPGA F3 OpenCores master,**讀用 Repeated START**(SMBus/PMBus 裝置必需) | +| **ICB / PDB 存取** | `vi2c_init/scan/read/write`、`vi2c_scan_all` | CB F3 VI2C proxy,~3.3 ms/reg,取代 VSPI 的 ~18 ms/reg(後者會踩 SMBus 25–35 ms timeout) | +| **溫度** | `temp_cb` / `temp_icb` / `temp_all` | TMP75(12-bit 左靠齊 ×0.0625)、TMP432(含 RANGE bit 的 −64 偏移、remote1/2) | +| **電源資料** | `pwr_data` / `pwr_data_pdb` / `pwr_pdb_id` | SWB VRM 全軌 Vin/Vout/Iout/Temp 對齊表;MP29816 解析度**執行期從 `MFR_VOUT_SCALE_LOOP` 讀**,不寫死 | +| **電壓 Margin** | `margin_init/status/set/apply_profile/save` + `*_all.sh` | 9 顆 LTC2980(CB CONN13、SWB0/1 CONN13~16)批次 high/low margin 與狀態掃描 | + +--- + +## Data Flow + +### 一輪完整測試(端到端) + +``` +[測試員] 開 Tera Term,連 COM,Control → Macro → 1_Blanton_Script_A.ttl + │ + ▼ +Script A ── logopen Logs/Blanton_Margin_.log ──┐ (之後所有畫面都進這個檔) + │ │ + ├─ 登入 admin → sudo -i → root@sonic:~# │ + ├─ date -s "" ← 讓 DUT 時戳可對照 │ + ├─ source 5 個 bash 工具(函數進 shell) │ + ├─ AER 基線:7 組 EP+RP 的 correctable/nonfatal/fatal + ├─ lspci -tvvv / -vv ← 拓樸 + link speed/width + ├─ margin_status_all ← 9 顆 LTC2980 × 16ch 的 Vout 與偏差% + ├─ show platform × 7 ← fan/temp/psu/voltage/current/ssdhealth + └─ dmesg | grep error/fail/warning + ▼ +[messagebox "Start Script B"] ← 人工確認後手動跑 B + │ + ▼ +Script B ── 同一個 log 檔續寫(logwrite 分隔線) + ├─ 背景程序:mlucas-avx2(CPU) ×1, stress_mem ×5, + │ stress_hhmd(I2C/LSB/PCIe), stress_ssd, stress_pcie, stress_usb + ├─ jobs ← 確認全部起來了 + └─ while 1: fan → temperature → margin_status_all (soak 期間持續取樣) + ▼ +[測試員 Ctrl-C / 停止 macro,接著跑 C] + │ + ▼ +Script C + ├─ kill $(jobs -p) ← 收掉所有背景壓力 + ├─ show platform × 7 + dmesg ← 收工快照 + ├─ AER 再抓一次 ← 與 Script A 基線相減 = 本輪新增錯誤 + └─ cat mlucas_amm_log / log.stress_ssd ← 壓力程式自身的 pass/fail + ▼ +[messagebox "GOOD JOB! Test Case DONE"] → 人工檢查 log +``` + +### 硬體讀值路徑(以「讀一顆 SWB VRM 的 Vout」為例) + +``` +pwr_data + └→ cb_pmbus_read 0x8B 2 (blanton_cb_i2c.sh) + └→ _cbi2c_xfer_read:STA+WR(slave|W) → WR(reg) → Sr + STA+WR(slave|R) + → RD(ACK) → RD(NACK)+STO ← Repeated START + └→ cb_fpga 3 <0x300 + ch*0x20 + reg> (blanton_fpga_pcimem.sh) + └→ pcimem /sys/bus/pci/devices/0000:03:00.3/resource0 w [data] + └→ CB FPGA BAR0 → F3 I2C master → SCL/SDA → MP29816/MP2985B + └→ 解碼:MP2985B = 1 mV/LSB;MP29816 = 由 MFR_VOUT_SCALE_LOOP(0x29) bit[12:10] 決定 + Vin 一律 31.25 mV/LSB(÷32) +``` + +--- + +## Key Constraints & Business Rules + +1. **A → B → C 必須依序跑,且 B 之後才能跑 C。** Script B 的背景 job 只存在於那個 shell session, + Script C 的 `kill $(jobs -p)` 依賴同一個 session;中途斷線就得手動收程序。 +2. **A / B / C 共用同一個 log 檔**:只有 Script A `logopen`,B / C 用 `logwrite` 續寫分隔線。 + 跑 B/C 前若關掉了 Tera Term,log 就斷了。 +3. **PCIe AER 的判定是「差值」不是「絕對值」**:Script A 抓基線、Script C 抓結果, + 兩者相減才是本輪產生的錯誤。EP 與上游 Root Port **兩邊都要看**(錯誤可能只記在 RP)。 +4. **BDF 是 per-unit 的**,換 DUT 必須重新確認並改 `blanton_fpga_pcimem.sh` 的 `FUNCT0..3_RES` + 與 `utils/show_pcie_error_reg_*.ttl`(見 Data Models §5 註)。 +5. **ICB / PDB 一律走 VI2C,不走 VSPI**:VSPI ~18 ms/reg 會讓 I2C byte 相之間拉到 ~50 ms, + 踩中 SMBus 25–35 ms timeout,裝置會 NACK register pointer。實測全 5 通道掃描 9.4 s vs 34.0 s。 +6. **I2C 讀一律用 Repeated START**(不是 STOP + START):PMBus / SMBus 裝置(VRM、EFUSE) + 只吃 Sr;只有純暫存器裝置兩種都行。 +7. **`margin_save`(`STORE_USER_ALL`)會永久寫進 NVM**,斷電保留。測試流程中**絕不執行**, + 以免覆蓋客戶出廠 config。`margin.sh` 的 auto-enable 只改 RAM(`ON_OFF_CONFIG`),斷電復原。 +8. **操作硬體電壓有損壞 DUT 的風險**:套 profile 前先確認該軌 OV/UV limit 與 servo DAC 注入電阻 + 有 populate(本板部分 margin 電阻標 PROTO,沒 populate 的軌電壓不會動)。 +9. **`ARB_LOST` 不等於裝置存在**:`vi2c_scan` 只看 `RX_ACK`,仲裁失敗會被誤報成「有裝置」。 + `blanton_pwr_data.sh` 因此加了 ARB_LOST-aware retry 與 plausibility window + (`0xFFFF` 或超出範圍一律回 `NA`)——**寧可 NA 也不要印出一個看起來像數據的錯值**。 +10. **DUT 密碼不得進 git**:`1_Blanton_Script_A.ttl` 目前的 `sendln "YourPaSsWoRd"` 是 placeholder, + 實際帳密必須放 `secret/config_secret.ttl`(gitignored)並由 `config.ttl` include。 +11. **客戶 NDA**:`docs/` 內含客戶 FPGA 規格與 schematic 衍生資訊,**本 repo 只推 NAS + Gitea, + 絕不推 GitHub**。 + +--- + +## Security Considerations + +| 項目 | 做法 | +|------|------| +| **DUT console 帳密** | 集中在 `secret/config_secret.ttl`(gitignored),`config.ttl` 以 `include` 載入。repo 內只留 `secret/config_secret.ttl.example`,敏感欄位一律 `__CHANGE_ME__` | +| **`secret/` 資料夾** | 本機 / 現場敏感資料集中地:DUT 帳密、per-unit BDF 覆寫、COM port 設定、客戶提供的未公開附件。`.gitignore` 用 `secret/*` + `!secret/README.md` + `!secret/*.example` + `!secret/.gitkeep`,**除 README 與 `.example` 外全部忽略** | +| **客戶機密文件** | `docs/` 內 FPGA 規格(docx/xlsx/md)屬客戶 NDA 範圍;schematic 原始檔(`*.DSN`)一律 gitignore,不進 repo | +| **Remote 限制** | 只推私有 remote:`nas`(`git.et-wen.com:51222`)+ `gitea`(`etgit.et-wen.com`)。**不設 GitHub `origin`** | +| **測試 log** | `logs/*.log` 含 DUT 序號、MAC、韌體版本等可識別資訊 → gitignore,只保留目錄結構(`.gitkeep`) | +| **破壞性硬體指令** | `margin_save` / `STORE_USER_ALL` 為永久 NVM 寫入,工具預設不呼叫;批次腳本 `margin_save_all.sh` 在 README 與腳本頂端都有警語 | +| **root 權限** | 全流程在 `root@sonic:~#` 下執行(pcimem / i2c 需要);腳本不留任何 `chmod 777` 或放寬權限的動作 | +| **For_AI/** | AI 協作素材(截圖、草稿筆記)整個資料夾 gitignore,避免不小心把客戶圖面帶進 repo | + +--- + +## Build & Setup Steps + +無編譯。從零到能跑一輪測試: + +```bash +# ── 0. 取得專案(開發機 / 測試 NB)──────────────────────────── +git clone ssh://ETHouseNAS@git.et-wen.com:51222/volume1/git/Blanton_TTL_Script.git +cd Blanton_TTL_Script + +# ── 1. 準備帳密(不進 git)────────────────────────────────── +cp secret/config_secret.ttl.example secret/config_secret.ttl +# 編輯 secret/config_secret.ttl,填入實際 DUT 帳密(取代 __CHANGE_ME__) + +# ── 2. DUT 端:部署 bash 工具庫 ───────────────────────────── +scp -r src/Script_ABC_Blanton/Blanton_Script admin@:~/ +ssh admin@ 'sudo -i' +# (現場無網路時改用 USB 隨身碟複製到 ~/Blanton_Script) + +# ── 3. DUT 端:確認 FPGA BDF(每台不同!)──────────────────── +lspci -Dnn | grep -i fpga # 例:0000:03:00.0 +ls -d /sys/bus/pci/devices/0000:*:00.3 +# 若不是 0000:03:00.x,改 ~/Blanton_Script/blanton_fpga_pcimem.sh 的 FUNCT0..3_RES +# 以及 src/Script_ABC_Blanton/utils/show_pcie_error_reg_*.ttl 內的 BDF + +# ── 4. DUT 端:煙霧測試(跑 Script A 之前先手動確認)────────── +source ~/Blanton_Script/blanton_fpga_pcimem.sh +cb_fpga 0 0xD90 # RST_CAUSE_REG,讀得到值 = BAR 通了 +source ~/Blanton_Script/blanton_cb_i2c.sh +cb_i2c_init 11 && cb_i2c_scan 11 # Ch11 風扇控制器,應看到 0x20 +source ~/Blanton_Script/LTC2980_Margin_Script/margin.sh +margin_init Blanton_CB_CONN13 && margin_status +``` + +**Host(Windows)端:** + +``` +1. 安裝 Tera Term 5.x +2. 把 src\Script_ABC_Blanton\ 整包複製到本機(路徑不要有空白與非 ASCII) +3. 在該資料夾下建立 Logs\ 目錄(Script A 的 logopen 需要) +4. Tera Term 連上 DUT COM port(預設 115200-8-N-1) +5. Control → Macro → 選 1_Blanton_Script_A.ttl +6. A 跑完出現 messagebox → 手動跑 2_Blanton_Script_B.ttl(soak) +7. Soak 時間到 → 停止 B 的 macro → 跑 3_Blanton_Script_C.ttl +8. 檢查 Logs\Blanton_Margin_.log +``` + +> 註:本專案非 .NET / Blazor / EC2 架構,`aws-ec2-deploy` 與 `vbox-run-deploy` 兩份部署指南不適用,已跳過。 + +--- + +## Development Phases + +現況基準:`docs/TTL_Script_Blanton_Status_20260814.xlsx` 已逐項標記 OK / On-Going, +以下 Phase 直接把該表的 On-Going 項目排進來,並補上工程化(版控、密碼外移、打包)的缺口。 + +### Phase 1 — 版控化 + 密碼外移(工作量:S) + +**目標:** 專案進 git(NAS + Gitea),帳密不再躺在腳本裡,任何人 clone 下來照文件就能跑。 + +**包含:** +- [ ] `git init` + `.gitignore`(`secret/*`、`For_AI/`、`logs/*.log`、`~$*`、`*.DSN`) +- [ ] 建 `secret/README.md` + `secret/config_secret.ttl.example`(`__CHANGE_ME__` placeholder) +- [ ] `config.ttl` 改為 `include "..\..\secret\config_secret.ttl"`(或現場放同層), + 把 `1_Blanton_Script_A.ttl` 的 `sendln "YourPaSsWoRd"` 換成 `sendln dut_password` +- [ ] `src/Script_ABC_Blanton/logs/.gitkeep`,既有 `Blanton_Margin_20260814-164122.log` 移出 repo +- [ ] `CLAUDE.md` + `ARCHITECTURE.md` 進 repo,push `nas` + `gitea`(**不推 GitHub**) + +**驗收條件:** 在另一台機器 `git clone` → 填 `secret/config_secret.ttl` → Script A 能完整登入並產生 log; +`git log -p` 中搜不到任何實際密碼。 + +--- + +### Phase 2 — Script A 補完:Check History + Margin 驗收(工作量:M) + +**目標:** Script A 的基線資料補齊到「開機原因 + 全部電壓軌」都有紀錄,Status 表的兩個 On-Going 轉 OK。 + +**包含:** +- [ ] 新增 `utils/show_reset_cause.ttl`:`cb_fpga 0 0xD90`(RST_CAUSE_REG)、 + `cb_fpga 0 0xD94`(SWB0)、`cb_fpga 0 0xD98`(SWB1),並在註解貼上 bit 定義 + (來源 `docs/Blantons_FPGA_Registers.md` §5 RST_CAUSE_REG) +- [ ] Script A 的 `; ========== Check History ==========` 區塊改 include 上面這支 +- [ ] `utils/show_margin_status.ttl`:清掉已註解的 per-conf 舊寫法,只留 + `margin_status_all.sh`;確認 9 顆 LTC2980 都能掃到(含 SWB 的 `TRANSPORT="swb"` 路徑) +- [ ] 新增 `utils/show_pwr_data.ttl`(`pwr_data` + `pwr_data_pdb`)與 + `utils/show_temp_sensor.ttl`(`temp_all`),把 `blanton_pwr_data.sh` / + `blanton_temp_sensor.sh` 真正接進流程(目前 Script A 只 source 沒用) +- [ ] Script A 開頭加 BDF 自檢:`lspci -Dnn | grep -i fpga`,log 裡看得到本台的實際 BDF + +**驗收條件:** 跑一次 Script A,log 內同時含 reset cause 三個暫存器值、9 顆 LTC2980 × 16ch 的 +margin status、全部 VRM 軌的 Vin/Vout/Iout/Temp、CB + ICB 溫感讀值,且無 `ERR` / `NA` 以外的異常。 + +--- + +### Phase 3 — Script B 壓力層穩固化(工作量:M) + +**目標:** 壓力程序起得來、起不來看得出來,soak 迴圈有時戳、可控週期。 + +**包含:** +- [ ] 部署 `~/hammer/tools/` 前置檢查:新增 `utils/check_hammer_tools.ttl` + (`ls -l ~/hammer/tools/` + `ls ~/hammer/tools/amd/mlucas-avx2`),缺檔就別往下跑 +- [ ] 壓力程序 log 加時戳,避免多輪覆蓋: + `mlucas_amm_log` → `~/logs/mlucas_amm_log_$(date +%Y%m%d-%H%M%S).log`(Status 表 ScriptB #2 的既定寫法) +- [ ] `jobs` 之後加驗證:期望 10 個背景 job(1 mlucas + 5 mem + hhmd/ssd/pcie/usb), + 數量不符時 `messagebox` 提示 +- [ ] soak 迴圈改為「每輪先 `date`、跑完 `pause <間隔>`」, + 把 `EN_LoopInterval`(預設 600 秒 = 10 min)放進 `config.ttl`,兌現 Status 表的「Get data every 10mins」 +- [ ] soak 每輪補 `show platform psustatus` / `voltage` / `current`(目前只有 fan + temperature) +- [ ] 補 `; ========== CLEAR EVENT ==========`(Status 表 ScriptB #1,Owner: Alan) + +**驗收條件:** Script B 啟動後 `jobs` 顯示 10 個 job;連續跑 3 輪,log 內三段各自帶正確時戳且間隔 ≈10 min; +故意把 `~/hammer` 改名,Script B 會在前置檢查就停下並提示。 + +--- + +### Phase 4 — Traffic 與 SONiC 介面資料(工作量:M) + +**目標:** 補齊 Status 表中 Owner=Alan 的三個 traffic 項目,讓測試涵蓋交換晶片的資料面。 + +**包含:** +- [ ] `utils/traffic_setup.ttl`:Blanton/SONiC 版的 port 起始設定與 counter 清零 + (對照 Carlsbad 的 `clear int stat global`,改用 SONiC `sonic-clear counters`) +- [ ] `utils/show_traffic_counters.ttl`:`show interface counters`、 + `show interface counters errors`、`show interface status` +- [ ] `utils/show_interface_detail.ttl`:`show interface transceiver eeprom/dom`、 + `show interface link-training`(對照 Carlsbad `sho int transceiver detail`) +- [ ] `utils/show_tech.ttl`:`show techsupport`(Script C 收工快照,Status 表 ScriptC #4) +- [ ] Script A 的 TRAFFIC-SETUP-STAGE 與 Script C 的 CHECK Traffic counters 接上這些片段 +- [ ] `config.ttl` 加 `EN_Traffic` 旗標,未接線的站點可整段跳過 + +**驗收條件:** `EN_Traffic=1` 時,Script A log 有清零後的 counter 基線、Script C log 有結束時的 +counter 與 error-counter,兩者可直接相減;`EN_Traffic=0` 時整段不執行且不報錯。 + +--- + +### Phase 5 — Log 解析與自動判定(工作量:L) + +**目標:** 不用人眼掃幾 MB 的 console log,跑完自動吐一張 PASS/FAIL 摘要。 + +**包含:** +- [ ] `tools/parse_blanton_log.py`:吃 `Logs/*.log`,切出 ScriptA / ScriptB / ScriptC 三段 + (靠 `logwrite` 的 `#####` 分隔線) +- [ ] AER / EDAC 差值計算:抽出 A 與 C 兩次的 `aer_dev_*` 與 `dimm_{ce,ue}_count`,輸出增量表, + UE > 0 或 fatal/nonfatal > 0 直接標 FAIL +- [ ] Margin 表解析:把 9 顆 × 16ch 的 Vout / 偏差% 收成 CSV,標出超出 ±(profile 設定值 + 容差) 的軌 +- [ ] 溫度 / 風扇 / 電源趨勢:soak 期間逐輪取樣 → CSV(可直接畫圖) +- [ ] Stress 判定:`mlucas_amm_log` 與 `log.stress_ssd` 的錯誤關鍵字掃描 +- [ ] 產出 `Logs/_summary.md`:一頁 PASS/FAIL + 每個子系統一行結論 + +**驗收條件:** 拿一份既有 log(如 `Blanton_Margin_20260814-164122.log`)跑解析器, +產出 summary 與 CSV;人工植入一筆假的 `dimm_ue_count=1` 後,summary 正確翻成 FAIL。 + +--- + +### Phase 6 — 打包、Runbook 與交付(工作量:S) + +**目標:** 產出可直接交給現場測試員(或客戶)的一包,含操作手冊,不需要看原始碼。 + +**包含:** +- [ ] `tools/publish.sh`:把 `src/Script_ABC_Blanton/` + 空 `Logs/` + `secret/*.example` + 打包成 `publish/Blanton_Script_ABC_v_/` 與同名 zip(比照 + 既有的 `Blanton_Script_ABC_v1.0_20251229` 命名) +- [ ] `README.md`(現場用):Tera Term 設定、A→B→C 操作順序、常見錯誤(BDF 不符、 + margin 掃不到、hammer 工具缺檔)與對應處理 +- [ ] `CHANGELOG.md`:延續三支腳本頂端的 Version History,集中成一份 +- [ ] 三支腳本的 header 版號與 `CHANGELOG.md` 對齊,`config.ttl` 加 `script_version` 並寫進 log 開頭 +- [ ] `docs/TTL_Script_Blanton_Status_*.xlsx` 更新為全 OK,或把剩餘項目移進 Future Extensions +- [ ] 打 git tag `v1.1.0`,push `nas` + `gitea` + +**驗收條件:** 從 zip 解壓到一台乾淨的測試 NB,照 README 操作,不看原始碼就能完成一輪 A→B→C +並產出 summary;`publish/` 內容與 git tag 一致。 + +--- + +## Future Extensions + +- **Script B 的 eye measurement**:Status 表 ScriptB「Take one round of eye measurement on uplink ports」 + 目前是空區塊,待 TH6 SDK 的 eye scan 指令確認後補上。 +- **PDB 電源轉換值驗證**:`blanton_pwr_data.sh` 的 PDB 段落在第一台 DUT(COM39)因 ch4 仲裁問題無法驗證, + COM36 才拿到部分結果;`READ_VIN` 已知不是真的輸入電壓(跟隨 `READ_VOUT`)。待拿到 brick 的 + `MFR_ID`/`MFR_MODEL` 後對照 datasheet 定案。 +- **`show_pcie_error_reg.ttl` 淘汰**:舊的合併版已被 7 支 per-device 版取代,確認無人引用後刪除。 +- **BDF 自動偵測**:把 `blanton_fpga_pcimem.sh` 註解中的 auto-detect 片段轉正, + 用 `lspci -Dnn | grep -i fpga` 動態填 `FUNCT0..3_RES`,讓換 DUT 不用改檔。 +- **SSH / 網路模式**:目前全走 COM console。若 DUT 管理網路可用,可改用 `plink`/`ssh` 執行同一組 + bash 工具,速度與可靠度都比 serial 好,TTL 只保留開機階段。 +- **多 DUT 併行**:多台 DUT 同時 soak 時,Tera Term 每台開一個 macro window; + 可考慮改成 Python(`pyserial`)統一排程與集中收 log。 +- **與 `LTC2980_Margin_Script` 獨立 repo 的同步機制**:目前 `Blanton_Script/LTC2980_Margin_Script/` + 是該 repo 的複本(少了 `ARCHITECTURE.md`/`CLAUDE.md`/`Reference/`,多了兩支 `blanton_*` 後端)。 + 待評估改用 git submodule 或明確的 vendored 同步腳本。 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e915ad6 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,110 @@ +# CLAUDE.md — Blanton TTL Script + +## 專案簡介 + +Blanton(Project Helios)交換器平台的系統層可靠性測試自動化腳本組。 +Windows 端用 **Tera Term TTL macro** 透過 COM console 驅動 DUT 的 SONiC, +A / B / C 三支腳本分別跑「基線 → 壓力 soak → 收工判定」,全程存 log。 +DUT 端的取數能力由一組 **bash 工具庫** 提供(CB FPGA `pcimem` → FPGA I2C/VI2C → VRM / 溫感 / LTC2980)。 + +完整架構見 [ARCHITECTURE.md](ARCHITECTURE.md)。 + +## 技術棧 + +- **Host**:Tera Term 5.x TTL macro(`.ttl`),Windows +- **DUT**:SONiC(Debian-based),bash + busybox/mawk,`root@sonic:~#` +- **暫存器存取**:`pcimem`(mmap PCI sysfs `resource0` + BAR 相對 offset,一律 32-bit word) +- **I2C/PMBus**:CB FPGA F3 I2C master(Ch0~Ch17,base 0x300 stride 0x20)、 + CB F3 VI2C proxy → ICB/PDB(Ch0~Ch4,base 0x780)、CPU 原生 bus(`i2cset`/`i2cget`) +- **Margin**:LTC2980(= 2 × LTC2977)over PMBus,LINEAR16 +- **判定資料源**:PCIe AER sysfs(`aer_dev_*`)、EDAC sysfs(`dimm_{ce,ue}_count`)、SONiC `show platform *` +- **無編譯步驟**:TTL 與 bash 都直譯執行 + +## 常用指令 + +```bash +# ── 部署 bash 工具庫到 DUT ────────────────────────── +scp -r src/Script_ABC_Blanton/Blanton_Script admin@:~/ + +# ── DUT 上先確認 FPGA BDF(每台不同!)─────────────── +lspci -Dnn | grep -i fpga +ls -d /sys/bus/pci/devices/0000:*:00.3 + +# ── DUT 上載入工具(Script A 也是做這五件事)───────── +source ~/Blanton_Script/blanton_fpga_pcimem.sh +source ~/Blanton_Script/blanton_cb_i2c.sh +source ~/Blanton_Script/blanton_icb_vi2c.sh +source ~/Blanton_Script/blanton_pwr_data.sh +source ~/Blanton_Script/LTC2980_Margin_Script/margin.sh + +# ── 煙霧測試 ──────────────────────────────────────── +cb_fpga 0 0xD90 # RST_CAUSE_REG,讀得到 = BAR 通了 +cb_i2c_init 11 && cb_i2c_scan 11 # Ch11 風扇控制器,應看到 0x20 +vi2c_scan_all # ICB/PDB 五個通道 +temp_all # CB + ICB 溫感 +pwr_data # SWB VRM 全軌 +margin_init Blanton_CB_CONN13 && margin_status + +# ── 各工具的 help ─────────────────────────────────── +blanton_fpga_help ; blanton_cb_i2c_help ; vi2c_help +temp_sensor_help ; pwr_data_help +``` + +**Host 端跑一輪測試:** + +``` +Tera Term 連 COM port (115200-8-N-1) +→ Control → Macro → 1_Blanton_Script_A.ttl (基線,跑完出 messagebox) +→ 手動跑 2_Blanton_Script_B.ttl (壓力 soak,while 1 迴圈,泡到時間到停掉) +→ 手動跑 3_Blanton_Script_C.ttl (kill + 收工快照 + 判定) +→ 檢查 Logs\Blanton_Margin_.log +``` + +## 開發慣例 + +- **執行單位**:`src/Script_ABC_Blanton/` 整包給測試員(Tera Term 工作目錄); + 其中 `Blanton_Script/` 是 scp 到 DUT `~/` 的單位 +- **TTL 分層**:`config.ttl` 放設定 → 三支主腳本編排流程 → `utils/*.ttl` 是可 include 的無狀態片段 + (只做 `wait prompt_sonic_root` + `sendln`,不設變數、不 logopen) +- **新增取數項目** = 新增一支 `utils/show_xxx.ttl`,再在主腳本 `include`,不要往主腳本塞指令 +- **bash 命名**:公開函數 `cb_i2c_* / vi2c_* / temp_* / pwr_* / margin_*`,內部 helper 一律底線開頭 + (`_cbi2c_* / _vr / _ts_* / _pwr_*`) +- **版本紀錄**:每支 `.ttl` 與 `.sh` 檔頭都有 `Version History` 區塊,改動時**在檔頭補一行** + (`V1.0.2 YYYY-MM-DD <做了什麼>`),不要只改版號 +- **Commit**:Conventional Commits,**英文**。scope 用 `ttl` / `fpga` / `i2c` / `vi2c` / + `margin` / `pwr` / `temp` / `docs` +- **Status 表**:`docs/TTL_Script_Blanton_Status_*.xlsx` 是逐項進度的正本(OK / On-Going + Owner), + 完成一項就同步更新,別讓文件跟腳本脫節 + +## 注意事項 + +- 🔒 **NDA:本 repo 只推 `nas` + `gitea`,絕不推 GitHub。** `docs/` 內含客戶 FPGA 規格。 +- 🔒 **DUT 帳密不進 git**。`1_Blanton_Script_A.ttl` 的 `sendln "YourPaSsWoRd"` 是 placeholder, + 實際值放 `secret/config_secret.ttl`(gitignored)。**任何 commit 前先 grep 一次確認沒帶到真密碼。** +- ⚠️ **PCIe BDF 是 per-unit 的**。`blanton_fpga_pcimem.sh` 的 `FUNCT0..3_RES` 已經改過三次 + (04:00.x → 03:00.x → 05:00.x → 03:00.x)。換 DUT 一定先 `lspci -Dnn | grep -i fpga`, + `utils/show_pcie_error_reg_*.ttl` 內的 BDF 也要一起校。 +- ⚠️ **AER 判定看差值不看絕對值**:Script A 抓基線、Script C 抓結果,相減才是本輪錯誤。 + **Endpoint 與上游 Root Port 兩邊都要讀**,錯誤可能只記在 RP。 +- ⚠️ **ICB/PDB 一律走 VI2C(`blanton_icb_vi2c.sh`),不要走 VSPI**:VSPI ~18 ms/reg 會讓 I2C + byte 相間隔拉到 ~50 ms,踩中 SMBus 25–35 ms timeout,裝置直接 NACK。實測全掃 9.4 s vs 34.0 s。 +- ⚠️ **I2C 讀一律 Repeated START**(不是 STOP + START),否則 PMBus/SMBus 裝置(VRM、EFUSE)不理。 +- ⚠️ **`margin_save` / `STORE_USER_ALL` 會永久寫 NVM**,斷電保留 → **測試流程中絕不執行**, + 以免覆蓋客戶出廠 config。`margin.sh` 的 auto-enable(`ON_OFF_CONFIG=0x1a`)只改 RAM,斷電復原。 +- ⚠️ **改電壓會弄壞 DUT**:套 profile 前確認該軌 OV/UV limit,且 servo DAC 注入電阻有 populate + (本板部分 margin 電阻標 PROTO,沒 populate 的軌電壓不會動,不是腳本壞掉)。 +- ⚠️ **`ARB_LOST` ≠ 有裝置**:`vi2c_scan` 只看 `RX_ACK`,仲裁失敗會被誤報成裝置存在。 + `blanton_pwr_data.sh` 已加 retry + plausibility window,**寧可印 `NA` 也不要印看起來像數據的錯值**。 +- ⚠️ **A → B → C 必須同一個 Tera Term session**:B 的背景 job 與 C 的 `kill $(jobs -p)` 綁在同一個 + shell;log 也只有 A 會 `logopen`,B/C 是續寫。中途關掉 window 就得手動收程序、log 也斷了。 +- ⚠️ **MP29816 的 Vout 解析度不是固定值**,由 `MFR_VOUT_SCALE_LOOP(0x29)` bit[12:10] 決定, + `blanton_pwr_data.sh` 執行期從晶片讀;xlsx 上寫的 `/5mV` 與 MP2985B 的 `+49` offset **都是錯的**。 + +## 資料夾說明 + +- `src/Script_ABC_Blanton/` — 可執行內容(Tera Term 工作目錄;內含要 scp 到 DUT 的 `Blanton_Script/`) +- `docs/` — 客戶 FPGA 規格、AER/EDAC 檢查依據、逐項 Status 表 +- `tools/` — Host 端輔助腳本(log 解析、報表產生、打包) +- `publish/` — 交付用打包輸出(`Blanton_Script_ABC_v_/` + zip) +- `secret/` — 🚫 gitignored(除 `README.md` 與 `*.example`):DUT 帳密、per-unit BDF 覆寫、COM 設定 +- `For_AI/` — 🚫 gitignored:AI 協作素材(波形截圖、草稿筆記) diff --git a/docs/Blantons_FPGA_Registers.md b/docs/Blantons_FPGA_Registers.md new file mode 100644 index 0000000..d495ad0 --- /dev/null +++ b/docs/Blantons_FPGA_Registers.md @@ -0,0 +1,3564 @@ +# Blanton (Project Helios) FPGA Register Specification + +> **Status:** Draft · **Source FPGA:** CB / SWB / ICB +> Converted from `Blantons_FPGA_Registers_draft.docx` and `Blantons_FPGA_Registers_Map_draft.xlsx`. +> This Markdown is a faithful, human-readable rendering of the two HPE source files — values are not edited. + +## Contents + +1. [Revision History](#1-revision-history) +2. [Document Abbreviations](#2-document-abbreviations) +3. [Register Address Map](#3-register-address-map) +4. [MSI Interrupt Mapping](#4-msi-interrupt-mapping) +5. [Register Descriptions](#5-register-descriptions) + +--- + +## 1. Revision History + +| Revision No. | Date
mm/dd/yy | Author | Changes | +|---|---|---|---| +| 0.1 | 03/20/2026 | Peter | 1st Draft | +| 0.2 | 03/23/2026 | Peter | Reviewed by HW | +| 0.3 | 04/06/2026 | Peter | CB
F0 PWR_CTRL/STAT changes
Move USRPRT power to F1 USRPRT_PWR_CTRL/STAT
Move USB 5V to USB_CTRL_REG
Added separate THRM_SUICIDE bit control for SWB 0/1
Added power status of SWB0/1 - #SWB_PWROK
USB_STAT_REG – added new detection bit [1]
ICB_CTRL_REG [3:0] – added encoded reset control to ICB
Fix minor typo in F1 registers
F1 USRPRT_PWR_CTRL – Efuse to QSFP are default to disabled
TND_BMC_GPIO_CTRL/STAT/DIR – replace bit [7] with [0]
Updated LED_CTRL_4/5_REG description
Decouple SWB reset signal into RST_CAUSE_SWB_REG (from RST_CAUSE_REG)
TND_PWR_CTRL/STAT_REG – added new power rails control and status bits
F1 RTM_CTL_REG #RTM_RST default change to asserted | + +**Register-map spreadsheet revisions:** + +| Rev | Date | Description | +|---|---|---| +| 0.1 | 2026-03-20 | First Draft | +| 0.2 | 2026-03-23 | Reviewed by HW | +| 0.3 | 2026-04-07 | - Add missing INTRD_STAT_REG - Add USRPRT_PWR_CTRL/STAT_REG - Updated CB-MSI / SWB-INT / ICB-INT tabs - Added USB_CTRL_REG - Added RST_CAUSE_SWB_REG (SWB0/1) | + +--- + +## 2. Document Abbreviations + +| Abbr. | Meaning | +|---|---| +| TBD | To be determined | +| W1C | Write 1 to clear | +| W0C | Write 0 to clear | +| RO | Read Only | +| WO | Write Only | +| RW | Read & Write | + +--- + +## 3. Register Address Map + +Address map of every FPGA register, grouped by FPGA type and PCI function. +Offsets are byte offsets within the function register window. `DW` = number of 32-bit double-words the entry occupies. + +### CB — Control Board + +#### CB — Function 0 + +| Offset | DW | Register | Group | Comment | +|---|---|---|---|---| +| 0x000 | 1 | FPGA_REV_ID_REG | GEN & ID | CB_FPGA revision & Id register | +| 0x004 | 1 | RSVD | GEN & ID | | +| 0x008 | 1 | RSVD | GEN & ID | | +| 0x00C | 1 | RSVD | GEN & ID | | +| 0x010 | 12 | RSVD | GEN & ID | | +| 0x040 | 1 | FUNC_CAP_0_REG | GEN & ID | | +| 0x044 | 1 | FUNC_CAP_1_REG | GEN & ID | | +| 0x048 | 1 | FUNC_CAP_2_REG | GEN & ID | | +| 0x04C | 1 | FUNC_CAP_3_REG | GEN & ID | | +| 0x050 | 1 | FUNC_CAP_4_REG | GEN & ID | | +| 0x054 | 1 | FUNC_CAP_5_REG | GEN & ID | | +| 0x058 | 1 | FUNC_CAP_6_REG | GEN & ID | | +| 0x05C | 1 | FUNC_CAP_7_REG | GEN & ID | | +| 0x060 | 1 | FUNC_CAP_8_REG | GEN & ID | | +| 0x064 | 7 | RSVD | GEN & ID | | +| 0x080 | 1 | FPGA_RECONFIG_CTRL_REG | FPGA Reconfig | | +| 0x084 | 1 | FPGA_RECONFIG_STAT_REG | FPGA Reconfig | | +| 0x088 | 6 | RSVD | FPGA Reconfig | 88 | +| 0x0A0 | 1 | RSVD | FPGA Reconfig | | +| 0x0A4 | 1 | RSVD | FPGA Reconfig | | +| 0x0A8 | 6 | RSVD | FPGA Reconfig | | +| 0x0C0 | 1 | SCRTCH_0_REG | Scratchpad | | +| 0x0C4 | 1 | SCRTCH_1_REG | Scratchpad | | +| 0x0C8 | 1 | SCRTCH_2_REG | Scratchpad | | +| 0x0CC | 1 | SCRTCH_3_REG | Scratchpad | | +| 0x0D0 | 12 | RSVD | Scratchpad | | +| 0x100 | 1 | DEV_MSI_0_PEND_REG | MSI INT | | +| 0x104 | 1 | RSVD | MSI INT | | +| 0x108 | 1 | DEV_MSI_0_INT_EN_REG | MSI INT | | +| 0x10C | 1 | RSVD | MSI INT | | +| 0x110 | 1 | DEV_MSI_1_PEND_REG | MSI INT | | +| 0x114 | 1 | RSVD | MSI INT | | +| 0x118 | 1 | DEV_MSI_1_INT_EN_REG | MSI INT | | +| 0x11C | 1 | RSVD | MSI INT | | +| 0x120 | 1 | DEV_MSI_2_PEND_REG | MSI INT | | +| 0x124 | 1 | RSVD | MSI INT | | +| 0x128 | 1 | DEV_MSI_2_INT_EN_REG | MSI INT | | +| 0x12C | 1 | RSVD | MSI INT | | +| 0x130 | 1 | DEV_MSI_3_PEND_REG | MSI INT | | +| 0x134 | 1 | RSVD | MSI INT | | +| 0x138 | 1 | DEV_MSI_3_INT_EN_REG | MSI INT | | +| 0x13C | 1 | RSVD | MSI INT | | +| 0x140 | 1 | DEV_MSI_4_PEND_REG | MSI INT | | +| 0x144 | 1 | RSVD | MSI INT | | +| 0x148 | 1 | DEV_MSI_4_INT_EN_REG | MSI INT | | +| 0x14C | 1 | RSVD | MSI INT | | +| 0x150 | 1 | DEV_MSI_5_PEND_REG | MSI INT | | +| 0x154 | 1 | RSVD | MSI INT | | +| 0x158 | 1 | DEV_MSI_5_INT_EN_REG | MSI INT | | +| 0x15C | 1 | RSVD | MSI INT | | +| 0x160 | 1 | DEV_MSI_6_PEND_REG | MSI INT | 160 | +| 0x164 | 1 | RSVD | MSI INT | | +| 0x168 | 1 | DEV_MSI_6_INT_EN_REG | MSI INT | | +| 0x16C | 1 | RSVD | MSI INT | | +| 0x170 | 1 | DEV_MSI_7_PEND_REG | MSI INT | | +| 0x174 | 1 | RSVD | MSI INT | | +| 0x178 | 1 | DEV_MSI_7_INT_EN_REG | MSI INT | | +| 0x17C | 1 | RSVD | MSI INT | | +| 0x180 | 64 | RSVD | MSI INT | | +| 0x280 | 32 | RSVD | Mailbox | | +| 0x300 | 1 | PWR_CTRL_REG | Power | | +| 0x304 | 1 | PWR_STAT_REG | Power | | +| 0x308 | 1 | PWR_STAT_PLRTY_REG | Power | | +| 0x30C | 1 | PWR_STAT_EDG_LVL_REG | Power | | +| 0x310 | 1 | PWR_STAT_INT_EN_REG | Power | | +| 0x314 | 1 | PWR_STAT_INT_STAT_REG | Power | | +| 0x318 | 1 | PWR_STAT_INT_CLR_REG | Power | | +| 0x31C | 1 | SEM_REG | Power | | +| 0x320 | 24 | RSVD | Power | | +| 0x380 | 1 | RS232_SPD_SNS_REG | Speed Sense | | +| 0x384 | 1 | RS232_CLR_SPD_SNS_REG | Speed Sense | | +| 0x388 | 14 | RSVD | Speed Sense | | +| 0x3C0 | 1 | RSVD | TPM | For TPM 1.0 and 2.0 | +| 0x3C4 | 1 | TPM_STAT_REG | TPM | | +| 0x3C8 | 1 | TPM_STAT_PLRTY_REG | TPM | | +| 0x3CC | 1 | TPM_STAT_EDG_LVL_REG | TPM | | +| 0x3D0 | 1 | TPM_STAT_INT_EN_REG | TPM | | +| 0x3D4 | 1 | TPM_STAT_INT_STAT_REG | TPM | | +| 0x3D8 | 1 | TPM_STAT_INT_CLR_REG | TPM | | +| 0x3DC | 1 | SEM_REG | TPM | | +| 0x3E0 | 24 | RSVD | TPM | | +| 0x440 | 1 | PMC_CTRL_REG | PMC | | +| 0x444 | 1 | PMC_STAT_REG | PMC | | +| 0x448 | 1 | PMC_STAT_PLRTY_REG | PMC | | +| 0x44C | 1 | PMC_STAT_EDG_LVL_REG | PMC | | +| 0x450 | 1 | PMC_STAT_INT_EN_REG | PMC | | +| 0x454 | 1 | PMC_STAT_INT_STAT_REG | PMC | | +| 0x458 | 1 | PMC_STAT_INT_CLR_REG | PMC | | +| 0x45C | 1 | SEM_REG | PMC | | +| 0x460 | 8 | RSVD | PMC | | +| 0x480 | 1 | ICB_CTRL_REG | ICB | | +| 0x484 | 1 | ICB_STAT_REG | ICB | | +| 0x488 | 1 | ICB_STAT_PLRTY_REG | ICB | | +| 0x48C | 1 | ICB_STAT_EDG_LVL_REG | ICB | | +| 0x490 | 1 | ICB_STAT_INT_EN_REG | ICB | | +| 0x494 | 1 | ICB_STAT_INT_STAT_REG | ICB | | +| 0x498 | 1 | ICB_STAT_INT_CLR_REG | ICB | | +| 0x49C | 1 | SEM_REG | ICB | | +| 0x4A0 | 8 | RSVD | ICB | | +| 0x4C0 | 1 | SWB_CTRL_REG | SWB0 | | +| 0x4C4 | 1 | SWB_STAT_REG | SWB0 | | +| 0x4C8 | 1 | SWB_STAT_PLRTY_REG | SWB0 | | +| 0x4CC | 1 | SWB_STAT_EDG_LVL_REG | SWB0 | | +| 0x4D0 | 1 | SWB_STAT_INT_EN_REG | SWB0 | | +| 0x4D4 | 1 | SWB_STAT_INT_STAT_REG | SWB0 | | +| 0x4D8 | 1 | SWB_STAT_INT_CLR_REG | SWB0 | | +| 0x4DC | 1 | SEM_REG | SWB0 | | +| 0x4E0 | 8 | RSVD | SWB0 | | +| 0x500 | 1 | SWB_CTRL_REG | SWB1 | | +| 0x504 | 1 | SWB_STAT_REG | SWB1 | 504 | +| 0x508 | 1 | SWB_STAT_PLRTY_REG | SWB1 | | +| 0x50C | 1 | SWB_STAT_EDG_LVL_REG | SWB1 | | +| 0x510 | 1 | SWB_STAT_INT_EN_REG | SWB1 | | +| 0x514 | 1 | SWB_STAT_INT_STAT_REG | SWB1 | | +| 0x518 | 1 | SWB_STAT_INT_CLR_REG | SWB1 | | +| 0x51C | 1 | SEM_REG | SWB1 | | +| 0x520 | 8 | RSVD | SWB1 | | +| 0x540 | 1 | BMC_CTRL_REG | BMC | | +| 0x544 | 1 | BMC_STAT_REG | BMC | | +| 0x548 | 1 | BMC_STAT_PLRTY_REG | BMC | | +| 0x54C | 1 | BMC_STAT_EDG_LVL_REG | BMC | | +| 0x550 | 1 | BMC_STAT_INT_EN_REG | BMC | | +| 0x554 | 1 | BMC_STAT_INT_STAT_REG | BMC | | +| 0x558 | 1 | BMC_STAT_INT_CLR_REG | BMC | | +| 0x55C | 1 | SEM_REG | BMC | | +| 0x560 | 8 | RSVD | BMC | | +| 0x580 | 1 | RSVD | THRM | | +| 0x584 | 1 | THRM_STAT_REG | THRM | | +| 0x588 | 1 | THRM_STAT_PLRTY_REG | THRM | | +| 0x58C | 1 | THRM_STAT_EDG_LVL_REG | THRM | | +| 0x590 | 1 | THRM_STAT_INT_EN_REG | THRM | | +| 0x594 | 1 | THRM_STAT_INT_STAT_REG | THRM | | +| 0x598 | 1 | THRM_STAT_INT_CLR_REG | THRM | | +| 0x59C | 1 | SEM_REG | THRM | | +| 0x5A0 | 8 | RSVD | THRM | | +| 0x5C0 | 1 | USB_CTRL_REG | USB | | +| 0x5C4 | 1 | USB_STAT_REG | USB | | +| 0x5C8 | 1 | USB_STAT_PLRTY_REG | USB | | +| 0x5CC | 1 | USB_STAT_EDG_LVL_REG | USB | | +| 0x5D0 | 1 | USB_STAT_INT_EN_REG | USB | | +| 0x5D4 | 1 | USB_STAT_INT_STAT_REG | USB | | +| 0x5D8 | 1 | USB_STAT_INT_CLR_REG | USB | | +| 0x5DC | 1 | SEM_REG | USB | | +| 0x5E0 | 8 | RSVD | USB | | +| 0x600 | 1 | RSVD | BTN | | +| 0x604 | 1 | BTN_STAT_REG | BTN | | +| 0x608 | 1 | BTN_STAT_PLRTY_REG | BTN | | +| 0x60C | 1 | BTN_STAT_EDG_LVL_REG | BTN | | +| 0x610 | 1 | BTN_STAT_INT_EN_REG | BTN | | +| 0x614 | 1 | BTN_STAT_INT_STAT_REG | BTN | | +| 0x618 | 1 | BTN_STAT_INT_CLR_REG | BTN | | +| 0x61C | 1 | SEM_REG | BTN | | +| 0x620 | 8 | RSVD | BTN | | +| 0x640 | 1 | RSVD | LEAK | | +| 0x644 | 1 | LEAK_STAT_REG | LEAK | | +| 0x648 | 1 | LEAK_STAT_PLRTY_REG | LEAK | 648 | +| 0x64C | 1 | LEAK_STAT_EDG_LVL_REG | LEAK | | +| 0x650 | 1 | LEAK_STAT_INT_EN_REG | LEAK | 650 | +| 0x654 | 1 | LEAK_STAT_INT_STAT_REG | LEAK | | +| 0x658 | 1 | LEAK_STAT_INT_CLR_REG | LEAK | | +| 0x65C | 1 | SEM_REG | LEAK | | +| 0x660 | 8 | RSVD | LEAK | | +| 0x680 | 1 | NFC_CTRL_REG | NFC | | +| 0x684 | 1 | NFC_STAT_REG | NFC | | +| 0x688 | 1 | NFC_STAT_PLRTY_REG | NFC | | +| 0x68C | 1 | NFC_STAT_EDG_LVL_REG | NFC | | +| 0x690 | 1 | NFC_STAT_INT_EN_REG | NFC | | +| 0x694 | 1 | NFC_STAT_INT_STAT_REG | NFC | | +| 0x698 | 1 | NFC_STAT_INT_CLR_REG | NFC | | +| 0x69C | 1 | SEM_REG | NFC | | +| 0x6A0 | 8 | RSVD | NFC | | +| 0x6C0 | 1 | RSVD | Intrusion | | +| 0x6C4 | 1 | INTRD_STAT_REG | Intrusion | | +| 0x6C8 | 1 | INTRD_STAT_PLRTY_REG | Intrusion | | +| 0x6CC | 1 | INTRD_STAT_EDG_LVL_REG | Intrusion | | +| 0x6D0 | 1 | INTRD_STAT_INT_EN_REG | Intrusion | | +| 0x6D4 | 1 | INTRD_STAT_INT_STAT_REG | Intrusion | | +| 0x6D8 | 1 | INTRD_STAT_INT_CLR_REG | Intrusion | | +| 0x6DC | 1 | SEM_REG | Intrusion | | +| 0x6E0 | 8 | RSVD | Intrusion | | +| 0x700 | 1 | RSVD | Battery | | +| 0x704 | 1 | BTRY_STAT_REG | Battery | | +| 0x708 | 1 | BTRY_STAT_PLRTY_REG | Battery | | +| 0x70C | 1 | BTRY_STAT_EDG_LVL_REG | Battery | | +| 0x710 | 1 | BTRY_STAT_INT_EN_REG | Battery | | +| 0x714 | 1 | BTRY_STAT_INT_STAT_REG | Battery | | +| 0x718 | 1 | BTRY_STAT_INT_CLR_REG | Battery | | +| 0x71C | 1 | SEM_REG | Battery | | +| 0x720 | 8 | RSVD | Battery | | +| 0x740 | 32 | RSVD | RSVD | | +| 0x7C0 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x7C4 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x7C8 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x7CC | 1 | EN_ACCSS_PRTCTD_REG | Other Dev ctrl-stat-int | | +| 0x7D0 | 1 | UART_MUX_REG | Other Dev ctrl-stat-int | | +| 0x7D4 | 1 | I2C_MUX_RST_REG | Other Dev ctrl-stat-int | | +| 0x7D8 | 1 | CPU_INTR_CTRL_REG | Other Dev ctrl-stat-int | | +| 0x7DC | 1 | BMC_JTAG_CTRL_REG | Other Dev ctrl-stat-int | | +| 0x7E0 | 1 | SWB0_JTAG_CTRL_REG | Other Dev ctrl-stat-int | | +| 0x7E4 | 1 | SWB1_JTAG_CTRL_REG | Other Dev ctrl-stat-int | | +| 0x7E8 | 198 | RSVD | RSVD | | +| 0xB00 | 1 | FLSH_CTRL_REG | Flash Write Protect | | +| 0xB04 | 31 | RSVD | Flash Write Protect | | +| 0xB80 | 1 | LED_SYNC_REG | LED | | +| 0xB84 | 1 | LED_CONFIG_REG | LED | | +| 0xB88 | 1 | LED_CTRL_0_REG | LED | | +| 0xB8C | 1 | LED_CTRL_1_REG | LED | | +| 0xB90 | 1 | LED_CTRL_2_REG | LED | | +| 0xB94 | 1 | LED_CTRL_3_REG | LED | | +| 0xB98 | 1 | LED_CTRL_4_REG | LED | | +| 0xB9C | 1 | LED_CTRL_5_REG | LED | | +| 0xBA0 | 1 | RSVD | LED | | +| 0xBA4 | 1 | RSVD | LED | | +| 0xBA8 | 1 | RSVD | LED | | +| 0xBAC | 1 | RSVD | LED | | +| 0xBB0 | 1 | RSVD | LED | | +| 0xBB4 | 8 | RSVD | RSVD | | +| 0xBD4 | 1 | WDG_CTRL_REG | WDG Ctrl-Stat-int | | +| 0xBD8 | 1 | WDG_STAT_REG | WDG Ctrl-Stat-int | | +| 0xBDC | 1 | WDG_RST_REG | WDG Ctrl-Stat-int | | +| 0xBE0 | 8 | RSVD | RSVD | | +| 0xC00 | 1 | TND_CTRL_REG | Debug & Test | | +| 0xC04 | 1 | TND_STAT_REG | Debug & Test | | +| 0xC08 | 1 | TND_PWR_CTRL_REG | Debug & Test | | +| 0xC0C | 1 | TND_PWR_STAT_REG | Debug & Test | | +| 0xC10 | 1 | TND_CLK_CTRL_REG | Debug & Test | | +| 0xC14 | 1 | RSVD | Debug & Test | | +| 0xC18 | 1 | TND_PMC_GPIO_CTRL_REG | Debug & Test | | +| 0xC1C | 1 | TND_PMC_GPIO_STAT_REG | Debug & Test | | +| 0xC20 | 1 | TND_PMC_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC24 | 1 | TND_BMC_GPIO_CTRL_REG | Debug & Test | | +| 0xC28 | 1 | TND_BMC_GPIO_STAT_REG | Debug & Test | | +| 0xC2C | 1 | TND_BMC_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC30 | 1 | TND_SWB0_GPIO_CTRL_REG | Debug & Test | | +| 0xC34 | 1 | TND_SWB0_GPIO_STAT_REG | Debug & Test | | +| 0xC38 | 1 | TND_SWB0_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC3C | 1 | TND_SWB1_GPIO_CTRL_REG | Debug & Test | | +| 0xC40 | 1 | TND_SWB1_GPIO_STAT_REG | Debug & Test | | +| 0xC44 | 1 | TND_SWB1_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC48 | 1 | TND_ICB_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC4C | 1 | TND_ICB_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC50 | 1 | TND_ICB_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC54 | 79 | RSVD | Debug & Test | | +| 0xD90 | 1 | RST_CAUSE_REG | Reset Stat | | +| 0xD94 | 1 | RST_CAUSE_SWB_REG | Reset Stat SWB0 | For SWB 0 | +| 0xD98 | 1 | RST_CAUSE_SWB_REG | Reset Stat SWB1 | For SWB 1 | +| 0xD9C | 1 | RSVD | RSVD | | + +#### CB — Function 1 + +| Offset | DW | Register | Group | Comment | +|---|---|---|---|---| +| 0x000 | 1 | FPGA_REV_ID_REG | GEN & ID | MCB FPGA revision & Id register | +| 0x004 | 1 | RSVD | GEN & ID | | +| 0x008 | 1 | RSVD | GEN & ID | | +| 0x00C | 13 | RSVD | GEN & ID | | +| 0x040 | 1 | FUNC_CAP_0_REG | GEN & ID | number of interrupts for MSI vectors 0 to 3 | +| 0x044 | 1 | FUNC_CAP_1_REG | GEN & ID | number of interrupts for MSI vectors 4 to 7 | +| 0x048 | 1 | FUNC_CAP_2_REG | GEN & ID | number of interrupts for MSI vectors 8 to 11 | +| 0x04C | 1 | FUNC_CAP_3_REG | GEN & ID | number of interrupts for MSI vectors 12 to 15 | +| 0x050 | 1 | FUNC_CAP_4_REG | GEN & ID | number of interrupts for MSI vectors 16 to 19 | +| 0x054 | 1 | FUNC_CAP_5_REG | GEN & ID | number of interrupts for MSI vectors 20 to 23 | +| 0x058 | 1 | FUNC_CAP_6_REG | GEN & ID | number of interrupts for MSI vectors 24 to 27 | +| 0x05C | 1 | FUNC_CAP_7_REG | GEN & ID | number of interrupts for MSI vectors 28 to 31 | +| 0x060 | 1 | FUNC_CAP_8_REG | GEN & ID | | +| 0x064 | 7 | RSVD | GEN & ID | | +| 0x080 | 16 | RSVD | RSVD | | +| 0x0C0 | 1 | SCRTCH_0_REG | Scratchpad | Scratch Registers for SW use | +| 0x0C4 | 1 | SCRTCH_1_REG | Scratchpad | Scratch Registers for SW use | +| 0x0C8 | 1 | SCRTCH_2_REG | Scratchpad | Scratch Registers for SW use | +| 0x0CC | 1 | SCRTCH_3_REG | Scratchpad | Scratch Registers for SW use | +| 0x0D0 | 12 | RSVD | Scratchpad | 12 register reserved for scratch | +| 0x100 | 1 | DEV_MSI_0_PEND_REG | MSI INT | | +| 0x104 | 1 | RSVD | MSI INT | to extend DEV_MSI_PEND_REG | +| 0x108 | 1 | DEV_MSI_0_INT_EN_REG | MSI INT | | +| 0x10C | 1 | RSVD | RSVD | to extend DEV_MSI_INT_EN_REG | +| 0x110 | 1 | DEV_MSI_1_PEND_REG | MSI INT | For other MSI Ctrl registers or INT vector registers | +| 0x114 | 1 | RSVD | MSI INT | | +| 0x118 | 1 | DEV_MSI_1_INT_EN_REG | MSI INT | | +| 0x11C | 1 | RSVD | RSVD | | +| 0x120 | 1 | DEV_MSI_2_PEND_REG | MSI INT | | +| 0x124 | 1 | RSVD | MSI INT | | +| 0x128 | 1 | DEV_MSI_2_INT_EN_REG | MSI INT | | +| 0x12C | 1 | RSVD | MSI INT | | +| 0x130 | 1 | DEV_MSI_3_PEND_REG | MSI INT | | +| 0x134 | 1 | RSVD | MSI INT | | +| 0x138 | 1 | DEV_MSI_3_INT_EN_REG | MSI INT | | +| 0x13C | 1 | RSVD | MSI INT | | +| 0x140 | 1 | DEV_MSI_4_PEND_REG | MSI INT | | +| 0x144 | 1 | RSVD | MSI INT | | +| 0x148 | 1 | DEV_MSI_4_INT_EN_REG | MSI INT | | +| 0x14C | 1 | RSVD | MSI INT | | +| 0x150 | 1 | DEV_MSI_5_PEND_REG | MSI INT | | +| 0x154 | 1 | RSVD | MSI INT | | +| 0x158 | 1 | DEV_MSI_5_INT_EN_REG | MSI INT | | +| 0x15C | 1 | RSVD | MSI INT | | +| 0x160 | 1 | DEV_MSI_6_PEND_REG | MSI INT | | +| 0x164 | 1 | RSVD | MSI INT | | +| 0x168 | 1 | DEV_MSI_6_INT_EN_REG | MSI INT | | +| 0x16C | 117 | RSVD | RSVD | | +| 0x340 | 1 | FAN_CTRL_REG | FAN | | +| 0x344 | 1 | FAN_STAT_REG | FAN | | +| 0x348 | 1 | FAN_STAT_PLRTY_REG | FAN | | +| 0x34C | 1 | FAN_STAT_EDG_LVL_REG | FAN | | +| 0x350 | 1 | FAN_STAT_INT_EN_REG | FAN | 350 | +| 0x354 | 1 | FAN_STAT_INT_STAT_REG | FAN | | +| 0x358 | 1 | FAN_STAT_INT_CLR_REG | FAN | | +| 0x35C | 1 | SEM_REG | FAN | | +| 0x360 | 8 | RSVD | RSVD | | +| 0x380 | 1 | RTM_CTRL_REG | Retimer | | +| 0x384 | 1 | RTM_STAT_REG | Retimer | | +| 0x388 | 1 | RTM_STAT_PLRTY_REG | Retimer | | +| 0x38C | 1 | RTM_STAT_EDG_LVL_REG | Retimer | | +| 0x390 | 1 | RTM_STAT_INT_EN_REG | Retimer | | +| 0x394 | 1 | RTM_STAT_INT_STAT_REG | Retimer | | +| 0x398 | 1 | RTM_STAT_INT_CLR_REG | Retimer | | +| 0x39C | 1 | SEM_REG | Retimer | | +| 0x3A0 | 8 | RSVD | Retimer | | +| 0x3C0 | 1 | ETH_CTRLR_CTRL_REG | Ethernet Controller | | +| 0x3C4 | 1 | ETH_CTRLR_STAT_REG | Ethernet Controller | 3C4 | +| 0x3C8 | 1 | ETH_CTRLR_STAT_PLRTY_REG | Ethernet Controller | | +| 0x3CC | 1 | ETH_CTRLR_STAT_EDG_LVL_REG | Ethernet Controller | | +| 0x3D0 | 1 | ETH_CTRLR_STAT_INT_EN_REG | Ethernet Controller | | +| 0x3D4 | 1 | ETH_CTRLR_STAT_INT_STAT_REG | Ethernet Controller | | +| 0x3D8 | 1 | ETH_CTRLR_STAT_INT_CLR_REG | Ethernet Controller | | +| 0x3DC | 1 | SEM_REG | Ethernet Controller | | +| 0x3E0 | 8 | RSVD | Ethernet Controller | | +| 0x400 | 240 | RSVD | RSVD | | +| 0x7C0 | 1 | USRPRT_PWR_CTRL_REG | FE Power stat-ctrl | | +| 0x7C4 | 1 | USRPRT_PWR_STAT_REG | FE Power stat-ctrl | | +| 0x7C8 | 1 | USRPRT_PWR_STAT_PLRTY_REG | FE Power stat-ctrl | | +| 0x7CC | 1 | USRPRT_PWR_STAT_EDG_LVL_REG | FE Power stat-ctrl | | +| 0x7D0 | 1 | USRPRT_PWR_STAT_INT_EN_REG | FE Power stat-ctrl | | +| 0x7D4 | 1 | USRPRT_PWR_STAT_INT_STAT_REG | FE Power stat-ctrl | | +| 0x7D8 | 1 | USRPRT_PWR_STAT_INT_CLR_REG | FE Power stat-ctrl | | +| 0x7DC | 1 | SEM_REG | FE Power stat-ctrl | | +| 0x7E0 | 8 | RSVD | FE Power stat-ctrl | | +| 0x800 | 1 | USRPRT_CTRL_0_REG | FE stat-ctrl | | +| 0x804 | 1 | USRPRT_STAT_0_REG | FE stat-ctrl | | +| 0x808 | 1 | USRPRT_STAT_0_PLRTY_REG | FE stat-ctrl | | +| 0x80C | 1 | USRPRT_STAT_0_EDG_LVL_REG | FE stat-ctrl | | +| 0x810 | 1 | USRPRT_STAT_0_INT_EN_REG | FE stat-ctrl | | +| 0x814 | 1 | USRPRT_STAT_0_INT_STAT_REG | FE stat-ctrl | | +| 0x818 | 1 | USRPRT_STAT_0_INT_CLR_REG | FE stat-ctrl | | +| 0x81C | 1 | SEM_REG | FE stat-ctrl | | +| 0x820 | 8 | RSVD | FE stat-ctrl | | +| 0x840 | 1 | USRPRT_CTRL_1_REG | FE stat-ctrl | | +| 0x844 | 1 | USRPRT_STAT_1_REG | FE stat-ctrl | | +| 0x848 | 1 | USRPRT_STAT_1_PLRTY_REG | FE stat-ctrl | | +| 0x84C | 1 | USRPRT_STAT_1_EDG_LVL_REG | FE stat-ctrl | | +| 0x850 | 1 | USRPRT_STAT_1_INT_EN_REG | FE stat-ctrl | | +| 0x854 | 1 | USRPRT_STAT_1_INT_STAT_REG | FE stat-ctrl | | +| 0x858 | 1 | USRPRT_STAT_1_INT_CLR_REG | FE stat-ctrl | | +| 0x85C | 1 | SEM_REG | FE stat-ctrl | | +| 0x860 | 8 | RSVD | FE stat-ctrl | | +| 0x880 | 96 | RSVD | RSVD | | +| 0xA00 | 1 | PHY_CTRL_0_REG | PHY stat-ctrl | | +| 0xA04 | 1 | RSVD | PHY stat-ctrl | | +| 0xA08 | 1 | RSVD | PHY stat-ctrl | | +| 0xA0C | 1 | RSVD | PHY stat-ctrl | | +| 0xA10 | 1 | RSVD | PHY stat-ctrl | | +| 0xA14 | 1 | RSVD | PHY stat-ctrl | | +| 0xA18 | 1 | RSVD | PHY stat-ctrl | | +| 0xA1C | 1 | RSVD | PHY stat-ctrl | | +| 0xA20 | 8 | RSVD | PHY stat-ctrl | | +| 0xA40 | 16 | RSVD | RSVD | | + +#### CB — Function 2 + +| Offset | DW | Register | Group | Comment | +|---|---|---|---|---| +| 0x000 | 1 | FPGA_REV_ID_REG | GEN & ID | MCB FPGA revision & Id register | +| 0x004 | 1 | RSVD | GEN & ID | | +| 0x008 | 1 | RSVD | GEN & ID | | +| 0x00C | 13 | RSVD | GEN & ID | | +| 0x040 | 1 | FUNC_CAP_0_REG | GEN & ID | number of interrupts for MSI vectors 0 to 3 | +| 0x044 | 1 | FUNC_CAP_1_REG | GEN & ID | number of interrupts for MSI vectors 4 to 7 | +| 0x048 | 1 | FUNC_CAP_2_REG | GEN & ID | number of interrupts for MSI vectors 8 to 11 | +| 0x04C | 1 | FUNC_CAP_3_REG | GEN & ID | number of interrupts for MSI vectors 12 to 15 | +| 0x050 | 1 | FUNC_CAP_4_REG | GEN & ID | number of interrupts for MSI vectors 16 to 19 | +| 0x054 | 1 | FUNC_CAP_5_REG | GEN & ID | number of interrupts for MSI vectors 20 to 23 | +| 0x058 | 1 | FUNC_CAP_6_REG | GEN & ID | number of interrupts for MSI vectors 24 to 27 | +| 0x05C | 1 | FUNC_CAP_7_REG | GEN & ID | number of interrupts for MSI vectors 28 to 31 | +| 0x060 | 1 | FUNC_CAP_8_REG | GEN & ID | | +| 0x064 | 7 | RSVD | GEN & ID | | +| 0x080 | 16 | RSVD | RSVD | | +| 0x0C0 | 1 | SCRTCH_0_REG | Scratchpad | Scratch Registers for SW use | +| 0x0C4 | 1 | SCRTCH_1_REG | Scratchpad | Scratch Registers for SW use | +| 0x0C8 | 1 | SCRTCH_2_REG | Scratchpad | Scratch Registers for SW use | +| 0x0CC | 1 | SCRTCH_3_REG | Scratchpad | Scratch Registers for SW use | +| 0x0D0 | 12 | RSVD | Scratchpad | 12 register reserved for scratch | +| 0x100 | 1 | DEV_MSI_0_PEND_REG | MSI INT | | +| 0x104 | 1 | RSVD | MSI INT | to extend DEV_MSI_PEND_REG | +| 0x108 | 1 | DEV_MSI_0_INT_EN_REG | MSI INT | | +| 0x10C | 1 | RSVD | MSI INT | to extend DEV_MSI_INT_EN_REG | +| 0x110 | 124 | RSVD | MSI INT | For other MSI Ctrl registers or INT vector registers | +| 0x300 | 1 | SPI_CMD_STAT_REG | SPI-flash | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x304 | 1 | SPI_ADD_REG | SPI-flash | Word address | +| 0x308 | 1 | SPI_WR_DATA_REG | SPI-flash | 32-bit data to be written in Configuration Flash Memory | +| 0x30C | 1 | SPI_RD_DATA_REG | SPI-flash | Holds read data form configuration Flash memory. | +| 0x310 | 1 | SPI_RST_REG | SPI-flash | Reset FPGA SPI module. | +| 0x314 | 1 | SEM_REG | SPI-flash | Semaphore Register | +| 0x318 | 10 | RSVD | RSVD | | +| 0x340 | 1 | SPI_CMD_STAT_REG | VSPI-Flash-PMC | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x344 | 1 | SPI_ADD_REG | VSPI-Flash-PMC | Word address | +| 0x348 | 1 | SPI_WR_DATA_REG | VSPI-Flash-PMC | 32-bit data to be written in Configuration Flash Memory | +| 0x34C | 1 | SPI_RD_DATA_REG | VSPI-Flash-PMC | Holds read data form configuration Flash memory. | +| 0x350 | 1 | SPI_RST_REG | VSPI-Flash-PMC | Reset VSPI-Flash module. | +| 0x354 | 11 | RSVD | RSVD | | +| 0x380 | 1 | SPI_CMD_STAT_REG | VSPI-Flash-ICB | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x384 | 1 | SPI_ADD_REG | VSPI-Flash-ICB | Word address | +| 0x388 | 1 | SPI_WR_DATA_REG | VSPI-Flash-ICB | 32-bit data to be written in Configuration Flash Memory | +| 0x38C | 1 | SPI_RD_DATA_REG | VSPI-Flash-ICB | Holds read data form configuration Flash memory. | +| 0x390 | 1 | SPI_RST_REG | VSPI-Flash-ICB | Reset VSPI-Flash module. | +| 0x394 | 11 | RSVD | RSVD | | +| 0x3C0 | 1 | SPI_CMD_STAT_REG | VSPI-Flash-SWB0 | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x3C4 | 1 | SPI_ADD_REG | VSPI-Flash-SWB0 | Word address | +| 0x3C8 | 1 | SPI_WR_DATA_REG | VSPI-Flash-SWB0 | 32-bit data to be written in Configuration Flash Memory | +| 0x3CC | 1 | SPI_RD_DATA_REG | VSPI-Flash-SWB0 | Holds read data form configuration Flash memory. | +| 0x3D0 | 1 | SPI_RST_REG | VSPI-Flash-SWB0 | Reset VSPI-Flash module. | +| 0x3D4 | 11 | RSVD | RSVD | | +| 0x400 | 1 | SPI_CMD_STAT_REG | VSPI-Flash-SWB1 | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x404 | 1 | SPI_ADD_REG | VSPI-Flash-SWB1 | Word address | +| 0x408 | 1 | SPI_WR_DATA_REG | VSPI-Flash-SWB1 | 32-bit data to be written in Configuration Flash Memory | +| 0x40C | 1 | SPI_RD_DATA_REG | VSPI-Flash-SWB1 | Holds read data form configuration Flash memory. | +| 0x410 | 1 | SPI_RST_REG | VSPI-Flash-SWB1 | Reset VSPI-Flash module. | +| 0x414 | 11 | RSVD | RSVD | | +| 0x440 | 128 | RSVD | RSVD | Reserved space for more VSPI-Flash channels | +| 0x640 | 1 | SPI_CMD_STAT_REG | VSPI-PMC | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x644 | 1 | SPI_ADD_REG | VSPI-PMC | Word address | +| 0x648 | 1 | SPI_WR_DATA_REG | VSPI-PMC | 32-bit data to be written in Configuration Flash Memory | +| 0x64C | 1 | SPI_RD_DATA_REG | VSPI-PMC | Holds read data form configuration Flash memory. | +| 0x650 | 1 | SPI_RST_REG | VSPI-PMC | Reset VSPI module. | +| 0x654 | 11 | RSVD | RSVD | | +| 0x680 | 1 | SPI_CMD_STAT_REG | VSPI-ICB | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x684 | 1 | SPI_ADD_REG | VSPI-ICB | Word address | +| 0x688 | 1 | SPI_WR_DATA_REG | VSPI-ICB | 32-bit data to be written in Configuration Flash Memory | +| 0x68C | 1 | SPI_RD_DATA_REG | VSPI-ICB | Holds read data form configuration Flash memory. | +| 0x690 | 1 | SPI_RST_REG | VSPI-ICB | Reset VSPI module. | +| 0x694 | 11 | RSVD | RSVD | | +| 0x6C0 | 1 | SPI_CMD_STAT_REG | VSPI-SWB0 | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x6C4 | 1 | SPI_ADD_REG | VSPI-SWB0 | Word address | +| 0x6C8 | 1 | SPI_WR_DATA_REG | VSPI-SWB0 | 32-bit data to be written in Configuration Flash Memory | +| 0x6CC | 1 | SPI_RD_DATA_REG | VSPI-SWB0 | Holds read data form configuration Flash memory. | +| 0x6D0 | 1 | SPI_RST_REG | VSPI-SWB0 | Reset VSPI module. | +| 0x6D4 | 11 | RSVD | RSVD | | +| 0x700 | 1 | SPI_CMD_STAT_REG | VSPI-SWB1 | Ready, NEW_CMD, Read, Write, Erase, Read Silicon Id, Illegal Erase, Illegal Write | +| 0x704 | 1 | SPI_ADD_REG | VSPI-SWB1 | Word address | +| 0x708 | 1 | SPI_WR_DATA_REG | VSPI-SWB1 | 32-bit data to be written in Configuration Flash Memory | +| 0x70C | 1 | SPI_RD_DATA_REG | VSPI-SWB1 | Holds read data form configuration Flash memory. | +| 0x710 | 1 | SPI_RST_REG | VSPI-SWB1 | Reset VSPI module. | +| 0x714 | 11 | RSVD | RSVD | | +| 0x740 | 64 | RSVD | RSVD | Reserved space for more VSPI channels | +| 0x840 | 1 | GEN_SPI_RD_DATA_REG | GEN-SPI-SWB0 | Generic SPI interface to SWB0, alternate route TH6 SPI flash | +| 0x844 | 1 | GEN_SPI_WR_DATA_REG | GEN-SPI-SWB0 | | +| 0x848 | 1 | GEN_SPI_STAT_REG | GEN-SPI-SWB0 | | +| 0x84C | 1 | GEN_SPI_CTRL_REG | GEN-SPI-SWB0 | | +| 0x850 | 1 | GEN_SPI_CFG_CTRL_REG | GEN-SPI-SWB0 | | +| 0x854 | 1 | GEN_SPI_SLV_REG | GEN-SPI-SWB0 | | +| 0x858 | 1 | SPI_RST_REG | GEN-SPI-SWB0 | | +| 0x85C | 1 | SEM_REG | GEN-SPI-SWB0 | | +| 0x860 | 8 | RSVD | GEN-SPI-SWB0 | | +| 0x880 | 1 | GEN_SPI_RD_DATA_REG | GEN-SPI-SWB1 | Generic SPI interface to SWB1, alternate route TH6 SPI flash | +| 0x884 | 1 | GEN_SPI_WR_DATA_REG | GEN-SPI-SWB1 | | +| 0x888 | 1 | GEN_SPI_STAT_REG | GEN-SPI-SWB1 | | +| 0x88C | 1 | GEN_SPI_CTRL_REG | GEN-SPI-SWB1 | | +| 0x890 | 1 | GEN_SPI_CFG_CTRL_REG | GEN-SPI-SWB1 | | +| 0x894 | 1 | GEN_SPI_SLV_REG | GEN-SPI-SWB1 | | +| 0x898 | 1 | SPI_RST_REG | GEN-SPI-SWB1 | | +| 0x89C | 1 | SEM_REG | GEN-SPI-SWB1 | | +| 0x8A0 | 8 | RSVD | GEN-SPI-SWB1 | | +| 0x8C0 | 64 | RSVD | RSVD | Reserved space for more SPI channels | +| 0x9C0 | 1 | MDIO_STAT_CMD_REG | MDIO-CH0 | To Retimer | +| 0x9C4 | 1 | MDIO_CTRL_REG | MDIO-CH0 | | +| 0x9C8 | 1 | MDIO_STK_CTRL_REG | MDIO-CH0 | | +| 0x9CC | 1 | MDIO_STK_ADDR_CONF_REG | MDIO-CH0 | | +| 0x9D0 | 1 | MDIO_STK_STAT_REG | MDIO-CH0 | | +| 0x9D4 | 1 | MDIO_STK_RAM_DATA_REG | MDIO-CH0 | | +| 0x9D8 | 1 | MDIO_STK_RAM_ADDR_REG | MDIO-CH0 | | +| 0x9DC | 1 | MDIO_STAT_INT_REG | MDIO-CH0 | | +| 0x9E0 | 128 | RSVD | RSVD | | + +#### CB — Function 3 + +| Offset | DW | Register | Group | Comment | +|---|---|---|---|---| +| 0x000 | 1 | FPGA_REV_ID_REG | GEN & ID | MCB FPGA revision & Id register | +| 0x004 | 1 | RSVD | GEN & ID | | +| 0x008 | 1 | RSVD | GEN & ID | | +| 0x00C | 13 | RSVD | GEN & ID | | +| 0x040 | 1 | FUNC_CAP_0_REG | GEN & ID | number of interrupts for MSI vectors 0 to 3 | +| 0x044 | 1 | FUNC_CAP_1_REG | GEN & ID | number of interrupts for MSI vectors 4 to 7 | +| 0x048 | 1 | FUNC_CAP_2_REG | GEN & ID | number of interrupts for MSI vectors 8 to 11 | +| 0x04C | 1 | FUNC_CAP_3_REG | GEN & ID | number of interrupts for MSI vectors 12 to 15 | +| 0x050 | 1 | FUNC_CAP_4_REG | GEN & ID | number of interrupts for MSI vectors 16 to 19 | +| 0x054 | 1 | FUNC_CAP_5_REG | GEN & ID | number of interrupts for MSI vectors 20 to 23 | +| 0x058 | 1 | FUNC_CAP_6_REG | GEN & ID | number of interrupts for MSI vectors 24 to 27 | +| 0x05C | 1 | FUNC_CAP_7_REG | GEN & ID | number of interrupts for MSI vectors 28 to 31 | +| 0x060 | 1 | FUNC_CAP_8_REG | GEN & ID | | +| 0x064 | 7 | RSVD | GEN & ID | | +| 0x080 | 16 | RSVD | RSVD | | +| 0x0C0 | 1 | SCRTCH_0_REG | Scratchpad | Scratch Registers for SW use | +| 0x0C4 | 1 | SCRTCH_1_REG | Scratchpad | Scratch Registers for SW use | +| 0x0C8 | 1 | SCRTCH_2_REG | Scratchpad | Scratch Registers for SW use | +| 0x0CC | 1 | SCRTCH_3_REG | Scratchpad | Scratch Registers for SW use | +| 0x0D0 | 12 | RSVD | Scratchpad | 12 register reserved for scratch | +| 0x100 | 1 | DEV_MSI_0_PEND_REG | MSI INT | | +| 0x104 | 1 | RSVD | MSI INT | to extend DEV_MSI_PEND_REG | +| 0x108 | 1 | DEV_MSI_0_INT_EN_REG | MSI INT | | +| 0x10C | 1 | RSVD | MSI INT | to extend DEV_MSI_INT_EN_REG | +| 0x110 | 124 | RSVD | MSI INT | For other MSI Ctrl registers or INT vector registers | +| 0x300 | 1 | I2C_PRSCL_LO_REG | I2C-Ch0 | SWB_0 1) M0 - 4ch I2C MUX TCA9546 (0xE8/0xE9) 2) M0.C0 Temp Sensor TPM432 (0x98/0x99) 3) M0.C1 Temp Sensor TPM432 (0x98/0x99) 4) M0.C2 Temp Sensor TPM432 (0x98/0x99) | +| 0x304 | 1 | I2C_PRSCL_HI_REG | I2C-Ch0 | | +| 0x308 | 1 | I2C_CTRL_REG | I2C-Ch0 | | +| 0x30C | 0 | I2C_TX_REG | I2C-Ch0 | | +| 0x30C | 1 | I2C_RX_REG | I2C-Ch0 | | +| 0x310 | 0 | I2C_CMD_REG | I2C-Ch0 | | +| 0x310 | 1 | I2C_STAT_REG | I2C-Ch0 | | +| 0x314 | 1 | I2C_MUX_SEL_REG | I2C-Ch0 | | +| 0x318 | 1 | I2C_RST_REG | I2C-Ch0 | | +| 0x31C | 1 | SEM_REG | I2C-Ch0 | | +| 0x320 | 1 | I2C_PRSCL_LO_REG | I2C-Ch1 | SWB_1 1) M0 - 4ch I2C MUX TCA9546 (0xE8/0xE9) 2) M0.C0 Temp Sensor TPM432 (0x98/0x99) 3) M0.C1 Temp Sensor TPM432 (0x98/0x99) 4) M0.C2 Temp Sensor TPM432 (0x98/0x99) | +| 0x324 | 1 | I2C_PRSCL_HI_REG | I2C-Ch1 | | +| 0x328 | 1 | I2C_CTRL_REG | I2C-Ch1 | | +| 0x32C | 0 | I2C_TX_REG | I2C-Ch1 | | +| 0x32C | 1 | I2C_RX_REG | I2C-Ch1 | | +| 0x330 | 0 | I2C_CMD_REG | I2C-Ch1 | | +| 0x330 | 1 | I2C_STAT_REG | I2C-Ch1 | | +| 0x334 | 1 | I2C_MUX_SEL_REG | I2C-Ch1 | | +| 0x338 | 1 | I2C_RST_REG | I2C-Ch1 | | +| 0x33C | 1 | SEM_REG | I2C-Ch1 | | +| 0x340 | 1 | I2C_PRSCL_LO_REG | I2C-Ch2 | SWB_0 1) SWB_FPGA - FPGA (0x80/0x81) 2) IO Exp - PCA9555 (0x48/0x49) | +| 0x344 | 1 | I2C_PRSCL_HI_REG | I2C-Ch2 | | +| 0x348 | 1 | I2C_CTRL_REG | I2C-Ch2 | | +| 0x34C | 0 | I2C_TX_REG | I2C-Ch2 | | +| 0x34C | 1 | I2C_RX_REG | I2C-Ch2 | | +| 0x350 | 0 | I2C_CMD_REG | I2C-Ch2 | | +| 0x350 | 1 | I2C_STAT_REG | I2C-Ch2 | | +| 0x354 | 1 | I2C_MUX_SEL_REG | I2C-Ch2 | | +| 0x358 | 1 | I2C_RST_REG | I2C-Ch2 | | +| 0x35C | 1 | SEM_REG | I2C-Ch2 | | +| 0x360 | 1 | I2C_PRSCL_LO_REG | I2C-Ch3 | SWB_1 1) SWB_FPGA - FPGA (0x80/0x81) 2) IO Exp - PCA9555 (0x48/0x49) | +| 0x364 | 1 | I2C_PRSCL_HI_REG | I2C-Ch3 | | +| 0x368 | 1 | I2C_CTRL_REG | I2C-Ch3 | | +| 0x36C | 0 | I2C_TX_REG | I2C-Ch3 | | +| 0x36C | 1 | I2C_RX_REG | I2C-Ch3 | | +| 0x370 | 0 | I2C_CMD_REG | I2C-Ch3 | | +| 0x370 | 1 | I2C_STAT_REG | I2C-Ch3 | | +| 0x374 | 1 | I2C_MUX_SEL_REG | I2C-Ch3 | | +| 0x378 | 1 | I2C_RST_REG | I2C-Ch3 | | +| 0x37C | 1 | SEM_REG | I2C-Ch3 | | +| 0x380 | 1 | I2C_PRSCL_LO_REG | I2C-Ch4 | SWB_0 1) M1 4ch I2C MUX TCA9546 (0xE8/0xE9) 2) M1.C0 Clk GEN - SI5363A (0xB0/0xB1) Clk GEN - SI5363A (0xB2/0xB3) Tray Catridge - EEPROM (0xA0/0xA1) 3) M1.C1 Clk GEN - SI5363A (0xB4/0xB5) Clk GEN - SI5363A (0xB6/0xB7) Clk GEN - SI5363A (0xB8/0xB9) Tray Catridge - EEPROM (0xA0/0xA1) 4) M1.C2 SWB EEPROM (0xA0/0xA1) | +| 0x384 | 1 | I2C_PRSCL_HI_REG | I2C-Ch4 | | +| 0x388 | 1 | I2C_CTRL_REG | I2C-Ch4 | | +| 0x38C | 0 | I2C_TX_REG | I2C-Ch4 | | +| 0x38C | 1 | I2C_RX_REG | I2C-Ch4 | | +| 0x390 | 0 | I2C_CMD_REG | I2C-Ch4 | | +| 0x390 | 1 | I2C_STAT_REG | I2C-Ch4 | | +| 0x394 | 1 | I2C_MUX_SEL_REG | I2C-Ch4 | | +| 0x398 | 1 | I2C_RST_REG | I2C-Ch4 | | +| 0x39C | 1 | SEM_REG | I2C-Ch4 | | +| 0x3A0 | 1 | I2C_PRSCL_LO_REG | I2C-Ch5 | SWB_1 1) M1 4ch I2C MUX TCA9546 (0xE8/0xE9) 2) M1.C0 Clk GEN - SI5363A (0xB0/0xB1) Clk GEN - SI5363A (0xB2/0xB3) Tray Catridge - EEPROM (0xA0/0xA1) 3) M1.C1 Clk GEN - SI5363A (0xB4/0xB5) Clk GEN - SI5363A (0xB6/0xB7) Clk GEN - SI5363A (0xB8/0xB9) Tray Catridge - EEPROM (0xA0/0xA1) 4) M1.C2 SWB EEPROM (0xA0/0xA1) | +| 0x3A4 | 1 | I2C_PRSCL_HI_REG | I2C-Ch5 | | +| 0x3A8 | 1 | I2C_CTRL_REG | I2C-Ch5 | | +| 0x3AC | 0 | I2C_TX_REG | I2C-Ch5 | | +| 0x3AC | 1 | I2C_RX_REG | I2C-Ch5 | | +| 0x3B0 | 0 | I2C_CMD_REG | I2C-Ch5 | | +| 0x3B0 | 1 | I2C_STAT_REG | I2C-Ch5 | | +| 0x3B4 | 1 | I2C_MUX_SEL_REG | I2C-Ch5 | | +| 0x3B8 | 1 | I2C_RST_REG | I2C-Ch5 | | +| 0x3BC | 1 | SEM_REG | I2C-Ch5 | | +| 0x3C0 | 1 | I2C_PRSCL_LO_REG | I2C-Ch6 | SWB_0 1) VRM - M29816 (0x40/0x41) 2) VRM - M2985B (0x42/0x43) 3) VRM - M2985B (0x44/0x45) 4) VRM - M2985B (0x46/0x47) 5) VRM - M2985B (0x48/0x49) | +| 0x3C4 | 1 | I2C_PRSCL_HI_REG | I2C-Ch6 | | +| 0x3C8 | 1 | I2C_CTRL_REG | I2C-Ch6 | | +| 0x3CC | 0 | I2C_TX_REG | I2C-Ch6 | | +| 0x3CC | 1 | I2C_RX_REG | I2C-Ch6 | | +| 0x3D0 | 0 | I2C_CMD_REG | I2C-Ch6 | | +| 0x3D0 | 1 | I2C_STAT_REG | I2C-Ch6 | | +| 0x3D4 | 1 | I2C_MUX_SEL_REG | I2C-Ch6 | | +| 0x3D8 | 1 | I2C_RST_REG | I2C-Ch6 | | +| 0x3DC | 1 | SEM_REG | I2C-Ch6 | | +| 0x3E0 | 1 | I2C_PRSCL_LO_REG | I2C-Ch7 | SWB_1 1) VRM - M29816 (0x40/0x41) 2) VRM - M2985B (0x42/0x43) 3) VRM - M2985B (0x44/0x45) 4) VRM - M2985B (0x46/0x47) 5) VRM - M2985B (0x48/0x49) | +| 0x3E4 | 1 | I2C_PRSCL_HI_REG | I2C-Ch7 | | +| 0x3E8 | 1 | I2C_CTRL_REG | I2C-Ch7 | | +| 0x3EC | 0 | I2C_TX_REG | I2C-Ch7 | | +| 0x3EC | 1 | I2C_RX_REG | I2C-Ch7 | | +| 0x3F0 | 0 | I2C_CMD_REG | I2C-Ch7 | | +| 0x3F0 | 1 | I2C_STAT_REG | I2C-Ch7 | | +| 0x3F4 | 1 | I2C_MUX_SEL_REG | I2C-Ch7 | | +| 0x3F8 | 1 | I2C_RST_REG | I2C-Ch7 | | +| 0x3FC | 1 | SEM_REG | I2C-Ch7 | | +| 0x400 | 1 | I2C_PRSCL_LO_REG | I2C-Ch8 | SWB_0 1) VRM - M2985B (0x4A/0x4B) 2) VRM - M2985B (0x4C/0x4D) 3) VRM - M2985B (0x4E/0x4F) 4) VRM - M2985B (0x50/0x51) 5) VRM - M2985B (0x52/0x53) | +| 0x404 | 1 | I2C_PRSCL_HI_REG | I2C-Ch8 | | +| 0x408 | 1 | I2C_CTRL_REG | I2C-Ch8 | | +| 0x40C | 0 | I2C_TX_REG | I2C-Ch8 | | +| 0x40C | 1 | I2C_RX_REG | I2C-Ch8 | | +| 0x410 | 0 | I2C_CMD_REG | I2C-Ch8 | | +| 0x410 | 1 | I2C_STAT_REG | I2C-Ch8 | | +| 0x414 | 1 | I2C_MUX_SEL_REG | I2C-Ch8 | | +| 0x418 | 1 | I2C_RST_REG | I2C-Ch8 | | +| 0x41C | 1 | SEM_REG | I2C-Ch8 | | +| 0x420 | 1 | I2C_PRSCL_LO_REG | I2C-Ch9 | SWB_1 1) VRM - M2985B (0x4A/0x4B) 2) VRM - M2985B (0x4C/0x4D) 3) VRM - M2985B (0x4E/0x4F) 4) VRM - M2985B (0x50/0x51) 5) VRM - M2985B (0x52/0x53) | +| 0x424 | 1 | I2C_PRSCL_HI_REG | I2C-Ch9 | | +| 0x428 | 1 | I2C_CTRL_REG | I2C-Ch9 | | +| 0x42C | 0 | I2C_TX_REG | I2C-Ch9 | | +| 0x42C | 1 | I2C_RX_REG | I2C-Ch9 | | +| 0x430 | 0 | I2C_CMD_REG | I2C-Ch9 | | +| 0x430 | 1 | I2C_STAT_REG | I2C-Ch9 | | +| 0x434 | 1 | I2C_MUX_SEL_REG | I2C-Ch9 | | +| 0x438 | 1 | I2C_RST_REG | I2C-Ch9 | | +| 0x43C | 1 | SEM_REG | I2C-Ch9 | | +| 0x440 | 1 | I2C_PRSCL_LO_REG | I2C-Ch10 | 1) M0 2ch I2C MUX - TCA9543 (0xE1/0xE0) 2) M0.C0 Clk Buf - 9DBL0452 (0xD6/0xD7) M0.C0 Clk Buf - 9DBL0452 (0xDA/0xDB) 3) M1.C1 Fan Ctrl - MAX31790 (0x40/0x41) Temp Sensor - TMP75 (0x90/0x91) Temp Sensor - TMP75 (0x92/0x93) Temp Sensor - TM432 (0x98/0x99) | +| 0x444 | 1 | I2C_PRSCL_HI_REG | I2C-Ch10 | | +| 0x448 | 1 | I2C_CTRL_REG | I2C-Ch10 | | +| 0x44C | 0 | I2C_TX_REG | I2C-Ch10 | | +| 0x44C | 1 | I2C_RX_REG | I2C-Ch10 | | +| 0x450 | 0 | I2C_CMD_REG | I2C-Ch10 | | +| 0x450 | 1 | I2C_STAT_REG | I2C-Ch10 | | +| 0x454 | 1 | I2C_MUX_SEL_REG | I2C-Ch10 | | +| 0x458 | 1 | I2C_RST_REG | I2C-Ch10 | | +| 0x45C | 1 | SEM_REG | I2C-Ch10 | | +| 0x460 | 1 | I2C_PRSCL_LO_REG | I2C-Ch11 | 1) Fan Ctrl - MAX31790 (0x40/0x41) | +| 0x464 | 1 | I2C_PRSCL_HI_REG | I2C-Ch11 | | +| 0x468 | 1 | I2C_CTRL_REG | I2C-Ch11 | | +| 0x46C | 0 | I2C_TX_REG | I2C-Ch11 | | +| 0x46C | 1 | I2C_RX_REG | I2C-Ch11 | | +| 0x470 | 0 | I2C_CMD_REG | I2C-Ch11 | | +| 0x470 | 1 | I2C_STAT_REG | I2C-Ch11 | | +| 0x474 | 1 | I2C_MUX_SEL_REG | I2C-Ch11 | | +| 0x478 | 1 | I2C_RST_REG | I2C-Ch11 | | +| 0x47C | 1 | SEM_REG | I2C-Ch11 | | +| 0x480 | 1 | I2C_PRSCL_LO_REG | I2C-Ch12 | 1) ADC leakage - ADC128D818 (0x3E/0x3F) | +| 0x484 | 1 | I2C_PRSCL_HI_REG | I2C-Ch12 | | +| 0x488 | 1 | I2C_CTRL_REG | I2C-Ch12 | | +| 0x48C | 0 | I2C_TX_REG | I2C-Ch12 | | +| 0x48C | 1 | I2C_RX_REG | I2C-Ch12 | | +| 0x490 | 0 | I2C_CMD_REG | I2C-Ch12 | | +| 0x490 | 1 | I2C_STAT_REG | I2C-Ch12 | | +| 0x494 | 1 | I2C_MUX_SEL_REG | I2C-Ch12 | | +| 0x498 | 1 | I2C_RST_REG | I2C-Ch12 | | +| 0x49C | 1 | SEM_REG | I2C-Ch12 | | +| 0x4A0 | 1 | I2C_PRSCL_LO_REG | I2C-Ch13 | 1) NFC SM-MFAD4-C02 (0x50/0x51) | +| 0x4A4 | 1 | I2C_PRSCL_HI_REG | I2C-Ch13 | | +| 0x4A8 | 1 | I2C_CTRL_REG | I2C-Ch13 | | +| 0x4AC | 0 | I2C_TX_REG | I2C-Ch13 | | +| 0x4AC | 1 | I2C_RX_REG | I2C-Ch13 | | +| 0x4B0 | 0 | I2C_CMD_REG | I2C-Ch13 | | +| 0x4B0 | 1 | I2C_STAT_REG | I2C-Ch13 | | +| 0x4B4 | 1 | I2C_MUX_SEL_REG | I2C-Ch13 | | +| 0x4B8 | 1 | I2C_RST_REG | I2C-Ch13 | | +| 0x4BC | 1 | SEM_REG | I2C-Ch13 | | +| 0x4C0 | 1 | I2C_PRSCL_LO_REG | I2C-Ch14 | 1) M1 2ch I2C MUX - TCA9543 (0xE1/0xE0) 2) M1.C0 QSFP28.P1 Xcvr (0xA1/0xA0) 3) M1.C1 QSFP28.P2 Xcvr (0xA1/0xA0) | +| 0x4C4 | 1 | I2C_PRSCL_HI_REG | I2C-Ch14 | | +| 0x4C8 | 1 | I2C_CTRL_REG | I2C-Ch14 | | +| 0x4CC | 0 | I2C_TX_REG | I2C-Ch14 | | +| 0x4CC | 1 | I2C_RX_REG | I2C-Ch14 | | +| 0x4D0 | 0 | I2C_CMD_REG | I2C-Ch14 | | +| 0x4D0 | 1 | I2C_STAT_REG | I2C-Ch14 | | +| 0x4D4 | 1 | I2C_MUX_SEL_REG | I2C-Ch14 | | +| 0x4D8 | 1 | I2C_RST_REG | I2C-Ch14 | | +| 0x4DC | 1 | SEM_REG | I2C-Ch14 | | +| 0x4E0 | 1 | I2C_PRSCL_LO_REG | I2C-Ch15 | 1) Fan1 EFUSE - STEF48H28 (0x20/0x21) 2) Fan2 EFUSE - STEF48H28 (0x22/0x23) 3) Fan3 EFUSE - STEF48H28 (0x80/0x81) | +| 0x4E4 | 1 | I2C_PRSCL_HI_REG | I2C-Ch15 | | +| 0x4E8 | 1 | I2C_CTRL_REG | I2C-Ch15 | | +| 0x4EC | 0 | I2C_TX_REG | I2C-Ch15 | | +| 0x4EC | 1 | I2C_RX_REG | I2C-Ch15 | | +| 0x4F0 | 0 | I2C_CMD_REG | I2C-Ch15 | | +| 0x4F0 | 1 | I2C_STAT_REG | I2C-Ch15 | | +| 0x4F4 | 1 | I2C_MUX_SEL_REG | I2C-Ch15 | | +| 0x4F8 | 1 | I2C_RST_REG | I2C-Ch15 | | +| 0x4FC | 1 | SEM_REG | I2C-Ch15 | | +| 0x500 | 1 | I2C_PRSCL_LO_REG | I2C-Ch16 | 1) 1G PHY - I210 Ethernet Controller (0x92/0x93) | +| 0x504 | 1 | I2C_PRSCL_HI_REG | I2C-Ch16 | | +| 0x508 | 1 | I2C_CTRL_REG | I2C-Ch16 | | +| 0x50C | 0 | I2C_TX_REG | I2C-Ch16 | | +| 0x50C | 1 | I2C_RX_REG | I2C-Ch16 | | +| 0x510 | 0 | I2C_CMD_REG | I2C-Ch16 | | +| 0x510 | 1 | I2C_STAT_REG | I2C-Ch16 | | +| 0x514 | 1 | I2C_MUX_SEL_REG | I2C-Ch16 | | +| 0x518 | 1 | I2C_RST_REG | I2C-Ch16 | | +| 0x51C | 1 | SEM_REG | I2C-Ch16 | | +| 0x520 | 1 | I2C_PRSCL_LO_REG | I2C-Ch17 | 1) Chassis EEPROM (0x50/0x51/0x52/0x53) 2) Diag EEPROM (0x57) 3) MGIN CHIP1- (0xB8/0xB9) MGIN CHIP2- (0xBC/0xBD) MGIN CHIP3- (0xC4/0xC5) MGIN CHIP4- (0xC8/0xC9) | +| 0x524 | 1 | I2C_PRSCL_HI_REG | I2C-Ch17 | | +| 0x528 | 1 | I2C_CTRL_REG | I2C-Ch17 | | +| 0x52C | 0 | I2C_TX_REG | I2C-Ch17 | | +| 0x52C | 1 | I2C_RX_REG | I2C-Ch17 | | +| 0x530 | 0 | I2C_CMD_REG | I2C-Ch17 | | +| 0x530 | 1 | I2C_STAT_REG | I2C-Ch17 | | +| 0x534 | 1 | I2C_MUX_SEL_REG | I2C-Ch17 | | +| 0x538 | 1 | I2C_RST_REG | I2C-Ch17 | | +| 0x53C | 1 | SEM_REG | I2C-Ch17 | | +| 0x540 | 144 | RSVD | RSVD | | +| 0x780 | 1 | I2C_PRSCL_LO_REG | VI2C-ICB-Ch0 | Mapped to ICBX_X VI2C_DEV_ID 8'h21 | +| 0x784 | 1 | I2C_PRSCL_HI_REG | VI2C-ICB-Ch0 | 1) PDB Fan Controller | +| 0x788 | 1 | I2C_CTRL_REG | VI2C-ICB-Ch0 | | +| 0x78C | 0 | I2C_TX_REG | VI2C-ICB-Ch0 | | +| 0x78C | 1 | I2C_RX_REG | VI2C-ICB-Ch0 | | +| 0x790 | 0 | I2C_CMD_REG | VI2C-ICB-Ch0 | | +| 0x790 | 1 | I2C_STAT_REG | VI2C-ICB-Ch0 | | +| 0x794 | 1 | I2C_MUX_SEL_REG | VI2C-ICB-Ch0 | | +| 0x798 | 1 | I2C_RST_REG | VI2C-ICB-Ch0 | | +| 0x79C | 1 | RSVD | VI2C-ICB-Ch0 | | +| 0x7A0 | 1 | I2C_PRSCL_LO_REG | VI2C-ICB-Ch1 | Mapped to ICBX_X VI2C_DEV_ID 8'h23 | +| 0x7A4 | 1 | I2C_PRSCL_HI_REG | VI2C-ICB-Ch1 | 1) PDB EEPROM | +| 0x7A8 | 1 | I2C_CTRL_REG | VI2C-ICB-Ch1 | | +| 0x7AC | 0 | I2C_TX_REG | VI2C-ICB-Ch1 | | +| 0x7AC | 1 | I2C_RX_REG | VI2C-ICB-Ch1 | | +| 0x7B0 | 0 | I2C_CMD_REG | VI2C-ICB-Ch1 | | +| 0x7B0 | 1 | I2C_STAT_REG | VI2C-ICB-Ch1 | | +| 0x7B4 | 1 | I2C_MUX_SEL_REG | VI2C-ICB-Ch1 | | +| 0x7B8 | 1 | I2C_RST_REG | VI2C-ICB-Ch1 | | +| 0x7BC | 1 | RSVD | VI2C-ICB-Ch1 | | +| 0x7C0 | 1 | I2C_PRSCL_LO_REG | VI2C-ICB-Ch2 | Mapped to ICBX_X VI2C_DEV_ID 8'h25 | +| 0x7C4 | 1 | I2C_PRSCL_HI_REG | VI2C-ICB-Ch2 | 1) PDB external temperature sensors | +| 0x7C8 | 1 | I2C_CTRL_REG | VI2C-ICB-Ch2 | | +| 0x7CC | 0 | I2C_TX_REG | VI2C-ICB-Ch2 | | +| 0x7CC | 1 | I2C_RX_REG | VI2C-ICB-Ch2 | | +| 0x7D0 | 0 | I2C_CMD_REG | VI2C-ICB-Ch2 | | +| 0x7D0 | 1 | I2C_STAT_REG | VI2C-ICB-Ch2 | | +| 0x7D4 | 1 | I2C_MUX_SEL_REG | VI2C-ICB-Ch2 | | +| 0x7D8 | 1 | I2C_RST_REG | VI2C-ICB-Ch2 | | +| 0x7DC | 1 | RSVD | VI2C-ICB-Ch2 | | +| 0x7E0 | 1 | I2C_PRSCL_LO_REG | VI2C-ICB-Ch3 | Mapped to ICBX_X VI2C_DEV_ID 8'h27 | +| 0x7E4 | 1 | I2C_PRSCL_HI_REG | VI2C-ICB-Ch3 | 1) Hotswap controller | +| 0x7E8 | 1 | I2C_CTRL_REG | VI2C-ICB-Ch3 | | +| 0x7EC | 0 | I2C_TX_REG | VI2C-ICB-Ch3 | | +| 0x7EC | 1 | I2C_RX_REG | VI2C-ICB-Ch3 | | +| 0x7F0 | 0 | I2C_CMD_REG | VI2C-ICB-Ch3 | | +| 0x7F0 | 1 | I2C_STAT_REG | VI2C-ICB-Ch3 | | +| 0x7F4 | 1 | I2C_MUX_SEL_REG | VI2C-ICB-Ch3 | | +| 0x7F8 | 1 | I2C_RST_REG | VI2C-ICB-Ch3 | | +| 0x7FC | 1 | RSVD | VI2C-ICB-Ch3 | | +| 0x800 | 1 | I2C_PRSCL_LO_REG | VI2C-ICB-Ch4 | Mapped to ICBX_X VI2C_DEV_ID 8'h29 | +| 0x804 | 1 | I2C_PRSCL_HI_REG | VI2C-ICB-Ch4 | 1) Power bricks and EFUSE | +| 0x808 | 1 | I2C_CTRL_REG | VI2C-ICB-Ch4 | | +| 0x80C | 0 | I2C_TX_REG | VI2C-ICB-Ch4 | | +| 0x80C | 1 | I2C_RX_REG | VI2C-ICB-Ch4 | | +| 0x810 | 0 | I2C_CMD_REG | VI2C-ICB-Ch4 | | +| 0x810 | 1 | I2C_STAT_REG | VI2C-ICB-Ch4 | | +| 0x814 | 1 | I2C_MUX_SEL_REG | VI2C-ICB-Ch4 | | +| 0x818 | 1 | I2C_RST_REG | VI2C-ICB-Ch4 | | +| 0x81C | 1 | RSVD | VI2C-ICB-Ch4 | | +| 0x820 | 1 | RSVD | RSVD | | + +### SWB — Switch Board + +#### SWB — Function none + +| Offset | DW | Register | Group | Comment | +|---|---|---|---|---| +| 0x000 | 1 | FPGA_REV_ID_REG | GEN & ID | | +| 0x004 | 1 | RSVD | GEN & ID | | +| 0x008 | 1 | RSVD | GEN & ID | | +| 0x00C | 1 | SWB_INFO_REG | GEN & ID | | +| 0x010 | 1 | RSVD | GEN & ID | | +| 0x014 | 11 | RSVD | GEN & ID | | +| 0x040 | 16 | RSVD | GEN & ID | | +| 0x080 | 1 | FPGA_RECONFIG_CTRL_REG | FPGA Reconfig | | +| 0x084 | 1 | FPGA_RECONFIG_STAT_REG | FPGA Reconfig | | +| 0x088 | 6 | RSVD | FPGA Reconfig | | +| 0x0A0 | 1 | RSVD | FPGA Reconfig | | +| 0x0A4 | 1 | RSVD | FPGA Reconfig | | +| 0x0A8 | 6 | RSVD | FPGA Reconfig | | +| 0x0C0 | 1 | SCRTCH_0_REG | Scratchpad | | +| 0x0C4 | 1 | SCRTCH_1_REG | Scratchpad | | +| 0x0C8 | 1 | SCRTCH_2_REG | Scratchpad | | +| 0x0CC | 1 | SCRTCH_3_REG | Scratchpad | | +| 0x0D0 | 12 | RSVD | Scratchpad | | +| 0x100 | 96 | RSVD | MSI INT | | +| 0x280 | 32 | RSVD | Mailbox | | +| 0x300 | 1 | RSVD | Power | | +| 0x304 | 1 | PWR_STAT_REG | Power | | +| 0x308 | 1 | PWR_STAT_PLRTY_REG | Power | | +| 0x30C | 1 | PWR_STAT_EDG_LVL_REG | Power | | +| 0x310 | 1 | PWR_STAT_INT_EN_REG | Power | | +| 0x314 | 1 | PWR_STAT_INT_STAT_REG | Power | | +| 0x318 | 1 | PWR_STAT_INT_CLR_REG | Power | | +| 0x31C | 1 | SEM_REG | Power | | +| 0x320 | 8 | RSVD | Power | | +| 0x340 | 1 | RSVD | Speed Sense | | +| 0x344 | 1 | RSVD | Speed Sense | | +| 0x348 | 14 | RSVD | Speed Sense | | +| 0x380 | 1 | CB_CTRL_REG | CB | | +| 0x384 | 1 | CB_STAT_REG | CB | 384 | +| 0x388 | 1 | CB_STAT_PLRTY_REG | CB | | +| 0x38C | 1 | CB_STAT_EDG_LVL_REG | CB | | +| 0x390 | 1 | CB_STAT_INT_EN_REG | CB | | +| 0x394 | 1 | CB_STAT_INT_STAT_REG | CB | | +| 0x398 | 1 | CB_STAT_INT_CLR_REG | CB | | +| 0x39C | 1 | SEM_REG | CB | | +| 0x3A0 | 8 | RSVD | CB | | +| 0x3C0 | 1 | ASIC_CTRL_REG | ASIC | | +| 0x3C4 | 1 | ASIC_STAT_REG | ASIC | | +| 0x3C8 | 1 | ASIC_STAT_PLRTY_REG | ASIC | | +| 0x3CC | 1 | ASIC_STAT_EDG_LVL_REG | ASIC | | +| 0x3D0 | 1 | ASIC_STAT_INT_EN_REG | ASIC | | +| 0x3D4 | 1 | ASIC_STAT_INT_STAT_REG | ASIC | | +| 0x3D8 | 1 | ASIC_STAT_INT_CLR_REG | ASIC | | +| 0x3DC | 1 | SEM_REG | ASIC | | +| 0x3E0 | 8 | RSVD | ASIC | | +| 0x400 | 1 | RTM_CTRL_REG | Retimer | | +| 0x404 | 1 | RSVD | Retimer | | +| 0x408 | 1 | RSVD | Retimer | | +| 0x40C | 1 | RSVD | Retimer | | +| 0x410 | 1 | RSVD | Retimer | | +| 0x414 | 1 | RSVD | Retimer | | +| 0x418 | 1 | RSVD | Retimer | | +| 0x41C | 1 | RSVD | Retimer | | +| 0x420 | 8 | RSVD | Retimer | | +| 0x440 | 1 | RSVD | Thermal | | +| 0x444 | 1 | THRM_STAT_REG | Thermal | | +| 0x448 | 1 | THRM_STAT_PLRTY_REG | Thermal | | +| 0x44C | 1 | THRM_STAT_EDG_LVL_REG | Thermal | | +| 0x450 | 1 | THRM_STAT_INT_EN_REG | Thermal | | +| 0x454 | 1 | THRM_STAT_INT_STAT_REG | Thermal | | +| 0x458 | 1 | THRM_STAT_INT_CLR_REG | Thermal | | +| 0x45C | 1 | SEM_REG | Thermal | | +| 0x460 | 8 | RSVD | Thermal | | +| 0x480 | 128 | RSVD | RSVD | | +| 0x680 | 1 | RSVD | Other Dev ctrl-stat-int | 680 | +| 0x684 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x688 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x68C | 1 | EN_ACCSS_PRTCTD_REG | Other Dev ctrl-stat-int | | +| 0x690 | 12 | I2C_MUX_RST_REG | Other Dev ctrl-stat-int | | +| 0x6C0 | 1 | SPI_MUX_REG | Other Dev ctrl-stat-int | | +| 0x6C4 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x6C8 | 270 | RSVD | RSVD | | +| 0xB00 | 1 | FLSH_CTRL_REG | Flash Write Protect | | +| 0xB04 | 31 | RSVD | Flash Write Protect | | +| 0xB80 | 32 | RSVD | LED | | +| 0xC00 | 1 | RSVD | Debug & Test | | +| 0xC04 | 1 | RSVD | Debug & Test | | +| 0xC08 | 1 | TND_PWR_CTRL_0_REG | Debug & Test | | +| 0xC0C | 1 | TND_PWR_CTRL_1_REG | Debug & Test | | +| 0xC10 | 1 | TND_PWR_STAT_0_REG | Debug & Test | | +| 0xC14 | 1 | TND_PWR_STAT_1_REG | Debug & Test | | +| 0xC18 | 1 | TND_PWR_STAT_2_REG | Debug & Test | | +| 0xC1C | 1 | TND_PWR_STAT_3_REG | Debug & Test | | +| 0xC20 | 1 | TND_CB_GPIO_CTRL_REG | Debug & Test | | +| 0xC24 | 1 | TND_CB_GPIO_STAT_REG | Debug & Test | | +| 0xC28 | 1 | TND_CB_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC2C | 89 | RSVD | Debug & Test | | +| 0xD90 | 1 | RST_CAUSE_REG | Reset Stat | | +| 0xD94 | 31 | RSVD | Reset Stat | | +| 0xE10 | 56 | RSVD | RSVD | | + +### ICB — PDB / Power Distribution Board + +#### ICB — Function none + +| Offset | DW | Register | Group | Comment | +|---|---|---|---|---| +| 0x000 | 1 | FPGA_REV_ID_REG | GEN & ID | ICB_BP FPGA revision & Id register | +| 0x004 | 1 | RSVD | GEN & ID | | +| 0x008 | 1 | RSVD | GEN & ID | | +| 0x00C | 1 | RSVD | GEN & ID | | +| 0x010 | 28 | RSVD | GEN & ID | | +| 0x080 | 1 | FPGA_RECONFIG_CTRL_REG | FPGA Reconfig | | +| 0x084 | 1 | FPGA_RECONFIG_STAT_REG | FPGA Reconfig | | +| 0x088 | 14 | RSVD | FPGA Reconfig | | +| 0x0C0 | 1 | SCRTCH_0_REG | Scratchpad | | +| 0x0C4 | 1 | SCRTCH_1_REG | Scratchpad | | +| 0x0C8 | 1 | SCRTCH_2_REG | Scratchpad | | +| 0x0CC | 1 | SCRTCH_3_REG | Scratchpad | | +| 0x0D0 | 12 | RSVD | Scratchpad | | +| 0x100 | 96 | RSVD | MSI INT | | +| 0x280 | 32 | RSVD | Mailbox | | +| 0x300 | 1 | PWR_CTRL_REG | Power ctrl-stat-int | | +| 0x304 | 1 | PWR_STAT_REG | Power ctrl-stat-int | | +| 0x308 | 1 | PWR_STAT_PLRTY_REG | Power ctrl-stat-int | | +| 0x30C | 1 | PWR_STAT_EDG_LVL_REG | Power ctrl-stat-int | | +| 0x310 | 1 | PWR_STAT_INT_EN_REG | Power ctrl-stat-int | | +| 0x314 | 1 | PWR_STAT_INT_STAT_REG | Power ctrl-stat-int | | +| 0x318 | 1 | PWR_STAT_INT_CLR_REG | Power ctrl-stat-int | | +| 0x31C | 1 | SEM_REG | Power ctrl-stat-int | | +| 0x320 | 8 | RSVD | Power ctrl-stat-int | | +| 0x340 | 1 | FAN_CTRL_REG | Fan ctrl-stat-int | | +| 0x344 | 1 | FAN_STAT_REG | Fan ctrl-stat-int | | +| 0x348 | 1 | FAN_STAT_PLRTY_REG | Fan ctrl-stat-int | | +| 0x34C | 1 | FAN_STAT_EDG_LVL_REG | Fan ctrl-stat-int | | +| 0x350 | 1 | FAN_STAT_INT_EN_REG | Fan ctrl-stat-int | | +| 0x354 | 1 | FAN_STAT_INT_STAT_REG | Fan ctrl-stat-int | | +| 0x358 | 1 | FAN_STAT_INT_CLR_REG | Fan ctrl-stat-int | | +| 0x35C | 1 | SEM_REG | Fan ctrl-stat-int | | +| 0x360 | 1 | RSVD | Thermal | | +| 0x364 | 1 | THRM_STAT_REG | Thermal | | +| 0x368 | 1 | THRM_STAT_PLRTY_REG | Thermal | | +| 0x36C | 1 | THRM_STAT_EDG_LVL_REG | Thermal | | +| 0x370 | 1 | THRM_STAT_INT_EN_REG | Thermal | | +| 0x374 | 1 | THRM_STAT_INT_STAT_REG | Thermal | | +| 0x378 | 1 | THRM_STAT_INT_CLR_REG | Thermal | | +| 0x37C | 1 | SEM_REG | Thermal | | +| 0x380 | 8 | RSVD | Thermal | | +| 0x3A0 | 184 | RSVD | RSVD | | +| 0x680 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x684 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x688 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x68C | 1 | EN_ACCSS_PRTCTD_REG | Other Dev ctrl-stat-int | | +| 0x690 | 1 | I2C_MUX_RST_REG | Other Dev ctrl-stat-int | | +| 0x694 | 12 | RSVD | Other Dev ctrl-stat-int | | +| 0x6C4 | 1 | RSVD | Other Dev ctrl-stat-int | | +| 0x6C8 | 270 | RSVD | RSVD | | +| 0xB00 | 1 | FLSH_CTRL_REG | Flash Write Protect | | +| 0xB04 | 31 | RSVD | Flash Write Protect | | +| 0xB80 | 1 | LED_SYNC_REG | LED | | +| 0xB84 | 1 | LED_CONFIG_REG | LED | B84 | +| 0xB88 | 1 | LED_CTRL_0_REG | LED | B88 | +| 0xB8C | 1 | RSVD | LED | B8C | +| 0xB90 | 1 | RSVD | LED | B90 | +| 0xB94 | 27 | RSVD | LED | | +| 0xC00 | 1 | RSVD | Debug & Test | | +| 0xC04 | 1 | RSVD | Debug & Test | | +| 0xC08 | 1 | RSVD | Debug & Test | | +| 0xC0C | 1 | RSVD | Debug & Test | | +| 0xC10 | 1 | RSVD | Debug & Test | | +| 0xC14 | 1 | RSVD | Debug & Test | | +| 0xC18 | 1 | RSVD | Debug & Test | | +| 0xC1C | 1 | RSVD | Debug & Test | | +| 0xC20 | 1 | TND_CB_GPIO_CTRL_REG | Debug & Test | | +| 0xC24 | 1 | TND_CB_GPIO_STAT_REG | Debug & Test | | +| 0xC28 | 1 | TND_CB_GPIO_DIR_CTRL_REG | Debug & Test | | +| 0xC2C | 89 | RSVD | Debug & Test | | +| 0xD90 | 1 | RSVD | Reset Stat | | +| 0xD94 | 1 | RSVD | Reset Stat | | +| 0xD98 | 26 | RSVD | RSVD | | +| 0xE00 | 1 | I2C_PRSCL_LO_REG | I2C-Ch0 | 1) PDB Fan Controller | +| 0xE04 | 1 | I2C_PRSCL_HI_REG | I2C-Ch0 | | +| 0xE08 | 1 | I2C_CTRL_REG | I2C-Ch0 | | +| 0xE0C | 0 | I2C_TX_REG | I2C-Ch0 | | +| 0xE0C | 1 | I2C_RX_REG | I2C-Ch0 | | +| 0xE10 | 0 | I2C_CMD_REG | I2C-Ch0 | | +| 0xE10 | 1 | I2C_STAT_REG | I2C-Ch0 | | +| 0xE14 | 1 | I2C_MUX_SEL_REG | I2C-Ch0 | | +| 0xE18 | 1 | I2C_RST_REG | I2C-Ch0 | | +| 0xE1C | 1 | SEM_REG | I2C-Ch0 | | +| 0xE20 | 1 | I2C_PRSCL_LO_REG | I2C-Ch1 | 1) PDB EEPROM | +| 0xE24 | 1 | I2C_PRSCL_HI_REG | I2C-Ch1 | | +| 0xE28 | 1 | I2C_CTRL_REG | I2C-Ch1 | | +| 0xE2C | 0 | I2C_TX_REG | I2C-Ch1 | | +| 0xE2C | 1 | I2C_RX_REG | I2C-Ch1 | | +| 0xE30 | 0 | I2C_CMD_REG | I2C-Ch1 | | +| 0xE30 | 1 | I2C_STAT_REG | I2C-Ch1 | | +| 0xE34 | 1 | I2C_MUX_SEL_REG | I2C-Ch1 | | +| 0xE38 | 1 | I2C_RST_REG | I2C-Ch1 | | +| 0xE3C | 1 | SEM_REG | I2C-Ch1 | | +| 0xE40 | 1 | I2C_PRSCL_LO_REG | I2C-Ch2 | 1) PDB external temperature sensors | +| 0xE44 | 1 | I2C_PRSCL_HI_REG | I2C-Ch2 | | +| 0xE48 | 1 | I2C_CTRL_REG | I2C-Ch2 | | +| 0xE4C | 0 | I2C_TX_REG | I2C-Ch2 | | +| 0xE4C | 1 | I2C_RX_REG | I2C-Ch2 | | +| 0xE50 | 0 | I2C_CMD_REG | I2C-Ch2 | | +| 0xE50 | 1 | I2C_STAT_REG | I2C-Ch2 | | +| 0xE54 | 1 | I2C_MUX_SEL_REG | I2C-Ch2 | | +| 0xE58 | 1 | I2C_RST_REG | I2C-Ch2 | | +| 0xE5C | 1 | SEM_REG | I2C-Ch2 | | +| 0xE60 | 1 | I2C_PRSCL_LO_REG | I2C-Ch3 | 1) Hotswap controller | +| 0xE64 | 1 | I2C_PRSCL_HI_REG | I2C-Ch3 | | +| 0xE68 | 1 | I2C_CTRL_REG | I2C-Ch3 | | +| 0xE6C | 0 | I2C_TX_REG | I2C-Ch3 | | +| 0xE6C | 1 | I2C_RX_REG | I2C-Ch3 | | +| 0xE70 | 0 | I2C_CMD_REG | I2C-Ch3 | | +| 0xE70 | 1 | I2C_STAT_REG | I2C-Ch3 | | +| 0xE74 | 1 | I2C_MUX_SEL_REG | I2C-Ch3 | | +| 0xE78 | 1 | I2C_RST_REG | I2C-Ch3 | | +| 0xE7C | 1 | SEM_REG | I2C-Ch3 | | +| 0xE80 | 1 | I2C_PRSCL_LO_REG | I2C-Ch4 | 1) Power bricks and EFUSE | +| 0xE84 | 1 | I2C_PRSCL_HI_REG | I2C-Ch4 | | +| 0xE88 | 1 | I2C_CTRL_REG | I2C-Ch4 | | +| 0xE8C | 0 | I2C_TX_REG | I2C-Ch4 | | +| 0xE8C | 1 | I2C_RX_REG | I2C-Ch4 | | +| 0xE90 | 0 | I2C_CMD_REG | I2C-Ch4 | | +| 0xE90 | 1 | I2C_STAT_REG | I2C-Ch4 | | +| 0xE94 | 1 | I2C_MUX_SEL_REG | I2C-Ch4 | | +| 0xE98 | 1 | I2C_RST_REG | I2C-Ch4 | | +| 0xE9C | 1 | SEM_REG | I2C-Ch4 | | + +### Common + +#### none — Function none + +| Offset | DW | Register | Group | Comment | +|---|---|---|---|---| +| 0x | | none | none | Start of next device | +| 0x | none | none | none | Start of next device | +| 0x | | none | none | Start of next device | + +--- + +## 4. MSI Interrupt Mapping + +### CB MSI Vector Map + +| Interface | CB Register | Function | MSI Vector (Function.Vector.Bit) | Signal Description | Notes | +|---|---|---|---|---|---| +| Power | PWR_STAT_REG | 0 | 0.0.0 | Power Stat Interrupt | | +| TPM | TPM_STAT_REG | 0 | 0.1.0 | TPM Stat Interrupt | | +| PMC | PMC_STAT_REG | 0 | 0.2.0 | PMCC Stat Interrupt | | +| ICB | ICB_STAT_REG | 0 | 0.3.0 | ICB Stat Interrupt | | +| SWB 0 | SWB_STAT_REG | 0 | 0.4.0 | SWB 0 Stat Interrupt | | +| SWB 1 | SWB_STAT_REG | 0 | 0.5.0 | SWB 1 Stat Interrupt | | +| Thermal | THRM_STAT_REG | 0 | 0.6.0 | Thermal Stat Interrupt | | +| USB | USB_STAT_REG | 0 | 0.7.0 | USB Stat Interrupt | | +| Button | BTC_STAT_REG | 0 | 0.8.0 | Button Stat Interrupt | | +| Leak | LEAK_STAT_REG | 0 | 0.9.0 | Leak Stat Interrupt | | +| NFC | NFC_STAT_REG | 0 | 0.10.0 | NFC Stat Interrupt | | +| Intrusion | INTRD_STAT_REG | 0 | 0.11.0 | Intrusion Stat Interrupt | | +| Battery | BTRY_STAT_REG | 0 | 0.12.0 | Battery Stat Interrupt | | +| Fan | FAN_STAT_REG | 1 | 1.0.0 | Fan Stat Interrupt | | +| Retimer | RTM_STAT_REG | 1 | 1.1.0 | Retimer Stat Interrupt | | +| Ethernet Controller | ETH_CTRLR_STAT_REG | 1 | 1.2.0 | Ethernet Controller Stat Interrupt | | +| 1 | | | 1.3.0 | | | +| 1 | | | 1.4.0 | | | +| 1 | | | 1.5.0 | | | +| | | 1 | 1.6.0 | | | +| | | 1 | 1.7.0 | | | +| User Port Power | USRPRT_PWR_STAT_REG | 1 | 1.8.0 | UserPort Power Stat Interrupt | | +| User Port 0 | USRPRT_0_STAT_REG | 1 | 1.9.0 | UserPort 0 Stat Interrupt | | +| User Port 1 | USRPRT_0_STAT_REG | 1 | 1.10.0 | UserPort 1 Stat Interrupt | | +| 1 | | | 1.11.0 | | | +| SPI Flash Controller | SPI_CMD_STAT_REG | 2 | 2.0.0 | CB SPI Flash Controller Stat Interrupt | | +| VSPI Flash Controller | SPI_CMD_STAT_REG | 2 | 2.0.1 | PMC VSPI Flash Controller Stat Interrupt | | +| VSPI Flash Controller | SPI_CMD_STAT_REG | 2 | 2.0.2 | ICB VSPI Flash Controller Stat Interrupt | | +| VSPI Flash Controller | SPI_CMD_STAT_REG | 2 | 2.0.3 | SWB0 VSPI Flash Controller Stat Interrupt | | +| VSPI Flash Controller | SPI_CMD_STAT_REG | 2 | 2.0.4 | SWB1 VSPI Flash Controller Stat Interrupt | | +| | | 2 | 2.0.5 | | | +| | | 2 | 2.0.6 | | | +| | | 2 | 2.0.7 | | | +| | | 2 | 2.0.8 | | | +| | | 2 | 2.0.9 | | | +| | | 2 | 2.0.10 | | | +| | | 2 | 2.0.11 | | | +| | | 2 | 2.0.12 | | | +| I2C | I2C_STAT_REG | 3 | 3.0.0 | Open core I2C Interrupt Ch0 | | +| I2C | I2C_STAT_REG | 3 | 3.0.1 | Open core I2C Interrupt Ch1 | | +| I2C | I2C_STAT_REG | 3 | 3.0.2 | Open core I2C Interrupt Ch2 | | +| I2C | I2C_STAT_REG | 3 | 3.0.3 | Open core I2C Interrupt Ch3 | | +| I2C | I2C_STAT_REG | 3 | 3.0.4 | Open core I2C Interrupt Ch4 | | +| I2C | I2C_STAT_REG | 3 | 3.0.5 | Open core I2C Interrupt Ch5 | | +| I2C | I2C_STAT_REG | 3 | 3.0.6 | Open core I2C Interrupt Ch6 | | +| I2C | I2C_STAT_REG | 3 | 3.0.7 | Open core I2C Interrupt Ch7 | | +| I2C | I2C_STAT_REG | 3 | 3.0.8 | Open core I2C Interrupt Ch8 | | +| I2C | I2C_STAT_REG | 3 | 3.0.9 | Open core I2C Interrupt Ch9 | | +| I2C | I2C_STAT_REG | 3 | 3.0.10 | Open core I2C Interrupt Ch10 | | +| I2C | I2C_STAT_REG | 3 | 3.0.11 | Open core I2C Interrupt Ch11 | | +| I2C | I2C_STAT_REG | 3 | 3.0.12 | Open core I2C Interrupt Ch12 | | +| I2C | I2C_STAT_REG | 3 | 3.0.13 | Open core I2C Interrupt Ch13 | | +| I2C | I2C_STAT_REG | 3 | 3.0.14 | Open core I2C Interrupt Ch14 | | +| I2C | I2C_STAT_REG | 3 | 3.0.15 | Open core I2C Interrupt Ch15 | | +| I2C | I2C_STAT_REG | 3 | 3.0.16 | Open core I2C Interrupt Ch16 | | +| I2C | I2C_STAT_REG | 3 | 3.0.17 | Open core I2C Interrupt Ch17 | | +| | | 3 | 3.0.18 | | | +| | | 3 | 3.0.19 | | | +| VI2C | I2C_STAT_REG | 3 | 3.0.20 | ICB LSB VI2C Interrupt Ch0 | | +| VI2C | I2C_STAT_REG | 3 | 3.0.21 | ICB LSB VI2C Interrupt Ch1 | | +| VI2C | I2C_STAT_REG | 3 | 3.0.22 | ICB LSB VI2C Interrupt Ch2 | | +| VI2C | I2C_STAT_REG | 3 | 3.0.23 | ICB LSB VI2C Interrupt Ch3 | | +| VI2C | I2C_STAT_REG | 3 | 3.0.24 | ICB LSB VI2C Interrupt Ch4 | | +| | | 3 | 3.0.25 | | | +| | | 3 | 3.0.26 | | | +| 3 | | | 3.0.27 | | | + +### SWB Interrupt Map + +| Interface | CB Register | Interrupt Method | SWB Register | Signal Description | Notes | +|---|---|---|---|---|---| +| Power & Thermal | SWB_STAT_REG [2] #SWB_INT | Pin | PWR_STAT_REG THRM_STAT_REG | | | + +### ICB Interrupt Map + +| Interface | CB Register | Interrupt Method | SWB Register | Signal Description | Notes | +|---|---|---|---|---|---| +| Power & Thermal | ICB_STAT_REG [2] #ICB_INT | Pin | PWR_STAT_REG FAN_STAT_REG THRM_STAT_REG | | | + +--- + +## 5. Register Descriptions + +### MSI Interrupts + +#### Interrupt registers + +- MSI vector number assigned for each interrupt is predefined and not programmable. +- There is a pair of DEV_MSI_PEND_REG and DEV_MSI_INT_EN_REG register for each MSI vector. +- Each device within the function will have a PEND bit in one of the DEV_MSI_PEND_REG registers according to MSI vector number assigned to that device. +- A device will have its PEND bit set when it is requesting service. +- There can be as many as 32 pair of PEND/EN registers (one for each MSI interrupt vector) in a function. The actual number of MSI vectors reserved for each function is currently TBD. +- PEND/EN registers are 32 bit registers but they can be extended to 64 bit if more than 32 interrupt request are assigned to a single MSI (A 64 bit register is composed of two 32-bit registers). +##### DEV_MSI_PEND_REG + +There can be as many as 32 DEV_MSI_PEND_REG registers (one for each MSI interrupt vector) per function. Each device within the function will have a PEND bit in one of the PEND registers. A device will have its PEND bit set when it is requesting service. + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| TBD | | RO | | | +| TBD | | RO | | | + +##### DEV_MSI_INT_EN_REG + +There can be as many as 32 DEV_MSI_INT_EN_REG registers (one for each MSI interrupt vector) per function. The actual number of MSI vectors reserved for each function or device is currently TBD. + +Enables a device to have its interrupt PEND status to trigger a MSI interrupt. + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| TBD | | RW | | | +| TBD | | RW | | | + +#### MSI Generation + +FPGA will trigger MSI interrupt only when (INT_EN [MSI_INDEX] & PEND [MSI_INDEX]) transition from 0 to 1. To avoid missing interrupts SW would make sure that it does not exit the ISR until the condition (INT_EN [MSI_INDEX] & PEND [MSI_INDEX]) is zero. Following examples clarifies how MSI interrupts are generated and serviced by FPGA and SW. + +Scenario 1: Assume at time 0 no interrupt is pending and DEV1-INT is enabled (means its respective bit in DEV_MSI_INT_EN_REG is asserted). At time t1, PEND bit for DEV1-INT transitions from 0 to 1. Since enable bit is already 1, FPGA will detect 01 transition in (INT_EN & PEND) therefore will send MSI to CPU. + +Scenario 2:  Assume at time 0, DEV1-INT is pending but disabled. At time t1 SW set the DEV1-INT enable bit to 1. Since PEND bit is already 1, FPGA will detect 01 transition in (INT_EN & PEND) therefore will send MSI to CPU. + +Scenario 3: Assume at time 0 no interrupt is pending and DEV1-INT and DEV2-INT are enabled (means their respective bits in DEV_MSI_INT_EN_REG are asserted). At time t1, PEND bit for DEV1-INT transitions from 0 to 1. Since enable bit is already 1, FPGA will detect 01 transition in (INT_EN & PEND) therefore will send MSI to CPU. Immediately after sending MSI and before SW can service DEV1-INT, at time t1+e, PEND bit for DEV2-INT transitions from 0 to 1. At time t1+e, (INT_EN & PEND) is already 1 and FPGA will not detect any 01 transition so no new MSI will be generated. At the time SW services the first MSI, it will check the PEND register and find out that DEV1-INT and DEV2-INT is pending and will service both interrupt requests before exiting the ISR. + +Scenario 4: Assume at time 0 no interrupt is pending and DEV1-INT and DEV2-INT are enabled (means their respective bits in DEV_MSI_INT_EN_REG are asserted). At time t1, PEND bit for DEV1-INT transitions from 0 to 1. Since enable bit is already 1, FPGA will detect 01 transition in (INT_EN & PEND) therefore will send MSI to CPU. As part of ISR, SW will read PEND register and find out that Dev1-INT is pending. Before SW can fully service the DEV1-INT and clear the respective PEND bit, at time t2, PEND bit for DEV2-INT transitions from 0 to 1. At time t2, (INT_EN & PEND) is already 1 and FPGA will not detect any 01 transition so no new MSI will be generated. After SW cleared DEV1-INT before exiting the ISR, it will again read PEND register and find out that DEV2-INT is pending. SW will continue with servicing DEV2-INT before exiting the ISR. + +Scenario 5: at Scenario 4, after SW cleared DEV1-INT (INT_EN & PEND transition from 1 to 0), immediately DEV2-INT happens. Before exiting ISR, SW will read the PEND register and detect the DEV2-INT but at the same time FPGA will detect 01 transition in (INT_EN & PEND) and send MSI. In this scenario SW services DEV2-INT as part of first MSI interrupt, therefore when SW process the second MSI it finds no pending INT because DEV2-INT has already been serviced by first MSI. This situation should be managed by SW. + +### LED Control bits + +The status of each LED is defined by an 8-bit register as explained below: + +Bit [0] – 0 off, 1 on + +Bit [1] – 0 orange, 1 green or single color + +Bit [2] – 0 not blink, 1 blink + +Bit [3] – 0 slow blink, 1 fast blink + +Bit [4] – 0 full bright, 1 half bright + +Bit [5] – Reserved + +Bit [7:6] – This bit is reserved unless stated in description + +0 FPGA/SW Ctrl, other values (external control) + +All LED register in this document use above codes to define the status of LED. + +### Common Register Description + +#### FPGA_REV_ID_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** See Description + +Stores Device-ID & Revision Number for FPGA + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| FPGA_ID | 31:16 | RO | See Description | Device Identification,
CB = 0x2001
SWB = 0x2101
ICB = 0x2201 | +| FPGA_REV | 15:0 | RO | 0x0001 | FPGA Code Revision field. Incremented by 1 in each revision.
For lab Release, Rev will start with “1” illustrating beta version. e.g. 0x8001 | + +#### RDND_MGMT_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** 0xCCCC_CCCC + +Redundancy Management Registers + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RDND_MGMT_STAT | 31:0 | RW | 0xCCCC_CCCC | Under SW control | + +#### FUNC_CAP_0_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined per each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MSI_3_INT_NUM | 31:24 | RO | | Illustrates the Number of interrupts that can generate MSI vector 3 | +| MSI_2_INT_NUM | 23:16 | RO | | Illustrates the Number of interrupts that can generate MSI vector 2 | +| MSI_1_INT_NUM | 15:8 | RO | | Illustrates the Number of interrupts that can generate MSI vector 1 | +| MSI_0_INT_NUM | 7:0 | RO | | Illustrates the Number of interrupts that can generate MSI vector 0 | + +#### FUNC_CAP_1_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined per each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MSI_7_INT_NUM | 31:24 | RO | | Illustrates the Number of interrupts that can generate MSI vector 7 | +| MSI_6_INT_NUM | 23:16 | RO | | Illustrates the Number of interrupts that can generate MSI vector 6 | +| MSI_5_INT_NUM | 15:8 | RO | | Illustrates the Number of interrupts that can generate MSI vector 5 | +| MSI_4_INT_NUM | 7:0 | RO | | Illustrates the Number of interrupts that can generate MSI vector 4 | + +#### FUNC_CAP_2_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined per each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MSI_11_INT_NUM | 31:24 | RO | | Illustrates the Number of interrupts that can generate MSI vector 11 | +| MSI_10_INT_NUM | 23:16 | RO | | Illustrates the Number of interrupts that can generate MSI vector 10 | +| MSI_9_INT_NUM | 15:8 | RO | | Illustrates the Number of interrupts that can generate MSI vector 9 | +| MSI_8_INT_NUM | 7:0 | RO | | Illustrates the Number of interrupts that can generate MSI vector 8 | + +#### FUNC_CAP_3_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined per each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MSI_15_INT_NUM | 31:24 | RO | | Illustrates the Number of interrupts that can generate MSI vector 15 | +| MSI_14_INT_NUM | 23:16 | RO | | Illustrates the Number of interrupts that can generate MSI vector 14 | +| MSI_13_INT_NUM | 15:8 | RO | | Illustrates the Number of interrupts that can generate MSI vector 13 | +| MSI_12_INT_NUM | 7:0 | RO | | Illustrates the Number of interrupts that can generate MSI vector 12 | + +#### FUNC_CAP_4_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined per each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MSI_19_INT_NUM | 31:24 | RO | | Illustrates the Number of interrupts that can generate MSI vector 19 | +| MSI_18_INT_NUM | 23:16 | RO | | Illustrates the Number of interrupts that can generate MSI vector 18 | +| MSI_17_INT_NUM | 15:8 | RO | | Illustrates the Number of interrupts that can generate MSI vector 17 | +| MSI_16_INT_NUM | 7:0 | RO | | Illustrates the Number of interrupts that can generate MSI vector 16 | + +#### FUNC_CAP_5_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined per each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MSI_23_INT_NUM | 31:24 | RO | | Illustrates the Number of interrupts that can generate MSI vector 23 | +| MSI_22_INT_NUM | 23:16 | RO | | Illustrates the Number of interrupts that can generate MSI vector 22 | +| MSI_21_INT_NUM | 15:8 | RO | | Illustrates the Number of interrupts that can generate MSI vector 21 | +| MSI_20_INT_NUM | 7:0 | RO | | Illustrates the Number of interrupts that can generate MSI vector 20 | + +#### FUNC_CAP_6_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined per each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MSI_27_INT_NUM | 31:24 | RO | | Illustrates the Number of interrupts that can generate MSI vector 27 | +| MSI_26_INT_NUM | 23:16 | RO | | Illustrates the Number of interrupts that can generate MSI vector 26 | +| MSI_25_INT_NUM | 15:8 | RO | | Illustrates the Number of interrupts that can generate MSI vector 25 | +| MSI_24_INT_NUM | 7:0 | RO | | Illustrates the Number of interrupts that can generate MSI vector 24 | + +#### FUNC_CAP_7_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined per each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MSI_31_INT_NUM | 31:24 | RO | | Illustrates the Number of interrupts that can generate MSI vector 31 | +| MSI_30_INT_NUM | 23:16 | RO | | Illustrates the Number of interrupts that can generate MSI vector 30 | +| MSI_29_INT_NUM | 15:8 | RO | | Illustrates the Number of interrupts that can generate MSI vector 29 | +| MSI_28_INT_NUM | 7:0 | RO | | Illustrates the Number of interrupts that can generate MSI vector 28 | + +#### FUNC_CAP_8_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** Defined for each function of each FPGA. + +Defines the capability of PCIe function + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | | Reserved | +| NUM_OF_PRTS | 7:0 | RO | | Represent the number of I2C ports in function 3. This is inclusive of real I2C ports, Virtual I2C Ports, and reserved I2C ports.
This field is not used in other functions and will be always 0. | + +#### MBOX_n_DATA_REG + +Data will be written in this register only if respective stat bit in MBOX_STAT_REG is showing empty stat. Write in this register will set the respective stat bit in MBOX_STAT_REG. + +**Card Type:** All · **FPGA Type:** All · **Function:** 0 · **POR Value:** 0x0000_0000 + +Mailbox data + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| DATA | 31:0 | RW | 0 | | + +#### MBOX_STAT_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** 0 · **POR Value:** 0x0000_0000 + +Mailbox status + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| MBOX_3_STAT | 3 | W1C | 0 | 1: MBOX_3_DATA_REG is full.
0: MBOX_3_DATA_REG is empty. | +| MBOX_2_STAT | 2 | W1C | 0 | Same as MBOX_3_STAT | +| MBOX_1_STAT | 1 | W1C | 0 | Same as MBOX_3_STAT | +| MBOX_0_STAT | 0 | W1C | 0 | Same as MBOX_3_STAT | + +#### MBOX_STAT_PLRTY_REG + +Defines which level of the MBOX_STAT signal is the condition for triggering the Interrupt. + +STAT_PLRTY_REG is defined once in this document. All other STAT_PLRTY_REG registers’ definition will be similar to this and their bits will follow their respective STAT_REG. + +**Card Type:** All · **FPGA Type:** All · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| MBOX_3_STAT_PLRTY | 3 | RW | 0 | 1: means MBOX_3_STAT hi (1’b1) is the condition for triggering the interrupt. In case of edge interrupt a stat transition from lo to hi (1’b0 to 1’b1) is the condition for triggering the interrupt.
0: means MBOX_3_STAT lo (1’b0) is the condition for triggering the interrupt. In case of edge interrupt a stat transition from hi to lo (1’b1 to 1’b0) is the condition for triggering the interrupt. | +| MBOX_2_STAT_PLRTY | 2 | RW | 0 | Same as MBOX_3_STAT_PLRTY | +| MBOX_1_STAT_PLRTY | 1 | RW | 0 | Same as MBOX_3_STAT_PLRTY | +| MBOX_0_STAT_PLRTY | 0 | RW | 0 | Same as MBOX_3_STAT_PLRTY | + +#### MBOX_STAT_EDG_LVL_REG + +Defines if the level or the transition of the MBOX_STAT signal is the condition for triggering the Interrupt. + +STAT_EDG_LVL_REG is defined once in this document. All other STAT_EDG_LVL_REG registers’ definition will be similar to this and their bits will follow their respective STAT_REG. + +**Card Type:** All · **FPGA Type:** All · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| MBOX_3_STAT_EDG_LVL | 3 | RW | 0 | 1: means the transition (or the edge) of MBOX_3_STAT is the condition for triggering the interrupt.
0: means the level of MBOX_3_STAT is the condition for triggering the interrupt. | +| MBOX_2_STAT_EDG_LVL | 2 | RW | 0 | Same as MBOX_3_STAT_EDG_LVL | +| MBOX_1_STAT_EDG_LVL | 1 | RW | 0 | Same as MBOX_3_STAT_EDG_LVL | +| MBOX_0_STAT_EDG_LVL | 0 | RW | 0 | Same as MBOX_3_STAT_EDG_LVL | + +#### MBOX_STAT_INT_EN_REG + +Enable interrupts for status bits of mailboxes. + +STAT_INT_EN_REG is defined once in this document. All other STAT_INT_EN_REG registers’ definition will be similar to this and their bits will follow their respective STAT_REG. + +**Card Type:** All · **FPGA Type:** All · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| MBOX_3_STAT_EN | 3 | RW | 0 | 1: Enables MBOX_3_STAT to trigger interrupt if interrupt condition is met.
0: Disables MBOX_3_STAT interrupt. | +| MBOX_2_STAT_EN | 2 | RW | 0 | Same as MBOX_3_STAT_EN | +| MBOX_1_STAT_EN | 1 | RW | 0 | Same as MBOX_3_STAT_EN | +| MBOX_0_STAT_EN | 0 | RW | 0 | Same as MBOX_3_STAT_EN | + +#### MBOX_STAT_INT_STAT_REG + +Illustrates current interrupt status of mailboxes. + +STAT_INT_STAT_REG is defined once in this document. All other STAT_INT_STAT_REG registers’ definition will be similar to this and their bits will follow their respective STAT_REG. + +**Card Type:** All · **FPGA Type:** All · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| MBOX_3_INT_STAT | 3 | RO | 0 | 1: MBOX_3 INT is active and requesting service.
0: MBOX_3 INT is inactive. | +| MBOX_2_INT_STAT | 2 | RO | 0 | Same as MBOX_3_INT_STAT | +| MBOX_1_INT_STAT | 1 | RO | 0 | Same as MBOX_3_INT_STAT | +| MBOX_0_INT_STAT | 0 | RO | 0 | Same as MBOX_3_INT_STAT | + +#### MBOX_STAT_INT_CLR_REG + +Write one in this register to clear respective interrupt in MBOX_STAT_INT_STAT_REG. Applicable to Edge Interrupts. + +STAT_INT_CLR_REG is defined once in this document. All other STAT_INT_CLR_REG registers’ definition will be similar to this and their bits will follow their respective STAT_REG. + +**Card Type:** All · **FPGA Type:** All · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| MBOX_3_INT_CLR | 3 | RW | 0 | One in this bit location clears MBOX_3_INT_STAT. This bit resets itself in next clock cycle after a one is written into it, so it will always show 0 if SW attempt to read it. | +| MBOX_2_INT_CLR | 2 | RW | 0 | Same as MBOX_3_INT_CLR | +| MBOX_1_INT_CLR | 1 | RW | 0 | Same as MBOX_3_INT_CLR | +| MBOX_0_INT_CLR | 0 | RW | 0 | Same as MBOX_3_INT_CLR | + +#### SCRTCH_n_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** 0x0000_0000 + +Scratch Pad + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| DATA | 31:0 | RW | 0 | | + +#### SEM_REG + +Here is how SEM_REG works: + +- If the content of this register is zero, then it will allow SW to write any value on that. +- If the content of this register is nonzero, then SW is not allowed to write any value in this register but SW can clear this register by writing zero in it. In other words since this is 8-bit register, SW can clear this register by writing any value which has bits [7:0] = 8’h00. SW can always write zero in this register. +**Card Type:** All · **FPGA Type:** All · **Function:** All · **POR Value:** 0x0000_0000 + +Semaphore + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| DATA | 7:0 | RW | 0 | | + +#### SPI_CMD_STAT_REG + +SW should set only single command bit at a time. If more than one command bits are set, only the command bit in lower bit position will be executed. For example of READ_DW and WRITE_DW commands are set, only READ_DW (which is in lower bit position) is executed. + +**Card Type:** ALL · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0100 + +Instruct FPGA to erase, read from, and write into SPI peripheral. + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| INT_EN | 31 | RW | 0 | 1: Interrupt Enabled. | +| RSVD | 30:12 | RO | 0 | Reserved | +| INT | 11 | W1C | 0 | 1: SPI transaction is completed. | +| ILLEGAL_ERASE | 10 | W1C | 0 | 1: ILLEGAL ERASE detected. Trying to erase a protected sector.
In Virtual SPI Reg: Not Used. | +| ILLEGAL_WRITE | 9 | W1C | 0 | 1: ILLEGAL WRITE detected. Trying to write in a protected sector.
In Virtual SPI Reg: Not Used. | +| READY | 8 | RO | 1 | 1: Flash memory controller is ready and can accept new command.
0: Flash memory controller is executing a command and cannot accept new command.
Recommendation: SW should check this bit before initiating a new command. | +| READ_ID | 7 | RW | 0 | 1: Read Device Identification from the memory device
0: No Action
This bit is not used for internal flash access in PMC, ICB-FT and ICB-RDC FPGAs.
In Virtual SPI Reg: Not Used. | +| READ_SILICON_ID | 6 | RW | 0 | Not used in Ridley. Use bit 7 to read silicon ID. | +| READ_STATUS | 5 | RW | 0 | This is to read Status Register-1 from flash.
This bit is used differently in VSPI flash.
In Virtual SPI Flash this bit is W1C.
1: Read Failed
0: Read Successful
In Virtual SPI Reg this bit is not used. | +| PROTECT_SECTOR | 4 | RW | 0 | Not used in Ridley. | +| ERASE_SECTOR | 3 | RW | 0 | 1: Erase a sector specified by SPI_ADD_REG.
0: No Action
In Virtual SPI Reg: Not Used. | +| WRITE_W | 2 | RW | 0 | 1: Write one DW in Flash Memory address specified by SPI_ADD_REG. The data to be written should be stored in SPI_WR_DATA_REG.
0: No Action | +| READ_W | 1 | RW | 0 | 1: Read one DW from address specified by SPI_ADD_REG. The read data will be stored in SPI_RD_DATA_REG.
0: No Action | +| NEW_COMMAND | 0 | RW | 0 | 1: The command specified in Bit1 to 7 is a new command.
0: Command has been executed by FPGA and if there is any command bit set, FPGA will assume it is old command and will ignore it.
To initiate a new command (specified by bit1 to bit7), SW should set NEW_COMMAND bit high. This bit is de-asserted by FPGA after command is executed.
For Virtual SPI, if SW trigger a SPI command and the NEW_COMMAND bit never get cleared by FPGA (due to errors on the LSB bus) then SW can clear NEW_COMMAND bit and initiate another SPI command. In such a condition, | + +#### SPI_ADD_REG + +In SPI controller and in VSPI-Flash this register is used as it is defined in the description field below, but in VSPI-WB the upper 4 bits are used differently. In VSPI_WB, this register is used to specify the address of the register in the remote FPGA. Bits [19:0] are used as register offset (relative address in the respective function). Bits [23:20] are used to specify the function. + +Bits [23:20] = 0x1 and 0x0 specifies function 0. + +Bits [23:20] = 0x2 specifies function 1. + +Bits [23:20] = 0x4 specifies function 2. + +Bits [23:20] = 0x8 specifies function 3. + +Other values for Bits[23:20] are invalid. + +**Card Type:** ALL · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +Specifies an address in SPI Peripheral + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:24 | RO | 0 | Reserved | +| ADDR | 23:0 | RW | 0 | This field specifies the word address for READ_DW and WRITE_DW operation. A valid word address should have two LSB bits of zero.
For sector erase command, the address placed in this field can be any valid address in the sector that you can erase. | + +#### SPI_WR_DATA_REG + +**Card Type:** ALL · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +Data to be written in SPI Peripheral. + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| WR_DATA | 31:0 | RW | 0 | 32-bit data to be written in Configuration Flash Memory. | + +#### SPI_RD_DATA_REG + +**Card Type:** ALL · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +Data read from SPI Peripheral + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RD_DATA | 31:0 | RO | 0 | FPGA stores read data from configuration flash memory in this register.
The register content is valid after Read command is executed and will remain valid before the next command starts, so SW is expected to read this register after read command executed before issuing another command. | + +#### SPI_RST_REG + +**Card Type:** ALL · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | | +| LCL_RST | 3:0 | RW | 0 | 0xD: Reset the local SPI controller or local VSPI module.
With reset all registers are initialized by their POR value. All state machines are initialized to their initial state. After successful reset of SPI controller, this register will also be cleared to zero. Any other values other than 0xD will be ignored by FPGA. | + +#### I2C_PRSCL_LO_REG + +Pre-scale value is calculated as: [(input clock HZ) / (5xdesired SCL HZ)] – 1. + +Below values have been calculated based on 75MHZ input clock. + +Pre-scale = 0x88 (136 decimal) for 100KHZ SCL + +Pre-scale = 0x24 (36 decimal) for 400KHZ SCL + +Change the value of the prescale register only when the I2C_MOD_EN bit is cleared. + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_00FF + +This register is used to pre-scale the SCL clock line + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| PRESCALE | 7:0 | RW | 0xFF | Clock Pre scale register lo-byte | + +#### I2C_PRSCL_HI_REG + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_00FF + +This register is used to pre-scale the SCL clock line + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| PRESCALE | 7:0 | RW | 0xFF | Clock Pre scale register hi-byte | + +#### I2C_CTRL_REG + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| I2C_MOD_EN | 7 | RW | 0 | “1” means core is enabled.
“0” means core is disabled. | +| I2C_MOD_INT_EN | 6 | RW | 0 | “1” means interrupt is enabled.
“0” means interrupt is disabled. | +| RSVD | 5:0 | RO | 0 | Reserved | + +#### I2C_TX_REG + +This is Transmit Register during register write operation but it will be Receive Register during register read operation. + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_0000 + +Transmit Data Register + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| DATA_BYTE_TX | 7:0 | WO | 0x0 | Next byte to be transmitted by I2C.
In case of data transfer, bit [0] represents the data’s LSB. In case of a slave address transfer bit [0] represents the RW bit. ‘1’ means reading from slave and ‘0’ means writing to slave. | + +#### I2C_RX_REG + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_0000 + +Receive Data Register + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| DATA_BYTE_RX | 7:0 | RO | 0x00 | Last byte received via I2C | + +#### I2C_CMD_REG + +This is command register during register write operation. During register read it will be status register. + +Command bits [0] and [4:7] are cleared when I2C byte transaction is done or when bus arbitration is lost. + +Prior to setting a command SW has to make sure right values have already been written in pre‐scale, Ctrl, Mux, and TX registers + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| STA | 7 | WO | 0 | generate (repeated) start condition | +| STO | 6 | WO | 0 | generate stop condition | +| RD | 5 | WO | 0 | read from slave | +| WR | 4 | WO | 0 | write to slave | +| ACK | 3 | WO | 0 | when a receiver, sent ACK (ACK = ‘0’) or NACK (ACK = ‘1’) | +| RSVD | 2:1 | RO | 0 | Reserved | +| INT_ACK | 0 | WO | 0 | Interrupt acknowledge. When set, clears a pending interrupt. | + +#### I2C_STAT_REG + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| RX_ACK | 7 | RO | 0 | Received acknowledge from slave.
This flag represents acknowledge from the addressed slave.
‘1’ = No acknowledge received
‘0’ = Acknowledge received | +| BUSY | 6 | RO | 0 | I2C bus busy
‘1’ after START signal detected
‘0’ after STOP signal detected | +| ARB_LOST | 5 | RO | 0 | Arbitration lost.
This bit is set when the core lost arbitration. Arbitration is lost when:
• a STOP signal is detected, but not requested
• The master drives SDA high, but SDA is low. | +| RSVD | 4:2 | RO | 0 | write to slave | +| TIP | 1 | RO | 0 | Transfer in progress
‘1’ when transferring data
‘0’ when transfer complete | +| INT_FLAG | 0 | RO | 0 | This bit is set when an interrupt is pending, which will cause a processor interrupt request if the IEN (INT_EN) bit is set.
The Interrupt Flag is set when:
• one byte transfer has been completed
• arbitration is lost | + +#### I2C_MUX_SEL_REG + +If a single I2C port is used to communicate with multiple I2C devices, then SW needs to set the device number in this register to specify which device it wants to talk to. FPGA will use this register to set the right values for the Enable and Select pins of the external I2C multiplexers. + +If there is no external I2C multiplexer connected to I2C controller, value of this register is simply ignored and has no effect in I2C controller functions. + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | 0 | | +| DEV_SEL | 7:0 | RW | 0 | Specifies the I2C device that needs to be connected to I2C controller. FPGA use this value to set the enable and select pins for the external I2C multiplexer. | + +#### I2C_RST_REG + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 3, none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | | +| LCL_RST | 3:0 | RW | 0 | 0xD: Reset the local I2C controller or local VI2C module.
With reset all registers are initialized by their POR value. All state machines are initialized to their initial state. After successful reset of I2C controller, this register will also cleared to zero.
Any other values other than 0xD will be ignored by FPGA. | + +#### LED_SYNC_REG + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 0, none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | 0 | | +| LED_SYNC | 0 | RW | 0 | This is used to synchronize the LED blinks on all the boards in chassis. SW write 1 in this bit to synchronize the LEDs.
1: Resets blinking status of all the Leds
0: no Action
This bit is automatically cleared by FPGA. | + +#### LED_CONFIG_REG + +**Card Type:** ALL · **FPGA Type:** ALL · **Function:** 0, none · **POR Value:** 0x0003_0705 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:28 | RO | 0 | Reserved | +| LED_TMR_CTRL | 27:24 | RW | 0 | 0x09: Turns of the LED timer
Other values: no effect.
This field is only used at 300 sec after power up or after FPGA reconfiguration.
SW has to write 0x9 in this field within 300 sec after power up (or after FPGA reconfiguration) to illustrate that it is in control otherwise FPGA will change the status of HEALTH LED to Orange Slow blink.
After FPGA changed the status of HEALTH LED, SW still can change the status of the LED by writing in respective LED control bits in LED control register. | +| RSVD | 23:21 | RO | 0 | Reserved | +| FST_BLNK_SPD | 20:16 | RW | 0x3 | The value of this field is used only if LED is in fast blink mode.
0: 100ms
1: 200ms
3: 400ms

31: 3200ms (3.2 sec) | +| RSVD | 15:13 | RO | 0 | | +| SLW_BLNK_SPD | 12:8 | RW | 0x7 | The value of this field is used only if LED is in slow blink mode.
0: 100ms
1: 200ms
3: 400ms

31: 3200ms (3.2 sec) | +| RSVD | 7:4 | RO | 0 | | +| BRGHT_LVL | 3:0 | RW | 0x5 | The value of this field is used only when we put LED in half-bright mode in LED_CTRL_REG.
0: off
1: 10% of full brightness
2: 20% of full brightness
….
9: 90% of full brightness
10 to 15: Full bright | + +#### FPGA_RECONFIG_CTRL_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** 0, none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:9 | RO | All 0s | Reserved | +| SELECT_IMAGE | 8 | RW | 0 | 0: Boot from App1
1: Boot from App2 | +| UPDATE_FIRST_BOOT | 7:4 | RW | 0 | 0xD: Update ‘First Boot’ value in the Flash to the value shown by #SELECT_IMAGE
Any other value: Does nothing.
This field will get cleared by FPGA after command is executed successfully. | +| START_RECONFIG | 3:0 | RW | 0 | 0xD: Start FPGA reconfiguration
Any other value: Does nothing. | + +#### FPGA_RECONFIG_STAT_REG + +**Card Type:** All · **FPGA Type:** All · **Function:** 0 · **POR Value:** 0x0000_0002 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:5 | RO | All 0s | Reserved | +| ERROR_FIRST_BOOT | 4 | RO | 0 | 1: Error in UPDATE_FIRST_BOOT command | +| BUSY | 3 | RO | 0 | FPGA reconfiguration is busy and executing a command. | +| ERROR | 2 | RO | 0 | 0: No Error in FPGA Configuration
1: Error observed in FPGA reconfiguration | +| CURRENT_IMAGE | 1:0 | RO | 10 | 10: App1
11: App2 | + +### CB Registers + +All registers are not protected by default unless specified. + +#### Function 0 + +#### FPGA_REV_ID_REG + +#### FUNC_CAP_0_REG + +#### FPGA_RECONFIG_CTRL_REG + +#### FPGA_RECONFIG_STAT_REG + +#### SCRTCH_n_REG + +#### DEV_MSI_0_PEND_REG (TBD) + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| MBOX_INT | 0 | RO | 0 | 1: MBOX requires service.
0: no service is requested. | + +#### DEV_MSI_0_INT_EN_REG (TBD) + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | 0 | Reserved | +| MBOX_INT_EN | 0 | RW | 0 | 1: MBOX interrupt is enabled.
0: MBOX interrupt is disabled. | + +#### PWR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0009 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| PWR_SUICIDE | 31:16 | RW | All 0s | Value of 0xA73D in this register will disable 1Khz signal sent out to the hardware external watchdog and toggle the reconfiguration pin of CB.
This field is used for CB post-ISP update. | +| THERMAL_SUICIDE_SWB_1 | 15:12 | RW | All 0s | 0x6: Force SWB 1 PSSM to enter Thermal Fault state, CB will shutdown all power rails and recovers after 5min.
SW writes to this register when it detects over-temperature event.
Any other value: no effect, FPGA will not take any action. This bit is automatically cleared to 0 after shutdown. | +| THERMAL_SUICIDE_SWB_0 | 11:8 | RW | All 0s | 0x6: Force SWB 0 PSSM to enter Thermal Fault state, CB will shutdown all power rails and recovers after 5min.
SW writes to this register when it detects over-temperature event.
Any other value: no effect, FPGA will not take any action. This bit is automatically cleared to 0 after shutdown. | +| THERMAL_SUICIDE_MAIN | 7:4 | RW | 0x0 | 0x6: Force Main PSSM to enter Thermal Fault state, CB will shutdown all power rails and recovers after 5min.
SW writes to this register when it detects over-temperature event.
Any other value: no effect, FPGA will not take any action. This bit is automatically cleared to 0 after shutdown. | +| EN_ISP_MODE | 3:0 | RW | 0x9 | 0x6: Enter ISP mode.
0x9: Disable ISP mode.
Although any value can be written in this field by SW, FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status.
When enabled, this disable the power sequence logic of CB from monitoring the power good of PMC, SWB and ICB that is invalid when the PMC, SWB or ICB are performing self-reconfiguration. | + +#### PWR_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:11 | RO | All 0s | Reserved | +| SWB_1_ALL_PG | 10 | RO | 1 | 1: Pgood is okay | +| SWB_0_ALL_PG | 9 | RO | 1 | 1: Pgood is okay | +| PDB_ALL_PG | 8 | RO | 1 | 1: Pgood is okay | +| RSVD | 7 | RO | 0 | Reserved | +| SWB1_PWROK | 6 | RO | 0 | Indicates the power sequencing of SWB 1 is completed.
1: Asserted
0: De-asserted | +| SWB0_PWROK | 5 | RO | 0 | Indicates the power sequencing of SWB 0 is completed.
1: Asserted
0: De-asserted | +| CB_PWROK | 4 | RO | 0 | Indicates the power sequencing of Control Board is completed.
1: Asserted
0: De-asserted | +| RSVD | 3:1 | RO | 0 | Reserved | +| PMC_PWR_INT | 0 | RO | 0 | PMC Power interrupt
1: Asserted
0: De-asserted
(signal is buffered from PMC) | + +#### RS232_SPD_SNS_REG + +This register allows the sensing of the console baud rate. A write to this register will reset the counter and arm the speed sense circuit. When a character is sensed, the counter counts to the end of the start bit. At this point an interrupt is set and the count can be read to allow the baud rate to be determined. Upon writing this register back to zero, you clear the interrupt and send the state machine back to the wait for character state. + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +This register allows the sensing of the console baud rate + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:18 | RO | All 0s | Reserved | +| SPEED_SENSE | 17:0 | RW | 0x00000 | Number of clocks the start bit is low. A character with odd ASCII code (e.g. Carriage Return) should be selected for speed sense. | + +#### RS232_CLR_SPD_SNS_REG + +Speed Sense Interrupt will be reset by writing to this register. + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +Clear Speed Sense Interrupt + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:0 | RO | | Write any value to clear the Speed Sense Interrupt | + +#### TPM_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| TPM_INT | 0 | RO | 0 | 1: Request for Service
(signal is buffered from PMC) | + +#### PMC_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:12 | RO | All 0s | Reserved | +| PMC_LSB_RST | 11:8 | RW | 0 | Reset control of PMC LSB
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will reset the PMC LSB port and all related processors.
This Field is automatically cleared by FPGA after reset is issued. | +| RSVD | 7:0 | RO | 0 | Reserved | + +#### PMC_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:28 | RO | All 0s | Reserved | +| LSB_PROC_TYP_ERR | 27 | RO | 0 | One of the processors in LSB port received a packet with an invalid value in type field. | +| LSB_PROC_FATAL_ERR | 26 | RO | 0 | One of the state machines in one of the processors in LSB port has gone momentarily to unknown state. | +| LSB_PROC_EOP_ERR | 25 | RO | 0 | One of the processors in LSB port received a packet without EOP. | +| LSB_PROC_SOP_ERR | 24 | RO | 0 | One of the processors in LSB port received a packet without SOP. | +| RSVD | 23:19 | RO | 0 | Reserved | +| LSB_TX_FATAL_ERR | 18 | RO | 0 | One of the state machines in LSB TX PHY has gone momentarily to unknown state. | +| LSB_TX_EOP_ERR | 17 | RO | 0 | LSB TX PHY received a packet without EOP from one of the processors. | +| LSB_TX_SOP_ERR | 16 | RO | 0 | LSB TX PHY received a packet without SOP from one of the processors. | +| RSVD | 15 | RO | 0 | Reserved | +| LSB_RX_REV_NO_ERR | 14 | RO | 0 | REV of the received packet does not match with the REV_NO of the LSB RX PHY. | +| LSB_RX_UNEXP_ERR | 13 | RO | 0 | Unexpected condition in LSB RX PHY.
1: means RX_BUF is almost full or LSB_RX_PHY_CTRL has received a packet without SOP from DES (deserializer) | +| LSB_RX_SEQNO_ERR | 12 | RO | 0 | LSB RX PHY received a packet from remote party with invalid SEQ no. | +| LSB_RX_DEV_ID_ERR | 11 | RO | 0 | LSB RX PHY received a packet from remote party with invalid DEV-ID. | +| LSB_RX_FATAL_ERR | 10 | RO | 0 | One of the state machines in LSB RX PHY has gone momentarily to unknown state. | +| LSB_RX_LNGTH_ERR | 9 | RO | 0 | LSB RX PHY received a packet from remote party with invalid Length. | +| LSB_RX_CHKSM_ERR | 8 | RO | 0 | LSB RX PHY received a packet from remote party with checksum error. | +| RSVD | 7:0 | RO | 0 | Reserved | + +#### ICB_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:24 | RO | All 0s | Reserved | +| HSC_ENC_LATCH_OFF | 23:21 | RW | 0x0 | Send special Encoded Reset to ICB to hotswap controllers LATCH_OFF signal
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will power OFF system until switch tray removal.
This Field is automatically cleared by FPGA after reset is issued. | +| HSC_ENC_RST | 19:16 | RW | 0x0 | Send special Encoded Reset to ICB to toggle hotswap controllers
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will cycle the system power.
This Field is automatically cleared by FPGA after reset is issued. | +| RSVD | 15:12 | RO | All 0s | Reserved | +| ICB_LSB_RST | 11:8 | RW | 0x0 | Reset control of ICB LSB
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will reset the ICB LSB port and all related processors.
This Field is automatically cleared by FPGA after reset is issued. | +| RSVD | 7:4 | RO | 0 | Reserved | +| ICB_ERST | 3:0 | RW | 0 | Reset control of ICB
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will send encoded reset to the SWB on the respective switch board. The reset will be sent once, when this field is set to 0xD.
This Field is automatically cleared by FPGA after encoded reset is issued. | + +#### ICB_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0002 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:28 | RO | All 0s | Reserved | +| LSB_PROC_TYP_ERR | 27 | RO | 0 | One of the processors in LSB port received a packet with an invalid value in type field. | +| LSB_PROC_FATAL_ERR | 26 | RO | 0 | One of the state machines in one of the processors in LSB port has gone momentarily to unknown state. | +| LSB_PROC_EOP_ERR | 25 | RO | 0 | One of the processors in LSB port received a packet without EOP. | +| LSB_PROC_SOP_ERR | 24 | RO | 0 | One of the processors in LSB port received a packet without SOP. | +| RSVD | 23:19 | RO | 0 | Reserved | +| LSB_TX_FATAL_ERR | 18 | RO | 0 | One of the state machines in LSB TX PHY has gone momentarily to unknown state. | +| LSB_TX_EOP_ERR | 17 | RO | 0 | LSB TX PHY received a packet without EOP from one of the processors. | +| LSB_TX_SOP_ERR | 16 | RO | 0 | LSB TX PHY received a packet without SOP from one of the processors. | +| RSVD | 15 | RO | 0 | Reserved | +| LSB_RX_REV_NO_ERR | 14 | RO | 0 | REV of the received packet does not match with the REV_NO of the LSB RX PHY. | +| LSB_RX_UNEXP_ERR | 13 | RO | 0 | Unexpected condition in LSB RX PHY.
1: means RX_BUF is almost full or LSB_RX_PHY_CTRL has received a packet without SOP from DES (deserializer) | +| LSB_RX_SEQNO_ERR | 12 | RO | 0 | LSB RX PHY received a packet from remote party with invalid SEQ no. | +| LSB_RX_DEV_ID_ERR | 11 | RO | 0 | LSB RX PHY received a packet from remote party with invalid DEV-ID. | +| LSB_RX_FATAL_ERR | 10 | RO | 0 | One of the state machines in LSB RX PHY has gone momentarily to unknown state. | +| LSB_RX_LNGTH_ERR | 9 | RO | 0 | LSB RX PHY received a packet from remote party with invalid Length. | +| LSB_RX_CHKSM_ERR | 8 | RO | 0 | LSB RX PHY received a packet from remote party with checksum error. | +| RSVD | 7:3 | RO | 0 | Reserved | +| ICB_INT | 2 | RO | 0 | INT request of PDB board
1: ICB requests interrupt
0: No interrupt requested
This bit stores the filtered status of the pin | +| ICB_RDY | 1 | RO | 1 | Ready status of ICB FPGA
1: ICB is Ready
0: ICB is Not Ready
This bit stores the filtered status of the pin. | +| RSVD | 1:0 | RO | 0 | Reserved | + +#### SWB_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:12 | RO | All 0s | Reserved | +| SWB_LSB_RST | 11:8 | RW | 0 | Reset control of SWB_FPGA LSB
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will reset the SWB_FPGA LSB port and all related processors.
This Field is automatically cleared by FPGA after reset is issued. | +| SWB_PERST | 7:4 | RW | All 0s | PCIE Reset control of SWB
0xD: Asserted
Any other value: De-asserted
This Field is NOT automatically cleared by FPGA after reset is issued. | +| SWB_ERST | 3:0 | RW | 0 | Reset control of SWB
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will send encoded reset to the SWB on the respective switch board. The reset will be sent once, when this field is set to 0xD.
This Field is automatically cleared by FPGA after encoded reset is issued. | + +#### SWB_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0001 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:28 | RO | All 0s | Reserved | +| LSB_PROC_TYP_ERR | 27 | RO | 0 | One of the processors in LSB port received a packet with an invalid value in type field. | +| LSB_PROC_FATAL_ERR | 26 | RO | 0 | One of the state machines in one of the processors in LSB port has gone momentarily to unknown state. | +| LSB_PROC_EOP_ERR | 25 | RO | 0 | One of the processors in LSB port received a packet without EOP. | +| LSB_PROC_SOP_ERR | 24 | RO | 0 | One of the processors in LSB port received a packet without SOP. | +| RSVD | 23:19 | RO | 0 | Reserved | +| LSB_TX_FATAL_ERR | 18 | RO | 0 | One of the state machines in LSB TX PHY has gone momentarily to unknown state. | +| LSB_TX_EOP_ERR | 17 | RO | 0 | LSB TX PHY received a packet without EOP from one of the processors. | +| LSB_TX_SOP_ERR | 16 | RO | 0 | LSB TX PHY received a packet without SOP from one of the processors. | +| RSVD | 15 | RO | 0 | Reserved | +| LSB_RX_REV_NO_ERR | 14 | RO | 0 | REV of the received packet does not match with the REV_NO of the LSB RX PHY. | +| LSB_RX_UNEXP_ERR | 13 | RO | 0 | Unexpected condition in LSB RX PHY.
1: means RX_BUF is almost full or LSB_RX_PHY_CTRL has received a packet without SOP from DES (deserializer) | +| LSB_RX_SEQNO_ERR | 12 | RO | 0 | LSB RX PHY received a packet from remote party with invalid SEQ no. | +| LSB_RX_DEV_ID_ERR | 11 | RO | 0 | LSB RX PHY received a packet from remote party with invalid DEV-ID. | +| LSB_RX_FATAL_ERR | 10 | RO | 0 | One of the state machines in LSB RX PHY has gone momentarily to unknown state. | +| LSB_RX_LNGTH_ERR | 9 | RO | 0 | LSB RX PHY received a packet from remote party with invalid Length. | +| LSB_RX_CHKSM_ERR | 8 | RO | 0 | LSB RX PHY received a packet from remote party with checksum error. | +| RSVD | 7:3 | RO | 0 | Reserved | +| SWB_INT | 2 | RO | 0 | INT request of switch board
1: SWB requests interrupt
0: No interrupt requested
This bit stores the filtered status of the pin | +| RSVD | 1 | RO | 0 | Reserved | +| SWB_PRSNT | 0 | RO | 1 | Present status of switch board
1: SWB is present
0: SWB is Not Present
This bit stores the filtered status of the pin. | + +#### BMC_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0160 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:9 | RO | All 0s | Reserved | +| BMC_BOOT_SEL | 8 | RW | 1 | Boot selection for BMC
1: SPI flash
0: UART | +| BMC_PWR_EN | 7:4 | RW | 0x6 | Power control of BMC
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | +| BMC_RST | 3:0 | RW | 0x0 | Reset control of BMC
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will reset the BMC module.
This Field is automatically cleared by FPGA after reset is issued. | + +#### BMC_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:5 | RO | All 0s | Reserved | +| BMC_WDT_RST | 4 | RO | 0 | BMC Watchdog reset
1: Asserted
0: De-asserted | +| RSVD | 3:1 | RO | All 0s | Reserved | +| BMC_PRSNT | 0 | RO | 0 | Present status of BMC
1: Present
0: Not present | + +#### THRM_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:7 | RO | All 0s | Reserved | +| TEMP_SNSR_TMP432A_ALERT | 6 | RO | 0 | On-board Temp Sensor (TM432A) alert, monitor location A,B and E (see ES for details)
1: Asserted
0: De-asserted | +| TEMP_SNSR_TMP75_D_ALERT | 5 | RO | 0 | On-board Temp Sensor (TMP75) alert, monitor location D (see ES for details)
1: Asserted
0: De-asserted | +| TEMP_SNSR_TMP75_C_ALERT | 4 | RO | 0 | On-board Temp Sensor (TMP75) alert, monitor location C (see ES for details)
1: Asserted
0: De-asserted | +| RSVD | 3:2 | RO | All 0s | Reserved | +| CPU_EXT_TEMP_SNSR_ALERT | 1 | RO | 0 | CPU External Temp Sensor (TMP461) alert, monitor CPU local, PMC and SSD temperature
1: Asserted
0: De-asserted
(signal is buffered from PMC) | +| CPU_INT_THRM_TRIP | 0 | RO | 0 | CPU over temperature and unconditional shutdown
1: Asserted
0: De-asserted
(signal is buffered from PMC) | + +#### USB_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0006 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | All 0s | Reserved | +| USB_5V_EN | 3:0 | RW | 0x6 | Enable for USB 5V current limit switch
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | + +#### USB_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| USB_VBUS_DET | 1 | RO | 0 | 1: USB VBUS detected
0: USB VBUS not detected
(signal is buffered from PMC) | +| USB_5V_FAULT | 0 | RO | 0 | 1: USB 5V fault is asserted
0: USB 5V fault is not asserted
(signal is buffered from PMC) | + +#### BTN_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| FP_BTN | 0 | RO | 0 | Front Panel button is pressed.
1: Asserted
0: De-asserted | + +#### LEAK_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| LEAK_ALERT | 1 | RO | 0 | Leak ADC module Alert
1: Asserted
0: De-asserted | +| LEAK_ADC_INT | 0 | RO | 0 | Leak ADC module Interrupt
1: Interrupt asserted
0: Interrupt de-asserted | + +#### NFC_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | All 0s | Reserved | +| NFC_EN | 3:0 | RO | 0 | Enable (Wake) signal of NFC module
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | + +#### NFC_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0001 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:3 | RO | All 0s | Reserved | +| NFC_INT | 2 | RO | 0 | INT request of NFC module
1: NFC requests interrupt
0: No interrupt requested
This bit stores the filtered status of the pin | +| RSVD | 1 | RO | 0 | Reserved | +| NFC_PRSNT | 0 | RO | 1 | Present status of NFC module
1: NFC is present
0: NFC is Not Present
This bit stores the filtered status of the pin. | + +#### INTRD_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +Intrusion detection status + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| HANDLE_INT | 1 | RO | 0 | Interrupt of tray service or removal intent
1: Interrupt is asserted
0: Interrupt is not asserted | +| COVER_INT | 0 | RO | 0 | Interrupt of top cover
1: Interrupt is asserted
0: Interrupt is not asserted | + +#### BTRY_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| BTRY_UDV_ALERT | 0 | RO | 0 | Battery Under-voltage alert
1: Asserted
0: De-asserted | + +#### EN_ACCSS_PRTCTD_REG + +This register is to protect critical registers from accidental writes. SW should write 0x8F35_D72C in order to have write access to protected registers. + +**Card Type:** All · **FPGA Type:** PMC · **Function:** None · **POR Value:** 0x0000_0000 + +Enables access to protected registers. + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| EN_ACCSS | 31:0 | RW | 0 | 0x8F35_D72C: Enables access to protected registers.
Other Values: Disables access to protected registers. | + +#### UART_MUX_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:26 | RO | All 0s | Reserved | +| SWB1_MUX_SEL | 25:24 | RW | 0x0 | SWB1 MUX select
3: UART Channel 4
2: UART Channel 3
1: UART Channel 2
0: UART Channel 1 | +| RSVD | 23:22 | RO | All 0s | Reserved | +| SWB0_MUX_SEL | 21:20 | RW | 0x0 | SWB0 MUX select
3: UART Channel 4
2: UART Channel 3
1: UART Channel 2
0: UART Channel 1 | +| RSVD | 19:18 | RO | All 0s | Reserved | +| BMC_MUX_SEL | 17:16 | RW | 0x0 | BMC MUX select
2: SWB1
1: SWB0
0: USB Console | +| RSVD | 15:14 | RO | All 0s | Reserved | +| CPU_DBG_MUX_SEL | 13:12 | RW | 0x0 | CPU Debug MUX select
2: SWB1
1: SWB0
0: USB Console | +| RSVD | 11:10 | RO | All 0s | Reserved | +| CPU_CNSL_MUX_SEL | 9:8 | RW | 0x0 | CPU Console MUX select
2: SWB1
1: SWB0
0: USB Console | +| RSVD | 7:5 | RO | All 0s | Reserved | +| USB_CNSL_MUX_SEL | 4:0 | RW | 0x0 | USB Console MUX select
4: SWB1
3: SWB0
2: BMC
1: CPU Debug
0: CPU Console | + +#### I2C_MUX_RST_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** none · **POR Value:** 0x0000_00DD + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| I2C_CH14_MUX_RST | 7:4 | RW | 0xD | Reset control of I2C CH14 MUX
0xD: Asserted
Any other value: de-asserted.
This Field is NOT automatically cleared by FPGA after reset is issued. | +| I2C_CH10_MUX_RST | 3:0 | RW | 0xD | Reset control of I2C CH10 MUX
0xD: Asserted
Any other value: de-asserted.
This Field is NOT automatically cleared by FPGA after reset is issued. | + +#### CPU_INTR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| CPU_INTR_2 | 1 | RW | 0 | Control interrupt 2 to CPU
1: Assert interrupt
0: De-assert interrupt | +| CPU_INTR_1 | 0 | RW | 0 | Control interrupt 1 to CPU
1: Assert interrupt
0: De-assert interrupt | + +#### BMC_JTAG_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +Controls the source to/fom JTAG pins of BMC + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| TDO | 7 | RO | 0 | Input, Connected to BMC TDO pin | +| TDI | 6 | RW | 0 | Output Connected to BMC TDI pin | +| TMS | 5 | RW | 0 | Output Connected to BMC TMS pin | +| TCK | 4 | RW | 0 | Output Connected to BMC TCK pin | +| RSVD | 3:1 | RO | All 0s | Reserved | +| JTAG_SEL | 0 | RW | 0 | Select the source to BMC JTAG
0: On-board JTAG header
1: CB control with bit [6:4] | + +#### SWB_JTAG_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0100 + +Controls the source to/fom JTAG pins of SWB + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:9 | RO | All 0s | Reserved | +| TRST | 8 | RW | 1 | Output Connected to SWB TRST pin | +| TDO | 7 | RO | 0 | Input, Connected to SWB TDO pin | +| TDI | 6 | RW | 0 | Output Connected to SWB TDI pin | +| TMS | 5 | RW | 0 | Output Connected to SWB TMS pin | +| TCK | 4 | RW | 0 | Output Connected to SWB TCK pin | +| RSVD | 3:0 | RO | All 0s | Reserved | + +#### FLSH_CTRL_REG + +This register is clear under two conditions only. + +- Upon assertion of global reset. +- Power cycle +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:12 | RO | All 0s | Reserved | +| PHY2_RETIMER_WP | 11 | RW | 0 | PHY Retimer Write Protect
1: Protected,
Once asserted, cannot be de-asserted by SW. | +| PHY2_I210_CTRLR_SPI_WP | 10 | RW | 0 | PHY I210 Ethernet Controller SPI Write Protect
1: Protected,
Once asserted, cannot be de-asserted by SW. | +| PHY1_84991_WP | 9 | RW | 0 | PHY 84991 Write Protect
1: Protected,
Once asserted, cannot be de-asserted by SW. | +| BMC_EEPRM_WP | 8 | RW | 0 | BMC EEPROM Write Protect
1: Protected,
Once asserted, cannot be de-asserted by SW. | +| RSVD | 7:3 | RO | All 0s | Reserved | +| ZEROIZATION_WP | 2 | RW | 0 | 1: Protected,
Once asserted, cannot be de-asserted by SW.
SW writes into this register bit during boot and use it as a gate for zeroization.  This would block a user from running zeroization (or parts of it) in Service-OS and Product-OS.  It also blocks them clearing a sticky bit. | +| FPGA_FLSH_WP | 1 | RW | 0 | FPGA (CB) Flash Write Protect
1: Protected,
Once asserted, FPGA will not issue any write/erase command to the flash.
Once asserted, cannot be de-asserted by SW. | +| CHSS_EEPRM_WP | 0 | RW | 0 | System Key EEPROM Write Protect
1: Protected,
Once asserted, cannot be de-asserted by SW. | + +#### LED_SYNC_REG + +#### LED_CONFIG_REG + +#### LED_CTRL_0_REG + +For bit definitions please refer to the section “LED Control bits”. + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:24 | RO | All 0s | Reserved | +| UID | 23:16 | RW | 0x0 | Locator LED | +| ALM_STAT | 15:8 | RW | 0x0 | Alarm status LED | +| SYS_STAT | 7:0 | RW | 0x0 | System status LED | + +#### LED_CTRL_1_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| PSU_STAT | 7:0 | RW | 0x0 | Fan status LED | + +#### LED_CTRL_2_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| FAN_STAT | 7:0 | RW | 0x0 | Fan status LED | + +#### LED_CTRL_3_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| LEAK_STAT | 7:0 | RW | 0x0 | LEAK status LED | + +#### LED_CTRL_4_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:16 | RO | All 0s | Reserved | +| PHY_84991_ACT_STAT | 15:8 | RW | 0x0 | PHY 84991 activity status
bit [7:6] option available (see Chapter 5):
00 = SW control
01 = PHY 84991 LED 0 driver
10 = PHY 84991 LED 1 driver
11 = PHY 84991 LED 2 driver | +| PHY_84991_LINK_STAT | 7:0 | RW | 0x0 | PHY 84991 link status
bit [7:6] option available (see Chapter 5):
00 = SW control
01 = PHY 84991 LED 0 driver
10 = PHY 84991 LED 1 driver
11 = PHY 84991 LED 2 driver | + +#### LED_CTRL_5_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:16 | RO | All 0s | Reserved | +| PHY_I210_ACT_STAT | 15:8 | RW | 0x0 | PHY I210 activity status
bit [7:6] option available (see Chapter 5):
00 = SW control
01 = PHY I210 LED 0 driver
10 = PHY I210 LED 1 driver
11 = PHY I210 LED 2 driver | +| PHY_I210_LINK_STAT | 7:0 | RW | 0x0 | PHY I210 link status
bit [7:6] option available (see Chapter 5):
00 = SW control
01 = PHY I210 LED 0 driver
10 = PHY I210 LED 1 driver
11 = PHY I210 LED 2 driver | + +#### WDG_CTRL_REG + +This register will be reset upon CPU POR reset. + +**Card Type:** All · **FPGA Type:** CB · **Function:** none · **POR Value:** 0x3000_0FFF + +Watchdog control register + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| WDG_INT_EN | 31 | RW | 0 | 1: Enables wdog interrupt.
0: Disables wdog interrupt. | +| WDG_EN | 30:27 | RW | 0x6 | 0x6: Enables wdog counter.
0x9: Disables wdog counter.
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous on/off status.
After CPU POR reset is asserted, the wdog counter enable status follows the behavior below:
POR value when the register bit WDG_EN_POR_MSK of TND_CTRL_REG is de-asserted.
Register bit WDG_EN when the WDG_EN_POR_MSK of TND_CTRL_REG is asserted.
CPU POR reset will be asserted if WDG_EN is asserted and WDG_CNTR_VALUE = WDG_LNGTH | +| RSVD | 26:12 | RO | 0 | Reserved | +| WDG_LNGTH | 11:0 | RW | 0xFFF | Number of 100ms ticks before the watchdog triggers.
FPGA will never allow 0x000 to be written in this field. If SW tries write 0x000 in this field, FPGA will write POR value in this register.
Count Time (ms)
0x0 illegal value
0x1 100.0
0x2 200.0
... ... | + +#### WDG_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** none · **POR Value:** 0x0000_0000 + +Watchdog status register + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| WDG_INT | 31 | RO | 0 | 1: Asserted, wdog interrupt occurred.
0: De-asserted, no interrupt yet.
WDG_INT will be asserted if WDG_INT_EN is asserted and WDG_CNTR_VALUE = WDG_LNGTH | +| RSVD | 30:12 | RO | 0 | Reserved | +| WDG_CNTR_VLUE | 11:0 | RO | 0 | Illustrates the current value of wdog counter.
Watchdog counter value will keep incrementing if WDG_EN is asserted.
Watchdog counter will stop incrementing if counter value gets equal to WDG_LNGTH.
Watchdog counter will reset to zero if WDG_EN bit is de-asserted or CPU POR reset is asserted. | + +#### WDG_RST_REG + +Any write to this register will reset the watchdog counter and de-assert the interrupt. + +**Card Type:** All · **FPGA Type:** CB · **Function:** none · **POR Value:** 0x0000_0000 + +Watchdog reset register + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:0 | RO | 0 | Reserved | + +#### TND_CTRL_REG + +#### TND_STAT_REG + +#### TND_PWR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_01FF + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:21 | RO | All 0s | Reserved | +| PSSM_DBG_PIN_OVR | 20 | RW | 0 | Enable override of PSSM for all bits [14:2] below
1: Enable
0: Disable | +| RSVD | 19:17 | RO | 0 | Reserved | +| PSSM_PWR_EN_OVR | 16 | RW | 0 | Enable override of PSSM for all bits [8:0] below
1: Enable
0: Disable | +| RSVD | 15 | RO | 0 | Reserved | +| SWB1_BYPASSBOOT | 14 | RW | 0 | SWB1 Bypass Boot value | +| SWB0_BYPASSBOOT | 13 | RW | 0 | SWB0 Bypass Boot value | +| DBGBOOT | 12 | RW | 0 | Debugboot value | +| RSVD | 11:9 | RO | All 0s | Reserved | +| SWB1_PWREN | 8 | RW | 1 | | +| SWB1_STBYEN | 7 | RW | 1 | | +| SWB0_PWREN | 6 | RW | 1 | | +| SWB0_STBYEN | 5 | RW | 1 | | +| PHY2_1V8_PWREN | 4 | RW | 1 | | +| PHY2_0V8_AVDD_PWREN | 3 | RW | 1 | | +| PHY2_0V8_DVDD_PWREN | 2 | RW | 1 | | +| PHY_V3P3_PWREN | 1 | RW | 1 | | +| CPU_MDL_PWREN | 0 | RW | 1 | Power enable overrides
1: Enable
0: Disable | + +#### TND_PWR_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_01FF + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:19 | RO | All 0s | Reserved | +| DIP_SWB1_BYPASSBOOT | 18 | RO | 0 | SWB1 Bypass Boot DIP switch position | +| DIP_SWB0_BYPASSBOOT | 17 | RO | 0 | SWB0 Bypass Boot DIP switch position | +| DIP_DBGBOOT | 16 | RO | 0 | Debugboot DIP switch position | +| RSVD | 15:9 | RO | All 0s | Reserved | +| SWB1_ALL_PG | 8 | RO | 1 | | +| SWB1_STBY_PG | 7 | RO | 1 | | +| SWB0_ALL_PG | 6 | RO | 1 | | +| SWB0_STBY_PG | 5 | RO | 1 | | +| PHY2_1V8_PG | 4 | RO | 1 | | +| PHY2_0V8_AVDD_PG | 3 | RO | 1 | | +| PHY2_0V8_DVDD_PG | 2 | RO | 1 | | +| PHY_0V8_AVDD_PG | 1 | RO | 1 | | +| CPU_MDL_PG | 0 | RO | 1 | Pgood status | + +#### TND_CLK_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0006_6066 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:20 | RO | All 0s | Reserved | +| BUF2_En1 | 19:16 | RW | 0x6 | Clock Buffer 2 Output Enable 1 | +| BUF2_En0 | 15:12 | RW | 0x6 | Clock Buffer 2 Output Enable 0 | +| RSVD | 11:8 | RO | All 0s | Reserved | +| BUF1_En1 | 7:4 | RW | 0x6 | Clock Buffer 1 Output Enable 1 | +| BUF1_En0 | 3:0 | RW | 0x6 | Clock Buffer 1 Output Enable 0
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | + +#### TND_PMC_GPIO_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:15 | RO | 0 | Reserved | +| GPI_14 | 14 | RW | 0 | | +| GPI_13 | 13 | RW | 0 | | +| GPI_12 | 12 | RW | 0 | | +| GPI_11 | 11 | RW | 0 | | +| GPI_10 | 10 | RW | 0 | | +| GPI_9 | 9 | RW | 0 | | +| GPI_8 | 8 | RW | 0 | | +| GPI_7 | 7 | RW | 0 | | +| GPI_6 | 6 | RW | 0 | | +| GPI_5 | 5 | RW | 0 | 1: Assert GPIO 5
0: De-assert GPIO 5 | +| RSVD | 4:0 | RO | 0 | Reserved | + +#### TND_PMC_GPIO_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:5 | RO | All 0s | Reserved | +| GPO_14 | 14 | RO | 0 | | +| GPO_13 | 13 | RO | 0 | | +| GPO_12 | 12 | RO | 0 | | +| GPO_11 | 11 | RO | 0 | | +| GPO_10 | 10 | RO | 0 | | +| GPO_9 | 9 | RO | 0 | | +| GPO_8 | 8 | RO | 0 | | +| GPO_7 | 7 | RO | 0 | | +| GPO_6 | 6 | RO | 0 | | +| GPO_5 | 5 | RO | 0 | 1: GPIO 5 is asserted
0: GPIO 5 is de-asserted | +| RSVD | 4:0 | RO | All 0s | Reserved | + +#### TND_PMC_GPIO_DIR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:15 | RO | 0 | Reserved | +| GPIO_DIR_14 | 14 | RW | 0 | | +| GPIO_DIR_13 | 13 | RW | 0 | | +| GPIO_DIR_12 | 12 | RW | 0 | | +| GPIO_DIR_11 | 11 | RW | 0 | | +| GPIO_DIR_10 | 10 | RW | 0 | | +| GPIO_DIR_9 | 9 | RW | 0 | | +| GPIO_DIR_8 | 8 | RW | 0 | | +| GPIO_DIR_7 | 7 | RW | 0 | | +| GPIO_DIR_6 | 6 | RW | 0 | | +| GPIO_DIR_5 | 5 | RW | 0 | 1: Indicate GPIO 5 is configured as output and register GPIO_CTRL_REG is used to control this output port value.
0: Indicate GPIO 5 is configured as input and register GPIO_STAT_REG store this input port value. | +| RSVD | 4:0 | RO | 0 | Reserved | + +#### TND_BMC_GPIO_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:7 | RO | 0 | Reserved | +| GPI_6 | 6 | RW | 0 | | +| GPI_5 | 5 | RW | 0 | | +| GPI_4 | 4 | RW | 0 | | +| GPI_3 | 3 | RW | 0 | | +| GPI_2 | 2 | RW | 0 | | +| RSVD | 1 | RO | 0 | Reserved | +| GPI_0 | 0 | RW | 0 | 1: Assert GPIO 0
0: De-assert GPIO 0 | + +#### TND_BMC_GPIO_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:7 | RO | All 0s | Reserved | +| GPO_6 | 6 | RO | 0 | | +| GPO_5 | 5 | RO | 0 | | +| GPO_4 | 4 | RO | 0 | | +| GPO_3 | 3 | RO | 0 | | +| GPO_2 | 2 | RO | 0 | | +| RSVD | 1 | RO | 0 | Reserved | +| GPO_0 | 0 | RO | 0 | 1: GPIO 0 is asserted
0: GPIO 0 is de-asserted | + +#### TND_BMC_GPIO_DIR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:7 | RO | 0 | Reserved | +| GPIO_DIR_6 | 6 | RW | 0 | | +| GPIO_DIR_5 | 5 | RW | 0 | | +| GPIO_DIR_4 | 4 | RW | 0 | | +| GPIO_DIR_3 | 3 | RW | 0 | | +| GPIO_DIR_2 | 2 | RW | 0 | | +| RSVD | 1 | RO | 0 | Reserved | +| GPIO_DIR_0 | 0 | RW | 0 | 1: Indicate GPIO 0 is configured as output and register GPIO_CTRL_REG is used to control this output port value.
0: Indicate GPIO 0 is configured as input and register GPIO_STAT_REG store this input port value. | + +#### TND_SWB_GPIO_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | 0 | Reserved | +| GPI_7 | 7 | RW | 0 | | +| GPI_6 | 6 | RW | 0 | 1: Assert GPIO 6
0: De-assert GPIO 6 | +| RSVD | 5:0 | RO | 0 | Reserved | + +#### TND_SWB_GPIO_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| GPO_7 | 7 | RO | 0 | | +| GPO_6 | 6 | RO | 0 | 1: GPIO 6 is asserted
0: GPIO 6 is de-asserted | +| RSVD | 5:0 | RO | 0 | Reserved | + +#### TND_SWB_GPIO_DIR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | 0 | Reserved | +| GPIO_DIR_7 | 7 | RW | 0 | | +| GPIO_DIR_6 | 6 | RW | 0 | 1: Indicate GPIO 6 is configured as output and register GPIO_CTRL_REG is used to control this output port value.
0: Indicate GPIO 6 is configured as input and register GPIO_STAT_REG store this input port value. | +| RSVD | 5:0 | RO | 0 | Reserved | + +#### TND_ICB_GPIO_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| GPI_3 | 3 | RW | 0 | | +| GPI_2 | 2 | RW | 0 | | +| GPI_1 | 1 | RW | 0 | 1: Assert GPIO 1
0: De-assert GPIO 1 | +| RSVD | 0 | RO | 0 | Reserved | + +#### TND_ICB_GPIO_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | All 0s | Reserved | +| GPO_3 | 3 | RO | 0 | | +| GPO_2 | 2 | RO | 0 | | +| GPO_1 | 1 | RO | 0 | 1: GPIO 1 is asserted
0: GPIO 1 is de-asserted | +| RSVD | 0 | RO | 0 | Reserved | + +#### TND_ICB_GPIO_DIR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 0 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| GPIO_DIR_3 | 3 | RW | 0 | | +| GPIO_DIR_2 | 2 | RW | 0 | | +| GPIO_DIR_1 | 1 | RW | 0 | 1: Indicate GPIO 1 is configured as output and register GPIO_CTRL_REG is used to control this output port value.
0: Indicate GPIO 1 is configured as input and register GPIO_STAT_REG store this input port value. | +| RSVD | 0 | RO | 0 | Reserved | + +#### RST_CAUSE_REG + +This is a protected register. This is sticky and does not get reset under global reset condition. + +**Card Type:** All · **FPGA Type:** CB · **Function:** None · **POR Value:** 0x0000_0001 + +Monitor the main PSSM + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| SW_RST_COOKIES | 31:16 | RW | All 0s | For SW to read and write. | +| RSVD | 15:9 | RO | All 0s | Reserved. | +| CLD_RST | 8 | W1C | 0 | This bit will be set if the System PGOOD is de-sserted from a good state. | +| RSVD | 7:4 | RO | All 0s | Reserved. | +| HW_THERM_RST | 3 | W1C | 0 | This bit will be set if the hardware thermal suicide is caused by CB. | +| WDG_RST | 2 | W1C | 0 | This bit will be set if the CB internal watch dog timer is expired. | +| SW_THERM_RST | 1 | W1C | 0 | This bit will be set when SW asserts thermal suicide by asserting #THERMAL_SUICIDE_MAIN field in PWR_CTRL_REG. | +| PWR_ON_RST | 0 | W1C | 1 | | + +#### RST_CAUSE_SWB_REG + +This is a protected register. This is sticky and does not get reset under global reset condition. + +**Card Type:** All · **FPGA Type:** CB · **Function:** None · **POR Value:** 0x0000_0001 + +Monitor the SWB PSSM + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| SW_RST_COOKIES | 31:16 | RW | All 0s | For SW to read and write. | +| RSVD | 15:9 | RO | All 0s | Reserved. | +| CLD_RST | 8 | W1C | 0 | This bit will be set if the SWB PGOOD is de-sserted from a good state. | +| RSVD | 7:4 | RO | All 0s | Reserved. | +| HW_THERM_RST | 3 | W1C | 0 | This bit will be set if the hardware thermal suicide is caused by SWB. | +| RSVD | 2 | RO | 0 | Reserved. | +| SW_THERM_RST | 1 | W1C | 0 | This bit will be set when SW asserts thermal suicide by asserting #THERMAL_SUICIDE_SWB_ field in PWR_CTRL_REG. | +| PWR_ON_RST | 0 | W1C | 1 | | + +#### + +#### Function 1 + +#### FPGA_REV_ID_REG + +#### FUNC_CAP_0_REG + +#### SCRTCH_n_REG + +#### DEV_MSI_0_PEND_REG (TBD) + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| MBOX_INT | 0 | RO | 0 | 1: MBOX requires service.
0: no service is requested. | + +#### DEV_MSI_0_INT_EN_REG (TBD) + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | 0 | Reserved | +| MBOX_INT_EN | 0 | RW | 0 | 1: MBOX interrupt is enabled.
0: MBOX interrupt is disabled. | + +#### FAN_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0666 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:17 | RO | All 0s | Reserved | +| ALL_FAN_FULL_SPD | 16 | RW | 0 | Control all Fans (1,2,3) to run at full speed
1: Full speed
0: Non full speed | +| RSVD | 15:12 | RW | 0x0 | Reserved | +| EFUSE_EN_FAN3 | 11:8 | RW | 0x6 | Enable of Fan3 EFUSE
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | +| EFUSE_EN_FAN2 | 7:4 | RW | 0x6 | Enable of Fan2 EFUSE
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | +| EFUSE_EN_FAN1 | 3:0 | RW | 0x6 | Enable of Fan1 EFUSE
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | + +#### FAN_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:13 | RO | All 0s | Reserved | +| FAN_CTRLR_ALERT | 12 | RO | 0 | Fan controller alert
1: Asserted
0: De-asserted | +| RSVD | 11 | RO | 0 | Reserved | +| ALRT_FAN_3 | 10 | RO | 0 | EFUSE alert of Fan 3
1: Asserted
0: De-asserted | +| ALRT_FAN_2 | 9 | RO | 0 | EFUSE alert of Fan 2
1: Asserted
0: De-asserted | +| ALRT_FAN_1 | 8 | RO | 0 | EFUSE alert of Fan 1
1: Asserted
0: De-asserted | +| RSVD | 7 | RO | 0 | Reserved | +| PG_FAN_3 | 6 | RO | 0 | Power status of Fan 3
1: Ok
0: Not Ok | +| PG_FAN_2 | 5 | RO | 0 | Power status of Fan 2
1: Ok
0: Not Ok | +| PG_FAN_1 | 4 | RO | 0 | Power status of Fan 1
1: Ok
0: Not Ok | +| RSVD | 3 | RO | 0 | Reserved | +| PRSNT_FAN_3 | 2 | RO | 0 | Present status of Fan 3
1: Present
0: Not present
This bit stores the filtered status of the pin. | +| PRSNT_FAN_2 | 1 | RO | 0 | Present status of Fan 2
1: Present
0: Not present
This bit stores the filtered status of the pin. | +| PRSNT_FAN_1 | 0 | RO | 0 | Present status of Fan 1
1: Present
0: Not present
This bit stores the filtered status of the pin. | + +#### RTM_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0001_009D + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:17 | RO | All 0s | Reserved | +| RTM_SERBOOT | 16 | RW | 1 | Enable of Serial Boot of Retimer
1: from SPI ROM
0: from MDIO | +| RSVD | 15:8 | RO | All 0s | Reserved | +| RTM_OSC_EN | 7:4 | RW | 0x9 | Enable of PHY 81381 retimer 156.25MHz clock
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | +| RTM_RST | 3:0 | RW | 0xD | Reset of PHY 81381 retimer
0xD: Asserted
Any other value: de-asserted.
This Field is automatically cleared by FPGA after reset is issued. | + +#### RTM_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| PHY_RTM_INT | 0 | RO | 0 | Interrupt of PHY 813881 retimer
1: Asserted
0: De-asserted | + +#### ETH_CTRLR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:3 | RO | All 0s | Reserved | +| SD_PIN2 | 2 | RW | 0x0 | SW defined output pin2 to I210 controller | +| SD_PIN1 | 1 | RW | 0x0 | SW defined output pin1 to I210 controller | +| SD_PIN0 | 0 | RW | 0x0 | SW defined output pin0 to I210 controller | + +#### ETH_CTRLR_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| I210_WAKE_INT | 1 | RO | 0 | ‘Wake’ signal from I210
1: Asserted
0: De-asserted | +| I210_ALRT_INT | 0 | RO | 0 | Alert from I210
1: Asserted
0: De-asserted | + +#### USRPRT_PWR_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0099 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| USRPRT_EFUSE_EN_P2 | 7:4 | RW | 0x9 | Enable EFUSE for UserPort 2
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | +| USRPRT_EFUSE_EN_P1 | 3:0 | RW | 0x9 | Enable EFUSE for UserPort 1
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | + +#### USRPRT_PWR_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| EFUSE_PG_P2 | 1 | RO | 0 | EFUSE Pgood of UserPort 2 (QSFP)
1: Asserted
0: De-asserted | +| EFUSE_PG_P1 | 0 | RO | 0 | EFUSE Pgood of UserPort 1 (QSFP)
1: Asserted
0: De-asserted | + +#### USRPRT_CTRL_0_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| P2_RST | 1 | RW | 0 | QSFP UserPort 2 Reset | +| P1_RST | 0 | RW | 0 | QSFP UserPort 1 Reset
1: Assert reset
0: De-assert reset | + +#### USRPRT_STAT_0_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| P2_INT | 1 | RO | 0 | QSFP UserPort 2 Interrupt
1: Asserted
0: De-asserted | +| P1_INT | 0 | RO | 0 | QSFP UserPort 1 Interrupt
1: Asserted
0: De-asserted | + +#### USRPRT_CTRL_1_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| P2_LP_MODE | 1 | RW | 0 | QSFP UserPort 2 LP Mode | +| P1_LP_MODE | 0 | RW | 0 | QSFP UserPort 1 LP Mode
1: Assert
0: De-assert | + +#### USRPRT_STAT_1_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| P2_ PRSNT | 1 | RO | 0 | QSFP UserPort 2 Present
1: Asserted
0: De-asserted | +| P1_PRSNT | 0 | RO | 0 | QSFP UserPort 1 Present
1: Asserted
0: De-asserted | + +#### PHY_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 1 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | All 0s | Reserved | +| PHY_RST | 3:0 | RW | 0x0 | PHY 84991 Reset
0xD: Asserted
Any other value: de-asserted.
This Field is automatically cleared by FPGA after reset is issued. | + +#### + +#### Function 2 + +#### FPGA_REV_ID_REG + +#### FUNC_CAP_0_REG + +#### SCRTCH_n_REG + +#### DEV_MSI_0_PEND_REG (TBD) + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| MBOX_INT | 0 | RO | 0 | 1: MBOX requires service.
0: no service is requested. | + +#### DEV_MSI_0_INT_EN_REG (TBD) + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | 0 | Reserved | +| MBOX_INT_EN | 0 | RW | 0 | 1: MBOX interrupt is enabled.
0: MBOX interrupt is disabled. | + +#### SPI_CMD_STAT_REG + +#### SPI_ADD_REG + +#### SPI_WR_DATA_REG + +#### SPI_RD_DATA_REG + +#### SPI_RST_REG + +#### GEN_SPI_RD_DATA_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +Data read from SPI Peripheral + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RD_DATA | 31:0 | RO | 0 | Data read back from SPI transaction. Number of bits based on #SPI_DATA_WIDTH
The read back data is obtain each time write operation is carried out by writing into the GEN_SPI_WR_DATA_REG. | + +#### GEN_SPI_WR_DATA_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +Data to be written into SPI Peripheral. + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| WR_DATA | 31:0 | RW | 0 | Data to be written. Number of bits written based on #SPI_DATA_WIDTH
Writing into this register will initiate the Generic SPI Master to send out the SPI transaction to the SPI Slave. | + +#### GEN_SPI_STAT + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0060 + +Status register for Generic SPI Master for SPI interface + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 30:9 | RO | All 0s | Reserved | +| ERR_BIT | 8 | RO | 0 | Indicate overrun error has occur. 1: Transmit overrun error or receive overrun error has occur.
0: No overrun error has occurred.
Recommendation: SW should check this bit before initiating a new command. | +| RRDY | 7 | RO | 0 | Indicate receive ready status.
1: SPI_RD_DATA_REG register contains valid data and is ready to be read.
0: SPI_RD_DATA_REG register does not contain valid data.
Reading the SPI_RD_DATA_REG clears this register to 0. | +| TRRDY | 6 | RO | 1 | Indicate transmit ready status.
1: Transmit shift register is empty.
0: Transmit shift register is not empty.
The SPI_WR_DATA_REG register is able to transmit data into transmit shift register only when this register field is set to empty. | +| TMT | 5 | RO | 1 | Indicate transmit shift register is empty.
1: Transmit shift register is empty.
0: Transmit shift register is not empty.
When the transmit shift register is empty, the next data will be transferred from SPI_WR_DATA_REG register. | +| TOE | 4 | RO | 0 | Indicate transmit overrun error.
1: SPI_WR_DATA_REG register received new data before previous data was removed into the shift register. | +| ROE | 3 | RO | 0 | Indicate receive overrun error.
1: SPI_RD_DATA_REG register received new data before previous data was read.
0: No new data received before previous data was read. | +| RSVD | 2:0 | RO | 0 | Reserved | + +#### GEN_SPI_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +Instruct FPGA to select SPI peripheral and enable interrupt request. + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:11 | RO | All 0s | Reserved. | +| SSO | 10 | RW | 0 | Control the Chip Select output pin based on the mask provided in SPI_SLV_SEL_REG register. 1: Assert the Chip Select for the SPI slave device
0: De-assert the Chip Select for the SPI slave device.
SPI Master will continue to exchange data frames with correspondent SPI slave when this register field is asserted. | +| RSVD | 9:8 | RO | 0 | Reserved | +| IRRDY | 7 | RW | 0 | Enable interrupt request for receiver ready.
1: Interrupt enabled.
0: Interrupt disabled. | +| RSVD | 6:0 | RO | 0 | Reserved | + +#### GEN_SPI_CFG_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0210 + +Instruct FPGA to configure the SPI Master + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:15 | RO | All 0s | Reserved. | +| SPI_MODE | 14:13 | RW | 00 | Control the SPI mode for the SPI transaction.
00 : Data sampled on rising edge and shifted out on falling edge (Clock polarity and clock phase is low.)
01 : Data sampled on the falling edge and shifted out on rising edge.(Clock polarity is low and clock phase is high)
10 : Data sampled on falling edge and shifted out on rising edge (Clock polarity is high and clock phase is low.)
11 : :Data sampled on rising edge and shifted out on falling edge (Clock polarity is high and clock phase is high.) | +| SPI_SHIFT_BIT | 12 | RW | 0 | Control whether the MSB or LSB bit is shifted out first.
0: MSB bit is shifted out first
1: LSB bit is shifted out first | +| SPI_CHP_SEL_DELAY | 11:8 | RW | 0x2 | Specify the delay based on half of the SPI clock period for the delay to send out the first data after Chip Select pin is asserted.
0x0: 0 SPI clock cycle
0x1: 0.5 SPI clock cycle
0x2: 1 SPI clock cycle
….
0xF: 7.5 SPI clock cycles | +| RSVD | 7 | RO | 0 | Reserved. | +| SPI_CLK_CNT | 6:4 | RW | 001 | The value in this field is the frequency divider of the system clock (75 MHz) to generate the serial clock for the SPI transaction.
000 75Mhz/2 (37.50 MHz)
001 75Mhz/4 (18.75 MHz)
010 75Mhz/6 (12.5 MHz)
011 75Mhz/8 (9.375 MHz)
100 75Mhz/10 (7.5 MHz)
101 75Mhz/12 (6.25 MHz)
110 75Mhz/14 (5.357 MHz)
111 75Mhz/16 (4.686 MHz)
SPI clock frequency in MHz = 75MHz / (2 * (#SPI_CLK_CNT + 1) | +| RSVD | 3:2 | RO | | Reserved. | +| SPI_DATA_WIDTH | 1:0 | RW | 00 | Specify number of bits send per each write or read transaction to the SPI slave.
00: 8 bits
01: 16 bits
10: 24 bits
11: 32 bits | + +#### GEN_SPI_SLV_SEL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +Instruct SPI Master to select which SPI slave to send transaction. + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| SPI_SLV_SEL | 31: 0 | RW | All 0s | Bit 0: Control the SPI slave 0 enable for SPI master access where 1 is enable and 0 is disable.

Bit 31: Control the SPI slave 0 enable for SPI master access where 1 is enable and 0 is disable. | + +#### MDIO_STAT_CMD_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x8000_0000 + +CPU Control of MDIO Master IP + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| MDIO_STATUS | 31 | RO | 1 | 0: MDIO transaction in progress
1: MDIO transaction completed
It returns the status of the MDIO state machine. Once a CPU write to the MDIO register has taken place, the state machine begins to serialize the command to the transceiver. During this period, the status bit returns 0 every time the CPU reads from the register, and CPU writes will have no effect. As soon as the operation completes and the MDIO state machine has returned to
idle, the status bit returns a one, and the CPU can safely read the data field or write a new command to the MDIO.
This value is only cleared (1'b0) when a CPU MDIO transaction is pending or in progress. Otherwise it is set (1’b1) to represent that the last CPU MDIO transaction completed correctly. | +| RSVD | 30 | RO | 0 | Reserved | +| START | 29:28 | RW | 0 | Indicate the start of an MDIO transaction. These start bits differ between Clause 22 and Clause 45 MDIO. Note: Start bits are transmitted lsb first, so software must program them in reverse order as shown below.
Clause 22
- start sequence 01, program start <= 10
Clause 45
- start sequence 00, program start <= 00 | +| OPCODE | 27:26 | RW | All 0s | Determines the operation to be performed by the Management interface. The available
opcodes differ between Clause 22 and Clause 45 MDIO.
Clause 22 MDIO applies to 10/100/1000 Mbs MACs and
Clause 45 MDIO applies to 10 GIG MACs.
Note: Op-code bits are transmitted lsb first, so software must program them in reverse order as shown below. See long description for details.
Clause 22
IEEE-opcode ASIC.opcode Description
00 00 - Not valid
01 10 - Write
10 01 - Read
11 11 - Not valid
Clause 45
IEEE-opcode ASIC.opcode Description
00 00 Address
01 10 Write
11 11 Read
10 01 Post-read Increment Address | +| PHYAD | 25:21 | RW | All 0s | It indicates which of 32 possible physical devices transceivers attached to this bus is being addressed. | +| REGAD | 20:16 | RW | All 0s | It indicates which of 32 possible registers within the physical device the CPU wishes to read/write. | +| DATA | 15:0 | RW | All 0s | The value in this field corresponds to the 16 bit value defined in the physical layer device data sheet or the 802.3u specification.
On writes to the physical layer device, management would write the value to be sent to the physical layer device in this field while it was writing the opcode and address fields.
On reads from the physical layer device, management will write the opcode and address fields. It will then monitor the status bit. When status bit is set (idle), it knows the data field has the value read from the physical layer device.
Writes to this field are ignored when not idle. Reads of this field may contain invalid data when not idle. | + +#### MDIO_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x00F8_0007 + +General control of MDIO Master IP + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:24 | RO | All 0s | Reserved | +| MDIO_PREAMBLE_CNT | 23:19 | RW | 1F | Programmable preamble for both CPU and MDIO Stack issued MDIO commands.
NOTE: For proper operation with some Phys, this value should be set to 31. | +| RSVD | 18:12 | RO | All 0s | Reserved | +| STACK_EN | 11 | RW | 0 | 1: Enables the MDIO Stack.
0: Disable MDIO Stack. MDIO under CPU control with MDIO_STAT_CMD_REG. | +| RSVD | 10:8 | RO | All 0s | Reserved | +| MDIO_PROG_CLK_DIV | 7:0 | RW | 7 | This register sets the mdio clock divide rate.
Period of clock =
((MDIO_PROG_CLK_DIV + 1)*13.33ns)*2
14 (8’hE) : 2.5 MHz
7 (8’h7) : 4.6875 MHZ
4 (8’h4) : 7.5 MHz
2 (8’h2) : 12.5 MHz
0 (8’h0) : 37.5 MHz | + +#### MDIO_STK_CTRL_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | 0 | Reserved | +| STACK_CMD_START | 0 | RW | 0 | 1: Enables MDIO stack operation
0: Legacy CPU-only operation using MDIO_STAT_CMD_REG.
Note:
Stack will stop executing after the current instruction if #STACK_EN is disabled before #STACK_END_ADD MDIO instruction is reached. #STACK_END_ADD is the address of #STACK_START_ADD + #STACK_NUM_CMDS | + +#### MDIO_STK_ADDR_CONF_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0080 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:19 | RO | 0 | Reserved | +| STACK_PROG_DELAY | 18:14 | RW | All 0s | The number of MDIO clock cycles (MDC) to way in between each MDIO stack command.
(This is provided just in case some PHY has issues with quick back-to-back MDIO transactions.) | +| STACK_NUM_CMDS | 13:7 | RW | 1 | The number of MDIO Stack RAM instructions/entries to execute starting at #STACK_START_ADDR.
(Notes: Reading past the end of the stack is also and END condition) | +| STACK_START_ADDR | 6:0 | RW | All 0s | Starting MDIO instruction in the stack to begin executing when #STACK_CMD_START and #STACK_EN are set | + +#### MDIO_STK_STAT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0003 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | 0 | Reserved | +| STACK_IDLE | 1 | RO | 1 | For DEBUG use only, should not use by SW
Indicates that the MDIO stack has completed its instruction and there are no longer any MDIO commands to be executed. This field will be cleared whenever a new MDIO stack instruction has been issued with a non-zero number of MDIO commands. | +| STACK_CMD_DONE | 0 | RO | 1 | 1: Stack processing done for all MDIO transactions of a given MDIO stack instruction specified in MDIO_STK_ADDR_CONF_REG and started from MDIO_STK_CTRL_REG. It also means the last #STACK_NUM_CMDS number of commands it was instructed to execute have been successfully completed.
0: This value is only cleared when the MDIO Stack has MDIO transactions pending or in progress | + +#### MDIO_STK_RAM_DATA_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +Individual stack value entry for corresponding #STACK_ADDR + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:30 | RO | All 0s | Reserved | +| START | 29:28 | RW | All 0s | See MDIO_STAT_CMD_REG #START | +| OPCODE | 27:26 | RW | All 0s | See MDIO_STAT_CMD_REG #OPCODE | +| PHYAD | 25:21 | RW | All 0s | See MDIO_STAT_CMD_REG #PHYAD | +| REGAD | 20:16 | RW | All 0s | See MDIO_STAT_CMD_REG #REGAD | +| DATA | 15:0 | RW | All 0s | See MDIO_STAT_CMD_REG #DATA | + +#### MDIO_STK_RAM_ADDR_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +MDIO Stack address + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | 0 | Reserved | +| STACK_ADDR | 7:0 | RW | 0 | Indicates address/position of stack that MDIO_STK_RAM_DATA_REG is writing/reading to | + +#### MDIO_STAT_INT_REG + +**Card Type:** All · **FPGA Type:** CB · **Function:** 2 · **POR Value:** 0x0000_0000 + +MDIO Status interrupt + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:6 | RO | 0 | Reserved | +| MDIO_STATUS_INT | 5 | W1C | 0 | Indicates a Single MDIO transaction is completed | +| STK_CMD_DONE_INT | 4 | W1C | 0 | Indicates a new stack of MDIO transactions is done. | +| RSVD | 3:2 | RO | 0 | Reserved | +| MDIO_STATUS_INT_EN | 1 | RW | 0 | Enable Single MDIO interrupt (rising edge of MDIO_STAT_CMD_REG #MDIO_STATUS) | +| STK_CMD_DONE_INT_EN | 0 | RW | 0 | Enable Stack MDIO interrupt (rising edge of MDIO_STK_STAT_REG #STK_CMD_DONE) | + +#### + +#### Function 3 + +#### FPGA_REV_ID_REG + +#### FUNC_CAP_0_REG + +#### SCRTCH_n_REG + +#### DEV_MSI_0_PEND_REG (TBD) + +**Card Type:** All · **FPGA Type:** CB · **Function:** 3 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| MBOX_INT | 0 | RO | 0 | 1: MBOX requires service.
0: no service is requested. | + +#### DEV_MSI_0_INT_EN_REG (TBD) + +**Card Type:** All · **FPGA Type:** CB · **Function:** 3 · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | 0 | Reserved | +| MBOX_INT_EN | 0 | RW | 0 | 1: MBOX interrupt is enabled.
0: MBOX interrupt is disabled. | + +#### I2C_PRSCL_LO_REG + +#### I2C_PRSCL_HI_REG + +#### I2C_CTRL_REG + +#### I2C_TX_REG + +#### I2C_RX_REG + +#### I2C_CMD_REG + +#### I2C_STAT_REG + +#### I2C_MUX_SEL_REG + +#### I2C_RST_REG + +#### + +### SWB Registers + +#### FPGA_REV_ID_REG + +#### FPGA_RECONFIG_CTRL_REG + +#### FPGA_RECONFIG_STAT_REG + +#### SCRTCH_n_REG + +#### SWB_INFO_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| TRAY_2_ID | 11:8 | RO | All 0s | Current Tray 2 ID value | +| TRAY_1_ID | 7:4 | RO | All 0s | Current Tray 1 ID value | +| RSVD | 3:1 | RO | All 0s | Reserved | +| SWB_ID | 0 | RO | 0 | Current SWB ID
0: SWB0
1: SWB1 | + +#### PWR_STAT_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| SWB_ALL_PGOK | 16 | RO | 0 | Indicates SWB power sequencing is completed
1: Asserted
0: De-asserted | +| RSVD | 15:1 | RO | All 0s | Reserved | +| TH6_VDD_CORE_VRM_INT | 0 | RO | 0 | TH6 VDD Power Interrupt
1: Asserted
0: De-asserted | + +#### CB_CTRL_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:12 | RO | All 0s | Reserved | +| LSB_RST_SWB | 11:8 | RW | 0 | Reset control of remote LSB
0xD: Asserted
Any other value: de-asserted.
When asserted by SW, will reset the SWB LSB port and all related processors.
This Field is automatically cleared by FPGA after reset is issued. | +| RSVD | 7:0 | RO | 0 | Reserved | + +#### CB_STAT_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:28 | RO | All 0s | Reserved | +| LSB_PROC_TYP_ERR | 27 | RO | 0 | One of the processors in LSB port received a packet with an invalid value in type field. | +| LSB_PROC_FATAL_ERR | 26 | RO | 0 | One of the state machines in one of the processors in LSB port has gone momentarily to unknown state. | +| LSB_PROC_EOP_ERR | 25 | RO | 0 | One of the processors in LSB port received a packet without EOP. | +| LSB_PROC_SOP_ERR | 24 | RO | 0 | One of the processors in LSB port received a packet without SOP. | +| RSVD | 23:19 | RO | 0 | Reserved | +| LSB_TX_FATAL_ERR | 18 | RO | 0 | One of the state machines in LSB TX PHY has gone momentarily to unknown state. | +| LSB_TX_EOP_ERR | 17 | RO | 0 | LSB TX PHY received a packet without EOP from one of the processors. | +| LSB_TX_SOP_ERR | 16 | RO | 0 | LSB TX PHY received a packet without SOP from one of the processors. | +| RSVD | 15 | RO | 0 | Reserved | +| LSB_RX_REV_NO_ERR | 14 | RO | 0 | REV of the received packet does not match with the REV_NO of the LSB RX PHY. | +| LSB_RX_UNEXP_ERR | 13 | RO | 0 | Unexpected condition in LSB RX PHY.
1: means RX_BUF is almost full or LSB_RX_PHY_CTRL has received a packet without SOP from DES (deserializer) | +| LSB_RX_SEQNO_ERR | 12 | RO | 0 | LSB RX PHY received a packet from remote party with invalid SEQ no. | +| LSB_RX_DEV_ID_ERR | 11 | RO | 0 | LSB RX PHY received a packet from remote party with invalid DEV-ID. | +| LSB_RX_FATAL_ERR | 10 | RO | 0 | One of the state machines in LSB RX PHY has gone momentarily to unknown state. | +| LSB_RX_LNGTH_ERR | 9 | RO | 0 | LSB RX PHY received a packet from remote party with invalid Length. | +| LSB_RX_CHKSM_ERR | 8 | RO | 0 | LSB RX PHY received a packet from remote party with checksum error. | +| RSVD | 7:0 | RO | 0 | Reserved | + +#### ASIC_CTRL_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x00DD_03DD + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:24 | RO | All 0s | Reserved | +| M0_CORE_RST | 23:20 | RW | 0xD | M0 Core Reset
0: Asserted
1: De-asserted | +| R8_CORE_RST | 19:16 | RW | 0xD | R8 Core Reset
0: Asserted
1: De-asserted | +| RSVD | 15:14 | RO | All 0s | Reserved | +| TH6_PCIE_LANE | 13:12 | RW | 0x0 | Select the maximum link width of PCIe interface:
0: x1 / x2 / x4 link width
1: x1 link width
2: x1 or x2 link width
3: Reserved | +| RSVD | 11:10 | RO | All 0s | Reserved | +| TH6_PCIE_GEN | 9:8 | RW | 0x3 | Select the operating rate of PCIe interface:
0: Gen1
1: Gen2
2: Gen3
3: Gen4 | +| TH6_PERST | 7:4 | RW | 0xD | TH6 PCIe Reset
0xD: Asserted
Any other value: de-asserted.
This Field is NOT automatically cleared by FPGA after reset is issued. | +| TH6_SYS_RST | 3:0 | RW | 0xD | TH6 System Reset
0xD: Asserted
Any other value: de-asserted.
This Field is NOT automatically cleared by FPGA after reset is issued. | + +#### ASIC_STAT_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| TH6_PHY_LINK_UP | 0 | RO | 0 | TH6 PHY Link status
1: Link is up
0: Link is down | + +#### RTM_CTRL_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_011D + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:9 | RO | All 0s | Reserved | +| RTM_MODESEL | 8 | RW | 1 | Enable of Mode Select of all Retimer (1-56)
1: Shared SPI ROM
0: Single SPI ROM | +| RSVD | 7:5 | RO | All 0s | Reserved | +| RTM_SERBOOT | 4 | RW | 1 | Enable of Serial Boot of all Retimers (1-56)
1: from SPI ROM
0: from MDIO | +| RTM_RST | 3:0 | RW | 0xD | Reset of all Retimers (1-56)
0xD: Asserted
Any other value: de-asserted.
This Field is NOT automatically cleared by FPGA after reset is issued. | + +#### THRM_STAT_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| TH6_TS_HW_OTP_INT | 1 | RO | 0 | TH6 thermal diodes temperature sensor HW OTP shutdown interrupt
1: Asserted
0: De-asserted | +| EXT_TEMPSNSR_ALERT | 0 | RO | 0 | Multiple external temperature sensor alert
1: Asserted
0: De-asserted | + +#### EN_ACCSS_PRTCTD_REG + +This register is to protect critical registers from accidental writes. SW should write 0x8F35_D72C in order to have write access to protected registers. + +**Card Type:** All · **FPGA Type:** PMC · **Function:** None · **POR Value:** 0x0000_0000 + +Enables access to protected registers. + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| EN_ACCSS | 31:0 | RW | 0 | 0x8F35_D72C: Enables access to protected registers.
Other Values: Disables access to protected registers. | + +#### I2C_MUX_RST_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| I2C_MUX1_RST | 7:4 | RW | 0x0 | Reset control of I2C MUX which has I2Cs of
CB_FPGA to SWB external temperature sensors.
0xD: Asserted
Any other value: de-asserted.
This Field is NOT automatically cleared by FPGA after reset is issued. | +| I2C_MUX0_RST | 3:0 | RW | 0x0 | Reset control of I2C MUX which has I2Cs of
CB_FPGA to clock gen, EEPROM and tray cartridge
0xD: Asserted
Any other value: de-asserted.
This Field is NOT automatically cleared by FPGA after reset is issued. | + +#### SPI_MUX_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:9 | RO | All 0s | Reserved | +| TH6_SPI_MUX_SEL | 8 | RW | 0 | MUX Select for TH6 SPI flash connection from:
1: SWB FPGA
0: TH6 ASIC | +| RSVD | 7:4 | RO | All 0s | Reserved | +| SWB_SPI_MUX_SEL | 4 | RW | 0 | MUX Select for SWB SPI flash connection from:
1: CB FPGA
0: SWB FPGA | +| RSVD | 3:1 | RO | All 0s | Reserved | +| CB_SPI_MUX_SEL | 0 | RW | 0 | MUX Select for CB SPI connection to:
1: Direct access to SWB SPI Flash
0: Pass-through SWB_FPGA (to access TH6 SPI flash) | + +#### FLSH_CTRL_REG + +This register is clear under two conditions only. + +- Upon assertion of global reset. +- Power cycle +**Card Type:** All · **FPGA Type:** SWB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:13 | RO | All 0s | Reserved | +| RTM_FLSH_WP | 12 | RW | 0 | Retimers Flash Write Protect
1: Protected,
Once asserted, FPGA will not issue any write/erase command to the flash.
Once asserted, cannot be de-asserted by SW. | +| RSVD | 11:9 | RO | All 0s | Reserved | +| TH6_FLSH_WP | 8 | RW | 0 | TH6 Flash Write Protect
1: Protected,
Once asserted, FPGA will not issue any write/erase command to the flash.
Once asserted, cannot be de-asserted by SW. | +| RSVD | 7:5 | RO | All 0s | Reserved | +| DIAG_EEPRM_WP | 4 | RW | 0 | Diagnostic EEPROM Write Protect
1: Protected,
Once asserted, FPGA will not issue any write/erase command to the flash.
Once asserted, cannot be de-asserted by SW. | +| RSVD | 3:2 | RO | All 0s | Reserved | +| FPGA_FLSH_WP | 1 | RW | 0 | FPGA (CB) Flash Write Protect
1: Protected,
Once asserted, FPGA will not issue any write/erase command to the flash.
Once asserted, cannot be de-asserted by SW. | +| RSVD | 0 | RO | 0 | Reserved | + +x + +#### TND_PWR_CTRL_0_REG + +This is a protected register by EN_ACCSS_PRTCTD_REG. + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x001F_FFFF + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:30 | RO | All 0s | Reserved | +| DIPSW_DEBUGBOOT | 29 | RW | 0 | Debug Boot value | +| JMP_3ASTG_BOOT | 28 | RW | 0 | 3AStg Boot value | +| RSVD | 27:25 | RO | All 0s | Reserved | +| PSSM_OVR | 24 | RW | 0 | Enable override of PSSM
1: Enable
0: Disable | +| RSVD | 23:21 | RO | All 0s | Reserved | +| PWREN_PVDD1V2_1 | 20 | RW | 1 | | +| PWREN_PVDD1V2_0 | 19 | RW | 1 | | +| PWREN_PVDD1V8_DUT | 18 | RW | 1 | | +| PWREN_PVDD_MDIO | 17 | RW | 1 | | +| PWREN_P1V8_DVDDIO_4 | 16 | RW | 1 | | +| PWREN_P1V8_DVDDIO_3 | 15 | RW | 1 | | +| PWREN_P1V8_DVDDIO_2 | 14 | RW | 1 | | +| PWREN_P1V8_DVDDIO_1 | 13 | RW | 1 | | +| PWREN_P0V75_DVDD_57 | 12 | RW | 1 | | +| PWREN_P0V75_DVDD_50 | 11 | RW | 1 | | +| PWREN_P0V75_DVDD_43 | 10 | RW | 1 | | +| PWREN_P0V75_DVDD_36 | 9 | RW | 1 | | +| PWREN_P0V75_DVDD_21 | 8 | RW | 1 | | +| PWREN_P0V75_DVDD_14 | 7 | RW | 1 | | +| PWREN_P0V75_DVDD_7 | 6 | RW | 1 | | +| PWREN_P0V75_DVDD_0 | 5 | RW | 1 | | +| PWREN_P1V8 | 4 | | | | +| PWREN_PVDD_3V_SYNTH_LDO_B1 | 3 | RW | 1 | | +| PWREN_PVDD_3V_SYNTH_LDO_A1 | 2 | RW | 1 | | +| PWREN_P3V3 | 1 | RW | 1 | | +| PWREN_P5V_STBY | 0 | RW | 1 | | + +#### TND_PWR_CTRL_1_REG + +This is a protected register by EN_ACCSS_PRTCTD_REG. + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x3FFF_FFFF + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:30 | RO | All 0s | Reserved | +| CLKEN_BOT_TOP_PLL_CLKIN | 29 | RW | 1 | | +| PWREN_PVDD1V2_T3 | 28 | RW | 1 | | +| PWREN_PVDD1V45_3 | 27 | RW | 1 | | +| PWREN_PVDD1V45_2 | 26 | RW | 1 | | +| PWREN_PVDD1V45_1 | 25 | RW | 1 | | +| PWREN_PVDD1V45_0 | 24 | RW | 1 | | +| PWREN_P1V5_CNDR1 | 23 | RW | 1 | | +| PWREN_P1V5_CNDR0 | 22 | RW | 1 | | +| PWREN_PVDD1V5_ANLG | 21 | RW | 1 | | +| PWREN_PVDD_0V9_3 | 20 | RW | 1 | | +| PWREN_PVDD_0V9_2 | 19 | RW | 1 | | +| PWREN_PVDD_0V9_1 | 18 | RW | 1 | | +| PWREN_PVDD_0V9_0 | 17 | RW | 1 | | +| PWREN_PVDD_0V9_ANLG_1 | 16 | RW | 1 | | +| PWREN_PVDD_0V9_ANLG_0 | 15 | RW | 1 | | +| PWREN_PVDD0_8V_T3 | 14 | RW | 1 | | +| PWREN_PVDDA_PHYT3_P3 | 13 | RW | 1 | | +| PWREN_PVDDA_PHYT2_P2 | 12 | RW | 1 | | +| PWREN_PVDDA_PHYT1_P1 | 11 | RW | 1 | | +| PWREN_PVDD0V75_ANLG_1 | 10 | RW | 1 | | +| PWREN_PVDD0V75_ANLG_0 | 9 | RW | 1 | | +| PWREN_PVDD_PHYTILE_7 | 8 | RW | 1 | | +| PWREN_PVDD_PHYTILE_6 | 7 | RW | 1 | | +| PWREN_PVDD_PHYTILE_5 | 6 | RW | 1 | | +| PWREN_PVDD_PHYTILE_4 | 5 | RW | 1 | | +| PWREN_PVDD_PHYTILE_3 | 4 | RW | 1 | | +| PWREN_PVDD_PHYTILE_2 | 3 | RW | 1 | | +| PWREN_PVDD_PHYTILE_1 | 2 | RW | 1 | | +| PWREN_PVDD_PHYTILE_0 | 1 | RW | 1 | | +| PWREN_FM_PVDD_CORE | 0 | RW | 1 | | + +#### TND_PWR_STAT_0_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| PG_P0V75_DVDD_26 | 31 | | | | +| PG_P0V75_DVDD_25 | 30 | | | | +| PG_P0V75_DVDD_24 | 29 | | | | +| PG_P0V75_DVDD_23 | 28 | | | | +| PG_P0V75_DVDD_22 | 27 | | | | +| PG_P0V75_DVDD_21 | 26 | | | | +| PG_P0V75_DVDD_20 | 25 | | | | +| PG_P0V75_DVDD_19 | 24 | | | | +| PG_P0V75_DVDD_18 | 23 | | | | +| PG_P0V75_DVDD_17 | 22 | | | | +| PG_P0V75_DVDD_16 | 21 | | | | +| PG_P0V75_DVDD_15 | 20 | | | | +| PG_P0V75_DVDD_14 | 19 | | | | +| PG_P0V75_DVDD_13 | 18 | | | | +| PG_P0V75_DVDD_12 | 17 | | | | +| PG_P0V75_DVDD_11 | 16 | | | | +| PG_P0V75_DVDD_10 | 15 | | | | +| PG_P0V75_DVDD_9 | 14 | | | | +| PG_P0V75_DVDD_8 | 13 | | | | +| PG_P0V75_DVDD_7 | 12 | | | | +| PG_P0V75_DVDD_6 | 11 | | | | +| PG_P0V75_DVDD_5 | 10 | | | | +| PG_P0V75_DVDD_4 | 9 | | | | +| PG_P0V75_DVDD_3 | 8 | | | | +| PG_P0V75_DVDD_2 | 7 | | | | +| PG_P0V75_DVDD_1 | 6 | | | | +| PG_P0V75_DVDD_0 | 5 | | | | +| PG_P1V8 | 4 | | | | +| PG_PVDD_3V_SYNTH_LDO_B1 | 3 | | | | +| PG_PVDD_3V_SYNTH_LDO_A1 | 2 | | | | +| PG_P3V3 | 1 | | | | +| PG_P5V_STBY | 0 | | | | + +#### TND_PWR_STAT_1_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| PG_P1V8_DVDDIO_3 | 31 | | | | +| PG_P1V8_DVDDIO_2 | 30 | | | | +| PG_P1V8_DVDDIO_1 | 29 | | | | +| PG_P0V75_DVDD_63 | 28 | | | | +| PG_P0V75_DVDD_62 | 27 | | | | +| PG_P0V75_DVDD_61 | 26 | | | | +| PG_P0V75_DVDD_60 | 25 | | | | +| PG_P0V75_DVDD_59 | 24 | | | | +| PG_P0V75_DVDD_58 | 23 | | | | +| PG_P0V75_DVDD_57 | 22 | | | | +| PG_P0V75_DVDD_56 | 21 | | | | +| PG_P0V75_DVDD_55 | 20 | | | | +| PG_P0V75_DVDD_54 | 19 | | | | +| PG_P0V75_DVDD_53 | 18 | | | | +| PG_P0V75_DVDD_52 | 17 | | | | +| PG_P0V75_DVDD_51 | 16 | | | | +| PG_P0V75_DVDD_50 | 15 | | | | +| PG_P0V75_DVDD_49 | 14 | | | | +| PG_P0V75_DVDD_48 | 13 | | | | +| PG_P0V75_DVDD_47 | 12 | | | | +| PG_P0V75_DVDD_46 | 11 | | | | +| PG_P0V75_DVDD_45 | 10 | | | | +| PG_P0V75_DVDD_44 | 9 | | | | +| PG_P0V75_DVDD_43 | 8 | | | | +| PG_P0V75_DVDD_42 | 7 | | | | +| PG_P0V75_DVDD_41 | 6 | | | | +| PG_P0V75_DVDD_40 | 5 | | | | +| PG_P0V75_DVDD_39 | 4 | | | | +| PG_P0V75_DVDD_38 | 3 | | | | +| PG_P0V75_DVDD_37 | 2 | | | | +| PG_P0V75_DVDD_36 | 1 | | | | +| PG_P0V75_DVDD_27 | 0 | | | | + +#### TND_PWR_STAT_2_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| PG_PVDD1V45_2 | 31 | | | | +| PG_PVDD1V45_1 | 30 | | | | +| PG_PVDD1V45_0 | 29 | | | | +| PG_P1V5_CNDR1 | 28 | | | | +| PG_P1V5_CNDR0 | 27 | | | | +| PG_PVDD1V5_ANLG | 26 | | | | +| PG_PVDD_0V9_3 | 25 | | | | +| PG_PVDD_0V9_2 | 24 | | | | +| PG_PVDD_0V9_1 | 23 | | | | +| PG_PVDD_0V9_0 | 22 | | | | +| PG_PVDD_0V9_ANLG_1 | 21 | | | | +| PG_PVDD_0V9_ANLG_0 | 20 | | | | +| PG_PVDD0_8V_T3 | 19 | | | | +| PG_PVDDA_PHYT3_P3 | 18 | | | | +| PG_PVDDA_PHYT2_P2 | 17 | | | | +| PG_PVDDA_PHYT1_P1 | 16 | | | | +| PG_PVDD0V75_ANLG_1 | 15 | | | | +| PG_PVDD0V75_ANLG_0 | 14 | | | | +| PG_PVDD_PHYTILE_7 | 13 | | | | +| PG_PVDD_PHYTILE_6 | 12 | | | | +| PG_PVDD_PHYTILE_5 | 11 | | | | +| PG_PVDD_PHYTILE_4 | 10 | | | | +| PG_PVDD_PHYTILE_3 | 9 | | | | +| PG_PVDD_PHYTILE_2 | 8 | | | | +| PG_PVDD_PHYTILE_1 | 7 | | | | +| PG_PVDD_PHYTILE_0 | 6 | | | | +| PG_FM_PVDD_CORE | 5 | | | | +| PG_PVDD1V2_1 | 4 | | | | +| PG_PVDD1V2_0 | 3 | | | | +| PG_PVDD1V8_DUT | 2 | | | | +| PG_PVDD_MDIO | 1 | | | | +| PG_P1V8_DVDDIO_4 | 0 | | | | + +#### TND_PWR_STAT_3_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| PG_PVDD1V2_T3 | 1 | | | | +| PG_PVDD1V45_3 | 0 | | | | + +#### TND_CB_GPIO_CTRL_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | 0 | Reserved | +| GPI_7 | 7 | RW | 0 | | +| GPI_6 | 6 | RW | 0 | 1: Assert GPIO 6
0: De-assert GPIO 6 | +| RSVD | 5:0 | RO | 0 | Reserved | + +#### TND_CB_GPIO_STAT_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| GPO_7 | 7 | RO | 0 | | +| GPO_6 | 6 | RO | 0 | 1: GPIO 6 is asserted
0: GPIO 6 is de-asserted | +| RSVD | 5:0 | RO | All 0s | Reserved | + +#### TND_CB_GPIO_DIR_CTRL_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | 0 | Reserved | +| GPIO_DIR_7 | 7 | RW | 0 | | +| GPIO_DIR_6 | 6 | RW | 0 | 1: Indicate GPIO 6 is configured as output and register GPIO_CTRL_REG is used to control this output port value.
0: Indicate GPIO 6 is configured as input and register GPIO_STAT_REG store this input port value. | +| RSVD | 5:0 | RO | 0 | Reserved | + +#### RST_CAUSE_REG + +This is a protected register. This is sticky and does not get reset under global reset condition. + +**Card Type:** All · **FPGA Type:** SWB · **Function:** None · **POR Value:** 0x0000_0001 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| SW_RST_COOKIES | 31:16 | RW | All 0s | For SW to read and write. | +| RSVD | 11:9 | RO | All 0s | Reserved. | +| CLD_RST | 8 | W1C | 0 | This bit will be set if the System PGOOD is de-sserted from a good state. | +| RSVD | 7:1 | RO | All 0s | Reserved. | +| PWR_ON_RST | 0 | W1C | 1 | | + +#### + +### ICB Registers + +#### FPGA_REV_ID_REG + +#### FPGA_RECONFIG_CTRL_REG + +#### FPGA_RECONFIG_STAT_REG + +#### SCRTCH_n_REG + +#### PWR_CTRL_REG + +**Card Type:** All · **FPGA Type:** ICB · **Function:** none · **POR Value:** 0x0000_0099 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| PWR_SUICIDE | 31:16 | RW | All 0s | Value of 0xA73D in this register will disable 1Khz signal sent out to the hardware external watchdog and toggle the reconfiguration pin of ICB.
This field is used for ICB post-ISP update. | +| RSVD | 15:8 | RO | All 0s | Reserved. | +| P12V_VRM_EN_SWB_1 | 7:4 | RW | 0x9 | SWB1 VRM enable
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | +| P12V_VRM_EN_SWB_0 | 3:0 | RW | 0x9 | SWB0 VRM enable
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status. | + +#### PWR_STAT_REG + +**Card Type:** All · **FPGA Type:** ICB · **Function:** none · **POR Value:** 0x0000_00F7 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:21 | RO | All 0s | Reserved | +| ALRT_P50V_FAN_8 | 20 | RO | 0 | | +| ALRT_P50V_FAN_7 | 19 | RO | 0 | | +| ALRT_P50V_FAN_6 | 18 | RO | 0 | | +| ALRT_P50V_FAN_5 | 17 | RO | 0 | | +| ALRT_P50V_FAN_4 | 16 | RO | 0 | Alert from Fan 4
1: Asserted
0: De-asserted | +| RSVD | 15:13 | RO | All 0s | Reserved | +| PG_P50V_FAN_8 | 12 | RO | 0 | | +| PG_P50V_FAN_7 | 11 | RO | 0 | | +| PG_P50V_FAN_6 | 10 | RO | 0 | | +| PG_P50V_FAN_5 | 9 | RO | 0 | | +| PG_P50V_FAN_4 | 8 | RO | 0 | Power status of Fan 4
1: Power is ok | +| ALRT_P50V_HSC_STBY | 7 | RO | 1 | Alert from hotswap controller standby
1: Asserted
0: De-asserted | +| ALRT_P50V_HSC_MAIN | 6 | RO | 1 | Alert from hotswap controller main
1: Asserted
0: De-asserted | +| PRSNT_P50V_HSC_STBY | 5 | RO | 1 | Present status of hotswap controller standby
1: Present
0: Not present | +| PRSNT_P50V_HSC_MAIN | 4 | RO | 1 | Present status hotswap controller main
1: Present
0: Not present | +| RSVD | 3 | RO | 0 | Reserved | +| PG_P50V_HSC_STBY | 2 | RO | 1 | Power status of hotswap controller standby
1: Power is ok | +| PG_P50V_HSC_MAIN | 1 | RO | 1 | Power status of hotswap controller main
1: Power is ok | +| PG_P3V3_STBY | 0 | RO | 1 | Power status of P3V3 Standby power rail
1: Power is ok | + +#### FAN_CTRL_REG + +**Card Type:** All · **FPGA Type:** ICB · **Function:** none · **POR Value:** 0x0006_6666 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:20 | RO | All 0s | Reserved. | +| P50V_EFUSE_EN_FAN_8 | 19:16 | RW | 0x6 | Fan 8 EFUSE enable
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status.
(Exception: this signal will automatically clear when fan is not present) | +| P50V_EFUSE_EN_FAN_7 | 15:12 | RW | 0x6 | Fan 7 EFUSE enable
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status.
(Exception: this signal will automatically clear when fan is not present) | +| P50V_EFUSE_EN_FAN_6 | 11:8 | RW | 0x6 | Fan 6 EFUSE enable
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status.
(Exception: this signal will automatically clear when fan is not present) | +| P50V_EFUSE_EN_FAN_5 | 7:4 | RW | 0x6 | Fan 5 EFUSE enable
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status.
(Exception: this signal will automatically clear when fan is not present) | +| P50V_EFUSE_EN_FAN_4 | 3:0 | RW | 0x6 | Fan 4 EFUSE enable
0x6: Enable
0x9: Disable
Although any value can be written in this field by SW, but FPGA will not take action if the value is not 0x6 or 0x9 and will keep the previous Enable/Disable status.
(Exception: this signal will automatically clear when fan is not present) | + +#### FAN_STAT_REG + +**Card Type:** All · **FPGA Type:** ICB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:13 | RO | All 0s | Reserved | +| FAN_FULL_SPD | 12 | RO | 0 | Fan speed status
1: Fan is at full speed
0: Fan is not at full speed
(buffered signal from CB FPGA) | +| RSVD | 11:9 | RO | All 0s | Reserved | +| FAN_CTRLR_INT | 8 | RO | 0 | Interrupt status of fan controller (fan 4-8)
1: Asserted
0: De-asserted | +| RSVD | 7:5 | RO | All 0s | Reserved | +| PRSNT_FAN_8 | 4 | RO | 0 | | +| PRSNT_FAN_7 | 3 | RO | 0 | | +| PRSNT_FAN_6 | 2 | RO | 0 | | +| PRSNT_FAN_5 | 1 | RO | 0 | | +| PRSNT_FAN_4 | 0 | RO | 0 | Fan 4 presence status
1: Present
0: Not present | + +#### THRM_STAT_REG + +**Card Type:** All · **FPGA Type:** ICB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:2 | RO | All 0s | Reserved | +| TMP75_ALRT | 1 | RW | 0 | Interrupt from temperature sensor TMP75
1: Asserted
0: De-asserted | +| TMP432_ALRT | 0 | RW | 0 | Interrupt from temperature sensor TMP432
1: Asserted
0: De-asserted | + +#### EN_ACCSS_PRTCTD_REG + +This register is to protect critical registers from accidental writes. SW should write 0x8F35_D72C in order to have write access to protected registers. + +**Card Type:** All · **FPGA Type:** ICB · **Function:** none · **POR Value:** 0x0000_0000 + +Enables access to protected registers. + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| EN_ACCSS | 31:0 | RW | 0 | 0x8F35_D72C: Enables access to protected registers.
Other Values: Disables access to protected registers. | + +#### I2C_MUX_RST_REG + +**Card Type:** All · **FPGA Type:** ICB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | All 0s | Reserved | +| I2C_MUX_RST | 3:0 | RW | 0x0 | Reset control of I2C MUX Channel 4 – VRM and Fan EFUSE.
0xD: Asserted
Any other value: de-asserted.
This Field is NOT automatically cleared by FPGA after reset is issued. | + +#### FLSH_CTRL_REG + +This register is clear under two conditions only. + +- Upon assertion of global reset. +- Power cycle +**Card Type:** All · **FPGA Type:** ICB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:1 | RO | All 0s | Reserved | +| FRU_EEPRM_WP | 0 | RW | 0 | FRU EEPROM Write Protect
1: Protected,
Once asserted, cannot be de-asserted by SW. | + +#### LED_SYNC_REG + +#### LED_CONFIG_REG + +#### LED_CTRL_REG + +For bit definitions please refer to the section “LED Control bits”. + +**Card Type:** All · **FPGA Type:** ICB · **Function:** none · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:8 | RO | All 0s | Reserved | +| FAN_ALRT_STAT | 7:0 | RW | 0x0 | Fan Alert LED status | + +#### TND_CB_GPIO_CTRL_REG + +**Card Type:** All · **FPGA Type:** ICB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| GPI_3 | 3 | RW | 0 | | +| GPI_2 | 2 | RW | 0 | | +| GPI_1 | 1 | RW | 0 | 1: Assert GPIO 1
0: De-assert GPIO 1 | +| RSVD | 0 | RO | 0 | Reserved | + +#### TND_CB_GPIO_STAT_REG + +**Card Type:** All · **FPGA Type:** SWB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | All 0s | Reserved | +| GPO_3 | 3 | RO | 0 | | +| GPO_2 | 2 | RO | 0 | | +| GPO_1 | 1 | RO | 0 | 1: GPIO 1 is asserted
0: GPIO 1 is de-asserted | +| RSVD | 0 | RO | 0 | Reserved | + +#### TND_CB_GPIO_DIR_CTRL_REG + +**Card Type:** All · **FPGA Type:** ICB · **Function:** None · **POR Value:** 0x0000_0000 + +| Field | Bits | Type | Reset | Description | +|---|---|---|---|---| +| RSVD | 31:4 | RO | 0 | Reserved | +| GPIO_DIR_3 | 3 | RW | 0 | | +| GPIO_DIR_2 | 2 | RW | 0 | | +| GPIO_DIR_1 | 1 | RW | 0 | 1: Indicate GPIO 1 is configured as output and register GPIO_CTRL_REG is used to control this output port value.
0: Indicate GPIO 1 is configured as input and register GPIO_STAT_REG store this input port value. | +| RSVD | 0 | RO | 0 | Reserved | + diff --git a/docs/Blantons_FPGA_Registers_Map_draft.xlsx b/docs/Blantons_FPGA_Registers_Map_draft.xlsx new file mode 100644 index 0000000..0616933 Binary files /dev/null and b/docs/Blantons_FPGA_Registers_Map_draft.xlsx differ diff --git a/docs/Blantons_FPGA_Registers_draft.docx b/docs/Blantons_FPGA_Registers_draft.docx new file mode 100644 index 0000000..439ff0f Binary files /dev/null and b/docs/Blantons_FPGA_Registers_draft.docx differ diff --git a/docs/Blantons_PCIe_AER_and_DDR_EDAC_checks.pdf b/docs/Blantons_PCIe_AER_and_DDR_EDAC_checks.pdf new file mode 100644 index 0000000..2c6d5a1 Binary files /dev/null and b/docs/Blantons_PCIe_AER_and_DDR_EDAC_checks.pdf differ diff --git a/docs/TTL_Script_Blanton_Status_20260814.xlsx b/docs/TTL_Script_Blanton_Status_20260814.xlsx new file mode 100644 index 0000000..a0c3148 Binary files /dev/null and b/docs/TTL_Script_Blanton_Status_20260814.xlsx differ diff --git a/publish/.gitkeep b/publish/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/secret/README.md b/secret/README.md new file mode 100644 index 0000000..1910c58 --- /dev/null +++ b/secret/README.md @@ -0,0 +1,35 @@ +# secret/ — 本機 / 現場敏感資料 + +這個資料夾集中放**不能進 git** 的東西:DUT console 帳密、per-unit 的 PCIe BDF 覆寫、 +COM port 設定、客戶提供但未公開的附件。 + +## Committed vs Ignored + +`.gitignore` 規則是 `secret/*` 搭配 `!secret/README.md` / `!secret/*.example` / `!secret/.gitkeep`。 + +| 檔案 | 狀態 | 說明 | +|------|------|------| +| `README.md` | ✅ committed | 本說明 | +| `config_secret.ttl.example` | ✅ committed | 帳密範本,敏感欄位一律 `__CHANGE_ME__` | +| `config_secret.ttl` | 🚫 ignored | **實際** DUT 帳密,由 `config.ttl` include | +| `dut_bdf.ttl` / `*.local.*` | 🚫 ignored | per-unit 的 PCIe BDF / COM port 覆寫 | +| `*.pem` / `*.key` / `*.env` | 🚫 ignored | 憑證、金鑰 | +| 客戶未公開附件 | 🚫 ignored | schematic、內部 spec 草稿等 | + +## 第一次使用 + +```bash +cp secret/config_secret.ttl.example secret/config_secret.ttl +# 編輯 secret/config_secret.ttl,把 __CHANGE_ME__ 換成實際帳密 +``` + +Tera Term 端把整包 `src/Script_ABC_Blanton/` 複製到工作目錄時,**一併把 +`secret/config_secret.ttl` 放到 `src/Script_ABC_Blanton/` 同層**(`config.ttl` 以相對路徑 include)。 +現場機器上的那份不要再複製回 repo。 + +## 鐵則 + +- 🔒 **commit 前先 grep 一次**:`git grep -nE 'password|passwd|PaSsWoRd' -- . ':!secret'` + 應該只找得到變數名與 placeholder,不該出現真值。 +- 🔒 `.example` 檔內敏感欄位一律寫 `__CHANGE_ME__`,不留 `your_password` 這種半吊子 placeholder。 +- 🔒 本 repo 含客戶 NDA 資料,**只推 `nas` + `gitea`,絕不推 GitHub**。 diff --git a/secret/config_secret.ttl.example b/secret/config_secret.ttl.example new file mode 100644 index 0000000..63546d3 --- /dev/null +++ b/secret/config_secret.ttl.example @@ -0,0 +1,24 @@ +; ============================================================================= +; config_secret.ttl.example -- DUT credentials (NOT in git) +; ============================================================================= +; Usage: +; 1. cp secret/config_secret.ttl.example secret/config_secret.ttl +; 2. Replace every __CHANGE_ME__ below with the real value. +; 3. Put config_secret.ttl next to config.ttl in the Tera Term working dir. +; +; config.ttl includes this file; 1_Blanton_Script_A.ttl must use the variables +; below instead of a literal password: +; +; sendln dut_user +; wait "Password:" +; sendln dut_password +; +; NEVER commit the filled-in config_secret.ttl. +; ============================================================================= + +; --- SONiC console login --- +dut_user = "__CHANGE_ME__" +dut_password = "__CHANGE_ME__" + +; --- Optional: root password, if 'sudo -i' prompts on this unit --- +dut_root_password = "__CHANGE_ME__" diff --git a/src/Script_ABC_Blanton/1_Blanton_Script_A.ttl b/src/Script_ABC_Blanton/1_Blanton_Script_A.ttl new file mode 100644 index 0000000..e33102e --- /dev/null +++ b/src/Script_ABC_Blanton/1_Blanton_Script_A.ttl @@ -0,0 +1,95 @@ +; ============================================================================= +; Script A for Blanton +; Version : V1.0.1 +; Date : 2026-08-14 +; Author : ETWen +; ============================================================================= +; Version History: +; V1.0.0 2026-08-13 Initial Version +; V1.0.1 2026-08-14 Add CLEAR PCIE Error +; ============================================================================= +include "config.ttl" + +flushrecv +;================================================================ +; Log File Creation +;================================================================ +gettime str_starttime "%Y%m%d-%H%M%S" +getdir mdir + +if EN_log = 1 then + sprintf2 filename '%s\Logs\%s_%s_%s.log' mdir project_name strTestcase str_starttime + logopen filename 0 1 1 1 +endif + +; ========== Root Login ========== +wait prompt_login +sendln "admin" +wait "Password:" +sendln "YourPaSsWoRd" +wait prompt_sonic +sendln "sudo -i" + +; ========== Pre Setting ========== +; Make log directory +wait prompt_sonic_root +sendln "mkdir ./logs" + +; Setting System Time +getdate datestr +gettime timestr +sprintf2 cmd 'sudo date -s "%s %s"' datestr timestr +sendln cmd + +; ========== Load Shell Script ========== +wait prompt_sonic_root +sendln "source ~/Blanton_Script/blanton_fpga_pcimem.sh" +wait prompt_sonic_root +sendln "source ~/Blanton_Script/blanton_cb_i2c.sh" +wait prompt_sonic_root +sendln "source ~/Blanton_Script/blanton_icb_vi2c.sh" +wait prompt_sonic_root +sendln "source ~/Blanton_Script/blanton_pwr_data.sh" +wait prompt_sonic_root +sendln "source ~/Blanton_Script/LTC2980_Margin_Script/margin.sh" + +; ========== CLEAR PCIE Error ========== +include "utils/show_pcie_error_reg_TH6_SWB0.ttl" +include "utils/show_pcie_error_reg_TH6_SWB1.ttl" +include "utils/show_pcie_error_reg_FPGA.ttl" +include "utils/show_pcie_error_reg_BMC.ttl" +include "utils/show_pcie_error_reg_DDR.ttl" +include "utils/show_pcie_error_reg_I210.ttl" +include "utils/show_pcie_error_reg_SSD.ttl" + + +; ========== Check PCIE tree + PCIE link status + GET PCIE bandwidth Test ========== +include "utils/pcie_bus.ttl" + +; ========== Check History ========== + ;wait prompt_sonic_root + ;sendln "command" + +; ========== Check Margin ========== +if EN_Margin = 1 then + include "utils/show_margin_status.ttl" +endif + +; ========== Set and Read PMON Settings ========== +include "utils/setup_pmon.ttl" + +; ========== TAKE DATA ========== +include "utils/show_dmesg.ttl" +wait prompt_sonic_root + +;include "utils/xxx.ttl" +;wait prompt_sonic_root +;flushrecv + +; ========== TRAFFIC-SETUP-STAGE ========== + ;sendln "command" + + +sendln "" +wait prompt_sonic_root +messagebox 'Start Script B' 'Script A DONE' \ No newline at end of file diff --git a/src/Script_ABC_Blanton/2_Blanton_Script_B.ttl b/src/Script_ABC_Blanton/2_Blanton_Script_B.ttl new file mode 100644 index 0000000..8fa1455 --- /dev/null +++ b/src/Script_ABC_Blanton/2_Blanton_Script_B.ttl @@ -0,0 +1,74 @@ +; ============================================================================= +; Script B for Blanton +; Version : V1.0.1 +; Date : 2026-08-14 +; Author : ETWen +; ============================================================================= +; Version History: +; V1.0.0 2026-08-13 Initial Version +; V1.0.1 2026-08-14 Add AMD CPU STRESS TEST +; ============================================================================= +include "config.ttl" + +flushrecv +logwrite ''#13#10 +logwrite '#####################################'#13#10 +logwrite 'ScriptB START'#13#10 +logwrite '#####################################'#13#10 +pause 1 + +; ========== CLEAR EVENT ========== + ;wait prompt_sonic_root + ;sendln "command" + +; ========== AMD CPU STRESS TEST ========== +wait prompt_sonic_root +sendln 'chmod +x ~/hammer/tools/amd/mlucas-avx2' +wait prompt_sonic_root +sendln "~/hammer/tools/amd/mlucas-avx2 -s l -cpu 0:15 > ~/hammer/tools/amd/mlucas_amm_log 2>&1 &" + +; ========== DDR MEMORY STRESS TEST ========== +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_mem.py &" +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_mem.py &" +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_mem.py &" +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_mem.py &" +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_mem.py &" + +; ========== I2C, LSB and PCIE read with unlimited loop ========== +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_hhmd.py &" + +; ========== SSD read/write ========== +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_ssd.py &" + +; ========== PCIe CPU <- PCIe -> ASIC by dumping portStatus ========== +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_pcie.py &" + +; ========== USB read/write ========== +wait prompt_sonic_root +sendln "python ~/hammer/tools/stress_usb.py &" + +; ========== SHOW Background job ========== +wait prompt_sonic_root +sendln "jobs" + +; ========== Take one round of eye measurement on uplink ports ========== + +; ========== Get data every 10mins ========== +while 1 + wait prompt_sonic_root + sendln "show platform fan" + wait prompt_sonic_root + sendln "show platform temperature" + ; ========== Check Margin ========== + if EN_Margin = 1 then + include "utils/show_margin_status.ttl" + endif +endwhile \ No newline at end of file diff --git a/src/Script_ABC_Blanton/3_Blanton_Script_C.ttl b/src/Script_ABC_Blanton/3_Blanton_Script_C.ttl new file mode 100644 index 0000000..2cd3285 --- /dev/null +++ b/src/Script_ABC_Blanton/3_Blanton_Script_C.ttl @@ -0,0 +1,46 @@ +; ============================================================================= +; Script B for Blanton +; Version : V1.0.1 +; Date : 2026-08-14 +; Author : ETWen +; ============================================================================= +; Version History: +; V1.0.0 2026-08-13 Initial Version +; V1.0.1 2026-08-14 Add Check PCIE error counters,CHECK Stress results +; ============================================================================= +include "config.ttl" + +flushrecv +logwrite ''#13#10 +logwrite '#####################################'#13#10 +logwrite 'ScriptC START'#13#10 +logwrite '#####################################'#13#10 +pause 1 + +; ========== Kill Process ========== +include "utils/kill_all_process.ttl" +; ========== TAKE DATA ========== +include "utils/setup_pmon.ttl" +include "utils/show_dmesg.ttl" + +; ========== Check PCIE error counters ========== +include "utils/show_pcie_error_reg_TH6_SWB0.ttl" +include "utils/show_pcie_error_reg_TH6_SWB1.ttl" +include "utils/show_pcie_error_reg_FPGA.ttl" +include "utils/show_pcie_error_reg_BMC.ttl" +include "utils/show_pcie_error_reg_DDR.ttl" +include "utils/show_pcie_error_reg_I210.ttl" +include "utils/show_pcie_error_reg_SSD.ttl" + +; ========== CHECK Stress results ========== +wait prompt_sonic_root +sendln "cat ~/hammer/tools/amd/mlucas_amm_log" +wait prompt_sonic_root +sendln "cat ~/hammer/tools/log.stress_ssd" + +; ========== CHECK Traffic counters ========== + ;wait prompt_sonic_root + ;sendln "command" + + +messagebox 'GOOD JOB! Test Case DONE' 'teraterm' \ No newline at end of file diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/README.md b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/README.md new file mode 100644 index 0000000..5b64157 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/README.md @@ -0,0 +1,184 @@ +# LTC2980 Margin Script + +透過 PMBus (`i2cset` / `i2cget`) 控制 LTC2980 多通道電壓 Margin 測試工具。 +**一個 `.conf` = 一顆 LTC2980**(= 2 × LTC2977,每 address 8 channel,共 CH0~CH15)。 + +## Key Features + +| 函數 | 說明 | +|------|------| +| `margin_init ` | source `settings/.conf` 載入該顆 LTC2980 的設定 | +| `margin_status [ch]` | 讀取 CH0~CH15 全部或指定 channel 的 Vout + 偏差% | +| `margin_set ` | 三合一:寫值 + 切 operation + 讀回驗證 | +| `margin_set_value ` | 只寫 HIGH/LOW/OV/UV 暫存器 | +| `margin_operation ` | 只切 OPERATION register | +| `margin_apply_profile ` | 批次套用 profile(套用在當前載入的 LTC2980) | +| `margin_save` | 寫入 NVM(當前 LTC2980 的兩個 LTC2977 都寫) | +| `margin_debug [on\|off]` | 開關 debug 模式(不帶參數則 toggle) | +| `margin_log [on\|off]` | 開關 log 記錄(不帶參數則 toggle,預設開啟) | + +## Setup Steps + +```bash +# 1. 將此資料夾 scp 到目標 Linux 環境 +scp -r LTC2980_Margin_Script user@target:/path/to/ + +# 2. SSH 進入目標機器 +ssh user@target + +# 3. 載入工具 +cd ./LTC2980_Margin_Script +source margin.sh + +# 4. 初始化(指定要操作的 LTC2980) +margin_init Blanton_CB_CONN13 +``` + +## 可用 settings + +| .conf 名稱 | 對應板/接頭 | +|------------|-------------| +| `Blanton_CB_CONN13` | CB 板 CONN13 | +| `Blanton_SWB0_CONN13` | SWB0 板 CONN13 | +| `Blanton_SWB0_CONN14` | SWB0 板 CONN14 | +| `Blanton_SWB0_CONN15` | SWB0 板 CONN15 | +| `Blanton_SWB0_CONN16` | SWB0 板 CONN16 | +| `Blanton_SWB1_CONN13` | SWB1 板 CONN13 | +| `Blanton_SWB1_CONN14` | SWB1 板 CONN14 | +| `Blanton_SWB1_CONN15` | SWB1 板 CONN15 | +| `Blanton_SWB1_CONN16` | SWB1 板 CONN16 | + +## 使用範例 + +```bash +# 載入某顆 LTC2980 +margin_init Blanton_SWB0_CONN14 + +# 查看所有 channel 狀態(0~15) +margin_status + +# 查看單一 channel +margin_status 3 + +# 設定 margin(寫值 + 切 operation + 讀回驗證) +margin_set 0 high 8 # ch0 margin high 8% +margin_set 5 low 5 # ch5 margin low 5% +margin_set 3 nominal 8 # ch3 回標稱值 + +# 只切 operation(不改 margin 值) +margin_operation 0 high +margin_operation 0 nominal + +# 批次套用 profile(套在當前載入的 LTC2980) +margin_apply_profile profiles/comboA.conf +margin_apply_profile profiles/comboB.conf +margin_apply_profile profiles/all_off.conf + +# 切換到另一顆 LTC2980 +margin_init Blanton_SWB1_CONN16 +margin_apply_profile profiles/comboA.conf + +# 儲存到 NVM(斷電後保留) +margin_save +``` + +## 一次掃所有 LTC2980 + +`script/margin_status_all.sh` 依序對多顆 LTC2980 跑 `margin_init` + `margin_status`, +讀完一顆切下一顆。 + +```bash +source script/margin_status_all.sh +``` + +要改掃描範圍,編 script 頂端的 `BOARDS` 陣列即可: + +```bash +BOARDS=( + "Blanton_CB_CONN13" + "Blanton_SWB0_CONN13" + # ... 註解掉或刪掉不想跑的那行 +) +``` + +## 一次套 profile 到所有 LTC2980 + +`script/margin_apply_profile_all.sh` 對多顆 LTC2980 依 `BOARDS[i]` 配對 +`PROFILES[i]` 套用 profile(預設全部 `comboA`)。 + +```bash +source script/margin_apply_profile_all.sh +``` + +編 script 頂端兩個陣列換不同 profile 給不同板: + +```bash +BOARDS=( + "Blanton_CB_CONN13" + "Blanton_SWB0_CONN13" + ... +) + +PROFILES=( + "comboA" # Blanton_CB_CONN13 + "comboB" # Blanton_SWB0_CONN13 ← 改成 comboB + ... +) +``` + +`PROFILES` 寫名字即可(不含路徑跟 `.conf`),script 會自動展開成 +`profiles/.conf`。兩個陣列長度不一致會直接報錯。 + +## 一次把所有 LTC2980 寫入 NVM + +`script/margin_save_all.sh` 對 `BOARDS` 列出的每顆 LTC2980 跑 `margin_save`。 + +> ⚠️ `margin_save` 會把當前 margin / OV / UV 設定**永久寫入 NVM**, +> 斷電後保留。執行前先用 `margin_status_all.sh` 確認狀態正確。 + +```bash +source script/margin_save_all.sh +``` + +要改寫哪幾顆,編 script 頂端的 `BOARDS` 陣列即可(同前述)。 + +## Operation 對應 + +| 參數 | PMBus 0x01 值 | 說明 | +|------|---------------|------| +| `high` | 0xA8 | Margin high | +| `low` | 0x98 | Margin low | +| `nominal` | 0x80 | 回到標稱值 | +| `off` | 0x00 | 關閉輸出 | + +## Channel 編號規則 + +每個 .conf 內 channel 編號 0~15(per LTC2980 本地化): + +- `ch / 8` → CHIPS 陣列索引(0=低位 LTC2977 address,1=高位 LTC2977 address) +- `ch % 8` → LTC2977 page(0x00~0x07) + +## 設定檔 + +- `settings/*.conf` — 一顆 LTC2980 的 channel 定義(Vnom、Net、I2C address × 2、PRE/POST cmd) +- `profiles/*.conf` — 通用 16-ch 批次操作組合 +- `script/*.sh` — 多顆 LTC2980 批次操作(如 `margin_status_all.sh`) +- `logs/` — 操作 log,`source margin.sh` 時自動建立:主 log(摘要)+ detail log(完整輸出)。主 log 帶 `(detail Line:N)` 可跳轉 +- `margin_debug on` / `margin_debug off` / `margin_debug`(toggle)— 開關 debug 模式,印出所有 i2c 指令 +- `margin_log on` / `margin_log off` / `margin_log`(toggle)— 開關 log 記錄(預設開啟) +- `margin_init` 支援 TAB 補全,自動列出 `settings/` 中可用的 .conf 名稱 + +## PRE/POST 執行時機 + +`CHIP_PRE_CMD[0]` / `CHIP_POST_CMD[0]`(mux 切換等指令)由 `_pre_enter_own` / +`_pre_exit` 在**每個 public 函數的最外層**各跑一次: + +``` +margin_status: margin_apply_profile: + [PRE] (一次) [PRE] (一次) + CH0~CH15 i2c ops margin_set CH0, CH1, ... (各自不再 PRE) + [POST] (一次) [POST] (一次) +``` + +巢狀呼叫(`margin_apply_profile → margin_set → margin_set_value/operation/read_vout`) +透過全域旗標 `_PRE_SCOPE` 判斷是否已在 scope 內,內層直接跳過 PRE/POST。 diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/blanton_cb_i2c.sh b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/blanton_cb_i2c.sh new file mode 100644 index 0000000..296a9b5 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/blanton_cb_i2c.sh @@ -0,0 +1,444 @@ +#!/usr/bin/env bash +# ============================================================================= +# blanton_cb_i2c.sh -- CB FPGA (F3) I2C / PMBus over the OpenCores I2C master +# ============================================================================= +# Version History: +# V0.1.0 2026-06-16 CB sibling of blanton_icb_i2c.sh. Same OpenCores I2C +# handshake, but the I2C block lives in CB FPGA *Function 3* +# register space (base 0x300, stride 0x20, Ch0..Ch17), and +# is reached via cb_fpga 3 (direct PCIe BAR -> .3/resource0). +# ============================================================================= +# +# IMPORTANT (vs the hand-written cb_fpga.md pcimem commands): +# * The CB I2C channels are on PCI **Function 3**, so the sysfs file is +# .../0000:02:00.3/resource0 (NOT .0). cb_fpga 3 uses FUNCT3_RES for this. +# * This tool uses **Repeated START** for reads (write reg pointer with WR only, +# no STOP, then Sr + slave|R) so it works for the SMBus/PMBus parts (VRM, +# EFUSE) as well as plain register parts. STOP+START only works for the latter. +# * Slave addresses are 7-bit here. The spec lists 8-bit pairs (e.g. MAX31790 +# "0x40/0x41" -> 7-bit 0x20; TCA9546 "0xE8/0xE9" -> 7-bit 0x74). Divide by 2. +# +# CB FPGA F3 I2C channels (base 0x300, stride 0x20) -- 7-bit addrs in (...): +# Ch0 0x300 SWB_0: TCA9546 mux (0x74), M0.C0 temp sensor, ... +# Ch1 0x320 SWB_1: TCA9546 mux (0x74), ... +# Ch2 0x340 SWB_0: SWB_FPGA (0x40), IO Exp PCA9555 (0x24), ... +# Ch3 0x360 SWB_1: SWB_FPGA (0x40), PCA9555 (0x24), ... +# Ch4 0x380 SWB_0: M1 TCA9546 mux (0x74), Clk Gen SI5..., ... +# Ch5 0x3A0 SWB_1: M1 TCA9546 mux (0x74), ... +# Ch6 0x3C0 SWB_0: VRM M29816 (0x20), VRM M2985B (0x21), ... [PMBus] +# Ch7 0x3E0 SWB_1: VRM M29816 (0x20), VRM M2985B (0x21), ... [PMBus] +# Ch8 0x400 SWB_0: VRM M2985B (0x25), M2985B (0x26), ... [PMBus] +# Ch9 0x420 SWB_1: VRM M2985B (0x25), M2985B (0x26), ... [PMBus] +# Ch10 0x440 M0 TCA9543 mux (0x70), M0.C0 Clk Buf 9DBL0452, ... +# Ch11 0x460 Fan Ctrl MAX31790 (0x20) +# Ch12 0x480 ADC leakage ADC128D818 (0x1F) +# Ch13 0x4A0 NFC SM-MFAD4-C02 (0x28) +# Ch14 0x4C0 M1 TCA9543 mux (0x70), M1.C0 QSFP28.P1 xcvr, ... +# Ch15 0x4E0 Fan1/2 EFUSE STEF48H28 (0x10/0x11), ... [PMBus-ish] +# Ch16 0x500 1G PHY I210 Ethernet ctrlr (0x49) +# Ch17 0x520 Chassis EEPROM (0x28..0x29), Diag EEPROM (0x2B), ... +# (slave 7-bit addrs derived from the 8-bit pairs in the register map; verify +# against the device datasheet / your board before driving writes.) +# +# Per-channel register layout (offset from channel base): +# +0x00 I2C_PRSCL_LO +0x04 I2C_PRSCL_HI +0x08 I2C_CTRL (bit7 MOD_EN) +# +0x0C I2C_TX(W)/I2C_RX(R) +0x10 I2C_CMD(W)/I2C_STAT(R) +# +0x14 I2C_MUX_SEL +0x18 I2C_RST (0xD) +0x1C SEM +# CMD : STA=0x80 STO=0x40 RD=0x20 WR=0x10 ACK=0x08(1=NACK) IACK=0x01 +# STAT: RX_ACK=0x80(1=NACK) BUSY=0x40 ARB_LOST=0x20 TIP=0x02 INT_FLAG=0x01 +# Prescale = (in_clk/(5*scl))-1 @75MHz: 0x88=100kHz, 0x24=400kHz +# +# Usage: +# source blanton_fpga_pcimem.sh # provides cb_fpga / fpga_debug +# source blanton_cb_i2c.sh +# cb_i2c_init 11 # Ch11 (Fan Ctrl) @100kHz +# cb_i2c_scan 11 +# cb_i2c_read 11 0x20 0x01 1 # MAX31790 (7-bit 0x20) reg 0x01 +# cb_pmbus_read 6 0x20 0x8B 2 # Ch6 VRM READ_VOUT +# ============================================================================= + +# --- Pull in the register-access backend (cb_fpga) if not present ----------- +if ! declare -F cb_fpga >/dev/null 2>&1; then + _CBI2C_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" + if [ -n "$_CBI2C_DIR" ] && [ -f "$_CBI2C_DIR/blanton_fpga_pcimem.sh" ]; then + # shellcheck source=/dev/null + source "$_CBI2C_DIR/blanton_fpga_pcimem.sh" + else + echo -e "[\033[33mWARN\033[0m] blanton_cb_i2c.sh: cb_fpga() not found." >&2 + echo " source blanton_fpga_pcimem.sh first (provides cb_fpga)." >&2 + fi +fi + +# === CB I2C geometry ========================================================= +CBI2C_FN=3 # CB PCI Function hosting the I2C block +CBI2C_BASE=0x300 # channel 0 base offset (relative to F3 resource0) +CBI2C_CH_STRIDE=0x20 +CBI2C_CH_MAX=17 + +# Per-channel register offsets +_CBI2C_PRSCL_LO=0x00 +_CBI2C_PRSCL_HI=0x04 +_CBI2C_CTRL=0x08 +_CBI2C_TX=0x0C +_CBI2C_RX=0x0C +_CBI2C_CMD=0x10 +_CBI2C_STAT=0x10 +_CBI2C_MUX_SEL=0x14 +_CBI2C_RST=0x18 +_CBI2C_SEM=0x1C + +# I2C_CTRL_REG / CMD / STAT bits +_CBI2C_EN=0x80 +_CBI2C_STA=0x80 +_CBI2C_STO=0x40 +_CBI2C_RD=0x20 +_CBI2C_WR=0x10 +_CBI2C_NACK=0x08 +_CBI2C_RXACK=0x80 +_CBI2C_TIP=0x02 +_CBI2C_RST_VAL=0xD + +# Defaults +CB_I2C_PRESCALE_LO="${CB_I2C_PRESCALE_LO:-0x88}" # 100 kHz @ 75 MHz +CB_I2C_PRESCALE_HI="${CB_I2C_PRESCALE_HI:-0x00}" +CB_I2C_AUTO_INIT="${CB_I2C_AUTO_INIT:-1}" +CB_I2C_TIP_POLL_MAX="${CB_I2C_TIP_POLL_MAX:-100}" + +# --- External I2C-mux RESET control (verified on COM34, 2026-06-16) ---------- +# The TCA9543 muxes on CH10 (M0) and CH14 (M1) have an FPGA-driven, active-low +# RESET line. On power-up / FPGA reload the FPGA holds them in reset, so 0x70 +# does NOT ACK on the root bus and all downstream legs are unreachable. +# +# The control is a GLOBAL register in CB FPGA *Function 0*, offset 0x7D4 +# (I2C_MUX_RST_REG) -- NOT the per-channel I2C_MUX_SEL_REG (+0x14) which is a +# device-select and does nothing to the RESET pin. Per bit: 1 = release, +# 0 = hold-in-reset. Observed default 0xDD (bit1=CH10 mux, bit5=CH14 mux held). +# Writing 0xFF releases all external muxes (normal operating state). This value +# is volatile and is lost on the next power cycle / FPGA reload. +CBI2C_MUX_RST_FN="${CBI2C_MUX_RST_FN:-0}" +CBI2C_MUX_RST_OFF="${CBI2C_MUX_RST_OFF:-0x7D4}" + +# Channels whose root bus carries an external mux that hangs off the RESET reg. +# CH10/CH14 = TCA9543; CH0/1/4/5 = TCA9546 (SWB/M1) per the channel map above. +CBI2C_MUX_CHANNELS="${CBI2C_MUX_CHANNELS:-0 1 4 5 10 14}" + +# Auto-release external mux RESET before scanning / mux-writing a mux channel. +CB_I2C_AUTO_MUX_RST="${CB_I2C_AUTO_MUX_RST:-1}" + +# --- Single FPGA register read/write via cb_fpga [data] ---------- +# _cbi2c_reg [data] data present = write, absent = read (echo hex) +_cbi2c_reg() { + local off="$1" data="${2:-}" + if [ -n "$data" ]; then cb_fpga "$CBI2C_FN" "$off" "$data"; else cb_fpga "$CBI2C_FN" "$off"; fi +} + +# Channel base absolute offset +_cbi2c_chan_base() { + local ch="$1" + if (( ch < 0 || ch > CBI2C_CH_MAX )); then + echo "blanton_cb_i2c: ch must be 0..$CBI2C_CH_MAX" >&2; return 1 + fi + printf '0x%X' $(( CBI2C_BASE + ch * CBI2C_CH_STRIDE )) +} + +# Normalize a register read-back to a number string ("0x...." -> 0x....) +_cbi2c_num() { local v="$1"; [[ "$v" =~ (0[xX][0-9a-fA-F]+) ]] && echo "${BASH_REMATCH[1]}" || echo "0"; } + +# Write CMD then poll STAT (same offset) until TIP clears; echo final status hex +_cbi2c_cmd_wait() { + local cmd_off="$1" cmd_val="$2" i status + _cbi2c_reg "$cmd_off" "$cmd_val" >/dev/null + for (( i=0; i&2 + printf '0x%X' "${status:-0}"; return 1 +} + +# Check RX_ACK in status (bit7). 0 = ACK, 1 = NACK -> return 1 +_cbi2c_check_ack() { + local status; status=$(_cbi2c_num "$1") + (( (status & _CBI2C_RXACK) != 0 )) && return 1 || return 0 +} + +# === Public: init / reset / semaphore / mux-sel ============================= + +# cb_i2c_init [prescale_lo] [prescale_hi] +cb_i2c_init() { + [[ $# -lt 1 ]] && { echo "Usage: cb_i2c_init [prescale_lo] [prescale_hi]"; return 1; } + local ch="$1" lo="${2:-$CB_I2C_PRESCALE_LO}" hi="${3:-$CB_I2C_PRESCALE_HI}" base + base=$(_cbi2c_chan_base "$ch") || return 1 + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_CTRL)))" 0x00 >/dev/null # disable + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_PRSCL_LO)))" "$lo" >/dev/null + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_PRSCL_HI)))" "$hi" >/dev/null + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_CTRL)))" "$_CBI2C_EN" >/dev/null # enable + return 0 +} + +# cb_i2c_reset +cb_i2c_reset() { + [[ $# -lt 1 ]] && { echo "Usage: cb_i2c_reset "; return 1; } + local ch="$1" base; base=$(_cbi2c_chan_base "$ch") || return 1 + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_RST)))" "$_CBI2C_RST_VAL" >/dev/null + echo " [RST] ch=$ch local I2C controller reset (0xD)" +} + +# cb_i2c_sem [status|acquire [val]|release] +cb_i2c_sem() { + [[ $# -lt 1 ]] && { echo "Usage: cb_i2c_sem [status|acquire [val]|release]"; return 1; } + local ch="$1" act="${2:-status}" base off cur + base=$(_cbi2c_chan_base "$ch") || return 1 + off=$(printf '0x%X' $((base + _CBI2C_SEM))) + case "$act" in + status) + cur=$(_cbi2c_num "$(_cbi2c_reg "$off")") + (( (cur & 0xFF) == 0 )) && echo " [SEM] ch=$ch free (0x00)" \ + || printf ' [SEM] ch=%s held (0x%02X)\n' "$ch" $((cur & 0xFF)) ;; + acquire) + local val="${3:-0x01}" + cur=$(_cbi2c_num "$(_cbi2c_reg "$off")") + if (( (cur & 0xFF) != 0 )); then + printf ' [SEM] ch=%s already held (0x%02X) -- not acquired\n' "$ch" $((cur & 0xFF)); return 1 + fi + _cbi2c_reg "$off" "$val" >/dev/null + cur=$(_cbi2c_num "$(_cbi2c_reg "$off")") + (( (cur & 0xFF) != 0 )) && printf ' [SEM] ch=%s acquired (0x%02X)\n' "$ch" $((cur & 0xFF)) \ + || { echo " [SEM] ch=$ch acquire failed"; return 1; } ;; + release) + _cbi2c_reg "$off" 0x00 >/dev/null; echo " [SEM] ch=$ch released (0x00)" ;; + *) echo "Usage: cb_i2c_sem [status|acquire [val]|release]"; return 1 ;; + esac +} + +# cb_i2c_muxsel -- write I2C_MUX_SEL_REG (FPGA drives ext mux pins) +cb_i2c_muxsel() { + [[ $# -lt 2 ]] && { echo "Usage: cb_i2c_muxsel "; return 1; } + local ch="$1" sel="$2" base; base=$(_cbi2c_chan_base "$ch") || return 1 + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_MUX_SEL)))" "$sel" >/dev/null + printf ' [MUXSEL] ch=%s DEV_SEL <= 0x%02X\n' "$ch" $((sel & 0xFF)) +} + +# cb_i2c_mux_reset_release -- de-assert ALL external mux RESET lines (F0 0x7D4 <= 0xFF) +# Global, not per-channel. Volatile: lost on power cycle / FPGA reload. +cb_i2c_mux_reset_release() { + cb_fpga "$CBI2C_MUX_RST_FN" "$CBI2C_MUX_RST_OFF" 0xFF >/dev/null + local rb; rb=$(_cbi2c_num "$(cb_fpga "$CBI2C_MUX_RST_FN" "$CBI2C_MUX_RST_OFF")") + printf ' [MUX-RST] I2C_MUX_RST_REG (F%s %s) <= 0xFF (all external muxes released, readback %s)\n' \ + "$CBI2C_MUX_RST_FN" "$CBI2C_MUX_RST_OFF" "$rb" +} + +# _cbi2c_is_mux_channel -- 0 (true) if ch is in CBI2C_MUX_CHANNELS +_cbi2c_is_mux_channel() { + local ch="$1" c + for c in $CBI2C_MUX_CHANNELS; do [[ "$c" == "$ch" ]] && return 0; done + return 1 +} + +# _cbi2c_auto_mux_rst -- release external mux RESET if ch is a mux channel +_cbi2c_auto_mux_rst() { + [[ "$CB_I2C_AUTO_MUX_RST" == "1" ]] || return 0 + _cbi2c_is_mux_channel "$1" || return 0 + cb_i2c_mux_reset_release +} + +# === Core transfers (Repeated START, SMBus/PMBus compatible) ================= + +# _cbi2c_xfer_read echoes space-separated hex bytes +_cbi2c_xfer_read() { + local ch="$1" slave="$2" reg="$3" n="$4" base tx cmd rx status i last cmdv val out="" + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + rx=$(printf '0x%X' $((base + _CBI2C_RX))) + [[ "$CB_I2C_AUTO_INIT" == "1" ]] && cb_i2c_init "$ch" >/dev/null + + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (slave << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on slave addr (W) 0x$(printf %02X "$slave")" >&2; return 1; } + + _cbi2c_reg "$tx" "$(printf '0x%X' $((reg & 0xFF)))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_WR)))") # WR only, no STOP + _cbi2c_check_ack "$status" || { echo "ERR: NACK on reg 0x$(printf %02X "$reg")" >&2; return 1; } + + _cbi2c_reg "$tx" "$(printf '0x%X' $(( ((slave << 1) | 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") # Repeated START + _cbi2c_check_ack "$status" || { echo "ERR: NACK on slave addr (R) 0x$(printf %02X "$slave")" >&2; return 1; } + + for (( i=0; i/dev/null + val=$(_cbi2c_num "$(_cbi2c_reg "$rx")") + out+="$(printf '0x%02X ' $((val & 0xFF)))" + done + echo "${out% }" +} + +# _cbi2c_xfer_write [byte...] +_cbi2c_xfer_write() { + local ch="$1" slave="$2" reg="$3"; shift 3 + local base tx cmd status b last cmdv n=$# idx=0 + [[ $n -lt 1 ]] && { echo "ERR: no data bytes" >&2; return 1; } + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + [[ "$CB_I2C_AUTO_INIT" == "1" ]] && cb_i2c_init "$ch" >/dev/null + + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (slave << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on slave addr (W) 0x$(printf %02X "$slave")" >&2; return 1; } + + _cbi2c_reg "$tx" "$(printf '0x%X' $((reg & 0xFF)))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on reg 0x$(printf %02X "$reg")" >&2; return 1; } + + for b in "$@"; do + idx=$((idx+1)); last=$(( idx == n )) + _cbi2c_reg "$tx" "$(printf '0x%X' $(( $((b)) & 0xFF )))" >/dev/null + if (( last )); then cmdv=$(( _CBI2C_WR | _CBI2C_STO )); else cmdv=$(( _CBI2C_WR )); fi + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' "$cmdv")") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on data byte #$idx" >&2; return 1; } + done + return 0 +} + +# _cbi2c_xfer_cmd_only -- START+W, cmd byte, STOP (no data) +_cbi2c_xfer_cmd_only() { + local ch="$1" slave="$2" cc="$3" base tx cmd status + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + [[ "$CB_I2C_AUTO_INIT" == "1" ]] && cb_i2c_init "$ch" >/dev/null + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (slave << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on slave addr (W) 0x$(printf %02X "$slave")" >&2; return 1; } + _cbi2c_reg "$tx" "$(printf '0x%X' $((cc & 0xFF)))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_WR | _CBI2C_STO)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on cmd 0x$(printf %02X "$cc")" >&2; return 1; } + return 0 +} + +# === Public: generic I2C ===================================================== + +# cb_i2c_read [nbytes] +cb_i2c_read() { + [[ $# -lt 3 ]] && { echo "Usage: cb_i2c_read [nbytes]"; return 1; } + local ch="$1" slave=$(( $2 )) reg=$(( $3 )) n="${4:-1}" bytes + bytes=$(_cbi2c_xfer_read "$ch" "$slave" "$reg" "$n") || return 1 + printf ' [I2C-R] ch=%s slave=0x%02X reg=0x%02X => [%s]\n' "$ch" "$slave" "$reg" "$bytes" +} + +# cb_i2c_write [byte...] +cb_i2c_write() { + [[ $# -lt 4 ]] && { echo "Usage: cb_i2c_write [byte...]"; return 1; } + local ch="$1" slave=$(( $2 )) reg=$(( $3 )); shift 3 + _cbi2c_xfer_write "$ch" "$slave" "$reg" "$@" || return 1 + printf ' [I2C-W] ch=%s slave=0x%02X reg=0x%02X <= [%s]\n' "$ch" "$slave" "$reg" "$*" +} + +# cb_i2c_muxwrite -- raw 1-byte write, no reg (TCA954x) +cb_i2c_muxwrite() { + [[ $# -lt 3 ]] && { echo "Usage: cb_i2c_muxwrite "; return 1; } + local ch="$1" slave=$(( $2 )) val=$(( $3 )) base tx cmd status + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + [[ "$CB_I2C_AUTO_INIT" == "1" ]] && cb_i2c_init "$ch" >/dev/null + _cbi2c_auto_mux_rst "$ch" + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (slave << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on mux addr 0x$(printf %02X "$slave")" >&2; return 1; } + _cbi2c_reg "$tx" "$(printf '0x%X' $((val & 0xFF)))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_WR | _CBI2C_STO)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on mux ctrl byte" >&2; return 1; } + printf ' [MUX-W] ch=%s mux=0x%02X <= 0x%02X\n' "$ch" "$slave" "$val" +} + +# cb_i2c_scan -- probe 0x08..0x77, report slaves that ACK +cb_i2c_scan() { + [[ $# -lt 1 ]] && { echo "Usage: cb_i2c_scan "; return 1; } + local ch="$1" base tx cmd a status found="" + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + cb_i2c_init "$ch" >/dev/null + _cbi2c_auto_mux_rst "$ch" + for (( a=0x08; a<=0x77; a++ )); do + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (a << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR | _CBI2C_STO)))") + _cbi2c_check_ack "$status" && found+="$(printf '0x%02X ' "$a")" + done + [[ -n "$found" ]] && echo " [SCAN] ch=$ch found: ${found% }" || echo " [SCAN] ch=$ch no devices" +} + +# === Public: PMBus (== SMBus; command code + Repeated START read) ============ + +# cb_pmbus_read [nbytes] (default 2 bytes, LSB first) +cb_pmbus_read() { + [[ $# -lt 3 ]] && { echo "Usage: cb_pmbus_read [nbytes]"; return 1; } + local ch="$1" slave=$(( $2 )) cc=$(( $3 )) n="${4:-2}" bytes + bytes=$(_cbi2c_xfer_read "$ch" "$slave" "$cc" "$n") || return 1 + if [[ "$n" == "2" ]]; then + local b0 b1 word; b0=$(( $(echo "$bytes" | awk '{print $1}') )); b1=$(( $(echo "$bytes" | awk '{print $2}') )) + word=$(( b0 | (b1 << 8) )) + printf ' [PMB-R] ch=%s slave=0x%02X cmd=0x%02X => 0x%04X raw=[%s] linear16=%s\n' \ + "$ch" "$slave" "$cc" "$word" "$bytes" "$(cb_pmbus_linear16 "$word")" + else + printf ' [PMB-R] ch=%s slave=0x%02X cmd=0x%02X => [%s]\n' "$ch" "$slave" "$cc" "$bytes" + fi +} + +# cb_pmbus_write [data byte...] (no byte = send-byte) +cb_pmbus_write() { + [[ $# -lt 3 ]] && { echo "Usage: cb_pmbus_write [data byte...]"; return 1; } + local ch="$1" slave=$(( $2 )) cc=$(( $3 )); shift 3 + if [[ $# -eq 0 ]]; then + _cbi2c_xfer_cmd_only "$ch" "$slave" "$cc" || return 1 + printf ' [PMB-W] ch=%s slave=0x%02X cmd=0x%02X <= (send-byte)\n' "$ch" "$slave" "$cc"; return 0 + fi + _cbi2c_xfer_write "$ch" "$slave" "$cc" "$@" || return 1 + printf ' [PMB-W] ch=%s slave=0x%02X cmd=0x%02X <= [%s]\n' "$ch" "$slave" "$cc" "$*" +} + +# cb_pmbus_linear16 +cb_pmbus_linear16() { + local word=$(( $1 & 0xFFFF )) + awk -v w="$word" 'BEGIN{ + e=int(w/2048)%32; if(e>15)e-=32; + m=w%2048; if(m>1023)m-=2048; + printf "%.4f", m * (2.0 ^ e); + }' +} + +# === Help ==================================================================== +blanton_cb_i2c_help() { + echo -e "\033[1mblanton_cb_i2c.sh - CB FPGA (F3) I2C / PMBus over OpenCores I2C master\033[0m" + echo "" + echo -e " Backend: \033[36mcb_fpga $CBI2C_FN\033[0m (direct PCIe BAR -> .3/resource0), base 0x300, Ch0..$CBI2C_CH_MAX" + echo "" + echo -e "\033[1mSetup\033[0m" + echo -e " \033[33mcb_i2c_init\033[0m [pre_lo] [pre_hi] prescale + enable (def 0x88/0x00 = 100kHz)" + echo -e " \033[33mcb_i2c_reset\033[0m LCL_RST=0xD" + echo -e " \033[33mcb_i2c_sem\033[0m [status|acquire [v]|release]" + echo -e " \033[33mcb_i2c_muxsel\033[0m write I2C_MUX_SEL_REG" + echo -e " \033[33mcb_i2c_mux_reset_release\033[0m de-assert ALL ext mux RESET (F0 0x7D4<=0xFF)" + echo "" + echo -e "\033[1mGeneric I2C\033[0m" + echo -e " \033[33mcb_i2c_scan\033[0m " + echo -e " \033[33mcb_i2c_read\033[0m [nbytes]" + echo -e " \033[33mcb_i2c_write\033[0m [byte...]" + echo -e " \033[33mcb_i2c_muxwrite\033[0m raw 1-byte (TCA954x)" + echo "" + echo -e "\033[1mPMBus / SMBus\033[0m" + echo -e " \033[33mcb_pmbus_read\033[0m [nbytes] (def 2, LE word + linear16)" + echo -e " \033[33mcb_pmbus_write\033[0m [byte...]" + echo -e " \033[33mcb_pmbus_linear16\033[0m " + echo "" + echo -e " Slave = 7-bit (tool shifts). Spec lists 8-bit pairs -> divide by 2." + echo -e " \033[33mfpga_debug on\033[0m to see every underlying pcimem command." +} + +blanton_cb_i2c_help diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/blanton_fpga_pcimem.sh b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/blanton_fpga_pcimem.sh new file mode 100644 index 0000000..ca21689 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/blanton_fpga_pcimem.sh @@ -0,0 +1,270 @@ +#!/usr/bin/env bash +# ============================================================================= +# blanton_fpga_pcimem.sh -- pcimem backend, sysfs resource file + relative offset +# ============================================================================= +# Version History: +# V1.3.0 2026-06-12 pcimem variant (SONiC hardware). memtool variant: blanton_fpga_memtool.sh +# Version number kept in sync with blanton_fpga_memtool.sh +# V1.4.0 2026-06-15 Fix: VSPI window bases pointed at the VSPI-Flash block +# (0x340/0x380/0x3C0/0x400, config-flash channel) so register +# reads returned 0; corrected to the VSPI register block +# (PMC 0x640 / ICB 0x680 / SWB0 0x6C0 / SWB1 0x700) +# Add: _vspi_fnwarn guard - warns when PMC/ICB/SWB are called with +# cb_fpga-style " " (a read turning into a write) +# Change: suppress pcimem write stdout noise (mmap/Written lines) +# Docs: comments/help translated to English (ASCII-only for SONiC console) +# V1.4.1 2026-06-23 Fix: BDF in example auto-detect was wrong (02:00 vs 04:00); corrected to match the lspci example. +# ============================================================================= +# +# SONiC hardware has no memtool / devmem, but it has pcimem. pcimem mmaps the PCI +# sysfs resource file directly and takes "resource file + offset relative to BAR +# start", not an absolute physical address. +# +# pcimem { sysfile } { offset } [ type*count [ data ] ] +# sysfile : sysfs file for the pci resource (e.g. .../resource0) +# offset : offset into pci memory region +# type : [b]yte, [h]alfword, [w]ord, [d]ouble-word +# *count : number of items (w*100 dump 100 words) +# data : data to be written +# +# This tool always accesses as word (w, 32-bit). +# +# After sourcing this file the following functions are available: +# cb_fpga [data] +# pmc_fpga [data] +# icb_fpga [data] +# swb0_fpga [data] +# swb1_fpga [data] +# +# data present = write, absent = read. +# Usage: source blanton_fpga_pcimem.sh + +# === CB FPGA PCIe resource file (sysfs) === +# Use lspci -D to find the BDF (domain:bus:dev.fn); resource0 is the sysfs mapping of BAR0. +# e.g. lspci -Dnn | grep -i fpga -> 0000:02:00.0 ... +# memtool variant fills in the BAR value; pcimem variant fills in the resource file +# path instead (offset becomes relative to BAR). +FUNCT0_RES=/sys/bus/pci/devices/0000:04:00.0/resource0 +FUNCT1_RES=/sys/bus/pci/devices/0000:04:00.1/resource0 +FUNCT2_RES=/sys/bus/pci/devices/0000:04:00.2/resource0 +FUNCT3_RES=/sys/bus/pci/devices/0000:04:00.3/resource0 + +# Auto-detect example (uncomment to use; needs the FPGA's BDF prefix): +# _BDF=0000:02:00 +# FUNCT0_RES=/sys/bus/pci/devices/${_BDF}.0/resource0 +# FUNCT1_RES=/sys/bus/pci/devices/${_BDF}.1/resource0 +# FUNCT2_RES=/sys/bus/pci/devices/${_BDF}.2/resource0 +# FUNCT3_RES=/sys/bus/pci/devices/${_BDF}.3/resource0 + +# === VSPI window base offset (relative to CB Function 2 resource0 start) === +# NOTE: CB.F2 has TWO near-identical VSPI register blocks (see spec register map): +# - VSPI-Flash-* @ 0x340/0x380/0x3C0/0x400 -> accesses the remote FPGA's CONFIG FLASH +# - VSPI-* @ 0x640/0x680/0x6C0/0x700 -> accesses the remote FPGA's REGISTERS +# This tool reads/writes remote registers, so it uses the VSPI-* block (0x640+). +# The VSPI-Flash bases are kept below (commented) in case flash access is needed later. +VSPI_PMC_BASE=0x640 +VSPI_ICB_BASE=0x680 +VSPI_SWB0_BASE=0x6C0 +VSPI_SWB1_BASE=0x700 + +# VSPI-Flash window bases (config-flash access, not register access): +# VSPI_FLASH_PMC_BASE=0x340 +# VSPI_FLASH_ICB_BASE=0x380 +# VSPI_FLASH_SWB0_BASE=0x3C0 +# VSPI_FLASH_SWB1_BASE=0x400 + +# === VSPI protocol constants === +_VSPI_CMD_STAT=0x00 +_VSPI_ADDR=0x04 +_VSPI_WR_DATA=0x08 +_VSPI_RD_DATA=0x0C +_VSPI_NEW_CMD=0x01 +_VSPI_READ_W=0x02 +_VSPI_WRITE_W=0x04 +_VSPI_READY_MASK=0x100 +_VSPI_POLL_MAX=200 + +# === pcimem command === +PCIMEM_CMD="${PCIMEM_CMD:-pcimem}" + +# === Debug mode (1=print commands AND execute, 0=execute only) === +DEBUG_MODE=${DEBUG_MODE:-0} + +fpga_debug() { + if [ "${1:-}" = "on" ]; then DEBUG_MODE=1 + elif [ "${1:-}" = "off" ]; then DEBUG_MODE=0 + else [ "$DEBUG_MODE" = "0" ] && DEBUG_MODE=1 || DEBUG_MODE=0; fi + echo -e "[\033[34mINFO\033[0m] DEBUG_MODE=$DEBUG_MODE" +} + +# Wrapper: debug mode prints command (to stderr) AND executes, normal mode executes only. +# On read, returns the parsed hex value (stripping pcimem's mmap noise). +# Usage: _pcimem [data] (data present = write, absent = read) +_pcimem() { + local sysfile="$1" offset="$2" data="${3:-}" + if [[ -n "$data" ]]; then + [ "$DEBUG_MODE" = "1" ] && \ + echo -e "\033[90m[DEBG] $PCIMEM_CMD $sysfile $offset w $data\033[0m" >&2 + # Write output (opened / Target offset / mmap / Written...readback) is never + # parsed -> drop stdout noise; keep stderr so real errors still surface. + $PCIMEM_CMD "$sysfile" "$offset" w "$data" >/dev/null + else + [ "$DEBUG_MODE" = "1" ] && \ + echo -e "\033[90m[DEBG] $PCIMEM_CMD $sysfile $offset w\033[0m" >&2 + # pcimem read prints mmap info + "Value at offset ...: 0xXXXX"; + # take the last 0x... token as the actual read-back value. + $PCIMEM_CMD "$sysfile" "$offset" w | grep -oiE '0x[0-9a-f]+' | tail -1 + fi +} + +# --- Internal VSPI helpers (all hang off CB Function 2's resource0) --- + +_vspi_read() { + local win_off="$1" remote_offset="$2" + local cmd_off add_off rd_off addr_val status i + + cmd_off=$(printf '0x%X' $(( win_off + _VSPI_CMD_STAT ))) + add_off=$(printf '0x%X' $(( win_off + _VSPI_ADDR ))) + rd_off=$(printf '0x%X' $(( win_off + _VSPI_RD_DATA ))) + addr_val=$(printf '0x%08X' $(( (0x0 << 20) | (remote_offset & 0xFFFFF) ))) + + _pcimem "$FUNCT2_RES" "$add_off" "$addr_val" + _pcimem "$FUNCT2_RES" "$cmd_off" $(printf '0x%X' $(( _VSPI_NEW_CMD | _VSPI_READ_W ))) + + for (( i=0; i<_VSPI_POLL_MAX; i++ )); do + status=$(_pcimem "$FUNCT2_RES" "$cmd_off") + if (( ( ${status:-0} & _VSPI_READY_MASK) != 0 )); then + _pcimem "$FUNCT2_RES" "$rd_off" + return 0 + fi + done + echo "ERROR: VSPI read timeout @ offset $remote_offset" >&2 + return 1 +} + +_vspi_write() { + local win_off="$1" remote_offset="$2" data="$3" + local cmd_off add_off wr_off addr_val status i + + cmd_off=$(printf '0x%X' $(( win_off + _VSPI_CMD_STAT ))) + add_off=$(printf '0x%X' $(( win_off + _VSPI_ADDR ))) + wr_off=$(printf '0x%X' $(( win_off + _VSPI_WR_DATA ))) + addr_val=$(printf '0x%08X' $(( (0x0 << 20) | (remote_offset & 0xFFFFF) ))) + + _pcimem "$FUNCT2_RES" "$wr_off" "$data" + _pcimem "$FUNCT2_RES" "$add_off" "$addr_val" + _pcimem "$FUNCT2_RES" "$cmd_off" $(printf '0x%X' $(( _VSPI_NEW_CMD | _VSPI_WRITE_W ))) + + for (( i=0; i<_VSPI_POLL_MAX; i++ )); do + status=$(_pcimem "$FUNCT2_RES" "$cmd_off") + if (( ( ${status:-0} & _VSPI_READY_MASK) != 0 )); then + return 0 + fi + done + echo "ERROR: VSPI write timeout @ offset $remote_offset" >&2 + return 1 +} + +# Guard: PMC/ICB/SWB are single-function; signature is [data], NO fn arg. +# Common pitfall: using cb_fpga's " " form -> 2nd arg becomes data, a read +# turns into a write. If addr is 0~3 (looks like fn) AND data is given, warn and +# confirm; on a non-tty (script) just warn, don't block. +# Usage: _vspi_fnwarn non-zero return = cancel +_vspi_fnwarn() { + local name="$1" addr="$2" data="$3" + [[ -z "$data" ]] && return 0 # read, nothing to warn + case "$addr" in + 0|1|2|3|0x0|0x1|0x2|0x3|0x00|0x01|0x02|0x03) ;; # looks like fn, warn below + *) return 0 ;; # normal offset, allow + esac + echo -e "[\033[33mWARN\033[0m] $name has no fn arg; signature is [data] (NOT cb_fpga's )." >&2 + echo -e " This will WRITE $data to PMC/ICB/SWB offset $addr." >&2 + echo -e " To READ offset $addr, pass a single arg: $name $addr" >&2 + if [ -t 0 ]; then + local ans + read -r -p " Proceed with write anyway? [y/N] " ans + case "$ans" in + y|Y|yes|YES) return 0 ;; + *) echo " Cancelled." >&2; return 1 ;; + esac + fi + return 0 +} + +# === Public functions === + +cb_fpga() { + if [[ $# -lt 2 ]]; then + echo "Usage: cb_fpga [data]"; return 1 + fi + local fn="$1" addr="$2" data="${3:-}" res + case "$fn" in + 0) res=$FUNCT0_RES ;; 1) res=$FUNCT1_RES ;; + 2) res=$FUNCT2_RES ;; 3) res=$FUNCT3_RES ;; + *) echo "cb_fpga: fn must be 0-3" >&2; return 1 ;; + esac + # pcimem offset is relative to BAR start; do not add BAR. + if [[ -z "$data" ]]; then + _pcimem "$res" "$addr" + else + _pcimem "$res" "$addr" "$data" + fi +} + +pmc_fpga() { + if [[ $# -lt 1 ]]; then + echo "Usage: pmc_fpga [data]"; return 1 + fi + local addr="$1" data="${2:-}" + _vspi_fnwarn pmc_fpga "$addr" "$data" || return 1 + if [[ -z "$data" ]]; then _vspi_read "$VSPI_PMC_BASE" "$addr" + else _vspi_write "$VSPI_PMC_BASE" "$addr" "$data"; fi +} + +icb_fpga() { + if [[ $# -lt 1 ]]; then + echo "Usage: icb_fpga [data]"; return 1 + fi + local addr="$1" data="${2:-}" + _vspi_fnwarn icb_fpga "$addr" "$data" || return 1 + if [[ -z "$data" ]]; then _vspi_read "$VSPI_ICB_BASE" "$addr" + else _vspi_write "$VSPI_ICB_BASE" "$addr" "$data"; fi +} + +swb0_fpga() { + if [[ $# -lt 1 ]]; then + echo "Usage: swb0_fpga [data]"; return 1 + fi + local addr="$1" data="${2:-}" + _vspi_fnwarn swb0_fpga "$addr" "$data" || return 1 + if [[ -z "$data" ]]; then _vspi_read "$VSPI_SWB0_BASE" "$addr" + else _vspi_write "$VSPI_SWB0_BASE" "$addr" "$data"; fi +} + +swb1_fpga() { + if [[ $# -lt 1 ]]; then + echo "Usage: swb1_fpga [data]"; return 1 + fi + local addr="$1" data="${2:-}" + _vspi_fnwarn swb1_fpga "$addr" "$data" || return 1 + if [[ -z "$data" ]]; then _vspi_read "$VSPI_SWB1_BASE" "$addr" + else _vspi_write "$VSPI_SWB1_BASE" "$addr" "$data"; fi +} + +blanton_fpga_help() { + echo -e "\033[1mblanton_fpga (pcimem) - FPGA Register Access Tool\033[0m" + echo "" + echo -e "\033[1mUsage:\033[0m" + echo -e " \033[33mcb_fpga\033[0m [data] CB FPGA direct (sysfs resource0)" + echo -e " \033[33mpmc_fpga\033[0m [data] PMC FPGA via VSPI" + echo -e " \033[33micb_fpga\033[0m [data] ICB FPGA via VSPI" + echo -e " \033[33mswb0_fpga\033[0m [data] SWB0 FPGA via VSPI" + echo -e " \033[33mswb1_fpga\033[0m [data] SWB1 FPGA via VSPI" + echo -e " \033[33mfpga_debug\033[0m on|off Toggle debug mode (print commands and execute)" + echo "" + echo -e " Omit [data] to \033[32mread\033[0m, provide [data] to \033[31mwrite\033[0m." + echo -e " Backend: \033[36mpcimem\033[0m (sysfs resource file + relative offset)." + echo -e " Run \033[33mblanton_fpga_help\033[0m to show this message again." +} + +blanton_fpga_help diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/logs/.gitkeep b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/logs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/margin.sh b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/margin.sh new file mode 100644 index 0000000..3e5ab4c --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/margin.sh @@ -0,0 +1,493 @@ +#!/bin/bash +# Blanton Margin Tool - Shell version (CB: i2cset/i2cget | SWB: cb_pmbus_* via FPGA) +# Usage: source margin.sh; margin_init; margin_status +# +# ============================================================================= +# Version Control +# ----------------------------------------------------------------------------- +# v2.5.0 SWB margin support via a per-conf TRANSPORT layer. The SWB margin +# boards are ALSO LTC2980 (2x LTC2977) -- same chip as CB -- just reached +# through the CB FPGA F3 I2C master instead of a native bus. So the whole +# stack above the wire (PAGE, LINEAR16 x8192, VNOM margin) is identical; +# only the wire op changes. A .conf sets: +# TRANSPORT="swb" CB_I2C_CH=<6|7|8|9> +# and i2cset/i2cget are swapped for cb_pmbus_write/cb_pmbus_read (from the +# bundled blanton_cb_i2c.sh + blanton_fpga_pcimem.sh) on that FPGA channel. +# The LTC2977 addresses stay in CHIPS; the bus field is unused for swb. +# TRANSPORT unset -> "i2c", so existing CB confs are unchanged. +# v2.4.0 Auto-enable channel before margining: clear ON_OFF_CONFIG use_control +# (0x02=0x1a) so OPERATION can turn the channel on and soft-connect the +# servo DAC. Fixes "STATUS_WORD OFF=1, Vout won't move" on rails the +# LTC2980 does not sequence (externally enabled, e.g. MPQ8625 always-on). +# margin_set does NOT block for servo settle — confirm final voltages +# with margin_status afterwards. RAM-only; reverts on power cycle. +# v2.3.1 Fix: LINEAR16 hex->dec parsing (SONiC busybox/mawk ignores "0x") +# v2.3.0 Logging system, TAB completion, colored output +# v2.2.0 margin_debug toggle + colored log output +# v2.1.0 Batch scripts for status / apply_profile / save across boards +# v2.0.0 Per-LTC2980 .conf, Script Channel mapping, scoped PRE/POST (breaking) +# v1.2.0 Per-chip PRE/POST command hooks +# v1.1.0 Replace i2cexec with i2cset/i2cget, rename to LTC2980 +# v1.0.0 Initial release - LTC2977 PMBus margin test tool +# ============================================================================= + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SETTINGS_DIR="$SCRIPT_DIR/settings" +PROFILES_DIR="$SCRIPT_DIR/profiles" +LOGS_DIR="$SCRIPT_DIR/logs" + +# --- Ensure logs directory exists --- +mkdir -p "$LOGS_DIR" + +# --- Global state --- +PART_NUMBER="" +CHIPS=() +DEBUG_MODE=0 +LOG_MODE=1 + +# Transport backend, selected per-conf (a .conf sets TRANSPORT): +# "i2c" (default) - LTC2980 on the CPU I2C bus via i2cset/i2cget +# "swb" - the SAME LTC2980 margin board, but reached through the CB +# FPGA F3 I2C master via cb_pmbus_read/cb_pmbus_write. The +# LTC2977 addresses stay in CHIPS; CB_I2C_CH picks the FPGA +# I2C channel (6/7/8/9). Everything above the wire (PAGE, +# LINEAR16 x8192, VNOM margin) is identical to the i2c path. +TRANSPORT="i2c" +CB_I2C_CH="" + +# Channel enable for margining. Rails the LTC2980 does not sequence (externally +# enabled, e.g. an always-on MPQ8625 buck) sit with STATUS_WORD OFF=1 and won't +# margin, because the servo DAC never soft-connects. Writing ON_OFF_CONFIG (0x02) +# to clear use_control lets a following OPERATION command turn the channel on so +# the DAC connects and servos to the margin target. Change is RAM-only and reverts +# on power cycle (never STORE_USER_ALL during a test). Set MARGIN_AUTO_ENABLE=0 to +# keep the stored ON_OFF_CONFIG untouched. +MARGIN_AUTO_ENABLE=1 +ONOFF_ENABLE_VALUE="0x1a" # controlled_on=1, use_pmbus=1, use_control=0, b1=1 +# Short pause after OPERATION so the write registers; NOT a full servo settle. +# margin_set returns immediately (does not block per channel) — the DAC soft-connect +# + servo ramp takes a few seconds, so confirm final voltages yourself with +# margin_status after all channels are set. Bump this if you want margin_set's own +# read-back to reflect the settled value. +MARGIN_SETTLE="0.3" +_BUS="" +_ADDR="" +_PRE_SCOPE="" # set while inside a PRE/POST wrapped operation; prevents nested re-entry +_LOG_FILE="" +_LOG_DETAIL_FILE="" +_LOG_DETAIL_LINE=0 + +# --- Logging helper --- +_ts() { + date "+%Y-%m-%d %H:%M:%S.%3N" +} + +_log() { + [ "$LOG_MODE" = "0" ] && return + [ -z "$_LOG_FILE" ] && return + echo -e "[$(_ts)] $*" >> "$_LOG_FILE" +} + +_log_detail() { + [ "$LOG_MODE" = "0" ] && return + [ -z "$_LOG_DETAIL_FILE" ] && return + (( _LOG_DETAIL_LINE++ )) + echo "[$(_ts)] $*" >> "$_LOG_DETAIL_FILE" +} + +_log_label() { + [ "$LOG_MODE" = "0" ] && return + local label=$1 + (( _LOG_DETAIL_LINE++ )) + echo "[$(_ts)] --- $label ---" >> "$_LOG_DETAIL_FILE" + _log "$label \033[90m(detail Line:${_LOG_DETAIL_LINE})\033[0m" +} + +_log_start_session() { + _log "--- margin_init: $PART_NUMBER ---" +} + +# --- Toggle log mode --- +margin_log() { + if [ "${1:-}" = "on" ]; then + LOG_MODE=1 + elif [ "${1:-}" = "off" ]; then + LOG_MODE=0 + else + [ "$LOG_MODE" = "0" ] && LOG_MODE=1 || LOG_MODE=0 + fi + echo -e "[\033[34mINFO\033[0m] LOG_MODE=$LOG_MODE" +} + +# --- Toggle debug mode --- +margin_debug() { + if [ "${1:-}" = "on" ]; then + DEBUG_MODE=1 + elif [ "${1:-}" = "off" ]; then + DEBUG_MODE=0 + else + [ "$DEBUG_MODE" = "0" ] && DEBUG_MODE=1 || DEBUG_MODE=0 + fi + echo -e "[\033[34mINFO\033[0m] DEBUG_MODE=$DEBUG_MODE" +} + +# --- Init: load setting by name --- +margin_init() { + if [ -z "$1" ]; then + echo -e "[\033[31mERRO\033[0m] Usage: margin_init " + return 1 + fi + PART_NUMBER="$1" + echo "Part Number: $PART_NUMBER" + + local setting_file="$SETTINGS_DIR/${PART_NUMBER}.conf" + if [ ! -f "$setting_file" ]; then + echo -e "[\033[31mERRO\033[0m] Setting file not found: $setting_file" + return 1 + fi + TRANSPORT="i2c"; CB_I2C_CH="" # reset before sourcing; swb confs override + source "$setting_file" + TRANSPORT="${TRANSPORT:-i2c}" # a blank TRANSPORT="" in a .conf means i2c + echo -e "[\033[34mINFO\033[0m] Loaded setting: $setting_file (transport=$TRANSPORT)" + + # SWB rails need the cb_pmbus_* backend; source it on demand. + if [ "$TRANSPORT" = "swb" ] && ! declare -F cb_pmbus_read >/dev/null 2>&1; then + if [ -f "$SCRIPT_DIR/blanton_cb_i2c.sh" ]; then + # shellcheck source=/dev/null + source "$SCRIPT_DIR/blanton_cb_i2c.sh" + else + echo -e "[\033[31mERRO\033[0m] TRANSPORT=swb but blanton_cb_i2c.sh not found in $SCRIPT_DIR" + return 1 + fi + fi + _log_start_session +} + +# --- Tab completion for margin_init --- +_margin_init_completions() { + [ "$COMP_CWORD" -ne 1 ] && return + local cur="${COMP_WORDS[COMP_CWORD]}" + local names=$(ls "$SETTINGS_DIR"/*.conf 2>/dev/null | xargs -n1 basename | sed 's/\.conf$//') + COMPREPLY=($(compgen -W "$names" -- "$cur")) +} +complete -F _margin_init_completions margin_init + +# --- PRE/POST scope helpers --- +# PRE/POST run once at the outermost public-function entry/exit. +# Nested calls (e.g. margin_apply_profile -> margin_set -> margin_read_vout) +# see _PRE_SCOPE already set and skip, so the mux only switches once. +_run_cmds() { + local cmds=$1 label=$2 + [ -z "$cmds" ] && return + IFS=';' read -ra _cmds <<< "$cmds" + for _cmd in "${_cmds[@]}"; do + _cmd=$(echo "$_cmd" | xargs) + [ -z "$_cmd" ] && continue + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[36m$label $_cmd\033[0m" + eval "$_cmd" >/dev/null 2>&1 + done +} + +# Returns 0 (true) if caller owns the scope and must call _pre_exit on the way out. +_pre_enter_own() { + if [ -z "$_PRE_SCOPE" ]; then + _PRE_SCOPE=1 + _run_cmds "${CHIP_PRE_CMD[0]}" "[PRE]" + return 0 + fi + return 1 +} + +_pre_exit() { + _run_cmds "${CHIP_POST_CMD[0]}" "[POST]" + _PRE_SCOPE="" +} + +# --- Helper: set _BUS and _ADDR from channel number --- +# Both transports use CHIPS (LTC2977 addresses). For swb the bus field is unused +# (the FPGA I2C channel comes from CB_I2C_CH); _ADDR is the PMBus slave. +_get_chip() { + local chip_idx=$(( $1 / 8 )) + IFS=':' read -r _BUS _ADDR <<< "${CHIPS[$chip_idx]}" +} + +# --- Helper: get page (channel within LTC2977, 0x00~0x07) --- +_get_page() { + printf "0x%02x" $(( $1 % 8 )) +} + +# --- I2C low-level helpers (use _BUS/_ADDR set by _get_chip) --- +# TRANSPORT=swb swaps the i2cset/i2cget wire op for cb_pmbus_* on CB_I2C_CH. +# PAGE is written the same way on both (PMBus command 0x00). +_open_page() { + if [ "$TRANSPORT" = "swb" ]; then + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] cb_pmbus_write $CB_I2C_CH $_ADDR 0x00 $1\033[0m" + cb_pmbus_write "$CB_I2C_CH" "$_ADDR" 0x00 "$1" >/dev/null 2>&1 + return + fi + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] i2cset -y $_BUS $_ADDR 0x00 $1 b\033[0m" + i2cset -y "$_BUS" "$_ADDR" 0x00 "$1" b >/dev/null 2>&1 +} + +# Write a 16-bit word (LINEAR16, little-endian: lo byte first). +_i2c_write_word() { + local reg=$1 lo=$2 hi=$3 + if [ "$TRANSPORT" = "swb" ]; then + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] cb_pmbus_write $CB_I2C_CH $_ADDR $reg $lo $hi\033[0m" + cb_pmbus_write "$CB_I2C_CH" "$_ADDR" "$reg" "$lo" "$hi" >/dev/null 2>&1 + return + fi + local word=$(( (hi << 8) | lo )) + local word_hex=$(printf "0x%04x" "$word") + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] i2cset -y $_BUS $_ADDR $reg $word_hex w\033[0m" + i2cset -y "$_BUS" "$_ADDR" "$reg" "$word" w >/dev/null 2>&1 +} + +_i2c_write_byte() { + if [ "$TRANSPORT" = "swb" ]; then + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] cb_pmbus_write $CB_I2C_CH $_ADDR $1 $2\033[0m" + cb_pmbus_write "$CB_I2C_CH" "$_ADDR" "$1" "$2" >/dev/null 2>&1 + return + fi + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] i2cset -y $_BUS $_ADDR $1 $2 b\033[0m" + i2cset -y "$_BUS" "$_ADDR" "$1" "$2" b >/dev/null 2>&1 +} + +# Read a 16-bit word; echoes "0xXXXX". For swb, parse cb_pmbus_read's "=> 0xXXXX". +_i2c_read_word() { + if [ "$TRANSPORT" = "swb" ]; then + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] cb_pmbus_read $CB_I2C_CH $_ADDR $1 2\033[0m" >&2 + local out word + out=$(cb_pmbus_read "$CB_I2C_CH" "$_ADDR" "$1" 2 2>/dev/null) + # cb_pmbus_read prints "... => 0xXXXX raw=[...] ..."; take the word after "=>". + word=$(printf '%s' "$out" | awk -F'=> ' 'NF>1{print $2}' | awk '{print $1}') + [[ "$word" =~ ^0[xX][0-9a-fA-F]+$ ]] || word="0x0000" + echo "$word" + return + fi + [ "$DEBUG_MODE" = "1" ] && echo -e "\033[90m[DEBG] i2cget -y $_BUS $_ADDR $1 w\033[0m" >&2 + local result + result=$(i2cget -y "$_BUS" "$_ADDR" "$1" w 2>/dev/null) + if [ -z "$result" ]; then + echo "0x0000" + else + echo "$result" + fi +} + +# --- Enable current channel for margining (clear ON_OFF_CONFIG use_control) --- +# Assumes _get_chip + _open_page already ran (uses current _BUS/_ADDR/page). +# Lets a subsequent OPERATION command turn the channel on so the servo DAC +# soft-connects; without this, rails the LTC2980 doesn't sequence stay OFF and +# margining has no effect. RAM-only; a power cycle restores the stored value. +_enable_channel() { + _i2c_write_byte 0x02 "$ONOFF_ENABLE_VALUE" +} + +# --- Helper: decimal to LINEAR16 (returns "lo hi" hex strings) --- +_dec_to_lin16() { + local value=$1 + if [ "$value" = "0" ]; then + echo "0x00 0x00" + return + fi + local raw=$(awk "BEGIN { printf \"%04X\", int($value * 8192) }") + local hi=${raw:0:2} + local lo=${raw:2:2} + echo "0x${lo} 0x${hi}" +} + +# --- Helper: LINEAR16 word to decimal voltage --- +# i2cget returns a hex string like "0x9fc2". SONiC's awk (busybox/mawk) does NOT +# parse a "0x" prefix in arithmetic and treats it as 0, so convert hex -> decimal +# with bash arithmetic $(( )) first, then feed the decimal to awk. +_lin16_to_dec() { + local raw_word=$(( ${1:-0} )) + awk "BEGIN { printf \"%.4f\", $raw_word / 8192.0 }" +} + +# --- Read Vout for a channel --- +margin_read_vout() { + local ch=$1 + local vnom_var="CH${ch}_VNOM" + local net_var="CH${ch}_NET" + local vnom=${!vnom_var} + local net=${!net_var} + + if [ "$vnom" = "-" ] || [ -z "$vnom" ]; then + printf "CH %2d: Channel not used\n" "$ch" + LAST_VOUT="0" + return + fi + + local _own=0 + _pre_enter_own && _own=1 + + _get_chip "$ch" + _open_page "$(_get_page "$ch")" + local raw + raw=$(_i2c_read_word 0x8b) + local vout=$(_lin16_to_dec "$raw") + + local pct + pct=$(awk "BEGIN { printf \"%+.3f\", ($vout - $vnom) / $vnom * 100 }") + local _line + printf -v _line "CH %2d: Vnom = %.3f, Vout = %s (%s%%). Net - %s" "$ch" "$vnom" "$vout" "$pct" "$net" + echo "$_line" + _log_detail "$_line" + LAST_VOUT="$vout" + + [ "$_own" = "1" ] && _pre_exit +} + +# --- Status: read all or specific channel --- +margin_status() { + local ch_in=${1:-all} + echo "-------------" + echo "[$PART_NUMBER] Channel status" + echo "-------------" + _log_label "margin_status [$PART_NUMBER] ch=$ch_in" + + local _own=0 + _pre_enter_own && _own=1 + + if [ "$ch_in" = "all" ]; then + for i in $(seq 0 15); do + local vnom_var="CH${i}_VNOM" + [ -n "${!vnom_var}" ] && margin_read_vout "$i" + done + else + margin_read_vout "$ch_in" + fi + + [ "$_own" = "1" ] && _pre_exit +} + +# --- Set margin value (write high/low + OV/UV) --- +margin_set_value() { + local ch=$1 vnom=$2 change=$3 ovuv=${4:-2} + + local high_val low_val ov_val uv_val + high_val=$(_dec_to_lin16 "$(awk "BEGIN { print $vnom * (1 + $change/100) }")") + low_val=$(_dec_to_lin16 "$(awk "BEGIN { print $vnom * (1 - $change/100) }")") + ov_val=$(_dec_to_lin16 "$(awk "BEGIN { print $vnom * (1 + ($change+$ovuv)/100) }")") + uv_val=$(_dec_to_lin16 "$(awk "BEGIN { print $vnom * (1 - ($change+$ovuv)/100) }")") + + local _own=0 + _pre_enter_own && _own=1 + + _get_chip "$ch" + _open_page "$(_get_page "$ch")" + + local hi lo + read lo hi <<< $high_val + _i2c_write_word 0x25 "$lo" "$hi" + read lo hi <<< $low_val + _i2c_write_word 0x26 "$lo" "$hi" + read lo hi <<< $ov_val + _i2c_write_word 0x40 "$lo" "$hi" + read lo hi <<< $uv_val + _i2c_write_word 0x44 "$lo" "$hi" + + [ "$_own" = "1" ] && _pre_exit +} + +# --- Set operation register --- +margin_operation() { + local ch=$1 op=$2 + + local op_val + case "$op" in + high) op_val=0xa8 ;; + low) op_val=0x98 ;; + nominal) op_val=0x80 ;; + off) op_val=0x00 ;; + *) echo -e "[\033[31mERRO\033[0m] invalid operation '$op'"; return 1 ;; + esac + + local _own=0 + _pre_enter_own && _own=1 + + _get_chip "$ch" + _open_page "$(_get_page "$ch")" + # Let OPERATION turn the channel on (soft-connect DAC) even on rails the + # LTC2980 does not sequence; skip when turning the channel off. + [ "$MARGIN_AUTO_ENABLE" = "1" ] && [ "$op" != "off" ] && _enable_channel + _i2c_write_byte 0x01 "$op_val" + sleep "$MARGIN_SETTLE" + + [ "$_own" = "1" ] && _pre_exit +} + +# --- Set: combined set_value + operation + verify --- +margin_set() { + local ch=$1 op=$2 change=$3 + local vnom_var="CH${ch}_VNOM" + local vnom=${!vnom_var} + + if [ "$vnom" = "-" ] || [ -z "$vnom" ]; then + printf "CH %2d: Channel not used\n" "$ch" + return + fi + + local _own=0 + _pre_enter_own && _own=1 + + margin_set_value "$ch" "$vnom" "$change" + margin_operation "$ch" "$op" + margin_read_vout "$ch" + local _line + printf -v _line "CH %2d: Set %s %s%% done (Vout=%s)" "$ch" "$op" "$change" "$LAST_VOUT" + echo "$_line" + _log_detail "$_line" + _log "$(printf 'margin_set CH%2d %-7s %3s%% Vout=%-8s' $ch $op $change $LAST_VOUT)\033[90m(detail Line:${_LOG_DETAIL_LINE})\033[0m" + + [ "$_own" = "1" ] && _pre_exit +} + +# --- Apply a margin profile file --- +margin_apply_profile() { + local profile=${1:-"$PROFILES_DIR/${PART_NUMBER}_default.conf"} + if [ ! -f "$profile" ]; then + echo -e "[\033[31mERRO\033[0m] Profile not found: $profile" + return 1 + fi + echo "Applying profile: $profile" + _log_label "margin_apply_profile [$PART_NUMBER] $profile" + source "$profile" + + local _own=0 + _pre_enter_own && _own=1 + + for entry in "${PROFILE_CHANNELS[@]}"; do + local ch op change + IFS=':' read -r ch op change <<< "$entry" + margin_set "$ch" "$op" "$change" + done + + [ "$_own" = "1" ] && _pre_exit +} + +# --- Save to NVM --- +margin_save() { + local _own=0 + _pre_enter_own && _own=1 + + for chip in "${CHIPS[@]}"; do + IFS=':' read -r _BUS _ADDR <<< "$chip" + _i2c_write_byte 0x15 0x00 + done + echo "Change Saved (${#CHIPS[@]} chips)" + _log_label "margin_save $PART_NUMBER (${#CHIPS[@]} chips)" + + [ "$_own" = "1" ] && _pre_exit +} + +if [ -z "$_LOG_FILE" ]; then + _LOG_FILE="$LOGS_DIR/margin_$(date '+%Y%m%d_%H%M%S').log" + _LOG_DETAIL_FILE="${_LOG_FILE%.log}_detail.log" + _log "=== Session start ===" + _log "Detail log: $_LOG_DETAIL_FILE" +fi + +echo -e "[\033[34mINFO\033[0m] LTC2980 Margin Tool loaded. Run 'margin_init' to start." diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/all_off.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/all_off.conf new file mode 100644 index 0000000..1c6e6b3 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/all_off.conf @@ -0,0 +1,22 @@ +# Profile: all_off - 全部回 nominal +# Applied to whichever LTC2980 is currently loaded via margin_init +# Format: "channel:operation:change_percent" + +PROFILE_CHANNELS=( + "0:nominal:8" + "1:nominal:8" + "2:nominal:8" + "3:nominal:8" + "4:nominal:8" + "5:nominal:8" + "6:nominal:8" + "7:nominal:8" + "8:nominal:8" + "9:nominal:8" + "10:nominal:8" + "11:nominal:8" + "12:nominal:8" + "13:nominal:8" + "14:nominal:8" + "15:nominal:8" +) diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/comboA.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/comboA.conf new file mode 100644 index 0000000..5889fec --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/comboA.conf @@ -0,0 +1,22 @@ +# Profile: comboA - alternating high/low (even=high, odd=low) +# Applied to whichever LTC2980 is currently loaded via margin_init +# Format: "channel:operation:change_percent" + +PROFILE_CHANNELS=( + "0:high:8" + "1:low:8" + "2:high:8" + "3:low:8" + "4:high:8" + "5:low:8" + "6:high:8" + "7:low:8" + "8:high:8" + "9:low:8" + "10:high:8" + "11:low:8" + "12:high:8" + "13:low:8" + "14:high:8" + "15:low:8" +) diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/comboB.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/comboB.conf new file mode 100644 index 0000000..a765610 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/comboB.conf @@ -0,0 +1,22 @@ +# Profile: comboB - inverse of comboA (even=low, odd=high) +# Applied to whichever LTC2980 is currently loaded via margin_init +# Format: "channel:operation:change_percent" + +PROFILE_CHANNELS=( + "0:low:8" + "1:high:8" + "2:low:8" + "3:high:8" + "4:low:8" + "5:high:8" + "6:low:8" + "7:high:8" + "8:low:8" + "9:high:8" + "10:low:8" + "11:high:8" + "12:low:8" + "13:high:8" + "14:low:8" + "15:high:8" +) diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_high3.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_high3.conf new file mode 100644 index 0000000..f386642 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_high3.conf @@ -0,0 +1,22 @@ +# Profile: combo_high3 - 全部 channel margin high +3% +# Applied to whichever LTC2980 is currently loaded via margin_init +# Format: "channel:operation:change_percent" + +PROFILE_CHANNELS=( + "0:high:3" + "1:high:3" + "2:high:3" + "3:high:3" + "4:high:3" + "5:high:3" + "6:high:3" + "7:high:3" + "8:high:3" + "9:high:3" + "10:high:3" + "11:high:3" + "12:high:3" + "13:high:3" + "14:high:3" + "15:high:3" +) diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_high5.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_high5.conf new file mode 100644 index 0000000..f69df0f --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_high5.conf @@ -0,0 +1,22 @@ +# Profile: combo_high - 全部 channel margin high +5% +# Applied to whichever LTC2980 is currently loaded via margin_init +# Format: "channel:operation:change_percent" + +PROFILE_CHANNELS=( + "0:high:5" + "1:high:5" + "2:high:5" + "3:high:5" + "4:high:5" + "5:high:5" + "6:high:5" + "7:high:5" + "8:high:5" + "9:high:5" + "10:high:5" + "11:high:5" + "12:high:5" + "13:high:5" + "14:high:5" + "15:high:5" +) diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_low3.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_low3.conf new file mode 100644 index 0000000..18717f3 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_low3.conf @@ -0,0 +1,22 @@ +# Profile: combo_low3 - 全部 channel margin low -3% +# Applied to whichever LTC2980 is currently loaded via margin_init +# Format: "channel:operation:change_percent" + +PROFILE_CHANNELS=( + "0:low:3" + "1:low:3" + "2:low:3" + "3:low:3" + "4:low:3" + "5:low:3" + "6:low:3" + "7:low:3" + "8:low:3" + "9:low:3" + "10:low:3" + "11:low:3" + "12:low:3" + "13:low:3" + "14:low:3" + "15:low:3" +) diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_low5.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_low5.conf new file mode 100644 index 0000000..54fc7c9 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_low5.conf @@ -0,0 +1,22 @@ +# Profile: combo_low - 全部 channel margin low -5% +# Applied to whichever LTC2980 is currently loaded via margin_init +# Format: "channel:operation:change_percent" + +PROFILE_CHANNELS=( + "0:low:5" + "1:low:5" + "2:low:5" + "3:low:5" + "4:low:5" + "5:low:5" + "6:low:5" + "7:low:5" + "8:low:5" + "9:low:5" + "10:low:5" + "11:low:5" + "12:low:5" + "13:low:5" + "14:low:5" + "15:low:5" +) diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_normal.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_normal.conf new file mode 100644 index 0000000..3da4768 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/profiles/combo_normal.conf @@ -0,0 +1,23 @@ +# Profile: combo_normal - 全部 channel 回 nominal(標稱值) +# Applied to whichever LTC2980 is currently loaded via margin_init +# Format: "channel:operation:change_percent" +# nominal 時 operation=0x80,輸出跟隨 VOUT_COMMAND;change_percent 不影響輸出 + +PROFILE_CHANNELS=( + "0:nominal:5" + "1:nominal:5" + "2:nominal:5" + "3:nominal:5" + "4:nominal:5" + "5:nominal:5" + "6:nominal:5" + "7:nominal:5" + "8:nominal:5" + "9:nominal:5" + "10:nominal:5" + "11:nominal:5" + "12:nominal:5" + "13:nominal:5" + "14:nominal:5" + "15:nominal:5" +) diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_apply_profile_all.sh b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_apply_profile_all.sh new file mode 100644 index 0000000..11b393c --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_apply_profile_all.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Apply a margin profile to every LTC2980 in BOARDS. +# BOARDS[i] 對應 PROFILES[i],兩個陣列長度必須一樣。 +# Usage: +# source script/margin_apply_profile_all.sh + +# --- Edit this list --- +BOARDS=( + "Blanton_CB_CONN13" + "Blanton_SWB0_CONN13" + "Blanton_SWB0_CONN14" + "Blanton_SWB0_CONN15" + "Blanton_SWB0_CONN16" + "Blanton_SWB1_CONN13" + "Blanton_SWB1_CONN14" + "Blanton_SWB1_CONN15" + "Blanton_SWB1_CONN16" +) + +# 對應的 profile 名稱(不含路徑與 .conf 副檔名),預設全部 comboA +PROFILES=( + "comboA" # Blanton_CB_CONN13 + "comboA" # Blanton_SWB0_CONN13 + "comboA" # Blanton_SWB0_CONN14 + "comboA" # Blanton_SWB0_CONN15 + "comboA" # Blanton_SWB0_CONN16 + "comboA" # Blanton_SWB1_CONN13 + "comboA" # Blanton_SWB1_CONN14 + "comboA" # Blanton_SWB1_CONN15 + "comboA" # Blanton_SWB1_CONN16 +) + +# --- Source margin.sh if not already loaded --- +_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +[ -z "$(type -t margin_init)" ] && source "$_SCRIPT_DIR/../margin.sh" + +# --- Sanity check --- +if [ ${#BOARDS[@]} -ne ${#PROFILES[@]} ]; then + echo "ERROR: BOARDS (${#BOARDS[@]}) and PROFILES (${#PROFILES[@]}) length mismatch" + return 1 2>/dev/null || exit 1 +fi + +# --- Iterate --- +for i in "${!BOARDS[@]}"; do + board="${BOARDS[$i]}" + profile="${PROFILES[$i]}" + margin_init "$board" || continue + margin_apply_profile "$PROFILES_DIR/${profile}.conf" + echo "" +done diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_save_all.sh b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_save_all.sh new file mode 100644 index 0000000..c34249a --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_save_all.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Run margin_save on every LTC2980 in BOARDS. +# +# ⚠️ margin_save 會把目前的 margin / OV / UV 設定**永久寫入 NVM**, +# 斷電後仍保留。執行前請務必先 margin_status 確認各 channel 狀態正確。 +# +# Usage: +# source script/margin_save_all.sh + +# --- Edit this list --- +BOARDS=( + "Blanton_CB_CONN13" + "Blanton_SWB0_CONN13" + "Blanton_SWB0_CONN14" + "Blanton_SWB0_CONN15" + "Blanton_SWB0_CONN16" + "Blanton_SWB1_CONN13" + "Blanton_SWB1_CONN14" + "Blanton_SWB1_CONN15" + "Blanton_SWB1_CONN16" +) + +# --- Source margin.sh if not already loaded --- +_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +[ -z "$(type -t margin_init)" ] && source "$_SCRIPT_DIR/../margin.sh" + +# --- Iterate --- +for board in "${BOARDS[@]}"; do + margin_init "$board" || continue + margin_save + echo "" +done diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_status_all.sh b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_status_all.sh new file mode 100644 index 0000000..9434ff5 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/script/margin_status_all.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Run margin_status across every Blanton LTC2980 listed in BOARDS. +# Edit BOARDS to include / exclude / reorder which .conf files to iterate. +# Usage: +# source script/margin_status_all.sh + +# --- Edit this list --- +BOARDS=( + "Blanton_CB_CONN13" + "Blanton_SWB0_CONN13" + "Blanton_SWB0_CONN14" + "Blanton_SWB0_CONN15" + "Blanton_SWB0_CONN16" + "Blanton_SWB1_CONN13" + "Blanton_SWB1_CONN14" + "Blanton_SWB1_CONN15" + "Blanton_SWB1_CONN16" +) + +# --- Source margin.sh if not already loaded --- +_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +[ -z "$(type -t margin_init)" ] && source "$_SCRIPT_DIR/../margin.sh" + +# --- Iterate --- +for board in "${BOARDS[@]}"; do + margin_init "$board" || continue + margin_status + echo "" +done diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_CB_CONN13.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_CB_CONN13.conf new file mode 100644 index 0000000..478d899 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_CB_CONN13.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- Transport (blank = i2c): CB's LTC2980 is on the native I2C bus, driven by +# i2cset/i2cget. Only SWB boards set TRANSPORT="swb" + CB_I2C_CH=<6|7|8|9>. --- +TRANSPORT="" +CB_I2C_CH= + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: CB (CONN13) + "4:0x5C" # CH0 ~ CH7 + "4:0x5E" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # CB CONN13 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # CB CONN13 (lo) +) + +# ============================================================ +# chip1: CB (CONN13) +# ============================================================ +CH0_VNOM="5.0"; CH0_NET="V5P0_ALW" +CH1_VNOM="3.3"; CH1_NET="V3P3_ALW" +CH2_VNOM="0.75"; CH2_NET="PWR_VDD_MISC_ALW" +CH3_VNOM="1.8"; CH3_NET="V1P8_ALW" +CH4_VNOM="1.1"; CH4_NET="PWR_APU_VDDIO_SUS" +CH5_VNOM="0.75"; CH5_NET="PWR_VDD_MISC_RUN" +CH6_VNOM="0.78"; CH6_NET="PWR_APU_VDD_MEM_RUN" +CH7_VNOM="0.8"; CH7_NET="V0P8_PHY2_DVDD" +CH8_VNOM="0.8"; CH8_NET="V0P8_AVDD" +CH9_VNOM="0.8"; CH9_NET="V0P8_PHY" +CH10_VNOM="1.8"; CH10_NET="V1P8_FPGA" +CH11_VNOM="2.5"; CH11_NET="V2P5_FPGA" +CH12_VNOM="1.1"; CH12_NET="V1P1_FPGA" +CH13_VNOM="5.0"; CH13_NET="P5V_STBY" +CH14_VNOM="3.3"; CH14_NET="P3V3_STBY" +CH15_VNOM="0.8"; CH15_NET="V0P8_PHY2_AVDD" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN13.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN13.conf new file mode 100644 index 0000000..2f8665d --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN13.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- SWB transport (added): this LTC2980 sits behind the CB FPGA F3 I2C; reach +# it with cb_pmbus, not i2cset. CB_I2C_CH = FPGA I2C channel for this CONN. --- +TRANSPORT="swb" +CB_I2C_CH=6 + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: SWB0 (CONN13) + "0:0x5C" # CH0 ~ CH7 + "0:0x5E" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # SWB0 CONN13 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # SWB0 CONN13 (lo) +) + +# ============================================================ +# chip1: SWB0 (CONN13) +# ============================================================ +CH0_VNOM="0.75"; CH0_NET="P0V75_DVDD_47" +CH1_VNOM="0.75"; CH1_NET="P0V75_AVDD_47" +CH2_VNOM="1.5"; CH2_NET="P1V5_AVDD_47" +CH3_VNOM="0.9"; CH3_NET="P0V9_AVDD_47" +CH4_VNOM="1.8"; CH4_NET="P1V8_1" +CH5_VNOM="3.3"; CH5_NET="PVDD3_3V_SYNTH_LDO_A3" +CH6_VNOM="3.3"; CH6_NET="PVDD3_3V_SYNTH_LDO_B1" +CH7_VNOM="1.8"; CH7_NET="P1V8_3" +CH8_VNOM="1.8"; CH8_NET="P1V8_DVDDIO_3" +CH9_VNOM="0.75"; CH9_NET="P0V75_DVDD_39" +CH10_VNOM="0.75"; CH10_NET="P0V75_AVDD_39" +CH11_VNOM="1.5"; CH11_NET="P1V5_AVDD_39" +CH12_VNOM="0.9"; CH12_NET="P0V9_AVDD_39" +CH13_VNOM="1.5"; CH13_NET="PVDD1V5_2" +CH14_VNOM="1.8"; CH14_NET="PVDD1V8_DUT" +CH15_VNOM="1.2"; CH15_NET="PVDD_MDIO" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN14.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN14.conf new file mode 100644 index 0000000..77b9545 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN14.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- SWB transport (added): this LTC2980 sits behind the CB FPGA F3 I2C; reach +# it with cb_pmbus, not i2cset. CB_I2C_CH = FPGA I2C channel for this CONN. --- +TRANSPORT="swb" +CB_I2C_CH=8 + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: SWB0 (CONN14) + "0:0x5E" # CH0 ~ CH7 + "0:0x5F" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # SWB0 CONN14 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # SWB0 CONN14 (lo) +) + +# ============================================================ +# chip1: SWB0 (CONN14) +# ============================================================ +CH0_VNOM="0.75"; CH0_NET="P0V75_AVDD_7" +CH1_VNOM="1.5"; CH1_NET="P1V5_AVDD_7" +CH2_VNOM="0.9"; CH2_NET="P0V9_AVDD_7" +CH3_VNOM="1.8"; CH3_NET="P1V8_5" +CH4_VNOM="1.8"; CH4_NET="P1V8_2" +CH5_VNOM="3.3"; CH5_NET="PVDD3_3V_SYNTH_LDO_B2" +CH6_VNOM="3.3"; CH6_NET="PVDD3_3V_SYNTH_LDO_A2" +CH7_VNOM="3.3"; CH7_NET="PVDD3_3V_SYNTH_LDO_A1" +CH8_VNOM="1.5"; CH8_NET="PVDD1V5_TSC" +CH9_VNOM="1.5"; CH9_NET="PVDD1V5_ANLG" +CH10_VNOM="-"; CH10_NET="NC" +CH11_VNOM="-"; CH11_NET="NC" +CH12_VNOM="1.5"; CH12_NET="PVDD1V5_1" +CH13_VNOM="-"; CH13_NET="NC" +CH14_VNOM="1.8"; CH14_NET="P1V8_DVDDIO_1" +CH15_VNOM="0.75"; CH15_NET="P0V75_DVDD_7" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN15.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN15.conf new file mode 100644 index 0000000..256e2e2 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN15.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- SWB transport (added): this LTC2980 sits behind the CB FPGA F3 I2C; reach +# it with cb_pmbus, not i2cset. CB_I2C_CH = FPGA I2C channel for this CONN. --- +TRANSPORT="swb" +CB_I2C_CH=6 + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: SWB0 (CONN15) + "0:0x62" # CH0 ~ CH7 + "0:0x63" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # SWB0 CONN15 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # SWB0 CONN15 (lo) +) + +# ============================================================ +# chip1: SWB0 (CONN15) +# ============================================================ +CH0_VNOM="1.5"; CH0_NET="P1V5_AVDD_55" +CH1_VNOM="0.9"; CH1_NET="P0V9_AVDD_55" +CH2_VNOM="0.75"; CH2_NET="P0V75_DVDD_63" +CH3_VNOM="0.75"; CH3_NET="P0V75_AVDD_63" +CH4_VNOM="1.5"; CH4_NET="P1V5_AVDD_63" +CH5_VNOM="0.9"; CH5_NET="P0V9_AVDD_63" +CH6_VNOM="3.3"; CH6_NET="PVDD3_3V_SYNTH_LDO_B3" +CH7_VNOM="1.5"; CH7_NET="PVDD1V5_3" +CH8_VNOM="0.85"; CH8_NET="P0V85_STBY" +CH9_VNOM="1.8"; CH9_NET="P1V8_STBY" +CH10_VNOM="-"; CH10_NET="NC" +CH11_VNOM="3.3"; CH11_NET="P3V3_STBY" +CH12_VNOM="0.9"; CH12_NET="PVDD0V9_2" +CH13_VNOM="0.75"; CH13_NET="P0V75_DVDD_55" +CH14_VNOM="0.75"; CH14_NET="P0V75_AVDD_55" +CH15_VNOM="1.8"; CH15_NET="P1V8_DVDDIO_4" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN16.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN16.conf new file mode 100644 index 0000000..09c6da5 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB0_CONN16.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- SWB transport (added): this LTC2980 sits behind the CB FPGA F3 I2C; reach +# it with cb_pmbus, not i2cset. CB_I2C_CH = FPGA I2C channel for this CONN. --- +TRANSPORT="swb" +CB_I2C_CH=8 + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: SWB0 (CONN16) + "0:0x64" # CH0 ~ CH7 + "0:0x65" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # SWB0 CONN16 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # SWB0 CONN16 (lo) +) + +# ============================================================ +# chip1: SWB0 (CONN16) +# ============================================================ +CH0_VNOM="1.5"; CH0_NET="PVDD1V5_0" +CH1_VNOM="1.8"; CH1_NET="P1V8_4" +CH2_VNOM="3.3"; CH2_NET="PVDD3_3V_SYNTH_LDO_B5" +CH3_VNOM="3.3"; CH3_NET="PVDD3_3V_SYNTH_LDO_A5" +CH4_VNOM="3.3"; CH4_NET="PVDD3_3V_SYNTH_LDO_B4" +CH5_VNOM="3.3"; CH5_NET="PVDD3_3V_SYNTH_LDO_A4" +CH6_VNOM="3.3"; CH6_NET="P3V3" +CH7_VNOM="0.8"; CH7_NET="PVDD0_8V_T3" +CH8_VNOM="0.75"; CH8_NET="P0V75_DVDD_1" +CH9_VNOM="0.75"; CH9_NET="P0V75_AVDD_1" +CH10_VNOM="1.5"; CH10_NET="P1V5_AVDD_1" +CH11_VNOM="0.9"; CH11_NET="P0V9_AVDD_1" +CH12_VNOM="0.9"; CH12_NET="PVDD0V9_0" +CH13_VNOM="0.9"; CH13_NET="PVDD0V9_1" +CH14_VNOM="0.9"; CH14_NET="PVDD0V9_3" +CH15_VNOM="1.2"; CH15_NET="PVDD1V2_T3" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN13.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN13.conf new file mode 100644 index 0000000..c414909 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN13.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- SWB transport (added): this LTC2980 sits behind the CB FPGA F3 I2C; reach +# it with cb_pmbus, not i2cset. CB_I2C_CH = FPGA I2C channel for this CONN. --- +TRANSPORT="swb" +CB_I2C_CH=7 + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: SWB1 (CONN13) + "1:0x5C" # CH0 ~ CH7 + "1:0x5D" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # SWB1 CONN13 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # SWB1 CONN13 (lo) +) + +# ============================================================ +# chip1: SWB1 (CONN13) +# ============================================================ +CH0_VNOM="0.75"; CH0_NET="P0V75_DVDD_47" +CH1_VNOM="0.75"; CH1_NET="P0V75_AVDD_47" +CH2_VNOM="1.5"; CH2_NET="P1V5_AVDD_47" +CH3_VNOM="0.9"; CH3_NET="P0V9_AVDD_47" +CH4_VNOM="1.8"; CH4_NET="P1V8_1" +CH5_VNOM="3.3"; CH5_NET="PVDD3_3V_SYNTH_LDO_A3" +CH6_VNOM="3.3"; CH6_NET="PVDD3_3V_SYNTH_LDO_B1" +CH7_VNOM="1.8"; CH7_NET="P1V8_3" +CH8_VNOM="1.8"; CH8_NET="P1V8_DVDDIO_3" +CH9_VNOM="0.75"; CH9_NET="P0V75_DVDD_39" +CH10_VNOM="0.75"; CH10_NET="P0V75_AVDD_39" +CH11_VNOM="1.5"; CH11_NET="P1V5_AVDD_39" +CH12_VNOM="0.9"; CH12_NET="P0V9_AVDD_39" +CH13_VNOM="1.5"; CH13_NET="PVDD1V5_2" +CH14_VNOM="1.8"; CH14_NET="PVDD1V8_DUT" +CH15_VNOM="1.2"; CH15_NET="PVDD_MDIO" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN14.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN14.conf new file mode 100644 index 0000000..b85fdc4 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN14.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- SWB transport (added): this LTC2980 sits behind the CB FPGA F3 I2C; reach +# it with cb_pmbus, not i2cset. CB_I2C_CH = FPGA I2C channel for this CONN. --- +TRANSPORT="swb" +CB_I2C_CH=9 + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: SWB1 (CONN14) + "1:0x5E" # CH0 ~ CH7 + "1:0x5F" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # SWB1 CONN14 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # SWB1 CONN14 (lo) +) + +# ============================================================ +# chip1: SWB1 (CONN14) +# ============================================================ +CH0_VNOM="0.75"; CH0_NET="P0V75_AVDD_7" +CH1_VNOM="1.5"; CH1_NET="P1V5_AVDD_7" +CH2_VNOM="0.9"; CH2_NET="P0V9_AVDD_7" +CH3_VNOM="1.8"; CH3_NET="P1V8_5" +CH4_VNOM="1.8"; CH4_NET="P1V8_2" +CH5_VNOM="3.3"; CH5_NET="PVDD3_3V_SYNTH_LDO_B2" +CH6_VNOM="3.3"; CH6_NET="PVDD3_3V_SYNTH_LDO_A2" +CH7_VNOM="3.3"; CH7_NET="PVDD3_3V_SYNTH_LDO_A1" +CH8_VNOM="1.5"; CH8_NET="PVDD1V5_TSC" +CH9_VNOM="1.5"; CH9_NET="PVDD1V5_ANLG" +CH10_VNOM="-"; CH10_NET="NC" +CH11_VNOM="-"; CH11_NET="NC" +CH12_VNOM="1.5"; CH12_NET="PVDD1V5_1" +CH13_VNOM="-"; CH13_NET="NC" +CH14_VNOM="1.8"; CH14_NET="P1V8_DVDDIO_1" +CH15_VNOM="0.75"; CH15_NET="P0V75_DVDD_7" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN15.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN15.conf new file mode 100644 index 0000000..97eef1b --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN15.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- SWB transport (added): this LTC2980 sits behind the CB FPGA F3 I2C; reach +# it with cb_pmbus, not i2cset. CB_I2C_CH = FPGA I2C channel for this CONN. --- +TRANSPORT="swb" +CB_I2C_CH=7 + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: SWB1 (CONN15) + "1:0x62" # CH0 ~ CH7 + "1:0x63" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # SWB1 CONN15 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # SWB1 CONN15 (lo) +) + +# ============================================================ +# chip1: SWB1 (CONN15) +# ============================================================ +CH0_VNOM="1.5"; CH0_NET="P1V5_AVDD_55" +CH1_VNOM="0.9"; CH1_NET="P0V9_AVDD_55" +CH2_VNOM="0.75"; CH2_NET="P0V75_DVDD_63" +CH3_VNOM="0.75"; CH3_NET="P0V75_AVDD_63" +CH4_VNOM="1.5"; CH4_NET="P1V5_AVDD_63" +CH5_VNOM="0.9"; CH5_NET="P0V9_AVDD_63" +CH6_VNOM="3.3"; CH6_NET="PVDD3_3V_SYNTH_LDO_B3" +CH7_VNOM="1.5"; CH7_NET="PVDD1V5_3" +CH8_VNOM="0.85"; CH8_NET="P0V85_STBY" +CH9_VNOM="1.8"; CH9_NET="P1V8_STBY" +CH10_VNOM="-"; CH10_NET="NC" +CH11_VNOM="3.3"; CH11_NET="P3V3_STBY" +CH12_VNOM="0.9"; CH12_NET="PVDD0V9_2" +CH13_VNOM="0.75"; CH13_NET="P0V75_DVDD_55" +CH14_VNOM="0.75"; CH14_NET="P0V75_AVDD_55" +CH15_VNOM="1.8"; CH15_NET="P1V8_DVDDIO_4" diff --git a/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN16.conf b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN16.conf new file mode 100644 index 0000000..a620a77 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/LTC2980_Margin_Script/settings/Blanton_SWB1_CONN16.conf @@ -0,0 +1,52 @@ +# Blanton Channel Settings +# Format: CH_VNOM=voltage CH_NET=net_name +# +# Channel numbering (Script Channel, per Blanton_Margin_List): +# ch_global / 8 -> CHIPS index (0~17) +# ch_global % 8 -> page within LTC2977 (0~7) +# One LTC2980 = two LTC2977 (8ch each), controlled via 2 I2C addresses. + +# --- SWB transport (added): this LTC2980 sits behind the CB FPGA F3 I2C; reach +# it with cb_pmbus, not i2cset. CB_I2C_CH = FPGA I2C channel for this CONN. --- +TRANSPORT="swb" +CB_I2C_CH=9 + +# --- I2C Configuration --- + +# Format: "bus:address" (8 channels per entry / per LTC2977) +CHIPS=( + # chip1: SWB1 (CONN16) + "1:0x64" # CH0 ~ CH7 + "1:0x65" # CH8 ~ CH15 +) + +# Pre-commands to run before accessing each chip (empty = none) +# Multiple commands separated by ; +CHIP_PRE_CMD=( + "" # SWB1 CONN16 (lo) +) + +# Post-commands to run after accessing each chip (optional, empty = none) +CHIP_POST_CMD=( + "" # SWB1 CONN16 (lo) +) + +# ============================================================ +# chip1: SWB1 (CONN16) +# ============================================================ +CH0_VNOM="1.5"; CH0_NET="PVDD1V5_0" +CH1_VNOM="1.8"; CH1_NET="P1V8_4" +CH2_VNOM="3.3"; CH2_NET="PVDD3_3V_SYNTH_LDO_B5" +CH3_VNOM="3.3"; CH3_NET="PVDD3_3V_SYNTH_LDO_A5" +CH4_VNOM="3.3"; CH4_NET="PVDD3_3V_SYNTH_LDO_B4" +CH5_VNOM="3.3"; CH5_NET="PVDD3_3V_SYNTH_LDO_A4" +CH6_VNOM="3.3"; CH6_NET="P3V3" +CH7_VNOM="0.8"; CH7_NET="PVDD0_8V_T3" +CH8_VNOM="0.75"; CH8_NET="P0V75_DVDD_1" +CH9_VNOM="0.75"; CH9_NET="P0V75_AVDD_1" +CH10_VNOM="1.5"; CH10_NET="P1V5_AVDD_1" +CH11_VNOM="0.9"; CH11_NET="P0V9_AVDD_1" +CH12_VNOM="0.9"; CH12_NET="PVDD0V9_0" +CH13_VNOM="0.9"; CH13_NET="PVDD0V9_1" +CH14_VNOM="0.9"; CH14_NET="PVDD0V9_3" +CH15_VNOM="1.2"; CH15_NET="PVDD1V2_T3" diff --git a/src/Script_ABC_Blanton/Blanton_Script/blanton_cb_i2c.sh b/src/Script_ABC_Blanton/Blanton_Script/blanton_cb_i2c.sh new file mode 100644 index 0000000..c4e5d0f --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/blanton_cb_i2c.sh @@ -0,0 +1,444 @@ +#!/usr/bin/env bash +# ============================================================================= +# blanton_cb_i2c.sh -- CB FPGA (F3) I2C / PMBus over the OpenCores I2C master +# ============================================================================= +# Version History: +# V0.1.0 2026-06-16 CB sibling of blanton_icb_i2c.sh. Same OpenCores I2C +# handshake, but the I2C block lives in CB FPGA *Function 3* +# register space (base 0x300, stride 0x20, Ch0..Ch17), and +# is reached via cb_fpga 3 (direct PCIe BAR -> .3/resource0). +# ============================================================================= +# +# IMPORTANT (vs the hand-written cb_fpga.md pcimem commands): +# * The CB I2C channels are on PCI **Function 3**, so the sysfs file is +# .../0000:02:00.3/resource0 (NOT .0). cb_fpga 3 uses FUNCT3_RES for this. +# * This tool uses **Repeated START** for reads (write reg pointer with WR only, +# no STOP, then Sr + slave|R) so it works for the SMBus/PMBus parts (VRM, +# EFUSE) as well as plain register parts. STOP+START only works for the latter. +# * Slave addresses are 7-bit here. The spec lists 8-bit pairs (e.g. MAX31790 +# "0x40/0x41" -> 7-bit 0x20; TCA9546 "0xE8/0xE9" -> 7-bit 0x74). Divide by 2. +# +# CB FPGA F3 I2C channels (base 0x300, stride 0x20) -- 7-bit addrs in (...): +# Ch0 0x300 SWB_0: TCA9546 mux (0x74), M0.C0 temp sensor, ... +# Ch1 0x320 SWB_1: TCA9546 mux (0x74), ... +# Ch2 0x340 SWB_0: SWB_FPGA (0x40), IO Exp PCA9555 (0x24), ... +# Ch3 0x360 SWB_1: SWB_FPGA (0x40), PCA9555 (0x24), ... +# Ch4 0x380 SWB_0: M1 TCA9546 mux (0x74), Clk Gen SI5..., ... +# Ch5 0x3A0 SWB_1: M1 TCA9546 mux (0x74), ... +# Ch6 0x3C0 SWB_0: VRM M29816 (0x20), VRM M2985B (0x21), ... [PMBus] +# Ch7 0x3E0 SWB_1: VRM M29816 (0x20), VRM M2985B (0x21), ... [PMBus] +# Ch8 0x400 SWB_0: VRM M2985B (0x25), M2985B (0x26), ... [PMBus] +# Ch9 0x420 SWB_1: VRM M2985B (0x25), M2985B (0x26), ... [PMBus] +# Ch10 0x440 M0 TCA9543 mux (0x70), M0.C0 Clk Buf 9DBL0452, ... +# Ch11 0x460 Fan Ctrl MAX31790 (0x20) +# Ch12 0x480 ADC leakage ADC128D818 (0x1F) +# Ch13 0x4A0 NFC SM-MFAD4-C02 (0x28) +# Ch14 0x4C0 M1 TCA9543 mux (0x70), M1.C0 QSFP28.P1 xcvr, ... +# Ch15 0x4E0 Fan1/2 EFUSE STEF48H28 (0x10/0x11), ... [PMBus-ish] +# Ch16 0x500 1G PHY I210 Ethernet ctrlr (0x49) +# Ch17 0x520 Chassis EEPROM (0x28..0x29), Diag EEPROM (0x2B), ... +# (slave 7-bit addrs derived from the 8-bit pairs in the register map; verify +# against the device datasheet / your board before driving writes.) +# +# Per-channel register layout (offset from channel base): +# +0x00 I2C_PRSCL_LO +0x04 I2C_PRSCL_HI +0x08 I2C_CTRL (bit7 MOD_EN) +# +0x0C I2C_TX(W)/I2C_RX(R) +0x10 I2C_CMD(W)/I2C_STAT(R) +# +0x14 I2C_MUX_SEL +0x18 I2C_RST (0xD) +0x1C SEM +# CMD : STA=0x80 STO=0x40 RD=0x20 WR=0x10 ACK=0x08(1=NACK) IACK=0x01 +# STAT: RX_ACK=0x80(1=NACK) BUSY=0x40 ARB_LOST=0x20 TIP=0x02 INT_FLAG=0x01 +# Prescale = (in_clk/(5*scl))-1 @75MHz: 0x88=100kHz, 0x24=400kHz +# +# Usage: +# source blanton_fpga_pcimem.sh # provides cb_fpga / fpga_debug +# source blanton_cb_i2c.sh +# cb_i2c_init 11 # Ch11 (Fan Ctrl) @100kHz +# cb_i2c_scan 11 +# cb_i2c_read 11 0x20 0x01 1 # MAX31790 (7-bit 0x20) reg 0x01 +# cb_pmbus_read 6 0x20 0x8B 2 # Ch6 VRM READ_VOUT +# ============================================================================= + +# --- Pull in the register-access backend (cb_fpga) if not present ----------- +if ! declare -F cb_fpga >/dev/null 2>&1; then + _CBI2C_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" + if [ -n "$_CBI2C_DIR" ] && [ -f "$_CBI2C_DIR/blanton_fpga_pcimem.sh" ]; then + # shellcheck source=/dev/null + source "$_CBI2C_DIR/blanton_fpga_pcimem.sh" + else + echo -e "[\033[33mWARN\033[0m] blanton_cb_i2c.sh: cb_fpga() not found." >&2 + echo " source blanton_fpga_pcimem.sh first (provides cb_fpga)." >&2 + fi +fi + +# === CB I2C geometry ========================================================= +CBI2C_FN=3 # CB PCI Function hosting the I2C block +CBI2C_BASE=0x300 # channel 0 base offset (relative to F3 resource0) +CBI2C_CH_STRIDE=0x20 +CBI2C_CH_MAX=17 + +# Per-channel register offsets +_CBI2C_PRSCL_LO=0x00 +_CBI2C_PRSCL_HI=0x04 +_CBI2C_CTRL=0x08 +_CBI2C_TX=0x0C +_CBI2C_RX=0x0C +_CBI2C_CMD=0x10 +_CBI2C_STAT=0x10 +_CBI2C_MUX_SEL=0x14 +_CBI2C_RST=0x18 +_CBI2C_SEM=0x1C + +# I2C_CTRL_REG / CMD / STAT bits +_CBI2C_EN=0x80 +_CBI2C_STA=0x80 +_CBI2C_STO=0x40 +_CBI2C_RD=0x20 +_CBI2C_WR=0x10 +_CBI2C_NACK=0x08 +_CBI2C_RXACK=0x80 +_CBI2C_TIP=0x02 +_CBI2C_RST_VAL=0xD + +# Defaults +CB_I2C_PRESCALE_LO="${CB_I2C_PRESCALE_LO:-0x88}" # 100 kHz @ 75 MHz +CB_I2C_PRESCALE_HI="${CB_I2C_PRESCALE_HI:-0x00}" +CB_I2C_AUTO_INIT="${CB_I2C_AUTO_INIT:-1}" +CB_I2C_TIP_POLL_MAX="${CB_I2C_TIP_POLL_MAX:-100}" + +# --- External I2C-mux RESET control (verified on COM34, 2026-06-16) ---------- +# The TCA9543 muxes on CH10 (M0) and CH14 (M1) have an FPGA-driven, active-low +# RESET line. On power-up / FPGA reload the FPGA holds them in reset, so 0x70 +# does NOT ACK on the root bus and all downstream legs are unreachable. +# +# The control is a GLOBAL register in CB FPGA *Function 0*, offset 0x7D4 +# (I2C_MUX_RST_REG) -- NOT the per-channel I2C_MUX_SEL_REG (+0x14) which is a +# device-select and does nothing to the RESET pin. Per bit: 1 = release, +# 0 = hold-in-reset. Observed default 0xDD (bit1=CH10 mux, bit5=CH14 mux held). +# Writing 0xFF releases all external muxes (normal operating state). This value +# is volatile and is lost on the next power cycle / FPGA reload. +CBI2C_MUX_RST_FN="${CBI2C_MUX_RST_FN:-0}" +CBI2C_MUX_RST_OFF="${CBI2C_MUX_RST_OFF:-0x7D4}" + +# Channels whose root bus carries an external mux that hangs off the RESET reg. +# CH10/CH14 = TCA9543; CH0/1/4/5 = TCA9546 (SWB/M1) per the channel map above. +CBI2C_MUX_CHANNELS="${CBI2C_MUX_CHANNELS:-0 1 4 5 10 14}" + +# Auto-release external mux RESET before scanning / mux-writing a mux channel. +CB_I2C_AUTO_MUX_RST="${CB_I2C_AUTO_MUX_RST:-1}" + +# --- Single FPGA register read/write via cb_fpga [data] ---------- +# _cbi2c_reg [data] data present = write, absent = read (echo hex) +_cbi2c_reg() { + local off="$1" data="${2:-}" + if [ -n "$data" ]; then cb_fpga "$CBI2C_FN" "$off" "$data"; else cb_fpga "$CBI2C_FN" "$off"; fi +} + +# Channel base absolute offset +_cbi2c_chan_base() { + local ch="$1" + if (( ch < 0 || ch > CBI2C_CH_MAX )); then + echo "blanton_cb_i2c: ch must be 0..$CBI2C_CH_MAX" >&2; return 1 + fi + printf '0x%X' $(( CBI2C_BASE + ch * CBI2C_CH_STRIDE )) +} + +# Normalize a register read-back to a number string ("0x...." -> 0x....) +_cbi2c_num() { local v="$1"; [[ "$v" =~ (0[xX][0-9a-fA-F]+) ]] && echo "${BASH_REMATCH[1]}" || echo "0"; } + +# Write CMD then poll STAT (same offset) until TIP clears; echo final status hex +_cbi2c_cmd_wait() { + local cmd_off="$1" cmd_val="$2" i status + _cbi2c_reg "$cmd_off" "$cmd_val" >/dev/null + for (( i=0; i&2 + printf '0x%X' "${status:-0}"; return 1 +} + +# Check RX_ACK in status (bit7). 0 = ACK, 1 = NACK -> return 1 +_cbi2c_check_ack() { + local status; status=$(_cbi2c_num "$1") + (( (status & _CBI2C_RXACK) != 0 )) && return 1 || return 0 +} + +# === Public: init / reset / semaphore / mux-sel ============================= + +# cb_i2c_init [prescale_lo] [prescale_hi] +cb_i2c_init() { + [[ $# -lt 1 ]] && { echo "Usage: cb_i2c_init [prescale_lo] [prescale_hi]"; return 1; } + local ch="$1" lo="${2:-$CB_I2C_PRESCALE_LO}" hi="${3:-$CB_I2C_PRESCALE_HI}" base + base=$(_cbi2c_chan_base "$ch") || return 1 + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_CTRL)))" 0x00 >/dev/null # disable + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_PRSCL_LO)))" "$lo" >/dev/null + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_PRSCL_HI)))" "$hi" >/dev/null + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_CTRL)))" "$_CBI2C_EN" >/dev/null # enable + return 0 +} + +# cb_i2c_reset +cb_i2c_reset() { + [[ $# -lt 1 ]] && { echo "Usage: cb_i2c_reset "; return 1; } + local ch="$1" base; base=$(_cbi2c_chan_base "$ch") || return 1 + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_RST)))" "$_CBI2C_RST_VAL" >/dev/null + echo " [RST] ch=$ch local I2C controller reset (0xD)" +} + +# cb_i2c_sem [status|acquire [val]|release] +cb_i2c_sem() { + [[ $# -lt 1 ]] && { echo "Usage: cb_i2c_sem [status|acquire [val]|release]"; return 1; } + local ch="$1" act="${2:-status}" base off cur + base=$(_cbi2c_chan_base "$ch") || return 1 + off=$(printf '0x%X' $((base + _CBI2C_SEM))) + case "$act" in + status) + cur=$(_cbi2c_num "$(_cbi2c_reg "$off")") + (( (cur & 0xFF) == 0 )) && echo " [SEM] ch=$ch free (0x00)" \ + || printf ' [SEM] ch=%s held (0x%02X)\n' "$ch" $((cur & 0xFF)) ;; + acquire) + local val="${3:-0x01}" + cur=$(_cbi2c_num "$(_cbi2c_reg "$off")") + if (( (cur & 0xFF) != 0 )); then + printf ' [SEM] ch=%s already held (0x%02X) -- not acquired\n' "$ch" $((cur & 0xFF)); return 1 + fi + _cbi2c_reg "$off" "$val" >/dev/null + cur=$(_cbi2c_num "$(_cbi2c_reg "$off")") + (( (cur & 0xFF) != 0 )) && printf ' [SEM] ch=%s acquired (0x%02X)\n' "$ch" $((cur & 0xFF)) \ + || { echo " [SEM] ch=$ch acquire failed"; return 1; } ;; + release) + _cbi2c_reg "$off" 0x00 >/dev/null; echo " [SEM] ch=$ch released (0x00)" ;; + *) echo "Usage: cb_i2c_sem [status|acquire [val]|release]"; return 1 ;; + esac +} + +# cb_i2c_muxsel -- write I2C_MUX_SEL_REG (FPGA drives ext mux pins) +cb_i2c_muxsel() { + [[ $# -lt 2 ]] && { echo "Usage: cb_i2c_muxsel "; return 1; } + local ch="$1" sel="$2" base; base=$(_cbi2c_chan_base "$ch") || return 1 + _cbi2c_reg "$(printf '0x%X' $((base + _CBI2C_MUX_SEL)))" "$sel" >/dev/null + printf ' [MUXSEL] ch=%s DEV_SEL <= 0x%02X\n' "$ch" $((sel & 0xFF)) +} + +# cb_i2c_mux_reset_release -- de-assert ALL external mux RESET lines (F0 0x7D4 <= 0xFF) +# Global, not per-channel. Volatile: lost on power cycle / FPGA reload. +cb_i2c_mux_reset_release() { + cb_fpga "$CBI2C_MUX_RST_FN" "$CBI2C_MUX_RST_OFF" 0xFF >/dev/null + local rb; rb=$(_cbi2c_num "$(cb_fpga "$CBI2C_MUX_RST_FN" "$CBI2C_MUX_RST_OFF")") + printf ' [MUX-RST] I2C_MUX_RST_REG (F%s %s) <= 0xFF (all external muxes released, readback %s)\n' \ + "$CBI2C_MUX_RST_FN" "$CBI2C_MUX_RST_OFF" "$rb" +} + +# _cbi2c_is_mux_channel -- 0 (true) if ch is in CBI2C_MUX_CHANNELS +_cbi2c_is_mux_channel() { + local ch="$1" c + for c in $CBI2C_MUX_CHANNELS; do [[ "$c" == "$ch" ]] && return 0; done + return 1 +} + +# _cbi2c_auto_mux_rst -- release external mux RESET if ch is a mux channel +_cbi2c_auto_mux_rst() { + [[ "$CB_I2C_AUTO_MUX_RST" == "1" ]] || return 0 + _cbi2c_is_mux_channel "$1" || return 0 + cb_i2c_mux_reset_release +} + +# === Core transfers (Repeated START, SMBus/PMBus compatible) ================= + +# _cbi2c_xfer_read echoes space-separated hex bytes +_cbi2c_xfer_read() { + local ch="$1" slave="$2" reg="$3" n="$4" base tx cmd rx status i last cmdv val out="" + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + rx=$(printf '0x%X' $((base + _CBI2C_RX))) + [[ "$CB_I2C_AUTO_INIT" == "1" ]] && cb_i2c_init "$ch" >/dev/null + + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (slave << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on slave addr (W) 0x$(printf %02X "$slave")" >&2; return 1; } + + _cbi2c_reg "$tx" "$(printf '0x%X' $((reg & 0xFF)))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_WR)))") # WR only, no STOP + _cbi2c_check_ack "$status" || { echo "ERR: NACK on reg 0x$(printf %02X "$reg")" >&2; return 1; } + + _cbi2c_reg "$tx" "$(printf '0x%X' $(( ((slave << 1) | 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") # Repeated START + _cbi2c_check_ack "$status" || { echo "ERR: NACK on slave addr (R) 0x$(printf %02X "$slave")" >&2; return 1; } + + for (( i=0; i/dev/null + val=$(_cbi2c_num "$(_cbi2c_reg "$rx")") + out+="$(printf '0x%02X ' $((val & 0xFF)))" + done + echo "${out% }" +} + +# _cbi2c_xfer_write [byte...] +_cbi2c_xfer_write() { + local ch="$1" slave="$2" reg="$3"; shift 3 + local base tx cmd status b last cmdv n=$# idx=0 + [[ $n -lt 1 ]] && { echo "ERR: no data bytes" >&2; return 1; } + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + [[ "$CB_I2C_AUTO_INIT" == "1" ]] && cb_i2c_init "$ch" >/dev/null + + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (slave << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on slave addr (W) 0x$(printf %02X "$slave")" >&2; return 1; } + + _cbi2c_reg "$tx" "$(printf '0x%X' $((reg & 0xFF)))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on reg 0x$(printf %02X "$reg")" >&2; return 1; } + + for b in "$@"; do + idx=$((idx+1)); last=$(( idx == n )) + _cbi2c_reg "$tx" "$(printf '0x%X' $(( $((b)) & 0xFF )))" >/dev/null + if (( last )); then cmdv=$(( _CBI2C_WR | _CBI2C_STO )); else cmdv=$(( _CBI2C_WR )); fi + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' "$cmdv")") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on data byte #$idx" >&2; return 1; } + done + return 0 +} + +# _cbi2c_xfer_cmd_only -- START+W, cmd byte, STOP (no data) +_cbi2c_xfer_cmd_only() { + local ch="$1" slave="$2" cc="$3" base tx cmd status + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + [[ "$CB_I2C_AUTO_INIT" == "1" ]] && cb_i2c_init "$ch" >/dev/null + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (slave << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on slave addr (W) 0x$(printf %02X "$slave")" >&2; return 1; } + _cbi2c_reg "$tx" "$(printf '0x%X' $((cc & 0xFF)))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_WR | _CBI2C_STO)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on cmd 0x$(printf %02X "$cc")" >&2; return 1; } + return 0 +} + +# === Public: generic I2C ===================================================== + +# cb_i2c_read [nbytes] +cb_i2c_read() { + [[ $# -lt 3 ]] && { echo "Usage: cb_i2c_read [nbytes]"; return 1; } + local ch="$1" slave=$(( $2 )) reg=$(( $3 )) n="${4:-1}" bytes + bytes=$(_cbi2c_xfer_read "$ch" "$slave" "$reg" "$n") || return 1 + printf ' [I2C-R] ch=%s slave=0x%02X reg=0x%02X => [%s]\n' "$ch" "$slave" "$reg" "$bytes" +} + +# cb_i2c_write [byte...] +cb_i2c_write() { + [[ $# -lt 4 ]] && { echo "Usage: cb_i2c_write [byte...]"; return 1; } + local ch="$1" slave=$(( $2 )) reg=$(( $3 )); shift 3 + _cbi2c_xfer_write "$ch" "$slave" "$reg" "$@" || return 1 + printf ' [I2C-W] ch=%s slave=0x%02X reg=0x%02X <= [%s]\n' "$ch" "$slave" "$reg" "$*" +} + +# cb_i2c_muxwrite -- raw 1-byte write, no reg (TCA954x) +cb_i2c_muxwrite() { + [[ $# -lt 3 ]] && { echo "Usage: cb_i2c_muxwrite "; return 1; } + local ch="$1" slave=$(( $2 )) val=$(( $3 )) base tx cmd status + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + [[ "$CB_I2C_AUTO_INIT" == "1" ]] && cb_i2c_init "$ch" >/dev/null + _cbi2c_auto_mux_rst "$ch" + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (slave << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on mux addr 0x$(printf %02X "$slave")" >&2; return 1; } + _cbi2c_reg "$tx" "$(printf '0x%X' $((val & 0xFF)))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_WR | _CBI2C_STO)))") + _cbi2c_check_ack "$status" || { echo "ERR: NACK on mux ctrl byte" >&2; return 1; } + printf ' [MUX-W] ch=%s mux=0x%02X <= 0x%02X\n' "$ch" "$slave" "$val" +} + +# cb_i2c_scan -- probe 0x08..0x77, report slaves that ACK +cb_i2c_scan() { + [[ $# -lt 1 ]] && { echo "Usage: cb_i2c_scan "; return 1; } + local ch="$1" base tx cmd a status found="" + base=$(_cbi2c_chan_base "$ch") || return 1 + tx=$(printf '0x%X' $((base + _CBI2C_TX))) + cmd=$(printf '0x%X' $((base + _CBI2C_CMD))) + cb_i2c_init "$ch" >/dev/null + _cbi2c_auto_mux_rst "$ch" + for (( a=0x08; a<=0x77; a++ )); do + _cbi2c_reg "$tx" "$(printf '0x%X' $(( (a << 1) & 0xFF )))" >/dev/null + status=$(_cbi2c_cmd_wait "$cmd" "$(printf '0x%X' $((_CBI2C_STA | _CBI2C_WR | _CBI2C_STO)))") + _cbi2c_check_ack "$status" && found+="$(printf '0x%02X ' "$a")" + done + [[ -n "$found" ]] && echo " [SCAN] ch=$ch found: ${found% }" || echo " [SCAN] ch=$ch no devices" +} + +# === Public: PMBus (== SMBus; command code + Repeated START read) ============ + +# cb_pmbus_read [nbytes] (default 2 bytes, LSB first) +cb_pmbus_read() { + [[ $# -lt 3 ]] && { echo "Usage: cb_pmbus_read [nbytes]"; return 1; } + local ch="$1" slave=$(( $2 )) cc=$(( $3 )) n="${4:-2}" bytes + bytes=$(_cbi2c_xfer_read "$ch" "$slave" "$cc" "$n") || return 1 + if [[ "$n" == "2" ]]; then + local b0 b1 word; b0=$(( $(echo "$bytes" | awk '{print $1}') )); b1=$(( $(echo "$bytes" | awk '{print $2}') )) + word=$(( b0 | (b1 << 8) )) + printf ' [PMB-R] ch=%s slave=0x%02X cmd=0x%02X => 0x%04X raw=[%s] linear16=%s\n' \ + "$ch" "$slave" "$cc" "$word" "$bytes" "$(cb_pmbus_linear16 "$word")" + else + printf ' [PMB-R] ch=%s slave=0x%02X cmd=0x%02X => [%s]\n' "$ch" "$slave" "$cc" "$bytes" + fi +} + +# cb_pmbus_write [data byte...] (no byte = send-byte) +cb_pmbus_write() { + [[ $# -lt 3 ]] && { echo "Usage: cb_pmbus_write [data byte...]"; return 1; } + local ch="$1" slave=$(( $2 )) cc=$(( $3 )); shift 3 + if [[ $# -eq 0 ]]; then + _cbi2c_xfer_cmd_only "$ch" "$slave" "$cc" || return 1 + printf ' [PMB-W] ch=%s slave=0x%02X cmd=0x%02X <= (send-byte)\n' "$ch" "$slave" "$cc"; return 0 + fi + _cbi2c_xfer_write "$ch" "$slave" "$cc" "$@" || return 1 + printf ' [PMB-W] ch=%s slave=0x%02X cmd=0x%02X <= [%s]\n' "$ch" "$slave" "$cc" "$*" +} + +# cb_pmbus_linear16 +cb_pmbus_linear16() { + local word=$(( $1 & 0xFFFF )) + awk -v w="$word" 'BEGIN{ + e=int(w/2048)%32; if(e>15)e-=32; + m=w%2048; if(m>1023)m-=2048; + printf "%.4f", m * (2.0 ^ e); + }' +} + +# === Help ==================================================================== +blanton_cb_i2c_help() { + echo -e "\033[1mblanton_cb_i2c.sh - CB FPGA (F3) I2C / PMBus over OpenCores I2C master\033[0m" + echo "" + echo -e " Backend: \033[36mcb_fpga $CBI2C_FN\033[0m (direct PCIe BAR -> .3/resource0), base 0x300, Ch0..$CBI2C_CH_MAX" + echo "" + echo -e "\033[1mSetup\033[0m" + echo -e " \033[33mcb_i2c_init\033[0m [pre_lo] [pre_hi] prescale + enable (def 0x88/0x00 = 100kHz)" + echo -e " \033[33mcb_i2c_reset\033[0m LCL_RST=0xD" + echo -e " \033[33mcb_i2c_sem\033[0m [status|acquire [v]|release]" + echo -e " \033[33mcb_i2c_muxsel\033[0m write I2C_MUX_SEL_REG" + echo -e " \033[33mcb_i2c_mux_reset_release\033[0m de-assert ALL ext mux RESET (F0 0x7D4<=0xFF)" + echo "" + echo -e "\033[1mGeneric I2C\033[0m" + echo -e " \033[33mcb_i2c_scan\033[0m " + echo -e " \033[33mcb_i2c_read\033[0m [nbytes]" + echo -e " \033[33mcb_i2c_write\033[0m [byte...]" + echo -e " \033[33mcb_i2c_muxwrite\033[0m raw 1-byte (TCA954x)" + echo "" + echo -e "\033[1mPMBus / SMBus\033[0m" + echo -e " \033[33mcb_pmbus_read\033[0m [nbytes] (def 2, LE word + linear16)" + echo -e " \033[33mcb_pmbus_write\033[0m [byte...]" + echo -e " \033[33mcb_pmbus_linear16\033[0m " + echo "" + echo -e " Slave = 7-bit (tool shifts). Spec lists 8-bit pairs -> divide by 2." + echo -e " \033[33mfpga_debug on\033[0m to see every underlying pcimem command." +} + +blanton_cb_i2c_help diff --git a/src/Script_ABC_Blanton/Blanton_Script/blanton_fpga_pcimem.sh b/src/Script_ABC_Blanton/Blanton_Script/blanton_fpga_pcimem.sh new file mode 100644 index 0000000..12d8d77 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/blanton_fpga_pcimem.sh @@ -0,0 +1,277 @@ +#!/usr/bin/env bash +# ============================================================================= +# blanton_fpga_pcimem.sh -- pcimem backend, sysfs resource file + relative offset +# ============================================================================= +# Version History: +# V1.3.0 2026-06-12 pcimem variant (SONiC hardware). memtool variant: blanton_fpga_memtool.sh +# Version number kept in sync with blanton_fpga_memtool.sh +# V1.4.0 2026-06-15 Fix: VSPI window bases pointed at the VSPI-Flash block +# (0x340/0x380/0x3C0/0x400, config-flash channel) so register +# reads returned 0; corrected to the VSPI register block +# (PMC 0x640 / ICB 0x680 / SWB0 0x6C0 / SWB1 0x700) +# Add: _vspi_fnwarn guard - warns when PMC/ICB/SWB are called with +# cb_fpga-style " " (a read turning into a write) +# Change: suppress pcimem write stdout noise (mmap/Written lines) +# Docs: comments/help translated to English (ASCII-only for SONiC console) +# V1.4.1 2026-06-23 Fix: BDF in example auto-detect was wrong (02:00 vs 04:00); corrected to match the lspci example. +# V1.4.2 2026-08-10 Change: FUNCT0..3_RES BDF updated 0000:04:00.x -> 0000:03:00.x (current unit's enumeration). +# V1.4.3 2026-08-12 Change: FUNCT0..3_RES BDF updated 0000:03:00.x -> 0000:05:00.x (current unit's enumeration). +# V1.4.4 2026-08-12 Change: FUNCT0..3_RES BDF back to 0000:03:00.x for the DUT on COM36. +# NOTE: this BDF is per-unit. Check with +# lspci -Dnn | grep -i fpga or +# ls -d /sys/bus/pci/devices/0000:*:00.3 +# and edit the four lines below if it differs. +# ============================================================================= +# +# SONiC hardware has no memtool / devmem, but it has pcimem. pcimem mmaps the PCI +# sysfs resource file directly and takes "resource file + offset relative to BAR +# start", not an absolute physical address. +# +# pcimem { sysfile } { offset } [ type*count [ data ] ] +# sysfile : sysfs file for the pci resource (e.g. .../resource0) +# offset : offset into pci memory region +# type : [b]yte, [h]alfword, [w]ord, [d]ouble-word +# *count : number of items (w*100 dump 100 words) +# data : data to be written +# +# This tool always accesses as word (w, 32-bit). +# +# After sourcing this file the following functions are available: +# cb_fpga [data] +# pmc_fpga [data] +# icb_fpga [data] +# swb0_fpga [data] +# swb1_fpga [data] +# +# data present = write, absent = read. +# Usage: source blanton_fpga_pcimem.sh + +# === CB FPGA PCIe resource file (sysfs) === +# Use lspci -D to find the BDF (domain:bus:dev.fn); resource0 is the sysfs mapping of BAR0. +# e.g. lspci -Dnn | grep -i fpga -> 0000:02:00.0 ... +# memtool variant fills in the BAR value; pcimem variant fills in the resource file +# path instead (offset becomes relative to BAR). +FUNCT0_RES=/sys/bus/pci/devices/0000:03:00.0/resource0 +FUNCT1_RES=/sys/bus/pci/devices/0000:03:00.1/resource0 +FUNCT2_RES=/sys/bus/pci/devices/0000:03:00.2/resource0 +FUNCT3_RES=/sys/bus/pci/devices/0000:03:00.3/resource0 + +# Auto-detect example (uncomment to use; needs the FPGA's BDF prefix): +# _BDF=0000:02:00 +# FUNCT0_RES=/sys/bus/pci/devices/${_BDF}.0/resource0 +# FUNCT1_RES=/sys/bus/pci/devices/${_BDF}.1/resource0 +# FUNCT2_RES=/sys/bus/pci/devices/${_BDF}.2/resource0 +# FUNCT3_RES=/sys/bus/pci/devices/${_BDF}.3/resource0 + +# === VSPI window base offset (relative to CB Function 2 resource0 start) === +# NOTE: CB.F2 has TWO near-identical VSPI register blocks (see spec register map): +# - VSPI-Flash-* @ 0x340/0x380/0x3C0/0x400 -> accesses the remote FPGA's CONFIG FLASH +# - VSPI-* @ 0x640/0x680/0x6C0/0x700 -> accesses the remote FPGA's REGISTERS +# This tool reads/writes remote registers, so it uses the VSPI-* block (0x640+). +# The VSPI-Flash bases are kept below (commented) in case flash access is needed later. +VSPI_PMC_BASE=0x640 +VSPI_ICB_BASE=0x680 +VSPI_SWB0_BASE=0x6C0 +VSPI_SWB1_BASE=0x700 + +# VSPI-Flash window bases (config-flash access, not register access): +# VSPI_FLASH_PMC_BASE=0x340 +# VSPI_FLASH_ICB_BASE=0x380 +# VSPI_FLASH_SWB0_BASE=0x3C0 +# VSPI_FLASH_SWB1_BASE=0x400 + +# === VSPI protocol constants === +_VSPI_CMD_STAT=0x00 +_VSPI_ADDR=0x04 +_VSPI_WR_DATA=0x08 +_VSPI_RD_DATA=0x0C +_VSPI_NEW_CMD=0x01 +_VSPI_READ_W=0x02 +_VSPI_WRITE_W=0x04 +_VSPI_READY_MASK=0x100 +_VSPI_POLL_MAX=200 + +# === pcimem command === +PCIMEM_CMD="${PCIMEM_CMD:-pcimem}" + +# === Debug mode (1=print commands AND execute, 0=execute only) === +DEBUG_MODE=${DEBUG_MODE:-0} + +fpga_debug() { + if [ "${1:-}" = "on" ]; then DEBUG_MODE=1 + elif [ "${1:-}" = "off" ]; then DEBUG_MODE=0 + else [ "$DEBUG_MODE" = "0" ] && DEBUG_MODE=1 || DEBUG_MODE=0; fi + echo -e "[\033[34mINFO\033[0m] DEBUG_MODE=$DEBUG_MODE" +} + +# Wrapper: debug mode prints command (to stderr) AND executes, normal mode executes only. +# On read, returns the parsed hex value (stripping pcimem's mmap noise). +# Usage: _pcimem [data] (data present = write, absent = read) +_pcimem() { + local sysfile="$1" offset="$2" data="${3:-}" + if [[ -n "$data" ]]; then + [ "$DEBUG_MODE" = "1" ] && \ + echo -e "\033[90m[DEBG] $PCIMEM_CMD $sysfile $offset w $data\033[0m" >&2 + # Write output (opened / Target offset / mmap / Written...readback) is never + # parsed -> drop stdout noise; keep stderr so real errors still surface. + $PCIMEM_CMD "$sysfile" "$offset" w "$data" >/dev/null + else + [ "$DEBUG_MODE" = "1" ] && \ + echo -e "\033[90m[DEBG] $PCIMEM_CMD $sysfile $offset w\033[0m" >&2 + # pcimem read prints mmap info + "Value at offset ...: 0xXXXX"; + # take the last 0x... token as the actual read-back value. + $PCIMEM_CMD "$sysfile" "$offset" w | grep -oiE '0x[0-9a-f]+' | tail -1 + fi +} + +# --- Internal VSPI helpers (all hang off CB Function 2's resource0) --- + +_vspi_read() { + local win_off="$1" remote_offset="$2" + local cmd_off add_off rd_off addr_val status i + + cmd_off=$(printf '0x%X' $(( win_off + _VSPI_CMD_STAT ))) + add_off=$(printf '0x%X' $(( win_off + _VSPI_ADDR ))) + rd_off=$(printf '0x%X' $(( win_off + _VSPI_RD_DATA ))) + addr_val=$(printf '0x%08X' $(( (0x0 << 20) | (remote_offset & 0xFFFFF) ))) + + _pcimem "$FUNCT2_RES" "$add_off" "$addr_val" + _pcimem "$FUNCT2_RES" "$cmd_off" $(printf '0x%X' $(( _VSPI_NEW_CMD | _VSPI_READ_W ))) + + for (( i=0; i<_VSPI_POLL_MAX; i++ )); do + status=$(_pcimem "$FUNCT2_RES" "$cmd_off") + if (( ( ${status:-0} & _VSPI_READY_MASK) != 0 )); then + _pcimem "$FUNCT2_RES" "$rd_off" + return 0 + fi + done + echo "ERROR: VSPI read timeout @ offset $remote_offset" >&2 + return 1 +} + +_vspi_write() { + local win_off="$1" remote_offset="$2" data="$3" + local cmd_off add_off wr_off addr_val status i + + cmd_off=$(printf '0x%X' $(( win_off + _VSPI_CMD_STAT ))) + add_off=$(printf '0x%X' $(( win_off + _VSPI_ADDR ))) + wr_off=$(printf '0x%X' $(( win_off + _VSPI_WR_DATA ))) + addr_val=$(printf '0x%08X' $(( (0x0 << 20) | (remote_offset & 0xFFFFF) ))) + + _pcimem "$FUNCT2_RES" "$wr_off" "$data" + _pcimem "$FUNCT2_RES" "$add_off" "$addr_val" + _pcimem "$FUNCT2_RES" "$cmd_off" $(printf '0x%X' $(( _VSPI_NEW_CMD | _VSPI_WRITE_W ))) + + for (( i=0; i<_VSPI_POLL_MAX; i++ )); do + status=$(_pcimem "$FUNCT2_RES" "$cmd_off") + if (( ( ${status:-0} & _VSPI_READY_MASK) != 0 )); then + return 0 + fi + done + echo "ERROR: VSPI write timeout @ offset $remote_offset" >&2 + return 1 +} + +# Guard: PMC/ICB/SWB are single-function; signature is [data], NO fn arg. +# Common pitfall: using cb_fpga's " " form -> 2nd arg becomes data, a read +# turns into a write. If addr is 0~3 (looks like fn) AND data is given, warn and +# confirm; on a non-tty (script) just warn, don't block. +# Usage: _vspi_fnwarn non-zero return = cancel +_vspi_fnwarn() { + local name="$1" addr="$2" data="$3" + [[ -z "$data" ]] && return 0 # read, nothing to warn + case "$addr" in + 0|1|2|3|0x0|0x1|0x2|0x3|0x00|0x01|0x02|0x03) ;; # looks like fn, warn below + *) return 0 ;; # normal offset, allow + esac + echo -e "[\033[33mWARN\033[0m] $name has no fn arg; signature is [data] (NOT cb_fpga's )." >&2 + echo -e " This will WRITE $data to PMC/ICB/SWB offset $addr." >&2 + echo -e " To READ offset $addr, pass a single arg: $name $addr" >&2 + if [ -t 0 ]; then + local ans + read -r -p " Proceed with write anyway? [y/N] " ans + case "$ans" in + y|Y|yes|YES) return 0 ;; + *) echo " Cancelled." >&2; return 1 ;; + esac + fi + return 0 +} + +# === Public functions === + +cb_fpga() { + if [[ $# -lt 2 ]]; then + echo "Usage: cb_fpga [data]"; return 1 + fi + local fn="$1" addr="$2" data="${3:-}" res + case "$fn" in + 0) res=$FUNCT0_RES ;; 1) res=$FUNCT1_RES ;; + 2) res=$FUNCT2_RES ;; 3) res=$FUNCT3_RES ;; + *) echo "cb_fpga: fn must be 0-3" >&2; return 1 ;; + esac + # pcimem offset is relative to BAR start; do not add BAR. + if [[ -z "$data" ]]; then + _pcimem "$res" "$addr" + else + _pcimem "$res" "$addr" "$data" + fi +} + +pmc_fpga() { + if [[ $# -lt 1 ]]; then + echo "Usage: pmc_fpga [data]"; return 1 + fi + local addr="$1" data="${2:-}" + _vspi_fnwarn pmc_fpga "$addr" "$data" || return 1 + if [[ -z "$data" ]]; then _vspi_read "$VSPI_PMC_BASE" "$addr" + else _vspi_write "$VSPI_PMC_BASE" "$addr" "$data"; fi +} + +icb_fpga() { + if [[ $# -lt 1 ]]; then + echo "Usage: icb_fpga [data]"; return 1 + fi + local addr="$1" data="${2:-}" + _vspi_fnwarn icb_fpga "$addr" "$data" || return 1 + if [[ -z "$data" ]]; then _vspi_read "$VSPI_ICB_BASE" "$addr" + else _vspi_write "$VSPI_ICB_BASE" "$addr" "$data"; fi +} + +swb0_fpga() { + if [[ $# -lt 1 ]]; then + echo "Usage: swb0_fpga [data]"; return 1 + fi + local addr="$1" data="${2:-}" + _vspi_fnwarn swb0_fpga "$addr" "$data" || return 1 + if [[ -z "$data" ]]; then _vspi_read "$VSPI_SWB0_BASE" "$addr" + else _vspi_write "$VSPI_SWB0_BASE" "$addr" "$data"; fi +} + +swb1_fpga() { + if [[ $# -lt 1 ]]; then + echo "Usage: swb1_fpga [data]"; return 1 + fi + local addr="$1" data="${2:-}" + _vspi_fnwarn swb1_fpga "$addr" "$data" || return 1 + if [[ -z "$data" ]]; then _vspi_read "$VSPI_SWB1_BASE" "$addr" + else _vspi_write "$VSPI_SWB1_BASE" "$addr" "$data"; fi +} + +blanton_fpga_help() { + echo -e "\033[1mblanton_fpga (pcimem) - FPGA Register Access Tool\033[0m" + echo "" + echo -e "\033[1mUsage:\033[0m" + echo -e " \033[33mcb_fpga\033[0m [data] CB FPGA direct (sysfs resource0)" + echo -e " \033[33mpmc_fpga\033[0m [data] PMC FPGA via VSPI" + echo -e " \033[33micb_fpga\033[0m [data] ICB FPGA via VSPI" + echo -e " \033[33mswb0_fpga\033[0m [data] SWB0 FPGA via VSPI" + echo -e " \033[33mswb1_fpga\033[0m [data] SWB1 FPGA via VSPI" + echo -e " \033[33mfpga_debug\033[0m on|off Toggle debug mode (print commands and execute)" + echo "" + echo -e " Omit [data] to \033[32mread\033[0m, provide [data] to \033[31mwrite\033[0m." + echo -e " Backend: \033[36mpcimem\033[0m (sysfs resource file + relative offset)." + echo -e " Run \033[33mblanton_fpga_help\033[0m to show this message again." +} + +blanton_fpga_help diff --git a/src/Script_ABC_Blanton/Blanton_Script/blanton_icb_vi2c.sh b/src/Script_ABC_Blanton/Blanton_Script/blanton_icb_vi2c.sh new file mode 100644 index 0000000..b36a17e --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/blanton_icb_vi2c.sh @@ -0,0 +1,167 @@ +#!/usr/bin/env bash +# ===================================================================== +# blanton_icb_vi2c.sh V0.1.0 2026-08-10 +# ICB (PDB) I2C through the CB FPGA **VI2C** proxy blocks in CB PCI +# Function 3. Direct BAR access (cb_fpga 3 ) - NO VSPI bridge, so +# this is ~1 pcimem call per register instead of 3+, i.e. much faster +# than blanton_icb_i2c.sh which walks CB F2's VSPI-ICB window. +# +# CB F3 VI2C-ICB channels (stride 0x20), per the FPGA register map: +# Ch0 0x780 VI2C_DEV_ID 0x21 PDB Fan Controller +# Ch1 0x7A0 VI2C_DEV_ID 0x23 PDB EEPROM (FRU) +# Ch2 0x7C0 VI2C_DEV_ID 0x25 PDB external temp sensors +# Ch3 0x7E0 VI2C_DEV_ID 0x27 Hotswap controller [PMBus] +# Ch4 0x800 VI2C_DEV_ID 0x29 Power bricks + EFUSE [PMBus] +# These are the SAME physical buses as ICB I2C Ch0..Ch4 (ICB 0xE00+), +# so a scan here must match blanton_icb_i2c.sh's scan. +# +# Why use this instead of blanton_icb_i2c.sh for data access (DUT 2026-08-10): +# VSPI access is ~18 ms/register -> ~50 ms between I2C byte phases, which +# trips the SMBus 25-35 ms timeout on the Ch2/Ch3/Ch4 devices (they NACK +# the register pointer). CB F3 VI2C is ~3.3 ms/register and stays inside +# the timeout, so all 5 channels are fully usable here. +# Measured: full 5-channel scan 9.4 s here vs 34.0 s over VSPI. +# +# Per-ch: +00 PRSCL_LO +04 PRSCL_HI +08 CTRL(b7 MOD_EN) +# +0C TX/RX +10 CMD/STAT +14 MUX_SEL +18 RST(0xD) +# +1C RSVD <-- VI2C has NO SEM_REG (unlike the native I2C blocks) +# CMD : STA=0x80 STO=0x40 RD=0x20 WR=0x10 ACK=0x08(1=NACK) INT_ACK=0x01 +# STAT: RX_ACK=0x80(1=NACK) BUSY=0x40 ARB_LOST=0x20 TIP=0x02 INT_FLAG=0x01 +# Slave addrs are 7-bit (spec quotes 8-bit pairs -> divide by 2). +# Usage: source blanton_fpga_pcimem.sh ; source blanton_icb_vi2c.sh +# vi2c_scan_all +# ===================================================================== +if ! declare -F cb_fpga >/dev/null 2>&1; then + _VD="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" + [ -f "$_VD/blanton_fpga_pcimem.sh" ] && . "$_VD/blanton_fpga_pcimem.sh" +fi +VI2C_FN=3; VI2C_BASE=0x780; VI2C_STRIDE=0x20; VI2C_CH_MAX=4 +V_EN=0x80; V_STA=0x80; V_STO=0x40; V_RD=0x20; V_WR=0x10; V_NAK=0x08 +V_RXACK=0x80; V_TIP=0x02 +VI2C_PRE_LO=${VI2C_PRE_LO:-0x88}; VI2C_PRE_HI=${VI2C_PRE_HI:-0x00} +VI2C_POLL=${VI2C_POLL:-50} +VI2C_SCAN_FROM=${VI2C_SCAN_FROM:-0x08}; VI2C_SCAN_TO=${VI2C_SCAN_TO:-0x77} +VI2C_CH_DESC=("Fan Controller" "EEPROM/FRU" "Temp sensors" \ + "Hotswap ctrlr" "Power bricks+EFUSE") +VI2C_DEV_ID=(0x21 0x23 0x25 0x27 0x29) + +# --- low level (direct CB F3 BAR access) ---------------------------- +_vr(){ if [ -n "${2:-}" ]; then cb_fpga $VI2C_FN "$1" "$2"; else cb_fpga $VI2C_FN "$1"; fi; } +_vnum(){ [[ "$1" =~ (0[xX][0-9a-fA-F]+) ]] && echo "${BASH_REMATCH[1]}" || echo 0; } +_vbase(){ local c=$1 + if (( c<0 || c>VI2C_CH_MAX )); then echo "ch must be 0..$VI2C_CH_MAX" >&2; return 1; fi + printf '0x%X' $(( VI2C_BASE + c*VI2C_STRIDE )); } +_vwait(){ local o=$1 v=$2 i s + _vr "$o" "$v" >/dev/null + for ((i=0;i&2; printf '0x%X' "${s:-0}"; return 1; } +_vack(){ local s; s=$(_vnum "$1"); (( (s & V_RXACK)!=0 )) && return 1 || return 0; } + +vi2c_init(){ local c=$1 b + b=$(_vbase "$c") || return 1 + _vr $(printf '0x%X' $((b+0x08))) 0x00 >/dev/null + _vr $(printf '0x%X' $((b+0x00))) "${2:-$VI2C_PRE_LO}" >/dev/null + _vr $(printf '0x%X' $((b+0x04))) "${3:-$VI2C_PRE_HI}" >/dev/null + _vr $(printf '0x%X' $((b+0x08))) $V_EN >/dev/null; } +vi2c_reset(){ local c=$1 b; b=$(_vbase "$c") || return 1 + _vr $(printf '0x%X' $((b+0x18))) 0xD >/dev/null; echo " [RST] vi2c ch$c LCL_RST=0xD"; } +vi2c_muxsel(){ local c=$1 b; b=$(_vbase "$c") || return 1 + _vr $(printf '0x%X' $((b+0x14))) "$2" >/dev/null + printf ' [MUXSEL] vi2c ch%s DEV_SEL <= %s\n' "$c" "$2"; } +vi2c_dump(){ [ $# -lt 1 ] && { echo "Usage: vi2c_dump "; return 1; } + local c=$1 b o nm i + b=$(_vbase "$c") || return 1 + nm=(PRSCL_LO PRSCL_HI CTRL RX STAT MUX_SEL RST RSVD); i=0 + printf ' [REGS] vi2c ch%s base=%s (CB F%s)\n' "$c" "$b" "$VI2C_FN" + for o in 0x00 0x04 0x08 0x0C 0x10 0x14 0x18 0x1C; do + printf ' +%s %-9s = %s\n' "$o" "${nm[$i]}" "$(_vnum "$(_vr $(printf '0x%X' $((b+o))))")" + i=$((i+1)) + done; } + +# --- transfers (Repeated START, SMBus/PMBus safe) ------------------- +_vrd(){ local c=$1 s=$2 r=$3 n=$4 b tx cm i st v out="" + b=$(_vbase "$c") || return 1 + tx=$(printf '0x%X' $((b+0x0C))); cm=$(printf '0x%X' $((b+0x10))) + vi2c_init "$c" + _vr $tx $(printf '0x%X' $(( (s<<1) & 0xFF ))) >/dev/null + st=$(_vwait $cm $(printf '0x%X' $((V_STA|V_WR)))); _vack "$st" || { echo "NACK slave-W 0x$(printf %02X $s)" >&2; return 1; } + _vr $tx $(printf '0x%X' $((r & 0xFF))) >/dev/null + st=$(_vwait $cm $(printf '0x%X' $((V_WR)))); _vack "$st" || { echo "NACK reg 0x$(printf %02X $r)" >&2; return 1; } + _vr $tx $(printf '0x%X' $(( ((s<<1)|1) & 0xFF ))) >/dev/null + st=$(_vwait $cm $(printf '0x%X' $((V_STA|V_WR)))); _vack "$st" || { echo "NACK slave-R 0x$(printf %02X $s)" >&2; return 1; } + for ((i=0;i/dev/null + else _vwait $cm $(printf '0x%X' $((V_RD))) >/dev/null; fi + v=$(_vnum "$(_vr $tx)"); out+="$(printf '0x%02X ' $((v & 0xFF)))" + done + echo "${out% }"; } +_vwr(){ local c=$1 s=$2 r=$3; shift 3 + local b tx cm st x n=$# k=0 cv + (( n<1 )) && { echo "no data bytes" >&2; return 1; } + b=$(_vbase "$c") || return 1 + tx=$(printf '0x%X' $((b+0x0C))); cm=$(printf '0x%X' $((b+0x10))) + vi2c_init "$c" + _vr $tx $(printf '0x%X' $(( (s<<1) & 0xFF ))) >/dev/null + st=$(_vwait $cm $(printf '0x%X' $((V_STA|V_WR)))); _vack "$st" || { echo "NACK slave-W" >&2; return 1; } + _vr $tx $(printf '0x%X' $((r & 0xFF))) >/dev/null + st=$(_vwait $cm $(printf '0x%X' $((V_WR)))); _vack "$st" || { echo "NACK reg" >&2; return 1; } + for x in "$@"; do k=$((k+1)) + _vr $tx $(printf '0x%X' $(( $((x)) & 0xFF ))) >/dev/null + if (( k==n )); then cv=$((V_WR|V_STO)); else cv=$((V_WR)); fi + st=$(_vwait $cm $(printf '0x%X' $cv)); _vack "$st" || { echo "NACK data#$k" >&2; return 1; } + done; } + +# --- public --------------------------------------------------------- +vi2c_read(){ [ $# -lt 3 ] && { echo "Usage: vi2c_read [n]"; return 1; } + local o; o=$(_vrd "$1" $(( $2 )) $(( $3 )) "${4:-1}") || return 1 + printf ' [VI2C-R] ch%s slave=0x%02X reg=0x%02X => [%s]\n' "$1" $(( $2 )) $(( $3 )) "$o"; } +vi2c_write(){ [ $# -lt 4 ] && { echo "Usage: vi2c_write ..."; return 1; } + local c=$1 s=$(( $2 )) r=$(( $3 )); shift 3 + _vwr "$c" "$s" "$r" "$@" || return 1 + printf ' [VI2C-W] ch%s slave=0x%02X reg=0x%02X <= [%s]\n' "$c" "$s" "$r" "$*"; } +vi2c_pmbus_read(){ [ $# -lt 3 ] && { echo "Usage: vi2c_pmbus_read [n]"; return 1; } + local o n=${4:-2}; o=$(_vrd "$1" $(( $2 )) $(( $3 )) "$n") || return 1 + if [ "$n" = 2 ]; then local b0 b1 w + b0=$(( $(echo "$o" | awk '{print $1}') )); b1=$(( $(echo "$o" | awk '{print $2}') )) + w=$(( b0 | (b1<<8) )) + printf ' [VPMB-R] ch%s slave=0x%02X cmd=0x%02X => 0x%04X raw=[%s] lin16=%s\n' \ + "$1" $(( $2 )) $(( $3 )) "$w" "$o" "$(vi2c_lin16 $w)" + else printf ' [VPMB-R] ch%s slave=0x%02X cmd=0x%02X => [%s]\n' "$1" $(( $2 )) $(( $3 )) "$o"; fi; } +vi2c_lin16(){ awk -v w=$(( $1 & 0xFFFF )) 'BEGIN{e=int(w/2048)%32;if(e>15)e-=32;m=w%2048;if(m>1023)m-=2048;printf "%.4f",m*(2.0^e)}'; } + +# --- scan ----------------------------------------------------------- +vi2c_scan(){ [ $# -lt 1 ] && { echo "Usage: vi2c_scan "; return 1; } + local c=$1 b tx cm a st f="" + b=$(_vbase "$c") || return 1 + tx=$(printf '0x%X' $((b+0x0C))); cm=$(printf '0x%X' $((b+0x10))) + vi2c_init "$c" + for (( a=$((VI2C_SCAN_FROM)); a<=$((VI2C_SCAN_TO)); a++ )); do + _vr $tx $(printf '0x%X' $(( (a<<1) & 0xFF ))) >/dev/null + st=$(_vwait $cm $(printf '0x%X' $((V_STA|V_WR|V_STO)))) || continue + _vack "$st" && f+="$(printf '0x%02X ' $a)" + done + printf ' Ch%-2s %-20s : %s\n' "$c" "${VI2C_CH_DESC[$c]}" "${f:-(none)}"; } +vi2c_scan_all(){ local c list="$*" + [ -z "$list" ] && list="0 1 2 3 4" + echo "=== ICB VI2C scan via CB F$VI2C_FN direct BAR, base $VI2C_BASE ===" + printf ' range 0x%02X..0x%02X (7-bit), prescale %s/%s\n' \ + $((VI2C_SCAN_FROM)) $((VI2C_SCAN_TO)) "$VI2C_PRE_LO" "$VI2C_PRE_HI" + for c in $list; do vi2c_scan "$c"; done; } +vi2c_help(){ + echo "blanton_icb_vi2c.sh - ICB(PDB) I2C via CB F$VI2C_FN VI2C proxy (direct BAR, no VSPI)" + local i + for i in 0 1 2 3 4; do + printf ' Ch%-2s 0x%X DEV_ID %s %s\n' $i $((VI2C_BASE+i*VI2C_STRIDE)) "${VI2C_DEV_ID[$i]}" "${VI2C_CH_DESC[$i]}" + done + echo " vi2c_scan_all [ch...] scan all VI2C-ICB channels" + echo " vi2c_scan vi2c_dump " + echo " vi2c_init [pre_lo] [pre_hi] vi2c_reset " + echo " vi2c_read [n]" + echo " vi2c_write ..." + echo " vi2c_pmbus_read [n] vi2c_lin16 " + echo " vi2c_muxsel (VI2C has no SEM_REG)" + echo " env: VI2C_SCAN_FROM VI2C_SCAN_TO VI2C_PRE_LO VI2C_PRE_HI VI2C_POLL" + echo " Same buses as blanton_icb_i2c.sh Ch0..Ch4 - scans should match."; } +vi2c_help diff --git a/src/Script_ABC_Blanton/Blanton_Script/blanton_pwr_data.sh b/src/Script_ABC_Blanton/Blanton_Script/blanton_pwr_data.sh new file mode 100644 index 0000000..b12019d --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/blanton_pwr_data.sh @@ -0,0 +1,653 @@ +#!/usr/bin/env bash +# ============================================================================= +# blanton_pwr_data.sh -- SWB VRM rail monitor (Vin / Vout / Iout / Temp) +# ============================================================================= +# Version History: +# V1.0.0 2026-08-12 Initial. Reads every SWB VRM rail over the CB FPGA F3 +# I2C master (blanton_cb_i2c.sh) and prints an aligned +# table. Rail map + conversions from PWR_Data.xlsx. +# +# Two xlsx conversions were CORRECTED after measuring the +# real parts on COM39 (see _pwr_vout_* below): +# * MP2985B Vout: xlsx said "(data + 49) / 1mV". The +# "+49" offset is wrong -- it is plain 1mV/LSB. Proof: +# PVDD_0V75_ANLG_0 read 750 (0.750V) and PVDD1V5_CNDR0 +# read 1501 (1.501V), which match their net names +# exactly with no offset (+49 would give 0.799/1.550). +# * MP29816 Vout: xlsx said "/5mV". The LSB is not fixed +# -- it is selected by MFR_VOUT_SCALE_LOOP (0x29) +# bits[12:10]. This unit reads 0x0820 -> code 2 -> +# 2.5mV/LSB, so READ_VOUT 314 = 0.785V (VOUT_COMMAND +# 320 = 0.800V nominal). 5mV would give 1.57V. The +# resolution is now read from the chip at runtime. +# * xlsx Vin "divide by 32,33,34...49" is an Excel +# autofill artifact; the divisor is 32 (31.25mV/LSB) +# for every part. +# V1.1.0 2026-08-12 Add: "pwr_data pdb" - PDB power bricks + EFUSE, reached +# over ICB VI2C ch4 behind the 0x72 mux, channel 0 +# (blanton_icb_vi2c.sh backend, CB F3 direct BAR). +# Add: ARB_LOST-aware retry on the VI2C path. On the first +# DUT (COM39) ICB ch4 lost arbitration on every other +# transaction for any 7-bit addr >= 0x40, and vi2c_scan +# reported those failures as devices because it only tests +# RX_ACK and ignores ARB_LOST (STAT bit5). A true-ACK scan +# showed ch4 really had only 0x1A and 0x26 - the 0x72 mux +# never ACKed, so 0x60..0x63 were unreachable. Suspected +# board issue, so the PDB table here is written to spec and +# is NOT yet verified against working bricks. +# Change: missing-value placeholder is now "NA" everywhere. +# Add: PDB values are rejected as NA when the word reads +# 0xFFFF (floating bus, not data) or falls outside a +# plausibility window. Without this the broken ch4 bus +# printed Vin=12124160 V and Vout=65.5350 V, which look +# like readings; a wrong number is worse than NA. Limits +# are PDB_VIN_MAX / PDB_VOUT_MAX / PDB_IOUT_ABS_MAX / +# PDB_TEMP_MIN / PDB_TEMP_MAX, and PDB_REJECT_FFFF=0 +# disables the all-ones check. +# !! PDB CONVERSIONS ARE UNVERIFIED !! PWR_Data.xlsx has no PDB sheet and no +# brick responded on the first DUT, so the PDB rows use generic PMBus +# decoding (SLINEAR11 for Vin/Iout/Temp, LINEAR16 with the exponent taken +# from VOUT_MODE for Vout, direct format falls back to 1mV/LSB). Once a +# brick answers, run "pwr_pdb_id" to get MFR_ID/MFR_MODEL and check the +# numbers against the datasheet before trusting them. +# V1.2.0 2026-08-12 Verified against working bricks on the COM36 DUT, where the +# 0x72 mux DOES respond and 0x60..0x63 answer. Findings: +# * VOUT_MODE = 0x40 (direct) -> Vout is 1 mV/LSB, giving +# 1.212..1.220 V, consistent with the "I2C_PDB_VRM" net +# name on that mux leg. Vout is now trusted. +# * READ_VIN (0x88) is NOT a real input reading: it tracks +# READ_VOUT within 1 LSB per device (0x60 1217/1218, +# 0x61 1219/1220, 0x62 1212/1212, 0x63 1217/1217) and does +# not read alike across bricks sharing one input rail. +# Reported NA unless PDB_TRUST_VIN=1. +# * READ_TEMPERATURE_1 (0x8D), 0x8E and STATUS_BYTE (0x78) +# all return 0xFFFF and STATUS_WORD (0x79) = 0x0002 = CML +# fault, i.e. a partial command set. Temp is NA. +# * MFR_ID/MFR_MODEL return one byte then float (0x4D 'M', +# 0x59 'Y'), so they are not block reads here. +# Fix: presence is now a true-ACK probe and every value is read +# independently. Previously a failed Vin read aborted the whole +# row, so one unsupported register blanked Vout and Iout too. +# ============================================================================= +# +# Usage: +# source blanton_pwr_data.sh +# pwr_data # SWB0 (default) +# pwr_data swb1 # SWB1 (same map, I2C channel +1) +# pwr_data pdb # PDB power bricks + EFUSE (ICB VI2C ch4, mux 0x72 ch0) +# pwr_data all # all three +# pwr_pdb_id # read MFR_ID / MFR_MODEL of whatever answers on the PDB +# pwr_data_help +# +# Requires blanton_cb_i2c.sh + blanton_fpga_pcimem.sh in the same directory +# (auto-sourced below). "pwr_data pdb" additionally needs blanton_icb_vi2c.sh, +# which is sourced on demand. +# +# Register / conversion summary (PMBus, page written to 0x00 first): +# Vin 0x88 bits[9:0] * 31.25mV (page 0 -- Vin is the shared input) +# Vout 0x8B MP29816 : bits[11:0] * MFR_VOUT_SCALE_LOOP resolution +# MP2985B : bits[11:0] * 1mV +# Iout 0x8C SLINEAR11 (MP29816 lands on 2A/LSB, MP2985B on 0.0625A/LSB) +# Temp 0x8D MP29816 : SLINEAR11 ; MP2985B : bits[10:0] two's complement degC +# ============================================================================= + +# --- Pull in the I2C/PMBus backend if not already present -------------------- +_PWR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" +if ! declare -F cb_pmbus_read >/dev/null 2>&1; then + if [ -n "$_PWR_DIR" ] && [ -f "$_PWR_DIR/blanton_cb_i2c.sh" ]; then + # shellcheck source=/dev/null + source "$_PWR_DIR/blanton_cb_i2c.sh" >/dev/null + else + echo -e "[\033[33mWARN\033[0m] blanton_pwr_data.sh: cb_pmbus_read() not found." >&2 + echo " source blanton_cb_i2c.sh first." >&2 + fi +fi + +# === PMBus command codes ===================================================== +_PWR_PAGE=0x00 +_PWR_VIN=0x88 +_PWR_VOUT=0x8B +_PWR_IOUT=0x8C +_PWR_TEMP=0x8D +_PWR_MFR_VOUT_SCALE_LOOP=0x29 # MP29816 only: bits[12:10] = Vout LSB select + +# === Rail map (from PWR_Data.xlsx) =========================================== +# One entry per rail: "location:vrm:ch:slave:page:netname" +# ch = "I2C CH SWB0" column. SWB1 is the same map with ch+1 (7/9). +# page = value written to PMBus PAGE (0x00) before Vout/Iout/Temp. +# Vin is always read from page 0 (shared input rail). +PWR_RAILS=( + "PU2:MP29816:6:0x20:0x00:PVDD_CORE" + "PU105:MP2985B:6:0x21:0x00:PVDD_PHYTILE_P2" + "PU105:MP2985B:6:0x21:0x01:PVDD_PHYTILE_P3" + "PU102:MP2985B:6:0x22:0x00:PVDD_PHYTILE_P0" + "PU102:MP2985B:6:0x22:0x01:PVDD_PHYTILE_P1" + "PU114:MP2985B:6:0x25:0x00:PVDD_0V9_ANLG_0" + "PU114:MP2985B:6:0x25:0x01:PVDD_0V75_ANLG_0" + "PU122:MP2985B:6:0x27:0x00:PVDDA_PHYT0_P0" + "PU122:MP2985B:6:0x27:0x01:PVDDA_PHYT1_P1" + "PU142:MP2985B:6:0x29:0x00:PVDD1V5_CNDR0" + "PU142:MP2985B:6:0x29:0x01:PVDD1V5_CNDR1" + "PU108:MP2985B:8:0x23:0x00:PVDD_PHYTILE_P4" + "PU108:MP2985B:8:0x23:0x01:PVDD_PHYTILE_P5" + "PU111:MP2985B:8:0x24:0x00:PVDD_PHYTILE_P6" + "PU111:MP2985B:8:0x24:0x01:PVDD_PHYTILE_P7" + "PU118:MP2985B:8:0x26:0x00:PVDD_0V9_ANLG_1" + "PU118:MP2985B:8:0x26:0x01:PVDD_0V75_ANLG_1" + "PU127:MP2985B:8:0x28:0x00:PVDDA_PHYT2_P2" + "PU127:MP2985B:8:0x28:0x01:PVDDA_PHYT3_P3" +) + +# I2C channel offset per board: SWB0 uses the map as-is, SWB1 is +1. +_pwr_board_offset() { + case "$(echo "${1:-swb0}" | tr 'A-Z' 'a-z')" in + swb0|0) echo 0 ;; + swb1|1) echo 1 ;; + *) return 1 ;; + esac +} + +# === Missing-value placeholder ================================================ +PWR_NA="${PWR_NA:-NA}" + +# === PDB: power bricks + EFUSE =============================================== +# Path: CB F3 VI2C ch4 (== ICB I2C ch4, "Power bricks + EFUSE") -> external +# TCA954x mux at 7-bit 0x72 -> mux channel 0 -> the bricks. +# The VI2C path is used rather than the VSPI path (blanton_icb_i2c.sh) because +# VSPI costs ~18 ms per register, which puts ~50 ms between I2C byte phases and +# trips the 25-35 ms SMBus timeout on these PMBus parts. VI2C is ~3.3 ms. +PDB_VI2C_CH="${PDB_VI2C_CH:-4}" +PDB_MUX_ADDR="${PDB_MUX_ADDR:-0x72}" +PDB_MUX_SEL="${PDB_MUX_SEL:-0x01}" # TCA954x control byte: bit0 = channel 0 +PDB_RETRY="${PDB_RETRY:-3}" # retries per transfer (ARB_LOST recovery) + +# A floating I2C bus reads back all ones, so a 0xFFFF word is treated as "no +# data" instead of being decoded - otherwise it prints as a perfectly +# reasonable-looking 65.535 V / -0.5 A. Set 0 to decode it anyway. +PDB_REJECT_FFFF="${PDB_REJECT_FFFF:-1}" + +# The bricks alias READ_VIN (0x88) to the READ_VOUT measurement, so Vin is +# reported as NA by default rather than printing a wrong number. See the note in +# _pwr_read_pdb_rail for the measurement that shows this. Set to 1 to decode it. +PDB_TRUST_VIN="${PDB_TRUST_VIN:-0}" + +# Plausibility window; anything outside prints NA. Measured need: on the first +# DUT the contended ch4 bus produced words that decoded to 12124160 V, and a +# wrong number is worse than no number on a bring-up tool. +PDB_VIN_MAX="${PDB_VIN_MAX:-100}" +PDB_VOUT_MAX="${PDB_VOUT_MAX:-60}" +PDB_IOUT_ABS_MAX="${PDB_IOUT_ABS_MAX:-500}" +PDB_TEMP_MIN="${PDB_TEMP_MIN:--55}" +PDB_TEMP_MAX="${PDB_TEMP_MAX:-150}" + +# One entry per device: "location:model:slave:page:netname" +# page "-" = do not write PMBus PAGE (these are single-output parts) +PDB_RAILS=( + "PDB:BRICK:0x60:-:PDB_BRICK_0" + "PDB:BRICK:0x61:-:PDB_BRICK_1" + "PDB:BRICK:0x62:-:PDB_BRICK_2" + "PDB:BRICK:0x63:-:PDB_BRICK_3" + "PDB:EFUSE:0x26:-:PDB_EFUSE" +) + +_PWR_VI2C_ARBLOST=0x20 # VI2C STAT bit5 + +# === Debug =================================================================== +PWR_DEBUG=${PWR_DEBUG:-0} +pwr_debug() { + if [ "${1:-}" = "on" ]; then PWR_DEBUG=1 + elif [ "${1:-}" = "off" ]; then PWR_DEBUG=0 + else [ "$PWR_DEBUG" = "0" ] && PWR_DEBUG=1 || PWR_DEBUG=0; fi + echo -e "[\033[34mINFO\033[0m] PWR_DEBUG=$PWR_DEBUG" +} + +# === Low-level: read one 16-bit PMBus word, echo it as a decimal ============= +# _pwr_rd16 -> decimal word on stdout, non-zero on NACK +_pwr_rd16() { + local ch="$1" slave=$(( $2 )) reg="$3" bytes lo hi + bytes=$(_cbi2c_xfer_read "$ch" "$slave" "$(( $reg ))" 2 2>/dev/null) || return 1 + lo=$(printf '%s' "$bytes" | awk '{print $1}') + hi=$(printf '%s' "$bytes" | awk '{print $2}') + [ -z "$lo" ] || [ -z "$hi" ] && return 1 + local w=$(( ( $(( hi )) << 8 ) | $(( lo )) )) + [ "$PWR_DEBUG" = "1" ] && printf '\033[90m[DEBG] ch=%s slave=0x%02X reg=%s -> 0x%04X\033[0m\n' \ + "$ch" "$slave" "$reg" "$w" >&2 + echo "$w" +} + +# _pwr_set_page +_pwr_set_page() { + cb_pmbus_write "$1" "$2" "$_PWR_PAGE" "$3" >/dev/null 2>&1 +} + +# === Format decoders ========================================================= + +# SLINEAR11: bits[15:11] = signed exponent, bits[10:0] = signed mantissa +_pwr_l11() { + local w=$(( $1 & 0xFFFF )) + local e=$(( (w >> 11) & 0x1F )) + local m=$(( w & 0x7FF )) + (( e > 15 )) && e=$(( e - 32 )) + (( m > 1023 )) && m=$(( m - 2048 )) + awk -v m="$m" -v e="$e" 'BEGIN { printf "%.3f", m * (2.0 ^ e) }' +} + +# Signed 11-bit two's complement (bits[10:0]) -> integer +_pwr_s11() { + local m=$(( $1 & 0x7FF )) + (( m > 1023 )) && m=$(( m - 2048 )) + echo "$m" +} + +# Vin: bits[9:0] * 31.25mV (identical to xlsx "/32" and to "Linear11 *31.25mV") +_pwr_vin() { + awk -v c="$(( $1 & 0x3FF ))" 'BEGIN { printf "%.3f", c * 0.03125 }' +} + +# MP29816 Vout LSB (volts) from MFR_VOUT_SCALE_LOOP bits[12:10]. +# Cached per ch:slave so the table costs one extra read per MP29816, not per row. +declare -A _PWR_RES_CACHE 2>/dev/null +_pwr_mp29816_res() { + local ch="$1" slave="$2" key="$ch:$slave" w code + if [ -n "${_PWR_RES_CACHE[$key]}" ]; then echo "${_PWR_RES_CACHE[$key]}"; return 0; fi + w=$(_pwr_rd16 "$ch" "$slave" "$_PWR_MFR_VOUT_SCALE_LOOP") || return 1 + code=$(( (w >> 10) & 0x7 )) + local res + case "$code" in + 0) res=0.00625 ;; # 6.25 mV/LSB + 1) res=0.005 ;; # 5 mV/LSB + 2) res=0.0025 ;; # 2.5 mV/LSB + 3) res=0.002 ;; # 2 mV/LSB + 4) res=0.001 ;; # 1 mV/LSB + 5) res=0.00390625 ;; # 3.90625mV/LSB + 6) res=0.001953125 ;; # 1.953125 mV/LSB + 7) res=0.0009765625 ;; # 0.9765625 mV/LSB + *) return 1 ;; + esac + _PWR_RES_CACHE[$key]="$res" + echo "$res" +} + +# === Per-rail read =========================================================== +# Fills _PWR_VIN_V / _PWR_VOUT_V / _PWR_IOUT_A / _PWR_TEMP_C ("n/a" on failure) +_pwr_read_rail() { + local vrm="$1" ch="$2" slave="$3" page="$4" w res + _PWR_VIN_V="$PWR_NA"; _PWR_VOUT_V="$PWR_NA"; _PWR_IOUT_A="$PWR_NA"; _PWR_TEMP_C="$PWR_NA" + + # --- Vin: always page 0 (shared input rail) --- + _pwr_set_page "$ch" "$slave" 0x00 + if w=$(_pwr_rd16 "$ch" "$slave" "$_PWR_VIN"); then + _PWR_VIN_V=$(_pwr_vin "$w") + else + return 1 # slave did not ACK at all -> leave the whole row n/a + fi + + # --- Vout / Iout / Temp: on the rail's own page --- + _pwr_set_page "$ch" "$slave" "$page" + + if w=$(_pwr_rd16 "$ch" "$slave" "$_PWR_VOUT"); then + if [ "$vrm" = "MP29816" ]; then + res=$(_pwr_mp29816_res "$ch" "$slave") || res=0.0025 + _PWR_VOUT_V=$(awk -v c="$(( w & 0xFFF ))" -v r="$res" 'BEGIN { printf "%.4f", c * r }') + else + # MP2985B: direct, 1mV/LSB (no offset -- see header note) + _PWR_VOUT_V=$(awk -v c="$(( w & 0xFFF ))" 'BEGIN { printf "%.4f", c / 1000.0 }') + fi + fi + + w=$(_pwr_rd16 "$ch" "$slave" "$_PWR_IOUT") && _PWR_IOUT_A=$(_pwr_l11 "$w") + + if w=$(_pwr_rd16 "$ch" "$slave" "$_PWR_TEMP"); then + if [ "$vrm" = "MP29816" ]; then + _PWR_TEMP_C=$(printf '%.1f' "$(_pwr_l11 "$w")") + else + _PWR_TEMP_C=$(printf '%.1f' "$(_pwr_s11 "$w")") + fi + fi + return 0 +} + +# === PDB backend: ICB VI2C ch4, ARB_LOST-aware ================================ +# blanton_icb_vi2c.sh supplies _vbase/_vr/_vwait/_vnum/_vrd/_vwr/vi2c_init and +# the V_* bit constants. Sourced on demand so plain SWB use does not need it. +_pwr_vi2c_ready() { + declare -F vi2c_init >/dev/null 2>&1 && return 0 + if [ -n "$_PWR_DIR" ] && [ -f "$_PWR_DIR/blanton_icb_vi2c.sh" ]; then + # shellcheck source=/dev/null + source "$_PWR_DIR/blanton_icb_vi2c.sh" >/dev/null + fi + declare -F vi2c_init >/dev/null 2>&1 && return 0 + echo -e "[\033[31mERRO\033[0m] blanton_icb_vi2c.sh not found in ${_PWR_DIR:-.} - needed for 'pwr_data pdb'" >&2 + return 1 +} + +# ARB_LOST on this bus hits roughly every other transaction, and it makes the +# address-phase RX_ACK meaningless, so every transfer is retried. +# _pwr_pdb_rd16 -> decimal word +_pwr_pdb_rd16() { + local slave="$1" reg="$2" try bytes lo hi w + for (( try=0; try/dev/null) || continue + lo=$(printf '%s' "$bytes" | awk '{print $1}') + hi=$(printf '%s' "$bytes" | awk '{print $2}') + if [ -n "$lo" ] && [ -n "$hi" ]; then + w=$(( ( $(( hi )) << 8 ) | $(( lo )) )) + [ "$PWR_DEBUG" = "1" ] && printf '\033[90m[DEBG] pdb slave=0x%02X reg=0x%02X -> 0x%04X\033[0m\n' \ + "$(( slave ))" "$(( reg ))" "$w" >&2 + # All ones = nothing drove SDA; not real data. + if [ "$PDB_REJECT_FFFF" = "1" ] && (( w == 0xFFFF )); then continue; fi + echo "$w"; return 0 + fi + done + return 1 +} + +# _pwr_pdb_rd8 -> decimal byte +_pwr_pdb_rd8() { + local slave="$1" reg="$2" try bytes b0 + for (( try=0; try/dev/null) || continue + b0=$(printf '%s' "$bytes" | awk '{print $1}') + if [ -n "$b0" ]; then + local v=$(( $(( b0 )) & 0xFF )) + if [ "$PDB_REJECT_FFFF" = "1" ] && (( v == 0xFF )); then continue; fi + echo "$v"; return 0 + fi + done + return 1 +} + +# Raw 1-byte read of the mux control register (a TCA954x takes no register +# pointer). Echoes the control byte as a decimal. +_pwr_pdb_mux_read() { + local ch="$PDB_VI2C_CH" s=$(( PDB_MUX_ADDR )) b tx cm st v + b=$(_vbase "$ch") || return 1 + tx=$(printf '0x%X' $(( b + 0x0C ))) + cm=$(printf '0x%X' $(( b + 0x10 ))) + _vr "$tx" "$(printf '0x%X' $(( ((s << 1) | 1) & 0xFF )))" >/dev/null + st=$(_vwait "$cm" "$(printf '0x%X' $(( V_STA | V_WR )))") + (( ( $(( st )) & (_PWR_VI2C_ARBLOST | V_RXACK) ) != 0 )) && return 1 + _vwait "$cm" "$(printf '0x%X' $(( V_RD | V_NAK | V_STO )))" >/dev/null + v=$(_vnum "$(_vr "$tx")") + echo $(( v & 0xFF )) +} + +# Point the mux at channel 0 and confirm by reading the control byte back. +# A TCA954x accepts exactly ONE byte and NACKs anything after it, which is why +# vi2c_write (register pointer + data = 2 bytes) cannot be used here. +_pwr_pdb_mux_open() { + local ch="$PDB_VI2C_CH" s=$(( PDB_MUX_ADDR )) v=$(( PDB_MUX_SEL )) + local b tx cm st try rb + b=$(_vbase "$ch") || return 1 + tx=$(printf '0x%X' $(( b + 0x0C ))) + cm=$(printf '0x%X' $(( b + 0x10 ))) + for (( try=0; try/dev/null + st=$(_vwait "$cm" "$(printf '0x%X' $(( V_STA | V_WR )))") + _vr "$tx" "$(printf '0x%X' $(( v & 0xFF )))" >/dev/null + st=$(_vwait "$cm" "$(printf '0x%X' $(( V_WR | V_STO )))") + (( ( $(( st )) & (_PWR_VI2C_ARBLOST | V_RXACK) ) != 0 )) && continue + rb=$(_pwr_pdb_mux_read) || continue + if (( rb == (v & 0xFF) )); then + [ "$PWR_DEBUG" = "1" ] && printf '\033[90m[DEBG] mux 0x%02X <= 0x%02X (readback 0x%02X)\033[0m\n' \ + "$s" $(( v & 0xFF )) "$rb" >&2 + return 0 + fi + done + return 1 +} + +# VOUT_MODE (0x20): bits[7:5] = mode, bits[4:0] = parameter. +# 000 LINEAR -> exponent is bits[4:0], signed 5-bit (Vout = raw * 2^exp) +# 010 DIRECT -> needs the COEFFICIENTS command; falls back to 1 mV/LSB +# Cached per slave. Echoes "linear " or "direct". +declare -A _PWR_VMODE_CACHE 2>/dev/null +_pwr_pdb_vout_mode() { + local slave="$1" key="$slave" w mode exp r + if [ -n "${_PWR_VMODE_CACHE[$key]}" ]; then echo "${_PWR_VMODE_CACHE[$key]}"; return 0; fi + w=$(_pwr_pdb_rd8 "$slave" 0x20) || return 1 + mode=$(( (w >> 5) & 0x7 )) + exp=$(( w & 0x1F )); (( exp > 15 )) && exp=$(( exp - 32 )) + case "$mode" in + 0) r="linear $exp" ;; + 2) r="direct" ;; + *) r="direct" ;; + esac + _PWR_VMODE_CACHE[$key]="$r" + echo "$r" +} + +# True-ACK presence probe. vi2c_scan only tests RX_ACK and mistakes ARB_LOST for +# a device, so presence is checked here with STA|WR|STO and ARB_LOST rejected. +_pwr_pdb_present() { + local slave=$(( $1 )) ch="$PDB_VI2C_CH" b tx cm st s try + b=$(_vbase "$ch") || return 1 + tx=$(printf '0x%X' $(( b + 0x0C ))) + cm=$(printf '0x%X' $(( b + 0x10 ))) + for (( try=0; try/dev/null + st=$(_vwait "$cm" "$(printf '0x%X' $(( V_STA | V_WR | V_STO )))") + s=$(( st )) + (( (s & _PWR_VI2C_ARBLOST) == 0 )) && break + done + (( (s & _PWR_VI2C_ARBLOST) == 0 && (s & V_RXACK) == 0 )) +} + +# Echo the value if it falls inside [min,max], otherwise fail. +_pwr_sane() { + awk -v v="$1" -v lo="$2" -v hi="$3" \ + 'BEGIN { if (v+0 >= lo+0 && v+0 <= hi+0) { print v; exit 0 } exit 1 }' +} + +# Fills _PWR_* for one PDB device. Generic PMBus decoding - see header warning. +# Every value is read independently: these parts implement a partial command set +# (READ_TEMPERATURE_1 answers 0xFFFF and STATUS_WORD reports a CML fault), so one +# unsupported register must not blank the whole row. +_pwr_read_pdb_rail() { + local model="$1" slave="$2" page="$3" w mode exp v + _PWR_VIN_V="$PWR_NA"; _PWR_VOUT_V="$PWR_NA"; _PWR_IOUT_A="$PWR_NA"; _PWR_TEMP_C="$PWR_NA" + + _pwr_pdb_present "$slave" || return 1 + + [ "$page" != "-" ] && _vwr "$PDB_VI2C_CH" "$(( slave ))" 0x00 "$page" >/dev/null 2>&1 + + # Vin is deliberately NOT reported for the bricks. Measured on COM36: + # READ_VIN (0x88) tracks READ_VOUT (0x8B) to within 1 LSB on each device + # (0x60 1217/1218, 0x61 1219/1220, 0x62 1212/1212, 0x63 1217/1217) and does + # not behave like the shared input rail it would have to be, so 0x88 is + # aliased to the Vout measurement rather than a real input reading. + # Set PDB_TRUST_VIN=1 to decode it anyway. + if [ "$PDB_TRUST_VIN" = "1" ] && w=$(_pwr_pdb_rd16 "$slave" "$_PWR_VIN"); then + v=$(_pwr_l11 "$w") && _PWR_VIN_V=$(_pwr_sane "$v" 0 "$PDB_VIN_MAX") || _PWR_VIN_V="$PWR_NA" + fi + + if w=$(_pwr_pdb_rd16 "$slave" "$_PWR_VOUT"); then + mode=$(_pwr_pdb_vout_mode "$slave") || mode="direct" + case "$mode" in + linear*) + exp="${mode#linear }" + v=$(awk -v c="$(( w & 0xFFFF ))" -v e="$exp" 'BEGIN { printf "%.4f", c * (2.0 ^ e) }') ;; + *) v=$(awk -v c="$(( w & 0xFFFF ))" 'BEGIN { printf "%.4f", c / 1000.0 }') ;; + esac + _PWR_VOUT_V=$(_pwr_sane "$v" 0 "$PDB_VOUT_MAX") || _PWR_VOUT_V="$PWR_NA" + fi + + if w=$(_pwr_pdb_rd16 "$slave" "$_PWR_IOUT"); then + v=$(_pwr_l11 "$w") + _PWR_IOUT_A=$(_pwr_sane "$v" "-$PDB_IOUT_ABS_MAX" "$PDB_IOUT_ABS_MAX") || _PWR_IOUT_A="$PWR_NA" + fi + + if w=$(_pwr_pdb_rd16 "$slave" "$_PWR_TEMP"); then + v=$(_pwr_l11 "$w") + if v=$(_pwr_sane "$v" "$PDB_TEMP_MIN" "$PDB_TEMP_MAX"); then + _PWR_TEMP_C=$(printf '%.1f' "$v") + else + _PWR_TEMP_C="$PWR_NA" + fi + fi + return 0 +} + +# === Shared table chrome ===================================================== +_pwr_table_header() { + echo "==== $1 ====" + printf "%-4s %-9s %-8s %-7s %-3s %-17s %9s %9s %9s %8s\n" \ + "No." "Location" "VRM" "SlaveID" "Pg" "Netname" "Vin(V)" "Vout(V)" "Iout(A)" "Temp(C)" + printf '%s\n' "-------------------------------------------------------------------------------------------------" +} + +# === Public: pwr_data pdb ==================================================== +pwr_data_pdb() { + _pwr_vi2c_ready || return 1 + local muxok=0 + _pwr_pdb_mux_open && muxok=1 + + _pwr_table_header "PDB" + local n=0 entry loc model slave page net pgshow + for entry in "${PDB_RAILS[@]}"; do + IFS=':' read -r loc model slave page net <<< "$entry" + n=$(( n + 1 )) + if [ "$page" = "-" ]; then pgshow="-"; else pgshow="$(( page ))"; fi + _pwr_read_pdb_rail "$model" "$slave" "$page" + printf "%-4s %-9s %-8s %-7s %-3s %-17s %9s %9s %9s %8s\n" \ + "$n" "$loc" "$model" "$slave" "$pgshow" "$net" \ + "$_PWR_VIN_V" "$_PWR_VOUT_V" "$_PWR_IOUT_A" "$_PWR_TEMP_C" + done + + if [ "$muxok" != "1" ]; then + echo -e "[\033[33mWARN\033[0m] mux $PDB_MUX_ADDR on ICB ch$PDB_VI2C_CH did not answer, so the brick" + echo " leg was never opened and 0x60..0x63 read as $PWR_NA." + echo " Run 'pwr_pdb_bus' to tell 'absent' from 'bus losing arbitration'." + fi + return 0 +} + +# True-ACK scan of the PDB bus. vi2c_scan / icb_i2c_scan only test RX_ACK and +# ignore ARB_LOST (STAT bit5), so on a contended bus they report arbitration +# failures as devices. This retries on ARB_LOST and lists the two cases apart. +pwr_pdb_bus() { + _pwr_vi2c_ready || return 1 + local ch="$PDB_VI2C_CH" b tx cm a st s try found="" arb="" rb + b=$(_vbase "$ch") || return 1 + tx=$(printf '0x%X' $(( b + 0x0C ))) + cm=$(printf '0x%X' $(( b + 0x10 ))) + vi2c_init "$ch" + for (( a=0x08; a<=0x77; a++ )); do + for (( try=0; try/dev/null + st=$(_vwait "$cm" "$(printf '0x%X' $(( V_STA | V_WR | V_STO )))") + s=$(( st )) + (( (s & _PWR_VI2C_ARBLOST) == 0 )) && break + done + if (( (s & _PWR_VI2C_ARBLOST) != 0 )); then + arb+="$(printf '0x%02X ' "$a")" + elif (( (s & V_RXACK) == 0 )); then + found+="$(printf '0x%02X ' "$a")" + fi + done + echo " [PDB-BUS] ICB ch$ch true ACK : ${found:-(none)}" + [ -n "$arb" ] && echo " [PDB-BUS] persistent ARB_LOST : ${arb% }" + if rb=$(_pwr_pdb_mux_read); then + printf ' [PDB-BUS] mux %s ctrl : 0x%02X\n' "$PDB_MUX_ADDR" "$rb" + else + echo " [PDB-BUS] mux $PDB_MUX_ADDR ctrl : no response" + fi +} + +# Identify whatever answers on the PDB bus: MFR_ID (0x99) / MFR_MODEL (0x9A) are +# PMBus block reads (first byte = length), VOUT_MODE (0x20) is a single byte. +# Needed to pin down the real conversions, which are generic guesses until then. +pwr_pdb_id() { + _pwr_vi2c_ready || return 1 + _pwr_pdb_mux_open >/dev/null 2>&1 + local entry loc model slave page net r bytes x v asc + for entry in "${PDB_RAILS[@]}"; do + IFS=':' read -r loc model slave page net <<< "$entry" + printf ' %-16s %s\n' "$net" "$slave" + for r in 0x99 0x9A; do + bytes=$(_vrd "$PDB_VI2C_CH" "$(( slave ))" "$(( r ))" 12 2>/dev/null) \ + || bytes=$(_vrd "$PDB_VI2C_CH" "$(( slave ))" "$(( r ))" 12 2>/dev/null) + if [ -n "$bytes" ]; then + asc="" + for x in $bytes; do + v=$(( x )) + if (( v >= 0x20 && v < 0x7F )); then asc+=$(printf '%b' "\\x$(printf '%02x' "$v")"); else asc+="."; fi + done + printf ' %s raw=[%s]\n' "$r" "$bytes" + printf ' %s asc="%s"\n' "$r" "$asc" + else + printf ' %s : no response\n' "$r" + fi + done + if v=$(_pwr_pdb_rd8 "$slave" 0x20); then + printf ' 0x20 VOUT_MODE=0x%02X -> %s\n' "$v" "$(_pwr_pdb_vout_mode "$slave")" + else + echo " 0x20 VOUT_MODE : no response" + fi + done +} + +# === Public: pwr_data [swb0|swb1|pdb|all] ==================================== +pwr_data() { + local board + board="$(echo "${1:-swb0}" | tr 'A-Z' 'a-z')" + case "$board" in + all) pwr_data swb0; echo ""; pwr_data swb1; echo ""; pwr_data pdb; return ;; + pdb) pwr_data_pdb; return ;; + esac + + local off + off=$(_pwr_board_offset "$board") || { + echo -e "[\033[31mERRO\033[0m] Usage: pwr_data [swb0|swb1|pdb|all]"; return 1; } + local tag="SWB${off}" + + if ! declare -F cb_pmbus_read >/dev/null 2>&1; then + echo -e "[\033[31mERRO\033[0m] cb_pmbus_read() missing - source blanton_cb_i2c.sh"; return 1 + fi + + # Init each I2C channel once and disable per-transfer auto-init: the table is + # ~80 PMBus transactions and every init costs 4 more pcimem calls. + local _save_auto="$CB_I2C_AUTO_INIT" chans="" c seen + for entry in "${PWR_RAILS[@]}"; do + IFS=':' read -r _ _ c _ _ _ <<< "$entry" + c=$(( c + off )) + seen=0; for x in $chans; do [ "$x" = "$c" ] && seen=1; done + [ "$seen" = "0" ] && chans="$chans $c" + done + for c in $chans; do cb_i2c_init "$c" >/dev/null; done + CB_I2C_AUTO_INIT=0 + + _pwr_table_header "$tag" + + local n=0 loc vrm ch slave page net + for entry in "${PWR_RAILS[@]}"; do + IFS=':' read -r loc vrm ch slave page net <<< "$entry" + ch=$(( ch + off )) + n=$(( n + 1 )) + _pwr_read_rail "$vrm" "$ch" "$slave" "$page" + printf "%-4s %-9s %-8s %-7s %-3s %-17s %9s %9s %9s %8s\n" \ + "$n" "$loc" "$vrm" "$slave" "$(( page ))" "$net" \ + "$_PWR_VIN_V" "$_PWR_VOUT_V" "$_PWR_IOUT_A" "$_PWR_TEMP_C" + done + + CB_I2C_AUTO_INIT="${_save_auto:-1}" + return 0 +} + +# === Help ==================================================================== +pwr_data_help() { + echo -e "\033[1mblanton_pwr_data.sh - SWB / PDB power rail monitor\033[0m" + echo "" + echo -e " \033[33mpwr_data\033[0m [swb0|swb1|pdb|all] read Vin/Vout/Iout/Temp for every rail" + echo -e " \033[33mpwr_pdb_bus\033[0m true-ACK scan of the PDB bus (rejects ARB_LOST)" + echo -e " \033[33mpwr_pdb_id\033[0m MFR_ID / MFR_MODEL / VOUT_MODE of the PDB parts" + echo -e " \033[33mpwr_debug\033[0m on|off show each PMBus word read" + echo "" + echo -e " SWB: \033[36mcb_pmbus_*\033[0m on CB F3 I2C. SWB0 = ch 6/8, SWB1 = ch 7/9." + echo -e " PDB: \033[36mVI2C\033[0m ICB ch$PDB_VI2C_CH -> mux $PDB_MUX_ADDR ch0 -> bricks 0x60..0x63 + EFUSE 0x26." + echo -e " Anything that does not answer prints \033[90m$PWR_NA\033[0m." + echo -e " \033[33mPDB conversions are generic PMBus and NOT yet verified\033[0m - see the file header." +} + +pwr_data_help diff --git a/src/Script_ABC_Blanton/Blanton_Script/blanton_temp_sensor.sh b/src/Script_ABC_Blanton/Blanton_Script/blanton_temp_sensor.sh new file mode 100644 index 0000000..9b809a6 --- /dev/null +++ b/src/Script_ABC_Blanton/Blanton_Script/blanton_temp_sensor.sh @@ -0,0 +1,225 @@ +#!/usr/bin/env bash +# ============================================================================= +# blanton_temp_sensor.sh -- Blanton CB + ICB(PDB) temperature sensor reader +# ============================================================================= +# V0.1.0 2026-08-11 Reads every board temp sensor through the existing I2C +# helpers and converts the raw registers to degC. +# +# Topology (verified on DUT COM37, 2026-08-11): +# +# CB : CB FPGA F3 I2C **Ch10** -> TCA9543 mux @0x70 (FPGA drives its RESET, +# released by cb_i2c_mux_reset_release / F0 0x7D4 <= 0xFF). +# mux ctrl 0x01 = leg0 = TEMP bus : TMP75 0x48, TMP75 0x49, TMP432 0x4C +# mux ctrl 0x02 = leg1 = DEBUG bus : PCIe fanout buf 0x6B/0x6D + hdr +# NOTE: CB_tree.png draws DEBUG on the upper leg and TEMP on the lower +# one; on real HW the TEMP devices answer with ctrl=0x01 (leg0). +# Backend: blanton_cb_i2c.sh (cb_i2c_read / cb_i2c_muxwrite) +# +# ICB : ICB(PDB) I2C **Ch2**, no mux : TMP75 U8 0x48, TMP75 U33 0x49, +# TMP432 U29 0x4C +# Backend: blanton_icb_vi2c.sh (CB F3 VI2C proxy, vi2c_read). +# Do NOT use blanton_icb_i2c.sh here: VSPI is ~18 ms/register, which +# trips the SMBus 25-35 ms timeout and the sensors NACK the pointer. +# +# Conversion (datasheets in this folder): +# TMP75 (SBOS288J) : reg 0x00, 2 bytes, 12-bit left-justified two's +# complement -> T = (raw16 >> 4) * 0.0625 +# TMP432 (SBOS441I) : local hi 0x00 / lo 0x29 (2-byte read from 0x00) +# remote1 hi 0x01 / lo 0x10 +# remote2 hi 0x23 / lo 0x24 +# T = (raw16 >> 4) * 0.0625, minus 64 when CONFIG1(0x03) +# bit2 RANGE = 1 (extended -64..191C mode) +# ID: 0xFD = 0x32 (device), 0xFE = 0x55 (TI) +# open-diode status: 0x1B bit1 R2OPEN / bit0 R1OPEN +# +# Usage: +# ./blanton_temp_sensor.sh # CB + ICB, one pass +# ./blanton_temp_sensor.sh -r # also show TMP432 remote1/remote2 +# ./blanton_temp_sensor.sh -c | -i # CB only / ICB only +# ./blanton_temp_sensor.sh -n 10 -t 5 # 10 passes, 5 s apart (-n 0 = forever) +# source blanton_temp_sensor.sh ; temp_all ; temp_cb ; temp_icb +# ============================================================================= + +# --- pull in the I2C backends ------------------------------------------------ +_TS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" +_ts_need() { + local fn="$1" file="$2" + declare -F "$fn" >/dev/null 2>&1 && return 0 + if [ -f "$_TS_DIR/$file" ]; then + # shellcheck source=/dev/null + source "$_TS_DIR/$file" >/dev/null 2>&1 + fi + declare -F "$fn" >/dev/null 2>&1 && return 0 + echo "[ERR] blanton_temp_sensor.sh: $fn() missing (need $file)" >&2 + return 1 +} +_ts_need cb_fpga blanton_fpga_pcimem.sh || true +_ts_need _cbi2c_xfer_read blanton_cb_i2c.sh || true +_ts_need _vrd blanton_icb_vi2c.sh || true + +# --- geometry / device tables ------------------------------------------------ +TS_CB_CH="${TS_CB_CH:-10}" # CB FPGA F3 I2C channel with the temp bus +TS_CB_MUX="${TS_CB_MUX:-0x70}" # TCA9543 on that channel +TS_CB_MUX_TEMP="${TS_CB_MUX_TEMP:-0x01}" # leg0 = temp sensors +TS_ICB_CH="${TS_ICB_CH:-2}" # ICB VI2C channel with the temp bus + +# "<7-bit addr>:" in the order they are printed +TS_CB_LIST="${TS_CB_LIST:-0x48:TMP75 0x49:TMP75 0x4C:TMP432}" +TS_ICB_LIST="${TS_ICB_LIST:-0x48:TMP75 0x49:TMP75 0x4C:TMP432}" + +# TMP432 register pointers +_TS432_LOCAL=0x00 +_TS432_REM1=0x01 +_TS432_REM2=0x23 +_TS432_CFG1=0x03 +_TS432_OPEN=0x1B + +# ============================================================================= +# conversion helpers +# ============================================================================= +# _ts_word -> decimal 16-bit word +_ts_word() { echo $(( ( $(($1)) & 0xFF ) << 8 | ( $(($2)) & 0xFF ) )); } + +# _ts_c12 mode: signed | offset64 +# signed : 12-bit two's complement (TMP75, TMP432 std range >=0) +# offset64 : TMP432 extended range, value - 64 +_ts_c12() { + awk -v w="$1" -v m="$2" 'BEGIN{ + r = int(w/16); + if (m == "offset64") { printf "%.1f", r*0.0625 - 64.0; } + else { if (r >= 2048) r -= 4096; printf "%.1f", r*0.0625; } + }' +} + +# _ts_fmt