summaryrefslogtreecommitdiff
path: root/recipes/zaurus-utils
diff options
context:
space:
mode:
authorAndrea Adami <andrea.adami@gmail.com>2009-08-12 00:30:24 +0200
committerAndrea Adami <andrea.adami@gmail.com>2009-08-12 00:30:24 +0200
commite71f85f6b4f015c172fdf570d831ef826d4df8c7 (patch)
treeae237259d5b06159d4d03d5d5404c87e6abce36f /recipes/zaurus-utils
parent5a7e0f0eb265c98248ffd23d4801d1e0c1af031b (diff)
nandlogical: move to zaurus-utils
Diffstat (limited to 'recipes/zaurus-utils')
-rw-r--r--recipes/zaurus-utils/nandlogical-klibc-static_1.0.0.bb23
-rw-r--r--recipes/zaurus-utils/nandlogical/mtd-abi.h152
-rw-r--r--recipes/zaurus-utils/nandlogical/mtd-user.h21
-rw-r--r--recipes/zaurus-utils/nandlogical/nandlogical.c386
-rw-r--r--recipes/zaurus-utils/nandlogical_1.0.0.bb18
5 files changed, 600 insertions, 0 deletions
diff --git a/recipes/zaurus-utils/nandlogical-klibc-static_1.0.0.bb b/recipes/zaurus-utils/nandlogical-klibc-static_1.0.0.bb
new file mode 100644
index 0000000000..8c3ca9da79
--- /dev/null
+++ b/recipes/zaurus-utils/nandlogical-klibc-static_1.0.0.bb
@@ -0,0 +1,23 @@
+require nandlogical_${PV}.bb
+
+SRC_URI_append = " file://nandlogical.c \
+ file://mtd-user.h \
+ file://mtd-abi.h \
+ "
+DEPENDS += "klibc"
+
+export CC = ${TARGET_PREFIX}klcc
+
+# standard oe cflags don't work with klcc
+export CFLAGS = ""
+export CPPFLAGS = ""
+export LDFLAGS = ""
+
+do_configure_prepend() {
+ sed -i 's:<mtd/mtd-user.h>:"mtd-user.h":g' '${S}/nandlogical.c'
+ sed -i 's:<mtd/mtd-abi.h>:"mtd-abi.h":g' '${S}/mtd-user.h'
+}
+
+do_compile() {
+ ${CC} nandlogical.c -o nandlogical ${CFLAGS} ${LDFLAGS} -static
+}
diff --git a/recipes/zaurus-utils/nandlogical/mtd-abi.h b/recipes/zaurus-utils/nandlogical/mtd-abi.h
new file mode 100644
index 0000000000..86defe175f
--- /dev/null
+++ b/recipes/zaurus-utils/nandlogical/mtd-abi.h
@@ -0,0 +1,152 @@
+/*
+ * $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $
+ *
+ * Portions of MTD ABI definition which are shared by kernel and user space
+ */
+
+#ifndef __MTD_ABI_H__
+#define __MTD_ABI_H__
+
+struct erase_info_user {
+ uint32_t start;
+ uint32_t length;
+};
+
+struct mtd_oob_buf {
+ uint32_t start;
+ uint32_t length;
+ unsigned char *ptr;
+};
+
+#define MTD_ABSENT 0
+#define MTD_RAM 1
+#define MTD_ROM 2
+#define MTD_NORFLASH 3
+#define MTD_NANDFLASH 4
+#define MTD_DATAFLASH 6
+#define MTD_UBIVOLUME 7
+
+#define MTD_WRITEABLE 0x400 /* Device is writeable */
+#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
+#define MTD_NO_ERASE 0x1000 /* No erase necessary */
+#define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */
+
+// Some common devices / combinations of capabilities
+#define MTD_CAP_ROM 0
+#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
+#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
+#define MTD_CAP_NANDFLASH (MTD_WRITEABLE)
+
+/* ECC byte placement */
+#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended)
+#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode)
+#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme
+#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read)
+#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default
+
+/* OTP mode selection */
+#define MTD_OTP_OFF 0
+#define MTD_OTP_FACTORY 1
+#define MTD_OTP_USER 2
+
+struct mtd_info_user {
+ uint8_t type;
+ uint32_t flags;
+ uint32_t size; // Total size of the MTD
+ uint32_t erasesize;
+ uint32_t writesize;
+ uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
+ /* The below two fields are obsolete and broken, do not use them
+ * (TODO: remove at some point) */
+ uint32_t ecctype;
+ uint32_t eccsize;
+};
+
+struct region_info_user {
+ uint32_t offset; /* At which this region starts,
+ * from the beginning of the MTD */
+ uint32_t erasesize; /* For this region */
+ uint32_t numblocks; /* Number of blocks in this region */
+ uint32_t regionindex;
+};
+
+struct otp_info {
+ uint32_t start;
+ uint32_t length;
+ uint32_t locked;
+};
+
+#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
+#define MEMERASE _IOW('M', 2, struct erase_info_user)
+#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
+#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
+#define MEMLOCK _IOW('M', 5, struct erase_info_user)
+#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
+#define MEMGETREGIONCOUNT _IOR('M', 7, int)
+#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
+#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
+#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
+#define MEMGETBADBLOCK _IOW('M', 11, loff_t)
+#define MEMSETBADBLOCK _IOW('M', 12, loff_t)
+#define OTPSELECT _IOR('M', 13, int)
+#define OTPGETREGIONCOUNT _IOW('M', 14, int)
+#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
+#define OTPLOCK _IOR('M', 16, struct otp_info)
+#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
+#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
+#define MTDFILEMODE _IO('M', 19)
+
+/*
+ * Obsolete legacy interface. Keep it in order not to break userspace
+ * interfaces
+ */
+struct nand_oobinfo {
+ uint32_t useecc;
+ uint32_t eccbytes;
+ uint32_t oobfree[8][2];
+ uint32_t eccpos[32];
+};
+
+struct nand_oobfree {
+ uint32_t offset;
+ uint32_t length;
+};
+
+#define MTD_MAX_OOBFREE_ENTRIES 8
+/*
+ * ECC layout control structure. Exported to userspace for
+ * diagnosis and to allow creation of raw images
+ */
+struct nand_ecclayout {
+ uint32_t eccbytes;
+ uint32_t eccpos[64];
+ uint32_t oobavail;
+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
+};
+
+/**
+ * struct mtd_ecc_stats - error correction stats
+ *
+ * @corrected: number of corrected bits
+ * @failed: number of uncorrectable errors
+ * @badblocks: number of bad blocks in this partition
+ * @bbtblocks: number of blocks reserved for bad block tables
+ */
+struct mtd_ecc_stats {
+ uint32_t corrected;
+ uint32_t failed;
+ uint32_t badblocks;
+ uint32_t bbtblocks;
+};
+
+/*
+ * Read/write file modes for access to MTD
+ */
+enum mtd_file_modes {
+ MTD_MODE_NORMAL = MTD_OTP_OFF,
+ MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
+ MTD_MODE_OTP_USER = MTD_OTP_USER,
+ MTD_MODE_RAW,
+};
+
+#endif /* __MTD_ABI_H__ */
diff --git a/recipes/zaurus-utils/nandlogical/mtd-user.h b/recipes/zaurus-utils/nandlogical/mtd-user.h
new file mode 100644
index 0000000000..713f34d3e6
--- /dev/null
+++ b/recipes/zaurus-utils/nandlogical/mtd-user.h
@@ -0,0 +1,21 @@
+/*
+ * $Id: mtd-user.h,v 1.2 2004/05/05 14:44:57 dwmw2 Exp $
+ *
+ * MTD ABI header for use by user space only.
+ */
+
+#ifndef __MTD_USER_H__
+#define __MTD_USER_H__
+
+#include <stdint.h>
+
+/* This file is blessed for inclusion by userspace */
+#include <mtd/mtd-abi.h>
+
+typedef struct mtd_info_user mtd_info_t;
+typedef struct erase_info_user erase_info_t;
+typedef struct region_info_user region_info_t;
+typedef struct nand_oobinfo nand_oobinfo_t;
+typedef struct nand_ecclayout nand_ecclayout_t;
+
+#endif /* __MTD_USER_H__ */
diff --git a/recipes/zaurus-utils/nandlogical/nandlogical.c b/recipes/zaurus-utils/nandlogical/nandlogical.c
new file mode 100644
index 0000000000..d88d1c212f
--- /dev/null
+++ b/recipes/zaurus-utils/nandlogical/nandlogical.c
@@ -0,0 +1,386 @@
+/*
+ NAND logical utility for Sharp Zaurus SL-C7x0/860/7500/Cxx00
+ version 1.0
+ Copyright 2006 Alexander Chukov <sash@pdaXrom.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ */
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+
+int fd;
+
+unsigned char *readbuf;
+unsigned char *oobbuf;
+unsigned long *log2phy;
+
+struct mtd_oob_buf oob = {0, 16, NULL};
+
+struct nand_oobinfo none_oobinfo = {
+ .useecc = MTD_NANDECC_OFF,
+};
+
+#define NAND_LOGICAL_SIZE (7 * 1024 * 1024)
+
+/////////////////////////////////////////////////////////////////////
+// oob structure
+/////////////////////////////////////////////////////////////////////
+
+#define NAND_NOOB_LOGADDR_00 8
+#define NAND_NOOB_LOGADDR_01 9
+#define NAND_NOOB_LOGADDR_10 10
+#define NAND_NOOB_LOGADDR_11 11
+#define NAND_NOOB_LOGADDR_20 12
+#define NAND_NOOB_LOGADDR_21 13
+
+static uint nand_get_logical_no(unsigned char *oob)
+{
+ unsigned short us,bit;
+ int par;
+ int good0, good1;
+
+ if(oob[NAND_NOOB_LOGADDR_00] == oob[NAND_NOOB_LOGADDR_10] &&
+ oob[NAND_NOOB_LOGADDR_01] == oob[NAND_NOOB_LOGADDR_11]){
+ good0 = NAND_NOOB_LOGADDR_00;
+ good1 = NAND_NOOB_LOGADDR_01;
+ }else
+ if(oob[NAND_NOOB_LOGADDR_10] == oob[NAND_NOOB_LOGADDR_20] &&
+ oob[NAND_NOOB_LOGADDR_11] == oob[NAND_NOOB_LOGADDR_21]){
+ good0 = NAND_NOOB_LOGADDR_10;
+ good1 = NAND_NOOB_LOGADDR_11;
+ }else
+ if(oob[NAND_NOOB_LOGADDR_20] == oob[NAND_NOOB_LOGADDR_00] &&
+ oob[NAND_NOOB_LOGADDR_21] == oob[NAND_NOOB_LOGADDR_01]){
+ good0 = NAND_NOOB_LOGADDR_20;
+ good1 = NAND_NOOB_LOGADDR_21;
+ }else{
+ return (uint)-1;
+ }
+
+ us = (((unsigned short)(oob[good0]) & 0x00ff) << 0) |
+ (((unsigned short)(oob[good1]) & 0x00ff) << 8);
+
+ par = 0;
+ for(bit = 0x0001; bit != 0; bit <<= 1){
+ if(us & bit){
+ par++;
+ }
+ }
+ if(par & 1){
+ return (uint)-2;
+ }
+
+ if(us == 0xffff){
+ return 0xffff;
+ }else{
+ return ((us & 0x07fe) >> 1);
+ }
+}
+
+static void nand_set_logical_no(uint log_no, unsigned char *oob)
+{
+ unsigned short us,bit;
+ int par;
+
+ us = (((log_no & 0x03ff) << 1) | 0x1000);
+
+ par = 0;
+ for(bit = 0x0001; bit != 0; bit <<= 1){
+ if(us & bit){
+ par++;
+ }
+ }
+ if(par & 1){
+ us |= 0x0001;
+ }
+
+ oob[NAND_NOOB_LOGADDR_00] = (unsigned char)((us & 0x00ff) >> 0);
+ oob[NAND_NOOB_LOGADDR_01] = (unsigned char)((us & 0xff00) >> 8);
+ oob[NAND_NOOB_LOGADDR_10] = oob[NAND_NOOB_LOGADDR_00];
+ oob[NAND_NOOB_LOGADDR_11] = oob[NAND_NOOB_LOGADDR_01];
+ oob[NAND_NOOB_LOGADDR_20] = oob[NAND_NOOB_LOGADDR_00];
+ oob[NAND_NOOB_LOGADDR_21] = oob[NAND_NOOB_LOGADDR_01];
+}
+
+void scan_logical(int blocks, int erasesize)
+{
+ int i;
+ unsigned long offset;
+ int ret = 1;
+ for (i = 0; i < blocks; i++)
+ log2phy[i] = (uint) -1;
+ offset = 0;
+ for (i = 0; i < blocks; i++) {
+ oob.start = offset;
+ ret = ioctl(fd, MEMREADOOB, &oob);
+
+ //ret = nand_read_raw(nand, oobuf, offset, nand->writesize, nand->oobsize);
+ if (!ret) {
+ int log_no = nand_get_logical_no(oobbuf);
+ if (((int)log_no >= 0) && (log_no < blocks)) {
+ log2phy[log_no] = offset;
+ //printf("NAND logical - %08X -> %04X\n", offset, log_no * erasesize);
+ } else {
+ //printf("NAND logical - %08X - skip (%x)\n", offset, log_no);
+ }
+ } else {
+ //printf("NAND logical - offset %x read OOB problem\n", offset);
+ }
+ offset += erasesize;
+ }
+}
+
+unsigned long add_logical(unsigned long ofs, int blocks, int erasesize, int bs)
+{
+ erase_info_t erase;
+ unsigned long offset = 0;
+ int i;
+ int ret;
+
+ erase.length = erasesize;
+
+ for (i = 0; i < blocks; i++) {
+ oob.start = offset;
+ ret = ioctl(fd, MEMREADOOB, &oob);
+
+ if (!ret) {
+ int log_no = nand_get_logical_no(oobbuf);
+
+//printf("-- %x\n", log_no);
+
+ if ((short)log_no == -1) {
+ int j = 0;
+ {
+ loff_t offs = offset;
+ erase.start = offset;
+ int ret = ioctl(fd, MEMGETBADBLOCK, &offs);
+ if (ret > 0) {
+ printf ("\nSkipping bad block at 0x%08x\n", erase.start);
+ goto nextblock;
+ } else if (ret < 0) {
+ perror("ioctl(MEMGETBADBLOCK)");
+ exit(1);
+ } else {
+ printf("%x - no bad block\n", offset);
+ }
+
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ perror("ioctl(MEMERASE)");
+ goto nextblock;
+ }
+
+ //printf("%x - erased\n", offset);
+
+ }
+
+ //printf("NAND logical - found free block %x, mapped as %x\n", offset, ofs);
+
+ log2phy[ofs / erasesize] = offset;
+
+ return offset;
+ } else {
+ //fprintf(stderr, "found: %x\n", log_no);
+ }
+ } else {
+ perror ("ioctl(MEMREADOOB)");
+ }
+
+ nextblock:
+ offset += erasesize;
+ }
+
+ return (unsigned long)-1;
+}
+
+void usage(void)
+{
+ fprintf(stderr, "Usage:\nnandlogical <mtd char device> READ|WRITE <start> <length> <file>\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ mtd_info_t meminfo;
+ char *mtddev;
+ int blocks;
+ unsigned long start_addr;
+ unsigned long end_addr;
+ unsigned long length;
+ unsigned long ofs;
+ int bs;
+ int ofd;
+ int func_write = 0;
+ int oobinfochanged = 0;
+ struct nand_oobinfo old_oobinfo;
+
+ if (argc < 6)
+ usage();
+
+ if (strcmp(argv[2], "WRITE") == 0)
+ func_write = 1;
+ else if (strcmp(argv[2], "READ") != 0)
+ usage();
+
+ mtddev = argv[1];
+ start_addr = strtoul(argv[3], NULL, 0);
+ length = strtoul(argv[4], NULL, 0);
+
+ if (func_write) {
+ if ((ofd = open(argv[5], O_RDONLY)) == -1) {
+ perror("open input file");
+ exit(1);
+ }
+ /* Open MTD device */
+ if ((fd = open(mtddev, O_RDWR)) == -1) {
+ perror("open flash");
+ exit (1);
+ }
+ } else {
+ if ((ofd = open(argv[5], O_WRONLY | O_TRUNC | O_CREAT, 0644)) == -1) {
+ perror ("open outfile");
+ exit(1);
+ }
+ /* Open MTD device */
+ if ((fd = open(mtddev, O_RDONLY)) == -1) {
+ perror("open flash");
+ exit (1);
+ }
+ }
+
+ /* Fill in MTD device capability structure */
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("MEMGETINFO");
+ close(fd);
+ exit (1);
+ }
+
+ /* Make sure device page sizes are valid */
+ if (!(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
+ !(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
+ !(meminfo.oobsize == 8 && meminfo.writesize == 256)) {
+ fprintf(stderr, "Unknown flash (not normal NAND)\n");
+ close(fd);
+ exit(1);
+ }
+
+ //printf("erasesize %x\nwritesize %x\noobsize %x\nsize %x\n", meminfo.erasesize, meminfo.writesize, meminfo.oobsize, meminfo.size);
+
+ blocks = NAND_LOGICAL_SIZE / meminfo.erasesize;
+ log2phy = (unsigned long *) malloc(blocks * sizeof(unsigned long));
+ readbuf = (char *)malloc(meminfo.erasesize);
+ oobbuf = (char *)malloc(meminfo.writesize);
+ oob.ptr = oobbuf;
+
+ scan_logical(blocks, meminfo.erasesize);
+
+ //printf("Start: %x\nEnd: %x\n", start_addr, length);
+
+ end_addr = start_addr + length;
+ bs = meminfo.writesize;
+
+ for (ofs = start_addr; ofs < end_addr ; ofs+=bs) {
+ int new_logical_added = 0;
+ int offset = log2phy[ofs / meminfo.erasesize];
+
+ if ((int)offset < 0 && func_write) {
+ //printf("add logical block...\n");
+ offset = add_logical(ofs, blocks, meminfo.erasesize, bs);
+ new_logical_added = 1;
+ }
+
+ if ((int)offset < 0) {
+ printf("NAND logical - offset %08X not found\n", ofs);
+ goto closeall;
+ }
+
+ offset += ofs % meminfo.erasesize;
+
+ //printf(":%x\n", offset);
+
+ if (func_write) {
+ int len;
+ memset(readbuf, 0xff, bs);
+ len = read(ofd, readbuf, bs);
+ if (len > 0) {
+#if 1
+ if (ofs % meminfo.erasesize == 0) {
+ int j;
+ erase_info_t erase;
+ erase.start = offset;
+ erase.length = meminfo.erasesize;
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ printf("ioctl(MEMERASE) %x\n", offset);
+ //goto nextblock;
+ }
+ //printf("Erased\n");
+
+ for (j = 0; j < meminfo.erasesize; j+=bs) {
+ int log_no;
+ oob.start = offset + j;
+ oob.length = 16;
+
+ memset(oobbuf, 0xff, 16);
+ nand_set_logical_no(ofs / meminfo.erasesize, oobbuf);
+ if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
+ //perror ("ioctl(MEMWRITEOOB)");
+ printf("NAND logical add - MEMWRITEOOB error %x\n", offset + j);
+ exit(1);
+ }
+ memset(oobbuf, 0xff, 16);
+ if (ioctl(fd, MEMREADOOB, &oob) != 0) {
+ perror ("ioctl(MEMREADOOB)");
+ exit(1);
+ }
+ log_no = nand_get_logical_no(oobbuf);
+ //printf("%x:1 write %x, read %x\n", offset + j, ofs / meminfo.erasesize, log_no);
+ }
+
+ }
+#endif
+ if (pwrite(fd, readbuf, bs, offset) != bs) {
+ perror ("pwrite");
+ goto closeall;
+ }
+
+ } else
+ break;
+ } else {
+ if (pread(fd, readbuf, bs, offset) != bs) {
+ perror("pread");
+ goto closeall;
+ }
+ write(ofd, readbuf, ((end_addr - ofs) < bs)?(end_addr - ofs):bs);
+ }
+ }
+
+ closeall:
+
+ free(log2phy);
+ free(readbuf);
+ free(oobbuf);
+ close(fd);
+ close(ofd);
+
+ return 0;
+}
diff --git a/recipes/zaurus-utils/nandlogical_1.0.0.bb b/recipes/zaurus-utils/nandlogical_1.0.0.bb
new file mode 100644
index 0000000000..d567b48a3c
--- /dev/null
+++ b/recipes/zaurus-utils/nandlogical_1.0.0.bb
@@ -0,0 +1,18 @@
+DESCRIPTION = "Nandlogical for Sharp mtd1"
+LICENSE = "GPL"
+DEPENDS = "mtd-utils"
+COMPATIBLE_MACHINE = "(poodle|c7x0|akita|spitz|tosa)"
+PR = "r2"
+
+SRC_URI = "file://nandlogical.c"
+
+S = "${WORKDIR}"
+
+do_compile () {
+ ${CC} nandlogical.c -o nandlogical ${CFLAGS} ${LDFLAGS}
+}
+
+do_install () {
+ install -d ${D}${bindir}/
+ install -m 0755 nandlogical ${D}${bindir}/
+}