Commit 9a94168e authored by Francois Ramu's avatar Francois Ramu Committed by Carles Cufi
Browse files

disk: sdhc: use the multiple block transfer for writing



The sdhc_spi_write_multi function is sending the CMD25
for multiple block write operation on the SD card
instead of looping the CMD24. This is improving
the transfer speed compared to the sdhc_spi_write function
when the nb of blocks to write is significant (more than 2).

Signed-off-by: default avatarFrancois Ramu <francois.ramu@st.com>
parent c505ca38
Loading
Loading
Loading
Loading
+94 −5
Original line number Diff line number Diff line
@@ -748,6 +748,85 @@ error:
	return err;
}

/* this function is optimized to write multiple blocks */
static int sdhc_spi_write_multi(struct sdhc_spi_data *data,
	const uint8_t *buf, uint32_t sector, uint32_t count)
{
	int err;
	uint32_t addr;
	uint8_t block[SDHC_CRC16_SIZE];

	err = sdhc_map_disk_status(data->status);
	if (err != 0) {
		return err;
	}

	if (data->high_capacity) {
		addr = sector;
	} else {
		addr = sector * SDMMC_DEFAULT_BLOCK_SIZE;
	}

	err = sdhc_spi_cmd_r1(data, SDHC_WRITE_MULTIPLE_BLOCK, addr);
	if (err < 0) {
		goto exit;
	}

	/* Write the blocks */
	for (; count != 0U; count--) {
		/* Start the block */
		block[0] = SDHC_TOKEN_MULTI_WRITE;
		err = sdhc_spi_tx(data, block, 1);
		if (err != 0) {
			goto exit;
		}

		/* Write the payload */
		err = sdhc_spi_tx(data, buf, SDMMC_DEFAULT_BLOCK_SIZE);
		if (err != 0) {
			goto exit;
		}

		/* Build and write the trailing CRC */
		sys_put_be16(crc16_itu_t(0, buf, SDMMC_DEFAULT_BLOCK_SIZE),
			     block);

		err = sdhc_spi_tx(data, block, sizeof(block));
		if (err != 0) {
			goto exit;
		}

		err = sdhc_map_data_status(sdhc_spi_rx_u8(data));
		if (err != 0) {
			goto exit;
		}

		/* Wait for the card to finish programming */
		err = sdhc_spi_skip_until_ready(data);
		if (err != 0) {
			goto exit;
		}

		buf += SDMMC_DEFAULT_BLOCK_SIZE;
		sector++;
	}

	/* Stop the transmission */
	sdhc_spi_tx_cmd(data, SDHC_STOP_TRANSMISSION, 0);

	/* Wait for the card to finish operation */
	err = sdhc_spi_skip_until_ready(data);
	if (err != 0) {
		goto exit;
	}

	err = 0;
exit:
	spi_release(data->spi, &data->cfg);

	return err;
}

static int disk_spi_sdhc_init(const struct device *dev);

static int sdhc_spi_init(const struct device *dev)
@@ -808,6 +887,16 @@ static int disk_spi_sdhc_access_write(struct disk_info *disk,
	struct sdhc_spi_data *data = dev->data;
	int err;

	/* for more than 2 blocks the multiple block is preferred */
	if (count > 2) {
		LOG_DBG("multi block sector=%u count=%u", sector, count);

		err = sdhc_spi_write_multi(data, buf, sector, count);
		if (err != 0 && sdhc_is_retryable(err)) {
			sdhc_spi_recover(data);
			err = sdhc_spi_write_multi(data, buf, sector, count);
		}
	} else {
		LOG_DBG("sector=%u count=%u", sector, count);

		err = sdhc_spi_write(data, buf, sector, count);
@@ -815,7 +904,7 @@ static int disk_spi_sdhc_access_write(struct disk_info *disk,
			sdhc_spi_recover(data);
			err = sdhc_spi_write(data, buf, sector, count);
		}

	}
	return err;
}