diff options
Diffstat (limited to 'sys/dev')
27 files changed, 0 insertions, 9419 deletions
diff --git a/sys/dev/nand/nand.c b/sys/dev/nand/nand.c deleted file mode 100644 index 6997ef7f8a0d..000000000000 --- a/sys/dev/nand/nand.c +++ /dev/null @@ -1,826 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/callout.h> -#include <sys/sysctl.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_ecc_pos.h> -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" -#include <machine/stdarg.h> - -#define NAND_RESET_DELAY 1000 /* tRST */ -#define NAND_ERASE_DELAY 3000 /* tBERS */ -#define NAND_PROG_DELAY 700 /* tPROG */ -#define NAND_READ_DELAY 50 /* tR */ - -#define BIT0(x) ((x) & 0x1) -#define BIT1(x) (BIT0(x >> 1)) -#define BIT2(x) (BIT0(x >> 2)) -#define BIT3(x) (BIT0(x >> 3)) -#define BIT4(x) (BIT0(x >> 4)) -#define BIT5(x) (BIT0(x >> 5)) -#define BIT6(x) (BIT0(x >> 6)) -#define BIT7(x) (BIT0(x >> 7)) - -#define SOFTECC_SIZE 256 -#define SOFTECC_BYTES 3 - -int nand_debug_flag = 0; -SYSCTL_INT(_debug, OID_AUTO, nand_debug, CTLFLAG_RWTUN, &nand_debug_flag, 0, - "NAND subsystem debug flag"); - -MALLOC_DEFINE(M_NAND, "NAND", "NAND dynamic data"); - -static void calculate_ecc(const uint8_t *, uint8_t *); -static int correct_ecc(uint8_t *, uint8_t *, uint8_t *); - -void -nand_debug(int level, const char *fmt, ...) -{ - va_list ap; - - if (!(nand_debug_flag & level)) - return; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); -} - -void -nand_init(struct nand_softc *nand, device_t dev, int ecc_mode, - int ecc_bytes, int ecc_size, uint16_t *eccposition, char *cdev_name) -{ - - nand->ecc.eccmode = ecc_mode; - nand->chip_cdev_name = cdev_name; - - if (ecc_mode == NAND_ECC_SOFT) { - nand->ecc.eccbytes = SOFTECC_BYTES; - nand->ecc.eccsize = SOFTECC_SIZE; - } else if (ecc_mode != NAND_ECC_NONE) { - nand->ecc.eccbytes = ecc_bytes; - nand->ecc.eccsize = ecc_size; - if (eccposition) - nand->ecc.eccpositions = eccposition; - } -} - -void -nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params) -{ - struct chip_geom *cg; - - cg = &chip->chip_geom; - - init_chip_geom(cg, params->luns, params->blocks_per_lun, - params->pages_per_block, params->bytes_per_page, - params->spare_bytes_per_page); - chip->t_bers = params->t_bers; - chip->t_prog = params->t_prog; - chip->t_r = params->t_r; - chip->t_ccs = params->t_ccs; - - if (params->features & ONFI_FEAT_16BIT) - chip->flags |= NAND_16_BIT; -} - -void -nand_set_params(struct nand_chip *chip, struct nand_params *params) -{ - struct chip_geom *cg; - uint32_t blocks_per_chip; - - cg = &chip->chip_geom; - blocks_per_chip = (params->chip_size << 20) / - (params->page_size * params->pages_per_block); - - init_chip_geom(cg, 1, blocks_per_chip, - params->pages_per_block, params->page_size, - params->oob_size); - - chip->t_bers = NAND_ERASE_DELAY; - chip->t_prog = NAND_PROG_DELAY; - chip->t_r = NAND_READ_DELAY; - chip->t_ccs = 0; - - if (params->flags & NAND_16_BIT) - chip->flags |= NAND_16_BIT; -} - -int -nand_init_stat(struct nand_chip *chip) -{ - struct block_stat *blk_stat; - struct page_stat *pg_stat; - struct chip_geom *cg; - uint32_t blks, pgs; - - cg = &chip->chip_geom; - blks = cg->blks_per_lun * cg->luns; - blk_stat = malloc(sizeof(struct block_stat) * blks, M_NAND, - M_WAITOK | M_ZERO); - if (!blk_stat) - return (ENOMEM); - - pgs = blks * cg->pgs_per_blk; - pg_stat = malloc(sizeof(struct page_stat) * pgs, M_NAND, - M_WAITOK | M_ZERO); - if (!pg_stat) { - free(blk_stat, M_NAND); - return (ENOMEM); - } - - chip->blk_stat = blk_stat; - chip->pg_stat = pg_stat; - - return (0); -} - -void -nand_destroy_stat(struct nand_chip *chip) -{ - - free(chip->pg_stat, M_NAND); - free(chip->blk_stat, M_NAND); -} - -int -init_chip_geom(struct chip_geom *cg, uint32_t luns, uint32_t blks_per_lun, - uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size) -{ - int shift; - - if (!cg) - return (-1); - - cg->luns = luns; - cg->blks_per_lun = blks_per_lun; - cg->blks_per_chip = blks_per_lun * luns; - cg->pgs_per_blk = pgs_per_blk; - - cg->page_size = pg_size; - cg->oob_size = oob_size; - cg->block_size = cg->page_size * cg->pgs_per_blk; - cg->chip_size = cg->block_size * cg->blks_per_chip; - - shift = fls(cg->pgs_per_blk - 1); - cg->pg_mask = (1 << shift) - 1; - cg->blk_shift = shift; - - if (cg->blks_per_lun > 0) { - shift = fls(cg->blks_per_lun - 1); - cg->blk_mask = ((1 << shift) - 1) << cg->blk_shift; - } else { - shift = 0; - cg->blk_mask = 0; - } - - cg->lun_shift = shift + cg->blk_shift; - shift = fls(cg->luns - 1); - cg->lun_mask = ((1 << shift) - 1) << cg->lun_shift; - - nand_debug(NDBG_NAND, "Masks: lun 0x%x blk 0x%x page 0x%x\n" - "Shifts: lun %d blk %d", - cg->lun_mask, cg->blk_mask, cg->pg_mask, - cg->lun_shift, cg->blk_shift); - - return (0); -} - -int -nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun, - uint32_t *blk, uint32_t *pg) -{ - - if (!cg || !lun || !blk || !pg) - return (-1); - - if (row & ~(cg->lun_mask | cg->blk_mask | cg->pg_mask)) { - nand_debug(NDBG_NAND,"Address out of bounds\n"); - return (-1); - } - - *lun = (row & cg->lun_mask) >> cg->lun_shift; - *blk = (row & cg->blk_mask) >> cg->blk_shift; - *pg = (row & cg->pg_mask); - - nand_debug(NDBG_NAND,"address %x-%x-%x\n", *lun, *blk, *pg); - - return (0); -} - -int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row) -{ - uint32_t lun, block, pg_in_blk; - - if (!cg || !row) - return (-1); - - block = page / cg->pgs_per_blk; - pg_in_blk = page % cg->pgs_per_blk; - - lun = block / cg->blks_per_lun; - block = block % cg->blks_per_lun; - - *row = (lun << cg->lun_shift) & cg->lun_mask; - *row |= ((block << cg->blk_shift) & cg->blk_mask); - *row |= (pg_in_blk & cg->pg_mask); - - return (0); -} - -int -nand_check_page_boundary(struct nand_chip *chip, uint32_t page) -{ - struct chip_geom* cg; - - cg = &chip->chip_geom; - if (page >= (cg->pgs_per_blk * cg->blks_per_lun * cg->luns)) { - nand_debug(NDBG_GEN,"%s: page number too big %#x\n", - __func__, page); - return (1); - } - - return (0); -} - -void -nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param) -{ - struct chip_geom *cg; - - cg = &chip->chip_geom; - param->page_size = cg->page_size; - param->oob_size = cg->oob_size; - - param->blocks = cg->blks_per_lun * cg->luns; - param->pages_per_block = cg->pgs_per_blk; -} - -static uint16_t * -default_software_ecc_positions(struct nand_chip *chip) -{ - /* If positions have been set already, use them. */ - if (chip->nand->ecc.eccpositions) - return (chip->nand->ecc.eccpositions); - - /* - * XXX Note that the following logic isn't really sufficient, especially - * in the ONFI case where the number of ECC bytes can be dictated by - * values in the parameters page, and that could lead to needing more - * byte positions than exist within the tables of software-ecc defaults. - */ - if (chip->chip_geom.oob_size >= 128) - return (default_software_ecc_positions_128); - if (chip->chip_geom.oob_size >= 64) - return (default_software_ecc_positions_64); - else if (chip->chip_geom.oob_size >= 16) - return (default_software_ecc_positions_16); - - return (NULL); -} - -static void -calculate_ecc(const uint8_t *buf, uint8_t *ecc) -{ - uint8_t p8, byte; - int i; - - memset(ecc, 0, 3); - - for (i = 0; i < 256; i++) { - byte = buf[i]; - ecc[0] ^= (BIT0(byte) ^ BIT2(byte) ^ BIT4(byte) ^ - BIT6(byte)) << 2; - ecc[0] ^= (BIT1(byte) ^ BIT3(byte) ^ BIT5(byte) ^ - BIT7(byte)) << 3; - ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT4(byte) ^ - BIT5(byte)) << 4; - ecc[0] ^= (BIT2(byte) ^ BIT3(byte) ^ BIT6(byte) ^ - BIT7(byte)) << 5; - ecc[0] ^= (BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ - BIT3(byte)) << 6; - ecc[0] ^= (BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ - BIT7(byte)) << 7; - - p8 = BIT0(byte) ^ BIT1(byte) ^ BIT2(byte) ^ - BIT3(byte) ^ BIT4(byte) ^ BIT5(byte) ^ BIT6(byte) ^ - BIT7(byte); - - if (p8) { - ecc[2] ^= (0x1 << BIT0(i)); - ecc[2] ^= (0x4 << BIT1(i)); - ecc[2] ^= (0x10 << BIT2(i)); - ecc[2] ^= (0x40 << BIT3(i)); - - ecc[1] ^= (0x1 << BIT4(i)); - ecc[1] ^= (0x4 << BIT5(i)); - ecc[1] ^= (0x10 << BIT6(i)); - ecc[1] ^= (0x40 << BIT7(i)); - } - } - ecc[0] = ~ecc[0]; - ecc[1] = ~ecc[1]; - ecc[2] = ~ecc[2]; - ecc[0] |= 3; -} - -static int -correct_ecc(uint8_t *buf, uint8_t *calc_ecc, uint8_t *read_ecc) -{ - uint8_t ecc0, ecc1, ecc2, onesnum, bit, byte; - uint16_t addr = 0; - - ecc0 = calc_ecc[0] ^ read_ecc[0]; - ecc1 = calc_ecc[1] ^ read_ecc[1]; - ecc2 = calc_ecc[2] ^ read_ecc[2]; - - if (!ecc0 && !ecc1 && !ecc2) - return (ECC_OK); - - addr = BIT3(ecc0) | (BIT5(ecc0) << 1) | (BIT7(ecc0) << 2); - addr |= (BIT1(ecc2) << 3) | (BIT3(ecc2) << 4) | - (BIT5(ecc2) << 5) | (BIT7(ecc2) << 6); - addr |= (BIT1(ecc1) << 7) | (BIT3(ecc1) << 8) | - (BIT5(ecc1) << 9) | (BIT7(ecc1) << 10); - - onesnum = 0; - while (ecc0 || ecc1 || ecc2) { - if (ecc0 & 1) - onesnum++; - if (ecc1 & 1) - onesnum++; - if (ecc2 & 1) - onesnum++; - - ecc0 >>= 1; - ecc1 >>= 1; - ecc2 >>= 1; - } - - if (onesnum == 11) { - /* Correctable error */ - bit = addr & 7; - byte = addr >> 3; - buf[byte] ^= (1 << bit); - return (ECC_CORRECTABLE); - } else if (onesnum == 1) { - /* ECC error */ - return (ECC_ERROR_ECC); - } else { - /* Uncorrectable error */ - return (ECC_UNCORRECTABLE); - } - - return (0); -} - -int -nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc) -{ - int steps = pagesize / SOFTECC_SIZE; - int i = 0, j = 0; - - for (; i < (steps * SOFTECC_BYTES); - i += SOFTECC_BYTES, j += SOFTECC_SIZE) { - calculate_ecc(&buf[j], &ecc[i]); - } - - return (0); -} - -int -nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize, - uint8_t *readecc, uint8_t *calcecc) -{ - int steps = pagesize / SOFTECC_SIZE; - int i = 0, j = 0, ret = 0; - - for (i = 0; i < (steps * SOFTECC_BYTES); - i += SOFTECC_BYTES, j += SOFTECC_SIZE) { - ret += correct_ecc(&buf[j], &calcecc[i], &readecc[i]); - if (ret < 0) - return (ret); - } - - return (ret); -} - -static int -offset_to_page(struct chip_geom *cg, uint32_t offset) -{ - - return (offset / cg->page_size); -} - -int -nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - struct nand_ecc_data *eccd; - struct page_stat *pg_stat; - device_t nandbus; - void *oob = NULL; - uint8_t *ptr; - uint16_t *eccpos = NULL; - uint32_t page, num, steps = 0; - int i, retval = 0, needwrite; - - nand_debug(NDBG_NAND,"%p read page %x[%x]", chip, offset, len); - cg = &chip->chip_geom; - eccd = &chip->nand->ecc; - page = offset_to_page(cg, offset); - num = len / cg->page_size; - - if (eccd->eccmode != NAND_ECC_NONE) { - steps = cg->page_size / eccd->eccsize; - eccpos = default_software_ecc_positions(chip); - oob = malloc(cg->oob_size, M_NAND, M_WAITOK); - } - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - while (num--) { - pg_stat = &(chip->pg_stat[page]); - - if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - retval = ENXIO; - break; - } - - if (eccd->eccmode != NAND_ECC_NONE) { - if (NAND_GET_ECC(chip->dev, ptr, eccd->ecccalculated, - &needwrite)) { - retval = ENXIO; - break; - } - nand_debug(NDBG_ECC,"%s: ECC calculated:", - __func__); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->ecccalculated[i]); - - nand_debug(NDBG_ECC,"\n"); - - if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size, - 0)) { - retval = ENXIO; - break; - } - for (i = 0; i < (eccd->eccbytes * steps); i++) - eccd->eccread[i] = ((uint8_t *)oob)[eccpos[i]]; - - nand_debug(NDBG_ECC,"%s: ECC read:", __func__); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->eccread[i]); - nand_debug(NDBG_ECC,"\n"); - - retval = NAND_CORRECT_ECC(chip->dev, ptr, eccd->eccread, - eccd->ecccalculated); - - nand_debug(NDBG_ECC, "NAND_CORRECT_ECC() returned %d", - retval); - - if (retval == 0) - pg_stat->ecc_stat.ecc_succeded++; - else if (retval > 0) { - pg_stat->ecc_stat.ecc_corrected += retval; - retval = ECC_CORRECTABLE; - } else { - pg_stat->ecc_stat.ecc_failed++; - break; - } - } - - pg_stat->page_read++; - page++; - ptr += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - - if (oob) - free(oob, M_NAND); - - return (retval); -} - -int -nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - uint8_t *ptr; - uint32_t page, num, end, begin = 0, begin_off; - int retval = 0; - - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - begin_off = offset - page * cg->page_size; - if (begin_off) { - begin = cg->page_size - begin_off; - len -= begin; - } - num = len / cg->page_size; - end = len % cg->page_size; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - if (begin_off) { - if (NAND_READ_PAGE(chip->dev, page, ptr, begin, begin_off)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += begin; - } - - while (num--) { - if (NAND_READ_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += cg->page_size; - } - - if (end) - if (NAND_READ_PAGE(chip->dev, page, ptr, end, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - - -int -nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf, - uint32_t len) -{ - struct chip_geom *cg; - struct page_stat *pg_stat; - struct nand_ecc_data *eccd; - device_t nandbus; - uint32_t page, num; - uint8_t *oob = NULL; - uint16_t *eccpos = NULL; - int steps = 0, i, needwrite, err = 0; - - nand_debug(NDBG_NAND,"%p prog page %x[%x]", chip, offset, len); - - eccd = &chip->nand->ecc; - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - num = len / cg->page_size; - - if (eccd->eccmode != NAND_ECC_NONE) { - steps = cg->page_size / eccd->eccsize; - oob = malloc(cg->oob_size, M_NAND, M_WAITOK); - eccpos = default_software_ecc_positions(chip); - } - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - while (num--) { - if (NAND_PROGRAM_PAGE(chip->dev, page, buf, cg->page_size, 0)) { - err = ENXIO; - break; - } - - if (eccd->eccmode != NAND_ECC_NONE) { - if (NAND_GET_ECC(chip->dev, buf, &eccd->ecccalculated, - &needwrite)) { - err = ENXIO; - break; - } - nand_debug(NDBG_ECC,"ECC calculated:"); - if (nand_debug_flag & NDBG_ECC) - for (i = 0; i < (eccd->eccbytes * steps); i++) - printf("%x ", eccd->ecccalculated[i]); - - nand_debug(NDBG_ECC,"\n"); - - if (needwrite) { - if (NAND_READ_OOB(chip->dev, page, oob, cg->oob_size, - 0)) { - err = ENXIO; - break; - } - - for (i = 0; i < (eccd->eccbytes * steps); i++) - oob[eccpos[i]] = eccd->ecccalculated[i]; - - if (NAND_PROGRAM_OOB(chip->dev, page, oob, - cg->oob_size, 0)) { - err = ENXIO; - break; - } - } - } - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_written++; - - page++; - buf += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - - if (oob) - free(oob, M_NAND); - - return (err); -} - -int -nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - uint8_t *ptr; - uint32_t page, num, end, begin = 0, begin_off; - int retval = 0; - - cg = &chip->chip_geom; - page = offset_to_page(cg, offset); - begin_off = offset - page * cg->page_size; - if (begin_off) { - begin = cg->page_size - begin_off; - len -= begin; - } - num = len / cg->page_size; - end = len % cg->page_size; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - ptr = (uint8_t *)buf; - if (begin_off) { - if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, begin, begin_off)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += begin; - } - - while (num--) { - if (NAND_PROGRAM_PAGE(chip->dev, page, ptr, cg->page_size, 0)) { - NANDBUS_UNLOCK(nandbus); - return (ENXIO); - } - - page++; - ptr += cg->page_size; - } - - if (end) - retval = NAND_PROGRAM_PAGE(chip->dev, page, ptr, end, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - -int -nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len) -{ - device_t nandbus; - int retval = 0; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - retval = NAND_READ_OOB(chip->dev, page, buf, len, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - - -int -nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len) -{ - device_t nandbus; - int retval = 0; - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - retval = NAND_PROGRAM_OOB(chip->dev, page, buf, len, 0); - - NANDBUS_UNLOCK(nandbus); - - return (retval); -} - -int -nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len) -{ - device_t nandbus; - struct chip_geom *cg; - uint32_t block, num_blocks; - int err = 0; - - cg = &chip->chip_geom; - if ((offset % cg->block_size) || (len % cg->block_size)) - return (EINVAL); - - block = offset / cg->block_size; - num_blocks = len / cg->block_size; - nand_debug(NDBG_NAND,"%p erase blocks %d[%d]", chip, block, num_blocks); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - while (num_blocks--) { - if (!nand_check_bad_block(chip, block)) { - if (NAND_ERASE_BLOCK(chip->dev, block)) { - nand_debug(NDBG_NAND,"%p erase blocks %d error", - chip, block); - nand_mark_bad_block(chip, block); - err = ENXIO; - } - } else - err = ENXIO; - - block++; - } - - NANDBUS_UNLOCK(nandbus); - - if (err) - nand_update_bbt(chip); - - return (err); -} - -MODULE_VERSION(nand, 1); diff --git a/sys/dev/nand/nand.h b/sys/dev/nand/nand.h deleted file mode 100644 index 06902601b8d0..000000000000 --- a/sys/dev/nand/nand.h +++ /dev/null @@ -1,415 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_H_ -#define _DEV_NAND_H_ - -#include <sys/bus.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/lock.h> -#include <sys/sx.h> -#include <sys/taskqueue.h> -#include <sys/queue.h> -#include <sys/bio.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/malloc.h> - -#include <dev/nand/nand_dev.h> - -MALLOC_DECLARE(M_NAND); - -/* Read commands */ -#define NAND_CMD_READ 0x00 -#define NAND_CMD_CHNG_READ_COL 0x05 -#define NAND_CMD_READ_END 0x30 -#define NAND_CMD_READ_CACHE 0x31 -#define NAND_CMD_READ_CPBK 0x35 -#define NAND_CMD_READ_CACHE_END 0x3F -#define NAND_CMD_CHNG_READ_COL_END 0xE0 - -/* Erase commands */ -#define NAND_CMD_ERASE 0x60 -#define NAND_CMD_ERASE_END 0xD0 -#define NAND_CMD_ERASE_INTLV 0xD1 - -/* Program commands */ -#define NAND_CMD_PROG 0x80 -#define NAND_CMD_CHNG_WRITE_COL 0x85 -#define NAND_CMD_PROG_END 0x10 -#define NAND_CMD_PROG_INTLV 0x11 -#define NAND_CMD_PROG_CACHE 0x15 - -/* Misc commands */ -#define NAND_CMD_STATUS 0x70 -#define NAND_CMD_STATUS_ENH 0x78 -#define NAND_CMD_READ_ID 0x90 -#define NAND_CMD_READ_PARAMETER 0xec -#define NAND_CMD_READ_UNIQUE_ID 0xed -#define NAND_CMD_GET_FEATURE 0xee -#define NAND_CMD_SET_FEATURE 0xef - -/* Reset commands */ -#define NAND_CMD_SYNCH_RESET 0xfc -#define NAND_CMD_RESET 0xff - -/* Small page flash commands */ -#define NAND_CMD_SMALLA 0x00 -#define NAND_CMD_SMALLB 0x01 -#define NAND_CMD_SMALLOOB 0x50 - -#define NAND_STATUS_FAIL 0x1 -#define NAND_STATUS_FAILC 0x2 -#define NAND_STATUS_ARDY 0x20 -#define NAND_STATUS_RDY 0x40 -#define NAND_STATUS_WP 0x80 - -#define NAND_LP_OOB_COLUMN_START 0x800 -#define NAND_LP_OOBSZ 0x40 -#define NAND_SP_OOB_COLUMN_START 0x200 -#define NAND_SP_OOBSZ 0x10 - -#define PAGE_PARAM_LENGTH 0x100 -#define PAGE_PARAMETER_DEF 0x0 -#define PAGE_PARAMETER_RED_1 0x100 -#define PAGE_PARAMETER_RED_2 0x200 - -#define ONFI_SIG_ADDR 0x20 - -#define NAND_MAX_CHIPS 0x4 -#define NAND_MAX_OOBSZ 512 -#define NAND_MAX_PAGESZ 16384 - -#define NAND_SMALL_PAGE_SIZE 0x200 - -#define NAND_16_BIT 0x00000001 - -#define NAND_ECC_NONE 0x0 -#define NAND_ECC_SOFT 0x1 -#define NAND_ECC_FULLHW 0x2 -#define NAND_ECC_PARTHW 0x4 -#define NAND_ECC_MODE_MASK 0x7 - -#define ECC_OK 0 -#define ECC_CORRECTABLE 1 -#define ECC_ERROR_ECC (-1) -#define ECC_UNCORRECTABLE (-2) - -#define NAND_MAN_SAMSUNG 0xec -#define NAND_MAN_HYNIX 0xad -#define NAND_MAN_STMICRO 0x20 -#define NAND_MAN_MICRON 0x2c - -struct nand_id { - uint8_t man_id; - uint8_t dev_id; -}; - -struct nand_params { - struct nand_id id; - char *name; - uint32_t chip_size; - uint32_t page_size; - uint32_t oob_size; - uint32_t pages_per_block; - uint32_t flags; -}; - -/* nand debug levels */ -#define NDBG_NAND 0x01 -#define NDBG_CDEV 0x02 -#define NDBG_GEN 0x04 -#define NDBG_GEOM 0x08 -#define NDBG_BUS 0x10 -#define NDBG_SIM 0x20 -#define NDBG_CTRL 0x40 -#define NDBG_DRV 0x80 -#define NDBG_ECC 0x100 - -/* nand_debug_function */ -void nand_debug(int level, const char *fmt, ...); -extern int nand_debug_flag; - -/* ONFI features bit*/ -#define ONFI_FEAT_16BIT 0x01 -#define ONFI_FEAT_MULT_LUN 0x02 -#define ONFI_FEAT_INTLV_OPS 0x04 -#define ONFI_FEAT_CPBK_RESTRICT 0x08 -#define ONFI_FEAT_SRC_SYNCH 0x10 - -/* ONFI optional commands bits */ -#define ONFI_OPTCOM_PROG_CACHE 0x01 -#define ONFI_OPTCOM_READ_CACHE 0x02 -#define ONFI_OPTCOM_GETSET_FEAT 0x04 -#define ONFI_OPTCOM_STATUS_ENH 0x08 -#define ONFI_OPTCOM_COPYBACK 0x10 -#define ONFI_OPTCOM_UNIQUE_ID 0x20 - - -/* Layout of parameter page is defined in ONFI */ -struct onfi_params { - char signature[4]; - uint16_t rev; - uint16_t features; - uint16_t optional_commands; - uint8_t primary_advanced_command; - uint8_t res1; - uint16_t extended_parameter_page_length; - uint8_t parameter_page_count; - uint8_t res2[17]; - char manufacturer_name[12]; - char device_model[20]; - uint8_t manufacturer_id; - uint8_t manufacture_date_yy; - uint8_t manufacture_date_ww; - uint8_t res3[13]; - uint32_t bytes_per_page; - uint16_t spare_bytes_per_page; - uint32_t bytes_per_partial_page; - uint16_t spare_bytes_per_partial_page; - uint32_t pages_per_block; - uint32_t blocks_per_lun; - uint8_t luns; - uint8_t address_cycles; - uint8_t bits_per_cell; - uint16_t max_bad_block_per_lun; - uint16_t block_endurance; - uint8_t guaranteed_valid_blocks; - uint16_t valid_block_endurance; - uint8_t programs_per_page; - uint8_t partial_prog_attr; - uint8_t bits_of_ecc; - uint8_t interleaved_addr_bits; - uint8_t interleaved_oper_attr; - uint8_t eznand_support; - uint8_t res4[12]; - uint8_t pin_capacitance; - uint16_t asynch_timing_mode_support; - uint16_t asynch_prog_cache_timing_mode_support; - uint16_t t_prog; /* us, max page program time */ - uint16_t t_bers; /* us, max block erase time */ - uint16_t t_r; /* us, max page read time */ - uint16_t t_ccs; /* ns, min change column setup time */ - uint16_t source_synch_timing_mode_support; - uint8_t source_synch_feat; - uint16_t clk_input_capacitance; - uint16_t io_capacitance; - uint16_t input_capacitance; - uint8_t input_capacitance_max; - uint8_t driver_strength_support; - uint16_t t_r_interleaved; - uint16_t t_adl; - uint16_t t_r_eznand; - uint8_t nv_ddr2_features; - uint8_t nv_ddr2_warmup_cycles; - uint8_t res5[4]; - uint16_t vendor_rev; - uint8_t vendor_spec[88]; - uint16_t crc; -}__attribute__((packed)); -CTASSERT(sizeof(struct onfi_params) == 256); - -struct onfi_chip_params { - uint32_t blocks_per_lun; - uint32_t pages_per_block; - uint32_t bytes_per_page; - uint32_t spare_bytes_per_page; - uint16_t t_bers; - uint16_t t_prog; - uint16_t t_r; - uint16_t t_ccs; - uint16_t features; - uint8_t address_cycles; - uint8_t luns; -}; - -struct nand_ecc_data { - int eccsize; /* Number of data bytes per ECC step */ - int eccmode; - int eccbytes; /* Number of ECC bytes per step */ - - uint16_t *eccpositions; /* Positions of ecc bytes */ - uint8_t ecccalculated[NAND_MAX_OOBSZ]; - uint8_t eccread[NAND_MAX_OOBSZ]; -}; - -struct ecc_stat { - uint32_t ecc_succeded; - uint32_t ecc_corrected; - uint32_t ecc_failed; -}; - -struct page_stat { - struct ecc_stat ecc_stat; - uint32_t page_read; - uint32_t page_raw_read; - uint32_t page_written; - uint32_t page_raw_written; -}; - -struct block_stat { - uint32_t block_erased; -}; - -struct chip_geom { - uint32_t chip_size; - uint32_t block_size; - uint32_t page_size; - uint32_t oob_size; - - uint32_t luns; - uint32_t blks_per_lun; - uint32_t blks_per_chip; - uint32_t pgs_per_blk; - - uint32_t pg_mask; - uint32_t blk_mask; - uint32_t lun_mask; - uint8_t blk_shift; - uint8_t lun_shift; -}; - -struct nand_chip { - device_t dev; - struct nand_id id; - struct chip_geom chip_geom; - - uint16_t t_prog; /* us, max page program time */ - uint16_t t_bers; /* us, max block erase time */ - uint16_t t_r; /* us, max page read time */ - uint16_t t_ccs; /* ns, min change column setup time */ - uint8_t num; - uint8_t flags; - - struct page_stat *pg_stat; - struct block_stat *blk_stat; - struct nand_softc *nand; - struct nand_bbt *bbt; - struct nand_ops *ops; - struct cdev *cdev; - - struct disk *ndisk; - struct disk *rdisk; - struct bio_queue_head bioq; /* bio queue */ - struct mtx qlock; /* bioq lock */ - struct taskqueue *tq; /* private task queue for i/o request */ - struct task iotask; /* i/o processing */ - -}; - -struct nand_softc { - uint8_t flags; - - char *chip_cdev_name; - struct nand_ecc_data ecc; -}; - -/* NAND ops */ -int nand_erase_blocks(struct nand_chip *chip, off_t offset, size_t len); -int nand_prog_pages(struct nand_chip *chip, uint32_t offset, uint8_t *buf, - uint32_t len); -int nand_read_pages(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_read_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_prog_pages_raw(struct nand_chip *chip, uint32_t offset, void *buf, - uint32_t len); -int nand_read_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len); -int nand_prog_oob(struct nand_chip *chip, uint32_t page, void *buf, - uint32_t len); - -int nand_select_cs(device_t dev, uint8_t cs); - -int nand_read_parameter(struct nand_softc *nand, struct onfi_params *param); -int nand_synch_reset(struct nand_softc *nand); -int nand_chng_read_col(device_t dev, uint32_t col, void *buf, size_t len); -int nand_chng_write_col(device_t dev, uint32_t col, void *buf, size_t len); -int nand_get_feature(device_t dev, uint8_t feat, void* buf); -int nand_set_feature(device_t dev, uint8_t feat, void* buf); - - -int nand_erase_block_intlv(device_t dev, uint32_t block); -int nand_copyback_read(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_copyback_prog(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_copyback_prog_intlv(device_t dev, uint32_t page); -int nand_prog_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end); -int nand_prog_intlv(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len); -int nand_read_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end); - -int nand_write_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data); -int nand_read_ecc(struct nand_softc *nand, uint32_t page, uint8_t *data); - -int nand_softecc_get(device_t dev, uint8_t *buf, int pagesize, uint8_t *ecc); -int nand_softecc_correct(device_t dev, uint8_t *buf, int pagesize, - uint8_t *readecc, uint8_t *calcecc); - -/* Chip initialization */ -void nand_init(struct nand_softc *nand, device_t dev, int ecc_mode, - int ecc_bytes, int ecc_size, uint16_t* eccposition, char* cdev_name); -void nand_detach(struct nand_softc *nand); -struct nand_params *nand_get_params(struct nand_id *id); - -void nand_onfi_set_params(struct nand_chip *chip, struct onfi_chip_params *params); -void nand_set_params(struct nand_chip *chip, struct nand_params *params); -int nand_init_stat(struct nand_chip *chip); -void nand_destroy_stat(struct nand_chip *chip); - -/* BBT */ -int nand_init_bbt(struct nand_chip *chip); -void nand_destroy_bbt(struct nand_chip *chip); -int nand_update_bbt(struct nand_chip *chip); -int nand_mark_bad_block(struct nand_chip* chip, uint32_t block_num); -int nand_check_bad_block(struct nand_chip* chip, uint32_t block_num); - -/* cdev creation/removal */ -int nand_make_dev(struct nand_chip* chip); -void nand_destroy_dev(struct nand_chip *chip); - -int create_geom_disk(struct nand_chip* chip); -int create_geom_raw_disk(struct nand_chip *chip); -void destroy_geom_disk(struct nand_chip *chip); -void destroy_geom_raw_disk(struct nand_chip *chip); - -int init_chip_geom(struct chip_geom* cg, uint32_t luns, uint32_t blks_per_lun, - uint32_t pgs_per_blk, uint32_t pg_size, uint32_t oob_size); -int nand_row_to_blkpg(struct chip_geom *cg, uint32_t row, uint32_t *lun, - uint32_t *blk, uint32_t *pg); -int page_to_row(struct chip_geom *cg, uint32_t page, uint32_t *row); -int nand_check_page_boundary(struct nand_chip *chip, uint32_t page); -void nand_get_chip_param(struct nand_chip *chip, struct chip_param_io *param); - -#endif /* _DEV_NAND_H_ */ diff --git a/sys/dev/nand/nand_bbt.c b/sys/dev/nand/nand_bbt.c deleted file mode 100644 index d99ed67523a2..000000000000 --- a/sys/dev/nand/nand_bbt.c +++ /dev/null @@ -1,275 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/cdefs.h> - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/bus.h> - -#include <dev/nand/nand.h> - -#include "nand_if.h" - -#define BBT_PRIMARY_PATTERN 0x01020304 -#define BBT_SECONDARY_PATTERN 0x05060708 - -enum bbt_place { - BBT_NONE, - BBT_PRIMARY, - BBT_SECONDARY -}; - -struct nand_bbt { - struct nand_chip *chip; - uint32_t primary_map; - uint32_t secondary_map; - enum bbt_place active; - struct bbt_header *hdr; - uint32_t tab_len; - uint32_t *table; -}; - -struct bbt_header { - uint32_t pattern; - int32_t seq_nr; -}; - -static int nand_bbt_save(struct nand_bbt *); -static int nand_bbt_load_hdr(struct nand_bbt *, struct bbt_header *, int8_t); -static int nand_bbt_load_table(struct nand_bbt *); -static int nand_bbt_prescan(struct nand_bbt *); - -int -nand_init_bbt(struct nand_chip *chip) -{ - struct chip_geom *cg; - struct nand_bbt *bbt; - int err; - - cg = &chip->chip_geom; - - bbt = malloc(sizeof(struct nand_bbt), M_NAND, M_ZERO | M_WAITOK); - if (!bbt) { - device_printf(chip->dev, - "Cannot allocate memory for bad block struct"); - return (ENOMEM); - } - - bbt->chip = chip; - bbt->active = BBT_NONE; - bbt->primary_map = cg->chip_size - cg->block_size; - bbt->secondary_map = cg->chip_size - 2 * cg->block_size; - bbt->tab_len = cg->blks_per_chip * sizeof(uint32_t); - bbt->hdr = malloc(sizeof(struct bbt_header) + bbt->tab_len, M_NAND, - M_WAITOK); - if (!bbt->hdr) { - device_printf(chip->dev, "Cannot allocate %d bytes for BB " - "Table", bbt->tab_len); - free(bbt, M_NAND); - return (ENOMEM); - } - bbt->hdr->seq_nr = 0; - bbt->table = (uint32_t *)((uint8_t *)bbt->hdr + - sizeof(struct bbt_header)); - - err = nand_bbt_load_table(bbt); - if (err) { - free(bbt->table, M_NAND); - free(bbt, M_NAND); - return (err); - } - - chip->bbt = bbt; - if (bbt->active == BBT_NONE) { - bbt->active = BBT_PRIMARY; - memset(bbt->table, 0xff, bbt->tab_len); - nand_bbt_prescan(bbt); - nand_bbt_save(bbt); - } else - device_printf(chip->dev, "Found BBT table for chip\n"); - - return (0); -} - -void -nand_destroy_bbt(struct nand_chip *chip) -{ - - if (chip->bbt) { - nand_bbt_save(chip->bbt); - - free(chip->bbt->hdr, M_NAND); - free(chip->bbt, M_NAND); - chip->bbt = NULL; - } -} - -int -nand_update_bbt(struct nand_chip *chip) -{ - - nand_bbt_save(chip->bbt); - - return (0); -} - -static int -nand_bbt_save(struct nand_bbt *bbt) -{ - enum bbt_place next; - uint32_t addr; - int32_t err; - - if (bbt->active == BBT_PRIMARY) { - addr = bbt->secondary_map; - bbt->hdr->pattern = BBT_SECONDARY_PATTERN; - next = BBT_SECONDARY; - } else { - addr = bbt->primary_map; - bbt->hdr->pattern = BBT_PRIMARY_PATTERN; - next = BBT_PRIMARY; - } - - err = nand_erase_blocks(bbt->chip, addr, - bbt->chip->chip_geom.block_size); - if (err) - return (err); - - bbt->hdr->seq_nr++; - - err = nand_prog_pages_raw(bbt->chip, addr, bbt->hdr, - bbt->tab_len + sizeof(struct bbt_header)); - if (err) - return (err); - - bbt->active = next; - return (0); -} - -static int -nand_bbt_load_hdr(struct nand_bbt *bbt, struct bbt_header *hdr, int8_t primary) -{ - uint32_t addr; - - if (primary) - addr = bbt->primary_map; - else - addr = bbt->secondary_map; - - return (nand_read_pages_raw(bbt->chip, addr, hdr, - sizeof(struct bbt_header))); -} - -static int -nand_bbt_load_table(struct nand_bbt *bbt) -{ - struct bbt_header hdr1, hdr2; - uint32_t address = 0; - int err = 0; - - bzero(&hdr1, sizeof(hdr1)); - bzero(&hdr2, sizeof(hdr2)); - - nand_bbt_load_hdr(bbt, &hdr1, 1); - if (hdr1.pattern == BBT_PRIMARY_PATTERN) { - bbt->active = BBT_PRIMARY; - address = bbt->primary_map; - } else - bzero(&hdr1, sizeof(hdr1)); - - - nand_bbt_load_hdr(bbt, &hdr2, 0); - if ((hdr2.pattern == BBT_SECONDARY_PATTERN) && - (hdr2.seq_nr > hdr1.seq_nr)) { - bbt->active = BBT_SECONDARY; - address = bbt->secondary_map; - } else - bzero(&hdr2, sizeof(hdr2)); - - if (bbt->active != BBT_NONE) - err = nand_read_pages_raw(bbt->chip, address, bbt->hdr, - bbt->tab_len + sizeof(struct bbt_header)); - - return (err); -} - -static int -nand_bbt_prescan(struct nand_bbt *bbt) -{ - int32_t i; - uint8_t bad; - bool printed_hash = 0; - - device_printf(bbt->chip->dev, "No BBT found. Prescan chip...\n"); - for (i = 0; i < bbt->chip->chip_geom.blks_per_chip; i++) { - if (NAND_IS_BLK_BAD(bbt->chip->dev, i, &bad)) - return (ENXIO); - - if (bad) { - device_printf(bbt->chip->dev, "Bad block(%d)\n", i); - bbt->table[i] = 0x0FFFFFFF; - } - if (!(i % 100)) { - printf("#"); - printed_hash = 1; - } - } - - if (printed_hash) - printf("\n"); - - return (0); -} - -int -nand_check_bad_block(struct nand_chip *chip, uint32_t block_number) -{ - - if (!chip || !chip->bbt) - return (0); - - if ((chip->bbt->table[block_number] & 0xF0000000) == 0) - return (1); - - return (0); -} - -int -nand_mark_bad_block(struct nand_chip *chip, uint32_t block_number) -{ - - chip->bbt->table[block_number] = 0x0FFFFFFF; - - return (0); -} diff --git a/sys/dev/nand/nand_cdev.c b/sys/dev/nand/nand_cdev.c deleted file mode 100644 index 53c62dbc2913..000000000000 --- a/sys/dev/nand/nand_cdev.c +++ /dev/null @@ -1,454 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/uio.h> -#include <sys/bio.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_dev.h> -#include "nand_if.h" -#include "nandbus_if.h" - -static int nand_page_stat(struct nand_chip *, struct page_stat_io *); -static int nand_block_stat(struct nand_chip *, struct block_stat_io *); - -static d_ioctl_t nand_ioctl; -static d_open_t nand_open; -static d_strategy_t nand_strategy; - -static struct cdevsw nand_cdevsw = { - .d_version = D_VERSION, - .d_name = "nand", - .d_open = nand_open, - .d_read = physread, - .d_write = physwrite, - .d_ioctl = nand_ioctl, - .d_strategy = nand_strategy, -}; - -static int -offset_to_page(struct chip_geom *cg, uint32_t offset) -{ - - return (offset / cg->page_size); -} - -static int -offset_to_page_off(struct chip_geom *cg, uint32_t offset) -{ - - return (offset % cg->page_size); -} - -int -nand_make_dev(struct nand_chip *chip) -{ - struct nandbus_ivar *ivar; - device_t parent, nandbus; - int parent_unit, unit; - char *name; - - ivar = device_get_ivars(chip->dev); - nandbus = device_get_parent(chip->dev); - - if (ivar->chip_cdev_name) { - name = ivar->chip_cdev_name; - - /* - * If we got distinct name for chip device we can enumarete it - * based on contoller number. - */ - parent = device_get_parent(nandbus); - } else { - name = "nand"; - parent = nandbus; - } - - parent_unit = device_get_unit(parent); - unit = parent_unit * 4 + chip->num; - chip->cdev = make_dev(&nand_cdevsw, unit, UID_ROOT, GID_WHEEL, - 0666, "%s%d.%d", name, parent_unit, chip->num); - - if (chip->cdev == NULL) - return (ENXIO); - - if (bootverbose) - device_printf(chip->dev, "Created cdev %s%d.%d for chip " - "[0x%0x, 0x%0x]\n", name, parent_unit, chip->num, - ivar->man_id, ivar->dev_id); - - chip->cdev->si_drv1 = chip; - - return (0); -} - -void -nand_destroy_dev(struct nand_chip *chip) -{ - - if (chip->cdev) - destroy_dev(chip->cdev); -} - -static int -nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td) -{ - - return (0); -} - -static int -nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - int start_page, count, off, err = 0; - uint8_t *ptr, *tmp; - - nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num, - chip, offset); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - cg = &chip->chip_geom; - start_page = offset_to_page(cg, offset); - off = offset_to_page_off(cg, offset); - count = (len > cg->page_size - off) ? cg->page_size - off : len; - - ptr = (uint8_t *)buf; - while (len > 0) { - if (len < cg->page_size) { - tmp = malloc(cg->page_size, M_NAND, M_WAITOK); - if (!tmp) { - err = ENOMEM; - break; - } - err = NAND_READ_PAGE(chip->dev, start_page, - tmp, cg->page_size, 0); - if (err) { - free(tmp, M_NAND); - break; - } - bcopy(tmp + off, ptr, count); - free(tmp, M_NAND); - } else { - err = NAND_READ_PAGE(chip->dev, start_page, - ptr, cg->page_size, 0); - if (err) - break; - } - - len -= count; - start_page++; - ptr += count; - count = (len > cg->page_size) ? cg->page_size : len; - off = 0; - } - - NANDBUS_UNLOCK(nandbus); - return (err); -} - -static int -nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) -{ - struct chip_geom *cg; - device_t nandbus; - int off, start_page, err = 0; - uint8_t *ptr; - - nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num, - chip, offset); - - nandbus = device_get_parent(chip->dev); - NANDBUS_LOCK(nandbus); - NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); - - cg = &chip->chip_geom; - start_page = offset_to_page(cg, offset); - off = offset_to_page_off(cg, offset); - - if (off != 0 || (len % cg->page_size) != 0) { - printf("Not aligned write start [0x%08x] size [0x%08x]\n", - off, len); - NANDBUS_UNLOCK(nandbus); - return (EINVAL); - } - - ptr = (uint8_t *)buf; - while (len > 0) { - err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr, - cg->page_size, 0); - if (err) - break; - - len -= cg->page_size; - start_page++; - ptr += cg->page_size; - } - - NANDBUS_UNLOCK(nandbus); - return (err); -} - -static void -nand_strategy(struct bio *bp) -{ - struct nand_chip *chip; - struct cdev *dev; - int err = 0; - - dev = bp->bio_dev; - chip = dev->si_drv1; - - nand_debug(NDBG_CDEV, "Strategy %s on chip %d [%p]\n", - bp->bio_cmd == BIO_READ ? "READ" : "WRITE", - chip->num, chip); - - if (bp->bio_cmd == BIO_READ) { - err = nand_read(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else { - err = nand_write(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - - if (err == 0) - bp->bio_resid = 0; - else { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - } - - biodone(bp); -} - -static int -nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, - uint32_t len, uint8_t *data, uint8_t write) -{ - struct chip_geom *cg; - uint8_t *buf = NULL; - int ret = 0; - - cg = &chip->chip_geom; - - buf = malloc(cg->oob_size, M_NAND, M_WAITOK); - if (!buf) - return (ENOMEM); - - memset(buf, 0xff, cg->oob_size); - - if (!write) { - ret = nand_read_oob(chip, page, buf, cg->oob_size); - copyout(buf, data, len); - } else { - copyin(data, buf, len); - ret = nand_prog_oob(chip, page, buf, cg->oob_size); - } - - free(buf, M_NAND); - - return (ret); -} - -static int -nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, - struct thread *td) -{ - struct nand_chip *chip; - struct chip_geom *cg; - struct nand_oob_rw *oob_rw = NULL; - struct nand_raw_rw *raw_rw = NULL; - device_t nandbus; - size_t bufsize = 0, len = 0; - size_t raw_size; - off_t off; - uint8_t *buf = NULL; - int ret = 0; - uint8_t status; - - chip = (struct nand_chip *)dev->si_drv1; - cg = &chip->chip_geom; - nandbus = device_get_parent(chip->dev); - - if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { - raw_rw = (struct nand_raw_rw *)data; - raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); - - /* Check if len is not bigger than chip size */ - if (raw_rw->len > raw_size) - return (EFBIG); - - /* - * Do not ask for too much memory, in case of large transfers - * read/write in 16-pages chunks - */ - bufsize = 16 * (cg->page_size + cg->oob_size); - if (raw_rw->len < bufsize) - bufsize = raw_rw->len; - - buf = malloc(bufsize, M_NAND, M_WAITOK); - len = raw_rw->len; - off = 0; - } - switch(cmd) { - case NAND_IO_ERASE: - ret = nand_erase_blocks(chip, ((off_t *)data)[0], - ((off_t *)data)[1]); - break; - - case NAND_IO_OOB_READ: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 0); - break; - - case NAND_IO_OOB_PROG: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 1); - break; - - case NAND_IO_GET_STATUS: - NANDBUS_LOCK(nandbus); - ret = NANDBUS_GET_STATUS(nandbus, &status); - if (ret == 0) - *(uint8_t *)data = status; - NANDBUS_UNLOCK(nandbus); - break; - - case NAND_IO_RAW_PROG: - while (len > 0) { - if (len < bufsize) - bufsize = len; - ret = copyin(raw_rw->data + off, buf, bufsize); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_RAW_READ: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - - ret = copyout(buf, raw_rw->data + off, bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_PAGE_STAT: - ret = nand_page_stat(chip, (struct page_stat_io *)data); - break; - - case NAND_IO_BLOCK_STAT: - ret = nand_block_stat(chip, (struct block_stat_io *)data); - break; - - case NAND_IO_GET_CHIP_PARAM: - nand_get_chip_param(chip, (struct chip_param_io *)data); - break; - - default: - printf("Unknown nand_ioctl request \n"); - ret = EIO; - } - - if (buf) - free(buf, M_NAND); - - return (ret); -} - -static int -nand_page_stat(struct nand_chip *chip, struct page_stat_io *page_stat) -{ - struct chip_geom *cg; - struct page_stat *stat; - int num_pages; - - cg = &chip->chip_geom; - num_pages = cg->pgs_per_blk * cg->blks_per_lun * cg->luns; - if (page_stat->page_num >= num_pages) - return (EINVAL); - - stat = &chip->pg_stat[page_stat->page_num]; - page_stat->page_read = stat->page_read; - page_stat->page_written = stat->page_written; - page_stat->page_raw_read = stat->page_raw_read; - page_stat->page_raw_written = stat->page_raw_written; - page_stat->ecc_succeded = stat->ecc_stat.ecc_succeded; - page_stat->ecc_corrected = stat->ecc_stat.ecc_corrected; - page_stat->ecc_failed = stat->ecc_stat.ecc_failed; - - return (0); -} - -static int -nand_block_stat(struct nand_chip *chip, struct block_stat_io *block_stat) -{ - struct chip_geom *cg; - uint32_t block_num = block_stat->block_num; - - cg = &chip->chip_geom; - if (block_num >= cg->blks_per_lun * cg->luns) - return (EINVAL); - - block_stat->block_erased = chip->blk_stat[block_num].block_erased; - - return (0); -} diff --git a/sys/dev/nand/nand_dev.h b/sys/dev/nand/nand_dev.h deleted file mode 100644 index bd00c4d4b3b4..000000000000 --- a/sys/dev/nand/nand_dev.h +++ /dev/null @@ -1,92 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_CDEV_H_ -#define _DEV_NAND_CDEV_H_ - -#include <sys/ioccom.h> -#include <sys/param.h> - -struct nand_raw_rw { - off_t off; - off_t len; - uint8_t *data; -}; - -struct nand_oob_rw { - uint32_t page; - off_t len; - uint8_t *data; -}; - -#define NAND_IOCTL_GROUP 'N' -#define NAND_IO_ERASE _IOWR(NAND_IOCTL_GROUP, 0x0, off_t[2]) - -#define NAND_IO_OOB_READ _IOWR(NAND_IOCTL_GROUP, 0x1, struct nand_oob_rw) - -#define NAND_IO_OOB_PROG _IOWR(NAND_IOCTL_GROUP, 0x2, struct nand_oob_rw) - -#define NAND_IO_RAW_READ _IOWR(NAND_IOCTL_GROUP, 0x3, struct nand_raw_rw) - -#define NAND_IO_RAW_PROG _IOWR(NAND_IOCTL_GROUP, 0x4, struct nand_raw_rw) - -#define NAND_IO_GET_STATUS _IOWR(NAND_IOCTL_GROUP, 0x5, uint8_t) - -struct page_stat_io { - uint32_t page_num; - uint32_t page_read; - uint32_t page_written; - uint32_t page_raw_read; - uint32_t page_raw_written; - uint32_t ecc_succeded; - uint32_t ecc_corrected; - uint32_t ecc_failed; -}; -#define NAND_IO_PAGE_STAT _IOWR(NAND_IOCTL_GROUP, 0x6, \ - struct page_stat_io) - -struct block_stat_io { - uint32_t block_num; - uint32_t block_erased; -}; -#define NAND_IO_BLOCK_STAT _IOWR(NAND_IOCTL_GROUP, 0x7, \ - struct block_stat_io) - -struct chip_param_io { - uint32_t page_size; - uint32_t oob_size; - - uint32_t blocks; - uint32_t pages_per_block; -}; -#define NAND_IO_GET_CHIP_PARAM _IOWR(NAND_IOCTL_GROUP, 0x8, \ - struct chip_param_io) - -#endif /* _DEV_NAND_CDEV_H_ */ diff --git a/sys/dev/nand/nand_ecc_pos.h b/sys/dev/nand/nand_ecc_pos.h deleted file mode 100644 index 835f45e6c083..000000000000 --- a/sys/dev/nand/nand_ecc_pos.h +++ /dev/null @@ -1,58 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _DEV_NAND_ECC_POS_H_ -#define _DEV_NAND_ECC_POS_H_ - -static uint16_t default_software_ecc_positions_16[] = {2, 0, 1, 7, 4, 6}; - -static uint16_t default_software_ecc_positions_64[] = { - - 42, 40, 41, 45, 43, 44, 48, 46, - 47, 51, 49, 50, 54, 52, 53, 57, - 55, 56, 60, 58, 59, 63, 61, 62 -}; - -static uint16_t default_software_ecc_positions_128[] = { - 8, 9, 10, 11, 12, 13, - 18, 19, 20, 21, 22, 23, - 28, 29, 30, 31, 32, 33, - 38, 39, 40, 41, 42, 43, - 48, 49, 50, 51, 52, 53, - 58, 59, 60, 61, 62, 63, - 68, 69, 70, 71, 72, 73, - 78, 79, 80, 81, 82, 83, - 88, 89, 90, 91, 92, 93, - 98, 99, 100, 101, 102, 103, - 108, 109, 110, 111, 112, 113, - 118, 119, 120, 121, 122, 123, -}; -#endif /* _DEV_NAND_ECC_POS_H_ */ - diff --git a/sys/dev/nand/nand_generic.c b/sys/dev/nand/nand_generic.c deleted file mode 100644 index cc6ef9bd57b0..000000000000 --- a/sys/dev/nand/nand_generic.c +++ /dev/null @@ -1,1366 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Generic NAND driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/endian.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> -#include <sys/malloc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nfc_if.h" -#include "nand_if.h" -#include "nandbus_if.h" - - -static int onfi_nand_probe(device_t dev); -static int large_nand_probe(device_t dev); -static int small_nand_probe(device_t dev); -static int generic_nand_attach(device_t dev); -static int generic_nand_detach(device_t dev); - -static int generic_erase_block(device_t, uint32_t); -static int generic_erase_block_intlv(device_t, uint32_t); -static int generic_read_page (device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_program_page_intlv(device_t, uint32_t, void *, uint32_t, - uint32_t); -static int generic_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int generic_is_blk_bad(device_t, uint32_t, uint8_t *); -static int generic_get_ecc(device_t, void *, void *, int *); -static int generic_correct_ecc(device_t, void *, void *, void *); - -static int small_read_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_read_oob(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_program_page(device_t, uint32_t, void *, uint32_t, uint32_t); -static int small_program_oob(device_t, uint32_t, void *, uint32_t, uint32_t); - -static int onfi_is_blk_bad(device_t, uint32_t, uint8_t *); -static int onfi_read_parameter(struct nand_chip *, struct onfi_chip_params *); - -static int nand_send_address(device_t, int32_t, int32_t, int8_t); - -static device_method_t onand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, onfi_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, generic_read_page), - DEVMETHOD(nand_program_page, generic_program_page), - DEVMETHOD(nand_program_page_intlv, generic_program_page_intlv), - DEVMETHOD(nand_read_oob, generic_read_oob), - DEVMETHOD(nand_program_oob, generic_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - DEVMETHOD(nand_erase_block_intlv, generic_erase_block_intlv), - - DEVMETHOD(nand_is_blk_bad, onfi_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -static device_method_t lnand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, large_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, generic_read_page), - DEVMETHOD(nand_program_page, generic_program_page), - DEVMETHOD(nand_read_oob, generic_read_oob), - DEVMETHOD(nand_program_oob, generic_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - - DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -static device_method_t snand_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, small_nand_probe), - DEVMETHOD(device_attach, generic_nand_attach), - DEVMETHOD(device_detach, generic_nand_detach), - - DEVMETHOD(nand_read_page, small_read_page), - DEVMETHOD(nand_program_page, small_program_page), - DEVMETHOD(nand_read_oob, small_read_oob), - DEVMETHOD(nand_program_oob, small_program_oob), - DEVMETHOD(nand_erase_block, generic_erase_block), - - DEVMETHOD(nand_is_blk_bad, generic_is_blk_bad), - DEVMETHOD(nand_get_ecc, generic_get_ecc), - DEVMETHOD(nand_correct_ecc, generic_correct_ecc), - { 0, 0 } -}; - -devclass_t onand_devclass; -devclass_t lnand_devclass; -devclass_t snand_devclass; - -driver_t onand_driver = { - "onand", - onand_methods, - sizeof(struct nand_chip) -}; - -driver_t lnand_driver = { - "lnand", - lnand_methods, - sizeof(struct nand_chip) -}; - -driver_t snand_driver = { - "snand", - snand_methods, - sizeof(struct nand_chip) -}; - -DRIVER_MODULE(onand, nandbus, onand_driver, onand_devclass, 0, 0); -DRIVER_MODULE(lnand, nandbus, lnand_driver, lnand_devclass, 0, 0); -DRIVER_MODULE(snand, nandbus, snand_driver, snand_devclass, 0, 0); - -static int -onfi_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && ivar->is_onfi) { - device_set_desc(dev, "ONFI compliant NAND"); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -large_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && !ivar->is_onfi && ivar->params->page_size >= 512) { - device_set_desc(dev, ivar->params->name); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -small_nand_probe(device_t dev) -{ - struct nandbus_ivar *ivar; - - ivar = device_get_ivars(dev); - if (ivar && !ivar->is_onfi && ivar->params->page_size == 512) { - device_set_desc(dev, ivar->params->name); - return (BUS_PROBE_DEFAULT); - } - - return (ENODEV); -} - -static int -generic_nand_attach(device_t dev) -{ - struct nand_chip *chip; - struct nandbus_ivar *ivar; - struct onfi_chip_params *onfi_chip_params; - device_t nandbus, nfc; - int err; - - chip = device_get_softc(dev); - chip->dev = dev; - - ivar = device_get_ivars(dev); - chip->id.man_id = ivar->man_id; - chip->id.dev_id = ivar->dev_id; - chip->num = ivar->cs; - - /* TODO remove when HW ECC supported */ - nandbus = device_get_parent(dev); - nfc = device_get_parent(nandbus); - - chip->nand = device_get_softc(nfc); - - if (ivar->is_onfi) { - onfi_chip_params = malloc(sizeof(struct onfi_chip_params), - M_NAND, M_WAITOK | M_ZERO); - - if (onfi_read_parameter(chip, onfi_chip_params)) { - nand_debug(NDBG_GEN,"Could not read parameter page!\n"); - free(onfi_chip_params, M_NAND); - return (ENXIO); - } - - nand_onfi_set_params(chip, onfi_chip_params); - /* Set proper column and row cycles */ - ivar->cols = (onfi_chip_params->address_cycles >> 4) & 0xf; - ivar->rows = onfi_chip_params->address_cycles & 0xf; - free(onfi_chip_params, M_NAND); - - } else { - nand_set_params(chip, ivar->params); - } - - err = nand_init_stat(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = nand_init_bbt(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = nand_make_dev(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - err = create_geom_disk(chip); - if (err) { - generic_nand_detach(dev); - return (err); - } - - return (0); -} - -static int -generic_nand_detach(device_t dev) -{ - struct nand_chip *chip; - - chip = device_get_softc(dev); - - nand_destroy_bbt(chip); - destroy_geom_disk(chip); - nand_destroy_dev(chip); - nand_destroy_stat(chip); - - return (0); -} - -static int -can_write(device_t nandbus) -{ - uint8_t status; - - if (NANDBUS_WAIT_READY(nandbus, &status)) - return (0); - - if (!(status & NAND_STATUS_WP)) { - nand_debug(NDBG_GEN,"Chip is write-protected"); - return (0); - } - - return (1); -} - -static int -check_fail(device_t nandbus) -{ - uint8_t status; - - NANDBUS_WAIT_READY(nandbus, &status); - if (status & NAND_STATUS_FAIL) { - nand_debug(NDBG_GEN,"Status failed %x", status); - return (ENXIO); - } - - return (0); -} - -static uint16_t -onfi_crc(const void *buf, size_t buflen) -{ - int i, j; - uint16_t crc; - const uint8_t *bufptr; - - bufptr = buf; - crc = 0x4f4e; - for (j = 0; j < buflen; j++) { - crc ^= *bufptr++ << 8; - for (i = 0; i < 8; i++) - if (crc & 0x8000) - crc = (crc << 1) ^ 0x8005; - else - crc <<= 1; - } - return crc; -} - -static int -onfi_read_parameter(struct nand_chip *chip, struct onfi_chip_params *chip_params) -{ - device_t nandbus; - struct onfi_params params; - int found, sigcount, trycopy; - - nand_debug(NDBG_GEN,"read parameter"); - - nandbus = device_get_parent(chip->dev); - - NANDBUS_SELECT_CS(nandbus, chip->num); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ_PARAMETER)) - return (ENXIO); - - if (nand_send_address(chip->dev, -1, -1, PAGE_PARAMETER_DEF)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - /* - * XXX Bogus DELAY, we really need a nandbus_wait_ready() here, but it's - * not accessible from here (static to nandbus). - */ - DELAY(1000); - - /* - * The ONFI spec mandates a minimum of three copies of the parameter - * data, so loop up to 3 times trying to find good data. Each copy is - * validated by a signature of "ONFI" and a crc. There is a very strange - * rule that the signature is valid if any 2 of the 4 bytes are correct. - */ - for (found= 0, trycopy = 0; !found && trycopy < 3; trycopy++) { - NANDBUS_READ_BUFFER(nandbus, ¶ms, sizeof(struct onfi_params)); - sigcount = params.signature[0] == 'O'; - sigcount += params.signature[1] == 'N'; - sigcount += params.signature[2] == 'F'; - sigcount += params.signature[3] == 'I'; - if (sigcount < 2) - continue; - if (onfi_crc(¶ms, 254) != params.crc) - continue; - found = 1; - } - if (!found) - return (ENXIO); - - chip_params->luns = params.luns; - chip_params->blocks_per_lun = le32dec(¶ms.blocks_per_lun); - chip_params->pages_per_block = le32dec(¶ms.pages_per_block); - chip_params->bytes_per_page = le32dec(¶ms.bytes_per_page); - chip_params->spare_bytes_per_page = le16dec(¶ms.spare_bytes_per_page); - chip_params->t_bers = le16dec(¶ms.t_bers); - chip_params->t_prog = le16dec(¶ms.t_prog); - chip_params->t_r = le16dec(¶ms.t_r); - chip_params->t_ccs = le16dec(¶ms.t_ccs); - chip_params->features = le16dec(¶ms.features); - chip_params->address_cycles = params.address_cycles; - - return (0); -} - -static int -send_read_page(device_t nand, uint8_t start_command, uint8_t end_command, - uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, start_command)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, end_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw read page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, - offset)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -generic_read_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw read oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) { - nand_debug(NDBG_GEN,"page boundary check failed: %08x\n", page); - return (ENXIO); - } - - page_to_row(&chip->chip_geom, page, &row); - - offset += chip->chip_geom.page_size; - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_END, row, - offset)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -send_start_program_page(device_t nand, uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_PROG)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - return (0); -} - -static int -send_end_program_page(device_t nandbus, uint8_t end_command) -{ - - if (NANDBUS_SEND_COMMAND(nandbus, end_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_program_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, - offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -static int -generic_program_page_intlv(device_t nand, uint32_t page, void *buf, - uint32_t len, uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -static int -generic_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p raw prog oob %x[%x] at %x", nand, page, len, - offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - offset += chip->chip_geom.page_size; - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -send_erase_block(device_t nand, uint32_t row, uint8_t second_command) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_ERASE)) - return (ENXIO); - - if (nand_send_address(nand, row, -1, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, second_command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -static int -generic_erase_block(device_t nand, uint32_t block) -{ - struct block_stat *blk_stat; - struct nand_chip *chip; - device_t nandbus; - int row; - - nand_debug(NDBG_GEN,"%p erase block %x", nand, block); - nandbus = device_get_parent(nand); - chip = device_get_softc(nand); - - if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) - return (ENXIO); - - row = (block << chip->chip_geom.blk_shift) & - chip->chip_geom.blk_mask; - - nand_debug(NDBG_GEN,"%p erase block row %x", nand, row); - - if (!can_write(nandbus)) - return (ENXIO); - - send_erase_block(nand, row, NAND_CMD_ERASE_END); - - DELAY(chip->t_bers); - - if (check_fail(nandbus)) - return (ENXIO); - - blk_stat = &(chip->blk_stat[block]); - blk_stat->block_erased++; - - return (0); -} - -static int -generic_erase_block_intlv(device_t nand, uint32_t block) -{ - struct block_stat *blk_stat; - struct nand_chip *chip; - device_t nandbus; - int row; - - nand_debug(NDBG_GEN,"%p erase block %x", nand, block); - nandbus = device_get_parent(nand); - chip = device_get_softc(nand); - - if (block >= (chip->chip_geom.blks_per_lun * chip->chip_geom.luns)) - return (ENXIO); - - row = (block << chip->chip_geom.blk_shift) & - chip->chip_geom.blk_mask; - - if (!can_write(nandbus)) - return (ENXIO); - - send_erase_block(nand, row, NAND_CMD_ERASE_INTLV); - - DELAY(chip->t_bers); - - if (check_fail(nandbus)) - return (ENXIO); - - blk_stat = &(chip->blk_stat[block]); - blk_stat->block_erased++; - - return (0); - -} - -static int -onfi_is_blk_bad(device_t device, uint32_t block_number, uint8_t *bad) -{ - struct nand_chip *chip; - int page_number, i, j, err; - uint8_t *oob; - - chip = device_get_softc(device); - - oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); - - page_number = block_number * chip->chip_geom.pgs_per_blk; - *bad = 0; - /* Check OOB of first and last page */ - for (i = 0; i < 2; i++, page_number+= chip->chip_geom.pgs_per_blk - 1) { - err = generic_read_oob(device, page_number, oob, - chip->chip_geom.oob_size, 0); - if (err) { - device_printf(device, "%s: cannot allocate oob\n", - __func__); - free(oob, M_NAND); - return (ENOMEM); - } - - for (j = 0; j < chip->chip_geom.oob_size; j++) { - if (!oob[j]) { - *bad = 1; - free(oob, M_NAND); - return (0); - } - } - } - - free(oob, M_NAND); - - return (0); -} - -static int -send_small_read_page(device_t nand, uint8_t start_command, - uint32_t row, uint32_t column) -{ - device_t nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, start_command)) - return (ENXIO); - - if (nand_send_address(nand, row, column, -1)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - - -static int -small_read_page(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small read page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (offset < 256) { - if (send_small_read_page(nand, NAND_CMD_SMALLA, row, offset)) - return (ENXIO); - } else { - offset -= 256; - if (send_small_read_page(nandbus, NAND_CMD_SMALLB, row, offset)) - return (ENXIO); - } - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -small_read_oob(device_t nand, uint32_t page, void *buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small read oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_small_read_page(nand, NAND_CMD_SMALLOOB, row, 0)) - return (ENXIO); - - DELAY(chip->t_r); - - NANDBUS_READ_BUFFER(nandbus, buf, len); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -static int -small_program_page(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small prog page %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (offset < 256) { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLA)) - return (ENXIO); - } else { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLB)) - return (ENXIO); - } - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -static int -small_program_oob(device_t nand, uint32_t page, void* buf, uint32_t len, - uint32_t offset) -{ - struct nand_chip *chip; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"%p small prog oob %x[%x] at %x", nand, page, len, offset); - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SMALLOOB)) - return (ENXIO); - - if (send_start_program_page(nand, row, offset)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - return (0); -} - -int -nand_send_address(device_t nand, int32_t row, int32_t col, int8_t id) -{ - struct nandbus_ivar *ivar; - device_t nandbus; - uint8_t addr; - int err = 0; - int i; - - nandbus = device_get_parent(nand); - ivar = device_get_ivars(nand); - - if (id != -1) { - nand_debug(NDBG_GEN,"send_address: send id %02x", id); - err = NANDBUS_SEND_ADDRESS(nandbus, id); - } - - if (!err && col != -1) { - for (i = 0; i < ivar->cols; i++, col >>= 8) { - addr = (uint8_t)(col & 0xff); - nand_debug(NDBG_GEN,"send_address: send address column " - "%02x", addr); - err = NANDBUS_SEND_ADDRESS(nandbus, addr); - if (err) - break; - } - } - - if (!err && row != -1) { - for (i = 0; i < ivar->rows; i++, row >>= 8) { - addr = (uint8_t)(row & 0xff); - nand_debug(NDBG_GEN,"send_address: send address row " - "%02x", addr); - err = NANDBUS_SEND_ADDRESS(nandbus, addr); - if (err) - break; - } - } - - return (err); -} - -static int -generic_is_blk_bad(device_t dev, uint32_t block, uint8_t *bad) -{ - struct nand_chip *chip; - int page_number, err, i; - uint8_t *oob; - - chip = device_get_softc(dev); - - oob = malloc(chip->chip_geom.oob_size, M_NAND, M_WAITOK); - - page_number = block * chip->chip_geom.pgs_per_blk; - *bad = 0; - - /* Check OOB of first and second page */ - for (i = 0; i < 2; i++) { - err = NAND_READ_OOB(dev, page_number + i, oob, - chip->chip_geom.oob_size, 0); - if (err) { - device_printf(dev, "%s: cannot allocate OOB\n", - __func__); - free(oob, M_NAND); - return (ENOMEM); - } - - if (!oob[0]) { - *bad = 1; - free(oob, M_NAND); - return (0); - } - } - - free(oob, M_NAND); - - return (0); -} - -static int -generic_get_ecc(device_t dev, void *buf, void *ecc, int *needwrite) -{ - struct nand_chip *chip = device_get_softc(dev); - struct chip_geom *cg = &chip->chip_geom; - - return (NANDBUS_GET_ECC(device_get_parent(dev), buf, cg->page_size, - ecc, needwrite)); -} - -static int -generic_correct_ecc(device_t dev, void *buf, void *readecc, void *calcecc) -{ - struct nand_chip *chip = device_get_softc(dev); - struct chip_geom *cg = &chip->chip_geom; - - return (NANDBUS_CORRECT_ECC(device_get_parent(dev), buf, - cg->page_size, readecc, calcecc)); -} - - -#if 0 -int -nand_chng_read_col(device_t nand, uint32_t col, void *buf, size_t len) -{ - struct nand_chip *chip; - device_t nandbus; - - chip = device_get_softc(nand); - nandbus = device_get_parent(nand); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - return (0); -} - -int -nand_chng_write_col(device_t dev, uint32_t col, void *buf, - size_t len) -{ - struct nand_chip *chip; - device_t nandbus; - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, col, -1)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_READ_COL_END)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} - -int -nand_copyback_read(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN," raw read page %x[%x] at %x", page, col, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (send_read_page(nand, NAND_CMD_READ, NAND_CMD_READ_CPBK, row, 0)) - return (ENXIO); - - DELAY(chip->t_r); - if (check_fail(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -int -nand_copyback_prog(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"copyback prog page %x[%x]", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_CHNG_WRITE_COL)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_END)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_copyback_prog_intlv(device_t dev, uint32_t page) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - - nand_debug(NDBG_GEN,"cache prog page %x", page); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(nand, row, 0)) - return (ENXIO); - - if (send_end_program_page(nandbus, NAND_CMD_PROG_INTLV)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_prog_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - uint8_t command; - - nand_debug(NDBG_GEN,"cache prog page %x[%x]", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (!can_write(nandbus)) - return (ENXIO); - - if (send_start_program_page(dev, row, 0)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, len); - - if (end) - command = NAND_CMD_PROG_END; - else - command = NAND_CMD_PROG_CACHE; - - if (send_end_program_page(nandbus, command)) - return (ENXIO); - - DELAY(chip->t_prog); - - if (check_fail(nandbus)) - return (ENXIO); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_written++; - - return (0); -} - -int -nand_read_cache(device_t dev, uint32_t page, uint32_t col, - void *buf, size_t len, uint8_t end) -{ - struct nand_chip *chip; - struct page_stat *pg_stat; - device_t nandbus; - uint32_t row; - uint8_t command; - - nand_debug(NDBG_GEN,"cache read page %x[%x] ", page, len); - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (nand_check_page_boundary(chip, page)) - return (ENXIO); - - page_to_row(&chip->chip_geom, page, &row); - - if (page != -1) { - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_READ)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, row, col, -1)) - return (ENXIO); - } - - if (end) - command = NAND_CMD_READ_CACHE_END; - else - command = NAND_CMD_READ_CACHE; - - if (NANDBUS_SEND_COMMAND(nandbus, command)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - DELAY(chip->t_r); - if (check_fail(nandbus)) - return (ENXIO); - - if (buf != NULL && len > 0) - NANDBUS_READ_BUFFER(nandbus, buf, len); - - pg_stat = &(chip->pg_stat[page]); - pg_stat->page_raw_read++; - - return (0); -} - -int -nand_get_feature(device_t dev, uint8_t feat, void *buf) -{ - struct nand_chip *chip; - device_t nandbus; - - nand_debug(NDBG_GEN,"nand get feature"); - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_GET_FEATURE)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) - return (ENXIO); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - DELAY(chip->t_r); - NANDBUS_READ_BUFFER(nandbus, buf, 4); - - return (0); -} - -int -nand_set_feature(device_t dev, uint8_t feat, void *buf) -{ - struct nand_chip *chip; - device_t nandbus; - - nand_debug(NDBG_GEN,"nand set feature"); - - chip = device_get_softc(dev); - nandbus = device_get_parent(dev); - - if (NANDBUS_SEND_COMMAND(nandbus, NAND_CMD_SET_FEATURE)) - return (ENXIO); - - if (NANDBUS_SEND_ADDRESS(nandbus, -1, -1, feat)) - return (ENXIO); - - NANDBUS_WRITE_BUFFER(nandbus, buf, 4); - - if (NANDBUS_START_COMMAND(nandbus)) - return (ENXIO); - - return (0); -} -#endif diff --git a/sys/dev/nand/nand_geom.c b/sys/dev/nand/nand_geom.c deleted file mode 100644 index b814ffc4e0a9..000000000000 --- a/sys/dev/nand/nand_geom.c +++ /dev/null @@ -1,467 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/uio.h> -#include <sys/bio.h> -#include <geom/geom.h> -#include <geom/geom_disk.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nand_dev.h> -#include "nand_if.h" -#include "nandbus_if.h" - -#define BIO_NAND_STD ((void *)1) -#define BIO_NAND_RAW ((void *)2) - -static disk_ioctl_t nand_ioctl; -static disk_getattr_t nand_getattr; -static disk_strategy_t nand_strategy; -static disk_strategy_t nand_strategy_raw; - -static int -nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Read from chip %d [%p] at %d", chip->num, chip, - offset); - - return (nand_read_pages(chip, offset, buf, len)); -} - -static int -nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Write to chip %d [%p] at %d", chip->num, chip, - offset); - - return (nand_prog_pages(chip, offset, buf, len)); -} - -static int -nand_read_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - nand_debug(NDBG_GEOM, "Raw read from chip %d [%p] at %d", chip->num, - chip, offset); - - return (nand_read_pages_raw(chip, offset, buf, len)); -} - -static int -nand_write_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) -{ - - nand_debug(NDBG_GEOM, "Raw write to chip %d [%p] at %d", chip->num, - chip, offset); - - return (nand_prog_pages_raw(chip, offset, buf, len)); -} - -static void -nand_strategy(struct bio *bp) -{ - struct nand_chip *chip; - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - - bp->bio_driver1 = BIO_NAND_STD; - - nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", - bp->bio_cmd == BIO_READ ? "READ" : - (bp->bio_cmd == BIO_WRITE ? "WRITE" : - (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), - chip->num, chip); - - mtx_lock(&chip->qlock); - bioq_insert_tail(&chip->bioq, bp); - mtx_unlock(&chip->qlock); - taskqueue_enqueue(chip->tq, &chip->iotask); -} - -static void -nand_strategy_raw(struct bio *bp) -{ - struct nand_chip *chip; - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - - /* Inform taskqueue that it's a raw access */ - bp->bio_driver1 = BIO_NAND_RAW; - - nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", - bp->bio_cmd == BIO_READ ? "READ" : - (bp->bio_cmd == BIO_WRITE ? "WRITE" : - (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), - chip->num, chip); - - mtx_lock(&chip->qlock); - bioq_insert_tail(&chip->bioq, bp); - mtx_unlock(&chip->qlock); - taskqueue_enqueue(chip->tq, &chip->iotask); -} - -static int -nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, - uint32_t len, uint8_t *data, uint8_t write) -{ - struct chip_geom *cg; - int ret = 0; - - cg = &chip->chip_geom; - - if (!write) - ret = nand_read_oob(chip, page, data, cg->oob_size); - else - ret = nand_prog_oob(chip, page, data, cg->oob_size); - - return (ret); -} - -static int -nand_getattr(struct bio *bp) -{ - struct nand_chip *chip; - struct chip_geom *cg; - device_t dev; - int val; - - if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) - return (ENXIO); - - chip = (struct nand_chip *)bp->bio_disk->d_drv1; - cg = &(chip->chip_geom); - - dev = device_get_parent(chip->dev); - dev = device_get_parent(dev); - - if (strcmp(bp->bio_attribute, "NAND::device") == 0) { - if (bp->bio_length != sizeof(dev)) - return (EFAULT); - bcopy(&dev, bp->bio_data, sizeof(dev)); - } else { - if (strcmp(bp->bio_attribute, "NAND::oobsize") == 0) - val = cg->oob_size; - else if (strcmp(bp->bio_attribute, "NAND::pagesize") == 0) - val = cg->page_size; - else if (strcmp(bp->bio_attribute, "NAND::blocksize") == 0) - val = cg->block_size; - else - return (-1); - if (bp->bio_length != sizeof(val)) - return (EFAULT); - bcopy(&val, bp->bio_data, sizeof(val)); - } - bp->bio_completed = bp->bio_length; - return (0); -} - -static int -nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag, - struct thread *td) -{ - struct nand_chip *chip; - struct chip_geom *cg; - struct nand_oob_rw *oob_rw = NULL; - struct nand_raw_rw *raw_rw = NULL; - device_t nandbus; - size_t bufsize = 0, len = 0; - size_t raw_size; - off_t off; - uint8_t *buf = NULL; - int ret = 0; - uint8_t status; - - chip = (struct nand_chip *)ndisk->d_drv1; - cg = &chip->chip_geom; - nandbus = device_get_parent(chip->dev); - - if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { - raw_rw = (struct nand_raw_rw *)data; - raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); - - /* Check if len is not bigger than chip size */ - if (raw_rw->len > raw_size) - return (EFBIG); - - /* - * Do not ask for too much memory, in case of large transfers - * read/write in 16-pages chunks - */ - bufsize = 16 * (cg->page_size + cg->oob_size); - if (raw_rw->len < bufsize) - bufsize = raw_rw->len; - - buf = malloc(bufsize, M_NAND, M_WAITOK); - len = raw_rw->len; - off = 0; - } - - switch (cmd) { - case NAND_IO_ERASE: - ret = nand_erase_blocks(chip, ((off_t *)data)[0], - ((off_t *)data)[1]); - break; - - case NAND_IO_OOB_READ: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 0); - break; - - case NAND_IO_OOB_PROG: - oob_rw = (struct nand_oob_rw *)data; - ret = nand_oob_access(chip, oob_rw->page, 0, - oob_rw->len, oob_rw->data, 1); - break; - - case NAND_IO_GET_STATUS: - NANDBUS_LOCK(nandbus); - ret = NANDBUS_GET_STATUS(nandbus, &status); - if (ret == 0) - *(uint8_t *)data = status; - NANDBUS_UNLOCK(nandbus); - break; - - case NAND_IO_RAW_PROG: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = copyin(raw_rw->data + off, buf, bufsize); - if (ret) - break; - ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_RAW_READ: - while (len > 0) { - if (len < bufsize) - bufsize = len; - - ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, - bufsize); - if (ret) - break; - - ret = copyout(buf, raw_rw->data + off, bufsize); - if (ret) - break; - len -= bufsize; - off += bufsize; - } - break; - - case NAND_IO_GET_CHIP_PARAM: - nand_get_chip_param(chip, (struct chip_param_io *)data); - break; - - default: - printf("Unknown nand_ioctl request \n"); - ret = EIO; - } - - if (buf) - free(buf, M_NAND); - - return (ret); -} - -static void -nand_io_proc(void *arg, int pending) -{ - struct nand_chip *chip = arg; - struct bio *bp; - int err = 0; - - for (;;) { - mtx_lock(&chip->qlock); - bp = bioq_takefirst(&chip->bioq); - mtx_unlock(&chip->qlock); - if (bp == NULL) - break; - - if (bp->bio_driver1 == BIO_NAND_STD) { - if (bp->bio_cmd == BIO_READ) { - err = nand_read(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else if (bp->bio_cmd == BIO_WRITE) { - err = nand_write(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - } else if (bp->bio_driver1 == BIO_NAND_RAW) { - if (bp->bio_cmd == BIO_READ) { - err = nand_read_raw(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } else if (bp->bio_cmd == BIO_WRITE) { - err = nand_write_raw(chip, - bp->bio_offset & 0xffffffff, - bp->bio_data, bp->bio_bcount); - } - } else - panic("Unknown access type in bio->bio_driver1\n"); - - if (bp->bio_cmd == BIO_DELETE) { - nand_debug(NDBG_GEOM, "Delete on chip%d offset %lld " - "length %ld\n", chip->num, bp->bio_offset, - bp->bio_bcount); - err = nand_erase_blocks(chip, - bp->bio_offset & 0xffffffff, - bp->bio_bcount); - } - - if (err == 0 || err == ECC_CORRECTABLE) - bp->bio_resid = 0; - else { - nand_debug(NDBG_GEOM,"nand_[read|write|erase_blocks] " - "error: %d\n", err); - - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - } - biodone(bp); - } -} - -int -create_geom_disk(struct nand_chip *chip) -{ - struct disk *ndisk, *rdisk; - - /* Create the disk device */ - ndisk = disk_alloc(); - ndisk->d_strategy = nand_strategy; - ndisk->d_ioctl = nand_ioctl; - ndisk->d_getattr = nand_getattr; - ndisk->d_name = "gnand"; - ndisk->d_drv1 = chip; - ndisk->d_maxsize = chip->chip_geom.block_size; - ndisk->d_sectorsize = chip->chip_geom.page_size; - ndisk->d_mediasize = chip->chip_geom.chip_size; - ndisk->d_unit = chip->num + - 10 * device_get_unit(device_get_parent(chip->dev)); - - /* - * When using BBT, make two last blocks of device unavailable - * to user (because those are used to store BBT table). - */ - if (chip->bbt != NULL) - ndisk->d_mediasize -= (2 * chip->chip_geom.block_size); - - ndisk->d_flags = DISKFLAG_CANDELETE; - - snprintf(ndisk->d_ident, sizeof(ndisk->d_ident), - "nand: Man:0x%02x Dev:0x%02x", chip->id.man_id, chip->id.dev_id); - ndisk->d_rotation_rate = DISK_RR_NON_ROTATING; - - disk_create(ndisk, DISK_VERSION); - - /* Create the RAW disk device */ - rdisk = disk_alloc(); - rdisk->d_strategy = nand_strategy_raw; - rdisk->d_ioctl = nand_ioctl; - rdisk->d_getattr = nand_getattr; - rdisk->d_name = "gnand.raw"; - rdisk->d_drv1 = chip; - rdisk->d_maxsize = chip->chip_geom.block_size; - rdisk->d_sectorsize = chip->chip_geom.page_size; - rdisk->d_mediasize = chip->chip_geom.chip_size; - rdisk->d_unit = chip->num + - 10 * device_get_unit(device_get_parent(chip->dev)); - - rdisk->d_flags = DISKFLAG_CANDELETE; - - snprintf(rdisk->d_ident, sizeof(rdisk->d_ident), - "nand_raw: Man:0x%02x Dev:0x%02x", chip->id.man_id, - chip->id.dev_id); - rdisk->d_rotation_rate = DISK_RR_NON_ROTATING; - - disk_create(rdisk, DISK_VERSION); - - chip->ndisk = ndisk; - chip->rdisk = rdisk; - - mtx_init(&chip->qlock, "NAND I/O lock", NULL, MTX_DEF); - bioq_init(&chip->bioq); - - TASK_INIT(&chip->iotask, 0, nand_io_proc, chip); - chip->tq = taskqueue_create("nand_taskq", M_WAITOK, - taskqueue_thread_enqueue, &chip->tq); - taskqueue_start_threads(&chip->tq, 1, PI_DISK, "nand taskq"); - - if (bootverbose) - device_printf(chip->dev, "Created gnand%d for chip [0x%0x, " - "0x%0x]\n", ndisk->d_unit, chip->id.man_id, - chip->id.dev_id); - - return (0); -} - -void -destroy_geom_disk(struct nand_chip *chip) -{ - struct bio *bp; - - taskqueue_free(chip->tq); - disk_destroy(chip->ndisk); - disk_destroy(chip->rdisk); - - mtx_lock(&chip->qlock); - for (;;) { - bp = bioq_takefirst(&chip->bioq); - if (bp == NULL) - break; - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - bp->bio_resid = bp->bio_bcount; - - biodone(bp); - } - mtx_unlock(&chip->qlock); - - mtx_destroy(&chip->qlock); -} diff --git a/sys/dev/nand/nand_id.c b/sys/dev/nand/nand_id.c deleted file mode 100644 index 7259c951bfc9..000000000000 --- a/sys/dev/nand/nand_id.c +++ /dev/null @@ -1,70 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> - -#include <dev/nand/nand.h> - -struct nand_params nand_ids[] = { - { { NAND_MAN_SAMSUNG, 0x75 }, "Samsung K9F5608U0B NAND 32MiB 8-bit", - 0x20, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_SAMSUNG, 0xf1 }, "Samsung K9F1G08U0A NAND 128MiB 3,3V 8-bit", - 0x80, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xda }, "Samsung K9F2G08U0A NAND 256MiB 3,3V 8-bit", - 0x100, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xdc }, "Samsung NAND 512MiB 3,3V 8-bit", - 0x200, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_SAMSUNG, 0xd3 }, "Samsung NAND 1GiB 3,3V 8-bit", - 0x400, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_HYNIX, 0x76 }, "Hynix NAND 64MiB 3,3V 8-bit", - 0x40, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_HYNIX, 0xdc }, "Hynix NAND 512MiB 3,3V 8-bit", - 0x200, 0x800, 0x40, 0x40, 0 }, - { { NAND_MAN_HYNIX, 0x79 }, "Hynix NAND 128MB 3,3V 8-bit", - 0x80, 0x200, 0x10, 0x20, 0 }, - { { NAND_MAN_STMICRO, 0xf1 }, "STMicro 128MB 3,3V 8-bit", - 0x80, 2048, 64, 0x40, 0 }, - { { NAND_MAN_MICRON, 0xcc }, "Micron NAND 512MiB 3,3V 16-bit", - 0x200, 2048, 64, 0x40, 0 }, -}; - -struct nand_params *nand_get_params(struct nand_id *id) -{ - int i; - - for (i = 0; i < nitems(nand_ids); i++) - if (nand_ids[i].id.man_id == id->man_id && - nand_ids[i].id.dev_id == id->dev_id) - return (&nand_ids[i]); - - return (NULL); -} diff --git a/sys/dev/nand/nand_if.m b/sys/dev/nand/nand_if.m deleted file mode 100644 index 49c8879b6890..000000000000 --- a/sys/dev/nand/nand_if.m +++ /dev/null @@ -1,168 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $FreeBSD$ - -# NAND chip interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nand; - -CODE { - static int nand_method_not_supported(device_t dev) - { - return (ENOENT); - } -}; - -# Read NAND page -# -# Return values: -# 0: Success -# -METHOD int read_page { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND page -# -# Return values: -# 0: Success -# -METHOD int program_page { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND page interleaved -# -# Return values: -# 0: Success -# -METHOD int program_page_intlv { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -} DEFAULT nand_method_not_supported; - -# Read NAND oob -# -# Return values: -# 0: Success -# -METHOD int read_oob { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Program NAND oob -# -# Return values: -# 0: Success -# -METHOD int program_oob { - device_t dev; - uint32_t page; - void* buf; - uint32_t len; - uint32_t offset; -}; - -# Erase NAND block -# -# Return values: -# 0: Success -# -METHOD int erase_block { - device_t dev; - uint32_t block; -}; - -# Erase NAND block interleaved -# -# Return values: -# 0: Success -# -METHOD int erase_block_intlv { - device_t dev; - uint32_t block; -} DEFAULT nand_method_not_supported; - -# NAND get status -# -# Return values: -# 0: Success -# -METHOD int get_status { - device_t dev; - uint8_t *status; -}; - -# NAND check if block is bad -# -# Return values: -# 0: Success -# -METHOD int is_blk_bad { - device_t dev; - uint32_t block_number; - uint8_t *bad; -}; - -# NAND get ECC -# -# -METHOD int get_ecc { - device_t dev; - void *buf; - void *ecc; - int *needwrite; -}; - -# NAND correct ECC -# -# -METHOD int correct_ecc { - device_t dev; - void *buf; - void *readecc; - void *calcecc; -}; - diff --git a/sys/dev/nand/nandbus.c b/sys/dev/nand/nandbus.c deleted file mode 100644 index 003c1797af64..000000000000 --- a/sys/dev/nand/nandbus.c +++ /dev/null @@ -1,542 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/proc.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/condvar.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nand_if.h" -#include "nandbus_if.h" -#include "nfc_if.h" - -#define NAND_NCS 4 - -static int nandbus_probe(device_t dev); -static int nandbus_attach(device_t dev); -static int nandbus_detach(device_t dev); - -static int nandbus_child_location_str(device_t, device_t, char *, size_t); -static int nandbus_child_pnpinfo_str(device_t, device_t, char *, size_t); - -static int nandbus_get_status(device_t, uint8_t *); -static void nandbus_read_buffer(device_t, void *, uint32_t); -static int nandbus_select_cs(device_t, uint8_t); -static int nandbus_send_command(device_t, uint8_t); -static int nandbus_send_address(device_t, uint8_t); -static int nandbus_start_command(device_t); -static int nandbus_wait_ready(device_t, uint8_t *); -static void nandbus_write_buffer(device_t, void *, uint32_t); -static int nandbus_get_ecc(device_t, void *, uint32_t, void *, int *); -static int nandbus_correct_ecc(device_t, void *, int, void *, void *); -static void nandbus_lock(device_t); -static void nandbus_unlock(device_t); - -static int nand_readid(device_t, uint8_t *, uint8_t *); -static int nand_probe_onfi(device_t, uint8_t *); -static int nand_reset(device_t); - -struct nandbus_softc { - device_t dev; - struct cv nandbus_cv; - struct mtx nandbus_mtx; - uint8_t busy; -}; - -static device_method_t nandbus_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, nandbus_probe), - DEVMETHOD(device_attach, nandbus_attach), - DEVMETHOD(device_detach, nandbus_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), - DEVMETHOD(bus_child_pnpinfo_str, nandbus_child_pnpinfo_str), - DEVMETHOD(bus_child_location_str, nandbus_child_location_str), - - /* nandbus interface */ - DEVMETHOD(nandbus_get_status, nandbus_get_status), - DEVMETHOD(nandbus_read_buffer, nandbus_read_buffer), - DEVMETHOD(nandbus_select_cs, nandbus_select_cs), - DEVMETHOD(nandbus_send_command, nandbus_send_command), - DEVMETHOD(nandbus_send_address, nandbus_send_address), - DEVMETHOD(nandbus_start_command,nandbus_start_command), - DEVMETHOD(nandbus_wait_ready, nandbus_wait_ready), - DEVMETHOD(nandbus_write_buffer, nandbus_write_buffer), - DEVMETHOD(nandbus_get_ecc, nandbus_get_ecc), - DEVMETHOD(nandbus_correct_ecc, nandbus_correct_ecc), - DEVMETHOD(nandbus_lock, nandbus_lock), - DEVMETHOD(nandbus_unlock, nandbus_unlock), - { 0, 0 } -}; - -devclass_t nandbus_devclass; - -driver_t nandbus_driver = { - "nandbus", - nandbus_methods, - sizeof(struct nandbus_softc) -}; - -DRIVER_MODULE(nandbus, nand, nandbus_driver, nandbus_devclass, 0, 0); - -int -nandbus_create(device_t nfc) -{ - device_t child; - - child = device_add_child(nfc, "nandbus", -1); - if (!child) - return (ENODEV); - - bus_generic_attach(nfc); - - return(0); -} - -void -nandbus_destroy(device_t nfc) -{ - device_t *children; - int nchildren, i; - - mtx_lock(&Giant); - /* Detach & delete all children */ - if (!device_get_children(nfc, &children, &nchildren)) { - for (i = 0; i < nchildren; i++) - device_delete_child(nfc, children[i]); - - free(children, M_TEMP); - } - mtx_unlock(&Giant); -} - -static int -nandbus_probe(device_t dev) -{ - - device_set_desc(dev, "NAND bus"); - - return (0); -} - -static int -nandbus_attach(device_t dev) -{ - device_t child, nfc; - struct nand_id chip_id; - struct nandbus_softc *sc; - struct nandbus_ivar *ivar; - struct nand_softc *nfc_sc; - struct nand_params *chip_params; - uint8_t cs, onfi; - - sc = device_get_softc(dev); - sc->dev = dev; - - nfc = device_get_parent(dev); - nfc_sc = device_get_softc(nfc); - - mtx_init(&sc->nandbus_mtx, "nandbus lock", NULL, MTX_DEF); - cv_init(&sc->nandbus_cv, "nandbus cv"); - - /* Check each possible CS for existing nand devices */ - for (cs = 0; cs < NAND_NCS; cs++) { - nand_debug(NDBG_BUS,"probe chip select %x", cs); - - /* Select & reset chip */ - if (nandbus_select_cs(dev, cs)) - break; - - if (nand_reset(dev)) - continue; - - /* Read manufacturer and device id */ - if (nand_readid(dev, &chip_id.man_id, &chip_id.dev_id)) - continue; - - if (chip_id.man_id == 0xff) - continue; - - /* - * First try to get info from the table. If that fails, see if - * the chip can provide ONFI info. We check the table first to - * allow table entries to override info from chips that are - * known to provide bad ONFI data. - */ - onfi = 0; - chip_params = nand_get_params(&chip_id); - if (chip_params == NULL) { - nand_probe_onfi(dev, &onfi); - } - - /* - * At this point it appears there is a chip at this chipselect, - * so if we can't work with it, whine about it. - */ - if (chip_params == NULL && onfi == 0) { - if (bootverbose || (nand_debug_flag & NDBG_BUS)) - printf("Chip params not found, chipsel: %d " - "(manuf: 0x%0x, chipid: 0x%0x, onfi: %d)\n", - cs, chip_id.man_id, chip_id.dev_id, onfi); - continue; - } - - ivar = malloc(sizeof(struct nandbus_ivar), - M_NAND, M_WAITOK); - - if (onfi == 1) { - ivar->cs = cs; - ivar->cols = 0; - ivar->rows = 0; - ivar->params = NULL; - ivar->man_id = chip_id.man_id; - ivar->dev_id = chip_id.dev_id; - ivar->is_onfi = onfi; - ivar->chip_cdev_name = nfc_sc->chip_cdev_name; - - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, ivar); - continue; - } - - ivar->cs = cs; - ivar->cols = 1; - ivar->rows = 2; - ivar->params = chip_params; - ivar->man_id = chip_id.man_id; - ivar->dev_id = chip_id.dev_id; - ivar->is_onfi = onfi; - ivar->chip_cdev_name = nfc_sc->chip_cdev_name; - - /* - * Check what type of device we have. - * devices bigger than 32MiB have on more row (3) - */ - if (chip_params->chip_size > 32) - ivar->rows++; - /* Large page devices have one more col (2) */ - if (chip_params->chip_size >= 128 && - chip_params->page_size > 512) - ivar->cols++; - - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, ivar); - } - - bus_generic_attach(dev); - return (0); -} - -static int -nandbus_detach(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - bus_generic_detach(dev); - - mtx_destroy(&sc->nandbus_mtx); - cv_destroy(&sc->nandbus_cv); - - return (0); -} - -static int -nandbus_child_location_str(device_t bus, device_t child, char *buf, - size_t buflen) -{ - struct nandbus_ivar *ivar = device_get_ivars(child); - - snprintf(buf, buflen, "at cs#%d", ivar->cs); - return (0); -} - -static int -nandbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, - size_t buflen) -{ - // XXX man id, model id ???? - *buf = '\0'; - return (0); -} - -static int -nand_readid(device_t bus, uint8_t *man_id, uint8_t *dev_id) -{ - device_t nfc; - - if (!bus || !man_id || !dev_id) - return (EINVAL); - - nand_debug(NDBG_BUS,"read id"); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { - nand_debug(NDBG_BUS,"Error : could not send READ ID command"); - return (ENXIO); - } - - if (NFC_SEND_ADDRESS(nfc, 0)) { - nand_debug(NDBG_BUS,"Error : could not sent address to chip"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start command"); - return (ENXIO); - } - - DELAY(25); - - *man_id = NFC_READ_BYTE(nfc); - *dev_id = NFC_READ_BYTE(nfc); - - nand_debug(NDBG_BUS,"manufacturer id: %x chip id: %x", *man_id, - *dev_id); - - return (0); -} - -static int -nand_probe_onfi(device_t bus, uint8_t *onfi_compliant) -{ - device_t nfc; - char onfi_id[] = {'O', 'N', 'F', 'I', '\0'}; - int i; - - nand_debug(NDBG_BUS,"probing ONFI"); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { - nand_debug(NDBG_BUS,"Error : could not sent READ ID command"); - return (ENXIO); - } - - if (NFC_SEND_ADDRESS(nfc, ONFI_SIG_ADDR)) { - nand_debug(NDBG_BUS,"Error : could not sent address to chip"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start command"); - return (ENXIO); - } - for (i = 0; onfi_id[i] != '\0'; i++) - if (NFC_READ_BYTE(nfc) != onfi_id[i]) { - nand_debug(NDBG_BUS,"ONFI non-compliant"); - *onfi_compliant = 0; - return (0); - } - - nand_debug(NDBG_BUS,"ONFI compliant"); - *onfi_compliant = 1; - - return (0); -} - -static int -nand_reset(device_t bus) -{ - device_t nfc; - nand_debug(NDBG_BUS,"resetting..."); - - nfc = device_get_parent(bus); - - if (NFC_SEND_COMMAND(nfc, NAND_CMD_RESET) != 0) { - nand_debug(NDBG_BUS,"Error : could not sent RESET command"); - return (ENXIO); - } - - if (NFC_START_COMMAND(nfc) != 0) { - nand_debug(NDBG_BUS,"Error : could not start RESET command"); - return (ENXIO); - } - - DELAY(1000); - - return (0); -} - -void -nandbus_lock(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->nandbus_mtx); - if (sc->busy) - cv_wait(&sc->nandbus_cv, &sc->nandbus_mtx); - sc->busy = 1; - mtx_unlock(&sc->nandbus_mtx); -} - -void -nandbus_unlock(device_t dev) -{ - struct nandbus_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->nandbus_mtx); - sc->busy = 0; - cv_signal(&sc->nandbus_cv); - mtx_unlock(&sc->nandbus_mtx); -} - -int -nandbus_select_cs(device_t dev, uint8_t cs) -{ - - return (NFC_SELECT_CS(device_get_parent(dev), cs)); -} - -int -nandbus_send_command(device_t dev, uint8_t command) -{ - int err; - - if ((err = NFC_SEND_COMMAND(device_get_parent(dev), command))) - nand_debug(NDBG_BUS,"Err: Could not send command %x, err %x", - command, err); - - return (err); -} - -int -nandbus_send_address(device_t dev, uint8_t address) -{ - int err; - - if ((err = NFC_SEND_ADDRESS(device_get_parent(dev), address))) - nand_debug(NDBG_BUS,"Err: Could not send address %x, err %x", - address, err); - - return (err); -} - -int -nandbus_start_command(device_t dev) -{ - int err; - - if ((err = NFC_START_COMMAND(device_get_parent(dev)))) - nand_debug(NDBG_BUS,"Err: Could not start command, err %x", - err); - - return (err); -} - -void -nandbus_read_buffer(device_t dev, void *buf, uint32_t len) -{ - - NFC_READ_BUF(device_get_parent(dev), buf, len); -} - -void -nandbus_write_buffer(device_t dev, void *buf, uint32_t len) -{ - - NFC_WRITE_BUF(device_get_parent(dev), buf, len); -} - -int -nandbus_get_status(device_t dev, uint8_t *status) -{ - int err; - - if ((err = NANDBUS_SEND_COMMAND(dev, NAND_CMD_STATUS))) - return (err); - if ((err = NANDBUS_START_COMMAND(dev))) - return (err); - - *status = NFC_READ_BYTE(device_get_parent(dev)); - - return (0); -} - -int -nandbus_wait_ready(device_t dev, uint8_t *status) -{ - struct timeval tv, tv2; - - tv2.tv_sec = 0; - tv2.tv_usec = 50 * 5000; /* 250ms */ - - getmicrotime(&tv); - timevaladd(&tv, &tv2); - - do { - if (NANDBUS_GET_STATUS(dev, status)) - return (ENXIO); - - if (*status & NAND_STATUS_RDY) - return (0); - - getmicrotime(&tv2); - } while (timevalcmp(&tv2, &tv, <=)); - - return (EBUSY); -} - -int -nandbus_get_ecc(device_t dev, void *buf, uint32_t pagesize, void *ecc, - int *needwrite) -{ - - return (NFC_GET_ECC(device_get_parent(dev), buf, pagesize, ecc, needwrite)); -} - -int -nandbus_correct_ecc(device_t dev, void *buf, int pagesize, void *readecc, - void *calcecc) -{ - - return (NFC_CORRECT_ECC(device_get_parent(dev), buf, pagesize, - readecc, calcecc)); -} - diff --git a/sys/dev/nand/nandbus.h b/sys/dev/nand/nandbus.h deleted file mode 100644 index 6dd4cbf26daa..000000000000 --- a/sys/dev/nand/nandbus.h +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDBUS_H_ -#define _NANDBUS_H_ - -struct nandbus_ivar { - uint8_t cs; - uint8_t cols; - uint8_t rows; - uint8_t man_id; - uint8_t dev_id; - uint8_t is_onfi; - char *chip_cdev_name; - struct nand_params *params; -}; - -extern devclass_t nandbus_devclass; -extern driver_t nandbus_driver; - -int nandbus_create(device_t nfc); -void nandbus_destroy(device_t nfc); - -#endif /* _NANDBUS_H_ */ diff --git a/sys/dev/nand/nandbus_if.m b/sys/dev/nand/nandbus_if.m deleted file mode 100644 index e914e18de661..000000000000 --- a/sys/dev/nand/nandbus_if.m +++ /dev/null @@ -1,100 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $FreeBSD$ - -# NAND bus interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nandbus; - -METHOD int get_status { - device_t dev; - uint8_t * status; -}; - -METHOD void read_buffer { - device_t dev; - void * buf; - uint32_t len; -}; - -METHOD int select_cs { - device_t dev; - uint8_t cs; -}; - -METHOD int send_command { - device_t dev; - uint8_t command; -}; - -METHOD int send_address { - device_t dev; - uint8_t address; -}; - -METHOD int start_command { - device_t dev; -}; - -METHOD int wait_ready { - device_t dev; - uint8_t * status; -} - -METHOD void write_buffer { - device_t dev; - void * buf; - uint32_t len; -}; - -METHOD int get_ecc { - device_t dev; - void * buf; - uint32_t pagesize; - void * ecc; - int * needwrite; -}; - -METHOD int correct_ecc { - device_t dev; - void * buf; - int pagesize; - void * readecc; - void * calcecc; -}; - -METHOD void lock { - device_t dev; -}; - -METHOD void unlock { - device_t dev; -}; - diff --git a/sys/dev/nand/nandsim.c b/sys/dev/nand/nandsim.c deleted file mode 100644 index 50e4f8bb2e33..000000000000 --- a/sys/dev/nand/nandsim.c +++ /dev/null @@ -1,670 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Simulated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_swap.h> - -struct sim_param sim; -struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; - -static struct cdev *nandsim_dev; -static d_ioctl_t nandsim_ioctl; - -static void nandsim_init_sim_param(struct sim_param *); -static int nandsim_create_ctrl(struct sim_ctrl *); -static int nandsim_destroy_ctrl(int); -static int nandsim_ctrl_status(struct sim_ctrl *); -static int nandsim_create_chip(struct sim_chip *); -static int nandsim_destroy_chip(struct sim_ctrl_chip *); -static int nandsim_chip_status(struct sim_chip *); -static int nandsim_start_ctrl(int); -static int nandsim_stop_ctrl(int); -static int nandsim_inject_error(struct sim_error *); -static int nandsim_get_block_state(struct sim_block_state *); -static int nandsim_set_block_state(struct sim_block_state *); -static int nandsim_modify(struct sim_mod *); -static int nandsim_dump(struct sim_dump *); -static int nandsim_restore(struct sim_dump *); -static int nandsim_freeze(struct sim_ctrl_chip *); -static void nandsim_print_log(struct sim_log *); -static struct nandsim_chip *get_nandsim_chip(uint8_t, uint8_t); - -static struct cdevsw nandsim_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_ioctl = nandsim_ioctl, - .d_name = "nandsim", -}; - -int -nandsim_ioctl(struct cdev *dev, u_long cmd, caddr_t data, - int flags, struct thread *td) -{ - int ret = 0; - - switch (cmd) { - case NANDSIM_SIM_PARAM: - nandsim_init_sim_param((struct sim_param *)data); - break; - case NANDSIM_CREATE_CTRL: - ret = nandsim_create_ctrl((struct sim_ctrl *)data); - break; - case NANDSIM_DESTROY_CTRL: - ret = nandsim_destroy_ctrl(*(int *)data); - break; - case NANDSIM_STATUS_CTRL: - ret = nandsim_ctrl_status((struct sim_ctrl *)data); - break; - case NANDSIM_CREATE_CHIP: - ret = nandsim_create_chip((struct sim_chip *)data); - break; - case NANDSIM_DESTROY_CHIP: - ret = nandsim_destroy_chip((struct sim_ctrl_chip *)data); - break; - case NANDSIM_STATUS_CHIP: - ret = nandsim_chip_status((struct sim_chip *)data); - break; - case NANDSIM_MODIFY: - ret = nandsim_modify((struct sim_mod *)data); - break; - case NANDSIM_START_CTRL: - ret = nandsim_start_ctrl(*(int *)data); - break; - case NANDSIM_STOP_CTRL: - ret = nandsim_stop_ctrl(*(int *)data); - break; - case NANDSIM_INJECT_ERROR: - ret = nandsim_inject_error((struct sim_error *)data); - break; - case NANDSIM_SET_BLOCK_STATE: - ret = nandsim_set_block_state((struct sim_block_state *)data); - break; - case NANDSIM_GET_BLOCK_STATE: - ret = nandsim_get_block_state((struct sim_block_state *)data); - break; - case NANDSIM_PRINT_LOG: - nandsim_print_log((struct sim_log *)data); - break; - case NANDSIM_DUMP: - ret = nandsim_dump((struct sim_dump *)data); - break; - case NANDSIM_RESTORE: - ret = nandsim_restore((struct sim_dump *)data); - break; - case NANDSIM_FREEZE: - ret = nandsim_freeze((struct sim_ctrl_chip *)data); - break; - default: - ret = EINVAL; - break; - } - - return (ret); -} - -static void -nandsim_init_sim_param(struct sim_param *param) -{ - - if (!param) - return; - - nand_debug(NDBG_SIM,"log level:%d output %d", param->log_level, - param->log_output); - nandsim_log_level = param->log_level; - nandsim_log_output = param->log_output; -} - -static int -nandsim_create_ctrl(struct sim_ctrl *ctrl) -{ - struct sim_ctrl_conf *sim_ctrl; - - nand_debug(NDBG_SIM,"create controller num:%d cs:%d",ctrl->num, - ctrl->num_cs); - - if (ctrl->num >= MAX_SIM_DEV) { - return (EINVAL); - } - - sim_ctrl = &ctrls[ctrl->num]; - if(sim_ctrl->created) - return (EEXIST); - - sim_ctrl->num = ctrl->num; - sim_ctrl->num_cs = ctrl->num_cs; - sim_ctrl->ecc = ctrl->ecc; - memcpy(sim_ctrl->ecc_layout, ctrl->ecc_layout, - MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); - strlcpy(sim_ctrl->filename, ctrl->filename, - FILENAME_SIZE); - sim_ctrl->created = 1; - - return (0); -} - -static int -nandsim_destroy_ctrl(int ctrl_num) -{ - - nand_debug(NDBG_SIM,"destroy controller num:%d", ctrl_num); - - if (ctrl_num >= MAX_SIM_DEV) { - return (EINVAL); - } - - if (!ctrls[ctrl_num].created) { - return (ENODEV); - } - - if (ctrls[ctrl_num].running) { - return (EBUSY); - } - - memset(&ctrls[ctrl_num], 0, sizeof(ctrls[ctrl_num])); - - return (0); -} - -static int -nandsim_ctrl_status(struct sim_ctrl *ctrl) -{ - - nand_debug(NDBG_SIM,"status controller num:%d cs:%d",ctrl->num, - ctrl->num_cs); - - if (ctrl->num >= MAX_SIM_DEV) { - return (EINVAL); - } - - ctrl->num_cs = ctrls[ctrl->num].num_cs; - ctrl->ecc = ctrls[ctrl->num].ecc; - memcpy(ctrl->ecc_layout, ctrls[ctrl->num].ecc_layout, - MAX_ECC_BYTES * sizeof(ctrl->ecc_layout[0])); - strlcpy(ctrl->filename, ctrls[ctrl->num].filename, - FILENAME_SIZE); - ctrl->running = ctrls[ctrl->num].running; - ctrl->created = ctrls[ctrl->num].created; - - return (0); -} - -static int -nandsim_create_chip(struct sim_chip *chip) -{ - struct sim_chip *sim_chip; - - nand_debug(NDBG_SIM,"create chip num:%d at ctrl:%d", chip->num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->num >= MAX_CTRL_CS) { - return (EINVAL); - } - - if (ctrls[chip->ctrl_num].chips[chip->num]) { - return (EEXIST); - } - - sim_chip = malloc(sizeof(*sim_chip), M_NANDSIM, - M_WAITOK); - if (sim_chip == NULL) { - return (ENOMEM); - } - - memcpy(sim_chip, chip, sizeof(*sim_chip)); - ctrls[chip->ctrl_num].chips[chip->num] = sim_chip; - sim_chip->created = 1; - - return (0); -} - -static int -nandsim_destroy_chip(struct sim_ctrl_chip *chip) -{ - struct sim_ctrl_conf *ctrl_conf; - - nand_debug(NDBG_SIM,"destroy chip num:%d at ctrl:%d", chip->chip_num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - ctrl_conf = &ctrls[chip->ctrl_num]; - - if (!ctrl_conf->created || !ctrl_conf->chips[chip->chip_num]) - return (ENODEV); - - if (ctrl_conf->running) - return (EBUSY); - - free(ctrl_conf->chips[chip->chip_num], M_NANDSIM); - ctrl_conf->chips[chip->chip_num] = NULL; - - return (0); -} - -static int -nandsim_chip_status(struct sim_chip *chip) -{ - struct sim_ctrl_conf *ctrl_conf; - - nand_debug(NDBG_SIM,"status for chip num:%d at ctrl:%d", chip->num, - chip->ctrl_num); - - if (chip->ctrl_num >= MAX_SIM_DEV || - chip->num >= MAX_CTRL_CS) - return (EINVAL); - - ctrl_conf = &ctrls[chip->ctrl_num]; - if (!ctrl_conf->chips[chip->num]) - chip->created = 0; - else - memcpy(chip, ctrl_conf->chips[chip->num], sizeof(*chip)); - - return (0); -} - -static int -nandsim_start_ctrl(int num) -{ - device_t nexus, ndev; - devclass_t nexus_devclass; - int ret = 0; - - nand_debug(NDBG_SIM,"start ctlr num:%d", num); - - if (num >= MAX_SIM_DEV) - return (EINVAL); - - if (!ctrls[num].created) - return (ENODEV); - - if (ctrls[num].running) - return (EBUSY); - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) - return (EFAULT); - - /* - * Create a newbus device representing this frontend instance - * - * XXX powerpc nexus doesn't implement bus_add_child, so child - * must be added by device_add_child(). - */ -#if defined(__powerpc__) - ndev = device_add_child(nexus, "nandsim", num); -#else - ndev = BUS_ADD_CHILD(nexus, 0, "nandsim", num); -#endif - if (!ndev) - return (EFAULT); - - mtx_lock(&Giant); - ret = device_probe_and_attach(ndev); - mtx_unlock(&Giant); - - if (ret == 0) { - ctrls[num].sim_ctrl_dev = ndev; - ctrls[num].running = 1; - } - - return (ret); -} - -static int -nandsim_stop_ctrl(int num) -{ - device_t nexus; - devclass_t nexus_devclass; - int ret = 0; - - nand_debug(NDBG_SIM,"stop controller num:%d", num); - - if (num >= MAX_SIM_DEV) { - return (EINVAL); - } - - if (!ctrls[num].created || !ctrls[num].running) { - return (ENODEV); - } - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) { - return (ENODEV); - } - - mtx_lock(&Giant); - if (ctrls[num].sim_ctrl_dev) { - ret = device_delete_child(nexus, ctrls[num].sim_ctrl_dev); - ctrls[num].sim_ctrl_dev = NULL; - } - mtx_unlock(&Giant); - - ctrls[num].running = 0; - - return (ret); -} - -static struct nandsim_chip * -get_nandsim_chip(uint8_t ctrl_num, uint8_t chip_num) -{ - struct nandsim_softc *sc; - - if (!ctrls[ctrl_num].sim_ctrl_dev) - return (NULL); - - sc = device_get_softc(ctrls[ctrl_num].sim_ctrl_dev); - return (sc->chips[chip_num]); -} - -static void -nandsim_print_log(struct sim_log *sim_log) -{ - struct nandsim_softc *sc; - int len1, len2; - - if (!ctrls[sim_log->ctrl_num].sim_ctrl_dev) - return; - - sc = device_get_softc(ctrls[sim_log->ctrl_num].sim_ctrl_dev); - if (sc->log_buff) { - len1 = strlen(&sc->log_buff[sc->log_idx + 1]); - if (len1 >= sim_log->len) - len1 = sim_log->len; - copyout(&sc->log_buff[sc->log_idx + 1], sim_log->log, len1); - len2 = strlen(sc->log_buff); - if (len2 >= (sim_log->len - len1)) - len2 = (sim_log->len - len1); - copyout(sc->log_buff, &sim_log->log[len1], len2); - sim_log->len = len1 + len2; - } -} - -static int -nandsim_inject_error(struct sim_error *error) -{ - struct nandsim_chip *chip; - struct block_space *bs; - struct onfi_params *param; - int page, page_size, block, offset; - - nand_debug(NDBG_SIM,"inject error for chip %d at ctrl %d\n", - error->chip_num, error->ctrl_num); - - if (error->ctrl_num >= MAX_SIM_DEV || - error->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - if (!ctrls[error->ctrl_num].created || !ctrls[error->ctrl_num].running) - return (ENODEV); - - chip = get_nandsim_chip(error->ctrl_num, error->chip_num); - param = &chip->params; - page_size = param->bytes_per_page + param->spare_bytes_per_page; - block = error->page_num / param->pages_per_block; - page = error->page_num % param->pages_per_block; - - bs = get_bs(chip->swap, block, 1); - if (!bs) - return (EINVAL); - - offset = (page * page_size) + error->column; - memset(&bs->blk_ptr[offset], error->pattern, error->len); - - return (0); -} - -static int -nandsim_set_block_state(struct sim_block_state *bs) -{ - struct onfi_params *params; - struct nandsim_chip *chip; - int blocks; - - nand_debug(NDBG_SIM,"set block state for %d:%d block %d\n", - bs->chip_num, bs->ctrl_num, bs->block_num); - - if (bs->ctrl_num >= MAX_SIM_DEV || - bs->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num); - params = &chip->params; - blocks = params->luns * params->blocks_per_lun; - - if (bs->block_num > blocks) - return (EINVAL); - - chip->blk_state[bs->block_num].is_bad = bs->state; - - if (bs->wearout >= 0) - chip->blk_state[bs->block_num].wear_lev = bs->wearout; - - return (0); -} - -static int -nandsim_get_block_state(struct sim_block_state *bs) -{ - struct onfi_params *params; - struct nandsim_chip *chip; - int blocks; - - if (bs->ctrl_num >= MAX_SIM_DEV || - bs->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - nand_debug(NDBG_SIM,"get block state for %d:%d block %d\n", - bs->chip_num, bs->ctrl_num, bs->block_num); - - chip = get_nandsim_chip(bs->ctrl_num, bs->chip_num); - params = &chip->params; - blocks = params->luns * params->blocks_per_lun; - - if (bs->block_num > blocks) - return (EINVAL); - - bs->state = chip->blk_state[bs->block_num].is_bad; - bs->wearout = chip->blk_state[bs->block_num].wear_lev; - - return (0); -} - -static int -nandsim_dump(struct sim_dump *dump) -{ - struct nandsim_chip *chip; - struct block_space *bs; - int blk_size; - - nand_debug(NDBG_SIM,"dump chip %d %d\n", dump->ctrl_num, dump->chip_num); - - if (dump->ctrl_num >= MAX_SIM_DEV || - dump->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num); - blk_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - bs = get_bs(chip->swap, dump->block_num, 0); - if (!bs) - return (EINVAL); - - if (dump->len > blk_size) - dump->len = blk_size; - - copyout(bs->blk_ptr, dump->data, dump->len); - - return (0); -} - -static int -nandsim_restore(struct sim_dump *dump) -{ - struct nandsim_chip *chip; - struct block_space *bs; - int blk_size; - - nand_debug(NDBG_SIM,"restore chip %d %d\n", dump->ctrl_num, - dump->chip_num); - - if (dump->ctrl_num >= MAX_SIM_DEV || - dump->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(dump->ctrl_num, dump->chip_num); - blk_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - bs = get_bs(chip->swap, dump->block_num, 1); - if (!bs) - return (EINVAL); - - if (dump->len > blk_size) - dump->len = blk_size; - - - copyin(dump->data, bs->blk_ptr, dump->len); - - return (0); -} - -static int -nandsim_freeze(struct sim_ctrl_chip *ctrl_chip) -{ - struct nandsim_chip *chip; - - if (ctrl_chip->ctrl_num >= MAX_SIM_DEV || - ctrl_chip->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - chip = get_nandsim_chip(ctrl_chip->ctrl_num, ctrl_chip->chip_num); - nandsim_chip_freeze(chip); - - return (0); -} - -static int -nandsim_modify(struct sim_mod *mod) -{ - struct sim_chip *sim_conf = NULL; - struct nandsim_chip *sim_chip = NULL; - - nand_debug(NDBG_SIM,"modify ctlr %d chip %d", mod->ctrl_num, - mod->chip_num); - - if (mod->field != SIM_MOD_LOG_LEVEL) { - if (mod->ctrl_num >= MAX_SIM_DEV || - mod->chip_num >= MAX_CTRL_CS) - return (EINVAL); - - sim_conf = ctrls[mod->ctrl_num].chips[mod->chip_num]; - sim_chip = get_nandsim_chip(mod->ctrl_num, mod->chip_num); - } - - switch (mod->field) { - case SIM_MOD_LOG_LEVEL: - nandsim_log_level = mod->new_value; - break; - case SIM_MOD_ERASE_TIME: - sim_conf->erase_time = sim_chip->erase_delay = mod->new_value; - break; - case SIM_MOD_PROG_TIME: - sim_conf->prog_time = sim_chip->prog_delay = mod->new_value; - break; - case SIM_MOD_READ_TIME: - sim_conf->read_time = sim_chip->read_delay = mod->new_value; - break; - case SIM_MOD_ERROR_RATIO: - sim_conf->error_ratio = mod->new_value; - sim_chip->error_ratio = mod->new_value; - break; - default: - break; - } - - return (0); -} -static int -nandsim_modevent(module_t mod __unused, int type, void *data __unused) -{ - struct sim_ctrl_chip chip_ctrl; - int i, j; - - switch (type) { - case MOD_LOAD: - nandsim_dev = make_dev(&nandsim_cdevsw, 0, - UID_ROOT, GID_WHEEL, 0600, "nandsim.ioctl"); - break; - case MOD_UNLOAD: - for (i = 0; i < MAX_SIM_DEV; i++) { - nandsim_stop_ctrl(i); - chip_ctrl.ctrl_num = i; - for (j = 0; j < MAX_CTRL_CS; j++) { - chip_ctrl.chip_num = j; - nandsim_destroy_chip(&chip_ctrl); - } - nandsim_destroy_ctrl(i); - } - destroy_dev(nandsim_dev); - break; - case MOD_SHUTDOWN: - break; - default: - return (EOPNOTSUPP); - } - return (0); -} - -DEV_MODULE(nandsim, nandsim_modevent, NULL); -MODULE_VERSION(nandsim, 1); -MODULE_DEPEND(nandsim, nand, 1, 1, 1); -MODULE_DEPEND(nandsim, alq, 1, 1, 1); diff --git a/sys/dev/nand/nandsim.h b/sys/dev/nand/nandsim.h deleted file mode 100644 index d4b225113bfd..000000000000 --- a/sys/dev/nand/nandsim.h +++ /dev/null @@ -1,177 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_H_ -#define _NANDSIM_H_ - -#include <sys/ioccom.h> -#include <sys/types.h> - -#define MAX_SIM_DEV 4 -#define MAX_CTRL_CS 4 -#define MAX_ECC_BYTES 512 -#define MAX_BAD_BLOCKS 512 -#define DEV_MODEL_STR_SIZE 21 -#define MAN_STR_SIZE 13 -#define FILENAME_SIZE 20 - -#define MAX_CHIPS (MAX_SIM_DEV*MAX_CTRL_CS) - -#define NANDSIM_OUTPUT_NONE 0x0 -#define NANDSIM_OUTPUT_CONSOLE 0x1 -#define NANDSIM_OUTPUT_RAM 0x2 -#define NANDSIM_OUTPUT_FILE 0x3 - -struct sim_ctrl_chip { - uint8_t ctrl_num; - uint8_t chip_num; -}; - -#define NANDSIM_BASE 'A' - -struct sim_param { - uint8_t log_level; - uint8_t log_output; -}; - -#define NANDSIM_SIM_PARAM _IOW(NANDSIM_BASE, 1, struct sim_param) - -struct sim_ctrl { - uint8_t running; - uint8_t created; - uint8_t num; - uint8_t num_cs; - uint8_t ecc; - char filename[FILENAME_SIZE]; - uint16_t ecc_layout[MAX_ECC_BYTES]; -}; -#define NANDSIM_CREATE_CTRL _IOW(NANDSIM_BASE, 2, struct sim_ctrl) -#define NANDSIM_DESTROY_CTRL _IOW(NANDSIM_BASE, 3, int) - -struct sim_chip { - uint8_t num; - uint8_t ctrl_num; - uint8_t created; - uint8_t device_id; - uint8_t manufact_id; - char device_model[DEV_MODEL_STR_SIZE]; - char manufacturer[MAN_STR_SIZE]; - uint8_t col_addr_cycles; - uint8_t row_addr_cycles; - uint8_t features; - uint8_t width; - uint32_t page_size; - uint32_t oob_size; - uint32_t pgs_per_blk; - uint32_t blks_per_lun; - uint32_t luns; - - uint32_t prog_time; - uint32_t erase_time; - uint32_t read_time; - uint32_t ccs_time; - - uint32_t error_ratio; - uint32_t wear_level; - uint32_t bad_block_map[MAX_BAD_BLOCKS]; - uint8_t is_wp; -}; - -#define NANDSIM_CREATE_CHIP _IOW(NANDSIM_BASE, 3, struct sim_chip) - -struct sim_chip_destroy { - uint8_t ctrl_num; - uint8_t chip_num; -}; -#define NANDSIM_DESTROY_CHIP _IOW(NANDSIM_BASE, 4, struct sim_chip_destroy) - -#define NANDSIM_START_CTRL _IOW(NANDSIM_BASE, 5, int) -#define NANDSIM_STOP_CTRL _IOW(NANDSIM_BASE, 6, int) -#define NANDSIM_RESTART_CTRL _IOW(NANDSIM_BASE, 7, int) - -#define NANDSIM_STATUS_CTRL _IOWR(NANDSIM_BASE, 8, struct sim_ctrl) -#define NANDSIM_STATUS_CHIP _IOWR(NANDSIM_BASE, 9, struct sim_chip) - -struct sim_mod { - uint8_t chip_num; - uint8_t ctrl_num; - uint32_t field; - uint32_t new_value; -}; -#define SIM_MOD_LOG_LEVEL 0 -#define SIM_MOD_ERASE_TIME 1 -#define SIM_MOD_PROG_TIME 2 -#define SIM_MOD_READ_TIME 3 -#define SIM_MOD_CCS_TIME 4 -#define SIM_MOD_ERROR_RATIO 5 - -#define NANDSIM_MODIFY _IOW(NANDSIM_BASE, 10, struct sim_mod) -#define NANDSIM_FREEZE _IOW(NANDSIM_BASE, 11, struct sim_ctrl_chip) - -struct sim_error { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t page_num; - uint32_t column; - uint32_t len; - uint32_t pattern; -}; -#define NANDSIM_INJECT_ERROR _IOW(NANDSIM_BASE, 20, struct sim_error) - -#define NANDSIM_GOOD_BLOCK 0 -#define NANDSIM_BAD_BLOCK 1 -struct sim_block_state { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t block_num; - int wearout; - uint8_t state; -}; -#define NANDSIM_SET_BLOCK_STATE _IOW(NANDSIM_BASE, 21, struct sim_block_state) -#define NANDSIM_GET_BLOCK_STATE _IOWR(NANDSIM_BASE, 22, struct sim_block_state) - -struct sim_log { - uint8_t ctrl_num; - char* log; - size_t len; -}; -#define NANDSIM_PRINT_LOG _IOWR(NANDSIM_BASE, 23, struct sim_log) - -struct sim_dump { - uint8_t ctrl_num; - uint8_t chip_num; - uint32_t block_num; - uint32_t len; - void* data; -}; -#define NANDSIM_DUMP _IOWR(NANDSIM_BASE, 24, struct sim_dump) -#define NANDSIM_RESTORE _IOWR(NANDSIM_BASE, 25, struct sim_dump) - -#endif /* _NANDSIM_H_ */ diff --git a/sys/dev/nand/nandsim_chip.c b/sys/dev/nand/nandsim_chip.c deleted file mode 100644 index b7ab83b9d208..000000000000 --- a/sys/dev/nand/nandsim_chip.c +++ /dev/null @@ -1,898 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/mutex.h> -#include <sys/proc.h> -#include <sys/sched.h> -#include <sys/kthread.h> -#include <sys/unistd.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_swap.h> - -MALLOC_DEFINE(M_NANDSIM, "NANDsim", "NANDsim dynamic data"); - -#define NANDSIM_CHIP_LOCK(chip) mtx_lock(&(chip)->ns_lock) -#define NANDSIM_CHIP_UNLOCK(chip) mtx_unlock(&(chip)->ns_lock) - -static nandsim_evh_t erase_evh; -static nandsim_evh_t idle_evh; -static nandsim_evh_t poweron_evh; -static nandsim_evh_t reset_evh; -static nandsim_evh_t read_evh; -static nandsim_evh_t readid_evh; -static nandsim_evh_t readparam_evh; -static nandsim_evh_t write_evh; - -static void nandsim_loop(void *); -static void nandsim_undefined(struct nandsim_chip *, uint8_t); -static void nandsim_bad_address(struct nandsim_chip *, uint8_t *); -static void nandsim_ignore_address(struct nandsim_chip *, uint8_t); -static void nandsim_sm_error(struct nandsim_chip *); -static void nandsim_start_handler(struct nandsim_chip *, nandsim_evh_t); - -static void nandsim_callout_eh(void *); -static int nandsim_delay(struct nandsim_chip *, int); - -static int nandsim_bbm_init(struct nandsim_chip *, uint32_t, uint32_t *); -static int nandsim_blk_state_init(struct nandsim_chip *, uint32_t, uint32_t); -static void nandsim_blk_state_destroy(struct nandsim_chip *); -static int nandchip_is_block_valid(struct nandsim_chip *, int); - -static void nandchip_set_status(struct nandsim_chip *, uint8_t); -static void nandchip_clear_status(struct nandsim_chip *, uint8_t); - -struct proc *nandsim_proc; - -struct nandsim_chip * -nandsim_chip_init(struct nandsim_softc* sc, uint8_t chip_num, - struct sim_chip *sim_chip) -{ - struct nandsim_chip *chip; - struct onfi_params *chip_param; - char swapfile[20]; - uint32_t size; - int error; - - chip = malloc(sizeof(*chip), M_NANDSIM, M_WAITOK | M_ZERO); - - mtx_init(&chip->ns_lock, "nandsim lock", NULL, MTX_DEF); - callout_init(&chip->ns_callout, 1); - STAILQ_INIT(&chip->nandsim_events); - - chip->chip_num = chip_num; - chip->ctrl_num = sim_chip->ctrl_num; - chip->sc = sc; - - if (!sim_chip->is_wp) - nandchip_set_status(chip, NAND_STATUS_WP); - - chip_param = &chip->params; - - chip->id.dev_id = sim_chip->device_id; - chip->id.man_id = sim_chip->manufact_id; - - chip->error_ratio = sim_chip->error_ratio; - chip->wear_level = sim_chip->wear_level; - chip->prog_delay = sim_chip->prog_time; - chip->erase_delay = sim_chip->erase_time; - chip->read_delay = sim_chip->read_time; - - chip_param->t_prog = sim_chip->prog_time; - chip_param->t_bers = sim_chip->erase_time; - chip_param->t_r = sim_chip->read_time; - bcopy("onfi", &chip_param->signature, 4); - - chip_param->manufacturer_id = sim_chip->manufact_id; - strncpy(chip_param->manufacturer_name, sim_chip->manufacturer, 12); - chip_param->manufacturer_name[11] = 0; - strncpy(chip_param->device_model, sim_chip->device_model, 20); - chip_param->device_model[19] = 0; - - chip_param->bytes_per_page = sim_chip->page_size; - chip_param->spare_bytes_per_page = sim_chip->oob_size; - chip_param->pages_per_block = sim_chip->pgs_per_blk; - chip_param->blocks_per_lun = sim_chip->blks_per_lun; - chip_param->luns = sim_chip->luns; - - init_chip_geom(&chip->cg, chip_param->luns, chip_param->blocks_per_lun, - chip_param->pages_per_block, chip_param->bytes_per_page, - chip_param->spare_bytes_per_page); - - chip_param->address_cycles = sim_chip->row_addr_cycles | - (sim_chip->col_addr_cycles << 4); - chip_param->features = sim_chip->features; - if (sim_chip->width == 16) - chip_param->features |= ONFI_FEAT_16BIT; - - size = chip_param->blocks_per_lun * chip_param->luns; - - error = nandsim_blk_state_init(chip, size, sim_chip->wear_level); - if (error) { - mtx_destroy(&chip->ns_lock); - free(chip, M_NANDSIM); - return (NULL); - } - - error = nandsim_bbm_init(chip, size, sim_chip->bad_block_map); - if (error) { - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - free(chip, M_NANDSIM); - return (NULL); - } - - nandsim_start_handler(chip, poweron_evh); - - nand_debug(NDBG_SIM,"Create thread for chip%d [%8p]", chip->chip_num, - chip); - /* Create chip thread */ - error = kproc_kthread_add(nandsim_loop, chip, &nandsim_proc, - &chip->nandsim_td, RFSTOPPED | RFHIGHPID, - 0, "nandsim", "chip"); - if (error) { - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - free(chip, M_NANDSIM); - return (NULL); - } - - thread_lock(chip->nandsim_td); - sched_class(chip->nandsim_td, PRI_REALTIME); - sched_add(chip->nandsim_td, SRQ_BORING); - thread_unlock(chip->nandsim_td); - - size = (chip_param->bytes_per_page + - chip_param->spare_bytes_per_page) * - chip_param->pages_per_block; - - sprintf(swapfile, "chip%d%d.swp", chip->ctrl_num, chip->chip_num); - chip->swap = nandsim_swap_init(swapfile, chip_param->blocks_per_lun * - chip_param->luns, size); - if (!chip->swap) - nandsim_chip_destroy(chip); - - /* Wait for new thread to enter main loop */ - tsleep(chip->nandsim_td, PWAIT, "ns_chip", 1 * hz); - - return (chip); -} - -static int -nandsim_blk_state_init(struct nandsim_chip *chip, uint32_t size, - uint32_t wear_lev) -{ - int i; - - if (!chip || size == 0) - return (-1); - - chip->blk_state = malloc(size * sizeof(struct nandsim_block_state), - M_NANDSIM, M_WAITOK | M_ZERO); - - for (i = 0; i < size; i++) { - if (wear_lev) - chip->blk_state[i].wear_lev = wear_lev; - else - chip->blk_state[i].wear_lev = -1; - } - - return (0); -} - -static void -nandsim_blk_state_destroy(struct nandsim_chip *chip) -{ - - if (chip && chip->blk_state) - free(chip->blk_state, M_NANDSIM); -} - -static int -nandsim_bbm_init(struct nandsim_chip *chip, uint32_t size, - uint32_t *sim_bbm) -{ - uint32_t index; - int i; - - if ((chip == NULL) || (size == 0)) - return (-1); - - if (chip->blk_state == NULL) - return (-1); - - if (sim_bbm == NULL) - return (0); - - for (i = 0; i < MAX_BAD_BLOCKS; i++) { - index = sim_bbm[i]; - - if (index == 0xffffffff) - break; - else if (index > size) - return (-1); - else - chip->blk_state[index].is_bad = 1; - } - - return (0); -} - -void -nandsim_chip_destroy(struct nandsim_chip *chip) -{ - struct nandsim_ev *ev; - - ev = create_event(chip, NANDSIM_EV_EXIT, 0); - if (ev) - send_event(ev); -} - -void -nandsim_chip_freeze(struct nandsim_chip *chip) -{ - - chip->flags |= NANDSIM_CHIP_FROZEN; -} - -static void -nandsim_loop(void *arg) -{ - struct nandsim_chip *chip = (struct nandsim_chip *)arg; - struct nandsim_ev *ev; - - nand_debug(NDBG_SIM,"Start main loop for chip%d [%8p]", chip->chip_num, - chip); - for(;;) { - NANDSIM_CHIP_LOCK(chip); - if (!(chip->flags & NANDSIM_CHIP_ACTIVE)) { - chip->flags |= NANDSIM_CHIP_ACTIVE; - wakeup(chip->nandsim_td); - } - - if (STAILQ_EMPTY(&chip->nandsim_events)) { - nand_debug(NDBG_SIM,"Chip%d [%8p] going sleep", - chip->chip_num, chip); - msleep(chip, &chip->ns_lock, PRIBIO, "nandev", 0); - } - - ev = STAILQ_FIRST(&chip->nandsim_events); - STAILQ_REMOVE_HEAD(&chip->nandsim_events, links); - NANDSIM_CHIP_UNLOCK(chip); - if (ev->type == NANDSIM_EV_EXIT) { - NANDSIM_CHIP_LOCK(chip); - destroy_event(ev); - wakeup(ev); - while (!STAILQ_EMPTY(&chip->nandsim_events)) { - ev = STAILQ_FIRST(&chip->nandsim_events); - STAILQ_REMOVE_HEAD(&chip->nandsim_events, - links); - destroy_event(ev); - wakeup(ev); - } - NANDSIM_CHIP_UNLOCK(chip); - nandsim_log(chip, NANDSIM_LOG_SM, "destroyed\n"); - mtx_destroy(&chip->ns_lock); - nandsim_blk_state_destroy(chip); - nandsim_swap_destroy(chip->swap); - free(chip, M_NANDSIM); - nandsim_proc = NULL; - - kthread_exit(); - } - - if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { - nand_debug(NDBG_SIM,"Chip [%x] get event [%x]", - chip->chip_num, ev->type); - chip->ev_handler(chip, ev->type, ev->data); - } - - wakeup(ev); - destroy_event(ev); - } - -} - -struct nandsim_ev * -create_event(struct nandsim_chip *chip, uint8_t type, uint8_t data_size) -{ - struct nandsim_ev *ev; - - ev = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); - if (!ev) { - nand_debug(NDBG_SIM,"Cannot create event"); - return (NULL); - } - - if (data_size > 0) - ev->data = malloc(sizeof(*ev), M_NANDSIM, M_NOWAIT | M_ZERO); - ev->type = type; - ev->chip = chip; - - return (ev); -} - -void -destroy_event(struct nandsim_ev *ev) -{ - - if (ev->data) - free(ev->data, M_NANDSIM); - free(ev, M_NANDSIM); -} - -int -send_event(struct nandsim_ev *ev) -{ - struct nandsim_chip *chip = ev->chip; - - if (!(chip->flags & NANDSIM_CHIP_FROZEN)) { - nand_debug(NDBG_SIM,"Chip%d [%p] send event %x", - chip->chip_num, chip, ev->type); - - NANDSIM_CHIP_LOCK(chip); - STAILQ_INSERT_TAIL(&chip->nandsim_events, ev, links); - NANDSIM_CHIP_UNLOCK(chip); - - wakeup(chip); - if ((ev->type != NANDSIM_EV_TIMEOUT) && chip->nandsim_td && - (curthread != chip->nandsim_td)) - tsleep(ev, PWAIT, "ns_ev", 5 * hz); - } - - return (0); -} - -static void -nandsim_callout_eh(void *arg) -{ - struct nandsim_ev *ev = (struct nandsim_ev *)arg; - - send_event(ev); -} - -static int -nandsim_delay(struct nandsim_chip *chip, int timeout) -{ - struct nandsim_ev *ev; - struct timeval delay; - int tm; - - nand_debug(NDBG_SIM,"Chip[%d] Set delay: %d", chip->chip_num, timeout); - - ev = create_event(chip, NANDSIM_EV_TIMEOUT, 0); - if (!ev) - return (-1); - - chip->sm_state = NANDSIM_STATE_TIMEOUT; - tm = (timeout/10000) * (hz / 100); - if (callout_reset(&chip->ns_callout, tm, nandsim_callout_eh, ev)) - return (-1); - - delay.tv_sec = chip->read_delay / 1000000; - delay.tv_usec = chip->read_delay % 1000000; - timevaladd(&chip->delay_tv, &delay); - - return (0); -} - -static void -nandsim_start_handler(struct nandsim_chip *chip, nandsim_evh_t evh) -{ - struct nandsim_ev *ev; - - chip->ev_handler = evh; - - nand_debug(NDBG_SIM,"Start handler %p for chip%d [%p]", evh, - chip->chip_num, chip); - ev = create_event(chip, NANDSIM_EV_START, 0); - if (!ev) - nandsim_sm_error(chip); - - send_event(ev); -} - -static void -nandchip_set_data(struct nandsim_chip *chip, uint8_t *data, uint32_t len, - uint32_t idx) -{ - - nand_debug(NDBG_SIM,"Chip [%x] data %p [%x] at %x", chip->chip_num, - data, len, idx); - chip->data.data_ptr = data; - chip->data.size = len; - chip->data.index = idx; -} - -static int -nandchip_chip_space(struct nandsim_chip *chip, int32_t row, int32_t column, - size_t size, uint8_t writing) -{ - struct block_space *blk_space; - uint32_t lun, block, page, offset, block_size; - int err; - - block_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - err = nand_row_to_blkpg(&chip->cg, row, &lun, &block, &page); - if (err) { - nand_debug(NDBG_SIM,"cannot get address\n"); - return (-1); - } - - if (!nandchip_is_block_valid(chip, block)) { - nandchip_set_data(chip, NULL, 0, 0); - return (-1); - } - - blk_space = get_bs(chip->swap, block, writing); - if (!blk_space) { - nandchip_set_data(chip, NULL, 0, 0); - return (-1); - } - - if (size > block_size) - size = block_size; - - if (size == block_size) { - offset = 0; - column = 0; - } else - offset = page * (chip->cg.page_size + chip->cg.oob_size); - - nandchip_set_data(chip, &blk_space->blk_ptr[offset], size, column); - - return (0); -} - -static int -nandchip_get_addr_byte(struct nandsim_chip *chip, void *data, uint32_t *value) -{ - int ncycles = 0; - uint8_t byte; - uint8_t *buffer; - - buffer = (uint8_t *)value; - byte = *((uint8_t *)data); - - KASSERT((chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW || - chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL), - ("unexpected state")); - - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - ncycles = chip->params.address_cycles & 0xf; - buffer[chip->sm_addr_cycle++] = byte; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - ncycles = (chip->params.address_cycles >> 4) & 0xf; - buffer[chip->sm_addr_cycle++] = byte; - } - - nand_debug(NDBG_SIM, "Chip [%x] read addr byte: %02x (%d of %d)\n", - chip->chip_num, byte, chip->sm_addr_cycle, ncycles); - - if (chip->sm_addr_cycle == ncycles) { - chip->sm_addr_cycle = 0; - return (0); - } - - return (1); -} - -static int -nandchip_is_block_valid(struct nandsim_chip *chip, int block_num) -{ - - if (!chip || !chip->blk_state) - return (0); - - if (chip->blk_state[block_num].wear_lev == 0 || - chip->blk_state[block_num].is_bad) - return (0); - - return (1); -} - -static void -nandchip_set_status(struct nandsim_chip *chip, uint8_t flags) -{ - - chip->chip_status |= flags; -} - -static void -nandchip_clear_status(struct nandsim_chip *chip, uint8_t flags) -{ - - chip->chip_status &= ~flags; -} - -uint8_t -nandchip_get_status(struct nandsim_chip *chip) -{ - return (chip->chip_status); -} - -void -nandsim_chip_timeout(struct nandsim_chip *chip) -{ - struct timeval tv; - - getmicrotime(&tv); - - if (chip->sm_state == NANDSIM_STATE_TIMEOUT && - timevalcmp(&tv, &chip->delay_tv, >=)) { - nandchip_set_status(chip, NAND_STATUS_RDY); - } -} -void -poweron_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - uint8_t cmd; - - if (type == NANDSIM_EV_START) - chip->sm_state = NANDSIM_STATE_IDLE; - else if (type == NANDSIM_EV_CMD) { - cmd = *(uint8_t *)data; - switch(cmd) { - case NAND_CMD_RESET: - nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); - nandsim_start_handler(chip, reset_evh); - break; - default: - nandsim_undefined(chip, type); - break; - } - } else - nandsim_undefined(chip, type); -} - -void -idle_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - uint8_t cmd; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in IDLE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else if (type == NANDSIM_EV_CMD) { - nandchip_clear_status(chip, NAND_STATUS_FAIL); - getmicrotime(&chip->delay_tv); - cmd = *(uint8_t *)data; - switch(cmd) { - case NAND_CMD_READ_ID: - nandsim_start_handler(chip, readid_evh); - break; - case NAND_CMD_READ_PARAMETER: - nandsim_start_handler(chip, readparam_evh); - break; - case NAND_CMD_READ: - nandsim_start_handler(chip, read_evh); - break; - case NAND_CMD_PROG: - nandsim_start_handler(chip, write_evh); - break; - case NAND_CMD_ERASE: - nandsim_start_handler(chip, erase_evh); - break; - default: - nandsim_undefined(chip, type); - break; - } - } else - nandsim_undefined(chip, type); -} - -void -readid_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - struct onfi_params *params; - uint8_t addr; - - params = &chip->params; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in READID state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; - } else if (type == NANDSIM_EV_ADDR) { - - addr = *((uint8_t *)data); - - if (addr == 0x0) - nandchip_set_data(chip, (uint8_t *)&chip->id, 2, 0); - else if (addr == ONFI_SIG_ADDR) - nandchip_set_data(chip, (uint8_t *)¶ms->signature, - 4, 0); - else - nandsim_bad_address(chip, &addr); - - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -void -readparam_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - struct onfi_params *params; - uint8_t addr; - - params = &chip->params; - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in READPARAM state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_BYTE; - } else if (type == NANDSIM_EV_ADDR) { - addr = *((uint8_t *)data); - - if (addr == 0) { - nandchip_set_data(chip, (uint8_t *)params, - sizeof(*params), 0); - } else - nandsim_bad_address(chip, &addr); - - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -void -read_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t column = 0, row = 0; - uint32_t size; - uint8_t cmd; - - size = chip->cg.page_size + chip->cg.oob_size; - - switch (type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in READ state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - if (nandchip_get_addr_byte(chip, data, &column)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_READ_END) { - if (chip->read_delay != 0 && - nandsim_delay(chip, chip->read_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_chip_space(chip, row, column, size, 0); - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandchip_chip_space(chip, row, column, size, 0); - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); - break; - } -} -void -write_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t column, row; - uint32_t size; - uint8_t cmd; - int err; - - size = chip->cg.page_size + chip->cg.oob_size; - - switch(type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in WRITE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_COL; - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_COL) { - if (nandchip_get_addr_byte(chip, data, &column)) - break; - - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - } else if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - err = nandchip_chip_space(chip, row, column, size, 1); - if (err == -1) - nandchip_set_status(chip, NAND_STATUS_FAIL); - - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_PROG_END) { - if (chip->prog_delay != 0 && - nandsim_delay(chip, chip->prog_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandsim_start_handler(chip, idle_evh); - nandchip_set_status(chip, NAND_STATUS_RDY); - } else - nandsim_undefined(chip, type); - break; - } -} - -void -erase_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - static uint32_t row, block_size; - uint32_t lun, block, page; - int err; - uint8_t cmd; - - block_size = chip->cg.block_size + - (chip->cg.oob_size * chip->cg.pgs_per_blk); - - switch (type) { - case NANDSIM_EV_START: - nandsim_log(chip, NANDSIM_LOG_SM, "in ERASE state\n"); - chip->sm_state = NANDSIM_STATE_WAIT_ADDR_ROW; - break; - case NANDSIM_EV_CMD: - cmd = *(uint8_t *)data; - if (chip->sm_state == NANDSIM_STATE_WAIT_CMD && - cmd == NAND_CMD_ERASE_END) { - if (chip->data.data_ptr != NULL && - chip->data.size == block_size) - memset(chip->data.data_ptr, 0xff, block_size); - else - nand_debug(NDBG_SIM,"Bad block erase data\n"); - - err = nand_row_to_blkpg(&chip->cg, row, &lun, - &block, &page); - if (!err) { - if (chip->blk_state[block].wear_lev > 0) - chip->blk_state[block].wear_lev--; - } - - if (chip->erase_delay != 0 && - nandsim_delay(chip, chip->erase_delay) == 0) - nandchip_clear_status(chip, NAND_STATUS_RDY); - else { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } - } else - nandsim_undefined(chip, type); - break; - case NANDSIM_EV_ADDR: - if (chip->sm_state == NANDSIM_STATE_WAIT_ADDR_ROW) { - if (nandchip_get_addr_byte(chip, data, &row)) - break; - - err = nandchip_chip_space(chip, row, 0, block_size, 1); - if (err == -1) { - nandchip_set_status(chip, NAND_STATUS_FAIL); - } - chip->sm_state = NANDSIM_STATE_WAIT_CMD; - } else - nandsim_ignore_address(chip, *((uint8_t *)data)); - break; - case NANDSIM_EV_TIMEOUT: - if (chip->sm_state == NANDSIM_STATE_TIMEOUT) { - nandchip_set_status(chip, NAND_STATUS_RDY); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); - break; - } -} - -void -reset_evh(struct nandsim_chip *chip, uint32_t type, void *data) -{ - - if (type == NANDSIM_EV_START) { - nandsim_log(chip, NANDSIM_LOG_SM, "in RESET state\n"); - chip->sm_state = NANDSIM_STATE_TIMEOUT; - nandchip_set_data(chip, NULL, 0, 0); - DELAY(500); - nandsim_start_handler(chip, idle_evh); - } else - nandsim_undefined(chip, type); -} - -static void -nandsim_undefined(struct nandsim_chip *chip, uint8_t type) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, - "ERR: Chip received ev %x in state %x\n", - type, chip->sm_state); - nandsim_start_handler(chip, idle_evh); -} - -static void -nandsim_bad_address(struct nandsim_chip *chip, uint8_t *addr) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, - "ERR: Chip received out of range address" - "%02x%02x - %02x%02x%02x\n", addr[0], addr[1], addr[2], - addr[3], addr[4]); -} - -static void -nandsim_ignore_address(struct nandsim_chip *chip, uint8_t byte) -{ - nandsim_log(chip, NANDSIM_LOG_SM, "ignored address byte: %d\n", byte); -} - -static void -nandsim_sm_error(struct nandsim_chip *chip) -{ - - nandsim_log(chip, NANDSIM_LOG_ERR, "ERR: State machine error." - "Restart required.\n"); -} diff --git a/sys/dev/nand/nandsim_chip.h b/sys/dev/nand/nandsim_chip.h deleted file mode 100644 index 86ced5ea2bf2..000000000000 --- a/sys/dev/nand/nandsim_chip.h +++ /dev/null @@ -1,161 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_CHIP_H -#define _NANDSIM_CHIP_H - -#include <sys/malloc.h> -#include <sys/callout.h> -#include <dev/nand/nand.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_swap.h> - -MALLOC_DECLARE(M_NANDSIM); - -#define MAX_CS_NUM 4 -struct nandsim_chip; - -typedef void nandsim_evh_t(struct nandsim_chip *chip, uint32_t ev, void *data); - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct nandsim_softc { - struct nand_softc nand_dev; - device_t dev; - - struct nandsim_chip *chips[MAX_CS_NUM]; - struct nandsim_chip *active_chip; - - uint8_t address_cycle; - enum addr_type address_type; - int log_idx; - char *log_buff; - struct alq *alq; -}; - -struct nandsim_ev { - STAILQ_ENTRY(nandsim_ev) links; - struct nandsim_chip *chip; - uint8_t type; - void *data; -}; - -struct nandsim_data { - uint8_t *data_ptr; - uint32_t index; - uint32_t size; -}; - -struct nandsim_block_state { - int32_t wear_lev; - uint8_t is_bad; -}; - -#define NANDSIM_CHIP_ACTIVE 0x1 -#define NANDSIM_CHIP_FROZEN 0x2 -#define NANDSIM_CHIP_GET_STATUS 0x4 - -struct nandsim_chip { - struct nandsim_softc *sc; - struct thread *nandsim_td; - - STAILQ_HEAD(, nandsim_ev) nandsim_events; - nandsim_evh_t *ev_handler; - struct mtx ns_lock; - struct callout ns_callout; - - struct chip_geom cg; - struct nand_id id; - struct onfi_params params; - struct nandsim_data data; - struct nandsim_block_state *blk_state; - - struct chip_swap *swap; - - uint32_t error_ratio; - uint32_t wear_level; - uint32_t sm_state; - uint32_t sm_addr_cycle; - - uint32_t erase_delay; - uint32_t prog_delay; - uint32_t read_delay; - struct timeval delay_tv; - - uint8_t flags; - uint8_t chip_status; - uint8_t ctrl_num; - uint8_t chip_num; -}; - -struct sim_ctrl_conf { - uint8_t num; - uint8_t num_cs; - uint8_t ecc; - uint8_t running; - uint8_t created; - device_t sim_ctrl_dev; - struct sim_chip *chips[MAX_CTRL_CS]; - uint16_t ecc_layout[MAX_ECC_BYTES]; - char filename[FILENAME_SIZE]; -}; - -#define NANDSIM_STATE_IDLE 0x0 -#define NANDSIM_STATE_WAIT_ADDR_BYTE 0x1 -#define NANDSIM_STATE_WAIT_CMD 0x2 -#define NANDSIM_STATE_TIMEOUT 0x3 -#define NANDSIM_STATE_WAIT_ADDR_ROW 0x4 -#define NANDSIM_STATE_WAIT_ADDR_COL 0x5 - -#define NANDSIM_EV_START 0x1 -#define NANDSIM_EV_CMD 0x2 -#define NANDSIM_EV_ADDR 0x3 -#define NANDSIM_EV_TIMEOUT 0x4 -#define NANDSIM_EV_EXIT 0xff - -struct nandsim_chip *nandsim_chip_init(struct nandsim_softc *, - uint8_t, struct sim_chip *); -void nandsim_chip_destroy(struct nandsim_chip *); -void nandsim_chip_freeze(struct nandsim_chip *); -void nandsim_chip_timeout(struct nandsim_chip *); -int nandsim_chip_check_bad_block(struct nandsim_chip *, int); - -uint8_t nandchip_get_status(struct nandsim_chip *); - -void destroy_event(struct nandsim_ev *); -int send_event(struct nandsim_ev *); -struct nandsim_ev *create_event(struct nandsim_chip *, uint8_t, uint8_t); - -#endif /* _NANDSIM_CHIP_H */ diff --git a/sys/dev/nand/nandsim_ctrl.c b/sys/dev/nand/nandsim_ctrl.c deleted file mode 100644 index bc203902fe7e..000000000000 --- a/sys/dev/nand/nandsim_ctrl.c +++ /dev/null @@ -1,398 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Simulated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include <dev/nand/nandsim.h> -#include <dev/nand/nandsim_log.h> -#include <dev/nand/nandsim_chip.h> -#include "nfc_if.h" - -#define ADDRESS_SIZE 5 - -extern struct sim_ctrl_conf ctrls[MAX_SIM_DEV]; - -static void byte_corrupt(struct nandsim_chip *, uint8_t *); - -static int nandsim_attach(device_t); -static int nandsim_detach(device_t); -static int nandsim_probe(device_t); - -static uint8_t nandsim_read_byte(device_t); -static uint16_t nandsim_read_word(device_t); -static int nandsim_select_cs(device_t, uint8_t); -static void nandsim_write_byte(device_t, uint8_t); -static void nandsim_write_word(device_t, uint16_t); -static void nandsim_read_buf(device_t, void *, uint32_t); -static void nandsim_write_buf(device_t, void *, uint32_t); -static int nandsim_send_command(device_t, uint8_t); -static int nandsim_send_address(device_t, uint8_t); - -static device_method_t nandsim_methods[] = { - DEVMETHOD(device_probe, nandsim_probe), - DEVMETHOD(device_attach, nandsim_attach), - DEVMETHOD(device_detach, nandsim_detach), - - DEVMETHOD(nfc_select_cs, nandsim_select_cs), - DEVMETHOD(nfc_send_command, nandsim_send_command), - DEVMETHOD(nfc_send_address, nandsim_send_address), - DEVMETHOD(nfc_read_byte, nandsim_read_byte), - DEVMETHOD(nfc_read_word, nandsim_read_word), - DEVMETHOD(nfc_write_byte, nandsim_write_byte), - DEVMETHOD(nfc_read_buf, nandsim_read_buf), - DEVMETHOD(nfc_write_buf, nandsim_write_buf), - - { 0, 0 }, -}; - -static driver_t nandsim_driver = { - "nandsim", - nandsim_methods, - sizeof(struct nandsim_softc), -}; - -static devclass_t nandsim_devclass; -DRIVER_MODULE(nandsim, nexus, nandsim_driver, nandsim_devclass, 0, 0); -DRIVER_MODULE(nandbus, nandsim, nandbus_driver, nandbus_devclass, 0, 0); - -static int -nandsim_probe(device_t dev) -{ - - device_set_desc(dev, "NAND controller simulator"); - return (BUS_PROBE_DEFAULT); -} - -static int -nandsim_attach(device_t dev) -{ - struct nandsim_softc *sc; - struct sim_ctrl_conf *params; - struct sim_chip *chip; - uint16_t *eccpos; - int i, err; - - sc = device_get_softc(dev); - params = &ctrls[device_get_unit(dev)]; - - if (strlen(params->filename) == 0) - snprintf(params->filename, FILENAME_SIZE, "ctrl%d.log", - params->num); - - nandsim_log_init(sc, params->filename); - for (i = 0; i < params->num_cs; i++) { - chip = params->chips[i]; - if (chip && chip->device_id != 0) { - sc->chips[i] = nandsim_chip_init(sc, i, chip); - if (chip->features & ONFI_FEAT_16BIT) - sc->nand_dev.flags |= NAND_16_BIT; - } - } - - if (params->ecc_layout[0] != 0xffff) - eccpos = params->ecc_layout; - else - eccpos = NULL; - - nand_init(&sc->nand_dev, dev, params->ecc, 0, 0, eccpos, "nandsim"); - - err = nandbus_create(dev); - - return (err); -} - -static int -nandsim_detach(device_t dev) -{ - struct nandsim_softc *sc; - struct sim_ctrl_conf *params; - int i; - - sc = device_get_softc(dev); - params = &ctrls[device_get_unit(dev)]; - - for (i = 0; i < params->num_cs; i++) - if (sc->chips[i] != NULL) - nandsim_chip_destroy(sc->chips[i]); - - nandsim_log_close(sc); - - return (0); -} - -static int -nandsim_select_cs(device_t dev, uint8_t cs) -{ - struct nandsim_softc *sc; - - sc = device_get_softc(dev); - - if (cs >= MAX_CS_NUM) - return (EINVAL); - - sc->active_chip = sc->chips[cs]; - - if (sc->active_chip) - nandsim_log(sc->active_chip, NANDSIM_LOG_EV, - "Select cs %d\n", cs); - - return (0); -} - -static int -nandsim_send_command(device_t dev, uint8_t command) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - struct nandsim_ev *ev; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip == NULL) - return (0); - - nandsim_log(chip, NANDSIM_LOG_EV, "Send command %x\n", command); - - switch (command) { - case NAND_CMD_READ_ID: - case NAND_CMD_READ_PARAMETER: - sc->address_type = ADDR_ID; - break; - case NAND_CMD_ERASE: - sc->address_type = ADDR_ROW; - break; - case NAND_CMD_READ: - case NAND_CMD_PROG: - sc->address_type = ADDR_ROWCOL; - break; - default: - sc->address_type = ADDR_NONE; - break; - } - - if (command == NAND_CMD_STATUS) - chip->flags |= NANDSIM_CHIP_GET_STATUS; - else { - ev = create_event(chip, NANDSIM_EV_CMD, 1); - *(uint8_t *)ev->data = command; - send_event(ev); - } - - return (0); -} - -static int -nandsim_send_address(device_t dev, uint8_t addr) -{ - struct nandsim_ev *ev; - struct nandsim_softc *sc; - struct nandsim_chip *chip; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip == NULL) - return (0); - - KASSERT((sc->address_type != ADDR_NONE), ("unexpected address")); - nandsim_log(chip, NANDSIM_LOG_EV, "Send addr %x\n", addr); - - ev = create_event(chip, NANDSIM_EV_ADDR, 1); - - *((uint8_t *)(ev->data)) = addr; - - send_event(ev); - return (0); -} - -static uint8_t -nandsim_read_byte(device_t dev) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint8_t ret = 0xff; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if (chip->flags & NANDSIM_CHIP_GET_STATUS) { - nandsim_chip_timeout(chip); - ret = nandchip_get_status(chip); - chip->flags &= ~NANDSIM_CHIP_GET_STATUS; - } else if (chip->data.index < chip->data.size) { - ret = chip->data.data_ptr[chip->data.index++]; - byte_corrupt(chip, &ret); - } - nandsim_log(chip, NANDSIM_LOG_DATA, "read %02x\n", ret); - } - - return (ret); -} - -static uint16_t -nandsim_read_word(device_t dev) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint16_t *data_ptr; - uint16_t ret = 0xffff; - uint8_t *byte_ret = (uint8_t *)&ret; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if (chip->data.index < chip->data.size - 1) { - data_ptr = - (uint16_t *)&(chip->data.data_ptr[chip->data.index]); - ret = *data_ptr; - chip->data.index += 2; - byte_corrupt(chip, byte_ret); - byte_corrupt(chip, byte_ret + 1); - } - nandsim_log(chip, NANDSIM_LOG_DATA, "read %04x\n", ret); - } - - return (ret); -} - -static void -nandsim_write_byte(device_t dev, uint8_t byte) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN) && - (chip->data.index < chip->data.size)) { - byte_corrupt(chip, &byte); - chip->data.data_ptr[chip->data.index] &= byte; - chip->data.index++; - nandsim_log(chip, NANDSIM_LOG_DATA, "write %02x\n", byte); - } -} - -static void -nandsim_write_word(device_t dev, uint16_t word) -{ - struct nandsim_softc *sc; - struct nandsim_chip *chip; - uint16_t *data_ptr; - uint8_t *byte_ptr = (uint8_t *)&word; - - sc = device_get_softc(dev); - chip = sc->active_chip; - - if (chip && !(chip->flags & NANDSIM_CHIP_FROZEN)) { - if ((chip->data.index + 1) < chip->data.size) { - byte_corrupt(chip, byte_ptr); - byte_corrupt(chip, byte_ptr + 1); - data_ptr = - (uint16_t *)&(chip->data.data_ptr[chip->data.index]); - *data_ptr &= word; - chip->data.index += 2; - } - - nandsim_log(chip, NANDSIM_LOG_DATA, "write %04x\n", word); - } -} - -static void -nandsim_read_buf(device_t dev, void *buf, uint32_t len) -{ - struct nandsim_softc *sc; - uint16_t *buf16 = (uint16_t *)buf; - uint8_t *buf8 = (uint8_t *)buf; - int i; - - sc = device_get_softc(dev); - - if (sc->nand_dev.flags & NAND_16_BIT) { - for (i = 0; i < len / 2; i++) - buf16[i] = nandsim_read_word(dev); - } else { - for (i = 0; i < len; i++) - buf8[i] = nandsim_read_byte(dev); - } -} - -static void -nandsim_write_buf(device_t dev, void *buf, uint32_t len) -{ - struct nandsim_softc *sc; - uint16_t *buf16 = (uint16_t *)buf; - uint8_t *buf8 = (uint8_t *)buf; - int i; - - sc = device_get_softc(dev); - - if (sc->nand_dev.flags & NAND_16_BIT) { - for (i = 0; i < len / 2; i++) - nandsim_write_word(dev, buf16[i]); - } else { - for (i = 0; i < len; i++) - nandsim_write_byte(dev, buf8[i]); - } -} - -static void -byte_corrupt(struct nandsim_chip *chip, uint8_t *byte) -{ - uint32_t rand; - uint8_t bit; - - rand = random(); - if ((rand % 1000000) < chip->error_ratio) { - bit = rand % 8; - if (*byte & (1 << bit)) - *byte &= ~(1 << bit); - else - *byte |= (1 << bit); - } -} diff --git a/sys/dev/nand/nandsim_log.c b/sys/dev/nand/nandsim_log.c deleted file mode 100644 index 0bd316ace4e2..000000000000 --- a/sys/dev/nand/nandsim_log.c +++ /dev/null @@ -1,188 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <sys/alq.h> -#include <sys/time.h> - -#include <machine/stdarg.h> - -#include <dev/nand/nandsim_log.h> - -int nandsim_log_level; -int nandsim_log_output; -int log_size = NANDSIM_RAM_LOG_SIZE; - -static int nandsim_entry_size = NANDSIM_ENTRY_SIZE; -static int nandsim_entry_count = NANDSIM_ENTRY_COUNT; -static int str_index = 0; -static char string[NANDSIM_ENTRY_SIZE + 1] = {0}; - -int -nandsim_log_init(struct nandsim_softc *sc, char *filename) -{ - int error = 0; - - if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { - error = alq_open(&sc->alq, filename, - curthread->td_ucred, 0644, - nandsim_entry_size, nandsim_entry_count); - } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { - sc->log_buff = malloc(log_size, M_NANDSIM, M_WAITOK | M_ZERO); - if (!sc->log_buff) - error = ENOMEM; - } - - return (error); -} - -void -nandsim_log_close(struct nandsim_softc *sc) -{ - - if (nandsim_log_output == NANDSIM_OUTPUT_FILE) { - memset(&string[str_index], 0, NANDSIM_ENTRY_SIZE - str_index); - alq_write(sc->alq, (void *) string, ALQ_NOWAIT); - str_index = 0; - string[0] = '\0'; - alq_close(sc->alq); - } else if (nandsim_log_output == NANDSIM_OUTPUT_RAM) { - free(sc->log_buff, M_NANDSIM); - sc->log_buff = NULL; - } -} - -void -nandsim_log(struct nandsim_chip *chip, int level, const char *fmt, ...) -{ - char hdr[TIME_STR_SIZE]; - char tmp[NANDSIM_ENTRY_SIZE]; - struct nandsim_softc *sc; - struct timeval currtime; - va_list ap; - int hdr_len, len, rest; - - if (nandsim_log_output == NANDSIM_OUTPUT_NONE) - return; - - if (chip == NULL) - return; - - sc = chip->sc; - if (!sc->alq && nandsim_log_output == NANDSIM_OUTPUT_FILE) - return; - - if (level <= nandsim_log_level) { - microtime(&currtime); - hdr_len = sprintf(hdr, "%08jd.%08li [chip:%d, ctrl:%d]: ", - (intmax_t)currtime.tv_sec, currtime.tv_usec, - chip->chip_num, chip->ctrl_num); - - switch(nandsim_log_output) { - case NANDSIM_OUTPUT_CONSOLE: - printf("%s", hdr); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - break; - case NANDSIM_OUTPUT_RAM: - va_start(ap, fmt); - len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); - tmp[NANDSIM_ENTRY_SIZE - 1] = 0; - va_end(ap); - - rest = log_size - sc->log_idx - 1; - if (rest >= hdr_len) { - bcopy(hdr, &sc->log_buff[sc->log_idx], - hdr_len); - sc->log_idx += hdr_len; - sc->log_buff[sc->log_idx] = 0; - } else { - bcopy(hdr, &sc->log_buff[sc->log_idx], rest); - bcopy(&hdr[rest], sc->log_buff, - hdr_len - rest); - sc->log_idx = hdr_len - rest; - sc->log_buff[sc->log_idx] = 0; - } - - rest = log_size - sc->log_idx - 1; - if (rest >= len) { - bcopy(tmp, &sc->log_buff[sc->log_idx], len); - sc->log_idx += len; - sc->log_buff[sc->log_idx] = 0; - } else { - bcopy(tmp, &sc->log_buff[sc->log_idx], rest); - bcopy(&tmp[rest], sc->log_buff, len - rest); - sc->log_idx = len - rest; - sc->log_buff[sc->log_idx] = 0; - } - - break; - - case NANDSIM_OUTPUT_FILE: - va_start(ap, fmt); - len = vsnprintf(tmp, NANDSIM_ENTRY_SIZE - 1, fmt, ap); - tmp[NANDSIM_ENTRY_SIZE - 1] = 0; - va_end(ap); - - rest = NANDSIM_ENTRY_SIZE - str_index; - if (rest >= hdr_len) { - strcat(string, hdr); - str_index += hdr_len; - } else { - strlcat(string, hdr, NANDSIM_ENTRY_SIZE + 1); - alq_write(sc->alq, (void *) string, - ALQ_NOWAIT); - strcpy(string, &hdr[rest]); - str_index = hdr_len - rest; - } - rest = NANDSIM_ENTRY_SIZE - str_index; - if (rest >= len) { - strcat(string, tmp); - str_index += len; - } else { - strlcat(string, tmp, NANDSIM_ENTRY_SIZE + 1); - alq_write(sc->alq, (void *) string, - ALQ_NOWAIT); - strcpy(string, &tmp[rest]); - str_index = len - rest; - } - break; - default: - break; - } - } -} diff --git a/sys/dev/nand/nandsim_log.h b/sys/dev/nand/nandsim_log.h deleted file mode 100644 index 5e5a055a4053..000000000000 --- a/sys/dev/nand/nandsim_log.h +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_LOG_H -#define _NANDSIM_LOG_H - -#include <dev/nand/nandsim_chip.h> - -#define NANDSIM_ENTRY_SIZE 128 -#define NANDSIM_ENTRY_COUNT 1024 -#define NANDSIM_RAM_LOG_SIZE 16384 -#define TIME_STR_SIZE 40 - -#define NANDSIM_LOG_ERR 1 -#define NANDSIM_LOG_SM 5 -#define NANDSIM_LOG_EV 10 -#define NANDSIM_LOG_DATA 15 - -extern int nandsim_log_level; -extern int nandsim_log_output; - -int nandsim_log_init(struct nandsim_softc *, char *); -void nandsim_log_close(struct nandsim_softc *); -void nandsim_log(struct nandsim_chip *, int, const char *, ...); - -#endif /* _NANDSIM_LOG_H */ - diff --git a/sys/dev/nand/nandsim_swap.c b/sys/dev/nand/nandsim_swap.c deleted file mode 100644 index 78e14e9557bd..000000000000 --- a/sys/dev/nand/nandsim_swap.c +++ /dev/null @@ -1,383 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/queue.h> -#include <sys/fcntl.h> -#include <sys/proc.h> -#include <sys/namei.h> -#include <sys/lock.h> -#include <sys/vnode.h> -#include <sys/mount.h> - -#include <dev/nand/nandsim_chip.h> -#include <dev/nand/nandsim_swap.h> - -static int init_block_state(struct chip_swap *); -static void destroy_block_state(struct chip_swap *); - -static int create_buffers(struct chip_swap *); -static void destroy_buffers(struct chip_swap *); - -static int swap_file_open(struct chip_swap *, const char *); -static void swap_file_close(struct chip_swap *); -static int swap_file_write(struct chip_swap *, struct block_state *); -static int swap_file_read(struct chip_swap *, struct block_state *); - -#define CHIP_SWAP_CMODE 0600 -#define CHIP_SWAP_BLOCKSPACES 2 - -static int -init_block_state(struct chip_swap *swap) -{ - struct block_state *blk_state; - int i; - - if (swap == NULL) - return (-1); - - blk_state = malloc(swap->nof_blks * sizeof(struct block_state), - M_NANDSIM, M_WAITOK | M_ZERO); - - for (i = 0; i < swap->nof_blks; i++) - blk_state[i].offset = 0xffffffff; - - swap->blk_state = blk_state; - - return (0); -} - -static void -destroy_block_state(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - if (swap->blk_state != NULL) - free(swap->blk_state, M_NANDSIM); -} - -static int -create_buffers(struct chip_swap *swap) -{ - struct block_space *block_space; - void *block; - int i; - - for (i = 0; i < CHIP_SWAP_BLOCKSPACES; i++) { - block_space = malloc(sizeof(*block_space), M_NANDSIM, M_WAITOK); - block = malloc(swap->blk_size, M_NANDSIM, M_WAITOK); - block_space->blk_ptr = block; - SLIST_INSERT_HEAD(&swap->free_bs, block_space, free_link); - nand_debug(NDBG_SIM,"created blk_space %p[%p]\n", block_space, - block); - } - - if (i == 0) - return (-1); - - return (0); -} - -static void -destroy_buffers(struct chip_swap *swap) -{ - struct block_space *blk_space; - - if (swap == NULL) - return; - - blk_space = SLIST_FIRST(&swap->free_bs); - while (blk_space) { - SLIST_REMOVE_HEAD(&swap->free_bs, free_link); - nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n", - blk_space, blk_space->blk_ptr); - free(blk_space->blk_ptr, M_NANDSIM); - free(blk_space, M_NANDSIM); - blk_space = SLIST_FIRST(&swap->free_bs); - } - - blk_space = STAILQ_FIRST(&swap->used_bs); - while (blk_space) { - STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); - nand_debug(NDBG_SIM,"destroyed blk_space %p[%p]\n", - blk_space, blk_space->blk_ptr); - free(blk_space->blk_ptr, M_NANDSIM); - free(blk_space, M_NANDSIM); - blk_space = STAILQ_FIRST(&swap->used_bs); - } -} - -static int -swap_file_open(struct chip_swap *swap, const char *swap_file) -{ - struct nameidata nd; - int flags, error; - - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, swap_file, - curthread); - - flags = FWRITE | FREAD | O_NOFOLLOW | O_CREAT | O_TRUNC; - - error = vn_open(&nd, &flags, CHIP_SWAP_CMODE, NULL); - if (error) { - nand_debug(NDBG_SIM,"Cannot create swap file %s", swap_file); - NDFREE(&nd, NDF_ONLY_PNBUF); - return (error); - } - - swap->swap_cred = crhold(curthread->td_ucred); - NDFREE(&nd, NDF_ONLY_PNBUF); - - /* We just unlock so we hold a reference */ - VOP_UNLOCK(nd.ni_vp, 0); - - swap->swap_vp = nd.ni_vp; - - return (0); -} - -static void -swap_file_close(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - if (swap->swap_vp == NULL) - return; - - vn_close(swap->swap_vp, FWRITE, swap->swap_cred, curthread); - crfree(swap->swap_cred); -} - -static int -swap_file_write(struct chip_swap *swap, struct block_state *blk_state) -{ - struct block_space *blk_space; - struct thread *td; - struct mount *mp; - struct vnode *vp; - struct uio auio; - struct iovec aiov; - - if (swap == NULL || blk_state == NULL) - return (-1); - - blk_space = blk_state->blk_sp; - if (blk_state->offset == -1) { - blk_state->offset = swap->swap_offset; - swap->swap_offset += swap->blk_size; - } - - nand_debug(NDBG_SIM,"saving %p[%p] at %x\n", - blk_space, blk_space->blk_ptr, blk_state->offset); - - bzero(&aiov, sizeof(aiov)); - bzero(&auio, sizeof(auio)); - - aiov.iov_base = blk_space->blk_ptr; - aiov.iov_len = swap->blk_size; - td = curthread; - vp = swap->swap_vp; - - auio.uio_iov = &aiov; - auio.uio_offset = blk_state->offset; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_iovcnt = 1; - auio.uio_resid = swap->blk_size; - auio.uio_td = td; - - vn_start_write(vp, &mp, V_WAIT); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - VOP_WRITE(vp, &auio, IO_UNIT, swap->swap_cred); - VOP_UNLOCK(vp, 0); - vn_finished_write(mp); - - return (0); -} - -static int -swap_file_read(struct chip_swap *swap, struct block_state *blk_state) -{ - struct block_space *blk_space; - struct thread *td; - struct vnode *vp; - struct uio auio; - struct iovec aiov; - - if (swap == NULL || blk_state == NULL) - return (-1); - - blk_space = blk_state->blk_sp; - - nand_debug(NDBG_SIM,"restore %p[%p] at %x\n", - blk_space, blk_space->blk_ptr, blk_state->offset); - - bzero(&aiov, sizeof(aiov)); - bzero(&auio, sizeof(auio)); - - aiov.iov_base = blk_space->blk_ptr; - aiov.iov_len = swap->blk_size; - td = curthread; - vp = swap->swap_vp; - - auio.uio_iov = &aiov; - auio.uio_offset = blk_state->offset; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_READ; - auio.uio_iovcnt = 1; - auio.uio_resid = swap->blk_size; - auio.uio_td = td; - - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - VOP_READ(vp, &auio, 0, swap->swap_cred); - VOP_UNLOCK(vp, 0); - - return (0); -} - -struct chip_swap * -nandsim_swap_init(const char *swap_file, uint32_t nof_blks, uint32_t blk_size) -{ - struct chip_swap *swap; - int err = 0; - - if ((swap_file == NULL) || (nof_blks == 0) || (blk_size == 0)) - return (NULL); - - swap = malloc(sizeof(*swap), M_NANDSIM, M_WAITOK | M_ZERO); - - SLIST_INIT(&swap->free_bs); - STAILQ_INIT(&swap->used_bs); - swap->blk_size = blk_size; - swap->nof_blks = nof_blks; - - err = init_block_state(swap); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - err = create_buffers(swap); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - err = swap_file_open(swap, swap_file); - if (err) { - nandsim_swap_destroy(swap); - return (NULL); - } - - return (swap); -} - -void -nandsim_swap_destroy(struct chip_swap *swap) -{ - - if (swap == NULL) - return; - - destroy_block_state(swap); - destroy_buffers(swap); - swap_file_close(swap); - free(swap, M_NANDSIM); -} - -struct block_space * -get_bs(struct chip_swap *swap, uint32_t block, uint8_t writing) -{ - struct block_state *blk_state, *old_blk_state = NULL; - struct block_space *blk_space; - - if (swap == NULL || (block >= swap->nof_blks)) - return (NULL); - - blk_state = &swap->blk_state[block]; - nand_debug(NDBG_SIM,"blk_state %x\n", blk_state->status); - - if (blk_state->status & BLOCK_ALLOCATED) { - blk_space = blk_state->blk_sp; - } else { - blk_space = SLIST_FIRST(&swap->free_bs); - if (blk_space) { - SLIST_REMOVE_HEAD(&swap->free_bs, free_link); - STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, - used_link); - } else { - blk_space = STAILQ_FIRST(&swap->used_bs); - old_blk_state = blk_space->blk_state; - STAILQ_REMOVE_HEAD(&swap->used_bs, used_link); - STAILQ_INSERT_TAIL(&swap->used_bs, blk_space, - used_link); - if (old_blk_state->status & BLOCK_DIRTY) { - swap_file_write(swap, old_blk_state); - old_blk_state->status &= ~BLOCK_DIRTY; - old_blk_state->status |= BLOCK_SWAPPED; - } - } - } - - if (blk_space == NULL) - return (NULL); - - if (old_blk_state != NULL) { - old_blk_state->status &= ~BLOCK_ALLOCATED; - old_blk_state->blk_sp = NULL; - } - - blk_state->blk_sp = blk_space; - blk_space->blk_state = blk_state; - - if (!(blk_state->status & BLOCK_ALLOCATED)) { - if (blk_state->status & BLOCK_SWAPPED) - swap_file_read(swap, blk_state); - else - memset(blk_space->blk_ptr, 0xff, swap->blk_size); - blk_state->status |= BLOCK_ALLOCATED; - } - - if (writing) - blk_state->status |= BLOCK_DIRTY; - - nand_debug(NDBG_SIM,"get_bs returned %p[%p] state %x\n", blk_space, - blk_space->blk_ptr, blk_state->status); - - return (blk_space); -} diff --git a/sys/dev/nand/nandsim_swap.h b/sys/dev/nand/nandsim_swap.h deleted file mode 100644 index c9eb0be63a9c..000000000000 --- a/sys/dev/nand/nandsim_swap.h +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NANDSIM_SWAP_CHIP_H_ -#define _NANDSIM_SWAP_CHIP_H_ - -struct block_space { - SLIST_ENTRY(block_space) free_link; - STAILQ_ENTRY(block_space) used_link; - struct block_state *blk_state; - uint8_t *blk_ptr; -}; - -#define BLOCK_ALLOCATED 0x1 -#define BLOCK_SWAPPED 0x2 -#define BLOCK_DIRTY 0x4 - -struct block_state { - struct block_space *blk_sp; - uint32_t offset; - uint8_t status; -}; - -struct chip_swap { - struct block_state *blk_state; - SLIST_HEAD(,block_space) free_bs; - STAILQ_HEAD(,block_space) used_bs; - struct ucred *swap_cred; - struct vnode *swap_vp; - uint32_t swap_offset; - uint32_t blk_size; - uint32_t nof_blks; -}; - -struct chip_swap *nandsim_swap_init(const char *, uint32_t, uint32_t); -void nandsim_swap_destroy(struct chip_swap *); -struct block_space *get_bs(struct chip_swap *, uint32_t, uint8_t); - -#endif /* _NANDSIM_SWAP_CHIP_H_ */ diff --git a/sys/dev/nand/nfc_fsl.c b/sys/dev/nand/nfc_fsl.c deleted file mode 100644 index 992cfeb784fe..000000000000 --- a/sys/dev/nand/nfc_fsl.c +++ /dev/null @@ -1,717 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2012 Juniper Networks, Inc. - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * TODO : - * - * -- test support for small pages - * -- support for reading ONFI parameters - * -- support for cached and interleaving commands - * -- proper setting of AL bits in FMR - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/sysctl.h> -#include <sys/time.h> -#include <sys/kdb.h> - -#include <machine/bus.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <powerpc/mpc85xx/lbc.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> - -#include "nfc_fsl.h" - -#include "nfc_if.h" - -#define LBC_READ(regname) lbc_read_reg(dev, (LBC85XX_ ## regname)) -#define LBC_WRITE(regname, val) lbc_write_reg(dev, (LBC85XX_ ## regname), val) - -enum addr_type { - ADDR_NONE, - ADDR_ID, - ADDR_ROW, - ADDR_ROWCOL -}; - -struct fsl_nfc_fcm { - /* Read-only after initialization */ - uint32_t reg_fmr; - - /* To be preserved across "start_command" */ - u_int buf_ofs; - u_int read_ptr; - u_int status:1; - - /* Command state -- cleared by "start_command" */ - uint32_t fcm_startzero; - uint32_t reg_fcr; - uint32_t reg_fir; - uint32_t reg_mdr; - uint32_t reg_fbcr; - uint32_t reg_fbar; - uint32_t reg_fpar; - u_int cmdnr; - u_int opnr; - u_int pg_ofs; - enum addr_type addr_type; - u_int addr_bytes; - u_int row_addr; - u_int column_addr; - u_int data_fir:8; - uint32_t fcm_endzero; -}; - -struct fsl_nand_softc { - struct nand_softc nand_dev; - device_t dev; - struct resource *res; - int rid; /* Resourceid */ - struct lbc_devinfo *dinfo; - struct fsl_nfc_fcm fcm; - uint8_t col_cycles; - uint8_t row_cycles; - uint16_t pgsz; /* Page size */ -}; - -static int fsl_nand_attach(device_t dev); -static int fsl_nand_probe(device_t dev); -static int fsl_nand_detach(device_t dev); - -static int fsl_nfc_select_cs(device_t dev, uint8_t cs); -static int fsl_nfc_read_rnb(device_t dev); -static int fsl_nfc_send_command(device_t dev, uint8_t command); -static int fsl_nfc_send_address(device_t dev, uint8_t address); -static uint8_t fsl_nfc_read_byte(device_t dev); -static int fsl_nfc_start_command(device_t dev); -static void fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len); -static void fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len); - -static device_method_t fsl_nand_methods[] = { - DEVMETHOD(device_probe, fsl_nand_probe), - DEVMETHOD(device_attach, fsl_nand_attach), - DEVMETHOD(device_detach, fsl_nand_detach), - - DEVMETHOD(nfc_select_cs, fsl_nfc_select_cs), - DEVMETHOD(nfc_read_rnb, fsl_nfc_read_rnb), - DEVMETHOD(nfc_start_command, fsl_nfc_start_command), - DEVMETHOD(nfc_send_command, fsl_nfc_send_command), - DEVMETHOD(nfc_send_address, fsl_nfc_send_address), - DEVMETHOD(nfc_read_byte, fsl_nfc_read_byte), - DEVMETHOD(nfc_read_buf, fsl_nfc_read_buf), - DEVMETHOD(nfc_write_buf, fsl_nfc_write_buf), - { 0, 0 }, -}; - -static driver_t fsl_nand_driver = { - "nand", - fsl_nand_methods, - sizeof(struct fsl_nand_softc), -}; - -static devclass_t fsl_nand_devclass; - -DRIVER_MODULE(fsl_nand, lbc, fsl_nand_driver, fsl_nand_devclass, - 0, 0); - -static int fsl_nand_build_address(device_t dev, uint32_t page, uint32_t column); -static int fsl_nand_chip_preprobe(device_t dev, struct nand_id *id); - -#ifdef NAND_DEBUG_TIMING -static device_t fcm_devs[8]; -#endif - -#define CMD_SHIFT(cmd_num) (24 - ((cmd_num) * 8)) -#define OP_SHIFT(op_num) (28 - ((op_num) * 4)) - -#define FSL_LARGE_PAGE_SIZE (2112) -#define FSL_SMALL_PAGE_SIZE (528) - -static void -fsl_nand_init_regs(struct fsl_nand_softc *sc) -{ - uint32_t or_v, br_v; - device_t dev; - - dev = sc->dev; - - sc->fcm.reg_fmr = (15 << FMR_CWTO_SHIFT); - - /* - * Setup 4 row cycles and hope that chip ignores superfluous address - * bytes. - */ - sc->fcm.reg_fmr |= (2 << FMR_AL_SHIFT); - - /* Reprogram BR(x) */ - br_v = lbc_read_reg(dev, LBC85XX_BR(sc->dinfo->di_bank)); - br_v &= 0xffff8000; - br_v |= 1 << 11; /* 8-bit port size */ - br_v |= 0 << 9; /* No ECC checking and generation */ - br_v |= 1 << 5; /* FCM machine */ - br_v |= 1; /* Valid */ - lbc_write_reg(dev, LBC85XX_BR(sc->dinfo->di_bank), br_v); - - /* Reprogram OR(x) */ - or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); - or_v &= 0xfffffc00; - or_v |= 0x03AE; /* Default POR timing */ - lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); - - if (or_v & OR_FCM_PAGESIZE) { - sc->pgsz = FSL_LARGE_PAGE_SIZE; - sc->col_cycles = 2; - nand_debug(NDBG_DRV, "%s: large page NAND device at #%d", - device_get_nameunit(dev), sc->dinfo->di_bank); - } else { - sc->pgsz = FSL_SMALL_PAGE_SIZE; - sc->col_cycles = 1; - nand_debug(NDBG_DRV, "%s: small page NAND device at #%d", - device_get_nameunit(dev), sc->dinfo->di_bank); - } -} - -static int -fsl_nand_probe(device_t dev) -{ - - if (!ofw_bus_is_compatible(dev, "fsl,elbc-fcm-nand")) - return (ENXIO); - - device_set_desc(dev, "Freescale localbus FCM Controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -fsl_nand_attach(device_t dev) -{ - struct fsl_nand_softc *sc; - struct nand_id id; - struct nand_params *param; - uint32_t num_pages; - - sc = device_get_softc(dev); - sc->dev = dev; - sc->dinfo = device_get_ivars(dev); - - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - bzero(&sc->fcm, sizeof(sc->fcm)); - - /* Init register and check if HW ECC turned on */ - fsl_nand_init_regs(sc); - - /* Chip is probed, so determine number of row address cycles */ - fsl_nand_chip_preprobe(dev, &id); - param = nand_get_params(&id); - if (param != NULL) { - num_pages = (param->chip_size << 20) / param->page_size; - while(num_pages) { - sc->row_cycles++; - num_pages >>= 8; - } - - sc->fcm.reg_fmr &= ~(FMR_AL); - sc->fcm.reg_fmr |= (sc->row_cycles - 2) << FMR_AL_SHIFT; - } - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - -#ifdef NAND_DEBUG_TIMING - fcm_devs[sc->dinfo->di_bank] = dev; -#endif - - return (nandbus_create(dev)); -} - -static int -fsl_nand_detach(device_t dev) -{ - struct fsl_nand_softc *sc; - - sc = device_get_softc(dev); - - if (sc->res != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); - - return (0); -} - -static int -fsl_nfc_select_cs(device_t dev, uint8_t cs) -{ - - // device_printf(dev, "%s(cs=%u)\n", __func__, cs); - return ((cs > 0) ? EINVAL : 0); -} - -static int -fsl_nfc_read_rnb(device_t dev) -{ - - // device_printf(dev, "%s()\n", __func__); - return (0); -} - -static int -fsl_nfc_send_command(device_t dev, uint8_t command) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint8_t fir_op; - - // device_printf(dev, "%s(command=%u)\n", __func__, command); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - if (command == NAND_CMD_PROG_END) { - fcm->reg_fir |= (FIR_OP_WB << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - } - fcm->reg_fcr |= command << CMD_SHIFT(fcm->cmdnr); - fir_op = (fcm->cmdnr == 0) ? FIR_OP_CW0 : FIR_OP_CM(fcm->cmdnr); - fcm->cmdnr++; - - fcm->reg_fir |= (fir_op << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - switch (command) { - case NAND_CMD_READ_ID: - fcm->data_fir = FIR_OP_RBW; - fcm->addr_type = ADDR_ID; - break; - case NAND_CMD_SMALLOOB: - fcm->pg_ofs += 256; - /*FALLTHROUGH*/ - case NAND_CMD_SMALLB: - fcm->pg_ofs += 256; - /*FALLTHROUGH*/ - case NAND_CMD_READ: /* NAND_CMD_SMALLA */ - fcm->data_fir = FIR_OP_RBW; - fcm->addr_type = ADDR_ROWCOL; - break; - case NAND_CMD_STATUS: - fcm->data_fir = FIR_OP_RS; - fcm->status = 1; - break; - case NAND_CMD_ERASE: - fcm->addr_type = ADDR_ROW; - break; - case NAND_CMD_PROG: - fcm->addr_type = ADDR_ROWCOL; - break; - } - return (0); -} - -static int -fsl_nfc_send_address(device_t dev, uint8_t addr) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t addr_bits; - - // device_printf(dev, "%s(address=%u)\n", __func__, addr); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - KASSERT(fcm->addr_type != ADDR_NONE, - ("controller doesn't expect address cycle")); - - addr_bits = addr; - - if (fcm->addr_type == ADDR_ID) { - fcm->reg_fir |= (FIR_OP_UA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - fcm->reg_fbcr = 5; - fcm->reg_fbar = 0; - fcm->reg_fpar = 0; - fcm->reg_mdr = addr_bits; - fcm->buf_ofs = 0; - fcm->read_ptr = 0; - return (0); - } - - if (fcm->addr_type == ADDR_ROW) { - addr_bits <<= fcm->addr_bytes * 8; - fcm->row_addr |= addr_bits; - fcm->addr_bytes++; - if (fcm->addr_bytes < sc->row_cycles) - return (0); - } else { - if (fcm->addr_bytes < sc->col_cycles) { - addr_bits <<= fcm->addr_bytes * 8; - fcm->column_addr |= addr_bits; - } else { - addr_bits <<= (fcm->addr_bytes - sc->col_cycles) * 8; - fcm->row_addr |= addr_bits; - } - fcm->addr_bytes++; - if (fcm->addr_bytes < (sc->row_cycles + sc->col_cycles)) - return (0); - } - - return (fsl_nand_build_address(dev, fcm->row_addr, fcm->column_addr)); -} - -static int -fsl_nand_build_address(device_t dev, uint32_t row, uint32_t column) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t byte_count = 0; - uint32_t block_address = 0; - uint32_t page_address = 0; - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - fcm->read_ptr = 0; - fcm->buf_ofs = 0; - - if (fcm->addr_type == ADDR_ROWCOL) { - fcm->reg_fir |= (FIR_OP_CA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - column += fcm->pg_ofs; - fcm->pg_ofs = 0; - - page_address |= column; - - if (column != 0) { - byte_count = sc->pgsz - column; - fcm->read_ptr = column; - } - } - - fcm->reg_fir |= (FIR_OP_PA << OP_SHIFT(fcm->opnr)); - fcm->opnr++; - - if (sc->pgsz == FSL_LARGE_PAGE_SIZE) { - block_address = row >> 6; - page_address |= ((row << FPAR_LP_PI_SHIFT) & FPAR_LP_PI); - fcm->buf_ofs = (row & 1) * 4096; - } else { - block_address = row >> 5; - page_address |= ((row << FPAR_SP_PI_SHIFT) & FPAR_SP_PI); - fcm->buf_ofs = (row & 7) * 1024; - } - - fcm->reg_fbcr = byte_count; - fcm->reg_fbar = block_address; - fcm->reg_fpar = page_address; - return (0); -} - -static int -fsl_nfc_start_command(device_t dev) -{ - struct fsl_nand_softc *sc; - struct fsl_nfc_fcm *fcm; - uint32_t fmr, ltesr_v; - int error, timeout; - - // device_printf(dev, "%s()\n", __func__); - - sc = device_get_softc(dev); - fcm = &sc->fcm; - - fmr = fcm->reg_fmr | FMR_OP; - - if (fcm->data_fir) - fcm->reg_fir |= (fcm->data_fir << OP_SHIFT(fcm->opnr)); - - LBC_WRITE(FIR, fcm->reg_fir); - LBC_WRITE(FCR, fcm->reg_fcr); - - LBC_WRITE(FMR, fmr); - - LBC_WRITE(FBCR, fcm->reg_fbcr); - LBC_WRITE(FBAR, fcm->reg_fbar); - LBC_WRITE(FPAR, fcm->reg_fpar); - - if (fcm->addr_type == ADDR_ID) - LBC_WRITE(MDR, fcm->reg_mdr); - - nand_debug(NDBG_DRV, "BEFORE:\nFMR=%#x, FIR=%#x, FCR=%#x", fmr, - fcm->reg_fir, fcm->reg_fcr); - nand_debug(NDBG_DRV, "MDR=%#x, FBAR=%#x, FPAR=%#x, FBCR=%#x", - LBC_READ(MDR), fcm->reg_fbar, fcm->reg_fpar, fcm->reg_fbcr); - - LBC_WRITE(LSOR, sc->dinfo->di_bank); - - timeout = (cold) ? FSL_FCM_WAIT_TIMEOUT : ~0; - error = 0; - ltesr_v = LBC_READ(LTESR); - while (!error && (ltesr_v & LTESR_CC) == 0) { - if (cold) { - DELAY(1000); - timeout--; - if (timeout < 0) - error = EWOULDBLOCK; - } else - error = tsleep(device_get_parent(sc->dev), PRIBIO, - "nfcfsl", hz); - ltesr_v = LBC_READ(LTESR); - } - if (error) - nand_debug(NDBG_DRV, "Command complete wait timeout\n"); - - nand_debug(NDBG_DRV, "AFTER:\nLTESR=%#x, LTEDR=%#x, LTEIR=%#x," - " LTEATR=%#x, LTEAR=%#x, LTECCR=%#x", ltesr_v, - LBC_READ(LTEDR), LBC_READ(LTEIR), LBC_READ(LTEATR), - LBC_READ(LTEAR), LBC_READ(LTECCR)); - - bzero(&fcm->fcm_startzero, - __rangeof(struct fsl_nfc_fcm, fcm_startzero, fcm_endzero)); - - if (fcm->status) - sc->fcm.reg_mdr = LBC_READ(MDR); - - /* Even if timeout occurred, we should perform steps below */ - LBC_WRITE(LTESR, ltesr_v); - LBC_WRITE(LTEATR, 0); - - return (error); -} - -static uint8_t -fsl_nfc_read_byte(device_t dev) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - - // device_printf(dev, "%s()\n", __func__); - - /* - * LBC controller allows us to read status into a MDR instead of FCM - * buffer. If last operation requested before read_byte() was STATUS, - * then return MDR instead of reading a single byte from a buffer. - */ - if (sc->fcm.status) { - sc->fcm.status = 0; - return (sc->fcm.reg_mdr); - } - - KASSERT(sc->fcm.read_ptr < sc->pgsz, - ("Attempt to read beyond buffer %x %x", sc->fcm.read_ptr, - sc->pgsz)); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - sc->fcm.read_ptr++; - return (bus_read_1(sc->res, offset)); -} - -static void -fsl_nfc_read_buf(device_t dev, void *buf, uint32_t len) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - int bytesleft = 0; - - // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len); - - nand_debug(NDBG_DRV, "REQUEST OF 0x%0x B (BIB=0x%0x, NTR=0x%0x)", - len, sc->pgsz, sc->fcm.read_ptr); - - bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - bus_read_region_1(sc->res, offset, buf, bytesleft); - sc->fcm.read_ptr += bytesleft; -} - -static void -fsl_nfc_write_buf(device_t dev, void *buf, uint32_t len) -{ - struct fsl_nand_softc *sc = device_get_softc(dev); - uint32_t offset; - int bytesleft = 0; - - // device_printf(dev, "%s(buf=%p, len=%u)\n", __func__, buf, len); - - KASSERT(len <= sc->pgsz - sc->fcm.read_ptr, - ("Attempt to write beyond buffer")); - - bytesleft = MIN((unsigned int)len, sc->pgsz - sc->fcm.read_ptr); - - nand_debug(NDBG_DRV, "REQUEST TO WRITE 0x%0x (BIB=0x%0x, NTR=0x%0x)", - bytesleft, sc->pgsz, sc->fcm.read_ptr); - - offset = sc->fcm.buf_ofs + sc->fcm.read_ptr; - bus_write_region_1(sc->res, offset, buf, bytesleft); - sc->fcm.read_ptr += bytesleft; -} - -static int -fsl_nand_chip_preprobe(device_t dev, struct nand_id *id) -{ - - if (fsl_nfc_send_command(dev, NAND_CMD_RESET) != 0) - return (ENXIO); - - if (fsl_nfc_start_command(dev) != 0) - return (ENXIO); - - DELAY(1000); - - if (fsl_nfc_send_command(dev, NAND_CMD_READ_ID)) - return (ENXIO); - - if (fsl_nfc_send_address(dev, 0)) - return (ENXIO); - - if (fsl_nfc_start_command(dev) != 0) - return (ENXIO); - - DELAY(25); - - id->man_id = fsl_nfc_read_byte(dev); - id->dev_id = fsl_nfc_read_byte(dev); - - nand_debug(NDBG_DRV, "manufacturer id: %x chip id: %x", - id->man_id, id->dev_id); - - return (0); -} - -#ifdef NAND_DEBUG_TIMING - -static SYSCTL_NODE(_debug, OID_AUTO, fcm, CTLFLAG_RD, 0, "FCM timing"); - -static u_int csct = 1; /* 22: Chip select to command time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, csct, CTLFLAG_RW, &csct, 1, - "Chip select to command time: determines how far in advance -LCSn is " - "asserted prior to any bus activity during a NAND Flash access handled " - "by the FCM. This helps meet chip-select setup times for slow memories."); - -static u_int cst = 1; /* 23: Command setup time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, cst, CTLFLAG_RW, &cst, 1, - "Command setup time: determines the delay of -LFWE assertion relative to " - "the command, address, or data change when the external memory access " - "is handled by the FCM."); - -static u_int cht = 1; /* 24: Command hold time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, cht, CTLFLAG_RW, &cht, 1, - "Command hold time: determines the -LFWE negation prior to the command, " - "address, or data change when the external memory access is handled by " - "the FCM."); - -static u_int scy = 2; /* 25-27: Cycle length in bus clocks */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, scy, CTLFLAG_RW, &scy, 2, - "Cycle length in bus clocks: see RM"); - -static u_int rst = 1; /* 28: Read setup time (trlx). */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, rst, CTLFLAG_RW, &rst, 1, - "Read setup time: determines the delay of -LFRE assertion relative to " - "sampling of read data when the external memory access is handled by " - "the FCM."); - -static u_int trlx = 1; /* 29: Timing relaxed. */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, trlx, CTLFLAG_RW, &trlx, 1, - "Timing relaxed: modifies the settings of timing parameters for slow " - "memories. See RM"); - -static u_int ehtr = 1; /* 30: Extended hold time on read accesses. */ -SYSCTL_UINT(_debug_fcm, OID_AUTO, ehtr, CTLFLAG_RW, &ehtr, 1, - "Extended hold time on read accesses: indicates with TRLX how many " - "cycles are inserted between a read access from the current bank and " - "the next access."); - -static u_int -fsl_nand_get_timing(void) -{ - u_int timing; - - timing = ((csct & 1) << 9) | ((cst & 1) << 8) | ((cht & 1) << 7) | - ((scy & 7) << 4) | ((rst & 1) << 3) | ((trlx & 1) << 2) | - ((ehtr & 1) << 1); - - printf("nfc_fsl: timing = %u\n", timing); - return (timing); -} - -static int -fsl_sysctl_program(SYSCTL_HANDLER_ARGS) -{ - struct fsl_nand_softc *sc; - int error, i; - device_t dev; - uint32_t or_v; - - error = sysctl_wire_old_buffer(req, sizeof(int)); - if (error == 0) { - i = 0; - error = sysctl_handle_int(oidp, &i, 0, req); - } - if (error != 0 || req->newptr == NULL) - return (error); - - for (i = 0; i < 8; i++) { - dev = fcm_devs[i]; - if (dev == NULL) - continue; - sc = device_get_softc(dev); - - /* Reprogram OR(x) */ - or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); - or_v &= 0xfffffc00; - or_v |= fsl_nand_get_timing(); - lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); - } - return (0); -} - -SYSCTL_PROC(_debug_fcm, OID_AUTO, program, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, - fsl_sysctl_program, "I", "write to program FCM with current values"); - -#endif /* NAND_DEBUG_TIMING */ diff --git a/sys/dev/nand/nfc_fsl.h b/sys/dev/nand/nfc_fsl.h deleted file mode 100644 index 5410da558171..000000000000 --- a/sys/dev/nand/nfc_fsl.h +++ /dev/null @@ -1,99 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2012 Juniper Networks, Inc. - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _NAND_NFC_FSL_H_ -#define _NAND_NFC_FSL_H_ - -/* LBC BR/OR Registers layout definitions */ -#define BR_V 0x00000001 -#define BR_V_SHIFT 0 -#define BR_MSEL 0x000000E0 -#define BR_MSEL_SHIFT 5 -#define BR_DECC_CHECK_MODE 0x00000600 -#define BR_DECC_CHECK_GEN 0x00000400 - -#define OR_FCM_PAGESIZE 0x00000400 - -/* Options definitions */ -#define NAND_OPT_ECC_MODE_HW 1 -#define NAND_OPT_ECC_MODE_SOFT (1 << 1) - -/* FMR - Flash Mode Register */ -#define FMR_CWTO 0xF000 -#define FMR_CWTO_SHIFT 12 -#define FMR_BOOT 0x0800 -#define FMR_ECCM 0x0100 -#define FMR_AL 0x0030 -#define FMR_AL_SHIFT 4 -#define FMR_OP 0x0003 -#define FMR_OP_SHIFT 0 - -#define FIR_OP_NOP 0x0 /* No operation and end of sequence */ -#define FIR_OP_CA 0x1 /* Issue current column address */ -#define FIR_OP_PA 0x2 /* Issue current block+page address */ -#define FIR_OP_UA 0x3 /* Issue user defined address */ -#define FIR_OP_CM(x) (4 + (x)) /* Issue command from FCR[CMD(x)] */ -#define FIR_OP_WB 0x8 /* Write FBCR bytes from FCM buffer */ -#define FIR_OP_WS 0x9 /* Write 1 or 2 bytes from MDR[AS] */ -#define FIR_OP_RB 0xA /* Read FBCR bytes to FCM buffer */ -#define FIR_OP_RS 0xB /* Read 1 or 2 bytes to MDR[AS] */ -#define FIR_OP_CW0 0xC /* Wait then issue FCR[CMD0] */ -#define FIR_OP_CW1 0xD /* Wait then issue FCR[CMD1] */ -#define FIR_OP_RBW 0xE /* Wait then read FBCR bytes */ -#define FIR_OP_RSW 0xF /* Wait then read 1 or 2 bytes */ - -/* LTESR - Transfer Error Status Register */ -#define LTESR_BM 0x80000000 -#define LTESR_FCT 0x40000000 -#define LTESR_PAR 0x20000000 -#define LTESR_WP 0x04000000 -#define LTESR_ATMW 0x00800000 -#define LTESR_ATMR 0x00400000 -#define LTESR_CS 0x00080000 -#define LTESR_CC 0x00000001 - -#define LTESR_NAND_MASK (LTESR_FCT | LTESR_CC | LTESR_CS) - -/* FPAR - Flash Page Address Register */ -#define FPAR_SP_PI 0x00007C00 -#define FPAR_SP_PI_SHIFT 10 -#define FPAR_SP_MS 0x00000200 -#define FPAR_SP_CI 0x000001FF -#define FPAR_SP_CI_SHIFT 0 -#define FPAR_LP_PI 0x0003F000 -#define FPAR_LP_PI_SHIFT 12 -#define FPAR_LP_MS 0x00000800 -#define FPAR_LP_CI 0x000007FF -#define FPAR_LP_CI_SHIFT 0 - -#define FSL_FCM_WAIT_TIMEOUT 10 - -#endif /* _NAND_NFC_FSL_H_ */ diff --git a/sys/dev/nand/nfc_if.m b/sys/dev/nand/nfc_if.m deleted file mode 100644 index a4e1099220ac..000000000000 --- a/sys/dev/nand/nfc_if.m +++ /dev/null @@ -1,165 +0,0 @@ -#- -# Copyright (C) 2009-2012 Semihalf -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $FreeBSD$ - -# NAND controller interface description -# - -#include <sys/bus.h> -#include <dev/nand/nand.h> - -INTERFACE nfc; - -CODE { - static int nfc_default_method(device_t dev) - { - return (0); - } - - static int nfc_softecc_get(device_t dev, void *buf, int pagesize, - void *ecc, int *needwrite) - { - *needwrite = 1; - return (nand_softecc_get(dev, buf, pagesize, ecc)); - } - - static int nfc_softecc_correct(device_t dev, void *buf, int pagesize, - void *readecc, void *calcecc) - { - return (nand_softecc_correct(dev, buf, pagesize, readecc, - calcecc)); - } -}; - -# Send command to a NAND chip -# -# Return values: -# 0: Success -# -METHOD int send_command { - device_t dev; - uint8_t command; -}; - -# Send address to a NAND chip -# -# Return values: -# 0: Success -# -METHOD int send_address { - device_t dev; - uint8_t address; -}; - -# Read byte -# -# Return values: -# byte read -# -METHOD uint8_t read_byte { - device_t dev; -}; - -# Write byte -# -METHOD void write_byte { - device_t dev; - uint8_t byte; -}; - -# Read word -# -# Return values: -# word read -# -METHOD uint16_t read_word { - device_t dev; -}; - -# Write word -# -METHOD void write_word { - device_t dev; - uint16_t word; -}; - -# Read buf -# -METHOD void read_buf { - device_t dev; - void *buf; - uint32_t len; -}; - -# Write buf -# -METHOD void write_buf { - device_t dev; - void *buf; - uint32_t len; -}; - -# Select CS -# -METHOD int select_cs { - device_t dev; - uint8_t cs; -}; - -# Read ready/busy signal -# -METHOD int read_rnb { - device_t dev; -}; - -# Start command -# -# Return values: -# 0: Success -# -METHOD int start_command { - device_t dev; -} DEFAULT nfc_default_method; - -# Generate ECC or get it from H/W -# -METHOD int get_ecc { - device_t dev; - void *buf; - int pagesize; - void *ecc; - int *needwrite; -} DEFAULT nfc_softecc_get; - -# Correct ECC -# -METHOD int correct_ecc { - device_t dev; - void *buf; - int pagesize; - void *readecc; - void *calcecc; -} DEFAULT nfc_softecc_correct; diff --git a/sys/dev/nand/nfc_mv.c b/sys/dev/nand/nfc_mv.c deleted file mode 100644 index 0d78d34d9912..000000000000 --- a/sys/dev/nand/nfc_mv.c +++ /dev/null @@ -1,238 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (C) 2009-2012 Semihalf - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* Integrated NAND controller driver */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/time.h> - -#include <machine/bus.h> -#include <machine/fdt.h> -#include <arm/mv/mvvar.h> -#include <arm/mv/mvwin.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> -#include "nfc_if.h" - -#define MV_NAND_DATA (0x00) -#define MV_NAND_COMMAND (0x01) -#define MV_NAND_ADDRESS (0x02) - -struct mv_nand_softc { - struct nand_softc nand_dev; - bus_space_handle_t sc_handle; - bus_space_tag_t sc_tag; - struct resource *res; - int rid; -}; - -static int mv_nand_attach(device_t); -static int mv_nand_probe(device_t); -static int mv_nand_send_command(device_t, uint8_t); -static int mv_nand_send_address(device_t, uint8_t); -static uint8_t mv_nand_read_byte(device_t); -static void mv_nand_read_buf(device_t, void *, uint32_t); -static void mv_nand_write_buf(device_t, void *, uint32_t); -static int mv_nand_select_cs(device_t, uint8_t); -static int mv_nand_read_rnb(device_t); - -static device_method_t mv_nand_methods[] = { - DEVMETHOD(device_probe, mv_nand_probe), - DEVMETHOD(device_attach, mv_nand_attach), - - DEVMETHOD(nfc_send_command, mv_nand_send_command), - DEVMETHOD(nfc_send_address, mv_nand_send_address), - DEVMETHOD(nfc_read_byte, mv_nand_read_byte), - DEVMETHOD(nfc_read_buf, mv_nand_read_buf), - DEVMETHOD(nfc_write_buf, mv_nand_write_buf), - DEVMETHOD(nfc_select_cs, mv_nand_select_cs), - DEVMETHOD(nfc_read_rnb, mv_nand_read_rnb), - - { 0, 0 }, -}; - -static driver_t mv_nand_driver = { - "nand", - mv_nand_methods, - sizeof(struct mv_nand_softc), -}; - -static devclass_t mv_nand_devclass; -DRIVER_MODULE(mv_nand, localbus, mv_nand_driver, mv_nand_devclass, 0, 0); - -static int -mv_nand_probe(device_t dev) -{ - - if (!ofw_bus_is_compatible(dev, "mrvl,nfc")) - return (ENXIO); - - device_set_desc(dev, "Marvell NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -mv_nand_attach(device_t dev) -{ - struct mv_nand_softc *sc; - int err; - - sc = device_get_softc(dev); - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - sc->sc_tag = rman_get_bustag(sc->res); - sc->sc_handle = rman_get_bushandle(sc->res); - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - - err = nandbus_create(dev); - - return (err); -} - -static int -mv_nand_send_command(device_t dev, uint8_t command) -{ - struct mv_nand_softc *sc; - - nand_debug(NDBG_DRV,"mv_nand: send command %x", command); - - sc = device_get_softc(dev); - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_COMMAND, command); - return (0); -} - -static int -mv_nand_send_address(device_t dev, uint8_t addr) -{ - struct mv_nand_softc *sc; - - nand_debug(NDBG_DRV,"mv_nand: send address %x", addr); - - sc = device_get_softc(dev); - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_ADDRESS, addr); - return (0); -} - -static uint8_t -mv_nand_read_byte(device_t dev) -{ - struct mv_nand_softc *sc; - uint8_t data; - - sc = device_get_softc(dev); - data = bus_space_read_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA); - - nand_debug(NDBG_DRV,"mv_nand: read %x", data); - - return (data); -} - -static void -mv_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct mv_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { - b[i] = bus_space_read_1(sc->sc_tag, sc->sc_handle, - MV_NAND_DATA); -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "mv_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - } -} - -static void -mv_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct mv_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "mv_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - bus_space_write_1(sc->sc_tag, sc->sc_handle, MV_NAND_DATA, - b[i]); - } -} - -static int -mv_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -mv_nand_read_rnb(device_t dev) -{ - - /* no-op */ - return (0); /* ready */ -} diff --git a/sys/dev/nand/nfc_rb.c b/sys/dev/nand/nfc_rb.c deleted file mode 100644 index 1102b3abb9c4..000000000000 --- a/sys/dev/nand/nfc_rb.c +++ /dev/null @@ -1,321 +0,0 @@ -/*- - * Copyright (C) 2015 Justin Hibbits - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* RouterBoard 600/800 NAND controller driver. */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/slicer.h> - -#include <geom/geom_disk.h> - -#include <machine/bus.h> - -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <dev/nand/nand.h> -#include <dev/nand/nandbus.h> - -#include <powerpc/mpc85xx/mpc85xx.h> - -#include "nfc_if.h" -#include "gpio_if.h" - -#define RB_NAND_DATA (0x00) - -struct rb_nand_softc { - struct nand_softc nand_dev; - struct resource *sc_mem; - int rid; - device_t sc_gpio; - uint32_t sc_rdy_pin; - uint32_t sc_nce_pin; - uint32_t sc_cle_pin; - uint32_t sc_ale_pin; -}; - -static int rb_nand_attach(device_t); -static int rb_nand_probe(device_t); -static int rb_nand_send_command(device_t, uint8_t); -static int rb_nand_send_address(device_t, uint8_t); -static uint8_t rb_nand_read_byte(device_t); -static void rb_nand_read_buf(device_t, void *, uint32_t); -static void rb_nand_write_buf(device_t, void *, uint32_t); -static int rb_nand_select_cs(device_t, uint8_t); -static int rb_nand_read_rnb(device_t); - -static device_method_t rb_nand_methods[] = { - DEVMETHOD(device_probe, rb_nand_probe), - DEVMETHOD(device_attach, rb_nand_attach), - - DEVMETHOD(nfc_send_command, rb_nand_send_command), - DEVMETHOD(nfc_send_address, rb_nand_send_address), - DEVMETHOD(nfc_read_byte, rb_nand_read_byte), - DEVMETHOD(nfc_read_buf, rb_nand_read_buf), - DEVMETHOD(nfc_write_buf, rb_nand_write_buf), - DEVMETHOD(nfc_select_cs, rb_nand_select_cs), - DEVMETHOD(nfc_read_rnb, rb_nand_read_rnb), - - { 0, 0 }, -}; - -static driver_t rb_nand_driver = { - "nand", - rb_nand_methods, - sizeof(struct rb_nand_softc), -}; - -static devclass_t rb_nand_devclass; -DRIVER_MODULE(rb_nand, ofwbus, rb_nand_driver, rb_nand_devclass, 0, 0); - -#if 0 -static const struct nand_ecc_data rb_ecc = { - .eccsize = 6, - .eccmode = NAND_ECC_SOFT, - .eccbytes = 6, - .eccpositions = { 8, 9, 10, 13, 14, 15 }, -}; -#endif - -/* Slicer operates on the NAND controller, so we have to find the chip. */ -static int -rb_nand_slicer(device_t dev, const char *provider __unused, - struct flash_slice *slices, int *nslices) -{ - struct nand_chip *chip; - device_t *children; - int n; - - if (device_get_children(dev, &children, &n) != 0) { - panic("Slicer called on controller with no child!"); - } - dev = children[0]; - free(children, M_TEMP); - - if (device_get_children(dev, &children, &n) != 0) { - panic("Slicer called on controller with nandbus but no child!"); - } - dev = children[0]; - free(children, M_TEMP); - - chip = device_get_softc(dev); - *nslices = 2; - slices[0].base = 0; - slices[0].size = 4 * 1024 * 1024; - slices[0].label = "boot"; - - slices[1].base = 4 * 1024 * 1024; - slices[1].size = chip->ndisk->d_mediasize - slices[0].size; - slices[1].label = "rootfs"; - - return (0); -} - -static int -rb_nand_probe(device_t dev) -{ - const char *device_type; - - device_type = ofw_bus_get_type(dev); - - if (!device_type || strcmp(device_type, "rb,nand")) - return (ENXIO); - - device_set_desc(dev, "RouterBoard 333/600/800 NAND controller"); - return (BUS_PROBE_DEFAULT); -} - -static int -rb_nand_attach(device_t dev) -{ - struct rb_nand_softc *sc; - phandle_t node; - uint32_t ale[2],cle[2],nce[2],rdy[2]; - u_long size,start; - int err; - - sc = device_get_softc(dev); - node = ofw_bus_get_node(dev); - - if (OF_getprop(node, "ale", ale, sizeof(ale)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "cle", cle, sizeof(cle)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "nce", nce, sizeof(nce)) <= 0) { - return (ENXIO); - } - if (OF_getprop(node, "rdy", rdy, sizeof(rdy)) <= 0) { - return (ENXIO); - } - - if (ale[0] != cle[0] || ale[0] != nce[0] || ale[0] != rdy[0]) { - device_printf(dev, "GPIO handles for signals must match.\n"); - return (ENXIO); - } - sc->sc_ale_pin = ale[1]; - sc->sc_cle_pin = cle[1]; - sc->sc_nce_pin = nce[1]; - sc->sc_rdy_pin = rdy[1]; - - sc->sc_gpio = OF_device_from_xref(ale[0]); - if (sc->sc_gpio == NULL) { - device_printf(dev, "No GPIO resource found!\n"); - return (ENXIO); - } - - sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, - RF_ACTIVE); - if (sc->sc_mem == NULL) { - device_printf(dev, "could not allocate resources!\n"); - return (ENXIO); - } - - start = rman_get_start(sc->sc_mem); - size = rman_get_size(sc->sc_mem); - if (law_enable(OCP85XX_TGTIF_LBC, start, size) != 0) { - bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->sc_mem); - device_printf(dev, "could not allocate local address window.\n"); - return (ENXIO); - } - - flash_register_slicer(rb_nand_slicer, FLASH_SLICES_TYPE_NAND, TRUE); - - nand_init(&sc->nand_dev, dev, NAND_ECC_SOFT, 0, 0, NULL, NULL); - - err = nandbus_create(dev); - - return (err); -} - -static int -rb_nand_send_command(device_t dev, uint8_t command) -{ - struct rb_nand_softc *sc; - - nand_debug(NDBG_DRV,"rb_nand: send command %x", command); - - sc = device_get_softc(dev); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 1); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 0); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_nce_pin, 0); - bus_write_1(sc->sc_mem, RB_NAND_DATA, command); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 0); - return (0); -} - -static int -rb_nand_send_address(device_t dev, uint8_t addr) -{ - struct rb_nand_softc *sc; - - nand_debug(NDBG_DRV,"rb_nand: send address %x", addr); - - sc = device_get_softc(dev); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_cle_pin, 0); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 1); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_nce_pin, 0); - bus_write_1(sc->sc_mem, RB_NAND_DATA, addr); - GPIO_PIN_SET(sc->sc_gpio, sc->sc_ale_pin, 0); - return (0); -} - -static uint8_t -rb_nand_read_byte(device_t dev) -{ - struct rb_nand_softc *sc; - uint8_t data; - - sc = device_get_softc(dev); - data = bus_read_1(sc->sc_mem, RB_NAND_DATA); - - nand_debug(NDBG_DRV,"rb_nand: read %x", data); - - return (data); -} - -static void -rb_nand_read_buf(device_t dev, void* buf, uint32_t len) -{ - struct rb_nand_softc *sc; - - sc = device_get_softc(dev); - - bus_read_region_1(sc->sc_mem, RB_NAND_DATA, buf, len); -} - -static void -rb_nand_write_buf(device_t dev, void* buf, uint32_t len) -{ - struct rb_nand_softc *sc; - int i; - uint8_t *b = (uint8_t*)buf; - - sc = device_get_softc(dev); - - for (i = 0; i < len; i++) { -#ifdef NAND_DEBUG - if (!(i % 16)) - printf("%s", i == 0 ? "rb_nand:\n" : "\n"); - printf(" %x", b[i]); - if (i == len - 1) - printf("\n"); -#endif - bus_write_1(sc->sc_mem, RB_NAND_DATA, b[i]); - } -} - -static int -rb_nand_select_cs(device_t dev, uint8_t cs) -{ - - if (cs > 0) - return (ENODEV); - - return (0); -} - -static int -rb_nand_read_rnb(device_t dev) -{ - struct rb_nand_softc *sc; - uint32_t rdy_bit; - - sc = device_get_softc(dev); - GPIO_PIN_GET(sc->sc_gpio, sc->sc_rdy_pin, &rdy_bit); - - return (rdy_bit); /* ready */ -} |
