12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408 |
- From b915fe7cd934160bfaf2cd52f03c118abcae2419 Mon Sep 17 00:00:00 2001
- From: John Crispin <blogic@openwrt.org>
- Date: Sun, 17 Nov 2013 17:41:46 +0100
- Subject: [PATCH 43/57] mtd: ralink: add mt7620 nand driver
- Signed-off-by: John Crispin <blogic@openwrt.org>
- ---
- drivers/mtd/maps/Kconfig | 4 +
- drivers/mtd/maps/Makefile | 2 +
- drivers/mtd/maps/ralink_nand.c | 2136 ++++++++++++++++++++++++++++++++++++++++
- drivers/mtd/maps/ralink_nand.h | 232 +++++
- 4 files changed, 2374 insertions(+)
- create mode 100644 drivers/mtd/maps/ralink_nand.c
- create mode 100644 drivers/mtd/maps/ralink_nand.h
- --- a/drivers/mtd/maps/Kconfig
- +++ b/drivers/mtd/maps/Kconfig
- @@ -399,4 +399,8 @@ config MTD_LATCH_ADDR
-
- If compiled as a module, it will be called latch-addr-flash.
-
- +config MTD_NAND_MT7620
- + tristate "Support for NAND on Mediatek MT7620"
- + depends on RALINK && SOC_MT7620
- +
- endmenu
- --- a/drivers/mtd/maps/Makefile
- +++ b/drivers/mtd/maps/Makefile
- @@ -43,3 +43,5 @@ obj-$(CONFIG_MTD_VMU) += vmu-flash.o
- obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
- obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
- obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
- +obj-$(CONFIG_MTD_NAND_MT7620) += ralink_nand.o
- +
- --- /dev/null
- +++ b/drivers/mtd/maps/ralink_nand.c
- @@ -0,0 +1,2136 @@
- +#define DEBUG
- +#include <linux/device.h>
- +#undef DEBUG
- +#include <linux/slab.h>
- +#include <linux/mtd/mtd.h>
- +#include <linux/delay.h>
- +#include <linux/module.h>
- +#include <linux/interrupt.h>
- +#include <linux/dma-mapping.h>
- +#include <linux/mtd/partitions.h>
- +#include <asm/io.h>
- +#include <linux/delay.h>
- +#include <linux/sched.h>
- +#include <linux/of.h>
- +#include <linux/platform_device.h>
- +
- +#include "ralink_nand.h"
- +#ifdef RANDOM_GEN_BAD_BLOCK
- +#include <linux/random.h>
- +#endif
- +
- +#define LARGE_MTD_BOOT_PART_SIZE (CFG_BLOCKSIZE<<2)
- +#define LARGE_MTD_CONFIG_PART_SIZE (CFG_BLOCKSIZE<<2)
- +#define LARGE_MTD_FACTORY_PART_SIZE (CFG_BLOCKSIZE<<1)
- +
- +
- +#define BLOCK_ALIGNED(a) ((a) & (CFG_BLOCKSIZE - 1))
- +
- +#define READ_STATUS_RETRY 1000
- +
- +struct mtd_info *ranfc_mtd = NULL;
- +
- +int skipbbt = 0;
- +int ranfc_debug = 1;
- +static int ranfc_bbt = 1;
- +#if defined (WORKAROUND_RX_BUF_OV)
- +static int ranfc_verify = 1;
- +#endif
- +static u32 nand_addrlen;
- +
- +#if 0
- +module_param(ranfc_debug, int, 0644);
- +module_param(ranfc_bbt, int, 0644);
- +module_param(ranfc_verify, int, 0644);
- +#endif
- +
- +#if 0
- +#define ra_dbg(args...) do { if (ranfc_debug) printk(args); } while(0)
- +#else
- +#define ra_dbg(args...)
- +#endif
- +
- +#define CLEAR_INT_STATUS() ra_outl(NFC_INT_ST, ra_inl(NFC_INT_ST))
- +#define NFC_TRANS_DONE() (ra_inl(NFC_INT_ST) & INT_ST_ND_DONE)
- +
- +int is_nand_page_2048 = 0;
- +const unsigned int nand_size_map[2][3] = {{25, 30, 30}, {20, 27, 30}};
- +
- +static int nfc_wait_ready(int snooze_ms);
- +
- +static const char * const mtk_probe_types[] = { "cmdlinepart", "ofpart", NULL };
- +
- +/**
- + * reset nand chip
- + */
- +static int nfc_chip_reset(void)
- +{
- + int status;
- +
- + //ra_dbg("%s:\n", __func__);
- +
- + // reset nand flash
- + ra_outl(NFC_CMD1, 0x0);
- + ra_outl(NFC_CMD2, 0xff);
- + ra_outl(NFC_ADDR, 0x0);
- + ra_outl(NFC_CONF, 0x0411);
- +
- + status = nfc_wait_ready(5); //erase wait 5us
- + if (status & NAND_STATUS_FAIL) {
- + printk("%s: fail \n", __func__);
- + }
- +
- + return (int)(status & NAND_STATUS_FAIL);
- +
- +}
- +
- +
- +
- +/**
- + * clear NFC and flash chip.
- + */
- +static int nfc_all_reset(void)
- +{
- + int retry;
- +
- + ra_dbg("%s: \n", __func__);
- +
- + // reset controller
- + ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
- + ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
- +
- + CLEAR_INT_STATUS();
- +
- + retry = READ_STATUS_RETRY;
- + while ((ra_inl(NFC_INT_ST) & 0x02) != 0x02 && retry--);
- + if (retry <= 0) {
- + printk("nfc_all_reset: clean buffer fail \n");
- + return -1;
- + }
- +
- + retry = READ_STATUS_RETRY;
- + while ((ra_inl(NFC_STATUS) & 0x1) != 0x0 && retry--) { //fixme, controller is busy ?
- + udelay(1);
- + }
- +
- + nfc_chip_reset();
- +
- + return 0;
- +}
- +
- +/** NOTICE: only called by nfc_wait_ready().
- + * @return -1, nfc can not get transction done
- + * @return 0, ok.
- + */
- +static int _nfc_read_status(char *status)
- +{
- + unsigned long cmd1, conf;
- + int int_st, nfc_st;
- + int retry;
- +
- + cmd1 = 0x70;
- + conf = 0x000101 | (1 << 20);
- +
- + //fixme, should we check nfc status?
- + CLEAR_INT_STATUS();
- +
- + ra_outl(NFC_CMD1, cmd1);
- + ra_outl(NFC_CONF, conf);
- +
- + /* FIXME,
- + * 1. since we have no wired ready signal, directly
- + * calling this function is not gurantee to read right status under ready state.
- + * 2. the other side, we can not determine how long to become ready, this timeout retry is nonsense.
- + * 3. SUGGESTION: call nfc_read_status() from nfc_wait_ready(),
- + * that is aware about caller (in sementics) and has snooze plused nfc ND_DONE.
- + */
- + retry = READ_STATUS_RETRY;
- + do {
- + nfc_st = ra_inl(NFC_STATUS);
- + int_st = ra_inl(NFC_INT_ST);
- +
- + ndelay(10);
- + } while (!(int_st & INT_ST_RX_BUF_RDY) && retry--);
- +
- + if (!(int_st & INT_ST_RX_BUF_RDY)) {
- + printk("nfc_read_status: NFC fail, int_st(%x), retry:%x. nfc:%x, reset nfc and flash. \n",
- + int_st, retry, nfc_st);
- + nfc_all_reset();
- + *status = NAND_STATUS_FAIL;
- + return -1;
- + }
- +
- + *status = (char)(le32_to_cpu(ra_inl(NFC_DATA)) & 0x0ff);
- + return 0;
- +}
- +
- +/**
- + * @return !0, chip protect.
- + * @return 0, chip not protected.
- + */
- +static int nfc_check_wp(void)
- +{
- + /* Check the WP bit */
- +#if !defined CONFIG_NOT_SUPPORT_WP
- + return !!(ra_inl(NFC_CTRL) & 0x01);
- +#else
- + char result = 0;
- + int ret;
- +
- + ret = _nfc_read_status(&result);
- + //FIXME, if ret < 0
- +
- + return !(result & NAND_STATUS_WP);
- +#endif
- +}
- +
- +#if !defined CONFIG_NOT_SUPPORT_RB
- +/*
- + * @return !0, chip ready.
- + * @return 0, chip busy.
- + */
- +static int nfc_device_ready(void)
- +{
- + /* Check the ready */
- + return !!(ra_inl(NFC_STATUS) & 0x04);
- +}
- +#endif
- +
- +
- +/**
- + * generic function to get data from flash.
- + * @return data length reading from flash.
- + */
- +static int _ra_nand_pull_data(char *buf, int len, int use_gdma)
- +{
- +#ifdef RW_DATA_BY_BYTE
- + char *p = buf;
- +#else
- + __u32 *p = (__u32 *)buf;
- +#endif
- + int retry, int_st;
- + unsigned int ret_data;
- + int ret_size;
- +
- + // receive data by use_gdma
- + if (use_gdma) {
- + //if (_ra_nand_dma_pull((unsigned long)p, len)) {
- + if (1) {
- + printk("%s: fail \n", __func__);
- + len = -1; //return error
- + }
- +
- + return len;
- + }
- +
- + //fixme: retry count size?
- + retry = READ_STATUS_RETRY;
- + // no gdma
- + while (len > 0) {
- + int_st = ra_inl(NFC_INT_ST);
- + if (int_st & INT_ST_RX_BUF_RDY) {
- +
- + ret_data = ra_inl(NFC_DATA);
- + ra_outl(NFC_INT_ST, INT_ST_RX_BUF_RDY);
- +#ifdef RW_DATA_BY_BYTE
- + ret_size = sizeof(unsigned int);
- + ret_size = min(ret_size, len);
- + len -= ret_size;
- + while (ret_size-- > 0) {
- + //nfc is little endian
- + *p++ = ret_data & 0x0ff;
- + ret_data >>= 8;
- + }
- +#else
- + ret_size = min(len, 4);
- + len -= ret_size;
- + if (ret_size == 4)
- + *p++ = ret_data;
- + else {
- + __u8 *q = (__u8 *)p;
- + while (ret_size-- > 0) {
- + *q++ = ret_data & 0x0ff;
- + ret_data >>= 8;
- + }
- + p = (__u32 *)q;
- + }
- +#endif
- + retry = READ_STATUS_RETRY;
- + }
- + else if (int_st & INT_ST_ND_DONE) {
- + break;
- + }
- + else {
- + udelay(1);
- + if (retry-- < 0)
- + break;
- + }
- + }
- +
- +#ifdef RW_DATA_BY_BYTE
- + return (int)(p - buf);
- +#else
- + return ((int)p - (int)buf);
- +#endif
- +}
- +
- +/**
- + * generic function to put data into flash.
- + * @return data length writing into flash.
- + */
- +static int _ra_nand_push_data(char *buf, int len, int use_gdma)
- +{
- +#ifdef RW_DATA_BY_BYTE
- + char *p = buf;
- +#else
- + __u32 *p = (__u32 *)buf;
- +#endif
- + int retry, int_st;
- + unsigned int tx_data = 0;
- + int tx_size, iter = 0;
- +
- + // receive data by use_gdma
- + if (use_gdma) {
- + //if (_ra_nand_dma_push((unsigned long)p, len))
- + if (1)
- + len = 0;
- + printk("%s: fail \n", __func__);
- + return len;
- + }
- +
- + // no gdma
- + retry = READ_STATUS_RETRY;
- + while (len > 0) {
- + int_st = ra_inl(NFC_INT_ST);
- + if (int_st & INT_ST_TX_BUF_RDY) {
- +#ifdef RW_DATA_BY_BYTE
- + tx_size = min(len, (int)sizeof(unsigned long));
- + for (iter = 0; iter < tx_size; iter++) {
- + tx_data |= (*p++ << (8*iter));
- + }
- +#else
- + tx_size = min(len, 4);
- + if (tx_size == 4)
- + tx_data = (*p++);
- + else {
- + __u8 *q = (__u8 *)p;
- + for (iter = 0; iter < tx_size; iter++)
- + tx_data |= (*q++ << (8*iter));
- + p = (__u32 *)q;
- + }
- +#endif
- + ra_outl(NFC_INT_ST, INT_ST_TX_BUF_RDY);
- + ra_outl(NFC_DATA, tx_data);
- + len -= tx_size;
- + retry = READ_STATUS_RETRY;
- + }
- + else if (int_st & INT_ST_ND_DONE) {
- + break;
- + }
- + else {
- + udelay(1);
- + if (retry-- < 0) {
- + ra_dbg("%s p:%p buf:%p \n", __func__, p, buf);
- + break;
- + }
- + }
- + }
- +
- +
- +#ifdef RW_DATA_BY_BYTE
- + return (int)(p - buf);
- +#else
- + return ((int)p - (int)buf);
- +#endif
- +
- +}
- +
- +static int nfc_select_chip(struct ra_nand_chip *ra, int chipnr)
- +{
- +#if (CONFIG_NUMCHIPS == 1)
- + if (!(chipnr < CONFIG_NUMCHIPS))
- + return -1;
- + return 0;
- +#else
- + BUG();
- +#endif
- +}
- +
- +/** @return -1: chip_select fail
- + * 0 : both CE and WP==0 are OK
- + * 1 : CE OK and WP==1
- + */
- +static int nfc_enable_chip(struct ra_nand_chip *ra, unsigned int offs, int read_only)
- +{
- + int chipnr = offs >> ra->chip_shift;
- +
- + ra_dbg("%s: offs:%x read_only:%x \n", __func__, offs, read_only);
- +
- + chipnr = nfc_select_chip(ra, chipnr);
- + if (chipnr < 0) {
- + printk("%s: chip select error, offs(%x)\n", __func__, offs);
- + return -1;
- + }
- +
- + if (!read_only)
- + return nfc_check_wp();
- +
- + return 0;
- +}
- +
- +/** wait nand chip becomeing ready and return queried status.
- + * @param snooze: sleep time in ms unit before polling device ready.
- + * @return status of nand chip
- + * @return NAN_STATUS_FAIL if something unexpected.
- + */
- +static int nfc_wait_ready(int snooze_ms)
- +{
- + int retry;
- + char status;
- +
- + // wait nfc idle,
- + if (snooze_ms == 0)
- + snooze_ms = 1;
- + else
- + schedule_timeout(snooze_ms * HZ / 1000);
- +
- + snooze_ms = retry = snooze_ms *1000000 / 100 ; // ndelay(100)
- +
- + while (!NFC_TRANS_DONE() && retry--) {
- + if (!cond_resched())
- + ndelay(100);
- + }
- +
- + if (!NFC_TRANS_DONE()) {
- + printk("nfc_wait_ready: no transaction done \n");
- + return NAND_STATUS_FAIL;
- + }
- +
- +#if !defined (CONFIG_NOT_SUPPORT_RB)
- + //fixme
- + while(!(status = nfc_device_ready()) && retry--) {
- + ndelay(100);
- + }
- +
- + if (status == 0) {
- + printk("nfc_wait_ready: no device ready. \n");
- + return NAND_STATUS_FAIL;
- + }
- +
- + _nfc_read_status(&status);
- + return status;
- +#else
- +
- + while(retry--) {
- + _nfc_read_status(&status);
- + if (status & NAND_STATUS_READY)
- + break;
- + ndelay(100);
- + }
- + if (retry<0)
- + printk("nfc_wait_ready 2: no device ready, status(%x). \n", status);
- +
- + return status;
- +#endif
- +}
- +
- +/**
- + * return 0: erase OK
- + * return -EIO: fail
- + */
- +int nfc_erase_block(struct ra_nand_chip *ra, int row_addr)
- +{
- + unsigned long cmd1, cmd2, bus_addr, conf;
- + char status;
- +
- + cmd1 = 0x60;
- + cmd2 = 0xd0;
- + bus_addr = row_addr;
- + conf = 0x00511 | ((CFG_ROW_ADDR_CYCLE)<<16);
- +
- + // set NFC
- + ra_dbg("%s: cmd1: %lx, cmd2:%lx bus_addr: %lx, conf: %lx \n",
- + __func__, cmd1, cmd2, bus_addr, conf);
- +
- + //fixme, should we check nfc status?
- + CLEAR_INT_STATUS();
- +
- + ra_outl(NFC_CMD1, cmd1);
- + ra_outl(NFC_CMD2, cmd2);
- + ra_outl(NFC_ADDR, bus_addr);
- + ra_outl(NFC_CONF, conf);
- +
- + status = nfc_wait_ready(3); //erase wait 3ms
- + if (status & NAND_STATUS_FAIL) {
- + printk("%s: fail \n", __func__);
- + return -EIO;
- + }
- +
- + return 0;
- +
- +}
- +
- +static inline int _nfc_read_raw_data(int cmd1, int cmd2, int bus_addr, int bus_addr2, int conf, char *buf, int len, int flags)
- +{
- + int ret;
- +
- + CLEAR_INT_STATUS();
- + ra_outl(NFC_CMD1, cmd1);
- + ra_outl(NFC_CMD2, cmd2);
- + ra_outl(NFC_ADDR, bus_addr);
- +#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
- + defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)
- + ra_outl(NFC_ADDR2, bus_addr2);
- +#endif
- + ra_outl(NFC_CONF, conf);
- +
- + ret = _ra_nand_pull_data(buf, len, 0);
- + if (ret != len) {
- + ra_dbg("%s: ret:%x (%x) \n", __func__, ret, len);
- + return NAND_STATUS_FAIL;
- + }
- +
- + //FIXME, this section is not necessary
- + ret = nfc_wait_ready(0); //wait ready
- + /* to prevent the DATA FIFO 's old data from next operation */
- + ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
- + ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
- +
- + if (ret & NAND_STATUS_FAIL) {
- + printk("%s: fail \n", __func__);
- + return NAND_STATUS_FAIL;
- + }
- +
- + return 0;
- +}
- +
- +static inline int _nfc_write_raw_data(int cmd1, int cmd3, int bus_addr, int bus_addr2, int conf, char *buf, int len, int flags)
- +{
- + int ret;
- +
- + CLEAR_INT_STATUS();
- + ra_outl(NFC_CMD1, cmd1);
- + ra_outl(NFC_CMD3, cmd3);
- + ra_outl(NFC_ADDR, bus_addr);
- +#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
- + defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)
- + ra_outl(NFC_ADDR2, bus_addr2);
- +#endif
- + ra_outl(NFC_CONF, conf);
- +
- + ret = _ra_nand_push_data(buf, len, 0);
- + if (ret != len) {
- + ra_dbg("%s: ret:%x (%x) \n", __func__, ret, len);
- + return NAND_STATUS_FAIL;
- + }
- +
- + ret = nfc_wait_ready(1); //write wait 1ms
- + /* to prevent the DATA FIFO 's old data from next operation */
- + ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
- + ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
- +
- + if (ret & NAND_STATUS_FAIL) {
- + printk("%s: fail \n", __func__);
- + return NAND_STATUS_FAIL;
- + }
- +
- + return 0;
- +}
- +
- +/**
- + * @return !0: fail
- + * @return 0: OK
- + */
- +int nfc_read_oob(struct ra_nand_chip *ra, int page, unsigned int offs, char *buf, int len, int flags)
- +{
- + unsigned int cmd1 = 0, cmd2 = 0, conf = 0;
- + unsigned int bus_addr = 0, bus_addr2 = 0;
- + unsigned int ecc_en;
- + int use_gdma;
- + int status;
- +
- + int pages_perblock = 1<<(ra->erase_shift - ra->page_shift);
- + // constrain of nfc read function
- +
- +#if defined (WORKAROUND_RX_BUF_OV)
- + BUG_ON (len > 60); //problem of rx-buffer overrun
- +#endif
- + BUG_ON (offs >> ra->oob_shift); //page boundry
- + BUG_ON ((unsigned int)(((offs + len) >> ra->oob_shift) + page) >
- + ((page + pages_perblock) & ~(pages_perblock-1))); //block boundry
- +
- + use_gdma = flags & FLAG_USE_GDMA;
- + ecc_en = flags & FLAG_ECC_EN;
- + bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8) - 1));
- +
- + if (is_nand_page_2048) {
- + bus_addr += CFG_PAGESIZE;
- + bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
- + cmd1 = 0x0;
- + cmd2 = 0x30;
- + conf = 0x000511| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
- + }
- + else {
- + cmd1 = 0x50;
- + conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
- + }
- + if (ecc_en)
- + conf |= (1<<3);
- + if (use_gdma)
- + conf |= (1<<2);
- +
- + ra_dbg("%s: cmd1:%x, bus_addr:%x, conf:%x, len:%x, flag:%x\n",
- + __func__, cmd1, bus_addr, conf, len, flags);
- +
- + status = _nfc_read_raw_data(cmd1, cmd2, bus_addr, bus_addr2, conf, buf, len, flags);
- + if (status & NAND_STATUS_FAIL) {
- + printk("%s: fail\n", __func__);
- + return -EIO;
- + }
- +
- + return 0;
- +}
- +
- +/**
- + * @return !0: fail
- + * @return 0: OK
- + */
- +int nfc_write_oob(struct ra_nand_chip *ra, int page, unsigned int offs, char *buf, int len, int flags)
- +{
- + unsigned int cmd1 = 0, cmd3=0, conf = 0;
- + unsigned int bus_addr = 0, bus_addr2 = 0;
- + int use_gdma;
- + int status;
- +
- + int pages_perblock = 1<<(ra->erase_shift - ra->page_shift);
- + // constrain of nfc read function
- +
- + BUG_ON (offs >> ra->oob_shift); //page boundry
- + BUG_ON ((unsigned int)(((offs + len) >> ra->oob_shift) + page) >
- + ((page + pages_perblock) & ~(pages_perblock-1))); //block boundry
- +
- + use_gdma = flags & FLAG_USE_GDMA;
- + bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8) - 1));
- +
- + if (is_nand_page_2048) {
- + cmd1 = 0x80;
- + cmd3 = 0x10;
- + bus_addr += CFG_PAGESIZE;
- + bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
- + conf = 0x001123 | ((CFG_ADDR_CYCLE)<<16) | ((len) << 20);
- + }
- + else {
- + cmd1 = 0x08050;
- + cmd3 = 0x10;
- + conf = 0x001223 | ((CFG_ADDR_CYCLE)<<16) | ((len) << 20);
- + }
- + if (use_gdma)
- + conf |= (1<<2);
- +
- + // set NFC
- + ra_dbg("%s: cmd1: %x, cmd3: %x bus_addr: %x, conf: %x, len:%x\n",
- + __func__, cmd1, cmd3, bus_addr, conf, len);
- +
- + status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, len, flags);
- + if (status & NAND_STATUS_FAIL) {
- + printk("%s: fail \n", __func__);
- + return -EIO;
- + }
- +
- + return 0;
- +}
- +
- +
- +int nfc_read_page(struct ra_nand_chip *ra, char *buf, int page, int flags);
- +int nfc_write_page(struct ra_nand_chip *ra, char *buf, int page, int flags);
- +
- +
- +#if !defined (WORKAROUND_RX_BUF_OV)
- +static int one_bit_correction(char *ecc, char *expected, int *bytes, int *bits);
- +int nfc_ecc_verify(struct ra_nand_chip *ra, char *buf, int page, int mode)
- +{
- + int ret, i;
- + char *p, *e;
- + int ecc;
- +
- + //ra_dbg("%s, page:%x mode:%d\n", __func__, page, mode);
- +
- + if (mode == FL_WRITING) {
- + int len = CFG_PAGESIZE + CFG_PAGE_OOBSIZE;
- + int conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
- + conf |= (1<<3); //(ecc_en)
- + //conf |= (1<<2); // (use_gdma)
- +
- + p = ra->readback_buffers;
- + ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_ECC_EN);
- + if (ret == 0)
- + goto ecc_check;
- +
- + //FIXME, double comfirm
- + printk("%s: read back fail, try again \n",__func__);
- + ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_ECC_EN);
- + if (ret != 0) {
- + printk("\t%s: read back fail agian \n",__func__);
- + goto bad_block;
- + }
- + }
- + else if (mode == FL_READING) {
- + p = buf;
- + }
- + else
- + return -2;
- +
- +ecc_check:
- + p += CFG_PAGESIZE;
- + if (!is_nand_page_2048) {
- + ecc = ra_inl(NFC_ECC);
- + if (ecc == 0) //clean page.
- + return 0;
- + e = (char*)&ecc;
- + for (i=0; i<CONFIG_ECC_BYTES; i++) {
- + int eccpos = CONFIG_ECC_OFFSET + i;
- + if (*(p + eccpos) != (char)0xff)
- + break;
- + if (i == CONFIG_ECC_BYTES - 1) {
- + printk("skip ecc 0xff at page %x\n", page);
- + return 0;
- + }
- + }
- + for (i=0; i<CONFIG_ECC_BYTES; i++) {
- + int eccpos = CONFIG_ECC_OFFSET + i;
- + if (*(p + eccpos) != *(e + i)) {
- + printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, ecc:%x \n",
- + __func__, (mode == FL_READING)?"read":"write", page,
- + *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
- + return -1;
- + }
- + }
- + }
- +#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
- + defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)
- + else {
- + int ecc2, ecc3, ecc4, qsz;
- + char *e2, *e3, *e4;
- + int correction_flag = 0;
- + ecc = ra_inl(NFC_ECC_P1);
- + ecc2 = ra_inl(NFC_ECC_P2);
- + ecc3 = ra_inl(NFC_ECC_P3);
- + ecc4 = ra_inl(NFC_ECC_P4);
- + e = (char*)&ecc;
- + e2 = (char*)&ecc2;
- + e3 = (char*)&ecc3;
- + e4 = (char*)&ecc4;
- + qsz = CFG_PAGE_OOBSIZE / 4;
- + if (ecc == 0 && ecc2 == 0 && ecc3 == 0 && ecc4 == 0)
- + return 0;
- + for (i=0; i<CONFIG_ECC_BYTES; i++) {
- + int eccpos = CONFIG_ECC_OFFSET + i;
- + if (*(p + eccpos) != (char)0xff)
- + break;
- + else if (*(p + eccpos + qsz) != (char)0xff)
- + break;
- + else if (*(p + eccpos + qsz*2) != (char)0xff)
- + break;
- + else if (*(p + eccpos + qsz*3) != (char)0xff)
- + break;
- + if (i == CONFIG_ECC_BYTES - 1) {
- + printk("skip ecc 0xff at page %x\n", page);
- + return 0;
- + }
- + }
- + for (i=0; i<CONFIG_ECC_BYTES; i++) {
- + int eccpos = CONFIG_ECC_OFFSET + i;
- + if (*(p + eccpos) != *(e + i)) {
- + printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, ecc:%x \n",
- + __func__, (mode == FL_READING)?"read":"write", page,
- + *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
- + correction_flag |= 0x1;
- + }
- + if (*(p + eccpos + qsz) != *(e2 + i)) {
- + printk("%s mode:%s, invalid ecc2, page: %x read:%x %x %x, ecc2:%x \n",
- + __func__, (mode == FL_READING)?"read":"write", page,
- + *(p+CONFIG_ECC_OFFSET+qsz), *(p+ CONFIG_ECC_OFFSET+1+qsz), *(p+ CONFIG_ECC_OFFSET+2+qsz), ecc2);
- + correction_flag |= 0x2;
- + }
- + if (*(p + eccpos + qsz*2) != *(e3 + i)) {
- + printk("%s mode:%s, invalid ecc3, page: %x read:%x %x %x, ecc3:%x \n",
- + __func__, (mode == FL_READING)?"read":"write", page,
- + *(p+CONFIG_ECC_OFFSET+qsz*2), *(p+ CONFIG_ECC_OFFSET+1+qsz*2), *(p+ CONFIG_ECC_OFFSET+2+qsz*2), ecc3);
- + correction_flag |= 0x4;
- + }
- + if (*(p + eccpos + qsz*3) != *(e4 + i)) {
- + printk("%s mode:%s, invalid ecc4, page: %x read:%x %x %x, ecc4:%x \n",
- + __func__, (mode == FL_READING)?"read":"write", page,
- + *(p+CONFIG_ECC_OFFSET+qsz*3), *(p+ CONFIG_ECC_OFFSET+1+qsz*3), *(p+ CONFIG_ECC_OFFSET+2+qsz*3), ecc4);
- + correction_flag |= 0x8;
- + }
- + }
- +
- + if (correction_flag)
- + {
- + printk("trying to do correction!\n");
- + if (correction_flag & 0x1)
- + {
- + int bytes, bits;
- + char *pBuf = p - CFG_PAGESIZE;
- +
- + if (one_bit_correction(p + CONFIG_ECC_OFFSET, e, &bytes, &bits) == 0)
- + {
- + pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
- + printk("1. correct byte %d, bit %d!\n", bytes, bits);
- + }
- + else
- + {
- + printk("failed to correct!\n");
- + return -1;
- + }
- + }
- +
- + if (correction_flag & 0x2)
- + {
- + int bytes, bits;
- + char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE/4;
- +
- + if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz), e2, &bytes, &bits) == 0)
- + {
- + pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
- + printk("2. correct byte %d, bit %d!\n", bytes, bits);
- + }
- + else
- + {
- + printk("failed to correct!\n");
- + return -1;
- + }
- + }
- + if (correction_flag & 0x4)
- + {
- + int bytes, bits;
- + char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE/2;
- +
- + if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz * 2), e3, &bytes, &bits) == 0)
- + {
- + pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
- + printk("3. correct byte %d, bit %d!\n", bytes, bits);
- + }
- + else
- + {
- + printk("failed to correct!\n");
- + return -1;
- + }
- + }
- + if (correction_flag & 0x8)
- + {
- + int bytes, bits;
- + char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE*3/4;
- +
- + if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz * 3), e4, &bytes, &bits) == 0)
- + {
- + pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
- + printk("4. correct byte %d, bit %d!\n", bytes, bits);
- + }
- + else
- + {
- + printk("failed to correct!\n");
- + return -1;
- + }
- + }
- + }
- +
- + }
- +#endif
- + return 0;
- +
- +bad_block:
- + return -1;
- +}
- +
- +#else
- +
- +void ranfc_dump(void)
- +{
- + int i;
- + for (i=0; i<11; i++) {
- + if (i==6)
- + continue;
- + printk("%x: %x \n", NFC_BASE + i*4, ra_inl(NFC_BASE + i*4));
- + }
- +}
- +
- +/**
- + * @return 0, ecc OK or corrected.
- + * @return NAND_STATUS_FAIL, ecc fail.
- + */
- +
- +int nfc_ecc_verify(struct ra_nand_chip *ra, char *buf, int page, int mode)
- +{
- + int ret, i;
- + char *p, *e;
- + int ecc;
- +
- + if (ranfc_verify == 0)
- + return 0;
- +
- + ra_dbg("%s, page:%x mode:%d\n", __func__, page, mode);
- +
- + if (mode == FL_WRITING) { // read back and memcmp
- + ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_NONE);
- + if (ret != 0) //double comfirm
- + ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_NONE);
- +
- + if (ret != 0) {
- + printk("%s: mode:%x read back fail \n", __func__, mode);
- + return -1;
- + }
- + return memcmp(buf, ra->readback_buffers, 1<<ra->page_shift);
- + }
- +
- + if (mode == FL_READING) {
- +#if 0
- + if (ra->sandbox_page == 0)
- + return 0;
- +
- + ret = nfc_write_page(ra, buf, ra->sandbox_page, FLAG_USE_GDMA | FLAG_ECC_EN);
- + if (ret != 0) {
- + printk("%s, fail write sandbox_page \n", __func__);
- + return -1;
- + }
- +#else
- + /** @note:
- + * The following command is actually not 'write' command to drive NFC to write flash.
- + * However, it can make NFC to calculate ECC, that will be used to compare with original ones.
- + * --YT
- + */
- + unsigned int conf = 0x001223| (CFG_ADDR_CYCLE<<16) | (0x200 << 20) | (1<<3) | (1<<2);
- + _nfc_write_raw_data(0xff, 0xff, ra->sandbox_page<<ra->page_shift, conf, buf, 0x200, FLAG_USE_GDMA);
- +#endif
- +
- + ecc = ra_inl(NFC_ECC);
- + if (ecc == 0) //clean page.
- + return 0;
- + e = (char*)&ecc;
- + p = buf + (1<<ra->page_shift);
- + for (i=0; i<CONFIG_ECC_BYTES; i++) {
- + int eccpos = CONFIG_ECC_OFFSET + i;
- + if (*(p + eccpos) != *(e + i)) {
- + printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, write:%x \n",
- + __func__, (mode == FL_READING)?"read":"write", page,
- + *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
- +
- + for (i=0; i<528; i++)
- + printk("%-2x \n", *(buf + i));
- + return -1;
- + }
- + }
- + return 0;
- + }
- +
- + return -1;
- +
- +}
- +
- +#endif
- +
- +
- +/**
- + * @return -EIO, writing size is less than a page
- + * @return 0, OK
- + */
- +int nfc_read_page(struct ra_nand_chip *ra, char *buf, int page, int flags)
- +{
- + unsigned int cmd1 = 0, cmd2 = 0, conf = 0;
- + unsigned int bus_addr = 0, bus_addr2 = 0;
- + unsigned int ecc_en;
- + int use_gdma;
- + int size, offs;
- + int status = 0;
- +
- + use_gdma = flags & FLAG_USE_GDMA;
- + ecc_en = flags & FLAG_ECC_EN;
- +
- + page = page & (CFG_CHIPSIZE - 1); // chip boundary
- + size = CFG_PAGESIZE + CFG_PAGE_OOBSIZE; //add oobsize
- + offs = 0;
- +
- + while (size > 0) {
- + int len;
- +#if defined (WORKAROUND_RX_BUF_OV)
- + len = min(60, size);
- +#else
- + len = size;
- +#endif
- + bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8)-1));
- + if (is_nand_page_2048) {
- + bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
- + cmd1 = 0x0;
- + cmd2 = 0x30;
- + conf = 0x000511| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
- + }
- + else {
- + if (offs & ~(CFG_PAGESIZE-1))
- + cmd1 = 0x50;
- + else if (offs & ~((1<<CFG_COLUMN_ADDR_CYCLE*8)-1))
- + cmd1 = 0x01;
- + else
- + cmd1 = 0;
- +
- + conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20);
- + }
- +#if !defined (WORKAROUND_RX_BUF_OV)
- + if (ecc_en)
- + conf |= (1<<3);
- +#endif
- + if (use_gdma)
- + conf |= (1<<2);
- +
- + status = _nfc_read_raw_data(cmd1, cmd2, bus_addr, bus_addr2, conf, buf+offs, len, flags);
- + if (status & NAND_STATUS_FAIL) {
- + printk("%s: fail \n", __func__);
- + return -EIO;
- + }
- +
- + offs += len;
- + size -= len;
- + }
- +
- + // verify and correct ecc
- + if ((flags & (FLAG_VERIFY | FLAG_ECC_EN)) == (FLAG_VERIFY | FLAG_ECC_EN)) {
- + status = nfc_ecc_verify(ra, buf, page, FL_READING);
- + if (status != 0) {
- + printk("%s: fail, buf:%x, page:%x, flag:%x\n",
- + __func__, (unsigned int)buf, page, flags);
- + return -EBADMSG;
- + }
- + }
- + else {
- + // fix,e not yet support
- + ra->buffers_page = -1; //cached
- + }
- +
- + return 0;
- +}
- +
- +
- +/**
- + * @return -EIO, fail to write
- + * @return 0, OK
- + */
- +int nfc_write_page(struct ra_nand_chip *ra, char *buf, int page, int flags)
- +{
- + unsigned int cmd1 = 0, cmd3, conf = 0;
- + unsigned int bus_addr = 0, bus_addr2 = 0;
- + unsigned int ecc_en;
- + int use_gdma;
- + int size;
- + char status;
- + uint8_t *oob = buf + (1<<ra->page_shift);
- +
- + use_gdma = flags & FLAG_USE_GDMA;
- + ecc_en = flags & FLAG_ECC_EN;
- +
- + oob[ra->badblockpos] = 0xff; //tag as good block.
- + ra->buffers_page = -1; //cached
- +
- + page = page & (CFG_CHIPSIZE-1); //chip boundary
- + size = CFG_PAGESIZE + CFG_PAGE_OOBSIZE; //add oobsize
- + bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)); //write_page always write from offset 0.
- +
- + if (is_nand_page_2048) {
- + bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
- + cmd1 = 0x80;
- + cmd3 = 0x10;
- + conf = 0x001123| ((CFG_ADDR_CYCLE)<<16) | (size << 20);
- + }
- + else {
- + cmd1 = 0x8000;
- + cmd3 = 0x10;
- + conf = 0x001223| ((CFG_ADDR_CYCLE)<<16) | (size << 20);
- +}
- + if (ecc_en)
- + conf |= (1<<3); //enable ecc
- + if (use_gdma)
- + conf |= (1<<2);
- +
- + // set NFC
- + ra_dbg("nfc_write_page: cmd1: %x, cmd3: %x bus_addr: %x, conf: %x, len:%x\n",
- + cmd1, cmd3, bus_addr, conf, size);
- +
- + status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, size, flags);
- + if (status & NAND_STATUS_FAIL) {
- + printk("%s: fail \n", __func__);
- + return -EIO;
- + }
- +
- +
- + if (flags & FLAG_VERIFY) { // verify and correct ecc
- + status = nfc_ecc_verify(ra, buf, page, FL_WRITING);
- +
- +#ifdef RANDOM_GEN_BAD_BLOCK
- + if (((random32() & 0x1ff) == 0x0) && (page >= 0x100)) // randomly create bad block
- + {
- + printk("hmm... create a bad block at page %x\n", (bus_addr >> 16));
- + status = -1;
- + }
- +#endif
- +
- + if (status != 0) {
- + printk("%s: ecc_verify fail: ret:%x \n", __func__, status);
- + oob[ra->badblockpos] = 0x33;
- + page -= page % (CFG_BLOCKSIZE/CFG_PAGESIZE);
- + printk("create a bad block at page %x\n", page);
- + if (!is_nand_page_2048)
- + status = nfc_write_oob(ra, page, ra->badblockpos, oob+ra->badblockpos, 1, flags);
- + else
- + {
- + status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, size, flags);
- + nfc_write_oob(ra, page, 0, oob, 16, FLAG_NONE);
- + }
- + return -EBADMSG;
- + }
- + }
- +
- +
- + ra->buffers_page = page; //cached
- + return 0;
- +}
- +
- +
- +
- +/*************************************************************
- + * nand internal process
- + *************************************************************/
- +
- +/**
- + * nand_release_device - [GENERIC] release chip
- + * @mtd: MTD device structure
- + *
- + * Deselect, release chip lock and wake up anyone waiting on the device
- + */
- +static void nand_release_device(struct ra_nand_chip *ra)
- +{
- + /* De-select the NAND device */
- + nfc_select_chip(ra, -1);
- +
- + /* Release the controller and the chip */
- + ra->state = FL_READY;
- +
- + mutex_unlock(ra->controller);
- +}
- +
- +/**
- + * nand_get_device - [GENERIC] Get chip for selected access
- + * @chip: the nand chip descriptor
- + * @mtd: MTD device structure
- + * @new_state: the state which is requested
- + *
- + * Get the device and lock it for exclusive access
- + */
- +static int
- +nand_get_device(struct ra_nand_chip *ra, int new_state)
- +{
- + int ret = 0;
- +
- + ret = mutex_lock_interruptible(ra->controller);
- + if (!ret)
- + ra->state = new_state;
- +
- + return ret;
- +
- +}
- +
- +
- +
- +/*************************************************************
- + * nand internal process
- + *************************************************************/
- +
- +int nand_bbt_get(struct ra_nand_chip *ra, int block)
- +{
- + int byte, bits;
- + bits = block * BBTTAG_BITS;
- +
- + byte = bits / 8;
- + bits = bits % 8;
- +
- + return (ra->bbt[byte] >> bits) & BBTTAG_BITS_MASK;
- +}
- +
- +int nand_bbt_set(struct ra_nand_chip *ra, int block, int tag)
- +{
- + int byte, bits;
- + bits = block * BBTTAG_BITS;
- +
- + byte = bits / 8;
- + bits = bits % 8;
- +
- + // If previous tag is bad, dont overwrite it
- + if (((ra->bbt[byte] >> bits) & BBTTAG_BITS_MASK) == BBT_TAG_BAD)
- + {
- + return BBT_TAG_BAD;
- + }
- +
- + ra->bbt[byte] = (ra->bbt[byte] & ~(BBTTAG_BITS_MASK << bits)) | ((tag & BBTTAG_BITS_MASK) << bits);
- +
- + return tag;
- +}
- +
- +/**
- + * nand_block_checkbad - [GENERIC] Check if a block is marked bad
- + * @mtd: MTD device structure
- + * @ofs: offset from device start
- + *
- + * Check, if the block is bad. Either by reading the bad block table or
- + * calling of the scan function.
- + */
- +int nand_block_checkbad(struct ra_nand_chip *ra, loff_t offs)
- +{
- + int page, block;
- + int ret = 4;
- + unsigned int tag;
- + char *str[]= {"UNK", "RES", "BAD", "GOOD"};
- +
- + if (ranfc_bbt == 0)
- + return 0;
- +
- + {
- + // align with chip
- +
- + offs = offs & ((1<<ra->chip_shift) -1);
- +
- + page = offs >> ra->page_shift;
- + block = offs >> ra->erase_shift;
- + }
- +
- + tag = nand_bbt_get(ra, block);
- +
- + if (tag == BBT_TAG_UNKNOWN) {
- + ret = nfc_read_oob(ra, page, ra->badblockpos, (char*)&tag, 1, FLAG_NONE);
- + if (ret == 0)
- + tag = ((le32_to_cpu(tag) & 0x0ff) == 0x0ff) ? BBT_TAG_GOOD : BBT_TAG_BAD;
- + else
- + tag = BBT_TAG_BAD;
- +
- + nand_bbt_set(ra, block, tag);
- + }
- +
- + if (tag != BBT_TAG_GOOD) {
- + printk("%s: offs:%x tag: %s \n", __func__, (unsigned int)offs, str[tag]);
- + return 1;
- + }
- + else
- + return 0;
- +
- +}
- +
- +
- +
- +/**
- + * nand_block_markbad -
- + */
- +int nand_block_markbad(struct ra_nand_chip *ra, loff_t offs)
- +{
- + int page, block;
- + int ret = 4;
- + unsigned int tag;
- + char *ecc;
- +
- + // align with chip
- + ra_dbg("%s offs: %x \n", __func__, (int)offs);
- +
- + offs = offs & ((1<<ra->chip_shift) -1);
- +
- + page = offs >> ra->page_shift;
- + block = offs >> ra->erase_shift;
- +
- + tag = nand_bbt_get(ra, block);
- +
- + if (tag == BBT_TAG_BAD) {
- + printk("%s: mark repeatedly \n", __func__);
- + return 0;
- + }
- +
- + // new tag as bad
- + tag =BBT_TAG_BAD;
- + ret = nfc_read_page(ra, ra->buffers, page, FLAG_NONE);
- + if (ret != 0) {
- + printk("%s: fail to read bad block tag \n", __func__);
- + goto tag_bbt;
- + }
- +
- + ecc = &ra->buffers[(1<<ra->page_shift)+ra->badblockpos];
- + if (*ecc == (char)0x0ff) {
- + //tag into flash
- + *ecc = (char)tag;
- + ret = nfc_write_page(ra, ra->buffers, page, FLAG_USE_GDMA);
- + if (ret)
- + printk("%s: fail to write bad block tag \n", __func__);
- +
- + }
- +
- +tag_bbt:
- + //update bbt
- + nand_bbt_set(ra, block, tag);
- +
- + return 0;
- +}
- +
- +
- +#if defined (WORKAROUND_RX_BUF_OV)
- +/**
- + * to find a bad block for ecc verify of read_page
- + */
- +unsigned int nand_bbt_find_sandbox(struct ra_nand_chip *ra)
- +{
- + loff_t offs = 0;
- + int chipsize = 1 << ra->chip_shift;
- + int blocksize = 1 << ra->erase_shift;
- +
- +
- + while (offs < chipsize) {
- + if (nand_block_checkbad(ra, offs)) //scan and verify the unknown tag
- + break;
- + offs += blocksize;
- + }
- +
- + if (offs >= chipsize) {
- + offs = chipsize - blocksize;
- + }
- +
- + nand_bbt_set(ra, (unsigned int)offs>>ra->erase_shift, BBT_TAG_RES); // tag bbt only, instead of update badblockpos of flash.
- + return (offs >> ra->page_shift);
- +}
- +#endif
- +
- +
- +
- +/**
- + * nand_erase_nand - [Internal] erase block(s)
- + * @mtd: MTD device structure
- + * @instr: erase instruction
- + * @allowbbt: allow erasing the bbt area
- + *
- + * Erase one ore more blocks
- + */
- +int _nand_erase_nand(struct ra_nand_chip *ra, struct erase_info *instr)
- +{
- + int page, len, status, ret;
- + unsigned int addr, blocksize = 1<<ra->erase_shift;
- +
- + ra_dbg("%s: start:%x, len:%x \n", __func__,
- + (unsigned int)instr->addr, (unsigned int)instr->len);
- +
- +//#define BLOCK_ALIGNED(a) ((a) & (blocksize - 1)) // already defined
- +
- + if (BLOCK_ALIGNED(instr->addr) || BLOCK_ALIGNED(instr->len)) {
- + ra_dbg("%s: erase block not aligned, addr:%x len:%x\n", __func__, instr->addr, instr->len);
- + return -EINVAL;
- + }
- +
- + instr->fail_addr = 0xffffffff;
- +
- + len = instr->len;
- + addr = instr->addr;
- + instr->state = MTD_ERASING;
- +
- + while (len) {
- +
- + page = (int)(addr >> ra->page_shift);
- +
- + /* select device and check wp */
- + if (nfc_enable_chip(ra, addr, 0)) {
- + printk("%s: nand is write protected \n", __func__);
- + instr->state = MTD_ERASE_FAILED;
- + goto erase_exit;
- + }
- +
- + /* if we have a bad block, we do not erase bad blocks */
- + if (nand_block_checkbad(ra, addr)) {
- + printk(KERN_WARNING "nand_erase: attempt to erase a "
- + "bad block at 0x%08x\n", addr);
- + instr->state = MTD_ERASE_FAILED;
- + goto erase_exit;
- + }
- +
- + /*
- + * Invalidate the page cache, if we erase the block which
- + * contains the current cached page
- + */
- + if (BLOCK_ALIGNED(addr) == BLOCK_ALIGNED(ra->buffers_page << ra->page_shift))
- + ra->buffers_page = -1;
- +
- + status = nfc_erase_block(ra, page);
- + /* See if block erase succeeded */
- + if (status) {
- + printk("%s: failed erase, page 0x%08x\n", __func__, page);
- + instr->state = MTD_ERASE_FAILED;
- + instr->fail_addr = (page << ra->page_shift);
- + goto erase_exit;
- + }
- +
- +
- + /* Increment page address and decrement length */
- + len -= blocksize;
- + addr += blocksize;
- +
- + }
- + instr->state = MTD_ERASE_DONE;
- +
- +erase_exit:
- +
- + ret = ((instr->state == MTD_ERASE_DONE) ? 0 : -EIO);
- + /* Do call back function */
- + if (!ret)
- + mtd_erase_callback(instr);
- +
- + if (ret) {
- + nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
- + }
- +
- + /* Return more or less happy */
- + return ret;
- +}
- +
- +static int
- +nand_write_oob_buf(struct ra_nand_chip *ra, uint8_t *buf, uint8_t *oob, size_t size,
- + int mode, int ooboffs)
- +{
- + size_t oobsize = 1<<ra->oob_shift;
- + struct nand_oobfree *free;
- + uint32_t woffs = ooboffs;
- + int retsize = 0;
- +
- + ra_dbg("%s: size:%x, mode:%x, offs:%x \n", __func__, size, mode, ooboffs);
- +
- + switch(mode) {
- + case MTD_OPS_PLACE_OOB:
- + case MTD_OPS_RAW:
- + if (ooboffs > oobsize)
- + return -1;
- +
- + size = min(size, oobsize - ooboffs);
- + memcpy(buf + ooboffs, oob, size);
- + retsize = size;
- + break;
- +
- + case MTD_OPS_AUTO_OOB:
- + if (ooboffs > ra->oob->oobavail)
- + return -1;
- +
- + while (size) {
- + for(free = ra->oob->oobfree; free->length && size; free++) {
- + int wlen = free->length - woffs;
- + int bytes = 0;
- +
- + /* Write request not from offset 0 ? */
- + if (wlen <= 0) {
- + woffs = -wlen;
- + continue;
- + }
- +
- + bytes = min_t(size_t, size, wlen);
- + memcpy (buf + free->offset + woffs, oob, bytes);
- + woffs = 0;
- + oob += bytes;
- + size -= bytes;
- + retsize += bytes;
- + }
- + buf += oobsize;
- + }
- + break;
- +
- + default:
- + BUG();
- + }
- +
- + return retsize;
- +}
- +
- +static int nand_read_oob_buf(struct ra_nand_chip *ra, uint8_t *oob, size_t size,
- + int mode, int ooboffs)
- +{
- + size_t oobsize = 1<<ra->oob_shift;
- + uint8_t *buf = ra->buffers + (1<<ra->page_shift);
- + int retsize=0;
- +
- + ra_dbg("%s: size:%x, mode:%x, offs:%x \n", __func__, size, mode, ooboffs);
- +
- + switch(mode) {
- + case MTD_OPS_PLACE_OOB:
- + case MTD_OPS_RAW:
- + if (ooboffs > oobsize)
- + return -1;
- +
- + size = min(size, oobsize - ooboffs);
- + memcpy(oob, buf + ooboffs, size);
- + return size;
- +
- + case MTD_OPS_AUTO_OOB: {
- + struct nand_oobfree *free;
- + uint32_t woffs = ooboffs;
- +
- + if (ooboffs > ra->oob->oobavail)
- + return -1;
- +
- + size = min(size, ra->oob->oobavail - ooboffs);
- + for(free = ra->oob->oobfree; free->length && size; free++) {
- + int wlen = free->length - woffs;
- + int bytes = 0;
- +
- + /* Write request not from offset 0 ? */
- + if (wlen <= 0) {
- + woffs = -wlen;
- + continue;
- + }
- +
- + bytes = min_t(size_t, size, wlen);
- + memcpy (oob, buf + free->offset + woffs, bytes);
- + woffs = 0;
- + oob += bytes;
- + size -= bytes;
- + retsize += bytes;
- + }
- + return retsize;
- + }
- + default:
- + BUG();
- + }
- +
- + return -1;
- +}
- +
- +/**
- + * nand_do_write_ops - [Internal] NAND write with ECC
- + * @mtd: MTD device structure
- + * @to: offset to write to
- + * @ops: oob operations description structure
- + *
- + * NAND write with ECC
- + */
- +static int nand_do_write_ops(struct ra_nand_chip *ra, loff_t to,
- + struct mtd_oob_ops *ops)
- +{
- + int page;
- + uint32_t datalen = ops->len;
- + uint32_t ooblen = ops->ooblen;
- + uint8_t *oob = ops->oobbuf;
- + uint8_t *data = ops->datbuf;
- + int pagesize = (1<<ra->page_shift);
- + int pagemask = (pagesize -1);
- + int oobsize = 1<<ra->oob_shift;
- + loff_t addr = to;
- + //int i = 0; //for ra_dbg only
- +
- + ra_dbg("%s: to:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x oobmode:%x \n",
- + __func__, (unsigned int)to, data, oob, datalen, ooblen, ops->ooboffs, ops->mode);
- +
- + ops->retlen = 0;
- + ops->oobretlen = 0;
- +
- +
- + /* Invalidate the page cache, when we write to the cached page */
- + ra->buffers_page = -1;
- +
- +
- + if (data ==0)
- + datalen = 0;
- +
- + // oob sequential (burst) write
- + if (datalen == 0 && ooblen) {
- + int len = ((ooblen + ops->ooboffs) + (ra->oob->oobavail - 1)) / ra->oob->oobavail * oobsize;
- +
- + /* select chip, and check if it is write protected */
- + if (nfc_enable_chip(ra, addr, 0))
- + return -EIO;
- +
- + //FIXME, need sanity check of block boundary
- + page = (int)((to & ((1<<ra->chip_shift)-1)) >> ra->page_shift); //chip boundary
- + memset(ra->buffers, 0x0ff, pagesize);
- + //fixme, should we reserve the original content?
- + if (ops->mode == MTD_OPS_AUTO_OOB) {
- + nfc_read_oob(ra, page, 0, ra->buffers, len, FLAG_NONE);
- + }
- + //prepare buffers
- + if (ooblen != 8)
- + {
- + nand_write_oob_buf(ra, ra->buffers, oob, ooblen, ops->mode, ops->ooboffs);
- + // write out buffer to chip
- + nfc_write_oob(ra, page, 0, ra->buffers, len, FLAG_USE_GDMA);
- + }
- +
- + ops->oobretlen = ooblen;
- + ooblen = 0;
- + }
- +
- + // data sequential (burst) write
- + if (datalen && ooblen == 0) {
- + // ranfc can not support write_data_burst, since hw-ecc and fifo constraints..
- + }
- +
- + // page write
- + while(datalen || ooblen) {
- + int len;
- + int ret;
- + int offs;
- + int ecc_en = 0;
- +
- + ra_dbg("%s (%d): addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n",
- + __func__, i++, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
- +
- + page = (int)((addr & ((1<<ra->chip_shift)-1)) >> ra->page_shift); //chip boundary
- +
- + /* select chip, and check if it is write protected */
- + if (nfc_enable_chip(ra, addr, 0))
- + return -EIO;
- +
- + // oob write
- + if (ops->mode == MTD_OPS_AUTO_OOB) {
- + //fixme, this path is not yet varified
- + nfc_read_oob(ra, page, 0, ra->buffers + pagesize, oobsize, FLAG_NONE);
- + }
- + if (oob && ooblen > 0) {
- + len = nand_write_oob_buf(ra, ra->buffers + pagesize, oob, ooblen, ops->mode, ops->ooboffs);
- + if (len < 0)
- + return -EINVAL;
- +
- + oob += len;
- + ops->oobretlen += len;
- + ooblen -= len;
- + }
- +
- + // data write
- + offs = addr & pagemask;
- + len = min_t(size_t, datalen, pagesize - offs);
- + if (data && len > 0) {
- + memcpy(ra->buffers + offs, data, len); // we can not sure ops->buf wether is DMA-able.
- +
- + data += len;
- + datalen -= len;
- + ops->retlen += len;
- +
- + ecc_en = FLAG_ECC_EN;
- + }
- + ret = nfc_write_page(ra, ra->buffers, page, FLAG_USE_GDMA | FLAG_VERIFY |
- + ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0 : ecc_en ));
- + if (ret) {
- + nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
- + return ret;
- + }
- +
- + nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_GOOD);
- +
- + addr = (page+1) << ra->page_shift;
- +
- + }
- + return 0;
- +}
- +
- +/**
- + * nand_do_read_ops - [Internal] Read data with ECC
- + *
- + * @mtd: MTD device structure
- + * @from: offset to read from
- + * @ops: oob ops structure
- + *
- + * Internal function. Called with chip held.
- + */
- +static int nand_do_read_ops(struct ra_nand_chip *ra, loff_t from,
- + struct mtd_oob_ops *ops)
- +{
- + int page;
- + uint32_t datalen = ops->len;
- + uint32_t ooblen = ops->ooblen;
- + uint8_t *oob = ops->oobbuf;
- + uint8_t *data = ops->datbuf;
- + int pagesize = (1<<ra->page_shift);
- + int pagemask = (pagesize -1);
- + loff_t addr = from;
- + //int i = 0; //for ra_dbg only
- +
- + ra_dbg("%s: addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n",
- + __func__, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
- +
- + ops->retlen = 0;
- + ops->oobretlen = 0;
- + if (data == 0)
- + datalen = 0;
- +
- +
- + while(datalen || ooblen) {
- + int len;
- + int ret;
- + int offs;
- +
- + ra_dbg("%s (%d): addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n",
- + __func__, i++, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
- + /* select chip */
- + if (nfc_enable_chip(ra, addr, 1) < 0)
- + return -EIO;
- +
- + page = (int)((addr & ((1<<ra->chip_shift)-1)) >> ra->page_shift);
- +
- + ret = nfc_read_page(ra, ra->buffers, page, FLAG_VERIFY |
- + ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0: FLAG_ECC_EN ));
- + //FIXME, something strange here, some page needs 2 more tries to guarantee read success.
- + if (ret) {
- + printk("read again:\n");
- + ret = nfc_read_page(ra, ra->buffers, page, FLAG_VERIFY |
- + ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0: FLAG_ECC_EN ));
- +
- + if (ret) {
- + printk("read again fail \n");
- + nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
- + if ((ret != -EUCLEAN) && (ret != -EBADMSG)) {
- + return ret;
- + }
- + else {
- + /* ecc verification fail, but data need to be returned. */
- + }
- + }
- + else {
- + printk(" read agian susccess \n");
- + }
- + }
- +
- + // oob read
- + if (oob && ooblen > 0) {
- + len = nand_read_oob_buf(ra, oob, ooblen, ops->mode, ops->ooboffs);
- + if (len < 0) {
- + printk("nand_read_oob_buf: fail return %x \n", len);
- + return -EINVAL;
- + }
- +
- + oob += len;
- + ops->oobretlen += len;
- + ooblen -= len;
- + }
- +
- + // data read
- + offs = addr & pagemask;
- + len = min_t(size_t, datalen, pagesize - offs);
- + if (data && len > 0) {
- + memcpy(data, ra->buffers + offs, len); // we can not sure ops->buf wether is DMA-able.
- +
- + data += len;
- + datalen -= len;
- + ops->retlen += len;
- + if (ret)
- + return ret;
- + }
- +
- +
- + nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_GOOD);
- + // address go further to next page, instead of increasing of length of write. This avoids some special cases wrong.
- + addr = (page+1) << ra->page_shift;
- + }
- + return 0;
- +}
- +
- +static int
- +ramtd_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
- +{
- + struct ra_nand_chip *ra = (struct ra_nand_chip *)mtd->priv;
- + int ret;
- +
- + ra_dbg("%s: start:%x, len:%x \n", __func__,
- + (unsigned int)instr->addr, (unsigned int)instr->len);
- +
- + nand_get_device(ra, FL_ERASING);
- + ret = _nand_erase_nand((struct ra_nand_chip *)mtd->priv, instr);
- + nand_release_device(ra);
- +
- + return ret;
- +}
- +
- +static int
- +ramtd_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
- + size_t *retlen, const uint8_t *buf)
- +{
- + struct ra_nand_chip *ra = mtd->priv;
- + struct mtd_oob_ops ops;
- + int ret;
- +
- + ra_dbg("%s: to 0x%x len=0x%x\n", __func__, to, len);
- +
- + if ((to + len) > mtd->size)
- + return -EINVAL;
- +
- + if (!len)
- + return 0;
- +
- + nand_get_device(ra, FL_WRITING);
- +
- + memset(&ops, 0, sizeof(ops));
- + ops.len = len;
- + ops.datbuf = (uint8_t *)buf;
- + ops.oobbuf = NULL;
- + ops.mode = MTD_OPS_AUTO_OOB;
- +
- + ret = nand_do_write_ops(ra, to, &ops);
- +
- + *retlen = ops.retlen;
- +
- + nand_release_device(ra);
- +
- + return ret;
- +}
- +
- +static int
- +ramtd_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
- + size_t *retlen, uint8_t *buf)
- +{
- +
- + struct ra_nand_chip *ra = mtd->priv;
- + int ret;
- + struct mtd_oob_ops ops;
- +
- + ra_dbg("%s: mtd:%p from:%x, len:%x, buf:%p \n", __func__, mtd, (unsigned int)from, len, buf);
- +
- + /* Do not allow reads past end of device */
- + if ((from + len) > mtd->size)
- + return -EINVAL;
- + if (!len)
- + return 0;
- +
- + nand_get_device(ra, FL_READING);
- +
- + memset(&ops, 0, sizeof(ops));
- + ops.len = len;
- + ops.datbuf = buf;
- + ops.oobbuf = NULL;
- + ops.mode = MTD_OPS_AUTO_OOB;
- +
- + ret = nand_do_read_ops(ra, from, &ops);
- +
- + *retlen = ops.retlen;
- +
- + nand_release_device(ra);
- +
- + return ret;
- +
- +}
- +
- +static int
- +ramtd_nand_readoob(struct mtd_info *mtd, loff_t from,
- + struct mtd_oob_ops *ops)
- +{
- + struct ra_nand_chip *ra = mtd->priv;
- + int ret;
- +
- + ra_dbg("%s: \n", __func__);
- +
- + nand_get_device(ra, FL_READING);
- +
- + ret = nand_do_read_ops(ra, from, ops);
- +
- + nand_release_device(ra);
- +
- + return ret;
- +}
- +
- +static int
- +ramtd_nand_writeoob(struct mtd_info *mtd, loff_t to,
- + struct mtd_oob_ops *ops)
- +{
- + struct ra_nand_chip *ra = mtd->priv;
- + int ret;
- +
- + nand_get_device(ra, FL_READING);
- + ret = nand_do_write_ops(ra, to, ops);
- + nand_release_device(ra);
- +
- + return ret;
- +}
- +
- +static int
- +ramtd_nand_block_isbad(struct mtd_info *mtd, loff_t offs)
- +{
- + if (offs > mtd->size)
- + return -EINVAL;
- +
- + return nand_block_checkbad((struct ra_nand_chip *)mtd->priv, offs);
- +}
- +
- +static int
- +ramtd_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
- +{
- + struct ra_nand_chip *ra = mtd->priv;
- + int ret;
- +
- + ra_dbg("%s: \n", __func__);
- + nand_get_device(ra, FL_WRITING);
- + ret = nand_block_markbad(ra, ofs);
- + nand_release_device(ra);
- +
- + return ret;
- +}
- +
- +// 1-bit error detection
- +static int one_bit_correction(char *ecc1, char *ecc2, int *bytes, int *bits)
- +{
- + // check if ecc and expected are all valid
- + char *p, nibble, crumb;
- + int i, xor, iecc1 = 0, iecc2 = 0;
- +
- + printk("correction : %x %x %x\n", ecc1[0], ecc1[1], ecc1[2]);
- + printk("correction : %x %x %x\n", ecc2[0], ecc2[1], ecc2[2]);
- +
- + p = (char *)ecc1;
- + for (i = 0; i < CONFIG_ECC_BYTES; i++)
- + {
- + nibble = *(p+i) & 0xf;
- + if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
- + (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
- + return -1;
- + nibble = ((*(p+i)) >> 4) & 0xf;
- + if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
- + (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
- + return -1;
- + }
- +
- + p = (char *)ecc2;
- + for (i = 0; i < CONFIG_ECC_BYTES; i++)
- + {
- + nibble = *(p+i) & 0xf;
- + if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
- + (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
- + return -1;
- + nibble = ((*(p+i)) >> 4) & 0xf;
- + if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
- + (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
- + return -1;
- + }
- +
- + memcpy(&iecc1, ecc1, 3);
- + memcpy(&iecc2, ecc2, 3);
- +
- + xor = iecc1 ^ iecc2;
- + printk("xor = %x (%x %x)\n", xor, iecc1, iecc2);
- +
- + *bytes = 0;
- + for (i = 0; i < 9; i++)
- + {
- + crumb = (xor >> (2*i)) & 0x3;
- + if ((crumb == 0x0) || (crumb == 0x3))
- + return -1;
- + if (crumb == 0x2)
- + *bytes += (1 << i);
- + }
- +
- + *bits = 0;
- + for (i = 0; i < 3; i++)
- + {
- + crumb = (xor >> (18 + 2*i)) & 0x3;
- + if ((crumb == 0x0) || (crumb == 0x3))
- + return -1;
- + if (crumb == 0x2)
- + *bits += (1 << i);
- + }
- +
- + return 0;
- +}
- +
- +
- +
- +/************************************************************
- + * the init/exit section.
- + */
- +
- +static struct nand_ecclayout ra_oob_layout = {
- + .eccbytes = CONFIG_ECC_BYTES,
- + .eccpos = {5, 6, 7},
- + .oobfree = {
- + {.offset = 0, .length = 4},
- + {.offset = 8, .length = 8},
- + {.offset = 0, .length = 0}
- + },
- +#define RA_CHIP_OOB_AVAIL (4+8)
- + .oobavail = RA_CHIP_OOB_AVAIL,
- + // 5th byte is bad-block flag.
- +};
- +
- +static int
- +mtk_nand_probe(struct platform_device *pdev)
- +{
- + struct mtd_part_parser_data ppdata;
- + struct ra_nand_chip *ra;
- + int alloc_size, bbt_size, buffers_size, reg, err;
- + unsigned char chip_mode = 12;
- +
- +/* if(ra_check_flash_type()!=BOOT_FROM_NAND) {
- + return 0;
- + }*/
- +
- + //FIXME: config 512 or 2048-byte page according to HWCONF
- +#if defined (CONFIG_RALINK_RT6855A)
- + reg = ra_inl(RALINK_SYSCTL_BASE+0x8c);
- + chip_mode = ((reg>>28) & 0x3)|(((reg>>22) & 0x3)<<2);
- + if (chip_mode == 1) {
- + printk("! nand 2048\n");
- + ra_or(NFC_CONF1, 1);
- + is_nand_page_2048 = 1;
- + nand_addrlen = 5;
- + }
- + else {
- + printk("! nand 512\n");
- + ra_and(NFC_CONF1, ~1);
- + is_nand_page_2048 = 0;
- + nand_addrlen = 4;
- + }
- +#elif (defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_RT6855))
- + ra_outl(RALINK_SYSCTL_BASE+0x60, ra_inl(RALINK_SYSCTL_BASE+0x60) & ~(0x3<<18));
- + reg = ra_inl(RALINK_SYSCTL_BASE+0x10);
- + chip_mode = (reg & 0x0F);
- + if((chip_mode==1)||(chip_mode==11)) {
- + ra_or(NFC_CONF1, 1);
- + is_nand_page_2048 = 1;
- + nand_addrlen = ((chip_mode!=11) ? 4 : 5);
- + printk("!!! nand page size = 2048, addr len=%d\n", nand_addrlen);
- + }
- + else {
- + ra_and(NFC_CONF1, ~1);
- + is_nand_page_2048 = 0;
- + nand_addrlen = ((chip_mode!=10) ? 3 : 4);
- + printk("!!! nand page size = 512, addr len=%d\n", nand_addrlen);
- + }
- +#else
- + is_nand_page_2048 = 0;
- + nand_addrlen = 3;
- + printk("!!! nand page size = 512, addr len=%d\n", nand_addrlen);
- +#endif
- +
- +#if defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_RT6855)
- + //config ECC location
- + ra_and(NFC_CONF1, 0xfff000ff);
- + ra_or(NFC_CONF1, ((CONFIG_ECC_OFFSET + 2) << 16) +
- + ((CONFIG_ECC_OFFSET + 1) << 12) +
- + (CONFIG_ECC_OFFSET << 8));
- +#endif
- +
- +#define ALIGNE_16(a) (((unsigned long)(a)+15) & ~15)
- + buffers_size = ALIGNE_16((1<<CONFIG_PAGE_SIZE_BIT) + (1<<CONFIG_OOBSIZE_PER_PAGE_BIT)); //ra->buffers
- + bbt_size = BBTTAG_BITS * (1<<(CONFIG_CHIP_SIZE_BIT - (CONFIG_PAGE_SIZE_BIT + CONFIG_NUMPAGE_PER_BLOCK_BIT))) / 8; //ra->bbt
- + bbt_size = ALIGNE_16(bbt_size);
- +
- + alloc_size = buffers_size + bbt_size;
- + alloc_size += buffers_size; //for ra->readback_buffers
- + alloc_size += sizeof(*ra);
- + alloc_size += sizeof(*ranfc_mtd);
- +
- + //make sure gpio-0 is input
- + ra_outl(RALINK_PIO_BASE+0x24, ra_inl(RALINK_PIO_BASE+0x24) & ~0x01);
- +
- + ra = (struct ra_nand_chip *)kzalloc(alloc_size, GFP_KERNEL | GFP_DMA);
- + if (!ra) {
- + printk("%s: mem alloc fail \n", __func__);
- + return -ENOMEM;
- + }
- + memset(ra, 0, alloc_size);
- +
- + //dynamic
- + ra->buffers = (char *)((char *)ra + sizeof(*ra));
- + ra->readback_buffers = ra->buffers + buffers_size;
- + ra->bbt = ra->readback_buffers + buffers_size;
- + ranfc_mtd = (struct mtd_info *)(ra->bbt + bbt_size);
- +
- + //static
- + ra->numchips = CONFIG_NUMCHIPS;
- + ra->chip_shift = CONFIG_CHIP_SIZE_BIT;
- + ra->page_shift = CONFIG_PAGE_SIZE_BIT;
- + ra->oob_shift = CONFIG_OOBSIZE_PER_PAGE_BIT;
- + ra->erase_shift = (CONFIG_PAGE_SIZE_BIT + CONFIG_NUMPAGE_PER_BLOCK_BIT);
- + ra->badblockpos = CONFIG_BAD_BLOCK_POS;
- + ra_oob_layout.eccpos[0] = CONFIG_ECC_OFFSET;
- + ra_oob_layout.eccpos[1] = CONFIG_ECC_OFFSET + 1;
- + ra_oob_layout.eccpos[2] = CONFIG_ECC_OFFSET + 2;
- + ra->oob = &ra_oob_layout;
- + ra->buffers_page = -1;
- +
- +#if defined (WORKAROUND_RX_BUF_OV)
- + if (ranfc_verify) {
- + ra->sandbox_page = nand_bbt_find_sandbox(ra);
- + }
- +#endif
- + ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x01); //set wp to high
- + nfc_all_reset();
- +
- + ranfc_mtd->type = MTD_NANDFLASH;
- + ranfc_mtd->flags = MTD_CAP_NANDFLASH;
- + ranfc_mtd->size = CONFIG_NUMCHIPS * CFG_CHIPSIZE;
- + ranfc_mtd->erasesize = CFG_BLOCKSIZE;
- + ranfc_mtd->writesize = CFG_PAGESIZE;
- + ranfc_mtd->oobsize = CFG_PAGE_OOBSIZE;
- + ranfc_mtd->oobavail = RA_CHIP_OOB_AVAIL;
- + ranfc_mtd->name = "ra_nfc";
- + //ranfc_mtd->index
- + ranfc_mtd->ecclayout = &ra_oob_layout;
- + //ranfc_mtd->numberaseregions
- + //ranfc_mtd->eraseregions
- + //ranfc_mtd->bansize
- + ranfc_mtd->_erase = ramtd_nand_erase;
- + //ranfc_mtd->point
- + //ranfc_mtd->unpoint
- + ranfc_mtd->_read = ramtd_nand_read;
- + ranfc_mtd->_write = ramtd_nand_write;
- + ranfc_mtd->_read_oob = ramtd_nand_readoob;
- + ranfc_mtd->_write_oob = ramtd_nand_writeoob;
- + //ranfc_mtd->get_fact_prot_info; ranfc_mtd->read_fact_prot_reg;
- + //ranfc_mtd->get_user_prot_info; ranfc_mtd->read_user_prot_reg;
- + //ranfc_mtd->write_user_prot_reg; ranfc_mtd->lock_user_prot_reg;
- + //ranfc_mtd->writev; ranfc_mtd->sync; ranfc_mtd->lock; ranfc_mtd->unlock; ranfc_mtd->suspend; ranfc_mtd->resume;
- + ranfc_mtd->_block_isbad = ramtd_nand_block_isbad;
- + ranfc_mtd->_block_markbad = ramtd_nand_block_markbad;
- + //ranfc_mtd->reboot_notifier
- + //ranfc_mtd->ecc_stats;
- + // subpage_sht;
- +
- + //ranfc_mtd->get_device; ranfc_mtd->put_device
- + ranfc_mtd->priv = ra;
- +
- + ranfc_mtd->owner = THIS_MODULE;
- + ra->controller = &ra->hwcontrol;
- + mutex_init(ra->controller);
- +
- + printk("%s: alloc %x, at %p , btt(%p, %x), ranfc_mtd:%p\n",
- + __func__ , alloc_size, ra, ra->bbt, bbt_size, ranfc_mtd);
- +
- + ppdata.of_node = pdev->dev.of_node;
- + err = mtd_device_parse_register(ranfc_mtd, mtk_probe_types,
- + &ppdata, NULL, 0);
- +
- + return err;
- +}
- +
- +static int
- +mtk_nand_remove(struct platform_device *pdev)
- +{
- + struct ra_nand_chip *ra;
- +
- + if (ranfc_mtd) {
- + ra = (struct ra_nand_chip *)ranfc_mtd->priv;
- +
- + /* Deregister partitions */
- + //del_mtd_partitions(ranfc_mtd);
- + kfree(ra);
- + }
- + return 0;
- +}
- +
- +static const struct of_device_id mtk_nand_match[] = {
- + { .compatible = "mtk,mt7620-nand" },
- + {},
- +};
- +MODULE_DEVICE_TABLE(of, mtk_nand_match);
- +
- +static struct platform_driver mtk_nand_driver = {
- + .probe = mtk_nand_probe,
- + .remove = mtk_nand_remove,
- + .driver = {
- + .name = "mt7620_nand",
- + .owner = THIS_MODULE,
- + .of_match_table = mtk_nand_match,
- + },
- +};
- +
- +module_platform_driver(mtk_nand_driver);
- +
- +
- +MODULE_LICENSE("GPL");
- --- /dev/null
- +++ b/drivers/mtd/maps/ralink_nand.h
- @@ -0,0 +1,232 @@
- +#ifndef RT2880_NAND_H
- +#define RT2880_NAND_H
- +
- +#include <linux/mtd/mtd.h>
- +
- +//#include "gdma.h"
- +
- +#define RALINK_SYSCTL_BASE 0xB0000000
- +#define RALINK_PIO_BASE 0xB0000600
- +#define RALINK_NAND_CTRL_BASE 0xB0000810
- +#define CONFIG_RALINK_MT7620
- +
- +#define SKIP_BAD_BLOCK
- +//#define RANDOM_GEN_BAD_BLOCK
- +
- +#define ra_inl(addr) (*(volatile unsigned int *)(addr))
- +#define ra_outl(addr, value) (*(volatile unsigned int *)(addr) = (value))
- +#define ra_aor(addr, a_mask, o_value) ra_outl(addr, (ra_inl(addr) & (a_mask)) | (o_value))
- +#define ra_and(addr, a_mask) ra_aor(addr, a_mask, 0)
- +#define ra_or(addr, o_value) ra_aor(addr, -1, o_value)
- +
- +
- +#define CONFIG_NUMCHIPS 1
- +#define CONFIG_NOT_SUPPORT_WP //rt3052 has no WP signal for chip.
- +//#define CONFIG_NOT_SUPPORT_RB
- +
- +extern int is_nand_page_2048;
- +extern const unsigned int nand_size_map[2][3];
- +
- +//chip
- +// chip geometry: SAMSUNG small size 32MB.
- +#define CONFIG_CHIP_SIZE_BIT (nand_size_map[is_nand_page_2048][nand_addrlen-3]) //! (1<<NAND_SIZE_BYTE) MB
- +//#define CONFIG_CHIP_SIZE_BIT (is_nand_page_2048? 29 : 25) //! (1<<NAND_SIZE_BYTE) MB
- +#define CONFIG_PAGE_SIZE_BIT (is_nand_page_2048? 11 : 9) //! (1<<PAGE_SIZE) MB
- +//#define CONFIG_SUBPAGE_BIT 1 //! these bits will be compensate by command cycle
- +#define CONFIG_NUMPAGE_PER_BLOCK_BIT (is_nand_page_2048? 6 : 5) //! order of number of pages a block.
- +#define CONFIG_OOBSIZE_PER_PAGE_BIT (is_nand_page_2048? 6 : 4) //! byte number of oob a page.
- +#define CONFIG_BAD_BLOCK_POS (is_nand_page_2048? 0 : 4) //! offset of byte to denote bad block.
- +#define CONFIG_ECC_BYTES 3 //! ecc has 3 bytes
- +#define CONFIG_ECC_OFFSET (is_nand_page_2048? 6 : 5) //! ecc starts from offset 5.
- +
- +//this section should not be modified.
- +//#define CFG_COLUMN_ADDR_MASK ((1 << (CONFIG_PAGE_SIZE_BIT - CONFIG_SUBPAGE_BIT)) - 1)
- +//#define CFG_COLUMN_ADDR_CYCLE (((CONFIG_PAGE_SIZE_BIT - CONFIG_SUBPAGE_BIT) + 7)/8)
- +//#define CFG_ROW_ADDR_CYCLE ((CONFIG_CHIP_SIZE_BIT - CONFIG_PAGE_SIZE_BIT + 7)/8)
- +//#define CFG_ADDR_CYCLE (CFG_COLUMN_ADDR_CYCLE + CFG_ROW_ADDR_CYCLE)
- +
- +#define CFG_COLUMN_ADDR_CYCLE (is_nand_page_2048? 2 : 1)
- +#define CFG_ROW_ADDR_CYCLE (nand_addrlen - CFG_COLUMN_ADDR_CYCLE)
- +#define CFG_ADDR_CYCLE (CFG_COLUMN_ADDR_CYCLE + CFG_ROW_ADDR_CYCLE)
- +
- +#define CFG_CHIPSIZE (1 << ((CONFIG_CHIP_SIZE_BIT>=32)? 31 : CONFIG_CHIP_SIZE_BIT))
- +//#define CFG_CHIPSIZE (1 << CONFIG_CHIP_SIZE_BIT)
- +#define CFG_PAGESIZE (1 << CONFIG_PAGE_SIZE_BIT)
- +#define CFG_BLOCKSIZE (CFG_PAGESIZE << CONFIG_NUMPAGE_PER_BLOCK_BIT)
- +#define CFG_NUMPAGE (1 << (CONFIG_CHIP_SIZE_BIT - CONFIG_PAGE_SIZE_BIT))
- +#define CFG_NUMBLOCK (CFG_NUMPAGE >> CONFIG_NUMPAGE_PER_BLOCK_BIT)
- +#define CFG_BLOCK_OOBSIZE (1 << (CONFIG_OOBSIZE_PER_PAGE_BIT + CONFIG_NUMPAGE_PER_BLOCK_BIT))
- +#define CFG_PAGE_OOBSIZE (1 << CONFIG_OOBSIZE_PER_PAGE_BIT)
- +
- +#define NAND_BLOCK_ALIGN(addr) ((addr) & (CFG_BLOCKSIZE-1))
- +#define NAND_PAGE_ALIGN(addr) ((addr) & (CFG_PAGESIZE-1))
- +
- +
- +#define NFC_BASE RALINK_NAND_CTRL_BASE
- +#define NFC_CTRL (NFC_BASE + 0x0)
- +#define NFC_CONF (NFC_BASE + 0x4)
- +#define NFC_CMD1 (NFC_BASE + 0x8)
- +#define NFC_CMD2 (NFC_BASE + 0xc)
- +#define NFC_CMD3 (NFC_BASE + 0x10)
- +#define NFC_ADDR (NFC_BASE + 0x14)
- +#define NFC_DATA (NFC_BASE + 0x18)
- +#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
- + defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)
- +#define NFC_ECC (NFC_BASE + 0x30)
- +#else
- +#define NFC_ECC (NFC_BASE + 0x1c)
- +#endif
- +#define NFC_STATUS (NFC_BASE + 0x20)
- +#define NFC_INT_EN (NFC_BASE + 0x24)
- +#define NFC_INT_ST (NFC_BASE + 0x28)
- +#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
- + defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)
- +#define NFC_CONF1 (NFC_BASE + 0x2c)
- +#define NFC_ECC_P1 (NFC_BASE + 0x30)
- +#define NFC_ECC_P2 (NFC_BASE + 0x34)
- +#define NFC_ECC_P3 (NFC_BASE + 0x38)
- +#define NFC_ECC_P4 (NFC_BASE + 0x3c)
- +#define NFC_ECC_ERR1 (NFC_BASE + 0x40)
- +#define NFC_ECC_ERR2 (NFC_BASE + 0x44)
- +#define NFC_ECC_ERR3 (NFC_BASE + 0x48)
- +#define NFC_ECC_ERR4 (NFC_BASE + 0x4c)
- +#define NFC_ADDR2 (NFC_BASE + 0x50)
- +#endif
- +
- +enum _int_stat {
- + INT_ST_ND_DONE = 1<<0,
- + INT_ST_TX_BUF_RDY = 1<<1,
- + INT_ST_RX_BUF_RDY = 1<<2,
- + INT_ST_ECC_ERR = 1<<3,
- + INT_ST_TX_TRAS_ERR = 1<<4,
- + INT_ST_RX_TRAS_ERR = 1<<5,
- + INT_ST_TX_KICK_ERR = 1<<6,
- + INT_ST_RX_KICK_ERR = 1<<7
- +};
- +
- +
- +//#define WORKAROUND_RX_BUF_OV 1
- +
- +
- +/*************************************************************
- + * stolen from nand.h
- + *************************************************************/
- +
- +/*
- + * Standard NAND flash commands
- + */
- +#define NAND_CMD_READ0 0
- +#define NAND_CMD_READ1 1
- +#define NAND_CMD_RNDOUT 5
- +#define NAND_CMD_PAGEPROG 0x10
- +#define NAND_CMD_READOOB 0x50
- +#define NAND_CMD_ERASE1 0x60
- +#define NAND_CMD_STATUS 0x70
- +#define NAND_CMD_STATUS_MULTI 0x71
- +#define NAND_CMD_SEQIN 0x80
- +#define NAND_CMD_RNDIN 0x85
- +#define NAND_CMD_READID 0x90
- +#define NAND_CMD_ERASE2 0xd0
- +#define NAND_CMD_RESET 0xff
- +
- +/* Extended commands for large page devices */
- +#define NAND_CMD_READSTART 0x30
- +#define NAND_CMD_RNDOUTSTART 0xE0
- +#define NAND_CMD_CACHEDPROG 0x15
- +
- +/* Extended commands for AG-AND device */
- +/*
- + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
- + * there is no way to distinguish that from NAND_CMD_READ0
- + * until the remaining sequence of commands has been completed
- + * so add a high order bit and mask it off in the command.
- + */
- +#define NAND_CMD_DEPLETE1 0x100
- +#define NAND_CMD_DEPLETE2 0x38
- +#define NAND_CMD_STATUS_MULTI 0x71
- +#define NAND_CMD_STATUS_ERROR 0x72
- +/* multi-bank error status (banks 0-3) */
- +#define NAND_CMD_STATUS_ERROR0 0x73
- +#define NAND_CMD_STATUS_ERROR1 0x74
- +#define NAND_CMD_STATUS_ERROR2 0x75
- +#define NAND_CMD_STATUS_ERROR3 0x76
- +#define NAND_CMD_STATUS_RESET 0x7f
- +#define NAND_CMD_STATUS_CLEAR 0xff
- +
- +#define NAND_CMD_NONE -1
- +
- +/* Status bits */
- +#define NAND_STATUS_FAIL 0x01
- +#define NAND_STATUS_FAIL_N1 0x02
- +#define NAND_STATUS_TRUE_READY 0x20
- +#define NAND_STATUS_READY 0x40
- +#define NAND_STATUS_WP 0x80
- +
- +typedef enum {
- + FL_READY,
- + FL_READING,
- + FL_WRITING,
- + FL_ERASING,
- + FL_SYNCING,
- + FL_CACHEDPRG,
- + FL_PM_SUSPENDED,
- +} nand_state_t;
- +
- +/*************************************************************/
- +
- +
- +
- +typedef enum _ra_flags {
- + FLAG_NONE = 0,
- + FLAG_ECC_EN = (1<<0),
- + FLAG_USE_GDMA = (1<<1),
- + FLAG_VERIFY = (1<<2),
- +} RA_FLAGS;
- +
- +
- +#define BBTTAG_BITS 2
- +#define BBTTAG_BITS_MASK ((1<<BBTTAG_BITS) -1)
- +enum BBT_TAG {
- + BBT_TAG_UNKNOWN = 0, //2'b01
- + BBT_TAG_GOOD = 3, //2'b11
- + BBT_TAG_BAD = 2, //2'b10
- + BBT_TAG_RES = 1, //2'b01
- +};
- +
- +struct ra_nand_chip {
- + int numchips;
- + int chip_shift;
- + int page_shift;
- + int erase_shift;
- + int oob_shift;
- + int badblockpos;
- +#if !defined (__UBOOT__)
- + struct mutex hwcontrol;
- + struct mutex *controller;
- +#endif
- + struct nand_ecclayout *oob;
- + int state;
- + unsigned int buffers_page;
- + char *buffers; //[CFG_PAGESIZE + CFG_PAGE_OOBSIZE];
- + char *readback_buffers;
- + unsigned char *bbt;
- +#if defined (WORKAROUND_RX_BUF_OV)
- + unsigned int sandbox_page; // steal a page (block) for read ECC verification
- +#endif
- +
- +};
- +
- +
- +
- +//fixme, gdma api
- +int nand_dma_sync(void);
- +void release_dma_buf(void);
- +int set_gdma_ch(unsigned long dst,
- + unsigned long src, unsigned int len, int burst_size,
- + int soft_mode, int src_req_type, int dst_req_type,
- + int src_burst_mode, int dst_burst_mode);
- +
- +
- +
- +
- +#endif
|