Commit ea7d1eec authored by Scott Wood's avatar Scott Wood

mtd: nand: Remove docg4 driver and palmtreo680 flashing tool

Commit ad4f54ea ("arm: Remove palmtreo680 board") removed the only
user of the docg4 driver and the palmtreo680 image flashing tool.  This
patch removes them.
Signed-off-by: default avatarScott Wood <oss@buserror.net>
Cc: Mike Dunn <mikedunn@newsguy.com>
Cc: Simon Glass <sjg@chromium.org>
parent 5d74e3a6
......@@ -13,7 +13,6 @@ endif
obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o
obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
......@@ -67,7 +66,6 @@ obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
obj-$(CONFIG_NAND_PLAT) += nand_plat.o
obj-$(CONFIG_NAND_DOCG4) += docg4.o
else # minimal SPL drivers
......
This diff is collapsed.
/*
* SPL driver for Diskonchip G4 nand flash
*
* Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com>
*
* SPDX-License-Identifier: GPL-2.0+
*
* This driver basically mimics the load functionality of a typical IPL (initial
* program loader) resident in the 2k NOR-like region of the docg4 that is
* mapped to the reset vector. It allows the u-boot SPL to continue loading if
* the IPL loads a fixed number of flash blocks that is insufficient to contain
* the entire u-boot image. In this case, a concatenated spl + u-boot image is
* written at the flash offset from which the IPL loads an image, and when the
* IPL jumps to the SPL, the SPL resumes loading where the IPL left off. See
* the palmtreo680 for an example.
*
* This driver assumes that the data was written to the flash using the device's
* "reliable" mode, and also assumes that each 512 byte page is stored
* redundantly in the subsequent page. This storage format is likely to be used
* by all boards that boot from the docg4. The format compensates for the lack
* of ecc in the IPL.
*
* Reliable mode reduces the capacity of a block by half, and the redundant
* pages reduce it by half again. As a result, the normal 256k capacity of a
* block is reduced to 64k for the purposes of the IPL/SPL.
*/
#include <asm/io.h>
#include <linux/mtd/docg4.h>
/* forward declarations */
static inline void write_nop(void __iomem *docptr);
static int poll_status(void __iomem *docptr);
static void write_addr(void __iomem *docptr, uint32_t docg4_addr);
static void address_sequence(unsigned int g4_page, unsigned int g4_index,
void __iomem *docptr);
static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr);
int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
{
void *load_addr = dst;
uint32_t flash_offset = offs;
const unsigned int block_count =
(size + DOCG4_BLOCK_CAPACITY_SPL - 1)
/ DOCG4_BLOCK_CAPACITY_SPL;
int i;
for (i = 0; i < block_count; i++) {
int ret = docg4_load_block_reliable(flash_offset, load_addr);
if (ret)
return ret;
load_addr += DOCG4_BLOCK_CAPACITY_SPL;
flash_offset += DOCG4_BLOCK_SIZE;
}
return 0;
}
static inline void write_nop(void __iomem *docptr)
{
writew(0, docptr + DOC_NOP);
}
static int poll_status(void __iomem *docptr)
{
/*
* Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL
* register. Operations known to take a long time (e.g., block erase)
* should sleep for a while before calling this.
*/
uint8_t flash_status;
/* hardware quirk requires reading twice initially */
flash_status = readb(docptr + DOC_FLASHCONTROL);
do {
flash_status = readb(docptr + DOC_FLASHCONTROL);
} while (!(flash_status & DOC_CTRL_FLASHREADY));
return 0;
}
static void write_addr(void __iomem *docptr, uint32_t docg4_addr)
{
/* write the four address bytes packed in docg4_addr to the device */
writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
docg4_addr >>= 8;
writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
docg4_addr >>= 8;
writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
docg4_addr >>= 8;
writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS);
}
static void address_sequence(unsigned int g4_page, unsigned int g4_index,
void __iomem *docptr)
{
writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE);
writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND);
write_nop(docptr);
write_addr(docptr, ((uint32_t)g4_page << 16) | g4_index);
write_nop(docptr);
}
static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr)
{
void __iomem *docptr = (void *)CONFIG_SYS_NAND_BASE;
unsigned int g4_page = flash_offset >> 11; /* 2k page */
const unsigned int last_g4_page = g4_page + 0x80; /* last in block */
int g4_index = 0;
uint16_t flash_status;
uint16_t *buf;
/* flash_offset must be aligned to the start of a block */
if (flash_offset & 0x3ffff)
return -1;
writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE);
writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND);
write_nop(docptr);
write_nop(docptr);
poll_status(docptr);
write_nop(docptr);
writew(0x45, docptr + DOC_FLASHSEQUENCE);
writew(0xa3, docptr + DOC_FLASHCOMMAND);
write_nop(docptr);
writew(0x22, docptr + DOC_FLASHCOMMAND);
write_nop(docptr);
/* read 1st 4 oob bytes of first subpage of block */
address_sequence(g4_page, 0x0100, docptr); /* index at oob */
write_nop(docptr);
flash_status = readw(docptr + DOC_FLASHCONTROL);
flash_status = readw(docptr + DOC_FLASHCONTROL);
if (flash_status & 0x06) /* sequence or protection errors */
return -1;
writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND);
write_nop(docptr);
write_nop(docptr);
poll_status(docptr);
writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0);
write_nop(docptr);
write_nop(docptr);
write_nop(docptr);
write_nop(docptr);
write_nop(docptr);
/*
* Here we read the first four oob bytes of the first page of the block.
* The IPL on the palmtreo680 requires that this contain a 32 bit magic
* number, or the load aborts. We'll ignore it.
*/
readw(docptr + 0x103c); /* hw quirk; 1st read discarded */
readw(docptr + 0x103c); /* lower 16 bits of magic number */
readw(docptr + DOCG4_MYSTERY_REG); /* upper 16 bits of magic number */
writew(0, docptr + DOC_DATAEND);
write_nop(docptr);
write_nop(docptr);
/* load contents of block to memory */
buf = (uint16_t *)dest_addr;
do {
int i;
address_sequence(g4_page, g4_index, docptr);
writew(DOCG4_CMD_READ2,
docptr + DOC_FLASHCOMMAND);
write_nop(docptr);
write_nop(docptr);
poll_status(docptr);
writew(DOC_ECCCONF0_READ_MODE |
DOC_ECCCONF0_ECC_ENABLE |
DOCG4_BCH_SIZE,
docptr + DOC_ECCCONF0);
write_nop(docptr);
write_nop(docptr);
write_nop(docptr);
write_nop(docptr);
write_nop(docptr);
/* read the 512 bytes of page data, 2 bytes at a time */
readw(docptr + 0x103c); /* hw quirk */
for (i = 0; i < 256; i++)
*buf++ = readw(docptr + 0x103c);
/* read oob, but discard it */
for (i = 0; i < 7; i++)
readw(docptr + 0x103c);
readw(docptr + DOCG4_OOB_6_7);
readw(docptr + DOCG4_OOB_6_7);
writew(0, docptr + DOC_DATAEND);
write_nop(docptr);
write_nop(docptr);
if (!(g4_index & 0x100)) {
/* not redundant subpage read; check for ecc error */
write_nop(docptr);
flash_status = readw(docptr + DOC_ECCCONF1);
flash_status = readw(docptr + DOC_ECCCONF1);
if (flash_status & 0x80) { /* ecc error */
g4_index += 0x108; /* read redundant subpage */
buf -= 256; /* back up ram ptr */
continue;
} else /* no ecc error */
g4_index += 0x210; /* skip redundant subpage */
} else /* redundant page was just read; skip ecc error check */
g4_index += 0x108;
if (g4_index == 0x420) { /* finished with 2k page */
g4_index = 0;
g4_page += 2; /* odd-numbered 2k pages skipped */
}
} while (g4_page != last_g4_page); /* while still on same block */
return 0;
}
/*
* Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __DOCG4_H__
#define __DOCG4_H__
#include <common.h>
#include <linux/mtd/nand.h>
extern int docg4_nand_init(struct mtd_info *mtd,
struct nand_chip *nand, int devnum);
/* SPL-related definitions */
#define DOCG4_IPL_LOAD_BLOCK_COUNT 2 /* number of blocks that IPL loads */
#define DOCG4_BLOCK_CAPACITY_SPL 0x10000 /* reliable mode; redundant pages */
#define DOC_IOSPACE_DATA 0x0800
/* register offsets */
#define DOC_CHIPID 0x1000
#define DOC_DEVICESELECT 0x100a
#define DOC_ASICMODE 0x100c
#define DOC_DATAEND 0x101e
#define DOC_NOP 0x103e
#define DOC_FLASHSEQUENCE 0x1032
#define DOC_FLASHCOMMAND 0x1034
#define DOC_FLASHADDRESS 0x1036
#define DOC_FLASHCONTROL 0x1038
#define DOC_ECCCONF0 0x1040
#define DOC_ECCCONF1 0x1042
#define DOC_HAMMINGPARITY 0x1046
#define DOC_BCH_SYNDROM(idx) (0x1048 + idx)
#define DOC_ASICMODECONFIRM 0x1072
#define DOC_CHIPID_INV 0x1074
#define DOC_POWERMODE 0x107c
#define DOCG4_MYSTERY_REG 0x1050
/* apparently used only to write oob bytes 6 and 7 */
#define DOCG4_OOB_6_7 0x1052
/* DOC_FLASHSEQUENCE register commands */
#define DOC_SEQ_RESET 0x00
#define DOCG4_SEQ_PAGE_READ 0x03
#define DOCG4_SEQ_FLUSH 0x29
#define DOCG4_SEQ_PAGEWRITE 0x16
#define DOCG4_SEQ_PAGEPROG 0x1e
#define DOCG4_SEQ_BLOCKERASE 0x24
/* DOC_FLASHCOMMAND register commands */
#define DOCG4_CMD_PAGE_READ 0x00
#define DOC_CMD_ERASECYCLE2 0xd0
#define DOCG4_CMD_FLUSH 0x70
#define DOCG4_CMD_READ2 0x30
#define DOC_CMD_PROG_BLOCK_ADDR 0x60
#define DOCG4_CMD_PAGEWRITE 0x80
#define DOC_CMD_PROG_CYCLE2 0x10
#define DOC_CMD_RESET 0xff
/* DOC_POWERMODE register bits */
#define DOC_POWERDOWN_READY 0x80
/* DOC_FLASHCONTROL register bits */
#define DOC_CTRL_CE 0x10
#define DOC_CTRL_UNKNOWN 0x40
#define DOC_CTRL_FLASHREADY 0x01
/* DOC_ECCCONF0 register bits */
#define DOC_ECCCONF0_READ_MODE 0x8000
#define DOC_ECCCONF0_UNKNOWN 0x2000
#define DOC_ECCCONF0_ECC_ENABLE 0x1000
#define DOC_ECCCONF0_DATA_BYTES_MASK 0x07ff
/* DOC_ECCCONF1 register bits */
#define DOC_ECCCONF1_BCH_SYNDROM_ERR 0x80
#define DOC_ECCCONF1_ECC_ENABLE 0x07
#define DOC_ECCCONF1_PAGE_IS_WRITTEN 0x20
/* DOC_ASICMODE register bits */
#define DOC_ASICMODE_RESET 0x00
#define DOC_ASICMODE_NORMAL 0x01
#define DOC_ASICMODE_POWERDOWN 0x02
#define DOC_ASICMODE_MDWREN 0x04
#define DOC_ASICMODE_BDETCT_RESET 0x08
#define DOC_ASICMODE_RSTIN_RESET 0x10
#define DOC_ASICMODE_RAM_WE 0x20
/* good status values read after read/write/erase operations */
#define DOCG4_PROGSTATUS_GOOD 0x51
#define DOCG4_PROGSTATUS_GOOD_2 0xe0
/*
* On read operations (page and oob-only), the first byte read from I/O reg is a
* status. On error, it reads 0x73; otherwise, it reads either 0x71 (first read
* after reset only) or 0x51, so bit 1 is presumed to be an error indicator.
*/
#define DOCG4_READ_ERROR 0x02 /* bit 1 indicates read error */
/* anatomy of the device */
#define DOCG4_CHIP_SIZE 0x8000000
#define DOCG4_PAGE_SIZE 0x200
#define DOCG4_PAGES_PER_BLOCK 0x200
#define DOCG4_BLOCK_SIZE (DOCG4_PAGES_PER_BLOCK * DOCG4_PAGE_SIZE)
#define DOCG4_NUMBLOCKS (DOCG4_CHIP_SIZE / DOCG4_BLOCK_SIZE)
#define DOCG4_OOB_SIZE 0x10
#define DOCG4_CHIP_SHIFT 27 /* log_2(DOCG4_CHIP_SIZE) */
#define DOCG4_PAGE_SHIFT 9 /* log_2(DOCG4_PAGE_SIZE) */
#define DOCG4_ERASE_SHIFT 18 /* log_2(DOCG4_BLOCK_SIZE) */
/* all but the last byte is included in ecc calculation */
#define DOCG4_BCH_SIZE (DOCG4_PAGE_SIZE + DOCG4_OOB_SIZE - 1)
#define DOCG4_USERDATA_LEN 520 /* 512 byte page plus 8 oob avail to user */
/* expected values from the ID registers */
#define DOCG4_IDREG1_VALUE 0x0400
#define DOCG4_IDREG2_VALUE 0xfbff
/* primitive polynomial used to build the Galois field used by hw ecc gen */
#define DOCG4_PRIMITIVE_POLY 0x4443
#define DOCG4_M 14 /* Galois field is of order 2^14 */
#define DOCG4_T 4 /* BCH alg corrects up to 4 bit errors */
#define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
#endif /* __DOCG4_H__ */
/*
* Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com>
*
* This file is released under the terms of GPL v2 and any later version.
* See the file COPYING in the root directory of the source tree for details.
*
*
* This is a userspace Linux utility that, when run on the Treo 680, will
* program u-boot to flash. The docg4 driver *must* be loaded with the
* reliable_mode and ignore_badblocks parameters enabled:
*
* modprobe docg4 ignore_badblocks=1 reliable_mode=1
*
* This utility writes the concatenated spl + u-boot image to the start of the
* mtd device in the format expected by the IPL/SPL. The image file and mtd
* device node are passed to the utility as arguments. The blocks must have
* been erased beforehand.
*
* When you compile this, note that it links to libmtd from mtd-utils, so ensure
* that your include and lib paths include this.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <mtd/mtd-user.h>
#include "libmtd.h"
#define RELIABLE_BLOCKSIZE 0x10000 /* block capacity in reliable mode */
#define STANDARD_BLOCKSIZE 0x40000 /* block capacity in normal mode */
#define PAGESIZE 512
#define PAGES_PER_BLOCK 512
#define OOBSIZE 7 /* available to user (16 total) */
uint8_t ff_oob[OOBSIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/* this is the magic number the IPL looks for (ASCII "BIPO") */
uint8_t page0_oob[OOBSIZE] = {'B', 'I', 'P', 'O', 0xff, 0xff, 0xff};
int main(int argc, char * const argv[])
{
int devfd, datafd, num_blocks, block;
off_t file_size;
libmtd_t mtd_desc;
struct mtd_dev_info devinfo;
uint8_t *blockbuf;
char response[8];
if (argc != 3) {
printf("usage: %s <image file> <mtd dev node>\n", argv[0]);
return -EINVAL;
}
mtd_desc = libmtd_open();
if (mtd_desc == NULL) {
int errsv = errno;
fprintf(stderr, "can't initialize libmtd\n");
return -errsv;
}
/* open the spl image file and mtd device */
datafd = open(argv[1], O_RDONLY);
if (datafd == -1) {
int errsv = errno;
perror(argv[1]);
return -errsv;
}
devfd = open(argv[2], O_WRONLY);
if (devfd == -1) {
int errsv = errno;
perror(argv[2]);
return -errsv;
}
if (mtd_get_dev_info(mtd_desc, argv[2], &devinfo) < 0) {
int errsv = errno;
perror(argv[2]);
return -errsv;
}
/* determine the number of blocks needed by the image */
file_size = lseek(datafd, 0, SEEK_END);
if (file_size == (off_t)-1) {
int errsv = errno;
perror("lseek");
return -errsv;
}
num_blocks = (file_size + RELIABLE_BLOCKSIZE - 1) / RELIABLE_BLOCKSIZE;
file_size = lseek(datafd, 0, SEEK_SET);
if (file_size == (off_t)-1) {
int errsv = errno;
perror("lseek");
return -errsv;
}
printf("The mtd partition contains %d blocks\n", devinfo.eb_cnt);
printf("U-Boot will occupy %d blocks\n", num_blocks);
if (num_blocks > devinfo.eb_cnt) {
fprintf(stderr, "Insufficient blocks on partition\n");
return -EINVAL;
}
printf("IMPORTANT: These blocks must be in an erased state!\n");
printf("Do you want to proceed?\n");
scanf("%s", response);
if ((response[0] != 'y') && (response[0] != 'Y')) {
printf("Exiting\n");
close(devfd);
close(datafd);
return 0;
}
blockbuf = calloc(RELIABLE_BLOCKSIZE, 1);
if (blockbuf == NULL) {
int errsv = errno;
perror("calloc");
return -errsv;
}
for (block = 0; block < num_blocks; block++) {
int ofs, page;
uint8_t *pagebuf = blockbuf, *buf = blockbuf;
uint8_t *oobbuf = page0_oob; /* magic num in oob of 1st page */
size_t len = RELIABLE_BLOCKSIZE;
int ret;
/* read data for one block from file */
while (len) {
ssize_t read_ret = read(datafd, buf, len);
if (read_ret == -1) {
int errsv = errno;
if (errno == EINTR)
continue;
perror("read");
return -errsv;
} else if (read_ret == 0) {
break; /* EOF */
}
len -= read_ret;
buf += read_ret;
}
printf("Block %d: writing\r", block + 1);
fflush(stdout);
for (page = 0, ofs = 0;
page < PAGES_PER_BLOCK;
page++, ofs += PAGESIZE) {
if (page & 0x04) /* Odd-numbered 2k page */
continue; /* skipped in reliable mode */
ret = mtd_write(mtd_desc, &devinfo, devfd, block, ofs,
pagebuf, PAGESIZE, oobbuf, OOBSIZE,
MTD_OPS_PLACE_OOB);
if (ret) {
fprintf(stderr,
"\nmtd_write returned %d on block %d, ofs %x\n",
ret, block + 1, ofs);
return -EIO;
}
oobbuf = ff_oob; /* oob for subsequent pages */
if (page & 0x01) /* odd-numbered subpage */
pagebuf += PAGESIZE;
}
}
printf("\nDone\n");
close(devfd);
close(datafd);
free(blockbuf);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment