in dfl-n3000-nios.c [296:406]
static int n3000_nios_init_done_check(struct n3000_nios *nn)
{
unsigned int val, state_a, state_b;
struct device *dev = nn->dev;
int ret, ret2;
/*
* The SPI is shared by the Nios core inside the FPGA, Nios will use
* this SPI master to do some one time initialization after power up,
* and then release the control to OS. The driver needs to poll on
* INIT_DONE to see when driver could take the control.
*
* Please note that after Nios firmware version 3.0.0, INIT_START is
* introduced, so driver needs to trigger START firstly and then check
* INIT_DONE.
*/
ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val);
if (ret)
return ret;
/*
* If Nios version register is totally uninitialized(== 0x0), then the
* Nios firmware is missing. So host could take control of SPI master
* safely, but initialization work for Nios is not done. To restore the
* card, we need to reprogram a new Nios firmware via the BMC chip on
* SPI bus. So the driver doesn't error out, it continues to create the
* spi controller device and spi_board_info for BMC.
*/
if (val == 0) {
dev_err(dev, "Nios version reg = 0x%x, skip INIT_DONE check, but the retimer may be uninitialized\n",
val);
return 0;
}
if (FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val) >= 3) {
/* read NIOS_INIT to check if retimer initialization is done */
ret = regmap_read(nn->regmap, N3000_NIOS_INIT, &val);
if (ret)
return ret;
/* check if retimers are initialized already */
if (val & (N3000_NIOS_INIT_DONE | N3000_NIOS_INIT_START))
goto nios_init_done;
/* configure FEC mode per module param */
val = N3000_NIOS_INIT_START;
/*
* When the retimer is to be set to 10G mode, there is no FEC
* mode setting, so the REQ_FEC_MODE field will be ignored by
* Nios firmware in this case. But we should still fill the FEC
* mode field cause host could not get the retimer working mode
* until the Nios init is done.
*
* For now the driver doesn't support the retimer FEC mode
* switching per user's request. It is always set to Reed
* Solomon FEC.
*
* The driver will set the same FEC mode for all links.
*/
val |= N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL;
ret = regmap_write(nn->regmap, N3000_NIOS_INIT, val);
if (ret)
return ret;
}
nios_init_done:
/* polls on NIOS_INIT_DONE */
ret = regmap_read_poll_timeout(nn->regmap, N3000_NIOS_INIT, val,
val & N3000_NIOS_INIT_DONE,
N3000_NIOS_INIT_TIME_INTV,
N3000_NIOS_INIT_TIMEOUT);
if (ret)
dev_err(dev, "NIOS_INIT_DONE %s\n",
(ret == -ETIMEDOUT) ? "timed out" : "check error");
ret2 = regmap_read(nn->regmap, N3000_NIOS_PKVL_A_MODE_STS, &state_a);
if (ret2)
return ret2;
ret2 = regmap_read(nn->regmap, N3000_NIOS_PKVL_B_MODE_STS, &state_b);
if (ret2)
return ret2;
if (!ret) {
/*
* After INIT_DONE is detected, it still needs to check if the
* Nios firmware reports any error during the retimer
* configuration.
*/
if (IS_MODE_STATUS_OK(state_a) && IS_MODE_STATUS_OK(state_b))
return 0;
/*
* If the retimer configuration is failed, the Nios firmware
* will still release the spi controller for host to
* communicate with the BMC. It makes possible for people to
* reprogram a new Nios firmware and restore the card. So the
* driver doesn't error out, it continues to create the spi
* controller device and spi_board_info for BMC.
*/
dev_err(dev, "NIOS_INIT_DONE OK, but err on retimer init\n");
}
dev_err(nn->dev, "PKVL_A_MODE_STS 0x%x\n", state_a);
dev_err(nn->dev, "PKVL_B_MODE_STS 0x%x\n", state_b);
return ret;
}