diff --git a/firmware/skywalker1.c b/firmware/skywalker1.c index b33e935..5430c17 100644 --- a/firmware/skywalker1.c +++ b/firmware/skywalker1.c @@ -735,18 +735,12 @@ static BOOL bcm_indirect_write_block(BYTE page, __xdata BYTE *data, BYTE len) { /* * Poll BCM4500 for command completion via gateway register A8. + * Matches stock firmware's poll_ready() at 0x20C5: checks A8.bit0 = 0. + * Used AFTER init block writes / indirect commands. * - * The BCM3440 gateway's A8 register does not always clear bit 0 after - * the BCM4500 DSP processes an indirect write command, even though the - * write succeeds internally (confirmed by reading the direct BCM4500 - * address 0x08 where A8 bit 0 does clear and bit 1 becomes set). - * - * The stock firmware's 0x20C5 polls the same gateway A8 via 0x2258 - * and expects bit 0=0, bit 1=1. On our device, bit 1 never becomes 1 - * through the gateway after writes, but the init data IS applied. - * - * Strategy: poll for early completion, but treat timeout as success - * with a settling delay rather than hard failure. + * Treats timeout as success with settling delay — the gateway A8 register + * doesn't always reflect the BCM4500's internal ready state, but commands + * do complete internally. */ static BOOL bcm_poll_ready(void) { BYTE i, val; @@ -763,6 +757,59 @@ static BOOL bcm_poll_ready(void) { return TRUE; } +/* + * Comprehensive BCM4500 readiness check — used BEFORE init block writes. + * + * Replicates stock firmware wait_for_ready() at 0x2000, which checks + * THREE conditions that must ALL be true simultaneously: + * + * 1. A2.bit3 = 1 (BCM4500 status register — DSP processing complete) + * Stock firmware: condition_1() at 0x2314 + * + * 2. A8.bit0 = 0 (command register not busy) + * A8.bit1 = 1 (command result ready) + * Stock firmware: condition_2() at 0x2258 + * + * 3. A4.bit7 = 1 (lock/status register — init pipeline flushed) + * Stock firmware: condition_3() at 0x235B + * + * This is STRICTER than bcm_poll_ready() which only checks A8.bit0. + * The stock firmware uses this strict check before writing each init block, + * ensuring the BCM4500 has fully processed the previous block before + * accepting a new one. + * + * Retries up to 10 times with delays. Returns FALSE on timeout. + */ +static BOOL bcm_wait_ready(void) { + BYTE i, val; + for (i = 0; i < 10; i++) { + /* Condition 1: A2.bit3 — DSP status */ + if (!bcm_direct_read(BCM_REG_STATUS, &val)) + return FALSE; + if (val & 0x08) { + /* Condition 2: A8.bit0=0, A8.bit1=1 — command ready */ + if (!bcm_direct_read(BCM_REG_CMD, &val)) + return FALSE; + if (!(val & 0x01) && (val & 0x02)) { + /* Condition 3: A4.bit7 — pipeline flushed */ + if (!bcm_direct_read(BCM_REG_LOCK, &val)) + return FALSE; + if (val & 0x80) + return TRUE; /* All 3 conditions met */ + } + } + delay(10); + } + /* Fallback: if comprehensive check times out but A8 reports not-busy, + * proceed anyway — handles case where A2/A4 conditions don't reflect + * properly through the BCM3440 I2C gateway. */ + if (bcm_direct_read(BCM_REG_CMD, &val) && !(val & 0x01)) { + delay(5); + return TRUE; + } + return FALSE; +} + /* * Read 16-byte signal data block from BCM4500 via indirect register protocol. * @@ -848,9 +895,9 @@ static BOOL bcm_write_init_block(const __code BYTE *data, BYTE len) { BYTE i; /* Pre-write readiness check — stock firmware 0x0DE9 calls wait_for_ready() - * (0x2000) before each block. This polls A8 + additional conditions with - * up to 10 retries. Our simplified version polls A8 only. */ - if (!bcm_poll_ready()) + * (0x2000) before each block. This checks 3 conditions: A2.bit3, A8.bit0+1, + * A4.bit7. All must be true before the BCM4500 accepts a new init block. */ + if (!bcm_wait_ready()) return FALSE; /* Page select = 0 */