/** NVT check fastboot preload status @file fastboot_preload.c @ingroup @note Copyright Novatek Microelectronics Corp. 2020. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include static DEFINE_MUTEX(lock); #define NAND_CTRL_STS_REG_OFS 0x48 #define NAND_COMP_STS 0x00001000 // bit[12] #define NAND_SPI_CFG_REG_OFS 0x14 #define NAND_SPI_CS_MODE 0x4 #define NAND_SPI_OP_MODE 0x1 static DEFINE_MUTEX(mmc_lock); #define SDIO_STATUS_REG_OFS 0x28 #define RSP_CRC_FAIL 0x1 #define DATA_CRC_FAIL 0x2 #define RSP_TIMEOUT 0x4 #define DATA_TIMEOUT 0x8 #define DATA_END 0x80 #define DMA_ERROR 0x80000 int nvt_check_preload_finish(void) { void __iomem *flash_address; static int ret = 0; u32 status = 0x0, io_reg = 0x0; mutex_lock(&lock); if (ret) { mutex_unlock(&lock); return ret; } flash_address = ioremap_nocache(NVT_NAND_BASE_PHYS, 0x1000); if (unlikely(flash_address == 0)) { pr_err("%s fails: ioremap_nocache fail\n", __FUNCTION__); mutex_unlock(&lock); return -1; } do { status = readl(flash_address + NAND_CTRL_STS_REG_OFS); if (status & NAND_COMP_STS) { writel(status, flash_address + NAND_CTRL_STS_REG_OFS); io_reg = readl(flash_address + NAND_SPI_CFG_REG_OFS); io_reg |= (0x1 << NAND_SPI_CS_MODE); writel(io_reg, flash_address + NAND_SPI_CFG_REG_OFS); io_reg = readl(flash_address + NAND_SPI_CFG_REG_OFS); io_reg &=~ (0x1 << NAND_SPI_OP_MODE); writel(io_reg, flash_address + NAND_SPI_CFG_REG_OFS); ret = 1; break; } usleep_range(1, 2); } while (1); mutex_unlock(&lock); iounmap(flash_address); return ret; } EXPORT_SYMBOL(nvt_check_preload_finish); int nvt_mmc_check_preload_finish(void) { void __iomem *mmc_address; static int mmc_ret = 0; u32 status = 0x0, io_reg = 0x0; mutex_lock(&mmc_lock); if (mmc_ret) { mutex_unlock(&mmc_lock); return mmc_ret; } mmc_address = ioremap_nocache(NVT_SDIO3_BASE_PHYS, 0x1000); if (unlikely(mmc_address == 0)) { pr_err("%s fails: ioremap_nocache fail\n", __FUNCTION__); mutex_unlock(&mmc_lock); return -1; } do { status = readl(mmc_address + SDIO_STATUS_REG_OFS); if (status & DATA_END) { mmc_ret = 1; break; } else if (status & (RSP_CRC_FAIL | DATA_CRC_FAIL | RSP_TIMEOUT | DATA_TIMEOUT | DMA_ERROR)) { pr_err("%s fails: transfer error, status(0x%x)\n", __FUNCTION__, status); mmc_ret = 0; break; } usleep_range(1, 2); } while (1); mutex_unlock(&mmc_lock); iounmap(mmc_address); return mmc_ret; } EXPORT_SYMBOL(nvt_mmc_check_preload_finish);