系統平台: ARMv4
kernel 版本: 2.6.21
前家公司的嵌入式產品系統架構沒有很大,所以不需要很大容量的flash; 又該SOC上面沒有NOR or NAND flash的controller,所以只能使用SPI Flash 做為存放zImage以及相關DATA之用。 最早的時候是公司其他同仁利用字元驅動+IOCTL的方式來讀寫SPI Flash, 後來想要能夠套用本來Linux就有的MTD架構,於是乎就抱持著研究的精神 來研究一下相關的東西XD。 那時候google出來有用的訊息不太多,後來偶然發現新一點的kernel 2.6.28裡面 有一個支援 SPI flash 的驅動程式 m25p80.c,於是乎我就把它搬進來2.6.21, 然後再做了一點小修改,如此一來就支援 Linux 本來用來讀取flash的MTD架構, 更白話的說就是可以支援MTD partition切割以及利用mtd-utils等工具來讀寫flash了。 下圖是整個的架構圖,可以看到user-space發出讀寫命令開始,整個架構會牽扯到 MTD跟SPI兩大模組,MTD core 與SPI core 方面kernel 已經幫我們準備好了, 我們要做的就是修改/新增m25p80.c 與SOC上面的SPI controller 驅動程式。
我們主要的修改如下: A.在 m25p80.c上面新增flash的支援到m25p_data 這個結構陣列中,他的結構原型如下:
struct flash_info {
char *name;
/* JEDEC id zero means "no ID" (most older chips); otherwise it has
* a high byte of zero plus three data bytes: the manufacturer id,
* then a two byte device id.
*/
u32 jedec_id;
u16 ext_id;
/* The size listed here is what works with OPCODE_SE, which isn't
* necessarily called a "sector" by the vendor.
*/
unsigned sector_size;
u16 n_sectors;
u16 flags;
#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */
};
所以請參閱你的spi flash規格書填入對應的數據 以winbond的SPI flash w25q64為例,我們會填入:
{ "w25q64" , 0xef4017, 0, 64 * 1024, 128, }, 我們把name取作 w25q64,JEDEC_ID是 0xef4017,
後面則是flash相關的資訊
B.接下來要在適當的地方註冊spi_board_info與MTD_Partition等資訊,請先看另外三個結構:
In kernel_Src/include/linux/spi/spi.h
struct spi_board_info {
char modalias[KOBJ_NAME_LEN];
const void *platform_data;
void *controller_data;
int irq;
u32 max_speed_hz;
u16 bus_num;
u16 chip_select;
u8 mode;
};
In kernel_src/include/linux/mtd/partitions.h
struct mtd_partition {
char *name; /* identifier string */
u_int32_t size; /* partition size */
u_int32_t offset; /* offset within the master MTD space */
u_int32_t mask_flags; /* master MTD flags to mask out for this partition */
struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/
struct mtd_info **mtdp; /* pointer to store the MTD object */
};
In kernel_src/include/linux/spi/flash.h:
struct flash_platform_data {
char *name;
struct mtd_partition *parts;
unsigned int nr_parts;
char *type;
/* we'll likely add more ... use JEDEC IDs, etc */
};
spi_board_info需要指定你要控制的spi slave資訊; flash_platform_data要指定你flash的name、type與mtd_partition的資訊 ,
所以我們可以填入以下資料(注意spi_board_info的modalias欄位需要把值設為m25p80):
static struct spi_board_info my_spi_board[] = { //Need to modify ,some fields NULL!
[0] = {
.modalias = "m25p80",
.platform_data = &spi_flashdata,
.chip_select = 0,
.max_speed_hz = 500*1000,
},
};
static struct mtd_partition partition_info[] = {
{
.name = "Boot Strap",
.offset = 0x0,
.size = 0x100000,
},
{
.name = "ARM-BOOT",
.offset = 0x100000,
.size = 0x100000,
},
{
.name = "zImage",
.offset = 0x200000,
.size = 0x600000,
},
{
.name = "Jffs2 Partition",
.offset = 0x800000,
.size = 0x200000,
},
};
static struct flash_platform_data spi_flashdata = {
.name="w25q64",
.type="w25q64",
.parts=partition_info,
.nr_parts=ARRAY_SIZE(partition_info),
};
填完了以上資料,我們呼叫以下函式好將資料註冊到kernel 內部
spi_register_board_info(my_spi_board,1);
至於何時呼叫spi_register_board_info,你可以參考你SOC上的例子, 一般來說類似的資訊都集中在以下資料夾:
kernel_Src/arch/arm/mach-xxxx/ (xxxx是你的SOC名稱)
可以看到我們把spi_flashdata結構的type欄位設為w25q64, m25p80模組會在probe的時候搜尋m25p_data[]裡面
是否有 name為w25q64的元素,一但找到後會透過SPI去讀取SPI flash的 JEDEC_ID然後比對,一致之後m25p80會
繼續帶入你註冊的 MTD_Partition資訊,如此一來就可以使用MTD來分割flash了。 至於SPI controller,你可以參考
spi_s3c24xx.c依樣畫葫蘆即可。
NOTE: m25p80.c is in Kernel_Source/drivers/mtd/devices/m25p80.c
NOTE: spi_s3c24xx.c.c is in Kernel_Source/drivers/spi/spi_s3c24xx.c
NOTE: 當然了,config kernel 的時候相關的SPI 與MTD設定都要打開。
文章標籤
全站熱搜