I am not sure of the cause for the original problem - i.e. a hardware reset leaves the PHY in "bad" state. I suspect it may have something to do with the internal 25MHz oscillator not stabilizing before auto-negotiation starts?
In any event I found what looks to be a reliable solution - retstart the auto-negotiation in firmware after the PHY chip has stabilized. I Inserted the following code in the stm32cubemx generated source, in "ethernet.c".
/* USER CODE BEGIN PHY_PRE_CONFIG */
/* Force a PHY Auto-Negotiation -- Hardware Reset Can leave Phy in Bad state*/
{
/* PHY Register Definitions */
const uint32_t NEG_LAN8742A_ADDRESS = 0x00U;
const uint32_t NEG_PHY_BCR = 0x00U; /* Basic Control Register */
const uint32_t NEG_PHY_BCR_SOFT_RESET = (1 << 15);
const uint32_t NEG_PHY_BCR_AUTONEGO_EN = (1 << 12);
const uint32_t NEG_PHY_BCR_RESTART_AN = (1 << 9);
/* Implementation of the missing function */
uint32_t phy_reg = 0;
// 1. Send Soft Reset command
HAL_ETH_WritePHYRegister(&heth, NEG_LAN8742A_ADDRESS, NEG_PHY_BCR, NEG_PHY_BCR_SOFT_RESET);
// 2. Wait for Reset bit to self-clear (indicates PHY is ready)
uint32_t timeout = HAL_GetTick() + 500;
do {
HAL_ETH_ReadPHYRegister(&heth, NEG_LAN8742A_ADDRESS, NEG_PHY_BCR, &phy_reg);
} while ((phy_reg & NEG_PHY_BCR_SOFT_RESET) && (HAL_GetTick() < timeout));
// 3. Force Auto-Negotiation Enable and Restart
HAL_ETH_WritePHYRegister(&heth, NEG_LAN8742A_ADDRESS, NEG_PHY_BCR,
NEG_PHY_BCR_AUTONEGO_EN | NEG_PHY_BCR_RESTART_AN);
}
/* USER CODE END PHY_PRE_CONFIG */