Implementation of NOR FLASH Driver Based on JZ2440

Keywords: Linux Programming

The main task of this paper is to realize the NOR FLASH driver of MX29LV800BBTC on board of JZ2440 development board.


A Brief Introduction to MX29LV800BBTC

This is a NOR FLASH memory chip with a capacity of 2MB and a bit width of 16 bits. It can be accessed directly like memory, but it can not be written directly like memory. It supports XIP. Its schematic diagram is as follows:


Its pins are defined as follows:

LDATA0~LDATA15: Data pins

LADDR1~LADDR20: Address pins

LnOE: Read-enabled pins

LnWE: Write enabled pins

nGCS0: Chip Selection Pin


II. Driver Programming

The driver is based on the Linux-3.4.10 kernel.

1. General implementation steps

A. Assign a map_info structural variable

b. Set this structure variable

c. Use: do_map_probe()

d. Adding partitions

2. Driver Programming

2.1 In the preliminary preparatory work, in order to facilitate the writing of the whole driver program, the global structure is defined, and a global variable of the structure is defined, which is implemented as follows:

/* Construct a structure for writing driver easily */
struct yl_nor_mtd{
	struct map_info *map_info;			// Define pointer variables for map_info structure
	struct mtd_info *mtd_info;			// Define pointer variables for mtd_info structure
};

/* Define a global variable of yl_nor_mtd structure */
static struct yl_nor_mtd nor_mtd;
2.2 Assign a pointer variable to a map_info structure

/* 1,Assign a map_info structure variable */
	nor_mtd.map_info = kzalloc(sizeof(struct map_info), GFP_KERNEL);

2.3 Set this structure variable

	/* 2,Set up */
	nor_mtd.map_info->name 		= "yl_nor_flash";		// Name
	nor_mtd.map_info->phys 		= 0;					// Physical Base Address
	nor_mtd.map_info->size 		= 0x200000; 			// Size, >= Real Size
	nor_mtd.map_info->bankwidth = 2;					// Bit width
	/* Setting the base address of the virtual address */
	nor_mtd.map_info->virt 		= ioremap(nor_mtd.map_info->phys, nor_mtd.map_info->size);
	if (nor_mtd.map_info->virt == NULL) 
	{
		printk("Failed to ioremap flash region\n");
		ret = -EIO;
		goto out2;
	}

	/* Universal initialization of other nor flash */
	simple_map_init(nor_mtd.map_info);
2.4 Using this structural variable, an example of mtd_info structural variable is obtained.

	/* 3,Use */
	nor_mtd.mtd_info = do_map_probe("cfi_probe", nor_mtd.map_info);
	if(nor_mtd.mtd_info == NULL)
	{
		printk("do_map_probe for cfi_probe failure!\n");
		ret = -ENXIO;
		goto out3;
	}
2.5 Adding Partitions

/* 4,Adding partitions */
	ret = mtd_device_parse_register(nor_mtd.mtd_info, NULL, NULL,
				yl_s3c_nor_partitions, ARRAY_SIZE(yl_s3c_nor_partitions));
Adding partitions requires a partition table as the partition basis. The partition table is implemented as follows:

/* Define Norflash partition table */
static struct mtd_partition yl_s3c_nor_partitions[] = 
{
	[0] = {
		.name	= "bootloader_nor",
		.size	= SZ_256K,
		.offset	= 0,
	},
	[1] = {
		.name	= "params_nor",
		.offset = MTDPART_OFS_APPEND,
		.size	= SZ_128K,
	},
	[2] = {
		.name	= "rootfs_nor",
		.offset	= MTDPART_OFS_APPEND,
		.size	= MTDPART_SIZ_FULL,
	}
};


The complete code for the entire driver is as follows:
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/concat.h>
#include <linux/io.h>

/* Construct a structure for writing driver easily */
struct yl_nor_mtd{
	struct map_info *map_info;			// Define pointer variables for map_info structure
	struct mtd_info *mtd_info;			// Define pointer variables for mtd_info structure
};

/* Define a global variable of yl_nor_mtd structure */
static struct yl_nor_mtd nor_mtd;

/* Define Norflash partition table */
static struct mtd_partition yl_s3c_nor_partitions[] = 
{
	[0] = {
		.name	= "bootloader_nor",
		.size	= SZ_256K,
		.offset	= 0,
	},
	[1] = {
		.name	= "params_nor",
		.offset = MTDPART_OFS_APPEND,
		.size	= SZ_128K,
	},
	[2] = {
		.name	= "rootfs_nor",
		.offset	= MTDPART_OFS_APPEND,
		.size	= MTDPART_SIZ_FULL,
	}
};


/* Module entry function */
static int __init yl_s3c_nor_init(void)
{
	int ret = 0;

	/* 1,Assign a map_info structure variable */
	nor_mtd.map_info = kzalloc(sizeof(struct map_info), GFP_KERNEL);
	if (!nor_mtd.map_info) {
		printk("kzalloc for map_info error!\n");
		ret = -ENOMEM;
		goto out1;
	}

	/* 2,Set up */
	nor_mtd.map_info->name 		= "yl_nor_flash";		// Name
	nor_mtd.map_info->phys 		= 0;					// Physical Base Address
	nor_mtd.map_info->size 		= 0x200000; 			// Size, >= Real Size
	nor_mtd.map_info->bankwidth = 2;					// Bit width
	/* Setting the base address of the virtual address */
	nor_mtd.map_info->virt 		= ioremap(nor_mtd.map_info->phys, nor_mtd.map_info->size);
	if (nor_mtd.map_info->virt == NULL) 
	{
		printk("Failed to ioremap flash region\n");
		ret = -EIO;
		goto out2;
	}

	/* Universal initialization of other nor flash */
	simple_map_init(nor_mtd.map_info);

	/* 3,Use */
	nor_mtd.mtd_info = do_map_probe("cfi_probe", nor_mtd.map_info);
	if(nor_mtd.mtd_info == NULL)
	{
		printk("do_map_probe for cfi_probe failure!\n");
		ret = -ENXIO;
		goto out3;
	}

	/* 4,Adding partitions */
	ret = mtd_device_parse_register(nor_mtd.mtd_info, NULL, NULL,
				yl_s3c_nor_partitions, ARRAY_SIZE(yl_s3c_nor_partitions));
	if(ret)	// fail
	{
		printk("mtd_device_parse_register error!\n");
		ret = -ENODEV;
		goto out3;
	}
	else	// Success
	{
		return 0;	
	}
	
out3:
	iounmap(nor_mtd.map_info->virt);
out2:
	kfree(nor_mtd.map_info);
out1:
	return ret;
}

/* Exit function of module */
static void __exit yl_s3c_nor_exit(void)
{
	/* Some operations for export, release resources, unbind and cancel registration */
	mtd_device_unregister(nor_mtd.mtd_info);
	iounmap(nor_mtd.map_info->virt);
	kfree(nor_mtd.map_info);
}

module_init(yl_s3c_nor_init);
module_exit(yl_s3c_nor_exit);

MODULE_LICENSE("GPL");

3. Compile the driver and load the module into the kernel. The results are as follows:

Posted by sunil_23413 on Fri, 28 Jun 2019 11:47:46 -0700