/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ /* * drivers/nand/phy/amlnand_init.c * * Copyright (C) 2020 Amlogic, Inc. All rights reserved. * */ #include "../include/phynand.h" #include #include struct amlnand_chip *aml_nand_chip = NULL; extern int boot_dev_init(struct amlnand_chip *aml_chip); static void show_nand_driver_version(void) { aml_nand_msg("Nand PHY Ver:%d.%02d.%03d.%04d (c) 2013 Amlogic Inc.", (DRV_PHY_VERSION >> 24)&0xff, (DRV_PHY_VERSION >> 16)&0xff, (DRV_PHY_VERSION >> 8)&0xff, (DRV_PHY_VERSION)&0xff); } static int amlnf_phy_resource(struct amlnand_chip *aml_chip, struct platform_device *pdev) { int ret = 0; if (aml_chip == NULL) { aml_nand_msg("%s() %d: invalid param!", __FUNCTION__, __LINE__); ret = -1; goto _out; } #ifndef AML_NAND_UBOOT aml_chip->device = pdev->dev; aml_nand_msg("%s() %d: amlnf init flag %d", __FUNCTION__, __LINE__, aml_chip->init_flag); #ifdef CONFIG_OF aml_chip->nand_pinctrl = devm_pinctrl_get(&aml_chip->device); if (IS_ERR(aml_chip->nand_pinctrl)) { aml_nand_msg("get pinctrl error"); return PTR_ERR(aml_chip->nand_pinctrl); } aml_chip->nand_rbstate = pinctrl_lookup_state(aml_chip->nand_pinctrl, "nand_rb_mod"); if (IS_ERR(aml_chip->nand_rbstate)) { devm_pinctrl_put(aml_chip->nand_pinctrl); return PTR_ERR(aml_chip->nand_rbstate); } aml_chip->nand_norbstate = pinctrl_lookup_state(aml_chip->nand_pinctrl, "nand_norb_mod"); if (IS_ERR(aml_chip->nand_norbstate)) { devm_pinctrl_put(aml_chip->nand_pinctrl); return PTR_ERR(aml_chip->nand_norbstate); } aml_chip->nand_idlestate = pinctrl_lookup_state(aml_chip->nand_pinctrl, "nand_cs_pins_only"); if (IS_ERR(aml_chip->nand_idlestate)) { devm_pinctrl_put(aml_chip->nand_pinctrl); return PTR_ERR(aml_chip->nand_idlestate); } #endif /* CONFIG_OF */ #endif /* AML_NAND_UBOOT */ _out: return ret; } extern int dbg_amlnf_erase_ops(u64 off, u64 erase_len, unsigned char scrub_flag); extern void amlnf_get_chip_size(u64 *size); void dbg_erase_whole_chip(struct amlnand_chip *aml_chip) { struct nand_flash *flash = &aml_chip->flash; u64 chipsize; PHY_NAND_LINE //amlnf_get_chip_size(&chipsize); chipsize = flash->blocksize * 4; //erase 1st 60 blocks. PHY_NAND_LINE dbg_amlnf_erase_ops(0, chipsize, 1); } //------------------------------------------------------------------------------------------------------------------- extern void _dump_mem(u32 * buf, u32 len); #define DBG_OOB_LEN (8) static void dbg_buffer_free(struct amlnand_chip *aml_chip) { if (aml_chip->user_oob_buf != NULL) kfree(aml_chip->user_oob_buf); if (aml_chip->user_page_buf != NULL) kfree(aml_chip->user_page_buf); return; } static void dbg_buffer_alloc(struct amlnand_chip *aml_chip) { struct hw_controller *controller = &aml_chip->controller; struct nand_flash *flash = &aml_chip->flash; u32 buf_size; buf_size = flash->oobsize * controller->chip_num; if (flash->option & NAND_MULTI_PLANE_MODE) buf_size <<= 1; aml_chip->user_oob_buf = aml_nand_malloc(buf_size); if (aml_chip->user_oob_buf == NULL) { aml_nand_msg("malloc failed for user_oob_buf "); goto _out; } memset(aml_chip->user_oob_buf, 0x0, buf_size); buf_size = (flash->pagesize + flash->oobsize) * controller->chip_num; if (flash->option & NAND_MULTI_PLANE_MODE) buf_size <<= 1; aml_chip->user_page_buf = aml_nand_malloc(buf_size); if (aml_chip->user_page_buf == NULL) { aml_nand_msg("malloc failed for user_page_buf "); goto _out; } memset(aml_chip->user_page_buf, 0x0, buf_size); return; _out: dbg_buffer_free(aml_chip); return; } void dbg_calcaddress(u8 chip, u32 blk, u32 page, struct amlnand_chip *aml_chip) { struct nand_flash *flash = &aml_chip->flash; struct chip_ops_para *ops_para = &aml_chip->ops_para; u8 phys_erase_shift, phys_page_shift; u32 pages_per_blk; phys_erase_shift = ffs(flash->blocksize) - 1; phys_page_shift = ffs(flash->pagesize) - 1; pages_per_blk = (1 << (phys_erase_shift - phys_page_shift)); ops_para->chipnr = chip; ops_para->page_addr = blk * pages_per_blk + page; ops_para->ooblen = DBG_OOB_LEN; printk("%s(%d, %d, %d) - %x\n", __func__, chip, blk, page, ops_para->page_addr); } void dbg_ereaeblk(u8 chip, u32 blk, struct amlnand_chip *aml_chip) { struct hw_controller *controller = &aml_chip->controller; struct chip_operation *operation = &aml_chip->operation; struct chip_ops_para *ops_para = &aml_chip->ops_para; int ret; memset((u8 *)ops_para, 0x0, sizeof(struct chip_ops_para)); dbg_calcaddress(chip, blk, 0, aml_chip); ops_para->data_buf = aml_chip->user_page_buf; ops_para->oob_buf = aml_chip->user_oob_buf; controller->select_chip(controller, ops_para->chipnr); nand_get_chip(aml_chip); ret = operation->erase_block(aml_chip); if (ret < 0) { aml_nand_msg("%s() %d: nand erased failed", __func__, __LINE__); } nand_release_chip(aml_chip); } void dbg_readpage(u8 chip, u32 blk, u32 page, struct amlnand_chip *aml_chip) { struct hw_controller *controller = &aml_chip->controller; struct nand_flash *flash = &aml_chip->flash; struct chip_operation *operation = &aml_chip->operation; struct chip_ops_para *ops_para = &aml_chip->ops_para; int ret; memset((u8 *)ops_para, 0x0, sizeof(struct chip_ops_para)); memset(ops_para->data_buf, 0x0, flash->pagesize); memset(ops_para->oob_buf, 0x0, DBG_OOB_LEN); dbg_calcaddress(chip, blk, page, aml_chip); ops_para->data_buf = aml_chip->user_page_buf; ops_para->oob_buf = aml_chip->user_oob_buf; controller->select_chip(controller, ops_para->chipnr); nand_get_chip(aml_chip); ret = operation->read_page(aml_chip); if (ret < 0) { aml_nand_msg("%s() %d: nand read failed", __func__, __LINE__); } nand_release_chip(aml_chip); _dump_mem((u32 *)ops_para->oob_buf, DBG_OOB_LEN); _dump_mem((u32 *)ops_para->data_buf, 512); } void dbg_writepage(u8 chip, u32 blk, u32 page, struct amlnand_chip *aml_chip) { struct hw_controller *controller = &aml_chip->controller; struct nand_flash *flash = &aml_chip->flash; struct chip_operation *operation = &aml_chip->operation; struct chip_ops_para *ops_para = &aml_chip->ops_para; int ret; memset((u8 *)ops_para, 0x0, sizeof(struct chip_ops_para)); dbg_calcaddress(chip, blk, page, aml_chip); ops_para->data_buf = aml_chip->user_page_buf; ops_para->oob_buf = aml_chip->user_oob_buf; memset(ops_para->data_buf, 0xAA, flash->pagesize); memset(ops_para->oob_buf, 0x55, DBG_OOB_LEN); controller->select_chip(controller, ops_para->chipnr); nand_get_chip(aml_chip); ret = operation->write_page(aml_chip); if (ret < 0) { aml_nand_msg("%s() %d: nand write failed", __func__, __LINE__); } nand_release_chip(aml_chip); } void dbg_phyop( void ) { /* u64 blksize; */ struct amlnand_chip *aml_chip = aml_nand_chip; /* struct hw_controller *controller = &aml_chip->controller; */ /* struct nand_flash *flash = &aml_chip->flash; */ PHY_NAND_LINE dbg_buffer_alloc(aml_chip); PHY_NAND_LINE #if 0 blksize = (u64) flash->blocksize; PHY_NAND_LINE printk("erase\n"); amlnf_erase_ops(0, blksize * 2, 1); printk("erase again\n"); dbg_ereaeblk(0, 0, aml_chip); #endif PHY_NAND_LINE //write page here //printk("read after erase!\n"); dbg_readpage(0, 80, 0, aml_chip); dbg_readpage(0, 81, 0, aml_chip); PHY_NAND_LINE //read page here. #if 0 printk("write!\n"); dbg_writepage(0, 0, 0, aml_chip); printk("read!\n"); dbg_readpage(0, 0, 0, aml_chip); PHY_NAND_LINE #endif //0 dbg_buffer_free(aml_chip); } void amlnand_clear_pinmux(struct amlnand_chip *aml_chip) { amlnf_clr_reg32_mask(P_PERIPHS_PIN_MUX_4,(0x7ff<<20)); return; } int amlnf_phy_init(u8 flag, struct platform_device *pdev) { struct amlnand_chip *aml_chip = NULL; int ret = 0; /*show nand phy version here.*/ show_nand_driver_version(); aml_chip = aml_nand_malloc(sizeof(struct amlnand_chip)); if (aml_chip == NULL) { aml_nand_msg("malloc failed for aml_chip:%x", (uint32_t)sizeof(struct amlnand_chip)); ret = -NAND_MALLOC_FAILURE; goto exit_error1; } memset(aml_chip , 0, sizeof(struct amlnand_chip)); memset(aml_chip->reserved_blk, 0xff, RESERVED_BLOCK_CNT); aml_chip->init_flag = flag; aml_chip->nand_status = NAND_STATUS_NORMAL; aml_nand_chip = aml_chip; PHY_NAND_LINE ret = amlnf_phy_resource(aml_chip, pdev); if (ret) goto exit_error1; PHY_NAND_LINE /* Step 1: init hw controller */ ret = amlnand_hwcontroller_init(aml_chip); if (ret < 0) { aml_nand_msg("aml_hw_controller_init failed"); ret = -NAND_FAILED; goto exit_error1; } PHY_NAND_LINE /* Step 2: init aml_chip operation */ ret = amlnand_init_operation(aml_chip); if (ret < 0) { aml_nand_msg("chip detect failed and ret:%x", ret); ret = -NAND_FAILED; goto exit_error1; } PHY_NAND_LINE /* Step 3: get nand id and get hw flash information */ ret = amlnand_chip_init(aml_chip); if (ret < 0) { aml_nand_msg("chip detect failed and ret:%x", ret); device_boot_flag = EMMC_BOOT_FLAG; amlnand_clear_pinmux(aml_chip); ret = -NAND_FAILED; goto exit_error1; } PHY_NAND_LINE /* update device_boot_flag for outsides */ device_boot_flag = NAND_BOOT_FLAG; /* write 2 gp2*/ secure_storage_set_info(STORAGE_DEV_NAND); PHY_NAND_LINE if (aml_chip->init_flag == NAND_SCAN_ID_INIT) goto exit_error1; PHY_NAND_LINE //fixme, debug code //dbg_phyop(aml_chip); //dbg_erase_whole_chip(aml_chip); /* step 3.5 init boot phydev 1st, then we can operate uboot no matter what happens further.*/ boot_dev_init(aml_chip); if (aml_chip->init_flag == 6) { //NAND_PHY_INIT PHY_NAND_LINE goto exit_error0; } //Step 4: get device configs ret = amlnand_get_dev_configs(aml_chip); if (ret < 0) { if ((ret == -NAND_CONFIGS_FAILED) || (ret == -NAND_SHIPPED_BADBLOCK_FAILED) || (ret == -NAND_DETECT_DTB_FAILED)) { aml_nand_msg("get device configs failed and ret:%x", ret); goto exit_error0; }else{ aml_nand_msg("get device configs failed and ret:%x", ret); ret = -NAND_READ_FAILED; goto exit_error0; } } PHY_NAND_LINE if (aml_chip->init_flag >= NAND_BOOT_ERASE_PROTECT_CACHE) { struct hw_controller *controller = &aml_chip->controller; #ifndef AML_NAND_UBOOT struct nand_flash *flash = &aml_chip->flash; amlnf_dma_free(controller->data_buf, (flash->pagesize + flash->oobsize), 0); amlnf_dma_free(controller->user_buf, (flash->pagesize /controller->ecc_bytes)*sizeof(int), 1); #else /* AML_NAND_UBOOT */ aml_nand_free(controller->data_buf); aml_nand_free(controller->user_buf); #endif /* AML_NAND_UBOOT */ //aml_nand_free(controller->page_buf); aml_nand_free(controller->oob_buf); //nand_buf_free(aml_chip); /*exit with error code in porpoises, while we are erasing.*/ ret = -1; goto exit_error1; }else{ //Step 5: register nand device, and config device information PHY_NAND_LINE ret = amlnand_phydev_init(aml_chip); PHY_NAND_LINE if (ret < 0) { aml_nand_msg("register nand device failed and ret:%x", ret); ret = -NAND_READ_FAILED; goto exit_error0; } } return ret; exit_error1: aml_nand_free(aml_chip); exit_error0: return ret; }