📄 chipio.c
字号:
/* * $QNXLicenseC: * Copyright 2007,2008, QNX Software Systems. * * Licensed under the Apache License, Version 2.0 (the "License"). You * may not reproduce, modify or distribute this software except in * compliance with the License. You may obtain a copy of the License * at: http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * * This file may contain contributions from others, either as * contributors under the License or as licensors under other terms. * Please review this entire file for other proprietary rights or license * notices, as well as the QNX Development Suite License Guide at * http://licensing.qnx.com/license-guide/ for other information. * $ */#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <sys/slog.h>#include <sys/mman.h>#include <sys/neutrino.h>#include <hw/inout.h>#include <fs/etfs.h>struct chipio;#define CHIPIO struct chipio#include "devio.h"#define PRINT_FUNCTIONNAME fprintf(stderr, "ETFS: %s \n", __FUNCTION__);#define ATLASII_NAND_BASE 0x80070000#define ATLASII_NAND_SIZE 0xF20#define ATLASII_IOBRDG_FLUSH 0xB0000804#define EXT_PIO_BASE 0x14000000#define ATLASII_SM_WAIT 0x04#define ATLASII_SM_BANK_SEL 0x08#define ATLASII_SM_ADD_NUM 0x0C#define ATLASII_SM_CMD 0x10#define ATLASII_SM_LOW_ADDR 0x14#define ATLASII_SM_HIGH_ADDR 0x18#define ATLASII_SM_PAGE_SIZE 0x1C#define ATLASII_SM_INT_EN 0x20#define ATLASII_SM_INT_STATUS 0x24#define ATLASII_SM_CTRL 0x28#define ATLASII_SM_ECC_SET 0x2C#define ATLASII_SM_ECC_AREA1 0x30#define ATLASII_SM_ECC_AREA2 0x34#define ATLASII_SM_DMA_IO_CTRL 0xF00#define ATLASII_SM_DMA_IO_LEN 0xF04#define ATLASII_SM_FIFO_CTRL 0xF08#define ATLASII_SM_FIFO_LEVEL_CHK 0xF0C#define ATLASII_SM_FIFO_OP 0xF10#define ATLASII_SM_FIFO_STATUS 0xF14#define ATLASII_SM_FIFO_DATA 0xF18#define NAND_STATUS_READY 0x01#define NAND_STATUS_WT_CMD 0x02#define NAND_STATUS_WT_IO 0x04#define NAND_STATUS_WT_FIFO 0x08#define NAND_MODE_CMD 0x10#define NAND_MODE_IO_READ 0x3#define NAND_MODE_IO_WRITE 0x1//// Device specific data structure for the jace5 with 528 byte NAND pages.//struct chipio { struct _chipio chip; unsigned phy_base; unsigned bank; unsigned iobase; unsigned io_data; unsigned io_address; unsigned io_command; unsigned io_status; unsigned io_brdg;} chipio;intmain(int argc, char *argv[]) { return(etfs_main(argc, argv));}//// Process device specific options (if any).// This is always called before any access to the part.// It is called by the -D option to the filesystem. If no -D option is given// this function will still be called with "" for optstr.//int devio_options(struct etfs_devio *dev, char *optstr) { struct chipio *cio; char *value; static char *opts[] ={ "use", // 0 "addr", // 1 "cs", // 2 NULL } ; cio = dev->cio = &chipio; while(*optstr) { switch(getsubopt(&optstr, opts, &value)) { case 0: printf("Device specific options:\n"); printf(" -D use,addr=xxxx,cs\n"); return(-1); case 1: cio->phy_base = strtol(value, NULL, 16); break; case 2: cio->bank = 1; break; default: dev->log(_SLOG_ERROR, "Invalid -D suboption."); return(EINVAL); } } return(EOK);}// Called once at startupintnand_init(struct etfs_devio *dev) { uint8_t nandcs; unsigned expiobase; struct chipio *cio = dev->cio; // Pick a default for the board. if(cio->phy_base == 0) cio->phy_base = ATLASII_NAND_BASE; // Map in the device registers cio->iobase = mmap_device_io(ATLASII_NAND_SIZE, cio->phy_base); if(cio->iobase == (uintptr_t) MAP_FAILED) { dev->log(_SLOG_CRITICAL, "Unable to map in device registers (%d).", errno); return(-1); } cio->io_brdg = mmap_device_io(4, ATLASII_IOBRDG_FLUSH); if(cio->io_brdg == (uintptr_t) MAP_FAILED) { dev->log(_SLOG_CRITICAL, "Unable to map in device registers (%d).", errno); return(-1); } expiobase = mmap_device_io(0x6000, EXT_PIO_BASE); if(expiobase == (uintptr_t) MAP_FAILED) { dev->log(_SLOG_CRITICAL, "Unable to map in device registers (%d).", errno); return(-1); } //where we are booting from nandcs = (in8(expiobase+0x1A00)>>1) & 0x7; if(nandcs==7) //boting from SM card { if(cio->bank==1) { //set FCE2 t0 empty out8(expiobase+0x1C00, 0x0f); //set FCE3 to NANDCS0 out8(expiobase+0x1E00, 0); nandcs=3; } else nandcs=0; }else if(nandcs==0) { if(cio->bank==1) { //set FCE2 t0 empty out8(expiobase+0x1C00, 0x0f); //set FCE3 to SM card out8(expiobase+0x1E00, 0x08); nandcs=3; } else nandcs=0; }else //default to booting device nandcs=0; cio->io_data = cio->iobase + ATLASII_SM_FIFO_DATA; cio->io_address = cio->iobase + ATLASII_SM_LOW_ADDR; cio->io_command = cio->iobase + ATLASII_SM_CMD; out32(cio->iobase+ATLASII_SM_CTRL, in32(cio->iobase+ATLASII_SM_CTRL) & (~0x1)); //IO-Read mode out32(cio->iobase+ATLASII_SM_CTRL, in32(cio->iobase+ATLASII_SM_CTRL) & (~0x2)); //force 8-bit out32(cio->iobase+ATLASII_SM_WAIT, 0x1878); //Set Wait Reg out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x1); //Start FIFO out32(cio->iobase+ATLASII_SM_ECC_SET, 0x0); //disable hardware ECC //NAND bank select out32(cio->iobase+ATLASII_SM_BANK_SEL, (~(0x1<<nandcs)) & 0xF); cio->io_status =NAND_STATUS_READY; //clear all Intrrupt out32(cio->iobase+ATLASII_SM_INT_STATUS, 0xe); return(0);}// Read bit 0 of status/control reg (0xffff4003/0xffff5003). 0=chip busyintnand_wait_busy(struct chipio *cio, uint32_t usec) { uint32_t x; for(usec = MAX_ERASE_USEC; usec ; --usec) { if(cio->io_status == NAND_STATUS_READY) return(0); else if(cio->io_status == NAND_STATUS_WT_CMD) { x=in32(cio->iobase+ATLASII_SM_INT_STATUS); if(x & NAND_STATUS_WT_CMD) { //clear intr out32(cio->iobase+ATLASII_SM_INT_STATUS, x |NAND_STATUS_WT_CMD); cio->io_status = NAND_STATUS_READY; return(0); } else nanospin_ns(1000); } else if(cio->io_status == NAND_STATUS_WT_IO) { x=in32(cio->iobase+ATLASII_SM_INT_STATUS); if(x & NAND_STATUS_WT_IO) { //clear intr out32(cio->iobase+ATLASII_SM_INT_STATUS, x |NAND_STATUS_WT_IO); cio->io_status = NAND_STATUS_READY; return(0); } else nanospin_ns(1000); } else if(cio->io_status == NAND_STATUS_WT_FIFO) { x=in32(cio->iobase+ATLASII_SM_INT_STATUS); if(x & NAND_STATUS_WT_FIFO) { //clear intr out32(cio->iobase+ATLASII_SM_INT_STATUS, x |NAND_STATUS_WT_FIFO); cio->io_status = NAND_STATUS_READY; return(0); } else nanospin_ns(1000); } else nanospin_ns(1000); } return(-1); // We will exit from the log and never reach here. }// Accessing the command reg automatically sets ALE=0, CLE=1voidnand_write_cmd(struct chipio *cio, int command) { //enter to command mode out32(cio->iobase+ATLASII_SM_DMA_IO_CTRL, NAND_MODE_CMD); out32(cio->io_command, (uint8_t) command); cio->chip.lastcmd = command; cio->io_status = NAND_STATUS_WT_CMD;}int nand_read_flashid(struct chipio * cio, uint8_t *id, int data_cycles){ int i=100000000; out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x2); //Reset FIFO out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x0); //Reset FIFO //enter to io read mode out32(cio->iobase+ATLASII_SM_DMA_IO_CTRL, NAND_MODE_IO_READ); //set io-len out32(cio->iobase+ATLASII_SM_DMA_IO_LEN, 0x4); out32(cio->iobase+ATLASII_SM_FIFO_CTRL, 0x4<<2); //set addr num out32(cio->iobase+ATLASII_SM_ADD_NUM, 0x1); //set low addr=0; out32(cio->iobase+ATLASII_SM_LOW_ADDR, 0x0); //clear intr out32(cio->iobase+ATLASII_SM_INT_STATUS, 0xf); //set command out32(cio->io_command, 0x90); //read id command out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x1); //Reset FIFO while((in32(cio->iobase+ATLASII_SM_FIFO_STATUS) & 0x80) && i--) ; if(i<0) return -1; *(uint32_t *)id = in32(cio->iobase+ATLASII_SM_FIFO_DATA); out32(cio->io_brdg, 1); while (in32(cio->io_brdg)); return (0);}int nand_read_status(struct chipio * cio, uint8_t *databuffer){ out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x2); //Reset FIFO out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x0); //Reset FIFO //enter to io read mode out32(cio->iobase+ATLASII_SM_DMA_IO_CTRL, NAND_MODE_IO_READ); //set addr num out32(cio->iobase+ATLASII_SM_ADD_NUM, 0); //set low addr=0; out32(cio->iobase+ATLASII_SM_HIGH_ADDR, 0x0); out32(cio->iobase+ATLASII_SM_LOW_ADDR, 0x0); //set io-len out32(cio->iobase+ATLASII_SM_DMA_IO_LEN, 0x4); out32(cio->iobase+ATLASII_SM_FIFO_CTRL, 0x4<<2); //clear intr out32(cio->iobase+ATLASII_SM_INT_STATUS, 0xf); //set command out32(cio->io_command, 0x70); //read status command out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x1); //Reset FIFO //wait command end cio->io_status = NAND_STATUS_WT_FIFO; if(nand_wait_busy(cio, MAX_READ_USEC) != 0) return(-1); else *(uint32_t *)databuffer = in32(cio->iobase+ATLASII_SM_FIFO_DATA); out32(cio->io_brdg, 1); while (in32(cio->io_brdg)); out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x2); //Reset FIFO return 0;}//op=0, read data//op=1, read spareint nand_read_page(struct chipio * cio, unsigned page, uint8_t *databuffer, int data_cycles, int op){ if(op==0) { //Reset ECC out32(cio->iobase+ATLASII_SM_ECC_SET, 0x07); out32(cio->iobase+ATLASII_SM_ECC_SET, 0x05); } out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x2); //Reset FIFO out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x0); //Reset FIFO //enter to io read mode out32(cio->iobase+ATLASII_SM_DMA_IO_CTRL, NAND_MODE_IO_READ); //set io-len out32(cio->iobase+ATLASII_SM_DMA_IO_LEN, data_cycles); //set addr num out32(cio->iobase+ATLASII_SM_ADD_NUM, 0x4); //set low addr=0; out32(cio->iobase+ATLASII_SM_LOW_ADDR, page<<8); out32(cio->iobase+ATLASII_SM_HIGH_ADDR, 0); //clear intr out32(cio->iobase+ATLASII_SM_INT_STATUS, 0xf); //set command if(op==1) { out32(cio->io_command, 0x50); //read2 command cio->chip.lastcmd = NANDCMD_SPAREREAD; } else { out32(cio->io_command, 0x0); //read1 command cio->chip.lastcmd = NANDCMD_READ; } out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x1); //Reset FIFO //wait command end cio->io_status = NAND_STATUS_WT_IO; if(nand_read_data(cio, databuffer, data_cycles)!=0) return -1; return data_cycles;}//op=0, write data//op=1, write spareint nand_write_page(struct chipio * cio, unsigned page, uint8_t *databuffer, int data_cycles, int op){ if(op==0) { //Reset ECC out32(cio->iobase+ATLASII_SM_ECC_SET, 0x07); out32(cio->iobase+ATLASII_SM_ECC_SET, 0x05); } //change the write pointer to either data area or spare area out32(cio->iobase+ATLASII_SM_DMA_IO_CTRL, NAND_MODE_CMD); out32(cio->iobase+ATLASII_SM_ADD_NUM, 0x0); //clear intr out32(cio->iobase+ATLASII_SM_INT_STATUS, 0xf); if(op==0) { cio->chip.lastcmd = NANDCMD_READ; out32(cio->io_command, 0x0); //read1 command } else { cio->chip.lastcmd = NANDCMD_SPAREREAD; out32(cio->io_command, 0x50); //read2 command } cio->io_status = NAND_STATUS_WT_CMD; //wait for the command end if(nand_wait_busy(cio, MAX_READ_USEC) !=0) return (-1); out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x2); //Reset FIFO out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x0); //Reset FIFO //enter to io write mode out32(cio->iobase+ATLASII_SM_DMA_IO_CTRL, NAND_MODE_IO_WRITE); //set io-len out32(cio->iobase+ATLASII_SM_DMA_IO_LEN, data_cycles); //set addr num out32(cio->iobase+ATLASII_SM_ADD_NUM, 0x4); //set low addr=0; out32(cio->iobase+ATLASII_SM_LOW_ADDR, page<<8); out32(cio->iobase+ATLASII_SM_HIGH_ADDR, 0); //clear interrupt out32(cio->iobase+ATLASII_SM_INT_STATUS, 0xf); //set command cio->chip.lastcmd = NANDCMD_PROGRAM; out32(cio->io_command, 0x80); //write command out32(cio->iobase+ATLASII_SM_FIFO_OP, 0x1); //Reset FIFO if(nand_write_data(cio, databuffer, data_cycles)!=0) return -1; //wait command end cio->io_status = NAND_STATUS_WT_IO; if(nand_wait_busy(cio, MAX_POST_USEC) != 0) return(-2); //enter to command mode out32(cio->iobase+ATLASII_SM_DMA_IO_CTRL, NAND_MODE_CMD); out32(cio->iobase+ATLASII_SM_ADD_NUM, 0x0); //clear interrupt out32(cio->iobase+ATLASII_SM_INT_STATUS, 0xf); //set command cio->chip.lastcmd = NANDCMD_PROGRAMCONFIRM; out32(cio->io_command, 0x10); //write confirm command cio->io_status = NAND_STATUS_WT_CMD; if(nand_wait_busy(cio, MAX_POST_USEC) != 0) return(-3); return 0;}int nand_erase_blk(struct chipio * cio, unsigned blk){ out32(cio->iobase+ATLASII_SM_DMA_IO_CTRL, NAND_MODE_CMD); out32(cio->iobase+ATLASII_SM_ADD_NUM, 0x3); //set low addr=0; out32(cio->iobase+ATLASII_SM_LOW_ADDR, (blk<<5)); out32(cio->iobase+ATLASII_SM_HIGH_ADDR, 0); //clear interrupt out32(cio->iobase+ATLASII_SM_INT_STATUS, 0xf); //set command cio->chip.lastcmd = NANDCMD_ERASECONFIRM; out32(cio->io_command, 0xD060); //blk erase command //wait command end cio->io_status = NAND_STATUS_WT_CMD; if(nand_wait_busy(cio, MAX_ERASE_USEC) != 0) return(-1); return 0;}// Accessing the address reg automatically sets ALE=1, CLE=0voidnand_write_pageaddr(struct chipio *cio, unsigned page, int addr_cycles) {}// Accessing the address reg automatically sets ALE=1, CLE=0voidnand_write_blkaddr(struct chipio *cio, unsigned blk, int addr_cycles) {}// Accessing the data reg automatically sets ALE=0, CLE=0intnand_write_data(struct chipio *cio, uint8_t *databuffer, int data_cycles) { int i; volatile unsigned *tmp; volatile unsigned val; if(data_cycles%4 !=0) { fprintf(stderr, "data not aligned on 4-byte boundary\n"); return -1; } tmp=(volatile unsigned *)databuffer; for(i = 0; i < data_cycles/4; i++){ while(in32(cio->iobase+ATLASII_SM_FIFO_STATUS) & 0x40) ; val=tmp[i]; out32(cio->io_data, val); } out32(cio->io_brdg, 1); while (in32(cio->io_brdg)); return 0; }// Accessing the data reg automatically sets ALE=0,CLE=0//must be 4-byte alignedintnand_read_data(struct chipio *cio, uint8_t *databuffer, int data_cycles) { int i; volatile unsigned *tmp; volatile unsigned val; if(data_cycles%4 !=0) { fprintf(stderr, "data not aligned on 4-byte boundary\n"); return -1; } tmp=(volatile unsigned *)databuffer; for(i = 0; i < data_cycles/4; i++){ while(in32(cio->iobase+ATLASII_SM_FIFO_STATUS) & 0x80) ; val = in32(cio->io_data); tmp[i]=val; } out32(cio->io_brdg, 1); while (in32(cio->io_brdg)); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -