From ff3e9d92dbfc645209e183e8dbf44e6cea0612f8 Mon Sep 17 00:00:00 2001 From: Eirik Stople Date: Sat, 14 Sep 2024 22:57:04 +0200 Subject: [PATCH 1/2] Add commands to read fuse settings, for SMC diagnostics (14 bytes) New size: 7028 (max size 7680) Reading fuse bits (and lock bits) is a hardware feature where you set SPMCSR to (1 << RFLB) | (1 << SELFPRGEN), and then LPM within 4 clock cycles. The feature you read with LPM is decided by Z: 0: Low fuse 1: Lock bits 2: Extended fuse 3: High fuse To keep firmware use at a minimum, assume that the numeric values of the I2C commands are in the same order as the hardware feature, so that they can share the code, and only do a simple subtract to separate between them. X16 need to know which fuse settings to expect, and which fuse settings are incorrect. --- README.md | 16 ++++++++++++++++ x16-smc.ino | 27 ++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fd6b8a2..389c3ab 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ If you want to update the SMC firmware, please read this [guide](doc/update-guid | 0x07 | Master read | 1 byte | Get keyboard keycode | | 0x08 | Master write | 1 byte | Echo | | 0x09 | Master write | 1 byte | Debug output | +| 0x0a | Master read | 1 byte | Get low fuse setting | +| 0x0b | Master read | 1 byte | Get lock bits | +| 0x0c | Master read | 1 byte | Get extended fuse setting | +| 0x0d | Master read | 1 byte | Get high fuse setting | | 0x18 | Master read | 1 byte | Get keyboard command status | | 0x19 | Master write | 1 byte | Send keyboard command | | 0x1a | Master write | 2 bytes | Send keyboard command | @@ -79,6 +83,18 @@ Key codes are one byte. Bit 7 indicates if the key was pressed (0) or released ( This command gets one keycode from the buffer. If the buffer is empty, it returns 0. +## Get fuses and lock bits (0x0a..0x0d) + +These offsets returns the fuse settings and lock bits (low-lock-extended-high). + +Expected value: +- Low: $F1 +- Lock: $FF +- Extended: $FE +- High: $D4 + +The reason for this particular order, is size optimization in SMC FW. + ## Get keyboard command status (0x18) This offset returns the status of the last host to keyboard command. diff --git a/x16-smc.ino b/x16-smc.ino index faacfac..bc48470 100644 --- a/x16-smc.ino +++ b/x16-smc.ino @@ -68,6 +68,10 @@ #define I2C_CMD_ECHO 0x08 #define I2C_CMD_DBG_OUT 0x09 #define I2C_CMD_GET_LONGPRESS 0x09 +#define I2C_CMD_GET_FUSE_LOW 0x0a +#define I2C_CMD_GET_FUSE_LOCK 0x0b +#define I2C_CMD_GET_FUSE_EXT 0x0c +#define I2C_CMD_GET_FUSE_HIGH 0x0d #define I2C_CMD_GET_KBD_STATUS 0x18 #define I2C_CMD_KBD_CMD1 0x19 #define I2C_CMD_KBD_CMD2 0x1a @@ -532,8 +536,21 @@ void I2C_Receive(int) { I2C_Data[0] = defaultRequest; } +// readFuse: +// Function must be called with interrupts disabled. +// 0: Low +// 1: Lock +// 2: Extended +// 3: High +uint8_t readFuse(uint8_t address) +{ + eeprom_busy_wait(); + return boot_lock_fuse_bits_get(address); +} + void I2C_Send() { - switch (I2C_Data[0]) { + uint8_t request = I2C_Data[0]; + switch (request) { case I2C_CMD_GET_KEYCODE_FAST: if (!sendKeyCode()) smcWire.clearBuffer(); break; @@ -602,6 +619,14 @@ void I2C_Send() { case I2C_CMD_SELF_PROGRAMMING_MODE: // Check if self programming mode is activated smcWire.write(selfProgrammingModeActive); break; + + case I2C_CMD_GET_FUSE_LOW: + case I2C_CMD_GET_FUSE_LOCK: + case I2C_CMD_GET_FUSE_EXT: + case I2C_CMD_GET_FUSE_HIGH: // Read fuses + // Size optimization: Assume that numeric values of these commands are in this order, to fit with hardware + smcWire.write(readFuse(request - I2C_CMD_GET_FUSE_LOW)); + break; } I2C_Data[0] = defaultRequest; From bbe1c9e95abb583faa66c1e72faf25afdb754e28 Mon Sep 17 00:00:00 2001 From: Eirik Stople Date: Sat, 12 Oct 2024 23:10:01 +0200 Subject: [PATCH 2/2] Bump version to 47.2.4 --- version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.h b/version.h index 9a4e975..d35922f 100644 --- a/version.h +++ b/version.h @@ -1,3 +1,3 @@ #define version_major 47 #define version_minor 2 -#define version_patch 3 +#define version_patch 4