// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include "../include/amlnf_dev.h" #include "../include/phynand.h" #include #include "partition_table.h" int boot_device_flag = 0; struct aml_nand_device *aml_nand_dev = NULL; extern uint32_t amlnf_get_rsv_size(const char *name); extern int amlnf_read_rsv(const char *name, size_t size, void *buf); extern int amlnf_write_rsv(const char *name, size_t size, void *buf); extern int amlnf_erase_rsv(const char *name); extern u8 amlnf_boot_cpys(const char *part_name); extern u64 amlnf_boot_copy_size(const char *part_name); extern u64 amlnf_get_size(const char *part_name); extern int amlnf_read(const char *part_name, loff_t off, size_t size,void *dest); extern int amlnf_write(const char *part_name, loff_t off, size_t size, void *source); extern int amlnf_erase(const char *part_name, loff_t off, size_t size, int scrub_flag); extern int amlnf_boot_read(const char *part_name, uint8_t copy, size_t size, void *buf); extern int amlnf_boot_write(const char *part_name, uint8_t copy, size_t size, void *buf); extern int amlnf_boot_erase(const char *part_name, uint8_t copy); extern int amlnf_rsv_protect(const char *name, bool ops); extern void store_register(struct storage_t *store_dev); int is_phydev_off_adjust(void) { int ret = 0; #ifdef NAND_ADJUST_PART_TABLE ret = 1; #endif return ret ; } int get_adjust_block_num(void) { int ret = 0; #ifdef NAND_ADJUST_PART_TABLE ret = ADJUST_BLOCK_NUM; #endif return ret ; } int amlnf_get_logicdev(struct amlnf_logicdev_t *amlnf_logicdev) { #ifndef AML_NAND_UBOOT mutex_lock(&amlnf_logicdev->lock); #endif return 0; } int amlnf_free_logicdev(struct amlnf_logicdev_t *amlnf_logicdev) { #ifndef AML_NAND_UBOOT mutex_unlock(&amlnf_logicdev->lock); #endif return 0; } /***************************************************************************** *Name : *Description : *Parameter : *Return : *Note : *****************************************************************************/ #ifndef AML_NAND_UBOOT static struct class_attribute phydev_class_attrs[] = { __ATTR(info, S_IRUGO | S_IWUSR, show_nand_info, NULL), __ATTR(verify, S_IRUGO | S_IWUSR, NULL, verify_nand_page), __ATTR(dump, S_IRUGO | S_IWUSR, NULL, dump_nand_page), __ATTR(bbt_table, S_IRUGO | S_IWUSR, NULL, show_bbt_table), __ATTR(test_sync_flag, S_IRUGO | S_IWUSR, NULL, change_test_sync_flag), __ATTR(page_read, S_IRUGO | S_IWUSR, NULL, nand_page_read), __ATTR(page_write, S_IRUGO | S_IWUSR, NULL, nand_page_write), __ATTR(version, S_IRUGO | S_IWUSR, show_amlnf_version_info, NULL), __ATTR_NULL }; #if 0 static struct class_attribute logicdev_class_attrs[] = { __ATTR(part, S_IRUGO , show_part_struct, NULL), __ATTR(list, S_IRUGO , show_list, NULL), __ATTR(gcall, S_IRUGO , do_gc_all, NULL), __ATTR(gcone, S_IRUGO , do_gc_one, NULL), __ATTR(test, S_IRUGO | S_IWUSR , NULL, do_test), __ATTR_NULL }; static struct class_attribute nfdev_class_attrs[] = { __ATTR(debug, S_IRUGO , nfdev_debug, NULL), __ATTR_NULL }; #endif #if 0 static struct class phydev_class = { .name = "amlphydev", .owner = THIS_MODULE, .suspend = phydev_cls_suspend, .resume = phydev_cls_resume, }; #endif int amlnf_pdev_register(struct amlnand_phydev *phydev) { int ret = 0; /* phydev->dev.class = &phydev_class; */ dev_set_name(&phydev->dev, phydev->name, 0); dev_set_drvdata(&phydev->dev, phydev); ret = device_register(&phydev->dev); if (ret != 0) { aml_nand_msg("device register failed for %s", phydev->name); aml_nand_free(phydev); goto exit_error0; } phydev->cls.name = aml_nand_malloc(strlen((const char *)phydev->name)+8); snprintf((char *)phydev->cls.name, (MAX_DEVICE_NAME_LEN+8), "%s%s", "phy_", (char *)(phydev->name)); phydev->cls.class_attrs = phydev_class_attrs; ret = class_register(&phydev->cls); if (ret) { aml_nand_msg("class register nand_class fail for %s", phydev->name); goto exit_error1; } return 0; exit_error1: aml_nand_free(phydev->cls.name); exit_error0: return ret; } static int amlnf_blk_open(struct block_device *bdev, fmode_t mode) { return 0; } static void amlnf_blk_release(struct gendisk *disk, fmode_t mode) { return; } static int amlnf_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) { return 0; } static int amlnf_blk_ioctl(struct block_device *bdev, fmode_t mode, u32 cmd, u32 arg) { return 0; } static const struct block_device_operations amlnf_blk_ops = { .owner = THIS_MODULE, .open = amlnf_blk_open, .release = amlnf_blk_release, .ioctl = amlnf_blk_ioctl, .getgeo = amlnf_blk_getgeo, }; #define blk_queue_plugged(q) test_bit(18, &(q)->queue_flags) /***************************************************************************** *Name : *Description : *Parameter : *Return : *Note : for kernel; for boot is in logic\aml_nftl_init.c *****************************************************************************/ int amlnf_logic_init(u32 flag) { struct amlnand_phydev *phydev = NULL; int ret = 0; aml_nand_msg("amlnand_add_nftl:"); /* amlnand_show_dev_partition(aml_chip); */ list_for_each_entry(phydev, &nphy_dev_list, list) { if (phydev == NULL) break; if (strncmp((char *)phydev->name, NAND_BOOT_NAME, strlen((const char *)NAND_BOOT_NAME))) { ret = add_ntd_partitions(phydev); if (ret < 0) { aml_nand_msg("nand add nftl failed"); goto exit_error; } } if (!strncmp((char *)phydev->name, NAND_BOOT_NAME, strlen((const char *)NAND_BOOT_NAME))) { ret = boot_device_register(phydev); if (ret < 0) { aml_nand_msg("boot device registe failed"); goto exit_error; } } } exit_error: return ret; } static ssize_t nand_version_get(struct class *class, struct class_attribute *attr, char *buf) { sprintf(buf, "%d", DRV_PHY_VERSION); return 0; } static void show_partition_table(struct partitions *table) { int i = 0; struct partitions *par_table = NULL; aml_nand_msg("show partition table:"); for (i = 0; i < MAX_PART_NUM; i++) { par_table = &table[i]; if (par_table->size == -1) { aml_nand_msg("part: %d, name: %10s, size: %-4s", i, par_table->name, "end"); break; } else aml_nand_msg("part: %d, name : %10s, size : %-4llx", i, par_table->name, par_table->size); } return; } static ssize_t nand_part_table_get(struct class *class, struct class_attribute *attr, char *buf) { struct amlnand_phydev *phydev = NULL; struct amlnand_chip *aml_chip = NULL; struct nand_config *config = NULL; struct dev_para *dev_paramt = NULL; struct partitions *part_table = NULL; int i = 0, j = 0, k = 0, m = 0, tmp_num = 0; int device_num; device_num = (aml_chip->h_cache_dev)? 3 : 2; list_for_each_entry(phydev, &nphy_dev_list, list) { if ((phydev != NULL) && (!strncmp((char *)phydev->name, NAND_CODE_NAME, strlen((const char *)NAND_CODE_NAME)))) break; } aml_chip = (struct amlnand_chip *)phydev->priv; config = aml_chip->config_ptr; part_table = aml_nand_malloc(MAX_PART_NUM*sizeof(struct partitions)); if (!part_table) { aml_nand_msg("nand_part_table_get : malloc failed"); return 0; } memset(part_table, 0x0, MAX_PART_NUM*sizeof(struct partitions)); if (boot_device_flag == 1) { i += 1; tmp_num = i; } for (; i < device_num + 1; i++) { dev_paramt = &config->dev_para[i]; if ((!strncmp((char *)dev_paramt->name, NAND_CODE_NAME, strlen((const char *)NAND_CODE_NAME)))) { for (j = 0; j < dev_paramt->nr_partitions; j++) { memcpy(&(part_table[j].name), dev_paramt->partitions[j].name, MAX_NAND_PART_NAME_LEN); part_table[j].size = dev_paramt->partitions[j].size; part_table[j].offset = dev_paramt->partitions[j].offset; part_table[j].mask_flags = dev_paramt->partitions[j].mask_flags; /* aml_nand_msg("CODE: partition name %s, size %llx, offset %llx maskflag %d", part_table[j].name, part_table[j].size, part_table[j].offset, part_table[j].mask_flags); */ } break; } } i = tmp_num; for (; i < device_num + 1; i++) { dev_paramt = &config->dev_para[i]; /* aml_nand_msg("cache : dev_paramt name %s ",dev_paramt->name); */ if ((!strncmp((char *)dev_paramt->name, NAND_CACHE_NAME, strlen((const char *)NAND_CACHE_NAME)))) { k = j++; for (j = 0; j < dev_paramt->nr_partitions; k++, j++) { memcpy(&(part_table[k].name), dev_paramt->partitions[j].name, MAX_NAND_PART_NAME_LEN); part_table[k].size = dev_paramt->partitions[j].size; part_table[k].offset = dev_paramt->partitions[j].offset; part_table[k].mask_flags = dev_paramt->partitions[j].mask_flags; /* aml_nand_msg("CODE: partition name %s,size %llx, offset %llx maskflag %d", part_table[k].name, part_table[k].size, part_table[k].offset, part_table[k].mask_flags); */ } break; } } i = tmp_num; for (; i < device_num + 1; i++) { dev_paramt = &config->dev_para[i]; /* aml_nand_msg("dev_paramt name %s ",dev_paramt->name); */ if ((!strncmp((char *)dev_paramt->name, NAND_DATA_NAME, strlen((const char *)NAND_DATA_NAME)))) { m = k++; for (j = 0; j < dev_paramt->nr_partitions; j++) { memcpy(&(part_table[m].name), dev_paramt->partitions[j].name, MAX_NAND_PART_NAME_LEN); part_table[m].size = dev_paramt->partitions[j].size; part_table[m].offset = dev_paramt->partitions[j].offset; part_table[m].mask_flags = dev_paramt->partitions[j].mask_flags; /* aml_nand_msg("CODE:partition name %s,size %llx, offset %llx maskflag %d", part_table[m].name, part_table[m].size, part_table[m].offset, part_table[m].mask_flags); */ } break; } } show_partition_table(part_table); memcpy(buf, part_table, MAX_PART_NUM*sizeof(struct partitions)); kfree(part_table); part_table = NULL; return 0; } static ssize_t store_device_flag_get(struct class *class, struct class_attribute *attr, char *buf) { sprintf(buf, "%d", boot_device_flag); return 0; } static struct class_attribute aml_version = __ATTR(version, S_IRUGO, nand_version_get, NULL); static struct class_attribute aml_part_table = __ATTR(part_table, S_IRUGO, nand_part_table_get, NULL); static struct class_attribute aml_store_device = __ATTR(store_device, S_IRUGO, store_device_flag_get, NULL); #endif /* AML_NAND_UBOOT */ /***************************************************************************** *Name : *Description : *Parameter : *Return : *Note : *****************************************************************************/ int amlnf_dev_init(u32 flag) { #ifndef AML_NAND_UBOOT struct amlnand_phydev *phydev = NULL; /* struct amlnf_dev* nf_dev = NULL; */ struct class *aml_store_class = NULL; int ret = 0; list_for_each_entry(phydev, &nphy_dev_list, list) { if ((phydev != NULL) && (strncmp((char *)phydev->name, NAND_BOOT_NAME, strlen((const char *)NAND_BOOT_NAME)))) { ret = amlnf_pdev_register(phydev); if (ret < 0) { aml_nand_msg("nand add nftl failed"); goto exit_error0; } } } aml_store_class = class_create(THIS_MODULE, "aml_store"); if (IS_ERR(aml_store_class)) { aml_nand_msg("amlnf_dev_init : class cread failed"); ret = -1; goto exit_error0; } ret = class_create_file(aml_store_class, &aml_version); if (ret) { aml_nand_msg("amlnf_dev_init : cannot create sysfs file : "); goto out_class1; } ret = class_create_file(aml_store_class, &aml_part_table); if (ret) { aml_nand_msg("amlnf_dev_init : cannot create sysfs file : "); goto out_class2; } ret = class_create_file(aml_store_class, &aml_store_device); if (ret) { aml_nand_msg("amlnf_dev_init : cannot create sysfs file : "); goto out_class3; } #endif return 0; #ifndef AML_NAND_UBOOT out_class3: class_remove_file(aml_store_class, &aml_part_table); out_class2: class_remove_file(aml_store_class, &aml_version); out_class1: class_destroy(aml_store_class); exit_error0: return ret; #endif } #ifdef CONFIG_OF static const struct of_device_id amlogic_nand_dt_match[] = { { .compatible = "amlogic,aml_nand", }, {}, }; /* static inline struct aml_nand_device *aml_get_driver_data(struct platform_device *pdev) { if (pdev->dev.of_node) { const struct of_device_id *match; match = of_match_node(amlogic_nand_dt_match, pdev->dev.of_node); return (struct aml_nand_device *)match->data; } return NULL; } static int get_nand_platform(struct aml_nand_device *aml_nand_dev, struct platform_device *pdev) { int ret; int plat_num = 0; struct device_node *np = pdev->dev.of_node; if (pdev->dev.of_node) { of_node_get(np); ret = of_property_read_u32(np, "plat-num", &plat_num); if (ret) { aml_nand_msg("%s:%d,please config plat-num item\n", __func__, __LINE__); return -1; } } aml_nand_dbg("plat_num %d ", plat_num); return 0; } */ #endif /* CONFIG_OF */ /*** *boot_device_flag = 0 ; indicate spi+nand boot *boot_device_flag = 1; indicate nand boot ***/ #if 1 int check_dev(void) { u32 boot_dev; u8 ret = 0; boot_dev = amlnf_read_reg32((volatile uint32_t *)P_AO_SEC_GP_CFG0); boot_dev = boot_dev&0xf; aml_nand_msg("boot_dev: 0x%x",boot_dev); switch (boot_dev) { case STORAGE_DEV_NAND: case STORAGE_DEV_EMMC: ret = boot_dev; break; case STORAGE_DEV_SDCARD: aml_nand_msg("warning you may need update your uboot!"); break; default: break; } aml_nand_msg("%s return %d\n", __func__, ret); return ret; } #if 0 int poc_cfg_prase(void) { int boot_flag; u32 cpu_type, poc_value; poc_value = amlnf_read_reg32(aml_nand_dev->platform_data->poc_reg); cpu_type = get_cpu_type(); if (cpu_type == MESON_CPU_MAJOR_ID_GX) { poc_value = (poc_value >> 6) & 0x03; } else if (cpu_type >= MESON_CPU_MAJOR_ID_M8) poc_value = ((((poc_value >> 0x09) & 0x01) << 2) | ((poc_value >> 6) & 0x03)); else poc_value = (poc_value & 0x07); if (cpu_type == MESON_CPU_MAJOR_ID_GX) { if (poc_value & 0x2) boot_flag = SPI_BOOT_FLAG; else boot_flag = NAND_BOOT_FLAG; //fixme, ... } else if (cpu_type > MESON_CPU_MAJOR_ID_M8) { if (poc_value == 0x05) boot_flag = SPI_BOOT_FLAG; if ((poc_value == 0x03) || (poc_value == 0x01)) boot_flag = EMMC_BOOT_FLAG; } else { if ((poc_value == 0x05) || (poc_value == 0x04)) boot_flag = SPI_BOOT_FLAG; if (poc_value == 0x03) boot_flag = EMMC_BOOT_FLAG; } if ((poc_value == 0x07) || (poc_value == 0x06)) boot_flag = NAND_BOOT_FLAG; if (poc_value == 0x00) boot_flag = EMMC_BOOT_FLAG; return boot_flag; } #endif int check_storage_device(void) { boot_device_flag = 1; //fixme, debug code.... aml_nand_msg("boot_device_flag : %d", boot_device_flag); return 0; } EXPORT_SYMBOL(check_storage_device); #endif #ifndef AML_NAND_UBOOT static int __init get_storage_device(char *str) { int value = -1; if (kstrtoul(str, 16, (u32 *)&value)) return -EINVAL; /*value = strtoul(str, NULL, 16);*/ aml_nand_msg("get storage device: storage %s", str); aml_nand_msg("value=%d", value); boot_device_flag = value; return 0; } early_param("storage", get_storage_device); static int amlnf_get_resource(struct platform_device *pdev) { struct resource *res_mem, *res_irq; int size; /* getting Nand Platform Data that are set in dts files by of_xxx functions */ #ifdef CONFIG_OF /* pdev->dev.platform_data = aml_get_driver_data(pdev); aml_nand_msg("==========================================="); aml_nand_msg("%s:%d,nand device tree ok,dev-name:%s\n", __func__, __LINE__, dev_name(&pdev->dev)); */ #endif /* ret = get_nand_platform(pdev->dev.platform_data, pdev); */ /*aml_nand_dev = pdev->dev.platform_data;*/ aml_nand_dev = kzalloc(sizeof(struct aml_nand_device), GFP_KERNEL); if (!aml_nand_dev) { aml_nand_msg("aml_nand_dev not exist\n"); return -ENODEV; } aml_nand_dev->platform_data = kzalloc(sizeof(struct amlnf_platform_data), GFP_KERNEL); if (!aml_nand_dev->platform_data) { aml_nand_msg("malloc platform data fail\n"); return -ENOMEM; } /*mapping PORT CONFIG register address*/ aml_nand_dev->platform_data->poc_reg = devm_ioremap_nocache(&pdev->dev, POC_CONFIG_REG, sizeof(int)); if (aml_nand_dev->platform_data->poc_reg == NULL) { dev_err(&pdev->dev, "ioremap External Port Config IO fail\n"); return -ENOMEM; } aml_nand_msg("poc_reg = 0x%0x\n", (u32)aml_nand_dev->platform_data->poc_reg); /*getting nand platform device IORESOURCE_MEM*/ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_mem) { dev_err(&pdev->dev, "cannot obtain I/O memory region"); return -ENODEV; } size = resource_size(res_mem); aml_nand_msg("%s : %0x %0x\n", __func__, res_mem->start , size); /*mapping Nand Flash Controller register address*/ /*request mem erea*/ if (!devm_request_mem_region(&pdev->dev, res_mem->start, size, dev_name(&pdev->dev))) { dev_err(&pdev->dev, "Memory region busy\n"); return -EBUSY; } /*mapping IO, nocache*/ aml_nand_dev->platform_data->nf_reg_base = devm_ioremap_nocache(&pdev->dev, res_mem->start, size); if (aml_nand_dev->platform_data->nf_reg_base == NULL) { dev_err(&pdev->dev, "ioremap Nand Flash IO fail\n"); return -ENOMEM; } /*mapping external Clock register address of Nand Flash Controller*/ aml_nand_dev->platform_data->ext_clk_reg = devm_ioremap_nocache(&pdev->dev, NAND_CLK_CNTL, sizeof(int)); if (aml_nand_dev->platform_data->ext_clk_reg == NULL) { dev_err(&pdev->dev, "ioremap External Nand Clock IO fail\n"); return -ENOMEM; } res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res_irq) { dev_err(&pdev->dev, "irq res get fail\n"); return -ENODEV; } aml_nand_dev->platform_data->irq = res_irq->start; return 0; } #else /* AML_NAND_UBOOT */ /*fixme, yyh*/ static int amlnf_get_resource(struct platform_device *pdev) { /*TODO: */ if (!aml_nand_dev) { aml_nand_dev = kzalloc(sizeof(struct aml_nand_device), GFP_KERNEL); if (!aml_nand_dev) { aml_nand_msg("aml_nand_dev not exist\n"); return -ENODEV; } aml_nand_dev->platform_data = kzalloc(sizeof(struct amlnf_platform_data), GFP_KERNEL); if (!aml_nand_dev->platform_data) { aml_nand_msg("malloc platform data fail\n"); return -ENOMEM; } aml_nand_dbg("nand io resources:\n"); aml_nand_dev->platform_data->poc_reg = (volatile uint32_t *)P_ASSIST_POR_CONFIG; aml_nand_dbg("poc_reg = %p\n", aml_nand_dev->platform_data->poc_reg); aml_nand_dev->platform_data->nf_reg_base = (volatile uint32_t *)NAND_BASE_APB; aml_nand_dbg("nf_reg_base = %p\n", aml_nand_dev->platform_data->nf_reg_base); aml_nand_dev->platform_data->ext_clk_reg = (volatile uint32_t *)NAND_CLK_CNTL; aml_nand_dbg("ext_clk_reg = %p\n", aml_nand_dev->platform_data->ext_clk_reg); } return 0; } #endif /* AML_NAND_UBOOT */ #ifdef AML_NAND_UBOOT extern struct list_head nlogic_dev_list; #endif /* AML_NAND_UBOOT */ static int _amlnf_init(struct platform_device *pdev, u32 flag) { int ret = 0; INIT_LIST_HEAD (&nphy_dev_list); INIT_LIST_HEAD (&nlogic_dev_list); INIT_LIST_HEAD (&nf_dev_list); PHY_NAND_LINE /*Nand physic init*/ /*Amlogic Nand Flash Controller init and Nand chip init ......*/ /*Scan or Build table,fbbt ,bbt, key and so on*/ /*Creating physical partition, offset and size*/ ret = amlnf_phy_init(flag, pdev); if (ret) { aml_nand_msg("nandphy_init failed and ret=0x%x", ret); if (ret == -NAND_FAILED) { ret = -1; // controller failed }else if(ret == -NAND_SHIPPED_BADBLOCK_FAILED){ ret = NAND_SHIPPED_BADBLOCK_FAILED; } else if (ret == -NAND_DETECT_DTB_FAILED) { ret = NAND_DETECT_DTB_FAILED; } else{ ret = 1; } goto exit_error0; } PHY_NAND_LINE //read id or erase env/erase all, quit myself. if (flag >= NAND_BOOT_ERASE_PROTECT_CACHE) goto exit_error0; PHY_NAND_LINE /*Nand logic init*/ ret = amlnf_logic_init(flag); if (ret < 0) { aml_nand_msg("amlnf_add_nftl failed and ret=0x%x", ret); goto exit_error0; } PHY_NAND_LINE ret = amlnf_dev_init(flag); if (ret < 0) { aml_nand_msg("amlnf_add_nftl failed and ret=0x%x", ret); goto exit_error0; } PHY_NAND_LINE exit_error0: return ret; /* fixme, */ } #ifndef AML_NAND_UBOOT static int amlnf_driver_probe(struct platform_device *pdev) #else static struct storage_t *storage_dev = NULL; int amlnf_init(u32 flag) #endif /* AML_NAND_UBOOT */ { struct amlnand_chip *aml_chip; int ret = 0; #ifndef AML_NAND_UBOOT u32 flag = 0; #else struct platform_device plat_dev; struct platform_device *pdev = &plat_dev; #endif /* AML_NAND_UBOOT */ PHY_NAND_LINE ret = amlnf_get_resource(pdev); if (ret < 0) { aml_nand_msg("get resource fail!"); return -1; } PHY_NAND_LINE /*judge if it is nand boot device*/ ret = check_storage_device(); if (ret < 0) { aml_nand_msg("do not init nand"); return 0; } PHY_NAND_LINE /*Initializing Nand Flash*/ ret = _amlnf_init(pdev, flag); if (ret) { aml_nand_msg("amlnf init failed ret: %x",ret); goto exit_error0; } PHY_NAND_LINE if (flag == NAND_SCAN_ID_INIT) goto exit_error1; #if 1/*support storage func*/ if (storage_dev == NULL) { storage_dev = kzalloc(sizeof(struct storage_t), GFP_KERNEL); if (!storage_dev) { aml_nand_msg("malloc failed for storage_dev"); ret = -1; goto exit_error0; } } else { storage_dev->init_flag = flag; aml_nand_msg("only update flag"); goto exit_error0; } if (aml_nand_chip == NULL) { aml_nand_msg("error: aml_nand_chip is null"); ret = -1; goto exit_error0; } aml_chip = aml_nand_chip; storage_dev->init_flag = flag; storage_dev->type = BOOT_NAND_NFTL; aml_nand_msg("store flag: %d,type: %d",storage_dev->init_flag, storage_dev->type); memcpy((char *)(storage_dev->info.name), aml_chip->flash.name, 32*sizeof(char)); memcpy((char *)(storage_dev->info.id), (char *)(aml_chip->flash.id), 8*sizeof(char)); storage_dev->info.read_unit = aml_chip->flash.pagesize; storage_dev->info.write_unit = aml_chip->flash.pagesize; storage_dev->info.erase_unit = aml_chip->flash.blocksize; storage_dev->info.caps = aml_chip->flash.chipsize; storage_dev->info.mode = COMPACT_BOOTLOADER; aml_nand_msg("name: %s",storage_dev->info.name); storage_dev->get_part_size = amlnf_get_size; storage_dev->read = amlnf_read; storage_dev->write = amlnf_write; storage_dev->erase = amlnf_erase; storage_dev->get_copies = amlnf_boot_cpys; storage_dev->get_copy_size = amlnf_boot_copy_size; storage_dev->boot_read = amlnf_boot_read; storage_dev->boot_write = amlnf_boot_write; storage_dev->boot_erase = amlnf_boot_erase; storage_dev->get_rsv_size = amlnf_get_rsv_size; storage_dev->read_rsv = amlnf_read_rsv; storage_dev->write_rsv = amlnf_write_rsv; storage_dev->erase_rsv = amlnf_erase_rsv; storage_dev->protect_rsv = amlnf_rsv_protect; store_register(storage_dev); aml_nand_msg("amlnf init success"); #endif exit_error1: if (flag >= NAND_BOOT_ERASE_PROTECT_CACHE) { if (aml_nand_chip) aml_nand_free(aml_nand_chip); } exit_error0: return ret; } #ifdef AML_NAND_UBOOT int amlnf_exit(unsigned flag) #else static int amlnf_exit(struct platform_device *pdev) #endif { extern void amlnf_phy_exit(void); extern void amlnf_logic_exit(void); amlnf_phy_exit(); amlnf_logic_exit(); aml_nand_msg("amlnf_exit : ok"); return 0; } #ifndef AML_NAND_UBOOT static int amlnf_driver_remove(struct platform_device *pdev) { return 0; } static void amlnf_driver_shutdown(struct platform_device *pdev) { struct amlnand_phydev *phy_dev = NULL; struct amlnand_chip *aml_chip = NULL; if (check_storage_device() < 0) { aml_nand_msg("without nand"); return; } list_for_each_entry(phy_dev, &nphy_dev_list, list) { if (phy_dev) { aml_chip = (struct amlnand_chip *)phy_dev->priv; amlnand_get_device(aml_chip, CHIP_SHUTDOWN); phy_dev->option |= NAND_SHUT_DOWN; amlnand_release_device(aml_chip); } } return; } /* driver device registration */ static struct platform_driver amlnf_driver = { .probe = amlnf_driver_probe, .remove = amlnf_driver_remove, .shutdown = amlnf_driver_shutdown, .driver = { .name = DRV_AMLNFDEV_NAME, .owner = THIS_MODULE, .of_match_table = amlogic_nand_dt_match, }, }; static int __init amlnf_module_init(void) { return platform_driver_register(&amlnf_driver); } static void __exit amlnf_module_exit(void) { platform_driver_unregister(&amlnf_driver); } module_init(amlnf_module_init); module_exit(amlnf_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("AML NAND TEAM"); MODULE_DESCRIPTION("aml nand flash driver"); #endif /* AML_NAND_UBOOT */ #ifdef AML_NAND_UBOOT struct amlnand_phydev *aml_phy_get_dev(const char * name) { struct amlnand_phydev * phy_dev = NULL; list_for_each_entry(phy_dev, &nphy_dev_list, list){ if (!strncmp((char*)phy_dev->name, name, MAX_DEVICE_NAME_LEN)) { aml_nand_dbg("nand get phy dev %s ",name); return phy_dev; } } aml_nand_msg("nand get phy dev %s failed",name); return NULL; } struct amlnf_dev* aml_nftl_get_dev(const char * name) { struct amlnf_dev * nf_dev = NULL; list_for_each_entry(nf_dev, &nf_dev_list, list){ if (!strcmp((char*)nf_dev->name, name)) { aml_nand_dbg("nand get nftl dev %s ",name); return nf_dev; } } aml_nand_msg("nand get nftl dev %s failed",name); return NULL; } void show_ldev_list(void) { struct amlnf_dev * nf_dev = NULL; int i = 0; printf("logic partitions table, in sectors\n"); list_for_each_entry(nf_dev, &nf_dev_list, list) { printf("%d: %s: 0x%llx 0x%llx\n", i++, (char*)nf_dev->name, nf_dev->offset_sector, nf_dev->size_sector); } } int amlnf_logicdev_mis_init(struct amlnf_logicdev_t *amlnf_logicdev) { return 0; } #endif