summaryrefslogtreecommitdiffstats
path: root/main/common/nand.c
diff options
context:
space:
mode:
authorAmar Takhar <amar@rtems.org>2015-04-16 15:26:21 -0400
committerAmar Takhar <amar@rtems.org>2015-04-16 15:26:21 -0400
commit87db514f2dfff5ad67863a30f075b718706de346 (patch)
tree31edc1b1700de9f3d4825822534928f8a213d53f /main/common/nand.c
downloadumon-87db514f2dfff5ad67863a30f075b718706de346.tar.bz2
Initial commit of the umon repository.
Prior to this three changes were made: * Remove umon_ prefix from parent directories. * Collapse main/target/ into main/ * Remove ports/template/flashtest.scr.ucon script.
Diffstat (limited to 'main/common/nand.c')
-rwxr-xr-xmain/common/nand.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/main/common/nand.c b/main/common/nand.c
new file mode 100755
index 0000000..45e7483
--- /dev/null
+++ b/main/common/nand.c
@@ -0,0 +1,350 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2013 Alcatel-Lucent
+ *
+ * Alcatel Lucent licenses this file to You under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. A copy of the License is contained the
+ * file LICENSE at the top level of this repository.
+ * You may also 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 OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **************************************************************************
+ *
+ * nand.c
+ *
+ * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com)
+ *
+ */
+#include "config.h"
+#if INCLUDE_NANDCMD
+#include "cpuio.h"
+#include "genlib.h"
+#include "stddefs.h"
+#include "tfs.h"
+#include "tfsprivate.h"
+#include "cli.h"
+#include "nand.h"
+
+int nandVerbose;
+
+#define END_OF_NAND (BASE_OF_NAND+SIZE_OF_NAND-1)
+
+#ifdef FLASHRAM_BASE
+#ifndef NAND_TFSRAM_BASE
+#define NAND_TFSRAM_BASE FLASHRAM_BASE
+#endif
+#endif
+
+char *nandHelp[] = {
+ "Interface with Nand-Flash",
+ "-[v] {cmd} [cmd-specific args]",
+#if INCLUDE_VERBOSEHELP
+ "Options:",
+ " -v incrementing verbosity level",
+ "",
+ "Cmds:",
+ " init initialize interface",
+ " info show device info",
+#ifdef FLASHRAM_BASE
+ " tfsls list files directly out of SPI flash",
+ " tfsload copy NAND to TFSRAM",
+ " tfsstat show state of SPI flash",
+ " tfsstore copy TFSRAM to NAND",
+ " tfserase erase NAND space allocated to TFS",
+ " tfsrm {name} remove file directly out of NAND flash",
+ " tfsadd {name} [src sz] add file directly to NAND flash",
+#endif
+ " erase {addr len} erase block",
+ " read {addr dest len} read block",
+ " write {addr src len} write block",
+#endif
+ 0,
+};
+
+int
+nandCmd(int argc,char *argv[])
+{
+ unsigned long addr;
+ char *cmd, *dest, *src;
+ int opt, len, rc;
+
+ rc = 0;
+ nandVerbose = 0;
+ while((opt=getopt(argc,argv,"v")) != -1) {
+ switch(opt) {
+ case 'v':
+ nandVerbose++;
+ break;
+ default:
+ return(CMD_PARAM_ERROR);
+ }
+ }
+
+ if (argc < optind+1)
+ return(CMD_PARAM_ERROR);
+
+ cmd = argv[optind];
+
+ if (nandVerbose)
+ printf("CMD: %s\n",cmd);
+
+ if (strcmp(cmd,"init") == 0) {
+ nandInit();
+ }
+ else if (strcmp(cmd,"info") == 0) {
+ nandInfo();
+ }
+ else if (strcmp(cmd,"erase") == 0) {
+ if (argc != optind+3)
+ return(CMD_PARAM_ERROR);
+ addr = strtoul(argv[optind+1],0,0);
+ len = (int)strtol(argv[optind+2],0,0);
+ nandEraseChunk((char *)addr,len);
+ }
+ else if (strcmp(cmd,"write") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+ addr = strtoul(argv[optind+1],0,0);
+ src = (char *)strtoul(argv[optind+2],0,0);
+ len = (int)strtol(argv[optind+3],0,0);
+ nandWriteChunk((char *)addr,src,len);
+ }
+ else if (strcmp(cmd,"read") == 0) {
+ if (argc != optind+4)
+ return(CMD_PARAM_ERROR);
+ addr = strtoul(argv[optind+1],0,0);
+ dest = (char *)strtoul(argv[optind+2],0,0);
+ len = (int)strtol(argv[optind+3],0,0);
+ nandReadChunk((char *)addr,dest,len);
+ }
+#ifdef FLASHRAM_BASE
+ else if (strcmp(cmd,"tfsload") == 0) {
+ }
+ else if (strcmp(cmd,"tfsstore") == 0) {
+ }
+ else if (strcmp(cmd,"tfserase") == 0) {
+ }
+ else if (strcmp(cmd, "tfsls") == 0) {
+ int ftot;
+ char *addr;
+ TFILE tfshdr, *fp;
+
+ ftot = 0;
+ fp = &tfshdr;
+ addr = (char *)BASE_OF_NAND;
+ while(addr < (char *)END_OF_NAND) {
+ char fbuf[32], *flags;
+
+ if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("nandReadChunk failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff)
+ break;
+ if (TFS_FILEEXISTS(fp)) {
+ if (ftot == 0)
+ printf(" Name Size Offset Flags Info\n");
+ ftot++;
+ flags = tfsflagsbtoa(TFS_FLAGS(fp),fbuf);
+ if ((!flags) || (!fbuf[0]))
+ flags = " ";
+ printf(" %-23s %7ld 0x%08lx %-5s %s\n",TFS_NAME(fp),
+ TFS_SIZE(fp),(unsigned long)(addr+TFSHDRSIZ),
+ flags,TFS_INFO(fp));
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while((long)addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsrm") == 0) {
+ char *addr;
+ TFILE tfshdr, *fp;
+ char *arg2 = argv[optind+1];
+
+ fp = &tfshdr;
+ addr = (char *)BASE_OF_NAND;
+ while(addr < (char *)END_OF_NAND) {
+ if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("nandReadChunk failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff) {
+ printf("%s not found\n",arg2);
+ break;
+ }
+ if (strcmp(TFS_NAME(fp),arg2) == 0) {
+ if (TFS_FILEEXISTS(fp)) {
+ fp->flags &= ~TFS_ACTIVE;
+ if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+ break;
+ }
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while((long)addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsadd") == 0) {
+ int size;
+ long bflags;
+ TFILE tfshdr, *fp;
+ char *addr;
+ char *src, *name, *info;
+ char *arg2 = argv[optind+1];
+ char *arg3 = argv[optind+2];
+ char *arg4 = argv[optind+3];
+ char *icomma, *fcomma;
+
+ info = "";
+ bflags = 0;
+ name = arg2;
+ addr = (char *)BASE_OF_NAND;
+
+ /* The incoming arguments can be either just the filename (in which
+ * case we assume the source is the file in TFS with the same name),
+ * or the filename, source address and size...
+ */
+ if (argc == optind+2) { // Just filename?
+ if ((fp = tfsstat(name)) == (TFILE *)0) {
+ printf("File '%s' not in TFS\n",name);
+ return(CMD_FAILURE);
+ }
+ name = fp->name;
+ info = fp->info;
+ bflags = fp->flags;
+ size = fp->filsize;
+ src = (char *)(fp + 1);
+ fp = &tfshdr;
+ memset((char *)fp,0,TFSHDRSIZ);
+ }
+ else if (argc == optind+4) { // Filename with addr and len
+ // Extract flags and info fields (if any) from the name...
+ fcomma = strchr(name,',');
+ if (fcomma) {
+ icomma = strchr(fcomma+1,',');
+ if (icomma) {
+ *icomma = 0;
+ info = icomma+1;
+ }
+ *fcomma = 0;
+ bflags = tfsctrl(TFS_FATOB,(long)(fcomma+1),0);
+ }
+
+ fp = &tfshdr;
+ memset((char *)fp,0,TFSHDRSIZ);
+ size = (int)strtol(arg4,0,0);
+ src = (char *)strtoul(arg3,0,0);
+ }
+ else
+ return(CMD_PARAM_ERROR);
+
+ while(addr < (char *)END_OF_NAND) {
+ if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ break;
+ if (fp->hdrsize == 0xffff) {
+ unsigned long nextfileaddr;
+
+ /* We're at the address in NAND where we can add the new
+ * file, but first we need to make sure there's enough
+ * room...
+ */
+ if ((TFSHDRSIZ + size + 16) >= ((char *)END_OF_NAND - addr)) {
+ printf(" not enough space\n");
+ return(CMD_FAILURE);
+ }
+
+ /* Copy name and info data to header.
+ */
+ strcpy(fp->name, name);
+ strcpy(fp->info, info);
+ fp->hdrsize = TFSHDRSIZ;
+ fp->hdrvrsn = TFSHDRVERSION;
+ fp->filsize = size;
+ fp->flags = bflags;
+ fp->flags |= (TFS_ACTIVE | TFS_NSTALE);
+ fp->filcrc = crc32((unsigned char *)src,size);
+ fp->modtime = tfsGetLtime();
+#if TFS_RESERVED
+ {
+ int rsvd;
+ for(rsvd=0;rsvd<TFS_RESERVED;rsvd++)
+ fp->rsvd[rsvd] = 0xffffffff;
+ }
+#endif
+ fp->next = 0;
+ fp->hdrcrc = 0;
+ fp->hdrcrc = crc32((unsigned char *)fp,TFSHDRSIZ);
+ nextfileaddr = NAND_TFSRAM_BASE - NAND_TFS_BASE + (long)addr + TFSHDRSIZ + size;
+ if (nextfileaddr & 0xf)
+ nextfileaddr = (nextfileaddr | 0xf) + 1;
+
+ fp->next = (TFILE *)nextfileaddr;
+
+ printf(" writing %s...\n",arg2);
+ if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+
+ if ((rc = nandWriteChunk(addr+TFSHDRSIZ,src,size)) < 0)
+ printf(" write_file failed %d\n",rc);
+ break;
+ }
+ if (strcmp(TFS_NAME(fp),arg2) == 0) {
+ if (TFS_FILEEXISTS(fp)) {
+ printf(" removing %s...\n",arg2);
+ fp->flags &= ~TFS_ACTIVE;
+ if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0)
+ printf(" write_hdr failed %d\n",rc);
+ }
+ }
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while((long)addr & 0xf) addr++;
+ }
+ }
+ else if (strcmp(cmd, "tfsstat") == 0) {
+ char *addr, *oaddr;
+ TFILE tfshdr, *fp;
+ unsigned long meminuse, memdead;
+
+ fp = &tfshdr;
+ meminuse = memdead = 0;
+ addr = (char *)BASE_OF_NAND;
+ while(addr < (char *)END_OF_NAND) {
+ if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) {
+ printf("nandReadChunk failed %d\n",rc);
+ break;
+ }
+ if (fp->hdrsize == 0xffff)
+ break;
+
+ oaddr = addr;
+ addr += TFS_SIZE(fp);
+ addr += TFSHDRSIZ;
+ while((long)addr & 0xf) addr++;
+
+ if (TFS_FILEEXISTS(fp))
+ meminuse += addr - oaddr;
+ else
+ memdead += addr - oaddr;
+ }
+ printf("Total: 0x%x, used: 0x%x, dead: 0x%x, avail: 0x%x\n",
+ SIZE_OF_NAND, meminuse, memdead,
+ SIZE_OF_NAND - (meminuse + memdead));
+ }
+#endif
+ else
+ return(CMD_PARAM_ERROR);
+
+ return(CMD_SUCCESS);
+}
+#endif