📄 chipio.c
字号:
/* * $QNXLicenseC: * Copyright 2007, QNX Software Systems. * * Licensed under the Apache License, Version 2.0 (the "License"). You * may not reproduce, modify or distribute this software except in * compliance with the License. You may obtain a copy of the License * at: http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * * This file may contain contributions from others, either as * contributors under the License or as licensors under other terms. * Please review this entire file for other proprietary rights or license * notices, as well as the QNX Development Suite License Guide at * http://licensing.qnx.com/license-guide/ for other information. * $ */#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <sys/slog.h>#include <sys/mman.h>#include <sys/neutrino.h>#include <hw/inout.h>#include <fs/etfs.h>#include <string.h>struct chipio;#define CHIPIO struct chipio#include "devio.h"#define COGNAC_NAND_BUF 3 /* Only buffer 3 can be used because we boot from NAND *//* * Device specific data structure for the Freescale i.mx31ads, with 528 byte NAND pages. */struct chipio { struct _chipio chip; uint32_t phys_base; uintptr_t io_base; uintptr_t reg_base; uint32_t data; uint32_t spare; uint32_t hwecc;} chipio;intmain(int argc, char *argv[]){ return (etfs_main(argc, argv));}/* * Process device specific options (if any). * This is always called before any access to the part. * It is called by the -D option to the filesystem. If no -D option is given * this function will still be called with "" for optstr. */int devio_options(struct etfs_devio *dev, char *optstr) { struct chipio *cio; char *value; static char *opts[] ={ "use", // 0 "addr", // 1 "ecc", // 2 NULL } ; cio = dev->cio = &chipio; /* Default NANDC base address for i.MX21. */ cio->phys_base = 0xDF003000; /* Bypass hardware ECC auto correction */ cio->hwecc = 0; while (*optstr) { switch (getsubopt(&optstr, opts, &value)) { case 0: fprintf(stderr, "Device specific options:\n"); fprintf(stderr, " -D use,ecc,addr=xxxx\n"); return (-1); case 1: cio->phys_base = strtol(value, NULL, 16); break; case 2: cio->hwecc = 1; break; default: dev->log(_SLOG_ERROR, "Invalid -D suboption."); return (EINVAL); } } return (EOK);}/* * Called once at startup */intnand_init(struct etfs_devio *dev) { struct chipio *cio = dev->cio; /* Map in the device registers */ cio->io_base = mmap_device_io(0x1000, cio->phys_base); if (cio->io_base == (uintptr_t) MAP_FAILED) dev->log(_SLOG_CRITICAL, "Unable to map in device registers (%d).", errno); cio->data = cio->io_base + 0x600; cio->spare = cio->io_base + 0x830; cio->reg_base = cio->io_base + 0xE00; /* unlock the internal RAM buffer */ out16(cio->reg_base + 0x0A, 0x02); /* set up configuration bits */ out16(cio->reg_base + 0x1A, 0x08); /* Disable Write Protection */ out16(cio->reg_base + 0x14, 0); out16(cio->reg_base + 0x16, 0xFFFF); out16(cio->reg_base + 0x12, 0x04); /* We only use buffer 3 */ out16(cio->reg_base + 0x04, COGNAC_NAND_BUF); return (0);}/* * Read MX31_ECC_STATUS_RESULT register */uint16_t nand_read_status(struct chipio *cio){ return (in16(cio->reg_base + 0x0C));}/* * Read bit 15 of NAND_CONFIG2 register. 1 == chip ready, 0=chip busy */intnand_wait_busy(struct chipio *cio, uint32_t usec) { uint16_t stat; for (usec = MAX_ERASE_USEC ; usec ; --usec) { stat = in16(cio->reg_base + 0x1C); if (stat & 0x8000) return (0); nanospin_ns(1000); } return (-1);}voidnand_write_cmd(struct chipio *cio, int command){ out16(cio->reg_base + 0x1C, 0); out16(cio->reg_base + 0x08, (uint16_t)command); out16(cio->reg_base + 0x1C, 1); nand_wait_busy(cio, MAX_READ_USEC); cio->chip.lastcmd = command;}voidnand_write_pageaddr(struct chipio *cio, unsigned page, int addr_cycles) { int i; unsigned addr = page << 8; for (i = 0; i < addr_cycles; i++) { out16(cio->reg_base + 0x1C, 0); out16(cio->reg_base + 0x06, addr & 0xFF); addr >>= 8; out16(cio->reg_base + 0x1C, 2); nand_wait_busy(cio, MAX_READ_USEC); }}voidnand_write_blkaddr(struct chipio *cio, unsigned blk, int addr_cycles) { int i; unsigned addr = blk << 5; for (i = 0; i < addr_cycles; i++) { out16(cio->reg_base + 0x1C, 0); out16(cio->reg_base + 0x06, addr & 0xFF); addr >>= 8; out16(cio->reg_base + 0x1C, 0x0002); nand_wait_busy(cio, MAX_READ_USEC); }}/* * write an entire page (data + spare). The calling function has been configured * to always pass an entire page, so we can avoid having to toggle the SP_EN bit * of the CONFIG1 register, which seems to cause problems */voidnand_write_data(struct chipio *cio, uint8_t *databuffer, uint8_t *sparebuffer){ int i; uint32_t *p1, *p2; out16(cio->reg_base + 0x04, COGNAC_NAND_BUF); p1 = (uint32_t *)databuffer; p2 = (uint32_t *)cio->data; for (i = 0; i < DATASIZE; i += 4) *p2++ = *p1++; p1 = (uint32_t *)sparebuffer; p2 = (uint32_t *)cio->spare; for (i = 0; i < SPARESIZE; i += 4) *p2++ = *p1++; out16(cio->reg_base + 0x1C, 0x0004); nand_wait_busy(cio, MAX_READ_USEC);}voidnand_read_data(struct chipio *cio, uint8_t *databuffer, int data_cycles) { uint16_t status, cfg1; uint32_t *pbuf = (uint32_t *)databuffer; uint32_t *psrc; uint8_t *ptrerr; int i, poserr; out16(cio->reg_base + 0x04, COGNAC_NAND_BUF); if (cio->hwecc) cfg1 = 1 << 3; else cfg1 = 0; /* * Determine what is being read; page data, chip ID, or chip status, * and set the config2 register accordingly */ switch (cio->chip.lastcmd) { case NANDCMD_IDREAD: out16(cio->reg_base + 0x1C, 0x0000); out16(cio->reg_base + 0x1C, 0x0010); nand_wait_busy(cio, MAX_READ_USEC); *(uint16_t *)databuffer = in16(cio->data); break; case NANDCMD_STATUSREAD: out16(cio->reg_base + 0x1C, 0); out16(cio->reg_base + 0x1C, 0x0020); nand_wait_busy(cio, MAX_READ_USEC); databuffer[0] = in16(cio->data); break; case NANDCMD_SPAREREAD: cfg1 |= 0x0004; case NANDCMD_READ: out16(cio->reg_base + 0x1C, 0); out16(cio->reg_base + 0x1A, cfg1); out16(cio->reg_base + 0x1C, 0x0008); nand_wait_busy(cio, MAX_READ_USEC); status = in16(cio->reg_base + 0x0C); /* Must be page read, read main buffer first */ if (data_cycles > DATASIZE) { if (!cio->hwecc) { if ((status & 0x0C) == 0x04) { /* 1 bit correctable error in main area */ ptrerr = (uint8_t *)cio->data; poserr = in16(cio->reg_base + 0x0E); ptrerr[(poserr >> 3) & 0x1FF] ^= (1 << (poserr & 0x07)); } } for (i = 0, psrc = (uint32_t *)cio->data; i < DATASIZE; i += 4) *pbuf++ = *psrc++; } if (!cio->hwecc) { if ((status & 0x03) == 0x01) { /* 1 bit correctable error in spare area */ ptrerr = (uint8_t *)cio->spare; poserr = in16(cio->reg_base + 0x10); ptrerr[(poserr >> 3) & 0x03] ^= (1 << (poserr & 0x07)); } } /* Read spare area */ for (i = 0, psrc = (uint32_t *)cio->spare; i < SPARESIZE; i += 4) *pbuf++ = *psrc++; break; } out16(cio->reg_base + 0x1A, 0x0008);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -