Add bcm_wait_ready() comprehensive pre-write readiness check

Stock firmware wait_for_ready() at 0x2000 checks three conditions before
each init block write — all must be simultaneously true:

  1. A2.bit3 = 1  (BCM4500 DSP processing complete)
  2. A8.bit0 = 0, A8.bit1 = 1  (command register ready)
  3. A4.bit7 = 1  (init pipeline flushed)

Our bcm_poll_ready() only checked A8.bit0, and was used for both
pre-write and post-write checks. Now:

  - bcm_wait_ready(): strict 3-condition check for PRE-write
    (with fallback to simple A8 check for gateway quirks)
  - bcm_poll_ready(): simple A8 check for POST-write
    (matches stock firmware's poll_ready() at 0x20C5)

Code size: 15,155 / 15,360 bytes (205 bytes spare)
This commit is contained in:
Ryan Malloy 2026-02-20 11:48:23 -07:00
parent e9e5ab859a
commit dffef75b06

View File

@ -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 */