static int n3000_nios_init_done_check()

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;
}