Thanks, zygot. It is frustrating that Digilent called the Macronix flash a "drop in replacement" for the Micron in their reference docs when it's apparently not.
Thanks, Ana-Maria.
I've made some progress on figuring out what's going on, but no progress towards a solution.
Debugging from the SDK the SPI bootloader seems to crash when it tries to access the flash.
This project was created in Vivado 2017.2. In the SDK source there's no device information for Macronix flash, nor is it an option in the QSPI block customization in Vivado. I opened the project in Vivado 2020.2, and there is now the option to select Macronix flash in the QSPI block customization as the slave device. However, enough stuff has changed between these versions that I can't move forward due to other errors and due to my inexperience I have no idea how to fix them.
After some further searching I've discovered Micron has obsoleted the flash used in these boards, hence the switch to Macronix. It's really unfortunate that these CMOD boards have the same part number but require a change to the original design to work.
Alliance Memory seems to have purchased to rights to manufacture these legacy Micron parts, so I'm going to try replacing the Macronix flash with this Micron-like part and see if that works. Hopefully device and manufacturer IDs remain the same and it Just Works. If that fails I suppose my next step is hire a contractor to get our project running in a newer version of Vivado. Or, perhaps just re-implement this fairly simple project in an MCU.