From 58480581725d8935a8d6101e84cb7595978f8fc5 Mon Sep 17 00:00:00 2001 From: Lan Honglin Date: Wed, 11 Oct 2023 10:36:42 +0800 Subject: [PATCH 01/31] ARM: dts: rockchip: rv1106-evb-cam: imx415 support 2lane Change-Id: I3702ee0d443270fadb5a87ea55bf9c86d90752f2 Signed-off-by: Lan Honglin --- arch/arm/boot/dts/rv1106-evb-cam.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/rv1106-evb-cam.dtsi b/arch/arm/boot/dts/rv1106-evb-cam.dtsi index 30e25864a401..d13073bb0507 100644 --- a/arch/arm/boot/dts/rv1106-evb-cam.dtsi +++ b/arch/arm/boot/dts/rv1106-evb-cam.dtsi @@ -53,7 +53,7 @@ csi_dphy_input6: endpoint@6 { reg = <6>; remote-endpoint = <&imx415_out>; - data-lanes = <1 2 3 4>; + data-lanes = <1 2>; }; }; @@ -225,7 +225,7 @@ port { imx415_out: endpoint { remote-endpoint = <&csi_dphy_input6>; - data-lanes = <1 2 3 4>; + data-lanes = <1 2>; }; }; }; From 2a81ace15bb3293054c5e7419230f0677600677a Mon Sep 17 00:00:00 2001 From: Lan Honglin Date: Mon, 9 Oct 2023 11:29:59 +0800 Subject: [PATCH 02/31] ARM: rv1106-evb.config: enable CONFIG_VIDEO_IMX415 Change-Id: I1d95a5dcd884ebcab8ce35912735fd670fc32724 Signed-off-by: Lan Honglin --- arch/arm/configs/rv1106-evb.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/rv1106-evb.config b/arch/arm/configs/rv1106-evb.config index e32ffeb8990f..7e71c6bab354 100644 --- a/arch/arm/configs/rv1106-evb.config +++ b/arch/arm/configs/rv1106-evb.config @@ -37,6 +37,7 @@ CONFIG_SPI=y CONFIG_USB_SUPPORT=y CONFIG_VFAT_FS=y CONFIG_VIDEO_GC2053=m +CONFIG_VIDEO_IMX415=m CONFIG_VIDEO_OS04A10=m CONFIG_VIDEO_SC3336=m CONFIG_VIDEO_SC4336=m From eb14307d6e686988e06419dfb6da3ce3694076db Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Sun, 24 Sep 2023 20:24:00 +0800 Subject: [PATCH 03/31] drivers: rkflash: Add mechanisms to protect bad block tables 1.Add hash check 2.Add anti-shake mechanism to avoid damaging the bad block tables 3.Add anti-shake mechanism to optimize the reliability of bad block table Change-Id: I888ceba54e5bbc55283850316e27560c484a9cf5 Signed-off-by: Jon Lin --- drivers/rkflash/sfc_nand_mtd_bbt.c | 330 ++++++++++++++++++++++------- 1 file changed, 252 insertions(+), 78 deletions(-) diff --git a/drivers/rkflash/sfc_nand_mtd_bbt.c b/drivers/rkflash/sfc_nand_mtd_bbt.c index eb641f89306c..0fce0b994654 100644 --- a/drivers/rkflash/sfc_nand_mtd_bbt.c +++ b/drivers/rkflash/sfc_nand_mtd_bbt.c @@ -21,13 +21,119 @@ #define BBT_DBG(args...) #endif +#define BBT_VERSION_INVALID (0xFFFFFFFFU) +#define BBT_VERSION_BLOCK_ABNORMAL (BBT_VERSION_INVALID - 1) +#define BBT_VERSION_MAX (BBT_VERSION_INVALID - 8) struct nanddev_bbt_info { u8 pattern[4]; unsigned int version; + u32 hash; }; static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP) +static void bbt_dbg_hex(char *s, void *buf, u32 len) +{ + print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET, 4, 4, buf, len, 0); +} +#endif + +static u32 js_hash(u8 *buf, u32 len) +{ + u32 hash = 0x47C6A7E6; + u32 i; + + for (i = 0; i < len; i++) + hash ^= ((hash << 5) + buf[i] + (hash >> 2)); + + return hash; +} + +static bool bbt_check_hash(u8 *buf, u32 len, u32 hash_cmp) +{ + u32 hash; + + /* compatible with no-hash version */ + if (hash_cmp == 0 || hash_cmp == 0xFFFFFFFF) + return 1; + + hash = js_hash(buf, len); + if (hash != hash_cmp) + return 0; + + return 1; +} + +static u32 bbt_nand_isbad_bypass(struct snand_mtd_dev *nand, u32 block) +{ + struct mtd_info *mtd = snanddev_to_mtd(nand); + + return sfc_nand_isbad_mtd(mtd, block * mtd->erasesize); +} + +static int bbt_mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) +{ + int i, ret = 0, bbt_page_num, page_addr, block; + u8 *temp_buf; + + bbt_page_num = ops->len >> mtd->writesize_shift; + block = from >> mtd->erasesize_shift; + + temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!temp_buf) + return -ENOMEM; + + page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift)); + for (i = 0; i < bbt_page_num; i++) { + ret = sfc_nand_read_page_raw(0, page_addr + i, (u32 *)temp_buf); + if (ret < 0) { + pr_err("%s fail %d\n", __func__, ret); + ret = -EIO; + goto out; + } + + memcpy(ops->datbuf + i * mtd->writesize, temp_buf, mtd->writesize); + memcpy(ops->oobbuf + i * mtd->oobsize, temp_buf + mtd->writesize, mtd->oobsize); + } + +out: + kfree(temp_buf); + + return ret; +} + +static int bbt_mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) +{ + int i, ret = 0, bbt_page_num, page_addr, block; + u8 *temp_buf; + + bbt_page_num = ops->len >> mtd->writesize_shift; + block = to >> mtd->erasesize_shift; + + temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!temp_buf) + return -ENOMEM; + + page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift)); + for (i = 0; i < bbt_page_num; i++) { + memcpy(temp_buf, ops->datbuf + i * mtd->writesize, mtd->writesize); + memcpy(temp_buf + mtd->writesize, ops->oobbuf + i * mtd->oobsize, mtd->oobsize); + + ret = sfc_nand_prog_page_raw(0, page_addr + i, (u32 *)temp_buf); + if (ret < 0) { + pr_err("%s fail %d\n", __func__, ret); + ret = -EIO; + goto out; + } + } + +out: + kfree(temp_buf); + + return ret; +} + /** * nanddev_read_bbt() - Read the BBT (Bad Block Table) * @nand: NAND device @@ -37,7 +143,7 @@ static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; * * Initialize the in-memory BBT. * - * Return: 0 in case of success, a negative error code otherwise. + * Return: positive value means success, 0 means abnornal data, a negative error code otherwise. */ static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update) { @@ -46,13 +152,12 @@ static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update) unsigned int nbytes = DIV_ROUND_UP(nblocks * bits_per_block, BITS_PER_LONG) * sizeof(*nand->bbt.cache); struct mtd_info *mtd = snanddev_to_mtd(nand); - u8 *data_buf, *oob_buf, *temp_buf; + u8 *data_buf, *oob_buf; struct nanddev_bbt_info *bbt_info; struct mtd_oob_ops ops; u32 bbt_page_num; int ret = 0; unsigned int version = 0; - u32 page_addr, i; if (!nand->bbt.cache) return -ENOMEM; @@ -85,37 +190,65 @@ static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update) ops.ooboffs = 0; /* Store one entry for each block */ - temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); - if (!temp_buf) { - kfree(data_buf); - kfree(oob_buf); - - return -ENOMEM; + ret = bbt_mtd_read_oob(mtd, block * mtd->erasesize, &ops); + if (ret && ret != -EUCLEAN) { + pr_err("read_bbt blk=%d fail=%d update=%d\n", block, ret, update); + ret = 0; + version = BBT_VERSION_BLOCK_ABNORMAL; + goto out; + } else { + ret = 0; } - page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift)); - for (i = 0; i < bbt_page_num; i++) { - ret = sfc_nand_read_page_raw(0, page_addr + i, (u32 *)temp_buf); - if (ret < 0) { - pr_err("%s fail %d\n", __func__, ret); - ret = -EIO; - kfree(temp_buf); - goto out; - } - - memcpy(ops.datbuf + i * mtd->writesize, temp_buf, mtd->writesize); - memcpy(ops.oobbuf + i * mtd->oobsize, temp_buf + mtd->writesize, mtd->oobsize); + /* bad block or good block without bbt */ + if (memcmp(bbt_pattern, bbt_info->pattern, 4)) { + ret = 0; + goto out; } - kfree(temp_buf); - if (oob_buf[0] != 0xff && !memcmp(bbt_pattern, bbt_info->pattern, 4)) - version = bbt_info->version; + /* good block with abnornal bbt */ + if (oob_buf[0] == 0xff || + !bbt_check_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4, bbt_info->hash)) { + pr_err("read_bbt check fail blk=%d ret=%d update=%d\n", block, ret, update); + ret = 0; + version = BBT_VERSION_BLOCK_ABNORMAL; + goto out; + } - BBT_DBG("read_bbt from blk=%d tag=%d ver=%d\n", block, update, version); + /* good block with good bbt */ + version = bbt_info->version; + BBT_DBG("read_bbt from blk=%d ver=%d update=%d\n", block, version, update); if (update && version > nand->bbt.version) { memcpy(nand->bbt.cache, data_buf, nbytes); nand->bbt.version = version; } +#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP) + bbt_dbg_hex("bbt", data_buf, nbytes + sizeof(struct nanddev_bbt_info)); + if (version) { + u8 *temp_buf = kzalloc(bbt_page_num * mtd->writesize, GFP_KERNEL); + bool in_scan = nand->bbt.option & NANDDEV_BBT_SCANNED; + + if (!temp_buf) + goto out; + + memcpy(temp_buf, nand->bbt.cache, nbytes); + memcpy(nand->bbt.cache, data_buf, nbytes); + + if (!in_scan) + nand->bbt.option |= NANDDEV_BBT_SCANNED; + for (block = 0; block < nblocks; block++) { + ret = snanddev_bbt_get_block_status(nand, block); + if (ret != NAND_BBT_BLOCK_GOOD) + BBT_DBG("bad block[0x%x], ret=%d\n", block, ret); + } + if (!in_scan) + nand->bbt.option &= ~NANDDEV_BBT_SCANNED; + memcpy(nand->bbt.cache, temp_buf, nbytes); + kfree(temp_buf); + ret = 0; + } +#endif + out: kfree(data_buf); kfree(oob_buf); @@ -130,12 +263,11 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block) unsigned int nbytes = DIV_ROUND_UP(nblocks * bits_per_block, BITS_PER_LONG) * sizeof(*nand->bbt.cache); struct mtd_info *mtd = snanddev_to_mtd(nand); - u8 *data_buf, *oob_buf, *temp_buf; + u8 *data_buf, *oob_buf; struct nanddev_bbt_info *bbt_info; struct mtd_oob_ops ops; u32 bbt_page_num; - int ret = 0; - u32 page_addr, i; + int ret = 0, version; BBT_DBG("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version); if (!nand->bbt.cache) @@ -164,6 +296,7 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block) memcpy(data_buf, nand->bbt.cache, nbytes); memcpy(bbt_info, bbt_pattern, 4); bbt_info->version = nand->bbt.version; + bbt_info->hash = js_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4); /* Store one entry for each block */ ret = sfc_nand_erase_mtd(mtd, block * mtd->erasesize); @@ -171,34 +304,27 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block) goto out; memset(&ops, 0, sizeof(struct mtd_oob_ops)); + ops.mode = MTD_OPS_PLACE_OOB; ops.datbuf = data_buf; ops.len = bbt_page_num * mtd->writesize; ops.oobbuf = oob_buf; ops.ooblen = bbt_page_num * mtd->oobsize; ops.ooboffs = 0; - - temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); - if (!temp_buf) { - kfree(data_buf); - kfree(oob_buf); - - return -ENOMEM; + ret = bbt_mtd_write_oob(mtd, block * mtd->erasesize, &ops); + if (ret) { + sfc_nand_erase_mtd(mtd, block * mtd->erasesize); + goto out; } - page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift)); - for (i = 0; i < bbt_page_num; i++) { - memcpy(temp_buf, ops.datbuf + i * mtd->writesize, mtd->writesize); - memcpy(temp_buf + mtd->writesize, ops.oobbuf + i * mtd->oobsize, mtd->oobsize); - ret = sfc_nand_prog_page_raw(0, page_addr + i, (u32 *)temp_buf); - if (ret < 0) { - pr_err("%s fail %d\n", __func__, ret); - ret = -EIO; - kfree(temp_buf); - goto out; - } + version = nanddev_read_bbt(nand, block, false); + if (version != bbt_info->version) { + pr_err("bbt_write fail, blk=%d recheck fail %d-%d\n", + block, version, bbt_info->version); + sfc_nand_erase_mtd(mtd, block * mtd->erasesize); + ret = -EIO; + } else { + ret = 0; } - kfree(temp_buf); - out: kfree(data_buf); kfree(oob_buf); @@ -211,13 +337,29 @@ static int nanddev_bbt_format(struct snand_mtd_dev *nand) unsigned int nblocks = snanddev_neraseblocks(nand); struct mtd_info *mtd = snanddev_to_mtd(nand); u32 start_block, block; + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block, + BITS_PER_LONG); start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS; for (block = 0; block < nblocks; block++) { - if (sfc_nand_isbad_mtd(mtd, block * mtd->erasesize)) + if (sfc_nand_isbad_mtd(mtd, block * mtd->erasesize)) { + if (bbt_nand_isbad_bypass(nand, 0)) { + memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache)); + pr_err("bbt_format fail, test good block %d fail\n", 0); + return -EIO; + } + + if (!bbt_nand_isbad_bypass(nand, block)) { + memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache)); + pr_err("bbt_format fail, test bad block %d fail\n", block); + return -EIO; + } + snanddev_bbt_set_block_status(nand, block, - NAND_BBT_BLOCK_FACTORY_BAD); + NAND_BBT_BLOCK_FACTORY_BAD); + } } for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { @@ -243,14 +385,34 @@ static int nanddev_scan_bbt(struct snand_mtd_dev *nand) nand->bbt.option |= NANDDEV_BBT_SCANNED; if (nand->bbt.version == 0) { - nanddev_bbt_format(nand); + ret = nanddev_bbt_format(nand); + if (ret) { + nand->bbt.option = 0; + pr_err("%s format fail\n", __func__); + + return ret; + } + ret = snanddev_bbt_update(nand); if (ret) { nand->bbt.option = 0; - pr_err("%s fail\n", __func__); + pr_err("%s update fail\n", __func__); + + return ret; } } +#if defined(BBT_DEBUG) + pr_err("scan_bbt success\n"); + if (nand->bbt.version) { + for (block = 0; block < nblocks; block++) { + ret = snanddev_bbt_get_block_status(nand, block); + if (ret != NAND_BBT_BLOCK_GOOD) + BBT_DBG("bad block[0x%x], ret=%d\n", block, ret); + } + } +#endif + return ret; } @@ -304,32 +466,32 @@ EXPORT_SYMBOL_GPL(snanddev_bbt_cleanup); int snanddev_bbt_update(struct snand_mtd_dev *nand) { #ifdef CONFIG_MTD_NAND_BBT_USING_FLASH + struct mtd_info *mtd = snanddev_to_mtd(nand); + if (nand->bbt.cache && nand->bbt.option & NANDDEV_BBT_USE_FLASH) { unsigned int nblocks = snanddev_neraseblocks(nand); u32 bbt_version[NANDDEV_BBT_SCAN_MAXBLOCKS]; int start_block, block; u32 min_version, block_des; - int ret, count = 0; + int ret, count = 0, status; start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS; for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { - ret = snanddev_bbt_get_block_status(nand, start_block + block); - if (ret == NAND_BBT_BLOCK_FACTORY_BAD) { - bbt_version[block] = 0xFFFFFFFF; - continue; - } - ret = nanddev_read_bbt(nand, start_block + block, - false); - if (ret < 0) - bbt_version[block] = 0xFFFFFFFF; - else if (ret == 0) - bbt_version[block] = 0; + status = snanddev_bbt_get_block_status(nand, start_block + block); + ret = nanddev_read_bbt(nand, start_block + block, false); + + if (ret == 0 && status == NAND_BBT_BLOCK_FACTORY_BAD) + bbt_version[block] = BBT_VERSION_INVALID; + else if (ret == -EIO) + bbt_version[block] = BBT_VERSION_INVALID; + else if (ret == BBT_VERSION_BLOCK_ABNORMAL) + bbt_version[block] = ret; else bbt_version[block] = ret; } get_min_ver: - min_version = 0xFFFFFFFF; + min_version = BBT_VERSION_MAX; block_des = 0; for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { if (bbt_version[block] < min_version) { @@ -338,25 +500,37 @@ get_min_ver: } } + /* Overwrite the BBT_VERSION_BLOCK_ABNORMAL block */ + if (nand->bbt.version < min_version) + nand->bbt.version = min_version + 4; + if (block_des > 0) { nand->bbt.version++; ret = nanddev_write_bbt(nand, block_des); - bbt_version[block_des - start_block] = 0xFFFFFFFF; if (ret) { - pr_err("%s blk= %d ret= %d\n", __func__, - block_des, ret); - goto get_min_ver; - } else { - count++; - if (count < 2) - goto get_min_ver; - BBT_DBG("%s success\n", __func__); - } - } else { - pr_err("%s failed\n", __func__); + pr_err("bbt_update fail, blk=%d ret= %d\n", block_des, ret); - return -1; + return -1; + } + + bbt_version[block_des - start_block] = BBT_VERSION_INVALID; + count++; + if (count < 2) + goto get_min_ver; + BBT_DBG("bbt_update success\n"); + } else { + pr_err("bbt_update failed\n"); + ret = -1; } + + for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { + if (bbt_version[block] == BBT_VERSION_BLOCK_ABNORMAL) { + block_des = start_block + block; + sfc_nand_erase_mtd(mtd, block_des * mtd->erasesize); + } + } + + return ret; } #endif return 0; From b5a6305b8b55facb5c36ba4a91eb1027dfb73b8e Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Wed, 11 Oct 2023 11:35:34 +0800 Subject: [PATCH 04/31] mtd: nand: bbt_store: Add mechanisms to protect bad block tables 1.Add hash check 2.Add anti-shake mechanism to avoid damaging the bad block tables 3.Add anti-shake mechanism to optimize the reliability of bad block table Change-Id: I468b1463677b8538c79b4ef1523ef96125f4d711 Signed-off-by: Jon Lin --- drivers/mtd/nand/bbt_store.c | 261 ++++++++++++++++++++++++++++------- 1 file changed, 213 insertions(+), 48 deletions(-) diff --git a/drivers/mtd/nand/bbt_store.c b/drivers/mtd/nand/bbt_store.c index 37b4708749d8..8687861bf3b4 100644 --- a/drivers/mtd/nand/bbt_store.c +++ b/drivers/mtd/nand/bbt_store.c @@ -8,18 +8,78 @@ #include #ifdef BBT_DEBUG -#define BBT_DBG pr_err +#define bbt_dbg pr_err #else -#define BBT_DBG(args...) +#define bbt_dbg(args...) #endif +#define BBT_VERSION_INVALID (0xFFFFFFFFU) +#define BBT_VERSION_BLOCK_ABNORMAL (BBT_VERSION_INVALID - 1) +#define BBT_VERSION_MAX (BBT_VERSION_INVALID - 8) + struct nanddev_bbt_info { u8 pattern[4]; unsigned int version; + u32 hash; }; static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP) +static void bbt_dbg_hex(char *s, void *buf, u32 len) +{ + print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET, 4, 4, buf, len, 0); +} +#endif + +static u32 js_hash(u8 *buf, u32 len) +{ + u32 hash = 0x47C6A7E6; + u32 i; + + for (i = 0; i < len; i++) + hash ^= ((hash << 5) + buf[i] + (hash >> 2)); + + return hash; +} + +static bool bbt_check_hash(u8 *buf, u32 len, u32 hash_cmp) +{ + u32 hash; + + /* compatible with no-hash version */ + if (hash_cmp == 0 || hash_cmp == 0xFFFFFFFF) + return 1; + + hash = js_hash(buf, len); + if (hash != hash_cmp) + return 0; + + return 1; +} + +static u32 bbt_nand_isbad_bypass(struct nand_device *nand, u32 block) +{ + struct mtd_info *mtd = nanddev_to_mtd(nand); + struct nand_pos pos; + + nanddev_bbt_set_block_status(nand, block, NAND_BBT_BLOCK_STATUS_UNKNOWN); + nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos); + + return nanddev_isbad(nand, &pos); +} + +/** + * nanddev_read_bbt() - Read the BBT (Bad Block Table) + * @nand: NAND device + * @block: bbt block address + * @update: true - get version and overwrite bbt.cache with new version; + * false - get bbt version only; + * + * Initialize the in-memory BBT. + * + * Return: 0 in case of success, a negative error code otherwise. + */ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update) { unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); @@ -30,7 +90,7 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update) u8 *data_buf, *oob_buf; struct nanddev_bbt_info *bbt_info; struct mtd_oob_ops ops; - int bbt_page_num; + u32 bbt_page_num; int ret = 0; unsigned int version = 0; @@ -40,7 +100,7 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update) if (block >= nblocks) return -EINVAL; - /* Aligned to page size, and even pages is better */ + /* aligned to page size, and even pages is better */ bbt_page_num = (sizeof(struct nanddev_bbt_info) + nbytes + mtd->writesize - 1) >> (ffs(mtd->writesize) - 1); bbt_page_num = (bbt_page_num + 1) / 2 * 2; @@ -64,29 +124,72 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update) ops.ooblen = bbt_page_num * mtd->oobsize; ops.ooboffs = 0; + /* store one entry for each block */ ret = mtd_read_oob(mtd, block * mtd->erasesize, &ops); if (ret && ret != -EUCLEAN) { - pr_err("%s fail %d\n", __func__, ret); - ret = -EIO; + pr_err("read_bbt blk=%d fail=%d update=%d\n", block, ret, update); + ret = 0; + version = BBT_VERSION_BLOCK_ABNORMAL; goto out; } else { ret = 0; } - if (oob_buf[0] != 0xff && !memcmp(bbt_pattern, bbt_info->pattern, 4)) - version = bbt_info->version; + /* bad block or good block without bbt */ + if (memcmp(bbt_pattern, bbt_info->pattern, 4)) { + ret = 0; + goto out; + } - BBT_DBG("read_bbt from blk=%d tag=%d ver=%d\n", block, update, version); + /* good block with abnornal bbt */ + if (oob_buf[0] == 0xff || + !bbt_check_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4, bbt_info->hash)) { + pr_err("read_bbt check fail blk=%d ret=%d update=%d\n", block, ret, update); + ret = 0; + version = BBT_VERSION_BLOCK_ABNORMAL; + goto out; + } + + /* good block with good bbt */ + version = bbt_info->version; + bbt_dbg("read_bbt from blk=%d ver=%d update=%d\n", block, version, update); if (update && version > nand->bbt.version) { memcpy(nand->bbt.cache, data_buf, nbytes); nand->bbt.version = version; } -out: - kfree(oob_buf); - kfree(data_buf); +#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP) + bbt_dbg_hex("bbt", data_buf, nbytes + sizeof(struct nanddev_bbt_info)); + if (version) { + u8 *temp_buf = kzalloc(bbt_page_num * mtd->writesize, GFP_KERNEL); + bool in_scan = nand->bbt.option & NANDDEV_BBT_SCANNED; - return ret < 0 ? -EIO : version; + if (!temp_buf) + goto out; + + memcpy(temp_buf, nand->bbt.cache, nbytes); + memcpy(nand->bbt.cache, data_buf, nbytes); + + if (!in_scan) + nand->bbt.option |= NANDDEV_BBT_SCANNED; + for (block = 0; block < nblocks; block++) { + ret = nanddev_bbt_get_block_status(nand, block); + if (ret != NAND_BBT_BLOCK_GOOD) + bbt_dbg("bad block[0x%x], ret=%d\n", block, ret); + } + if (!in_scan) + nand->bbt.option &= ~NANDDEV_BBT_SCANNED; + memcpy(nand->bbt.cache, temp_buf, nbytes); + kfree(temp_buf); + ret = 0; + } +#endif + +out: + kfree(data_buf); + kfree(oob_buf); + + return ret < 0 ? -EIO : (int)version; } static int nanddev_write_bbt(struct nand_device *nand, u32 block) @@ -99,18 +202,18 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block) u8 *data_buf, *oob_buf; struct nanddev_bbt_info *bbt_info; struct mtd_oob_ops ops; - int bbt_page_num; - int ret = 0; + u32 bbt_page_num; + int ret = 0, version; struct nand_pos pos; - BBT_DBG("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version); + bbt_dbg("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version); if (!nand->bbt.cache) return -ENOMEM; if (block >= nblocks) return -EINVAL; - /* Aligned to page size, and even pages is better */ + /* aligned to page size, and even pages is better */ bbt_page_num = (sizeof(struct nanddev_bbt_info) + nbytes + mtd->writesize - 1) >> (ffs(mtd->writesize) - 1); bbt_page_num = (bbt_page_num + 1) / 2 * 2; @@ -130,7 +233,9 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block) memcpy(data_buf, nand->bbt.cache, nbytes); memcpy(bbt_info, bbt_pattern, 4); bbt_info->version = nand->bbt.version; + bbt_info->hash = js_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4); + /* store one entry for each block */ nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos); ret = nand->ops->erase(nand, &pos); if (ret) @@ -144,10 +249,23 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block) ops.ooblen = bbt_page_num * mtd->oobsize; ops.ooboffs = 0; ret = mtd_write_oob(mtd, block * mtd->erasesize, &ops); + if (ret) { + nand->ops->erase(nand, &pos); + goto out; + } + version = nanddev_read_bbt(nand, block, false); + if (version != bbt_info->version) { + pr_err("bbt_write fail, blk=%d recheck fail %d-%d\n", + block, version, bbt_info->version); + nand->ops->erase(nand, &pos); + ret = -EIO; + } else { + ret = 0; + } out: - kfree(oob_buf); kfree(data_buf); + kfree(oob_buf); return ret; } @@ -158,14 +276,30 @@ static int nanddev_bbt_format(struct nand_device *nand) struct mtd_info *mtd = nanddev_to_mtd(nand); struct nand_pos pos; u32 start_block, block; + unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS); + unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block, + BITS_PER_LONG); start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS; for (block = 0; block < nblocks; block++) { nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos); - if (nanddev_isbad(nand, &pos)) + if (nanddev_isbad(nand, &pos)) { + if (bbt_nand_isbad_bypass(nand, 0)) { + memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache)); + pr_err("bbt_format fail, test good block %d fail\n", 0); + return -EIO; + } + + if (!bbt_nand_isbad_bypass(nand, block)) { + memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache)); + pr_err("bbt_format fail, test bad block %d fail\n", block); + return -EIO; + } + nanddev_bbt_set_block_status(nand, block, NAND_BBT_BLOCK_FACTORY_BAD); + } } for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { @@ -197,16 +331,34 @@ int nanddev_scan_bbt_in_flash(struct nand_device *nand) for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) nanddev_read_bbt(nand, start_block + block, true); + nand->bbt.option |= NANDDEV_BBT_SCANNED; if (nand->bbt.version == 0) { - nanddev_bbt_format(nand); + ret = nanddev_bbt_format(nand); + if (ret) { + nand->bbt.option = 0; + pr_err("%s format fail\n", __func__); + + return ret; + } ret = nanddev_bbt_in_flash_update(nand); if (ret) { nand->bbt.option = 0; - pr_err("%s fail\n", __func__); + pr_err("%s update fail\n", __func__); + + return ret; } } - nand->bbt.option |= NANDDEV_BBT_SCANNED; +#if defined(BBT_DEBUG) + pr_err("scan_bbt success\n"); + if (nand->bbt.version) { + for (block = 0; block < nblocks; block++) { + ret = nanddev_bbt_get_block_status(nand, block); + if (ret != NAND_BBT_BLOCK_GOOD) + bbt_dbg("bad block[0x%x], ret=%d\n", block, ret); + } + } +#endif return ret; } @@ -222,31 +374,31 @@ EXPORT_SYMBOL_GPL(nanddev_scan_bbt_in_flash); */ int nanddev_bbt_in_flash_update(struct nand_device *nand) { + struct nand_pos pos; + struct mtd_info *mtd = nanddev_to_mtd(nand); + if (nand->bbt.option & NANDDEV_BBT_SCANNED) { unsigned int nblocks = nanddev_neraseblocks(nand); u32 bbt_version[NANDDEV_BBT_SCAN_MAXBLOCKS]; int start_block, block; u32 min_version, block_des; - int ret, count = 0; + int ret, count = 0, status; start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS; for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { - ret = nanddev_bbt_get_block_status(nand, start_block + block); - if (ret == NAND_BBT_BLOCK_FACTORY_BAD) { - bbt_version[block] = 0xFFFFFFFF; - continue; - } - ret = nanddev_read_bbt(nand, start_block + block, - false); - if (ret < 0) - bbt_version[block] = 0xFFFFFFFF; - else if (ret == 0) - bbt_version[block] = 0; + status = nanddev_bbt_get_block_status(nand, start_block + block); + ret = nanddev_read_bbt(nand, start_block + block, false); + if (ret == 0 && status == NAND_BBT_BLOCK_FACTORY_BAD) + bbt_version[block] = BBT_VERSION_INVALID; + else if (ret == -EIO) + bbt_version[block] = BBT_VERSION_INVALID; + else if (ret == BBT_VERSION_BLOCK_ABNORMAL) + bbt_version[block] = ret; else bbt_version[block] = ret; } get_min_ver: - min_version = 0xFFFFFFFF; + min_version = BBT_VERSION_MAX; block_des = 0; for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { if (bbt_version[block] < min_version) { @@ -255,25 +407,38 @@ get_min_ver: } } + /* Overwrite the BBT_VERSION_BLOCK_ABNORMAL block */ + if (nand->bbt.version < min_version) + nand->bbt.version = min_version + 4; + if (block_des > 0) { nand->bbt.version++; ret = nanddev_write_bbt(nand, block_des); - bbt_version[block_des - start_block] = 0xFFFFFFFF; if (ret) { - pr_err("%s blk= %d ret= %d\n", __func__, - block_des, ret); - goto get_min_ver; - } else { - count++; - if (count < 2) - goto get_min_ver; - BBT_DBG("%s success\n", __func__); - } - } else { - pr_err("%s failed\n", __func__); + pr_err("bbt_update fail, blk=%d ret= %d\n", block_des, ret); - return -EINVAL; + return -1; + } + + bbt_version[block_des - start_block] = BBT_VERSION_INVALID; + count++; + if (count < 2) + goto get_min_ver; + bbt_dbg("bbt_update success\n"); + } else { + pr_err("bbt_update failed\n"); + ret = -1; } + + for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) { + if (bbt_version[block] == BBT_VERSION_BLOCK_ABNORMAL) { + block_des = start_block + block; + nanddev_offs_to_pos(nand, block_des * mtd->erasesize, &pos); + nand->ops->erase(nand, &pos); + } + } + + return ret; } return 0; From 718244e83a846bc2228c0499f564a9e420ee6aee Mon Sep 17 00:00:00 2001 From: XiaoDong Huang Date: Fri, 13 Oct 2023 16:43:04 +0800 Subject: [PATCH 05/31] ARM: rockchip: rv1106: sleep: save/restore pvtpll cru Signed-off-by: XiaoDong Huang Change-Id: I7bdfc573aa9d79da2b4305197d05cab50b25926c --- arch/arm/mach-rockchip/rv1106_pm.c | 6 ++++++ arch/arm/mach-rockchip/rv1106_pm.h | 1 + 2 files changed, 7 insertions(+) diff --git a/arch/arm/mach-rockchip/rv1106_pm.c b/arch/arm/mach-rockchip/rv1106_pm.c index 5b04bfda7983..1f4656f34893 100644 --- a/arch/arm/mach-rockchip/rv1106_pm.c +++ b/arch/arm/mach-rockchip/rv1106_pm.c @@ -59,6 +59,7 @@ static struct rv1106_sleep_ddr_data ddr_data; static void __iomem *pmucru_base; static void __iomem *cru_base; +static void __iomem *pvtpllcru_base; static void __iomem *pericru_base; static void __iomem *vicru_base; static void __iomem *npucru_base; @@ -105,6 +106,10 @@ static struct reg_region vd_core_reg_rgns[] = { { REG_REGION(0x300, 0x310, 4, &corecru_base, WMSK_VAL)}, { REG_REGION(0x800, 0x804, 4, &corecru_base, WMSK_VAL)}, + /* pvtpll_cru */ + { REG_REGION(0x00, 0x24, 4, &pvtpllcru_base, WMSK_VAL)}, + { REG_REGION(0x30, 0x54, 4, &pvtpllcru_base, WMSK_VAL)}, + /* core_sgrf */ { REG_REGION(0x004, 0x014, 4, &coresgrf_base, 0)}, { REG_REGION(0x000, 0x000, 4, &coresgrf_base, 0)}, @@ -1165,6 +1170,7 @@ static int __init rv1106_suspend_init(struct device_node *np) pmucru_base = dev_reg_base + RV1106_PMUCRU_OFFSET; cru_base = dev_reg_base + RV1106_CRU_OFFSET; + pvtpllcru_base = dev_reg_base + RV1106_PVTPLLCRU_OFFSET; pericru_base = dev_reg_base + RV1106_PERICRU_OFFSET; vicru_base = dev_reg_base + RV1106_VICRU_OFFSET; npucru_base = dev_reg_base + RV1106_NPUCRU_OFFSET; diff --git a/arch/arm/mach-rockchip/rv1106_pm.h b/arch/arm/mach-rockchip/rv1106_pm.h index da857a5b6fa2..6e822386ef23 100644 --- a/arch/arm/mach-rockchip/rv1106_pm.h +++ b/arch/arm/mach-rockchip/rv1106_pm.h @@ -35,6 +35,7 @@ #define RV1106_PMUCRU_OFFSET 0x3a0000 #define RV1106_CRU_OFFSET 0x3b0000 +#define RV1106_PVTPLLCRU_OFFSET 0x3b1000 #define RV1106_PERICRU_OFFSET 0x3b2000 #define RV1106_VICRU_OFFSET 0x3b4000 #define RV1106_NPUCRU_OFFSET 0x3b6000 From 6b0bd5e6b2e07a078173c2ce5230d97485614301 Mon Sep 17 00:00:00 2001 From: Huibin Hong Date: Wed, 11 Oct 2023 12:05:47 +0000 Subject: [PATCH 06/31] soc: rockchip: minidump: add backup of addr in phdr and shdr Signed-off-by: Huibin Hong Change-Id: I45b794b9f0d72a1520f3f259b1783bfac52d2f18 --- drivers/soc/rockchip/minidump/rk_minidump.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/soc/rockchip/minidump/rk_minidump.c b/drivers/soc/rockchip/minidump/rk_minidump.c index 7fa439746364..0f90fce431e2 100644 --- a/drivers/soc/rockchip/minidump/rk_minidump.c +++ b/drivers/soc/rockchip/minidump/rk_minidump.c @@ -168,6 +168,8 @@ static void md_update_ss_toc(const struct md_region *entry) shdr->sh_flags = SHF_WRITE; shdr->sh_offset = minidump_elfheader.elf_offset; shdr->sh_entsize = 0; + shdr->sh_addralign = shdr->sh_addr; /* backup */ + shdr->sh_entsize = entry->phys_addr; /* backup */ if (strstr((const char *)mdr->name, "note")) phdr->p_type = PT_NOTE; @@ -178,6 +180,7 @@ static void md_update_ss_toc(const struct md_region *entry) phdr->p_paddr = entry->phys_addr; phdr->p_filesz = phdr->p_memsz = mdr->region_size; phdr->p_flags = PF_R | PF_W; + phdr->p_align = phdr->p_paddr; /* backup */ minidump_elfheader.elf_offset += shdr->sh_size; mdr->md_valid = MD_REGION_VALID; minidump_table.md_ss_toc->ss_region_count++; @@ -274,8 +277,11 @@ int rk_minidump_update_region(int regno, const struct md_region *entry) phdr = elf_program(hdr, regno + 1); shdr->sh_addr = (elf_addr_t)entry->virt_addr; + shdr->sh_addralign = shdr->sh_addr; /* backup */ + shdr->sh_entsize = entry->phys_addr; /* backup */ phdr->p_vaddr = entry->virt_addr; phdr->p_paddr = entry->phys_addr; + phdr->p_align = phdr->p_paddr; /* backup */ err_unlock: read_unlock_irqrestore(&mdt_remove_lock, flags); @@ -675,6 +681,8 @@ static int rk_minidump_driver_probe(struct platform_device *pdev) phdr = (Elf64_Phdr *)(md_elf_mem + (ulong)ehdr->e_phoff); phdr += ehdr->e_phnum - 1; md_elf_size = phdr->p_memsz + phdr->p_offset; + if (md_elf_size > r_size) + md_elf_size = r_size; pr_info("Create /proc/rk_md/minidump, size:0x%llx...\n", md_elf_size); proc_rk_minidump = proc_create("minidump", 0400, base_dir, &rk_minidump_proc_ops); } else { From 7fe4c669e7cc59cb7ba2afdfc6bd2049df8e049d Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Fri, 8 Sep 2023 11:25:34 +0800 Subject: [PATCH 07/31] media: rockchip: isp: add RKISP_VICAP_CMD_QUICK_STREAM CMD Signed-off-by: Zefa Chen Change-Id: I37f52db2ac2a1a72e1ddc046d37db104e2d76d00 --- drivers/media/platform/rockchip/isp/isp_external.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/rockchip/isp/isp_external.h b/drivers/media/platform/rockchip/isp/isp_external.h index 6e117d40cd4b..3fc155fd03c4 100644 --- a/drivers/media/platform/rockchip/isp/isp_external.h +++ b/drivers/media/platform/rockchip/isp/isp_external.h @@ -13,6 +13,9 @@ #define RKISP_VICAP_CMD_RX_BUFFER_FREE \ _IOW('V', BASE_VIDIOC_PRIVATE + 2, struct rkisp_rx_buf) +#define RKISP_VICAP_CMD_QUICK_STREAM \ + _IOW('V', BASE_VIDIOC_PRIVATE + 3, int) + #define RKISP_VICAP_BUF_CNT 3 #define RKISP_VICAP_BUF_CNT_MAX 8 #define RKISP_RX_BUF_POOL_MAX (RKISP_VICAP_BUF_CNT_MAX * 3) From 30c7740c9b469f6865262e3ccd7df0cba083d061 Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Sun, 8 Oct 2023 14:49:28 +0800 Subject: [PATCH 08/31] media: rockchip: isp: support suspend and resume Change-Id: I92e73c82b389d75f9df0f804a950bcaec679fba3 Signed-off-by: Cai YiWei --- .../media/platform/rockchip/isp/capture_v21.c | 12 +- .../media/platform/rockchip/isp/capture_v30.c | 11 +- drivers/media/platform/rockchip/isp/dev.c | 73 ++++- drivers/media/platform/rockchip/isp/dev.h | 4 + drivers/media/platform/rockchip/isp/hw.c | 276 ++++++++++++++++-- drivers/media/platform/rockchip/isp/hw.h | 4 +- .../media/platform/rockchip/isp/isp_params.c | 15 +- .../media/platform/rockchip/isp/isp_params.h | 2 +- .../platform/rockchip/isp/isp_params_v21.c | 28 +- .../platform/rockchip/isp/isp_params_v2x.c | 17 +- .../platform/rockchip/isp/isp_params_v32.c | 41 ++- .../platform/rockchip/isp/isp_params_v3x.c | 23 +- drivers/media/platform/rockchip/isp/rkisp.c | 135 +-------- 13 files changed, 421 insertions(+), 220 deletions(-) diff --git a/drivers/media/platform/rockchip/isp/capture_v21.c b/drivers/media/platform/rockchip/isp/capture_v21.c index 67cb9f61b70d..4a0e2927cdcf 100644 --- a/drivers/media/platform/rockchip/isp/capture_v21.c +++ b/drivers/media/platform/rockchip/isp/capture_v21.c @@ -1225,6 +1225,15 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state) struct vb2_buffer *vb2_buf = &stream->curr_buf->vb.vb2_buf; u64 ns = 0; + if (stream->skip_frame) { + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + list_add_tail(&stream->curr_buf->queue, &stream->buf_queue); + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + if (stream->skip_frame) + stream->skip_frame--; + goto end; + } + /* Dequeue a filled buffer */ for (i = 0; i < isp_fmt->mplanes; i++) { u32 payload_size = @@ -1287,6 +1296,7 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state) stream->curr_buf = NULL; } +end: if (!interlaced || (stream->curr_buf == stream->next_buf && stream->u.sp.field == RKISP_FIELD_ODD)) { @@ -1505,7 +1515,7 @@ static int rkisp_start(struct rkisp_stream *stream) if (stream->id == RKISP_STREAM_MP || stream->id == RKISP_STREAM_SP) hdr_config_dmatx(dev); stream->streaming = true; - + stream->skip_frame = 0; return 0; } diff --git a/drivers/media/platform/rockchip/isp/capture_v30.c b/drivers/media/platform/rockchip/isp/capture_v30.c index 5f6616cdb031..b2d7490b4762 100644 --- a/drivers/media/platform/rockchip/isp/capture_v30.c +++ b/drivers/media/platform/rockchip/isp/capture_v30.c @@ -977,6 +977,15 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state) struct vb2_buffer *vb2_buf = &buf->vb.vb2_buf; u64 ns = 0; + if (stream->skip_frame) { + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + list_add_tail(&buf->queue, &stream->buf_queue); + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + if (stream->skip_frame) + stream->skip_frame--; + goto end; + } + /* Dequeue a filled buffer */ for (i = 0; i < isp_fmt->mplanes; i++) { u32 payload_size = stream->out_fmt.plane_fmt[i].sizeimage; @@ -1097,7 +1106,7 @@ static int rkisp_start(struct rkisp_stream *stream) stream->ops->enable_mi(stream); stream->streaming = true; - + stream->skip_frame = 0; return 0; } diff --git a/drivers/media/platform/rockchip/isp/dev.c b/drivers/media/platform/rockchip/isp/dev.c index 7da2c73b01fa..ed427c7ce3bf 100644 --- a/drivers/media/platform/rockchip/isp/dev.c +++ b/drivers/media/platform/rockchip/isp/dev.c @@ -1006,9 +1006,78 @@ static int __init rkisp_clr_unready_dev(void) late_initcall_sync(rkisp_clr_unready_dev); #endif +static int rkisp_pm_prepare(struct device *dev) +{ + struct rkisp_device *isp_dev = dev_get_drvdata(dev); + struct rkisp_hw_dev *hw = isp_dev->hw_dev; + struct rkisp_pipeline *p = &isp_dev->pipe; + unsigned long lock_flags = 0; + int i, on = 0, time = 100; + + if (isp_dev->isp_state & ISP_STOP) + return 0; + + isp_dev->suspend_sync = false; + isp_dev->is_suspend = true; + if (isp_dev->isp_inp & INP_CSI || + isp_dev->isp_inp & INP_DVP || isp_dev->isp_inp & INP_LVDS) { + for (i = p->num_subdevs - 1; i >= 0; i--) + v4l2_subdev_call(p->subdevs[i], video, s_stream, on); + } else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) { + v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_QUICK_STREAM, &on); + } + if (IS_HDR_RDBK(isp_dev->rd_mode)) { + spin_lock_irqsave(&hw->rdbk_lock, lock_flags); + if (!hw->is_idle && hw->cur_dev_id == isp_dev->dev_id) + isp_dev->suspend_sync = true; + spin_unlock_irqrestore(&hw->rdbk_lock, lock_flags); + } else { + /* wait one frame for online */ + isp_dev->suspend_sync = true; + if (hw->isp_size[isp_dev->dev_id].fps) + time = 1000 / hw->isp_size[isp_dev->dev_id].fps; + } + + if (isp_dev->suspend_sync) { + wait_for_completion_timeout(&isp_dev->pm_cmpl, msecs_to_jiffies(time)); + isp_dev->suspend_sync = false; + } + return 0; +} + +static void rkisp_pm_complete(struct device *dev) +{ + struct rkisp_device *isp_dev = dev_get_drvdata(dev); + struct rkisp_hw_dev *hw = isp_dev->hw_dev; + struct rkisp_pipeline *p = &isp_dev->pipe; + struct rkisp_stream *stream; + int i, on = 1; + + if (isp_dev->isp_state & ISP_STOP) + return; + + isp_dev->is_suspend = false; + isp_dev->isp_state = ISP_START | ISP_FRAME_END; + for (i = 0; i < RKISP_MAX_STREAM; i++) { + stream = &isp_dev->cap_dev.stream[i]; + if (i == RKISP_STREAM_VIR || !stream->streaming) + continue; + stream->skip_frame = 1; + } + if (hw->cur_dev_id == isp_dev->dev_id) + rkisp_rdbk_trigger_event(isp_dev, T_CMD_QUEUE, NULL); + if (isp_dev->isp_inp & INP_CSI || + isp_dev->isp_inp & INP_DVP || isp_dev->isp_inp & INP_LVDS) { + for (i = 0; i < p->num_subdevs; i++) + v4l2_subdev_call(p->subdevs[i], video, s_stream, on); + } else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) { + v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_QUICK_STREAM, &on); + } +} + static const struct dev_pm_ops rkisp_plat_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + .prepare = rkisp_pm_prepare, + .complete = rkisp_pm_complete, SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, rkisp_runtime_resume, NULL) }; diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index 4510f9ea04aa..fbd1b49e22a0 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -246,6 +246,8 @@ struct rkisp_device { struct rkisp_ispp_buf *cur_fbcgain; struct rkisp_buffer *cur_spbuf; + struct completion pm_cmpl; + struct work_struct rdbk_work; struct kfifo rdbk_kfifo; spinlock_t rdbk_lock; @@ -269,6 +271,8 @@ struct rkisp_device { bool is_first_double; bool is_probe_end; bool is_frame_double; + bool is_suspend; + bool suspend_sync; struct rkisp_vicap_input vicap_in; diff --git a/drivers/media/platform/rockchip/isp/hw.c b/drivers/media/platform/rockchip/isp/hw.c index d9d1627f6de5..0d1adcb31454 100644 --- a/drivers/media/platform/rockchip/isp/hw.c +++ b/drivers/media/platform/rockchip/isp/hw.c @@ -35,6 +35,12 @@ * rkisp_hw */ +struct backup_reg { + const u32 base; + const u32 shd; + u32 val; +}; + struct isp_irqs_data { const char *name; irqreturn_t (*irq_hdl)(int irq, void *ctx); @@ -348,6 +354,191 @@ int rkisp_register_irq(struct rkisp_hw_dev *hw_dev) return 0; } +void rkisp_hw_reg_save(struct rkisp_hw_dev *dev) +{ + void *buf = dev->sw_reg; + + memcpy_fromio(buf, dev->base_addr, RKISP_ISP_SW_REG_SIZE); + if (dev->unite == ISP_UNITE_TWO) { + buf += RKISP_ISP_SW_REG_SIZE; + memcpy_fromio(buf, dev->base_next_addr, RKISP_ISP_SW_REG_SIZE); + } +} + +void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) +{ + struct rkisp_device *isp = dev->isp[dev->cur_dev_id]; + void __iomem *base = dev->base_addr; + void *reg_buf = dev->sw_reg; + u32 val, *reg, *reg1, i, j; + u32 self_upd_reg[] = { + ISP21_BAY3D_BASE, ISP21_DRC_BASE, ISP3X_BAY3D_CTRL, + ISP_DHAZ_CTRL, ISP3X_3DLUT_BASE, ISP_RAWAE_LITE_BASE, + RAWAE_BIG1_BASE, RAWAE_BIG2_BASE, RAWAE_BIG3_BASE, + ISP_RAWHIST_LITE_BASE, ISP_RAWHIST_BIG1_BASE, + ISP_RAWHIST_BIG2_BASE, ISP_RAWHIST_BIG3_BASE, + ISP_RAWAF_BASE, ISP_RAWAWB_BASE, + }; + struct backup_reg backup[] = { + { + .base = MI_MP_WR_Y_BASE, + .shd = MI_MP_WR_Y_BASE_SHD, + }, { + .base = MI_MP_WR_CB_BASE, + .shd = MI_MP_WR_CB_BASE_SHD, + }, { + .base = MI_MP_WR_CR_BASE, + .shd = MI_MP_WR_CR_BASE_SHD, + }, { + .base = MI_SP_WR_Y_BASE, + .shd = MI_SP_WR_Y_BASE_SHD, + }, { + .base = MI_SP_WR_CB_BASE, + .shd = MI_SP_WR_CB_BASE_AD_SHD, + }, { + .base = MI_SP_WR_CR_BASE, + .shd = MI_SP_WR_CR_BASE_AD_SHD, + }, { + .base = ISP3X_MI_BP_WR_Y_BASE, + .shd = ISP3X_MI_BP_WR_Y_BASE_SHD, + }, { + .base = ISP3X_MI_BP_WR_CB_BASE, + .shd = ISP3X_MI_BP_WR_CB_BASE_SHD, + }, { + .base = ISP32_MI_MPDS_WR_Y_BASE, + .shd = ISP32_MI_MPDS_WR_Y_BASE_SHD, + }, { + .base = ISP32_MI_MPDS_WR_CB_BASE, + .shd = ISP32_MI_MPDS_WR_CB_BASE_SHD, + }, { + .base = ISP32_MI_BPDS_WR_Y_BASE, + .shd = ISP32_MI_BPDS_WR_Y_BASE_SHD, + }, { + .base = ISP32_MI_BPDS_WR_CB_BASE, + .shd = ISP32_MI_BPDS_WR_CB_BASE_SHD, + }, { + .base = MI_RAW0_WR_BASE, + .shd = MI_RAW0_WR_BASE_SHD, + }, { + .base = MI_RAW1_WR_BASE, + .shd = MI_RAW1_WR_BASE_SHD, + }, { + .base = MI_RAW2_WR_BASE, + .shd = MI_RAW2_WR_BASE_SHD, + }, { + .base = MI_RAW3_WR_BASE, + .shd = MI_RAW3_WR_BASE_SHD, + }, { + .base = MI_RAW0_RD_BASE, + .shd = MI_RAW0_RD_BASE_SHD, + }, { + .base = MI_RAW1_RD_BASE, + .shd = MI_RAW1_RD_BASE_SHD, + }, { + .base = MI_RAW2_RD_BASE, + .shd = MI_RAW2_RD_BASE_SHD, + }, { + .base = MI_GAIN_WR_BASE, + .shd = MI_GAIN_WR_BASE_SHD, + } + }; + + for (i = 0; i <= !!dev->unite; i++) { + if (dev->unite != ISP_UNITE_TWO && i) + break; + + if (i) { + reg_buf += RKISP_ISP_SW_REG_SIZE; + base = dev->base_next_addr; + } + + /* process special reg */ + for (j = 0; j < ARRAY_SIZE(self_upd_reg); j++) { + reg = reg_buf + self_upd_reg[j]; + *reg &= ~ISP21_SELF_FORCE_UPD; + if (self_upd_reg[j] == ISP3X_3DLUT_BASE && *reg & ISP_3DLUT_EN) { + reg = reg_buf + ISP3X_3DLUT_UPDATE; + *reg = 1; + } + } + reg = reg_buf + ISP_CTRL; + *reg &= ~(CIF_ISP_CTRL_ISP_ENABLE | + CIF_ISP_CTRL_ISP_INFORM_ENABLE | + CIF_ISP_CTRL_ISP_CFG_UPD); + reg = reg_buf + MI_WR_INIT; + *reg = 0; + reg = reg_buf + CSI2RX_CTRL0; + *reg &= ~SW_CSI2RX_EN; + for (j = 0; j < RKISP_ISP_SW_REG_SIZE; j += 4) { + /* skip table RAM */ + if ((j > ISP3X_LSC_CTRL && j < ISP3X_LSC_XGRAD_01) || + (j > ISP32_CAC_OFFSET && j < ISP3X_CAC_RO_CNT) || + (j > ISP3X_3DLUT_UPDATE && j < ISP3X_GAIN_BASE) || + (j == 0x4840 || j == 0x4a80 || j == 0x4b40 || j == 0x5660)) + continue; + /* skip mmu range */ + if (dev->isp_ver < ISP_V30 && + j > ISP21_MI_BAY3D_RD_BASE_SHD && j < CSI2RX_CTRL0) + continue; + /* reg value of read diff to write */ + if (j == ISP_MPFBC_CTRL || + j == ISP32_ISP_AWB1_GAIN_G || j == ISP32_ISP_AWB1_GAIN_RB) + reg = isp->sw_base_addr + j; + else + reg = reg_buf + j; + writel(*reg, base + j); + } + + /* config shd_reg to base_reg */ + for (j = 0; j < ARRAY_SIZE(backup); j++) { + reg = reg_buf + backup[j].base; + reg1 = reg_buf + backup[j].shd; + backup[j].val = *reg; + writel(*reg1, base + backup[j].base); + } + + /* update module */ + reg = reg_buf + DUAL_CROP_CTRL; + if (*reg & 0xf) + writel(*reg | CIF_DUAL_CROP_CFG_UPD, base + DUAL_CROP_CTRL); + reg = reg_buf + SELF_RESIZE_CTRL; + if (*reg & 0xf) { + if (dev->isp_ver == ISP_V32_L) + writel(*reg | ISP32_SCALE_FORCE_UPD, base + ISP32_SELF_SCALE_UPDATE); + else + writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + SELF_RESIZE_CTRL); + } + reg = reg_buf + MAIN_RESIZE_CTRL; + if (*reg & 0xf) + writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + MAIN_RESIZE_CTRL); + reg = reg_buf + ISP32_BP_RESIZE_CTRL; + if (*reg & 0xf) + writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + ISP32_BP_RESIZE_CTRL); + + /* update mi and isp, base_reg will update to shd_reg */ + writel(CIF_MI_INIT_SOFT_UPD, base + MI_WR_INIT); + + /* config base_reg */ + for (j = 0; j < ARRAY_SIZE(backup); j++) + writel(backup[j].val, base + backup[j].base); + /* base_reg = shd_reg, write is base but read is shd */ + val = rkisp_read_reg_cache(isp, ISP_MPFBC_HEAD_PTR); + writel(val, base + ISP_MPFBC_HEAD_PTR); + val = rkisp_read_reg_cache(isp, MI_SWS_3A_WR_BASE); + writel(val, base + MI_SWS_3A_WR_BASE); + } + + rkisp_params_cfgsram(&isp->params_vdev, false); + + reg = reg_buf + ISP_CTRL; + *reg |= CIF_ISP_CTRL_ISP_ENABLE | + CIF_ISP_CTRL_ISP_CFG_UPD | + CIF_ISP_CTRL_ISP_INFORM_ENABLE; + writel(*reg, dev->base_addr + ISP_CTRL); + if (dev->unite == ISP_UNITE_TWO) + writel(*reg, dev->base_next_addr + ISP_CTRL); +} + static const char * const rk3562_isp_clks[] = { "clk_isp_core", "aclk_isp", @@ -779,7 +970,6 @@ static void disable_sys_clk(struct rkisp_hw_dev *dev) static int enable_sys_clk(struct rkisp_hw_dev *dev) { int i, ret = -EINVAL; - unsigned long rate; for (i = 0; i < dev->num_clks; i++) { if (!IS_ERR(dev->clks[i])) { @@ -789,12 +979,6 @@ static int enable_sys_clk(struct rkisp_hw_dev *dev) } } - if (!dev->is_assigned_clk) { - rate = dev->clk_rate_tbl[0].clk_rate * 1000000UL; - rkisp_set_clk_rate(dev->clks[0], rate); - if (dev->unite == ISP_UNITE_TWO) - rkisp_set_clk_rate(dev->clks[5], rate); - } rkisp_soft_reset(dev, false); isp_config_clk(dev, true); return 0; @@ -851,19 +1035,24 @@ static int rkisp_hw_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct rkisp_hw_dev *hw_dev; struct resource *res; - int i, ret; + int i, ret, mult = 1; bool is_mem_reserved = true; u32 clk_rate = 0; match = of_match_node(rkisp_hw_of_match, node); if (IS_ERR(match)) return PTR_ERR(match); + match_data = match->data; hw_dev = devm_kzalloc(dev, sizeof(*hw_dev), GFP_KERNEL); if (!hw_dev) return -ENOMEM; - match_data = match->data; + if (match_data->unite) + mult = 2; + hw_dev->sw_reg = devm_kzalloc(dev, RKISP_ISP_SW_REG_SIZE * mult, GFP_KERNEL); + if (!hw_dev->sw_reg) + return -ENOMEM; dev_set_drvdata(dev, hw_dev); hw_dev->dev = dev; hw_dev->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); @@ -1041,11 +1230,23 @@ static void rkisp_hw_shutdown(struct platform_device *pdev) static int __maybe_unused rkisp_runtime_suspend(struct device *dev) { struct rkisp_hw_dev *hw_dev = dev_get_drvdata(dev); + int i; - hw_dev->dev_link_num = 0; - hw_dev->is_single = true; - hw_dev->is_multi_overflow = false; - hw_dev->is_frm_buf = false; + hw_dev->is_idle = true; + if (dev->power.runtime_status) { + hw_dev->dev_link_num = 0; + hw_dev->is_single = true; + hw_dev->is_multi_overflow = false; + hw_dev->is_frm_buf = false; + } else { + /* system suspend */ + for (i = 0; i < hw_dev->dev_num; i++) { + if (hw_dev->isp_size[i].is_on) { + rkisp_hw_reg_save(hw_dev); + break; + } + } + } disable_sys_clk(hw_dev); return pinctrl_pm_select_sleep_state(dev); } @@ -1108,28 +1309,45 @@ static int __maybe_unused rkisp_runtime_resume(struct device *dev) return ret; enable_sys_clk(hw_dev); - for (i = 0; i < hw_dev->dev_num; i++) { - isp = hw_dev->isp[i]; - if (!isp || !isp->sw_base_addr) - continue; - buf = isp->sw_base_addr; - memset(buf, 0, RKISP_ISP_SW_MAX_SIZE * mult); - memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE); - if (hw_dev->unite) { - buf += RKISP_ISP_SW_MAX_SIZE; - base = hw_dev->base_next_addr; - memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE); + if (dev->power.runtime_status) { + if (!hw_dev->is_assigned_clk) { + unsigned long rate = hw_dev->clk_rate_tbl[0].clk_rate * 1000000UL; + + rkisp_set_clk_rate(hw_dev->clks[0], rate); + if (hw_dev->unite == ISP_UNITE_TWO) + rkisp_set_clk_rate(hw_dev->clks[5], rate); + } + for (i = 0; i < hw_dev->dev_num; i++) { + isp = hw_dev->isp[i]; + if (!isp || !isp->sw_base_addr) + continue; + buf = isp->sw_base_addr; + memset(buf, 0, RKISP_ISP_SW_MAX_SIZE * mult); + memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE); + if (hw_dev->unite) { + buf += RKISP_ISP_SW_MAX_SIZE; + base = hw_dev->base_next_addr; + memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE); + } + default_sw_reg_flag(hw_dev->isp[i]); + } + rkisp_hw_enum_isp_size(hw_dev); + hw_dev->monitor.is_en = rkisp_monitor; + } else { + /* system resume */ + for (i = 0; i < hw_dev->dev_num; i++) { + if (hw_dev->isp_size[i].is_on) { + rkisp_hw_reg_restore(hw_dev); + break; + } } - default_sw_reg_flag(hw_dev->isp[i]); } - rkisp_hw_enum_isp_size(hw_dev); - hw_dev->monitor.is_en = rkisp_monitor; return 0; } static const struct dev_pm_ops rkisp_hw_pm_ops = { - SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, - rkisp_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, rkisp_runtime_resume, NULL) }; static struct platform_driver rkisp_hw_drv = { diff --git a/drivers/media/platform/rockchip/isp/hw.h b/drivers/media/platform/rockchip/isp/hw.h index 5c7129463101..657c77c0f937 100644 --- a/drivers/media/platform/rockchip/isp/hw.h +++ b/drivers/media/platform/rockchip/isp/hw.h @@ -29,7 +29,6 @@ struct rkisp_monitor { struct rkisp_hw_dev *dev; struct work_struct work; struct completion cmpl; - int (*reset_handle)(struct rkisp_device *dev); u32 state; u8 retry; bool is_en; @@ -53,6 +52,7 @@ struct rkisp_hw_dev { struct platform_device *pdev; struct device *dev; struct regmap *grf; + void *sw_reg; void __iomem *base_addr; void __iomem *base_next_addr; struct clk *clks[RKISP_MAX_BUS_CLK]; @@ -110,4 +110,6 @@ struct rkisp_hw_dev { int rkisp_register_irq(struct rkisp_hw_dev *dev); void rkisp_soft_reset(struct rkisp_hw_dev *dev, bool is_secure); void rkisp_hw_enum_isp_size(struct rkisp_hw_dev *hw_dev); +void rkisp_hw_reg_save(struct rkisp_hw_dev *dev); +void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev); #endif diff --git a/drivers/media/platform/rockchip/isp/isp_params.c b/drivers/media/platform/rockchip/isp/isp_params.c index 3db85a23c220..4b7bb64d65fa 100644 --- a/drivers/media/platform/rockchip/isp/isp_params.c +++ b/drivers/media/platform/rockchip/isp/isp_params.c @@ -368,15 +368,16 @@ void rkisp_params_cfg(struct rkisp_isp_params_vdev *params_vdev, u32 frame_id) params_vdev->ops->param_cfg(params_vdev, frame_id, RKISP_PARAMS_IMD); } -void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev) +void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev, bool is_check) { - if (params_vdev->dev->procfs.mode & RKISP_PROCFS_FIL_SW) - return; - - /* multi device to switch sram config */ - if (params_vdev->dev->hw_dev->is_single) - return; + if (is_check) { + if (params_vdev->dev->procfs.mode & RKISP_PROCFS_FIL_SW) + return; + /* multi device to switch sram config */ + if (params_vdev->dev->hw_dev->is_single) + return; + } if (params_vdev->ops->param_cfgsram) params_vdev->ops->param_cfgsram(params_vdev); } diff --git a/drivers/media/platform/rockchip/isp/isp_params.h b/drivers/media/platform/rockchip/isp/isp_params.h index d38c0dffb6bf..2d58aba98d16 100644 --- a/drivers/media/platform/rockchip/isp/isp_params.h +++ b/drivers/media/platform/rockchip/isp/isp_params.h @@ -140,7 +140,7 @@ void rkisp_params_isr(struct rkisp_isp_params_vdev *params_vdev, u32 isp_mis); void rkisp_params_cfg(struct rkisp_isp_params_vdev *params_vdev, u32 frame_id); -void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev); +void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev, bool is_check); void rkisp_params_get_meshbuf_inf(struct rkisp_isp_params_vdev *params_vdev, void *meshbuf); int rkisp_params_set_meshbuf_size(struct rkisp_isp_params_vdev *params_vdev, void *meshsize); void rkisp_params_meshbuf_free(struct rkisp_isp_params_vdev *params_vdev, u64 id); diff --git a/drivers/media/platform/rockchip/isp/isp_params_v21.c b/drivers/media/platform/rockchip/isp/isp_params_v21.c index 19f2a6228499..509554d63532 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v21.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v21.c @@ -460,10 +460,9 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, { int i, j; unsigned int sram_addr; - unsigned int data; + unsigned int data = rkisp_ioread32(params_vdev, ISP_LSC_CTRL); - if (is_check && - !(rkisp_ioread32(params_vdev, ISP_LSC_CTRL) & ISP_LSC_EN)) + if (is_check && (data & ISP_LSC_LUT_EN || !(data & ISP_LSC_EN))) return; /* CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ @@ -603,12 +602,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev, * readback mode lsc lut AHB config to sram, once for single device, * need record to switch for multi-device. */ - if (!IS_HDR_RDBK(dev->rd_mode)) + if (!IS_HDR_RDBK(dev->rd_mode)) { isp_lsc_matrix_cfg_ddr(params_vdev, arg); - else if (dev->hw_dev->is_single) - isp_lsc_matrix_cfg_sram(params_vdev, arg, false); - else + } else { + if (dev->hw_dev->is_single) + isp_lsc_matrix_cfg_sram(params_vdev, arg, false); params_rec->others.lsc_cfg = *arg; + } for (i = 0; i < 4; i++) { /* program x size tables */ @@ -1327,8 +1327,8 @@ isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, (arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | (arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | (arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24, - rkisp_iowrite32(params_vdev, val, ISP21_RAWAWB_WRAM_DATA_BASE); + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24; + rkisp_write(params_vdev->dev, ISP21_RAWAWB_WRAM_DATA_BASE, val, true); } } @@ -2143,10 +2143,9 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev, if (params_vdev->dev->hw_dev->is_single) isp_rawawb_cfg_sram(params_vdev, arg, false); - else - memcpy(arg_rec->sw_rawawb_wp_blk_wei_w, - arg->sw_rawawb_wp_blk_wei_w, - ISP21_RAWAWB_WEIGHT_NUM); + memcpy(arg_rec->sw_rawawb_wp_blk_wei_w, + arg->sw_rawawb_wp_blk_wei_w, + ISP21_RAWAWB_WEIGHT_NUM); /* avoid to override the old enable value */ value = rkisp_ioread32(params_vdev, ISP21_RAWAWB_CTRL); @@ -2370,8 +2369,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev, if (dev->hw_dev->is_single) isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false); - else - *arg_rec = *arg; + *arg_rec = *arg; } static void diff --git a/drivers/media/platform/rockchip/isp/isp_params_v2x.c b/drivers/media/platform/rockchip/isp/isp_params_v2x.c index b4525b378a6a..2877ab1d2fd8 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v2x.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v2x.c @@ -536,10 +536,9 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, { int i, j; unsigned int sram_addr; - unsigned int data; + unsigned int data = rkisp_ioread32(params_vdev, ISP_LSC_CTRL); - if (is_check && - !(rkisp_ioread32(params_vdev, ISP_LSC_CTRL) & ISP_LSC_EN)) + if (is_check && (data & ISP_LSC_LUT_EN || !(data & ISP_LSC_EN))) return; /* CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ @@ -679,12 +678,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev, * readback mode lsc lut AHB config to sram, once for single device, * need record to switch for multi-device. */ - if (!IS_HDR_RDBK(dev->rd_mode)) + if (!IS_HDR_RDBK(dev->rd_mode)) { isp_lsc_matrix_cfg_ddr(params_vdev, arg); - else if (dev->hw_dev->is_single) - isp_lsc_matrix_cfg_sram(params_vdev, arg, false); - else + } else { params_rec->others.lsc_cfg = *arg; + if (dev->hw_dev->is_single) + isp_lsc_matrix_cfg_sram(params_vdev, arg, false); + } for (i = 0; i < 4; i++) { /* program x size tables */ @@ -2910,8 +2910,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev, if (dev->hw_dev->is_single) isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false); - else - *arg_rec = *arg; + *arg_rec = *arg; } static void diff --git a/drivers/media/platform/rockchip/isp/isp_params_v32.c b/drivers/media/platform/rockchip/isp/isp_params_v32.c index 4343412c111c..255451cf7fee 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v32.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v32.c @@ -555,11 +555,11 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, bool is_check, u32 id) { struct rkisp_device *dev = params_vdev->dev; - u32 sram_addr, data, table; + u32 data = isp3_param_read(params_vdev, ISP3X_LSC_CTRL, id); + u32 sram_addr, table; int i, j; - if (is_check && - !(isp3_param_read(params_vdev, ISP3X_LSC_CTRL, id) & ISP_LSC_EN)) + if (is_check && (data & ISP3X_LSC_LUT_EN || !(data & ISP_LSC_EN))) return; table = isp3_param_read_direct(params_vdev, ISP3X_LSC_STATUS); @@ -643,12 +643,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev, * readback mode lsc lut AHB config to sram, once for single device, * need record to switch for multi-device. */ - if (!IS_HDR_RDBK(dev->rd_mode)) + if (!IS_HDR_RDBK(dev->rd_mode)) { isp_lsc_matrix_cfg_ddr(params_vdev, arg); - else if (dev->hw_dev->is_single) - isp_lsc_matrix_cfg_sram(params_vdev, arg, false, id); - else + } else { + if (dev->hw_dev->is_single) + isp_lsc_matrix_cfg_sram(params_vdev, arg, false, id); params_rec->others.lsc_cfg = *arg; + } } else { /* two lsc sram table */ params_rec->others.lsc_cfg = *arg; @@ -1576,20 +1577,19 @@ static void isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, const struct isp32_rawawb_meas_cfg *arg, bool is_check, u32 id) { - u32 i, val = ISP32_MODULE_EN; + u32 i, val = isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id); - if (params_vdev->dev->isp_ver == ISP_V32 && is_check && - !(isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id) & val)) + if (params_vdev->dev->isp_ver != ISP_V32 || + (is_check && !(val & ISP32_MODULE_EN))) return; for (i = 0; i < ISP32_RAWAWB_WEIGHT_NUM / 5; i++) { - isp3_param_write_direct(params_vdev, - (arg->wp_blk_wei_w[5 * i] & 0x3f) | - (arg->wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | - (arg->wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | - (arg->wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | - (arg->wp_blk_wei_w[5 * i + 4] & 0x3f) << 24, - ISP3X_RAWAWB_WRAM_DATA_BASE); + val = (arg->wp_blk_wei_w[5 * i] & 0x3f) | + (arg->wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | + (arg->wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | + (arg->wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | + (arg->wp_blk_wei_w[5 * i + 4] & 0x3f) << 24; + isp3_param_write_direct(params_vdev, val, ISP3X_RAWAWB_WRAM_DATA_BASE); } } @@ -2255,9 +2255,7 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev, if (params_vdev->dev->isp_ver == ISP_V32) { if (params_vdev->dev->hw_dev->is_single) isp_rawawb_cfg_sram(params_vdev, arg, false, id); - else - memcpy(arg_rec->wp_blk_wei_w, arg->wp_blk_wei_w, - ISP32_RAWAWB_WEIGHT_NUM); + memcpy(arg_rec->wp_blk_wei_w, arg->wp_blk_wei_w, ISP32_RAWAWB_WEIGHT_NUM); } else { for (i = 0; i < ISP32L_RAWAWB_WEIGHT_NUM; i++) isp3_param_write(params_vdev, arg->win_weight[i], @@ -2503,8 +2501,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev, if (dev->hw_dev->is_single) isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false, id); - else - *arg_rec = *arg; + *arg_rec = *arg; } static void diff --git a/drivers/media/platform/rockchip/isp/isp_params_v3x.c b/drivers/media/platform/rockchip/isp/isp_params_v3x.c index bd1e557eb5e8..2478c09d7062 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v3x.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v3x.c @@ -1430,13 +1430,12 @@ isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, return; for (i = 0; i < ISP3X_RAWAWB_WEIGHT_NUM / 5; i++) { - isp3_param_write(params_vdev, - (arg->sw_rawawb_wp_blk_wei_w[5 * i] & 0x3f) << 0 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | - (arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24, - ISP3X_RAWAWB_WRAM_DATA_BASE, id); + val = (arg->sw_rawawb_wp_blk_wei_w[5 * i] & 0x3f) << 0 | + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 | + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 | + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 | + (arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24; + isp3_param_write_direct(params_vdev, val, ISP3X_RAWAWB_WRAM_DATA_BASE, id); } } @@ -2288,10 +2287,9 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev, if (params_vdev->dev->hw_dev->is_single) isp_rawawb_cfg_sram(params_vdev, arg, false, id); - else - memcpy(arg_rec->sw_rawawb_wp_blk_wei_w, - arg->sw_rawawb_wp_blk_wei_w, - ISP3X_RAWAWB_WEIGHT_NUM); + memcpy(arg_rec->sw_rawawb_wp_blk_wei_w, + arg->sw_rawawb_wp_blk_wei_w, + ISP3X_RAWAWB_WEIGHT_NUM); /* avoid to override the old enable value */ value = isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id); @@ -2502,8 +2500,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev, if (dev->hw_dev->is_single) isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false, id); - else - *arg_rec = *arg; + *arg_rec = *arg; } static void diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index 8e83ff312b49..3fb64b3b6485 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -87,12 +87,6 @@ static void rkisp_config_cmsk(struct rkisp_device *dev); -struct backup_reg { - const u32 base; - const u32 shd; - u32 val; -}; - static inline struct rkisp_device *sd_to_isp_dev(struct v4l2_subdev *sd) { return container_of(sd->v4l2_dev, struct rkisp_device, v4l2_dev); @@ -730,7 +724,7 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo params_vdev->rdbk_times = dma2frm + 1; run_next: - rkisp_params_cfgsram(params_vdev); + rkisp_params_cfgsram(params_vdev, true); stats_vdev->rdbk_drop = false; if (dev->is_frame_double) { is_upd = true; @@ -943,11 +937,16 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) goto end; if (!IS_HDR_RDBK(dev->rd_mode)) goto end; + if (dev->is_suspend) { + if (dev->suspend_sync) + complete(&dev->pm_cmpl); + goto end; + } for (i = 0; i < hw->dev_num; i++) { isp = hw->isp[i]; if (!isp || - (isp && !(isp->isp_state & ISP_START))) + (isp && (!(isp->isp_state & ISP_START) || isp->is_suspend))) continue; rkisp_rdbk_trigger_event(isp, T_CMD_LEN, &len[i]); if (max < len[i]) { @@ -1180,86 +1179,19 @@ static void rkisp_config_ism(struct rkisp_device *dev) rkisp_write(dev, CIF_ISP_IS_CTRL, 1, false); } -static int rkisp_reset_handle_v2x(struct rkisp_device *dev) +static int rkisp_reset_handle(struct rkisp_device *dev) { - void __iomem *base = dev->base_addr; - void *reg_buf = NULL; - u32 *reg, *reg1, i; - struct backup_reg backup[] = { - { - .base = MI_MP_WR_Y_BASE, - .shd = MI_MP_WR_Y_BASE_SHD, - }, { - .base = MI_MP_WR_CB_BASE, - .shd = MI_MP_WR_CB_BASE_SHD, - }, { - .base = MI_MP_WR_CR_BASE, - .shd = MI_MP_WR_CR_BASE_SHD, - }, { - .base = MI_SP_WR_Y_BASE, - .shd = MI_SP_WR_Y_BASE_SHD, - }, { - .base = MI_SP_WR_CB_BASE, - .shd = MI_SP_WR_CB_BASE_AD_SHD, - }, { - .base = MI_SP_WR_CR_BASE, - .shd = MI_SP_WR_CR_BASE_AD_SHD, - }, { - .base = MI_RAW0_WR_BASE, - .shd = MI_RAW0_WR_BASE_SHD, - }, { - .base = MI_RAW1_WR_BASE, - .shd = MI_RAW1_WR_BASE_SHD, - }, { - .base = MI_RAW2_WR_BASE, - .shd = MI_RAW2_WR_BASE_SHD, - }, { - .base = MI_RAW3_WR_BASE, - .shd = MI_RAW3_WR_BASE_SHD, - }, { - .base = MI_RAW0_RD_BASE, - .shd = MI_RAW0_RD_BASE_SHD, - }, { - .base = MI_RAW1_RD_BASE, - .shd = MI_RAW1_RD_BASE_SHD, - }, { - .base = MI_RAW2_RD_BASE, - .shd = MI_RAW2_RD_BASE_SHD, - }, { - .base = MI_GAIN_WR_BASE, - .shd = MI_GAIN_WR_BASE_SHD, - } - }; - - reg_buf = kzalloc(RKISP_ISP_SW_REG_SIZE, GFP_KERNEL); - if (!reg_buf) - return -ENOMEM; + u32 val; dev_info(dev->dev, "%s enter\n", __func__); + rkisp_hw_reg_save(dev->hw_dev); - memcpy_fromio(reg_buf, base, RKISP_ISP_SW_REG_SIZE); rkisp_soft_reset(dev->hw_dev, true); - /* process special reg */ - reg = reg_buf + ISP_CTRL; - *reg &= ~(CIF_ISP_CTRL_ISP_ENABLE | - CIF_ISP_CTRL_ISP_INFORM_ENABLE | - CIF_ISP_CTRL_ISP_CFG_UPD); - reg = reg_buf + MI_WR_INIT; - *reg = 0; - reg = reg_buf + CSI2RX_CTRL0; - *reg &= ~SW_CSI2RX_EN; - /* skip mmu range */ - memcpy_toio(base, reg_buf, ISP21_MI_BAY3D_RD_BASE_SHD); - memcpy_toio(base + CSI2RX_CTRL0, reg_buf + CSI2RX_CTRL0, - RKISP_ISP_SW_REG_SIZE - CSI2RX_CTRL0); - /* config shd_reg to base_reg */ - for (i = 0; i < ARRAY_SIZE(backup); i++) { - reg = reg_buf + backup[i].base; - reg1 = reg_buf + backup[i].shd; - backup[i].val = *reg; - writel(*reg1, base + backup[i].base); - } + rkisp_hw_reg_restore(dev->hw_dev); + + val = CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR; + rkisp_unite_set_bits(dev, CIF_ISP_IMSC, 0, val, true); /* clear state */ dev->isp_err_cnt = 0; @@ -1267,40 +1199,12 @@ static int rkisp_reset_handle_v2x(struct rkisp_device *dev) rkisp_set_state(&dev->isp_state, ISP_FRAME_END); dev->hw_dev->monitor.state = ISP_FRAME_END; - /* update module */ - reg = reg_buf + DUAL_CROP_CTRL; - if (*reg & 0xf) - writel(*reg | CIF_DUAL_CROP_CFG_UPD, base + DUAL_CROP_CTRL); - reg = reg_buf + SELF_RESIZE_CTRL; - if (*reg & 0xf) - writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + SELF_RESIZE_CTRL); - reg = reg_buf + MAIN_RESIZE_CTRL; - if (*reg & 0xf) - writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + MAIN_RESIZE_CTRL); - - /* update mi and isp, base_reg will update to shd_reg */ - force_cfg_update(dev); - reg = reg_buf + ISP_CTRL; - *reg |= CIF_ISP_CTRL_ISP_ENABLE | - CIF_ISP_CTRL_ISP_INFORM_ENABLE | - CIF_ISP_CTRL_ISP_CFG_UPD; - writel(*reg, base + ISP_CTRL); - udelay(50); - /* config base_reg */ - for (i = 0; i < ARRAY_SIZE(backup); i++) - writel(backup[i].val, base + backup[i].base); - /* mpfbc base_reg = shd_reg, write is base but read is shd */ - if (dev->isp_ver == ISP_V20) - writel(rkisp_read_reg_cache(dev, ISP_MPFBC_HEAD_PTR), - base + ISP_MPFBC_HEAD_PTR); - rkisp_set_bits(dev, CIF_ISP_IMSC, 0, CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR, true); if (IS_HDR_RDBK(dev->hdr.op_mode)) { if (!dev->hw_dev->is_idle) rkisp_trigger_read_back(dev, 1, 0, true); else rkisp_rdbk_trigger_event(dev, T_CMD_QUEUE, NULL); } - kfree(reg_buf); dev_info(dev->dev, "%s exit\n", __func__); return 0; } @@ -1314,11 +1218,6 @@ static void rkisp_restart_monitor(struct work_struct *work) struct rkisp_pipeline *p; int ret, i, j, timeout = 5, mipi_irq_cnt = 0; - if (!monitor->reset_handle) { - monitor->is_en = false; - return; - } - dev_info(hw->dev, "%s enter\n", __func__); while (!(monitor->state & ISP_STOP) && monitor->is_en) { ret = wait_for_completion_timeout(&monitor->cmpl, @@ -1376,7 +1275,7 @@ static void rkisp_restart_monitor(struct work_struct *work) /* restart isp */ isp = hw->isp[hw->cur_dev_id]; - ret = monitor->reset_handle(isp); + ret = rkisp_reset_handle(isp); if (ret) { monitor->is_en = false; break; @@ -1413,9 +1312,6 @@ static void rkisp_monitor_init(struct rkisp_device *dev) struct rkisp_monitor *monitor = &dev->hw_dev->monitor; monitor->dev = dev->hw_dev; - monitor->reset_handle = NULL; - if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21) - monitor->reset_handle = rkisp_reset_handle_v2x; init_completion(&monitor->cmpl); INIT_WORK(&monitor->work, rkisp_restart_monitor); @@ -3839,6 +3735,7 @@ int rkisp_register_isp_subdev(struct rkisp_device *isp_dev, atomic_set(&isp_sdev->frm_sync_seq, 0); rkisp_monitor_init(isp_dev); INIT_WORK(&isp_dev->rdbk_work, rkisp_rdbk_work); + init_completion(&isp_dev->pm_cmpl); return 0; err_cleanup_media_entity: media_entity_cleanup(&sd->entity); From 7f673187a4498ea441f9756d2e5a02e604d60e53 Mon Sep 17 00:00:00 2001 From: Su Yuefu Date: Thu, 12 Oct 2023 15:26:05 +0800 Subject: [PATCH 09/31] media: i2c: sc2336: fix gain table error Signed-off-by: Su Yuefu Change-Id: I73fda7901bfd960bceb56ed1da11ec40b57b3e70 --- drivers/media/i2c/sc2336.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/media/i2c/sc2336.c b/drivers/media/i2c/sc2336.c index ca948d69ac8b..f1aeaefd35af 100644 --- a/drivers/media/i2c/sc2336.c +++ b/drivers/media/i2c/sc2336.c @@ -7,7 +7,7 @@ * V0.0X01.0X01 first version */ -//#define DEBUG +// #define DEBUG #include #include #include @@ -192,10 +192,10 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = { {0x3301, 0x09}, {0x3302, 0xff}, {0x3303, 0x10}, - {0x3306, 0x60}, + {0x3306, 0x68}, {0x3307, 0x02}, {0x330a, 0x01}, - {0x330b, 0x10}, + {0x330b, 0x18}, {0x330c, 0x16}, {0x330d, 0xff}, {0x3318, 0x02}, @@ -219,8 +219,8 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = { {0x33b1, 0x80}, {0x33b2, 0x68}, {0x33b3, 0x42}, - {0x33f9, 0x70}, - {0x33fb, 0xd0}, + {0x33f9, 0x78}, + {0x33fb, 0xe0}, {0x33fc, 0x0f}, {0x33fd, 0x1f}, {0x349f, 0x03}, @@ -229,9 +229,9 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = { {0x34a8, 0x42}, {0x34a9, 0x06}, {0x34aa, 0x01}, - {0x34ab, 0x23}, + {0x34ab, 0x28}, {0x34ac, 0x01}, - {0x34ad, 0x84}, + {0x34ad, 0x90}, {0x3630, 0xf4}, {0x3633, 0x22}, {0x3639, 0xf4}, @@ -242,9 +242,9 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = { {0x3676, 0xed}, {0x367c, 0x09}, {0x367d, 0x0f}, - {0x3690, 0x33}, - {0x3691, 0x33}, - {0x3692, 0x43}, + {0x3690, 0x22}, + {0x3691, 0x22}, + {0x3692, 0x22}, {0x3698, 0x89}, {0x3699, 0x96}, {0x369a, 0xd0}, @@ -452,15 +452,15 @@ static int sc2336_set_gain_reg(struct sc2336 *sc2336, u32 gain) coarse_dgain = 0x00; fine_dgain = gain_factor * 128 / 1000; } else if (gain_factor < 1000 * 4) { /*2x ~ 4x gain*/ - coarse_again = 0x01; + coarse_again = 0x08; coarse_dgain = 0x00; fine_dgain = gain_factor * 128 / 1000 / 2; } else if (gain_factor < 1000 * 8) { /*4x ~ 8x gain*/ - coarse_again = 0x03; + coarse_again = 0x09; coarse_dgain = 0x00; fine_dgain = gain_factor * 128 / 1000 / 4; } else if (gain_factor < 1000 * 16) { /*8x ~ 16x gain*/ - coarse_again = 0x07; + coarse_again = 0x0b; coarse_dgain = 0x00; fine_dgain = gain_factor * 128 / 1000 / 8; } else if (gain_factor < 1000 * 32) { /*16x ~ 32x gain*/ @@ -481,6 +481,7 @@ static int sc2336_set_gain_reg(struct sc2336 *sc2336, u32 gain) coarse_dgain = 0x03; fine_dgain = 0x80; } + fine_dgain = fine_dgain / 4 * 4; dev_dbg(&sc2336->client->dev, "total_gain: 0x%x, d_gain: 0x%x, d_fine_gain: 0x%x, c_gain: 0x%x\n", gain, coarse_dgain, fine_dgain, coarse_again); @@ -1159,7 +1160,7 @@ static int sc2336_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_VBLANK: /* Update max exposure while meeting expected vblanking */ - max = sc2336->cur_mode->height + ctrl->val - 8; + max = sc2336->cur_mode->height + ctrl->val - 6; __v4l2_ctrl_modify_range(sc2336->exposure, sc2336->exposure->minimum, max, sc2336->exposure->step, @@ -1282,7 +1283,7 @@ static int sc2336_initialize_controls(struct sc2336 *sc2336) V4L2_CID_VBLANK, vblank_def, SC2336_VTS_MAX - mode->height, 1, vblank_def); - exposure_max = mode->vts_def - 8; + exposure_max = mode->vts_def - 6; sc2336->exposure = v4l2_ctrl_new_std(handler, &sc2336_ctrl_ops, V4L2_CID_EXPOSURE, SC2336_EXPOSURE_MIN, exposure_max, SC2336_EXPOSURE_STEP, From b3f515deea5f5f88cbbcba8d44ed4218c57af381 Mon Sep 17 00:00:00 2001 From: Su Yuefu Date: Mon, 16 Oct 2023 16:06:16 +0800 Subject: [PATCH 10/31] media: i2c: sc200ai support normal boot Signed-off-by: Su Yuefu Change-Id: I380f06c4711fddc180761bf51a00a5b6be2d1739 --- drivers/media/i2c/sc200ai.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/sc200ai.c b/drivers/media/i2c/sc200ai.c index daa7e4e34b74..e7492cb45f77 100644 --- a/drivers/media/i2c/sc200ai.c +++ b/drivers/media/i2c/sc200ai.c @@ -2057,11 +2057,11 @@ static int sc200ai_probe(struct i2c_client *client, return -EINVAL; } - sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); + sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", sc200ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); if (IS_ERR(sc200ai->reset_gpio)) dev_warn(dev, "Failed to get reset-gpios\n"); - sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); + sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", sc200ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); if (IS_ERR(sc200ai->pwdn_gpio)) dev_warn(dev, "Failed to get pwdn-gpios\n"); From 734c046668af10dc33d768357291422df043702f Mon Sep 17 00:00:00 2001 From: Luo Wei Date: Wed, 27 Sep 2023 15:54:19 +0800 Subject: [PATCH 11/31] arm64: dts: rockchip: rk3588-vehicle-evb-v22: enable uboot logo again Signed-off-by: Luo Wei Change-Id: I2d001583f95b61bef35a8d6e27220a7591ff5ee7 --- .../dts/rockchip/rk3588-vehicle-evb-v22.dts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts index 2fe348b486b8..701cc247f593 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts @@ -373,12 +373,12 @@ }; &i2c2_bu18tl82 { - //route-enable; - use-delay-work; + route-enable; + //use-delay-work; }; &i2c2_bu18rl82 { - use-delay-work; + //use-delay-work; vpower-supply = <&lcd1_vcc12v_buck>; }; @@ -389,11 +389,11 @@ }; &i2c4_bu18tl82 { - use-delay-work; + //use-delay-work; }; &i2c4_bu18rl82 { - use-delay-work; + //use-delay-work; vpower-supply = <&lcd5_vcc12v_buck>; }; @@ -435,11 +435,11 @@ }; &i2c5_bu18tl82 { - use-delay-work; + //use-delay-work; }; &i2c5_bu18rl82 { - use-delay-work; + //use-delay-work; vpower-supply = <&lcd3_vcc12v_buck>; }; @@ -450,8 +450,8 @@ }; &i2c6_bu18tl82 { - //route-enable; - use-delay-work; + route-enable; + //use-delay-work; }; &i2c6_bu18rl82 { @@ -565,11 +565,11 @@ }; &route_dsi0 { - status = "disabled"; + status = "okay"; }; &route_dsi1 { - status = "disabled"; + status = "okay"; }; &u2phy1_otg { From 274110771942667fb57a8bf632c5c0da67acc3c6 Mon Sep 17 00:00:00 2001 From: Lan Honglin Date: Sun, 8 Oct 2023 11:27:36 +0800 Subject: [PATCH 12/31] ARM: dts: rockchip: add rv1106g-4k dts support isp unite mode Change-Id: I27d61555dd7faed85cb33de87818412e4e5dc570 Signed-off-by: Lan Honglin --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/rv1106g-evb1-v11-4k.dts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 arch/arm/boot/dts/rv1106g-evb1-v11-4k.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 36464dc36216..6eef8440e660 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -988,6 +988,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1106g-evb1-rgb-display-v11.dtb \ rv1106g-evb1-v10.dtb \ rv1106g-evb1-v11.dtb \ + rv1106g-evb1-v11-4k.dtb \ rv1106g-evb1-v11-cvr.dtb \ rv1106g-evb1-v11-cvr-dual-cam.dtb \ rv1106g-evb1-v11-spi-nand-cvr.dtb \ diff --git a/arch/arm/boot/dts/rv1106g-evb1-v11-4k.dts b/arch/arm/boot/dts/rv1106g-evb1-v11-4k.dts new file mode 100644 index 000000000000..2116496639f8 --- /dev/null +++ b/arch/arm/boot/dts/rv1106g-evb1-v11-4k.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; + +#include "rv1106g-evb1-v11.dts" + +/ { + model = "Rockchip RV1106G EVB1 V11 Board For RV1106G3 4K Unite"; + compatible = "rockchip,rv1106g-evb1-v11-4k", "rockchip,rv1106"; +}; + +&rkisp { + rockchip,unite-en; +}; From 803cb50485f31e2991d8c9396b08f19af7131e1c Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Fri, 13 Oct 2023 16:01:36 +0800 Subject: [PATCH 13/31] arm64: dts: rockchip: update rk3568-evb1-ddr4-v10-dual-lvds relevant files In order to add a rk3568-evb1-ddr4-v10-dual-lvds-linux.dts to support linux dts, slightly more relevant file for better readability. Change-Id: I5b5396aa6bf084b8eacfcff088c3478a00b83aaf Signed-off-by: Caesar Wang --- arch/arm64/boot/dts/rockchip/Makefile | 1 + .../rk3568-evb1-ddr4-v10-dual-lvds-linux.dts | 23 +++ .../rk3568-evb1-ddr4-v10-dual-lvds.dts | 161 +----------------- .../rk3568-evb1-ddr4-v10-dual-lvds.dtsi | 161 ++++++++++++++++++ 4 files changed, 188 insertions(+), 158 deletions(-) create mode 100644 arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds-linux.dts create mode 100644 arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 5793a32bdfe7..75b37a665bb3 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -138,6 +138,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-dual-lvds.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-camera.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-lvds.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-lvds-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux-amp.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux-spi-nor.dtb diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds-linux.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds-linux.dts new file mode 100644 index 000000000000..6a15126ee392 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds-linux.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; + +#include +#include "rk3568-evb1-ddr4-v10-dual-lvds.dtsi" +#include "rk3568-linux.dtsi" + +/ { + model = "Rockchip RK3568 EVB1 V10 Board with Dual LVDS"; + compatible = "rockchip,rk3568-evb1-ddr4-v10-dual-lvds", "rockchip,rk3568"; +}; + +&vp0 { + cursor-win-id = ; +}; + +&vp1 { + cursor-win-id = ; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dts index d2f0cab9968b..8cff3652b8d1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dts @@ -5,165 +5,10 @@ /dts-v1/; -#include -#include -#include - -#include "rk3568-evb1-ddr4-v10.dtsi" +#include "rk3568-evb1-ddr4-v10-dual-lvds.dtsi" #include "rk3568-android.dtsi" / { - panel { - compatible = "simple-panel"; - backlight = <&backlight>; - power-supply = <&vcc3v3_lcd0_n>; - enable-delay-ms = <20>; - prepare-delay-ms = <20>; - unprepare-delay-ms = <20>; - disable-delay-ms = <20>; - bus-format = ; - width-mm = <217>; - height-mm = <136>; - - display-timings { - native-mode = <&timing0>; - - timing0: timing0 { - clock-frequency = <134000000>; - hactive = <1600>; - vactive = <1280>; - hback-porch = <60>; - hfront-porch = <60>; - vback-porch = <4>; - vfront-porch = <2>; - hsync-len = <8>; - vsync-len = <2>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <0>; - pixelclk-active = <0>; - }; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - /** - * Panel <----> LVDS0 - * Panel <----> LVDS1 - */ - port@0 { - reg = <0>; - dual-lvds-left-pixels; - panel_in_lvds0: endpoint { - remote-endpoint = <&lvds0_out_panel>; - }; - }; - port@1 { - reg = <1>; - dual-lvds-right-pixels; - panel_in_lvds1: endpoint { - remote-endpoint = <&lvds1_out_panel>; - }; - }; - }; - }; -}; - -&backlight1 { - status = "okay"; -}; - -&backlight { - status = "okay"; -}; - -&lvds { - status = "okay"; - dual-channel; - - ports { - port@1 { - reg = <1>; - lvds0_out_panel: endpoint { - remote-endpoint = <&panel_in_lvds0>; - }; - }; - }; -}; - -&lvds1 { - status = "okay"; - - ports { - port@1 { - reg = <1>; - lvds1_out_panel: endpoint { - remote-endpoint = <&panel_in_lvds1>; - }; - }; - }; -}; - -&lvds_in_vp1 { - status = "okay"; -}; - -&lvds1_in_vp1 { - status = "disabled"; -}; - -&lvds1_in_vp2 { - status = "okay"; -}; - -/* enable hdmi */ -&hdmi_in_vp1 { - status = "okay"; -}; - -/* enable video phy */ -&video_phy0 { - status = "okay"; -}; - -&video_phy1 { - status = "okay"; -}; - -/* disable other encoder output */ -&dsi0 { - status = "disabled"; -}; - -&dsi0_in_vp0 { - status = "disabled"; -}; - -&dsi0_in_vp1 { - status = "disabled"; -}; - -&dsi1_in_vp1 { - status = "disabled"; -}; - -&edp_in_vp1 { - status = "disabled"; -}; - -&rgb_in_vp2 { - status = "disabled"; -}; - - -&vcc3v3_lcd0_n { - gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; - enable-active-high; -}; - -&vcc3v3_lcd1_n { - gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; - enable-active-high; + model = "Rockchip RK3568 EVB1 V10 Board with Dual LVDS"; + compatible = "rockchip,rk3568-evb1-ddr4-v10-dual-lvds", "rockchip,rk3568"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi new file mode 100644 index 000000000000..d38f2c2ca3ae --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10-dual-lvds.dtsi @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include "rk3568-evb1-ddr4-v10.dtsi" + +/ { + panel { + compatible = "simple-panel"; + backlight = <&backlight>; + power-supply = <&vcc3v3_lcd0_n>; + enable-delay-ms = <20>; + prepare-delay-ms = <20>; + unprepare-delay-ms = <20>; + disable-delay-ms = <20>; + bus-format = ; + width-mm = <217>; + height-mm = <136>; + + display-timings { + native-mode = <&timing0>; + + timing0: timing0 { + clock-frequency = <134000000>; + hactive = <1600>; + vactive = <1280>; + hback-porch = <60>; + hfront-porch = <60>; + vback-porch = <4>; + vfront-porch = <2>; + hsync-len = <8>; + vsync-len = <2>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /** + * Panel <----> LVDS0 + * Panel <----> LVDS1 + */ + port@0 { + reg = <0>; + dual-lvds-left-pixels; + panel_in_lvds0: endpoint { + remote-endpoint = <&lvds0_out_panel>; + }; + }; + port@1 { + reg = <1>; + dual-lvds-right-pixels; + panel_in_lvds1: endpoint { + remote-endpoint = <&lvds1_out_panel>; + }; + }; + }; + }; +}; + +&backlight1 { + status = "okay"; +}; + +&backlight { + status = "okay"; +}; + +&dsi0 { + status = "disabled"; +}; + +&dsi0_in_vp0 { + status = "disabled"; +}; + +&dsi0_in_vp1 { + status = "disabled"; +}; + +&dsi1_in_vp1 { + status = "disabled"; +}; + +&edp_in_vp1 { + status = "disabled"; +}; + +&hdmi_in_vp1 { + status = "okay"; +}; + +&lvds { + status = "okay"; + dual-channel; + + ports { + port@1 { + reg = <1>; + lvds0_out_panel: endpoint { + remote-endpoint = <&panel_in_lvds0>; + }; + }; + }; +}; + +&lvds1 { + status = "okay"; + + ports { + port@1 { + reg = <1>; + lvds1_out_panel: endpoint { + remote-endpoint = <&panel_in_lvds1>; + }; + }; + }; +}; + +&lvds_in_vp1 { + status = "okay"; +}; + +&lvds1_in_vp1 { + status = "disabled"; +}; + +&lvds1_in_vp2 { + status = "okay"; +}; + +&rgb_in_vp2 { + status = "disabled"; +}; + +&video_phy0 { + status = "okay"; +}; + +&video_phy1 { + status = "okay"; +}; + +&vcc3v3_lcd0_n { + gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; + enable-active-high; +}; + +&vcc3v3_lcd1_n { + gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; + enable-active-high; +}; From 9414fed2b79078438dfff7bcd5ef37ab2555c03d Mon Sep 17 00:00:00 2001 From: Mingwei Yan Date: Thu, 14 Sep 2023 15:12:11 +0800 Subject: [PATCH 14/31] media: rockchip: isp: pm add call sensor s_power Change-Id: Ic04794a6b00845b21ee0f098fea119ebde0fae71 Signed-off-by: Mingwei Yan --- drivers/media/platform/rockchip/isp/csi.c | 8 ++--- drivers/media/platform/rockchip/isp/csi.h | 2 ++ drivers/media/platform/rockchip/isp/dev.c | 37 +++++++++++++++++++---- drivers/media/platform/rockchip/isp/dev.h | 4 +++ 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/rockchip/isp/csi.c b/drivers/media/platform/rockchip/isp/csi.c index a747d6737010..c7a288c71f59 100644 --- a/drivers/media/platform/rockchip/isp/csi.c +++ b/drivers/media/platform/rockchip/isp/csi.c @@ -15,7 +15,7 @@ #include "isp_external.h" #include "regs.h" -static void get_remote_mipi_sensor(struct rkisp_device *dev, +void rkisp_get_remote_mipi_sensor(struct rkisp_device *dev, struct v4l2_subdev **sensor_sd, u32 function) { struct media_graph graph; @@ -210,7 +210,7 @@ static int csi_config(struct rkisp_csi_device *csi) emd_vc = 0xFF; emd_dt = 0; dev->hdr.sensor = NULL; - get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR); + rkisp_get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR); if (mipi_sensor) { ctrl = v4l2_ctrl_find(mipi_sensor->ctrl_handler, CIFISP_CID_EMB_VC); @@ -546,7 +546,7 @@ int rkisp_csi_get_hdr_cfg(struct rkisp_device *dev, void *arg) } return 0; } - get_remote_mipi_sensor(dev, &sd, type); + rkisp_get_remote_mipi_sensor(dev, &sd, type); if (!sd) { v4l2_err(&dev->v4l2_dev, "%s don't find subdev\n", __func__); return -EINVAL; @@ -577,7 +577,7 @@ int rkisp_csi_config_patch(struct rkisp_device *dev) memset(&mode, 0, sizeof(mode)); mode.name = dev->name; - get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_PROC_VIDEO_COMPOSER); + rkisp_get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_PROC_VIDEO_COMPOSER); if (!mipi_sensor) return -EINVAL; dev->hdr.op_mode = HDR_NORMAL; diff --git a/drivers/media/platform/rockchip/isp/csi.h b/drivers/media/platform/rockchip/isp/csi.h index 98bf2511088c..9fbdc35b4405 100644 --- a/drivers/media/platform/rockchip/isp/csi.h +++ b/drivers/media/platform/rockchip/isp/csi.h @@ -80,4 +80,6 @@ void rkisp_unregister_csi_subdev(struct rkisp_device *dev); int rkisp_csi_get_hdr_cfg(struct rkisp_device *dev, void *arg); int rkisp_csi_config_patch(struct rkisp_device *dev); void rkisp_csi_sof(struct rkisp_device *dev, u8 id); +void rkisp_get_remote_mipi_sensor(struct rkisp_device *dev, + struct v4l2_subdev **sensor_sd, u32 function); #endif diff --git a/drivers/media/platform/rockchip/isp/dev.c b/drivers/media/platform/rockchip/isp/dev.c index ed427c7ce3bf..b27522df25fe 100644 --- a/drivers/media/platform/rockchip/isp/dev.c +++ b/drivers/media/platform/rockchip/isp/dev.c @@ -52,6 +52,7 @@ #include "regs.h" #include "rkisp.h" #include "version.h" +#include "csi.h" #define RKISP_VERNO_LEN 10 @@ -1014,13 +1015,21 @@ static int rkisp_pm_prepare(struct device *dev) unsigned long lock_flags = 0; int i, on = 0, time = 100; - if (isp_dev->isp_state & ISP_STOP) + if (isp_dev->isp_state & ISP_STOP) { + if (pm_runtime_active(dev) && + rkisp_link_sensor(isp_dev->isp_inp)) { + struct v4l2_subdev *mipi_sensor = NULL; + + rkisp_get_remote_mipi_sensor(isp_dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR); + if (mipi_sensor) + v4l2_subdev_call(mipi_sensor, core, s_power, 0); + } return 0; + } isp_dev->suspend_sync = false; isp_dev->is_suspend = true; - if (isp_dev->isp_inp & INP_CSI || - isp_dev->isp_inp & INP_DVP || isp_dev->isp_inp & INP_LVDS) { + if (rkisp_link_sensor(isp_dev->isp_inp)) { for (i = p->num_subdevs - 1; i >= 0; i--) v4l2_subdev_call(p->subdevs[i], video, s_stream, on); } else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) { @@ -1042,6 +1051,11 @@ static int rkisp_pm_prepare(struct device *dev) wait_for_completion_timeout(&isp_dev->pm_cmpl, msecs_to_jiffies(time)); isp_dev->suspend_sync = false; } + + if (rkisp_link_sensor(isp_dev->isp_inp)) { + for (i = p->num_subdevs - 1; i >= 0; i--) + v4l2_subdev_call(p->subdevs[i], core, s_power, 0); + } return 0; } @@ -1053,8 +1067,17 @@ static void rkisp_pm_complete(struct device *dev) struct rkisp_stream *stream; int i, on = 1; - if (isp_dev->isp_state & ISP_STOP) + if (isp_dev->isp_state & ISP_STOP) { + if (pm_runtime_active(dev) && + rkisp_link_sensor(isp_dev->isp_inp)) { + struct v4l2_subdev *mipi_sensor = NULL; + + rkisp_get_remote_mipi_sensor(isp_dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR); + if (mipi_sensor) + v4l2_subdev_call(mipi_sensor, core, s_power, 1); + } return; + } isp_dev->is_suspend = false; isp_dev->isp_state = ISP_START | ISP_FRAME_END; @@ -1066,8 +1089,10 @@ static void rkisp_pm_complete(struct device *dev) } if (hw->cur_dev_id == isp_dev->dev_id) rkisp_rdbk_trigger_event(isp_dev, T_CMD_QUEUE, NULL); - if (isp_dev->isp_inp & INP_CSI || - isp_dev->isp_inp & INP_DVP || isp_dev->isp_inp & INP_LVDS) { + + if (rkisp_link_sensor(isp_dev->isp_inp)) { + for (i = 0; i < p->num_subdevs; i++) + v4l2_subdev_call(p->subdevs[i], core, s_power, 1); for (i = 0; i < p->num_subdevs; i++) v4l2_subdev_call(p->subdevs[i], video, s_stream, on); } else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) { diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index fbd1b49e22a0..b5cd72d21bb9 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -308,4 +308,8 @@ rkisp_unite_clear_bits(struct rkisp_device *dev, u32 reg, u32 mask, rkisp_next_clear_bits(dev, reg, mask, is_direct); } +static inline bool rkisp_link_sensor(u32 isp_inp) +{ + return isp_inp & (INP_CSI | INP_DVP | INP_LVDS); +} #endif From 8f9f8dc62df9bc8d7a9f4ec8ffbd78873eb3ee64 Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Sun, 8 Oct 2023 16:06:38 +0800 Subject: [PATCH 15/31] media: rockchip: isp: suspend resume with rtt Change-Id: Ibc86e518c3c464950d41166401c5ba2d9ee6c613 Signed-off-by: Cai YiWei --- drivers/media/platform/rockchip/isp/dev.c | 68 ++++++++++++++++++- drivers/media/platform/rockchip/isp/dev.h | 4 ++ .../media/platform/rockchip/isp/isp_params.c | 22 ++++++ .../media/platform/rockchip/isp/isp_rockit.c | 5 ++ .../platform/rockchip/isp/isp_stats_v32.c | 3 + drivers/media/platform/rockchip/isp/rkisp.c | 27 +++++--- drivers/media/platform/rockchip/isp/rkisp.h | 2 + include/uapi/linux/rk-isp2-config.h | 8 +++ include/uapi/linux/rk-isp32-config.h | 3 +- 9 files changed, 130 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/rockchip/isp/dev.c b/drivers/media/platform/rockchip/isp/dev.c index b27522df25fe..69a2ba09a440 100644 --- a/drivers/media/platform/rockchip/isp/dev.c +++ b/drivers/media/platform/rockchip/isp/dev.c @@ -816,6 +816,15 @@ static int rkisp_get_reserved_mem(struct rkisp_device *isp_dev) DMA_BIDIRECTIONAL); ret = dma_mapping_error(dev, isp_dev->resmem_addr); isp_dev->is_thunderboot = true; + isp_dev->is_rtt_suspend = false; + isp_dev->is_rtt_first = true; + if (device_property_read_bool(dev, "rtt-suspend")) { + isp_dev->is_rtt_suspend = true; + if (!isp_dev->hw_dev->is_thunderboot) { + isp_dev->is_thunderboot = false; + isp_dev->is_rtt_first = false; + } + } dev_info(dev, "Allocated reserved memory, paddr: 0x%x\n", (u32)isp_dev->resmem_pa); return ret; } @@ -1065,7 +1074,7 @@ static void rkisp_pm_complete(struct device *dev) struct rkisp_hw_dev *hw = isp_dev->hw_dev; struct rkisp_pipeline *p = &isp_dev->pipe; struct rkisp_stream *stream; - int i, on = 1; + int i, on = 1, rd_mode = isp_dev->rd_mode; if (isp_dev->isp_state & ISP_STOP) { if (pm_runtime_active(dev) && @@ -1079,6 +1088,63 @@ static void rkisp_pm_complete(struct device *dev) return; } + if (isp_dev->is_rtt_suspend) { + rkisp_save_tb_info(isp_dev); + v4l2_info(&isp_dev->v4l2_dev, + "tb info en:%d comp:%d cnt:%d w:%d h:%d cam:%d idx:%d mode:%d\n", + isp_dev->tb_head.enable, isp_dev->tb_head.complete, + isp_dev->tb_head.frm_total, isp_dev->tb_head.width, + isp_dev->tb_head.height, isp_dev->tb_head.camera_num, + isp_dev->tb_head.camera_index, isp_dev->tb_head.rtt_mode); + isp_dev->is_first_double = false; + switch (isp_dev->tb_head.rtt_mode) { + case RKISP_RTT_MODE_ONE_FRAME: + isp_dev->is_first_double = true; + /* switch to readback mode */ + switch (rd_mode) { + case HDR_LINEX3_DDR: + isp_dev->rd_mode = HDR_RDBK_FRAME3; + break; + case HDR_LINEX2_DDR: + isp_dev->rd_mode = HDR_RDBK_FRAME2; + break; + default: + isp_dev->rd_mode = HDR_RDBK_FRAME1; + } + break; + case RKISP_RTT_MODE_MULTI_FRAME: + default: + if (isp_dev->tb_head.rtt_mode != RKISP_RTT_MODE_MULTI_FRAME) + v4l2_warn(&isp_dev->v4l2_dev, + "invalid rtt mode:%d, change to mode:%d\n", + isp_dev->tb_head.rtt_mode, RKISP_RTT_MODE_MULTI_FRAME); + if (!hw->is_single) + break; + /* switch to online mode for single sensor */ + switch (rd_mode) { + case HDR_RDBK_FRAME3: + isp_dev->rd_mode = HDR_LINEX3_DDR; + break; + case HDR_RDBK_FRAME2: + isp_dev->rd_mode = HDR_LINEX2_DDR; + break; + default: + isp_dev->rd_mode = HDR_NORMAL; + } + } + isp_dev->hdr.op_mode = isp_dev->rd_mode; + if (rd_mode != isp_dev->rd_mode && hw->cur_dev_id == isp_dev->dev_id) { + rkisp_unite_write(isp_dev, CSI2RX_CTRL0, + SW_IBUF_OP_MODE(isp_dev->rd_mode), true); + if (IS_HDR_RDBK(isp_dev->rd_mode)) + rkisp_unite_set_bits(isp_dev, CTRL_SWS_CFG, 0, + SW_MPIP_DROP_FRM_DIS, true); + else + rkisp_unite_clear_bits(isp_dev, CTRL_SWS_CFG, + SW_MPIP_DROP_FRM_DIS, true); + } + } + isp_dev->is_suspend = false; isp_dev->isp_state = ISP_START | ISP_FRAME_END; for (i = 0; i < RKISP_MAX_STREAM; i++) { diff --git a/drivers/media/platform/rockchip/isp/dev.h b/drivers/media/platform/rockchip/isp/dev.h index b5cd72d21bb9..89043eaba7b4 100644 --- a/drivers/media/platform/rockchip/isp/dev.h +++ b/drivers/media/platform/rockchip/isp/dev.h @@ -235,6 +235,10 @@ struct rkisp_device { size_t resmem_size; struct rkisp_thunderboot_resmem_head tb_head; bool is_thunderboot; + /* first frame for rtt */ + bool is_rtt_first; + /* suspend/resume with rtt */ + bool is_rtt_suspend; struct rkisp_tb_stream_info tb_stream_info; unsigned int tb_addr_idx; diff --git a/drivers/media/platform/rockchip/isp/isp_params.c b/drivers/media/platform/rockchip/isp/isp_params.c index 4b7bb64d65fa..cbfcf581424d 100644 --- a/drivers/media/platform/rockchip/isp/isp_params.c +++ b/drivers/media/platform/rockchip/isp/isp_params.c @@ -185,6 +185,28 @@ static void rkisp_params_vb2_buf_queue(struct vb2_buffer *vb) spin_lock_irqsave(¶ms_vdev->config_lock, flags); list_add_tail(¶ms_buf->queue, ¶ms_vdev->params); spin_unlock_irqrestore(¶ms_vdev->config_lock, flags); + + if (params_vdev->dev->is_first_double) { + struct isp32_isp_params_cfg *params = params_buf->vaddr[0]; + struct rkisp_buffer *buf; + + if (!(params->module_cfg_update & ISP32_MODULE_RTT_FST)) + return; + spin_lock_irqsave(¶ms_vdev->config_lock, flags); + while (!list_empty(¶ms_vdev->params)) { + buf = list_first_entry(¶ms_vdev->params, + struct rkisp_buffer, queue); + if (buf == params_buf) + break; + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } + spin_unlock_irqrestore(¶ms_vdev->config_lock, flags); + dev_info(params_vdev->dev->dev, + "first params:%d for rtt resume\n", params->frame_id); + params_vdev->dev->is_first_double = false; + rkisp_trigger_read_back(params_vdev->dev, false, false, false); + } } static void rkisp_params_vb2_stop_streaming(struct vb2_queue *vq) diff --git a/drivers/media/platform/rockchip/isp/isp_rockit.c b/drivers/media/platform/rockchip/isp/isp_rockit.c index d97cc27976ee..7aa1632ff8fc 100644 --- a/drivers/media/platform/rockchip/isp/isp_rockit.c +++ b/drivers/media/platform/rockchip/isp/isp_rockit.c @@ -240,6 +240,11 @@ int rkisp_rockit_buf_done(struct rkisp_stream *stream, int cmd) rockit_cfg->frame.u64PTS = stream->curr_buf->vb.vb2_buf.timestamp; rockit_cfg->frame.u32TimeRef = stream->curr_buf->vb.sequence; + v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev, + "%s stream:%d seq:%d buf:0x%x done\n", + __func__, stream->id, + stream->curr_buf->vb.sequence, + stream->curr_buf->buff_addr[0]); } else { if (stream->ispdev->cap_dev.wrap_line && stream->id == RKISP_STREAM_MP) { diff --git a/drivers/media/platform/rockchip/isp/isp_stats_v32.c b/drivers/media/platform/rockchip/isp/isp_stats_v32.c index cd0a4907846d..79317e618620 100644 --- a/drivers/media/platform/rockchip/isp/isp_stats_v32.c +++ b/drivers/media/platform/rockchip/isp/isp_stats_v32.c @@ -628,6 +628,9 @@ rkisp_stats_send_meas(struct rkisp_isp_stats_vdev *stats_vdev, ops->get_vsm_stats(stats_vdev, cur_stat_buf); } + if (cur_stat_buf && stats_vdev->dev->is_first_double) + cur_stat_buf->meas_type |= ISP32_STAT_RTT_FST; + if (is_dummy) { spin_lock_irqsave(&stats_vdev->rd_lock, flags); if (!list_empty(&stats_vdev->stat)) { diff --git a/drivers/media/platform/rockchip/isp/rkisp.c b/drivers/media/platform/rockchip/isp/rkisp.c index 3fb64b3b6485..28fcad71b7ab 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.c +++ b/drivers/media/platform/rockchip/isp/rkisp.c @@ -873,6 +873,9 @@ static void rkisp_fast_switch_rx_buf(struct rkisp_device *dev, bool is_current) struct rkisp_buffer *buf; u32 i, val; + if (!dev->is_rtt_first) + return; + for (i = RKISP_STREAM_RAWRD0; i < RKISP_MAX_DMARX_STREAM; i++) { stream = &dev->dmarx_dev.stream[i]; if (!stream->ops) @@ -956,7 +959,7 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) } /* wait 2 frame to start isp for fast */ - if (dev->is_pre_on && max == 1 && !atomic_read(&dev->isp_sdev.frm_sync_seq)) + if (dev->is_rtt_first && max == 1 && !atomic_read(&dev->isp_sdev.frm_sync_seq)) goto end; if (max) { @@ -1002,7 +1005,7 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) /* first frame handle twice for thunderboot * first output stats to AIQ and wait new params to run second */ - if (isp->is_pre_on && t.frame_id == 0) { + if (isp->is_rtt_first && t.frame_id == 0) { isp->is_first_double = true; isp->skip_frame = 1; if (hw->unite != ISP_UNITE_ONE) { @@ -1010,6 +1013,8 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd) isp->is_frame_double = false; } rkisp_fast_switch_rx_buf(isp, false); + } else { + isp->is_rtt_first = false; } isp->params_vdev.rdbk_times = isp->sw_rd_cnt + 1; } @@ -1088,6 +1093,7 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq) if (dev->is_first_double) { rkisp_fast_switch_rx_buf(dev, true); + dev->is_rtt_first = false; dev->skip_frame = 0; dev->irq_ends = 0; return; @@ -3024,7 +3030,8 @@ static int rkisp_rx_buf_pool_init(struct rkisp_device *dev, pool->dbufs = dbufs; v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev, - "%s type:0x%x dbufs[%d]:%p", __func__, dbufs->type, i, dbufs); + "%s type:0x%x first:%d dbufs[%d]:%p", __func__, + dbufs->type, dbufs->is_first, i, dbufs); if (dbufs->is_resmem) { dma = dbufs->dma; @@ -3415,7 +3422,7 @@ static long rkisp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) rkisp_get_info(isp_dev, arg); break; case RKISP_CMD_GET_TB_HEAD_V32: - if (isp_dev->tb_head.complete != RKISP_TB_OK || !isp_dev->is_pre_on) { + if (isp_dev->tb_head.complete != RKISP_TB_OK) { ret = -EINVAL; break; } @@ -3775,8 +3782,7 @@ void rkisp_unregister_isp_subdev(struct rkisp_device *isp_dev) (cond) ? 0 : -ETIMEDOUT; \ }) -#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP -static void rkisp_save_tb_info(struct rkisp_device *isp_dev) +void rkisp_save_tb_info(struct rkisp_device *isp_dev) { struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev; void *resmem_va = phys_to_virt(isp_dev->resmem_pa); @@ -3796,7 +3802,8 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev) if (size && size < isp_dev->resmem_size) { dma_sync_single_for_cpu(isp_dev->dev, isp_dev->resmem_addr + offset, size, DMA_FROM_DEVICE); - params_vdev->is_first_cfg = true; + if (isp_dev->is_rtt_first) + params_vdev->is_first_cfg = true; if (isp_dev->isp_ver == ISP_V32) { struct rkisp32_thunderboot_resmem_head *tmp = resmem_va + offset; @@ -3808,7 +3815,7 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev) tmp->cfg.module_ens, tmp->cfg.module_cfg_update); } - if (param) + if (param && (isp_dev->isp_state & ISP_STOP)) params_vdev->ops->save_first_param(params_vdev, param); } else if (size > isp_dev->resmem_size) { v4l2_err(&isp_dev->v4l2_dev, @@ -3819,6 +3826,7 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev) memcpy(&isp_dev->tb_head, head, sizeof(*head)); } +#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP void rkisp_chk_tb_over(struct rkisp_device *isp_dev) { struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev; @@ -3866,11 +3874,10 @@ void rkisp_chk_tb_over(struct rkisp_device *isp_dev) end: head = &isp_dev->tb_head; v4l2_info(&isp_dev->v4l2_dev, - "thunderboot info: %d, %d, %d, %d, %d, %d | %d %d\n", + "tb info en:%d comp:%d cnt:%d w:%d h:%d cam:%d idx:%d\n", head->enable, head->complete, head->frm_total, - head->hdr_mode, head->width, head->height, head->camera_num, diff --git a/drivers/media/platform/rockchip/isp/rkisp.h b/drivers/media/platform/rockchip/isp/rkisp.h index 54f32b9685c3..76f8ce05e424 100644 --- a/drivers/media/platform/rockchip/isp/rkisp.h +++ b/drivers/media/platform/rockchip/isp/rkisp.h @@ -153,6 +153,8 @@ void rkisp_chk_tb_over(struct rkisp_device *isp_dev); static inline void rkisp_chk_tb_over(struct rkisp_device *isp_dev) {} #endif +void rkisp_save_tb_info(struct rkisp_device *isp_dev); + void rkisp_mipi_isr(unsigned int mipi_mis, struct rkisp_device *dev); void rkisp_mipi_v13_isr(unsigned int err1, unsigned int err2, diff --git a/include/uapi/linux/rk-isp2-config.h b/include/uapi/linux/rk-isp2-config.h index 9de8ac7d6e20..fb8254771d92 100644 --- a/include/uapi/linux/rk-isp2-config.h +++ b/include/uapi/linux/rk-isp2-config.h @@ -1968,6 +1968,12 @@ struct rkisp_isp2x_luma_buffer { struct rkisp_mipi_luma luma[ISP2X_MIPI_RAW_MAX]; } __attribute__ ((packed)); +enum { + RKISP_RTT_MODE_NORMAL = 0, + RKISP_RTT_MODE_MULTI_FRAME, + RKISP_RTT_MODE_ONE_FRAME, +}; + /** * struct rkisp_thunderboot_resmem_head */ @@ -1976,10 +1982,12 @@ struct rkisp_thunderboot_resmem_head { __u16 complete; __u16 frm_total; __u16 hdr_mode; + __u16 rtt_mode; __u16 width; __u16 height; __u16 camera_num; __u16 camera_index; + __u16 md_flag; __u32 exp_time[3]; __u32 exp_gain[3]; diff --git a/include/uapi/linux/rk-isp32-config.h b/include/uapi/linux/rk-isp32-config.h index cabd8c191c2d..ecd4eaef2cd3 100644 --- a/include/uapi/linux/rk-isp32-config.h +++ b/include/uapi/linux/rk-isp32-config.h @@ -52,7 +52,7 @@ #define ISP32_MODULE_CSM ISP3X_MODULE_CSM #define ISP32_MODULE_CGC ISP3X_MODULE_CGC #define ISP32_MODULE_VSM BIT_ULL(45) - +#define ISP32_MODULE_RTT_FST BIT_ULL(62) #define ISP32_MODULE_FORCE ISP3X_MODULE_FORCE /* Measurement types */ @@ -70,6 +70,7 @@ #define ISP32_STAT_DHAZ ISP3X_STAT_DHAZ #define ISP32_STAT_VSM BIT(18) #define ISP32_STAT_INFO2DDR BIT(19) +#define ISP32_STAT_RTT_FST BIT(31) #define ISP32_MESH_BUF_NUM ISP3X_MESH_BUF_NUM From 95d54529d9223a31f5ac52b3bbda051175caf203 Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Tue, 17 Oct 2023 14:25:01 +0800 Subject: [PATCH 16/31] media: rockchip: isp: fix resume hold by lut error Change-Id: I04264da03ac709963f8b50d18015cccc37daf141 Signed-off-by: Cai YiWei --- drivers/media/platform/rockchip/isp/hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/isp/hw.c b/drivers/media/platform/rockchip/isp/hw.c index 0d1adcb31454..f105afa33356 100644 --- a/drivers/media/platform/rockchip/isp/hw.c +++ b/drivers/media/platform/rockchip/isp/hw.c @@ -377,7 +377,8 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) RAWAE_BIG1_BASE, RAWAE_BIG2_BASE, RAWAE_BIG3_BASE, ISP_RAWHIST_LITE_BASE, ISP_RAWHIST_BIG1_BASE, ISP_RAWHIST_BIG2_BASE, ISP_RAWHIST_BIG3_BASE, - ISP_RAWAF_BASE, ISP_RAWAWB_BASE, + ISP_RAWAF_BASE, ISP_RAWAWB_BASE, ISP_LDCH_BASE, + ISP3X_CAC_BASE, }; struct backup_reg backup[] = { { From 6e83090a683ee51a50b3b87ee13f36f227490efa Mon Sep 17 00:00:00 2001 From: Wang Panzhenzhuan Date: Sat, 7 Oct 2023 11:24:59 +0000 Subject: [PATCH 17/31] arm64: dts: rockchip: rk3562-evb1-cam: add dw9714 supply control Signed-off-by: Wang Panzhenzhuan Change-Id: I8a01f184fdf6d743d87c94c9fe495c78d61e89c6 --- arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi b/arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi index b66f45e15824..492863b00fbe 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3562-evb1-cam.dtsi @@ -59,6 +59,7 @@ compatible = "dongwoon,dw9714"; status = "okay"; reg = <0x0c>; + avdd-supply = <&vcc2v8_dvp>; rockchip,vcm-start-current = <10>; rockchip,vcm-rated-current = <85>; rockchip,vcm-step-mode = <5>; From 7a20185e359415e288912db9eddeafb1aa496c5d Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Mon, 21 Aug 2023 10:00:59 +0800 Subject: [PATCH 18/31] ARM: dts: rockchip: rv1106g-evb2-v12-wakeup add rtt for isp node Change-Id: I3f185b0ea825ff6d9c9f0c1153417d79b95a0c17 Signed-off-by: Cai YiWei Signed-off-by: Zefa Chen --- arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts b/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts index 0ed1b84f05d1..eaeeccc40c9a 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts @@ -253,6 +253,9 @@ &rkisp_vir0 { status = "okay"; + memory-region-thunderboot = <&rkisp_thunderboot>; + rtt-suspend; + port@0 { isp_in: endpoint { remote-endpoint = <&mipi_lvds_sditf>; From f397a0261b1721c038ebce0fc4357639adec0111 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Tue, 17 Oct 2023 20:42:32 +0800 Subject: [PATCH 19/31] arm64: rockchip_defconfig: enable configs needed for RCU perf/power optimizations CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_BOOST=y CONFIG_RCU_NOCB_CPU=y According to gki commit e9b2f2878526 ("ANDROID: GKI: enable RCU configs") and commit c8701aa0a76b ("ANDROID: GKI: enable RCU_BOOST"). Change-Id: I441a203ffa85bff6eec244f1059faf8f97652ae0 Signed-off-by: Liang Chen --- arch/arm64/configs/rockchip_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/configs/rockchip_defconfig b/arch/arm64/configs/rockchip_defconfig index b19d854fc7da..ccf7e54fc9ed 100644 --- a/arch/arm64/configs/rockchip_defconfig +++ b/arch/arm64/configs/rockchip_defconfig @@ -9,6 +9,10 @@ CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_PSI=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_IKHEADERS=m From ca2973c80a16da3fb3d6ee9707db3d2248d90ed2 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Tue, 17 Oct 2023 20:49:47 +0800 Subject: [PATCH 20/31] arm64: rockchip_linux_defconfig: enable configs needed for RCU perf/power optimizations CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y Change-Id: I57cb51402e2137938ca46b4d31cf27e2cd32242f Signed-off-by: Liang Chen --- arch/arm64/configs/rockchip_linux_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index da5af4b275b2..5df82f41cf8f 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -3,6 +3,9 @@ CONFIG_SYSVIPC=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=18 From b0fa3b415db575b0510b67397e1a52f3583af601 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Tue, 17 Oct 2023 20:53:36 +0800 Subject: [PATCH 21/31] arm64: dts: rockchip: rk3588-android: set rcu_expedited/rcu_nocbs Change-Id: Ifff59d83e49f1b69a6b575d11a04fecb8a580ad8 Signed-off-by: Liang Chen --- arch/arm64/boot/dts/rockchip/rk3588-android.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi index 8901a033e9de..174001fd8e7c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi @@ -6,7 +6,7 @@ / { chosen: chosen { - bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0"; + bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 rcupdate.rcu_expedited=1 rcu_nocbs=all"; }; cspmu: cspmu@fd10c000 { From fb636d97d0f65c9a9966c6ea1fd8c0c6d66f8fb0 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Tue, 17 Oct 2023 20:56:58 +0800 Subject: [PATCH 22/31] arm64: dts: rockchip: rk3588-linux: set rcu_expedited/rcu_nocbs Change-Id: I66650255d2f961ac774135f778f25341d7b30ef4 Signed-off-by: Liang Chen --- arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi index 12b815850b57..d3f937b38228 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-linux.dtsi @@ -12,7 +12,7 @@ }; chosen: chosen { - bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTUUID=614e0000-0000 rw rootwait"; + bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTUUID=614e0000-0000 rw rootwait rcupdate.rcu_expedited=1 rcu_nocbs=all"; }; cspmu: cspmu@fd10c000 { From 8ad098a280199af885bc8236bdf5482a2b181913 Mon Sep 17 00:00:00 2001 From: William Wu Date: Mon, 16 Oct 2023 17:17:44 +0800 Subject: [PATCH 23/31] arm64: dts: rockchip: rk3588s: Add compatible for ohci Signed-off-by: William Wu Change-Id: I554bfc9f4546ddfff606475e0086e2c087d122dd --- arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index a9d49518b024..9bf6880d3239 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -2597,7 +2597,7 @@ }; usb_host0_ohci: usb@fc840000 { - compatible = "generic-ohci"; + compatible = "rockchip,rk3588-ohci", "generic-ohci"; reg = <0x0 0xfc840000 0x0 0x40000>; interrupts = ; clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST_ARB0>, <&u2phy2>, <&aclk_usb>; @@ -2622,7 +2622,7 @@ }; usb_host1_ohci: usb@fc8c0000 { - compatible = "generic-ohci"; + compatible = "rockchip,rk3588-ohci", "generic-ohci"; reg = <0x0 0xfc8c0000 0x0 0x40000>; interrupts = ; clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST_ARB1>, <&u2phy3>, <&aclk_usb>; From fa63778a211abaef7cdabf94cdd455eb3894390f Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 26 Sep 2023 12:01:17 +0800 Subject: [PATCH 24/31] usb: host: ohci-platform: enable async suspend for rk3588 The rk3588 has two ohci controllers, and the ohci_resume() takes a long time when system resume. Considering that the delay time in the ohci_resume() is related to controller hardware, we should not modify the delay time. This patch enable async suspend for rk3588 ohci controllers, then they can do asynchronous resume. Note that it generally is unsafe to permit the asynchronous suspend/resume for ohci because we can't certain that the PM dependencies of the ohci. However, for rk3588, we have add device_link between the ohci and ehci with the commit 68850661b51e ("usb: host: ehci-platform: Add device_link between the ehci and companion"), so we can safely enable async suspend/resume for rk3588 ohci. Signed-off-by: William Wu Change-Id: Ia74fc59c2c75a4bdc34d0de0a7bd047c178e9971 --- drivers/usb/host/ohci-platform.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 4923536780ee..aa9bc2edf7fc 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -216,6 +216,10 @@ static int ohci_platform_probe(struct platform_device *dev) device_wakeup_enable(hcd->self.controller); + if (of_device_is_compatible(dev->dev.of_node, + "rockchip,rk3588-ohci")) + device_enable_async_suspend(hcd->self.controller); + platform_set_drvdata(dev, hcd); return err; From f696e5532968478ef433f8a1954303e84bcd7744 Mon Sep 17 00:00:00 2001 From: Cody Xie Date: Tue, 17 Oct 2023 20:48:43 +0800 Subject: [PATCH 25/31] media: i2c: maxim4c: Fix unbalanced disable of PoC regulator Change-Id: I446e5774b460c55ba3feb91d7544c354f1e8886c Signed-off-by: Cody Xie --- drivers/media/i2c/maxim4c/maxim4c_drv.c | 31 ++++++++++++++++++------ drivers/media/i2c/maxim4c/maxim4c_v4l2.c | 11 ++++----- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/media/i2c/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim4c/maxim4c_drv.c index 16d11afb4828..9d9df08b4dbd 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim4c/maxim4c_drv.c @@ -29,10 +29,12 @@ * V2.03.00 * 1. remote device add the maxim4c prefix to driver name. * - * V2.04.02 + * V2.04.03 * 1. Add regulator supplier dependencies. * 2. Add config ssc-ratio property * 3. Add debugfs entry to change MIPI timing + * 4. Use PM runtime autosuspend feature + * 5. Fix unbalanced disabling for PoC regulator * */ #include @@ -63,7 +65,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x02) +#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x03) #define MAXIM4C_XVCLK_FREQ 25000000 @@ -681,6 +683,14 @@ static int maxim4c_probe(struct i2c_client *client, if (ret) goto err_destroy_mutex; + ret = maxim4c_remote_device_power_on(maxim4c); + if (ret) + dev_warn(dev, "Power on PoC regulator failed\n"); + + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + ret = maxim4c_check_local_chipid(maxim4c); if (ret) goto err_power_off; @@ -704,9 +714,10 @@ static int maxim4c_probe(struct i2c_client *client, goto err_power_off; #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; #endif /* MAXIM4C_TEST_PATTERN */ @@ -731,9 +742,10 @@ static int maxim4c_probe(struct i2c_client *client, maxim4c_lock_irq_init(maxim4c); maxim4c_lock_state_work_init(maxim4c); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; @@ -742,6 +754,9 @@ err_dbgfs_deinit: err_subdev_deinit: maxim4c_v4l2_subdev_deinit(maxim4c); err_power_off: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + maxim4c_remote_device_power_off(maxim4c); maxim4c_local_device_power_off(maxim4c); err_destroy_mutex: mutex_destroy(&maxim4c->mutex); diff --git a/drivers/media/i2c/maxim4c/maxim4c_v4l2.c b/drivers/media/i2c/maxim4c/maxim4c_v4l2.c index 37df9a622f59..b40fdf2b3632 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_v4l2.c +++ b/drivers/media/i2c/maxim4c/maxim4c_v4l2.c @@ -589,21 +589,20 @@ static int maxim4c_s_stream(struct v4l2_subdev *sd, int on) goto unlock_and_return; if (on) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) goto unlock_and_return; - } ret = __maxim4c_start_stream(maxim4c); if (ret) { v4l2_err(sd, "start stream failed while write regs\n"); - pm_runtime_put(&client->dev); + pm_runtime_put_sync(&client->dev); goto unlock_and_return; } } else { __maxim4c_stop_stream(maxim4c); - pm_runtime_put(&client->dev); + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); } maxim4c->streaming = on; From 7c27dbc54d74529b7d59c2f6b4afbf36befba7b4 Mon Sep 17 00:00:00 2001 From: Cody Xie Date: Tue, 17 Oct 2023 20:50:05 +0800 Subject: [PATCH 26/31] arm64: dts: rockchip: rk3588-vehicle-evb-v22: Use location name for camera regulators Change-Id: Ic1d21d5d987a819d88675d0a88b0347cbf8256fb Signed-off-by: Cody Xie --- .../dts/rockchip/rk3588-vehicle-evb-v22.dts | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts index 701cc247f593..c51f55339127 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts @@ -149,11 +149,10 @@ }; }; - camera1_vcc12v_buck: camera1_vcc12v-buck { + dcphy0_vcc12v_buck: dcphy0_vcc12v-buck { compatible = "regulator-fixed"; - regulator-name = "camera1_vcc12v_buck"; + regulator-name = "dcphy0_vcc12v_buck"; regulator-boot-on; - regulator-always-on; regulator-min-microvolt = <12000000>; regulator-max-microvolt = <12000000>; enable-active-high; @@ -167,11 +166,10 @@ }; }; - camera2_vcc12v_buck: camera2_vcc12v-buck { + dcphy1_vcc12v_buck: dcphy1_vcc12v-buck { compatible = "regulator-fixed"; - regulator-name = "camera2_vcc12v_buck"; + regulator-name = "dcphy1_vcc12v_buck"; regulator-boot-on; - regulator-always-on; regulator-min-microvolt = <12000000>; regulator-max-microvolt = <12000000>; enable-active-high; @@ -185,11 +183,10 @@ }; }; - camera3_vcc12v_buck: camera3_vcc12v-buck { + dphy0_vcc12v_buck: dphy0_vcc12v-buck { compatible = "regulator-fixed"; - regulator-name = "camera3_vcc12v_buck"; + regulator-name = "dphy0_vcc12v_buck"; regulator-boot-on; - regulator-always-on; regulator-min-microvolt = <12000000>; regulator-max-microvolt = <12000000>; enable-active-high; @@ -203,11 +200,10 @@ }; }; - camera4_vcc12v_buck: camera4_vcc12v-buck { + dphy3_vcc12v_buck: dphy3_vcc12v-buck { compatible = "regulator-fixed"; - regulator-name = "camera4_vcc12v_buck"; + regulator-name = "dphy3_vcc12v_buck"; regulator-boot-on; - regulator-always-on; regulator-min-microvolt = <12000000>; regulator-max-microvolt = <12000000>; enable-active-high; @@ -348,7 +344,7 @@ }; &max96712_dphy3_poc { - vin-supply = <&camera1_vcc12v_buck>; + vin-supply = <&dphy3_vcc12v_buck>; }; &avdd1v8_ddr_pll_s0 { From 194a7d5a7567395d37e11ffa9014589b83ba8aad Mon Sep 17 00:00:00 2001 From: Zhen Chen Date: Fri, 13 Oct 2023 15:37:30 +0800 Subject: [PATCH 27/31] MALI: bifrost: Fix a null pointer exception when event tracing is enabled The issue was reported in https://redmine.rock-chips.com/issues/442097. The kernel crash log: [ 10.737137][ T1028] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000010 ... [ 10.747955][ T1028] pc : __pi_strlen+0x60/0x84 [ 10.748673][ T1028] lr : trace_event_raw_event_dma_fence+0xe0/0x1e8 ... [ 10.761907][ T1028] Call trace: [ 10.762198][ T1028] __pi_strlen+0x60/0x84 [ 10.762561][ T1028] dma_fence_init+0xd4/0xfc [ 10.762951][ T1028] kbasep_kcpu_fence_signal_init+0x6c/0x1b0 [ 10.763454][ T1028] kbase_kcpu_fence_signal_prepare+0x6c/0x134 [ 10.763980][ T1028] kbase_csf_kcpu_queue_enqueue+0x1d0/0x10ec [ 10.764499][ T1028] kbase_ioctl+0xa80/0xf78 [ 10.764890][ T1028] __arm64_sys_ioctl+0x90/0xc8 [ 10.765296][ T1028] el0_svc_common+0xac/0x1ac [ 10.765691][ T1028] do_el0_svc+0x1c/0x28 [ 10.766058][ T1028] el0_svc+0x10/0x1c [ 10.766389][ T1028] el0_sync_handler+0x68/0xac [ 10.766796][ T1028] el0_sync+0x160/0x180 Change-Id: I68739107dd9486b3a964746583c526a51f68e1ae Signed-off-by: Zhen Chen --- drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c index 2b4d4a437213..da8dde239972 100644 --- a/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c +++ b/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_kcpu.c @@ -1604,6 +1604,10 @@ static int kbasep_kcpu_fence_signal_init(struct kbase_kcpu_command_queue *kcpu_q if (!kcpu_fence) return -ENOMEM; + /* Set reference to KCPU metadata and increment refcount */ + kcpu_fence->metadata = kcpu_queue->metadata; + WARN_ON(!kbase_refcount_inc_not_zero(&kcpu_fence->metadata->refcount)); + #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) fence_out = (struct fence *)kcpu_fence; #else @@ -1625,10 +1629,6 @@ static int kbasep_kcpu_fence_signal_init(struct kbase_kcpu_command_queue *kcpu_q dma_fence_get(fence_out); #endif - /* Set reference to KCPU metadata and increment refcount */ - kcpu_fence->metadata = kcpu_queue->metadata; - WARN_ON(!kbase_refcount_inc_not_zero(&kcpu_fence->metadata->refcount)); - /* create a sync_file fd representing the fence */ *sync_file = sync_file_create(fence_out); if (!(*sync_file)) { From fe7022a2f09824928f7a8353cb0bfc919024ca86 Mon Sep 17 00:00:00 2001 From: Wenping Zhang Date: Fri, 11 Aug 2023 03:52:47 +0000 Subject: [PATCH 28/31] dt-bindings: soc: rockchip: add reboot mode winusb. winusb mode is used to capture minidump in uboot through usb when kernel panic. Change-Id: I493d32746fd4030f8e7a1466d8a9b2f8bf3a3ccc Signed-off-by: Wenping Zhang --- include/dt-bindings/soc/rockchip,boot-mode.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/soc/rockchip,boot-mode.h b/include/dt-bindings/soc/rockchip,boot-mode.h index ec4e5dd83cc1..a0f63a040613 100644 --- a/include/dt-bindings/soc/rockchip,boot-mode.h +++ b/include/dt-bindings/soc/rockchip,boot-mode.h @@ -22,5 +22,7 @@ #define BOOT_UMS (REBOOT_FLAG + 12) /* reboot system quiescent */ #define BOOT_QUIESCENT (REBOOT_FLAG + 14) +/* reboot by panic and capture ramdump in uboot through usb */ +#define BOOT_WINUSB (REBOOT_FLAG + 15) #endif From a89996259850dc969c98d8ec10058ca825d0dd9f Mon Sep 17 00:00:00 2001 From: Wenping Zhang Date: Fri, 11 Aug 2023 03:56:37 +0000 Subject: [PATCH 29/31] arm64: dts: rockchip: rk3588s: add winusb reboot mode. Change-Id: Ie3eae1892e679a078aad79403e28af1cadff3832 Signed-off-by: Wenping Zhang --- arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 9bf6880d3239..7d1685fc562d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -2706,6 +2706,8 @@ mode-panic = ; mode-watchdog = ; mode-quiescent = ; + /* add a mode to capture the ramdump through usb */ + mode-winusb = ; }; }; From abdfc22491bbbe0fc5db612606cb48989b7b420f Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 21 Aug 2023 20:13:28 +0800 Subject: [PATCH 30/31] ARM: dts: rockchip: rv1106g-evb2-v12-wakeup add rtt for vicap node Signed-off-by: Zefa Chen Change-Id: I6023ffe9a79173998bacece428e4f38b1d7ff8fa --- arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts b/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts index eaeeccc40c9a..4ab4b1131232 100644 --- a/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts +++ b/arch/arm/boot/dts/rv1106g-evb2-v12-wakeup.dts @@ -223,7 +223,8 @@ &rkcif_mipi_lvds { status = "okay"; - //memory-region-thunderboot = <&rkisp_thunderboot>; + memory-region-thunderboot = <&rkisp_thunderboot>; + rtt-suspend; pinctrl-names = "default"; pinctrl-0 = <&mipi_pins>; From 8bbe906daa75d355607df9b586a5beb7adf3bf45 Mon Sep 17 00:00:00 2001 From: Luo Wei Date: Mon, 16 Oct 2023 19:33:55 +0800 Subject: [PATCH 31/31] mfd: display-serdes: power off remote serdes while shutdown Signed-off-by: Luo Wei Change-Id: Ic358750583e2cb94a79710cabc84bc739bf12b12 --- drivers/mfd/display-serdes/core.h | 3 ++- drivers/mfd/display-serdes/serdes-core.c | 25 +++++++++++++++++++++++- drivers/mfd/display-serdes/serdes-i2c.c | 11 ++++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/display-serdes/core.h b/drivers/mfd/display-serdes/core.h index 28f994588964..e05ff39236c3 100644 --- a/drivers/mfd/display-serdes/core.h +++ b/drivers/mfd/display-serdes/core.h @@ -334,7 +334,8 @@ int serdes_set_pinctrl_default(struct serdes *serdes); int serdes_set_pinctrl_sleep(struct serdes *serdes); int serdes_device_suspend(struct serdes *serdes); int serdes_device_resume(struct serdes *serdes); -void serdes_device_shutdown(struct serdes *serdes); +void serdes_device_poweroff(struct serdes *serdes); +int serdes_device_shutdown(struct serdes *serdes); int serdes_irq_init(struct serdes *serdes); void serdes_irq_exit(struct serdes *serdes); void serdes_auxadc_init(struct serdes *serdes); diff --git a/drivers/mfd/display-serdes/serdes-core.c b/drivers/mfd/display-serdes/serdes-core.c index 5ef62f8e4d75..08805244f928 100644 --- a/drivers/mfd/display-serdes/serdes-core.c +++ b/drivers/mfd/display-serdes/serdes-core.c @@ -376,7 +376,7 @@ int serdes_device_resume(struct serdes *serdes) } EXPORT_SYMBOL_GPL(serdes_device_resume); -void serdes_device_shutdown(struct serdes *serdes) +void serdes_device_poweroff(struct serdes *serdes) { int ret = 0; @@ -385,6 +385,29 @@ void serdes_device_shutdown(struct serdes *serdes) if (ret) dev_err(serdes->dev, "could not set sleep pins\n"); } + + if (!IS_ERR(serdes->vpower)) { + ret = regulator_disable(serdes->vpower); + if (ret) + dev_err(serdes->dev, "fail to disable vpower regulator\n"); + } + +} +EXPORT_SYMBOL_GPL(serdes_device_poweroff); + +int serdes_device_shutdown(struct serdes *serdes) +{ + int ret = 0; + + if (!IS_ERR(serdes->vpower)) { + ret = regulator_disable(serdes->vpower); + if (ret) { + dev_err(serdes->dev, "fail to disable vpower regulator\n"); + return ret; + } + } + + return ret; } EXPORT_SYMBOL_GPL(serdes_device_shutdown); diff --git a/drivers/mfd/display-serdes/serdes-i2c.c b/drivers/mfd/display-serdes/serdes-i2c.c index 237b1e61ded4..c95469bc07bb 100644 --- a/drivers/mfd/display-serdes/serdes-i2c.c +++ b/drivers/mfd/display-serdes/serdes-i2c.c @@ -223,6 +223,14 @@ static int serdes_i2c_probe(struct i2c_client *client, return 0; } +static void serdes_i2c_shutdown(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct serdes *serdes = dev_get_drvdata(dev); + + serdes_device_shutdown(serdes); +} + static int serdes_i2c_prepare(struct device *dev) { return 0; @@ -264,7 +272,7 @@ static int serdes_i2c_poweroff(struct device *dev) { struct serdes *serdes = dev_get_drvdata(dev); - serdes_device_shutdown(serdes); + serdes_device_poweroff(serdes); return 0; } @@ -315,6 +323,7 @@ static struct i2c_driver serdes_i2c_driver = { .of_match_table = of_match_ptr(serdes_of_match), }, .probe = serdes_i2c_probe, + .shutdown = serdes_i2c_shutdown, }; static int __init serdes_i2c_init(void)