123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761 |
- // linux/drivers/amlogic/nand/aml_nand.c
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/string.h>
- #include <linux/ioport.h>
- #include <linux/platform_device.h>
- #include <linux/delay.h>
- #include <linux/err.h>
- #include <linux/slab.h>
- #include <linux/io.h>
- #include <linux/bitops.h>
- #include <linux/crc32.h>
- #include <linux/fs.h>
- #include <asm/uaccess.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/nand_ecc.h>
- #include <linux/mtd/partitions.h>
- #include <mach/nand.h>
- #define NAND_DEBUG
- #ifdef NAND_DEBUG
- #define aml_nand_debug(a...) {printk("%s()[%s,%d]",__func__,__FILE__,__LINE__); printk(a);}
- #define aml_nand_debug2(a...) //printk(a)
- #else
- #define aml_nand_debug(a...)
- #define aml_nand_debug2(a...)
- #endif
- static char *aml_nand_bch_string[]={
- "NAND_SOFT_MODE",
- "NAND_BCH9_MODE",
- "NAND_BCH8_MODE",
- "NAND_BCH12_MODE",
- "NAND_BCH16_MODE",
- };
- static char *aml_nand_plane_string[]={
- "NAND_SINGLE_PLANE_MODE",
- "NAND_TWO_PLANE_MODE",
- };
- static char *aml_nand_internal_string[]={
- "NAND_NONE_INTERLEAVING_MODE",
- "NAND_INTERLEAVING_MODE",
- };
- static struct nand_ecclayout aml_nand_oob_64 = {
- .eccbytes = 60,
- .eccpos = {
- 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 40, 41, 42, 43,
- 44, 45, 46, 47, 48, 49, 50, 51,
- 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 62, 63},
- .oobfree = {
- {.offset = 0,
- .length = 4}}
- };
- static struct nand_ecclayout aml_nand_uboot_oob = {
- .eccbytes = 84,
- .oobfree = {
- {.offset = 0,
- .length = 6}}
- };
- static struct nand_ecclayout aml_nand_oob_64_2info = {
- .eccbytes = 56,
- .oobfree = {
- {.offset = 0,
- .length = 8}}
- };
- static struct nand_ecclayout aml_nand_oob_128 = {
- .eccbytes = 120,
- .oobfree = {
- {.offset = 0,
- .length = 8}}
- };
- static struct nand_ecclayout aml_nand_oob_218 = {
- .eccbytes = 200,
- .oobfree = {
- {.offset = 0,
- .length = 8}}
- };
- static struct nand_ecclayout aml_nand_oob_224 = {
- .eccbytes = 208,
- .oobfree = {
- {.offset = 0,
- .length = 8}}
- };
- static struct nand_ecclayout aml_nand_oob_256 = {
- .eccbytes = 240,
- .oobfree = {
- {.offset = 0,
- .length = 16}}
- };
- static struct nand_ecclayout aml_nand_oob_376 = {
- .eccbytes = 352,
- .oobfree = {
- {.offset = 0,
- .length = 16}}
- };
- static struct nand_ecclayout aml_nand_oob_436 = {
- .eccbytes = 352,
- .oobfree = {
- {.offset = 0,
- .length = 16}}
- };
- static struct nand_ecclayout aml_nand_oob_448 = {
- .eccbytes = 416,
- .oobfree = {
- {.offset = 0,
- .length = 16}}
- };
- static struct nand_ecclayout aml_nand_oob_640 = {
- .eccbytes = 608,
- .oobfree = {
- {.offset = 0,
- .length = 16}}
- };
- static unsigned default_environment_size = (ENV_SIZE - sizeof(struct aml_nand_bbt_info));
- static uint8_t nand_boot_flag = 0;
- static uint8_t nand_erarly_suspend_flag = 0;
- static uint8_t nand_mode_time[6] = {9, 7, 6, 5, 5, 4};
- static int aml_nand_update_env(struct mtd_info *mtd);
- //static void aml_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr);
- struct aml_nand_flash_dev aml_nand_flash_ids[] = {
- {"A revision NAND 2GiB H27UAG8T2A", {NAND_MFR_HYNIX, 0xd5, 0x94, 0x25, 0x44, 0x41}, 4096, 2048, 0x80000, 224, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"A revision NAND 4GiB H27UBG8T2A", {NAND_MFR_HYNIX, 0xd7, 0x94, 0x9a, 0x74, 0x42}, 8192, 4096, 0x200000, 448, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"B revision NAND 2GiB H27UAG8T2B", {NAND_MFR_HYNIX, 0xd5, 0x94, 0x9a, 0x74, 0x42}, 8192, 2048, 0x200000, 448, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- #ifdef NEW_NAND_SUPPORT
- {"B revision NAND 4GiB H27UBG8T2B", {NAND_MFR_HYNIX, 0xd7, 0x94, 0xda, 0x74, 0xc3}, 8192, 4096, 0x200000, 640, 1, 16, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE)}, //need readretry, disable two plane mode
- {"B revision NAND 8GiB H27UCG8T2M", {NAND_MFR_HYNIX, 0xde, 0x94, 0xd2, 0x04, 0x43}, 8192, 8192, 0x200000, 448, 1, 16, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE)}, //need readretry, disable two plane mode
- #endif
- {"A revision NAND 4GiB MT29F32G-A", {NAND_MFR_MICRON, 0xd7, 0x94, 0x3e, 0x84}, 4096, 4096, 0x80000, 218, 1, 16, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE | NAND_TWO_PLANE_MODE)},
- {"A revision NAND 16GiB MT29F128G-A", {NAND_MFR_MICRON, 0xd9, 0xd5, 0x3e, 0x88}, 4096, 16384, 0x80000, 218, 1, 16, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE | NAND_TWO_PLANE_MODE)},
- {"B revision NAND 4GiB MT29F32G-B", {NAND_MFR_MICRON, 0x68, 0x04, 0x46, 0x89}, 4096, 4096, 0x100000, 224, 1, 20, 15, 4, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"B revision NAND 16GiB MT29F128G-B", {NAND_MFR_MICRON, 0x88, 0x05, 0xc6, 0x89}, 4096, 16384, 0x100000, 224, 1, 20, 15, 4, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"C revision NAND 4GiB MT29F32G-C", {NAND_MFR_MICRON, 0x68, 0x04, 0x4a, 0xa9}, 4096, 4096, 0x100000, 224, 1, 16, 15, 5, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"C revision NAND 8GiB MT29F64G-C", {NAND_MFR_MICRON, 0x88, 0x04, 0x4b, 0xa9}, 8192, 8192, 0x200000, 448, 1, 16, 15, 5, (NAND_TIMING_MODE5 | NAND_ECC_BCH30_1K_MODE | NAND_TWO_PLANE_MODE)},
- {"C revision NAND 32GiB MT29F256G-C", {NAND_MFR_MICRON, 0xa8, 0x05, 0xcb, 0xa9}, 8192, 32768, 0x200000, 448, 2, 16, 15, 5, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE | NAND_INTERLEAVING_MODE)},
- {"1 Generation NAND 4GiB JS29F32G08AA-1", {NAND_MFR_INTEL, 0x68, 0x04, 0x46, 0xA9}, 4096, 4096, 0x100000, 218, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE | NAND_TWO_PLANE_MODE)},
- {"1 Generation NAND 8GiB JS29F64G08AA-1", {NAND_MFR_INTEL, 0x88, 0x24, 0x4b, 0xA9}, 8192, 8192, 0x200000, 448, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"E serials NAND 2GiB TC58NVG4D2ETA00", {NAND_MFR_TOSHIBA, 0xD5, 0x94, 0x32, 0x76, 0x54}, 8192, 2048, 0x100000, 376, 1, 20, 25, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE | NAND_TWO_PLANE_MODE)},
- {"E serials NAND 4GiB TC58NVG5D2ETA00", {NAND_MFR_TOSHIBA, 0xD7, 0x94, 0x32, 0x76, 0x54}, 8192, 4096, 0x100000, 376, 1, 20, 25, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE | NAND_TWO_PLANE_MODE)},
- {"F serials NAND 2GiB TC58NVG4D2FTA00", {NAND_MFR_TOSHIBA, 0xD5, 0x94, 0x32, 0x76, 0x55}, 8192, 2076, 0x100000, 448, 1, 20, 25, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"F serials NAND 4GiB TC58NVG5D2FTA00", {NAND_MFR_TOSHIBA, 0xD7, 0x94, 0x32, 0x76, 0x55}, 8192, 4096, 0x100000, 448, 1, 20, 25, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"F serials NAND 8GiB TC58NVG6D2FTA00", {NAND_MFR_TOSHIBA, 0xDE, 0x94, 0x32, 0x76, 0x55}, 8192, 8192, 0x100000, 448, 1, 20, 25, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"F serials NAND 8GiB TH58NVG7D2FTA20", {NAND_MFR_TOSHIBA, 0xDE, 0x95, 0x32, 0x7a, 0x55}, 8192, 8200, 0x100000, 448, 2, 20, 25, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE | NAND_INTERLEAVING_MODE)},
- #ifdef NEW_NAND_SUPPORT
- {"F serials NAND 4GiB TC58NVG5D2HTA00", {NAND_MFR_TOSHIBA, 0xD7, 0x94, 0x32, 0x76, 0x56}, 8192, 4096, 0x100000, 640, 1, 20, 25, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE )}, //need readretry, disable two plane mode
- {"F serials NAND 8GiB TC58NVG6D2GTA00", {NAND_MFR_TOSHIBA, 0xDE, 0x94, 0x82, 0x76, 0x56}, 8192, 8192, 0x200000, 640, 1, 20, 25, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE )}, //need readretry, disable two plane mode
- #endif
- {"M Generation NAND 2GiB K9GAG08U0M", {NAND_MFR_SAMSUNG, 0xD5, 0x14, 0xb6, 0x74}, 4096, 2048, 0x80000, 128, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH8_MODE)},
- {"5 Generation NAND 2GiB K9GAG08X0D", {NAND_MFR_SAMSUNG, 0xD5, 0x94, 0x29, 0x34, 0x41}, 4096, 2048, 0x80000, 218, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE | NAND_TWO_PLANE_MODE)},
- {"6 Generation NAND 2GiB K9GAG08U0E", {NAND_MFR_SAMSUNG, 0xD5, 0x84, 0x72, 0x50, 0x42}, 8192, 2048, 0x100000, 436, 1, 25, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE)},
- {"7 Generation NAND 2GiB K9GAG08U0F", {NAND_MFR_SAMSUNG, 0xD5, 0x94, 0x76, 0x54, 0x43}, 8192, 2048, 0x100000, 512, 1, 25, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"6 Generation NAND 4GiB K9LBG08U0E", {NAND_MFR_SAMSUNG, 0xD7, 0xC5, 0x72, 0x54, 0x42}, 8192, 4096, 0x100000, 436, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE | NAND_TWO_PLANE_MODE)},
- {"6 Generation NAND 8GiB K9HCG08U0E", {NAND_MFR_SAMSUNG, 0xDE, 0xC5, 0x72, 0x54, 0x42}, 8192, 8192, 0x100000, 436, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH12_MODE | NAND_TWO_PLANE_MODE)},
- {"2 Generation NAND 4GiB K9GBG08U0A", {NAND_MFR_SAMSUNG, 0xD7, 0x94, 0x7a, 0x54, 0x43}, 8192, 4152, 0x100000, 640, 1, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE)},
- {"2 Generation NAND 8GiB K9LCG08U0A", {NAND_MFR_SAMSUNG, 0xDE, 0xD5, 0x7a, 0x58, 0x43}, 8192, 8304, 0x100000, 640, 2, 20, 15, 0, (NAND_TIMING_MODE5 | NAND_ECC_BCH16_MODE | NAND_TWO_PLANE_MODE | NAND_INTERLEAVING_MODE)},
- {NULL,}
- };
- uint8_t aml_nand_get_onfi_features(struct aml_nand_chip *aml_chip, uint8_t *buf, int addr)
- {
- struct nand_chip *chip = &aml_chip->chip;
- struct mtd_info *mtd = &aml_chip->mtd;
- int i, j;
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- aml_chip->aml_nand_select_chip(aml_chip, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_GET_FEATURES, addr, -1, i);
- for (j=0; j<4; j++)
- buf[j] = chip->read_byte(mtd);
- }
- }
- return 0;
- }
- void aml_nand_set_onfi_features(struct aml_nand_chip *aml_chip, uint8_t *buf, int addr)
- {
- int i, j;
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- aml_chip->aml_nand_select_chip(aml_chip, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_SET_FEATURES, addr, -1, i);
- for (j=0; j<4; j++)
- aml_chip->aml_nand_write_byte(aml_chip, buf[j]);
- aml_chip->aml_nand_wait_devready(aml_chip, i);
- }
- }
- }
- static void aml_platform_get_user_byte(struct aml_nand_chip *aml_chip, unsigned char *oob_buf, int byte_num)
- {
- int read_times = 0;
- unsigned int len = PER_INFO_BYTE/sizeof(unsigned int);
- while (byte_num > 0) {
- *oob_buf++ = (aml_chip->user_info_buf[read_times*len] & 0xff);
- byte_num--;
- if (aml_chip->user_byte_mode == 2) {
- *oob_buf++ = ((aml_chip->user_info_buf[read_times*len] >> 8) & 0xff);
- byte_num--;
- }
- read_times++;
- }
- }
- static void aml_platform_set_user_byte(struct aml_nand_chip *aml_chip, unsigned char *oob_buf, int byte_num)
- {
- int write_times = 0;
- unsigned int len = PER_INFO_BYTE/sizeof(unsigned int);
- while (byte_num > 0) {
- aml_chip->user_info_buf[write_times*len] = *oob_buf++;
- byte_num--;
- if (aml_chip->user_byte_mode == 2) {
- aml_chip->user_info_buf[write_times*len] |= (*oob_buf++ << 8);
- byte_num--;
- }
- write_times++;
- }
- }
- #ifdef NEW_NAND_SUPPORT
- /*****************************HYNIX******************************************/
- uint8_t aml_nand_get_reg_value_hynix(struct aml_nand_chip *aml_chip, uint8_t *buf, uint8_t *addr, int chipnr, int cnt)
- {
- struct nand_chip *chip = &aml_chip->chip;
- struct mtd_info *mtd = &aml_chip->mtd;
- int j;
-
- if((aml_chip->new_nand_info.type == 0) ||(aml_chip->new_nand_info.type > 10))
- return 0;
- printk("Enter %s\n", __func__);
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_HYNIX_GET_VALUE, -1, -1, chipnr);
- for (j=0; j<cnt; j++){
- chip->cmd_ctrl(mtd, addr[j], NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
- udelay(2);
- buf[j] = chip->read_byte(mtd);
- udelay(2);
- printk("%s, REG(0x%x): value:0x%x, for chip[%d]\n", __func__, addr[j], buf[j], chipnr);
- }
-
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- return 0;
- }
- uint8_t aml_nand_set_reg_value_hynix(struct aml_nand_chip *aml_chip, uint8_t *buf, uint8_t *addr, int chipnr, int cnt)
- {
- struct nand_chip *chip = &aml_chip->chip;
- struct mtd_info *mtd = &aml_chip->mtd;
- int j;
- if((aml_chip->new_nand_info.type == 0) ||(aml_chip->new_nand_info.type > 10))
- return 0;
- printk("Enter %s\n", __func__);
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_HYNIX_SET_VALUE_START, -1, -1, chipnr);
- udelay(2);
- for (j=0; j<cnt; j++){
- chip->cmd_ctrl(mtd, addr[j], NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
- aml_chip->aml_nand_write_byte(aml_chip, buf[j]);
- printk("%s, REG(0x%x): value:0x%x for chip[%d]\n", __func__, addr[j], buf[j], chipnr);
- }
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_HYNIX_SET_VALUE_END, -1, -1, chipnr);
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- return 0;
- }
- void aml_nand_enter_enslc_mode_hynix(struct mtd_info *mtd)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- unsigned char hynix_reg_program_value_tmp[ENHANCE_SLC_REG_NUM];
- struct nand_chip *chip = mtd->priv;
- int i, j;
- if((aml_chip->new_nand_info.type == 0) ||(aml_chip->new_nand_info.type > 10))
- return;
- printk("Enter %s\n", __func__);
- memset(&hynix_reg_program_value_tmp[0], 0, ENHANCE_SLC_REG_NUM);
- chip->select_chip(mtd, 0);
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- for(j=0;j<aml_chip->new_nand_info.slc_program_info.reg_cnt;j++)
- hynix_reg_program_value_tmp[j] = aml_chip->new_nand_info.slc_program_info.reg_default_value[i][j] + aml_chip->new_nand_info.slc_program_info.reg_offset_value[j];
-
- aml_nand_set_reg_value_hynix(aml_chip, &hynix_reg_program_value_tmp[0], &aml_chip->new_nand_info.slc_program_info.reg_addr[0], i, aml_chip->new_nand_info.slc_program_info.reg_cnt);
- udelay(10);
- memset(&hynix_reg_program_value_tmp[0], 0, aml_chip->new_nand_info.slc_program_info.reg_cnt);
- }
- }
- mdelay(2);
- //chip->select_chip(mtd, -1);
- }
- //working in Normal program mode
- void aml_nand_exit_enslc_mode_hynix(struct mtd_info *mtd)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct nand_chip *chip = mtd->priv;
- int i;
- if((aml_chip->new_nand_info.type == 0) ||(aml_chip->new_nand_info.type > 10))
- return;
- printk("Enter %s\n", __func__);
-
- chip->select_chip(mtd, 0);
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- aml_nand_set_reg_value_hynix(aml_chip, &aml_chip->new_nand_info.slc_program_info.reg_default_value[i][0], &aml_chip->new_nand_info.slc_program_info.reg_addr[0], i, aml_chip->new_nand_info.slc_program_info.reg_cnt);
- udelay(10);
- }
- }
- mdelay(2);
- //chip->select_chip(mtd, -1);
- }
- //when ecc fail,set nand retry reg
- void aml_nand_read_retry_handle_hynix(struct mtd_info *mtd, int chipnr)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- u8 hynix_reg_read_value[READ_RETRY_REG_NUM];
- int i, cur_cnt;
- if((aml_chip->new_nand_info.type == 0) ||(aml_chip->new_nand_info.type > 10))
- return;
- cur_cnt = aml_chip->new_nand_info.read_rety_info.cur_cnt[chipnr];
-
- printk("HYNIX NAND set partmeters here and hynix_read_retry_cnt:%d\n", cur_cnt);
-
- memset(&hynix_reg_read_value[0], 0, READ_RETRY_REG_NUM);
-
- for(i=0;i<aml_chip->new_nand_info.read_rety_info.reg_cnt;i++){
- //printk("reg_offset_value[%d][%d]%02x\n", cur_cnt, i, aml_chip->new_nand_info.read_rety_info.reg_offset_value[cur_cnt][i]);
- if(aml_chip->new_nand_info.read_rety_info.reg_offset_value[cur_cnt][i] == READ_RETRY_ZERO){
- hynix_reg_read_value[i] = 0;
- }
- else{
- hynix_reg_read_value[i] = aml_chip->new_nand_info.read_rety_info.reg_default_value[chipnr][i] + aml_chip->new_nand_info.read_rety_info.reg_offset_value[cur_cnt][i];
- }
- }
-
- aml_nand_set_reg_value_hynix(aml_chip, &hynix_reg_read_value[0], &aml_chip->new_nand_info.read_rety_info.reg_addr[0], chipnr, aml_chip->new_nand_info.read_rety_info.reg_cnt);
- udelay(10);
- cur_cnt++;
- aml_chip->new_nand_info.read_rety_info.cur_cnt[chipnr] = (cur_cnt > (aml_chip->new_nand_info.read_rety_info.retry_cnt-1)) ? 0 : cur_cnt;
- }
- void aml_nand_get_slc_default_value_hynix(struct mtd_info *mtd)
- {
- struct nand_chip *chip = mtd->priv;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- int i;
-
- chip->select_chip(mtd, 0);
- for(i=0; i<aml_chip->chip_num; i++){
- if(aml_chip->valid_chip[i]){
- aml_nand_get_reg_value_hynix(aml_chip, &aml_chip->new_nand_info.slc_program_info.reg_default_value[i][0], &aml_chip->new_nand_info.slc_program_info.reg_addr[0], i, aml_chip->new_nand_info.slc_program_info.reg_cnt);
- udelay(2);
- }
- }
- //chip->select_chip(mtd, -1);
- }
- void aml_nand_set_readretry_default_value_hynix(struct mtd_info *mtd)
- {
- unsigned char hynix_reg_read_value_tmp[READ_RETRY_REG_NUM];
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct nand_chip *chip = mtd->priv;
- int i;
- if((aml_chip->new_nand_info.type == 0) ||(aml_chip->new_nand_info.type > 10))
- return;
- printk("Enter %s\n", __func__);
- memset(&hynix_reg_read_value_tmp[0], 0, READ_RETRY_REG_NUM);
- chip->select_chip(mtd, 0);
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- aml_nand_set_reg_value_hynix(aml_chip, &aml_chip->new_nand_info.read_rety_info.reg_default_value[i][0], &aml_chip->new_nand_info.read_rety_info.reg_addr[0], i, aml_chip->new_nand_info.read_rety_info.reg_cnt);
- udelay(10);
- //aml_nand_hynix_get_parameters(aml_chip, &hynix_reg_read_value_tmp[0], &aml_chip->hynix_reg_read_addr[0], i, 4);
- }
- }
- //chip->select_chip(mtd, -1);
- }
- void aml_nand_get_read_default_value_hynix(struct mtd_info *mtd)
- {
- struct mtd_oob_ops aml_oob_ops;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct nand_chip *chip = mtd->priv;
- size_t addr;
- unsigned char *data_buf;
- char oob_buf[4];
- unsigned char page_list[RETRY_NAND_COPY_NUM] = {0x07, 0x0B, 0x0F, 0x13};
- int error = 0, i, j, nand_type, total_blk, phys_erase_shift = fls(mtd->erasesize) - 1;
- data_buf = kzalloc(mtd->writesize, GFP_KERNEL);
- if (data_buf == NULL){
- printk("%s %d no mem for databuf and mtd->writesize:%d \n", __func__, __LINE__, mtd->writesize);
- return;
- }
- if (nand_boot_flag){
- addr = (1024 * mtd->writesize / aml_chip->plane_num);
- }
- else {
- addr = 0;
- }
- total_blk = 0;
- aml_chip->new_nand_info.read_rety_info.default_flag = 0;
- while(total_blk < RETRY_NAND_BLK_NUM){
- error = mtd->block_isbad(mtd, addr);
- if (error) {
- printk("%s %d detect bad blk at blk:%d\n", __func__, __LINE__, addr>> phys_erase_shift);
- addr += mtd->erasesize;
- total_blk++;
- continue;
- }
-
- aml_oob_ops.mode = MTD_OOB_AUTO;
- aml_oob_ops.len = mtd->writesize;
- aml_oob_ops.ooblen = 4;
- aml_oob_ops.ooboffs = mtd->ecclayout->oobfree[0].offset;
- aml_oob_ops.datbuf = data_buf;
- aml_oob_ops.oobbuf = oob_buf;
- memset(oob_buf, 0, 4);
- memset((unsigned char *)aml_oob_ops.datbuf, 0x0, mtd->writesize);
- memset((unsigned char *)aml_oob_ops.oobbuf, 0x0, aml_oob_ops.ooblen);
- for(i=0;i<RETRY_NAND_COPY_NUM;i++){
- memset(oob_buf, 0, 4);
- memset((unsigned char *)aml_oob_ops.datbuf, 0x0, mtd->writesize);
- memset((unsigned char *)aml_oob_ops.oobbuf, 0x0, aml_oob_ops.ooblen);
- nand_type = aml_chip->new_nand_info.type;
- aml_chip->new_nand_info.type = 0;
- error = mtd->read_oob(mtd, (addr + page_list[i]*mtd->writesize), &aml_oob_ops);
- aml_chip->new_nand_info.type = nand_type;
- if ((error != 0) && (error != -EUCLEAN)) {
- printk("%s %d read oob failed at blk:%d, page:%d\n", __func__, __LINE__, addr>> phys_erase_shift, (addr + page_list[i]*mtd->writesize)/mtd->writesize);
- continue;
- }
- if (!memcmp(oob_buf, RETRY_NAND_MAGIC, 4)){
- memcpy(&aml_chip->new_nand_info.read_rety_info.reg_default_value[0][0], (unsigned char *)aml_oob_ops.datbuf, MAX_CHIP_NUM*READ_RETRY_REG_NUM);
- //memcpy(&aml_chip->new_nand_info.slc_program_info.reg_default_value[0][0], (unsigned char *)aml_oob_ops.datbuf, MAX_CHIP_NUM*ENHANCE_SLC_REG_NUM);
- printk("%s %d get default reg value at blk:%d, page:%d\n", __func__, __LINE__, addr>> phys_erase_shift, (addr + page_list[i]*mtd->writesize)/mtd->writesize);
- for(i=0; i<aml_chip->chip_num; i++){
- if(aml_chip->valid_chip[i]){
- for(j=0;j<aml_chip->new_nand_info.read_rety_info.reg_cnt;j++)
- printk("%s, REG(0x%x): value:0x%x, for chip[%d]\n", __func__, aml_chip->new_nand_info.read_rety_info.reg_addr[j], aml_chip->new_nand_info.read_rety_info.reg_default_value[i][j], i);
-
- //for(j=0;j<aml_chip->new_nand_info.slc_program_info.reg_cnt;j++)
- // printk("%s, REG(0x%x): value:0x%x, for chip[%d]\n", __func__, aml_chip->new_nand_info.slc_program_info.reg_addr[j], aml_chip->new_nand_info.slc_program_info.reg_default_value[i][j], i);
- }
- }
- aml_chip->new_nand_info.read_rety_info.default_flag = 1;
- goto READ_OK;
- }
- }
-
- addr += mtd->erasesize;
- total_blk++;
- }
- aml_chip->new_nand_info.read_rety_info.default_flag = 0;
- printk("######%s %d read default read retry reg value failed and need read from chip write back to nand using SLC\n", __func__, __LINE__);
- chip->select_chip(mtd, 0);
- for(i=0; i<aml_chip->chip_num; i++){
- if(aml_chip->valid_chip[i]){
- aml_nand_get_reg_value_hynix(aml_chip, &aml_chip->new_nand_info.read_rety_info.reg_default_value[i][0], &aml_chip->new_nand_info.read_rety_info.reg_addr[0], i, aml_chip->new_nand_info.read_rety_info.reg_cnt);
- udelay(2);
- //aml_nand_get_reg_value_hynix(aml_chip, &aml_chip->new_nand_info.slc_program_info.reg_default_value[i][0], &aml_chip->new_nand_info.slc_program_info.reg_addr[0], i, aml_chip->new_nand_info.slc_program_info.reg_cnt);
- }
- }
- //chip->select_chip(mtd, -1);
- READ_OK:
- kfree(data_buf);
- }
- /*******************************************TOSHIBA*********************************************/
- void aml_nand_set_reg_value_toshiba(struct aml_nand_chip *aml_chip, uint8_t *buf, uint8_t *addr, int chipnr, int cnt)
- {
- struct nand_chip *chip = &aml_chip->chip;
- struct mtd_info *mtd = &aml_chip->mtd;
- int j;
- if(aml_chip->new_nand_info.type != TOSHIBA_24NM)
- return;
- printk("Enter %s\n", __func__);
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- aml_chip->aml_nand_select_chip(aml_chip, chipnr);
- if(aml_chip->new_nand_info.read_rety_info.cur_cnt[chipnr] ==0){
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TOSHIBA_PRE_CON1, -1, -1, chipnr);
- udelay(2);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TOSHIBA_PRE_CON2, -1, -1, chipnr);
- udelay(2);
- }
-
- for (j=0; j<cnt; j++){
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TOSHIBA_SET_VALUE, -1, -1, chipnr);
- udelay(2);
- chip->cmd_ctrl(mtd, addr[j], NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
- udelay(2);
- aml_chip->aml_nand_write_byte(aml_chip, buf[j]);
- printk("%s, REG(0x%x): value:0x%x\n", __func__, addr[j], buf[j]);
- }
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TOSHIBA_BEF_COMMAND1, -1, -1, chipnr);
- udelay(2);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TOSHIBA_BEF_COMMAND2, -1, -1, chipnr);
- udelay(2);
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- return;
- }
- //when ecc fail,set nand retry reg
- void aml_nand_read_retry_handle_toshiba(struct mtd_info *mtd, int chipnr)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- int cur_cnt;
-
- if(aml_chip->new_nand_info.type != TOSHIBA_24NM)
- return;
-
- cur_cnt = aml_chip->new_nand_info.read_rety_info.cur_cnt[chipnr];
- printk("TOSHIBA NAND set partmeters here and read_retry_cnt:%d\n", cur_cnt);
- aml_nand_set_reg_value_toshiba(aml_chip, &aml_chip->new_nand_info.read_rety_info.reg_offset_value[cur_cnt][0], &aml_chip->new_nand_info.read_rety_info.reg_addr[0], chipnr, aml_chip->new_nand_info.read_rety_info.reg_cnt);
- udelay(10);
- cur_cnt++;
- aml_chip->new_nand_info.read_rety_info.cur_cnt[chipnr] = (cur_cnt > (aml_chip->new_nand_info.read_rety_info.retry_cnt-1)) ? 0 : cur_cnt;
- }
- void aml_nand_read_retry_exit_toshiba(struct mtd_info *mtd, int chipnr)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- if(aml_chip->new_nand_info.type != TOSHIBA_24NM)
- return;
-
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_RESET, -1, -1, chipnr);
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- memset(&aml_chip->new_nand_info.read_rety_info.cur_cnt[0], 0, MAX_CHIP_NUM);
- }
- #endif
- static void aml_platform_hw_init(struct aml_nand_chip *aml_chip)
- {
- struct clk *sys_clk;
- int sys_clk_rate, sys_time, start_cycle, end_cycle, bus_cycle, time_mode, adjust, Tcycle, T_REA = DEFAULT_T_REA, T_RHOH = DEFAULT_T_RHOH, i;
- #ifdef CONFIG_ARCH_MESON
- struct mtd_info *mtd = &aml_chip->mtd;
- struct nand_chip *chip = &aml_chip->chip;
- if (aml_chip->chip_num > 1) {
- chip->select_chip(mtd, -1);
- CLEAR_CBUS_REG_MASK(PREG_HGPIO_EN_N, (1 << 5));
- CLEAR_CBUS_REG_MASK(PREG_HGPIO_O, (1 << 5));
- SET_CBUS_REG_MASK(PREG_HGPIO_EN_N, (1 << 16));
- if (!(READ_CBUS_REG(PREG_HGPIO_I) & (1 << 16))) {
- SET_CBUS_REG_MASK(PREG_HGPIO_O, (1 << 5));
- if ((READ_CBUS_REG(PREG_HGPIO_I) & (1 << 16))) {
- aml_chip->chip_enable[1] = (aml_chip->chip_enable[1] & aml_chip->chip_enable[2]);
- aml_chip->rb_enable[1] = aml_chip->rb_enable[2];
- aml_chip->chip_num = 2;
- aml_nand_debug("ce1 and ce2 connected\n");
- }
- }
- }
- #endif
- sys_clk = clk_get_sys(NAND_SYS_CLK_NAME, NULL);
- sys_clk_rate = clk_get_rate(sys_clk);
- sys_time = (10000 / (sys_clk_rate / 1000000));
- start_cycle = (((NAND_CYCLE_DELAY + T_REA * 10) * 10) / sys_time);
- start_cycle = (start_cycle + 9) / 10;
- time_mode = -1;
- for (i=5; i>=0; i--) {
- bus_cycle = nand_mode_time[i];
- Tcycle = bus_cycle * sys_time;
- end_cycle = (((NAND_CYCLE_DELAY + Tcycle / 2 + T_RHOH * 10) * 10) / sys_time);
- end_cycle = end_cycle / 10;
- if ((((start_cycle >= 3) && (start_cycle <= ( bus_cycle + 1)))
- || ((end_cycle >= 3) && (end_cycle <= (bus_cycle + 1))))
- && (start_cycle <= end_cycle)) {
- time_mode = i;
- break;
- }
- }
- if (time_mode < 0) {
- time_mode = 0;
- for (bus_cycle = 19; bus_cycle > nand_mode_time[time_mode]; bus_cycle--) {
- Tcycle = bus_cycle * sys_time;
- end_cycle = (((NAND_CYCLE_DELAY + Tcycle / 2 + T_RHOH * 10) * 10) / sys_time);
- end_cycle = end_cycle / 10;
- if ((((start_cycle >= 3) && (start_cycle <= ( bus_cycle + 1)))
- || ((end_cycle >= 3) && (end_cycle <= (bus_cycle + 1))))
- && (start_cycle <= end_cycle)) {
- break;
- }
- }
- if (bus_cycle <= nand_mode_time[time_mode])
- return;
- }
- if (nand_mode_time[time_mode] < start_cycle)
- adjust = start_cycle - nand_mode_time[time_mode];
- else if(nand_mode_time[time_mode] > end_cycle)
- adjust = ((((~(nand_mode_time[time_mode] - end_cycle) + 1)) & 0xf) | 0x8);
- else
- adjust = 0;
- NFC_SET_CFG(0);
- NFC_SET_TIMING(time_mode, (bus_cycle - 1), adjust);
- NFC_SEND_CMD(1<<31);
- dev_info(aml_chip->device, "time_mode=%d, bus_cycle=%d, adjust=%d, start_cycle=%d, end_cycle=%d,system=%d.%dns\n",
- time_mode, bus_cycle, adjust, start_cycle, end_cycle, sys_time/10, sys_time%10);
- }
- static void aml_platform_adjust_timing(struct aml_nand_chip *aml_chip)
- {
- struct aml_nand_platform *plat = aml_chip->platform;
- struct clk *sys_clk;
- int sys_clk_rate, sys_time, start_cycle, end_cycle, bus_cycle, time_mode, time_mode_select, adjust, Tcycle, i;
- time_mode_select = ((plat->platform_nand_data.chip.options & NAND_TIMING_OPTIONS_MASK) >> 8);
- if ((time_mode_select > 5) || (time_mode_select < 0))
- time_mode_select = 5;
- if (!aml_chip->T_REA)
- aml_chip->T_REA = 20;
- if (!aml_chip->T_RHOH)
- aml_chip->T_RHOH = 15;
- if (READ_CBUS_REG(HHI_MPEG_CLK_CNTL)&(1<<8)) {
- sys_clk = clk_get_sys(NAND_SYS_CLK_NAME, NULL);
- sys_clk_rate = clk_get_rate(sys_clk);
- time_mode = -1;
- }
- else {
- time_mode = 0;
- sys_clk_rate = 27000000;
- }
- sys_time = (10000 / (sys_clk_rate / 1000000));
- start_cycle = (((NAND_CYCLE_DELAY + aml_chip->T_REA * 10) * 10) / sys_time);
- start_cycle = (start_cycle + 9) / 10;
- if (time_mode == 0) {
- for (bus_cycle = 5; bus_cycle <= 19; bus_cycle++) {
- Tcycle = bus_cycle * sys_time;
- end_cycle = (((NAND_CYCLE_DELAY + Tcycle / 2 + aml_chip->T_RHOH * 10) * 10) / sys_time);
- end_cycle = end_cycle / 10;
- if (((start_cycle - bus_cycle) > 7) || ((bus_cycle - end_cycle) > 8))
- continue;
- if ((((start_cycle >= 3) && (start_cycle <= ( bus_cycle + 1)))
- || ((end_cycle >= 3) && (end_cycle <= (bus_cycle + 1))))
- && (start_cycle <= end_cycle)) {
- break;
- }
- }
- BUG_ON(bus_cycle > 19);
- }
- else{
- for (i=time_mode_select; i>=0; i--) {
- bus_cycle = nand_mode_time[i];
- Tcycle = bus_cycle * sys_time;
- end_cycle = (((NAND_CYCLE_DELAY + Tcycle / 2 + aml_chip->T_RHOH * 10) * 10) / sys_time);
- end_cycle = end_cycle / 10;
- if ((((start_cycle >= 3) && (start_cycle <= ( bus_cycle + 1)))
- || ((end_cycle >= 3) && (end_cycle <= (bus_cycle + 1))))
- && (start_cycle <= end_cycle)) {
- time_mode = i;
- break;
- }
- }
- if (time_mode < 0)
- return;
- }
- if (nand_mode_time[time_mode] < start_cycle)
- adjust = start_cycle - nand_mode_time[time_mode];
- else if(nand_mode_time[time_mode] > end_cycle)
- adjust = ((((~(nand_mode_time[time_mode] - end_cycle) + 1)) & 0xf) | 0x8);
- else
- adjust = 0;
- NFC_SET_TIMING(time_mode, (bus_cycle - 1), adjust);
- dev_info(aml_chip->device, "time_mode=%d, bus_cycle=%d, adjust=%d, start_cycle=%d, end_cycle=%d,system=%d.%dns\n",
- time_mode, bus_cycle, adjust, start_cycle, end_cycle, sys_time/10, sys_time%10);
- }
- static int aml_nand_add_partition(struct aml_nand_chip *aml_chip)
- {
- uint32_t adjust_offset = 0, mini_part_blk_num, start_blk = 0;
- struct mtd_info *mtd = &aml_chip->mtd;
- struct aml_nand_platform *plat = aml_chip->platform;
- struct platform_nand_chip *chip = &plat->platform_nand_data.chip;
- #ifdef CONFIG_MTD_PARTITIONS
- struct mtd_partition *temp_parts = NULL;
- struct mtd_partition *parts;
- int nr, i, error = 0, part_save_in_env = 1, file_system_part = 0, phys_erase_shift;
- u8 part_num = 0;
- size_t offset;
- uint64_t mini_part_size = ((mtd->erasesize > NAND_MINI_PART_SIZE) ? mtd->erasesize : NAND_MINI_PART_SIZE);
- if (chip->set_parts)
- chip->set_parts(mtd->size, chip);
- phys_erase_shift = fls(mtd->erasesize) - 1;
- parts = plat->platform_nand_data.chip.partitions;
- nr = plat->platform_nand_data.chip.nr_partitions;
- if (!strncmp((char*)plat->name, NAND_BOOT_NAME, strlen((const char*)NAND_BOOT_NAME))) {
- if (nr == 0) {
- parts = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
- if (!parts)
- return -ENOMEM;
- }
- parts->name = NAND_BOOT_NAME;
- parts->offset = 0;
- parts->size = (mtd->writesize * 1024);
- nr = 1;
- nand_boot_flag = 1;
- }
- else {
- if (nand_boot_flag)
- adjust_offset = (1024 * mtd->writesize / aml_chip->plane_num);
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->new_nand_info.type) && (aml_chip->new_nand_info.type < 10))
- adjust_offset += RETRY_NAND_BLK_NUM* mtd->erasesize;
- #endif
- part_num++;
- start_blk = adjust_offset / mtd->erasesize;
- if ((NAND_MINI_PART_SIZE / mtd->erasesize) < 2)
- mini_part_blk_num = 2;
- else
- mini_part_blk_num = (NAND_MINI_PART_SIZE >> phys_erase_shift);
-
- start_blk = 0;
- do {
- offset = adjust_offset + start_blk * mtd->erasesize;
- error = mtd->block_isbad(mtd, offset);
- if (error) {
- adjust_offset += mtd->erasesize;
- continue;
- }
- start_blk++;
- } while (start_blk < mini_part_blk_num);
- adjust_offset += mini_part_blk_num * mtd->erasesize;
- if (nr == 0) {
- part_save_in_env = 0;
- if (nand_boot_flag)
- nr = NAND_MINI_PART_NUM + 1;
- else
- nr = 2;
- parts = kzalloc((nr * sizeof(struct mtd_partition)), GFP_KERNEL);
- if (!parts)
- return -ENOMEM;
- mini_part_size = ((mtd->erasesize > NAND_MINI_PART_SIZE) ? mtd->erasesize : NAND_MINI_PART_SIZE);
- }
- for (i=0; i<nr; i++) {
- temp_parts = parts + i;
- if ((temp_parts->size >= mtd->erasesize) || (i == (nr - 1)))
- mini_part_size = temp_parts->size;
- temp_parts->offset = adjust_offset;
- if ((mini_part_size < NAND_SYS_PART_SIZE) && (file_system_part == 0)) {
- start_blk = 0;
- do {
- offset = adjust_offset + start_blk * mtd->erasesize;
- error = mtd->block_isbad(mtd, offset);
- if (error) {
- adjust_offset += mtd->erasesize;
- continue;
- }
- start_blk++;
- } while (start_blk < (mini_part_size >> phys_erase_shift));
- }
- else {
- file_system_part = 1;
- }
- if ((i == (nr - 1)) && (part_save_in_env == 0))
- temp_parts->size = NAND_SYS_PART_SIZE;
- else if (mini_part_size != MTDPART_SIZ_FULL)
- temp_parts->size = mini_part_size + (adjust_offset - temp_parts->offset);
- adjust_offset += mini_part_size;
- if (temp_parts->name == NULL) {
- temp_parts->name = kzalloc(MAX_MTD_PART_NAME_LEN, GFP_KERNEL);
- if (!temp_parts->name)
- return -ENOMEM;
- sprintf(temp_parts->name, "mtd%d", part_num++);
- }
- }
- }
- return add_mtd_partitions(mtd, parts, nr);
- #else
- return add_mtd_device(mtd);
- #endif
- }
- static void aml_nand_select_chip(struct mtd_info *mtd, int chipnr)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- if (((nand_erarly_suspend_flag == 1) && (!(READ_CBUS_REG(HHI_MPEG_CLK_CNTL)&(1<<8))))
- || ((READ_CBUS_REG(HHI_MPEG_CLK_CNTL)&(1<<8)) && (nand_erarly_suspend_flag == 2))) {
- aml_chip->aml_nand_adjust_timing(aml_chip);
- if (nand_erarly_suspend_flag == 1)
- nand_erarly_suspend_flag = 2;
- else if (nand_erarly_suspend_flag == 2)
- nand_erarly_suspend_flag = 0;
- }
- switch (chipnr) {
- case -1:
- nand_release_chip();
- break;
- case 0:
- nand_get_chip();
- aml_chip->aml_nand_select_chip(aml_chip, chipnr);
- break;
- case 1:
- case 2:
- case 3:
- aml_chip->aml_nand_select_chip(aml_chip, chipnr);
- break;
- default:
- BUG();
- }
- return;
- }
- static void aml_platform_select_chip(struct aml_nand_chip *aml_chip, int chipnr)
- {
- int i;
- switch (chipnr) {
- case 0:
- case 1:
- case 2:
- case 3:
- aml_chip->chip_selected = aml_chip->chip_enable[chipnr];
- aml_chip->rb_received = aml_chip->rb_enable[chipnr];
- for (i=1; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- if (!((aml_chip->chip_enable[i] >> 10) & 1))
- SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, (1 << 4));
- if (!((aml_chip->chip_enable[i] >> 10) & 2))
- SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, (1 << 3));
- if (!((aml_chip->chip_enable[i] >> 10) & 4))
- SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, (1 << 14));
- if (!((aml_chip->chip_enable[i] >> 10) & 8))
- SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, (1 << 13));
- if (!((aml_chip->rb_enable[i] >> 10) & 1))
- SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, (1 << 2));
- if (!((aml_chip->rb_enable[i] >> 10) & 2))
- SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, (1 << 1));
- if (!((aml_chip->rb_enable[i] >> 10) & 4))
- SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, (1 << 12));
- if (!((aml_chip->rb_enable[i] >> 10) & 8))
- SET_CBUS_REG_MASK(PERIPHS_PIN_MUX_6, (1 << 11));
- }
- }
- NFC_SEND_CMD_IDLE(aml_chip->chip_selected, 0);
- break;
- default:
- BUG();
- aml_chip->chip_selected = CE_NOT_SEL;
- break;
- }
- return;
- }
- static void aml_platform_cmd_ctrl(struct aml_nand_chip *aml_chip, int cmd, unsigned int ctrl)
- {
- if (cmd == NAND_CMD_NONE)
- return;
- #ifdef CONFIG_CLK81_DFS
- down(&aml_chip->nand_sem);
- #endif
- if (ctrl & NAND_CLE)
- cmd=NFC_CMD_CLE(aml_chip->chip_selected, cmd);
- else
- cmd=NFC_CMD_ALE(aml_chip->chip_selected, cmd);
- NFC_SEND_CMD(cmd);
- #ifdef CONFIG_CLK81_DFS
- up(&aml_chip->nand_sem);
- #endif
- }
- static int aml_platform_wait_devready(struct aml_nand_chip *aml_chip, int chipnr)
- {
- struct nand_chip *chip = &aml_chip->chip;
- struct mtd_info *mtd = &aml_chip->mtd;
- unsigned time_out_cnt = 0;
- int status;
- /* wait until command is processed or timeout occures */
- aml_chip->aml_nand_select_chip(aml_chip, chipnr);
- #if 1
- if (aml_chip->ops_mode & AML_CHIP_NONE_RB) {
- do{
- //udelay(chip->chip_delay);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_STATUS, -1, -1, chipnr);
- udelay(2);
- status = (int)chip->read_byte(mtd);
- if (status & NAND_STATUS_READY)
- break;
- udelay(20);
- }while(time_out_cnt++ <= 0x2000); //200ms max
- if (time_out_cnt > 0x2000)
- return 0;
- }
- else{
- do{
- if (chip->dev_ready(mtd))
- break;
- } while (time_out_cnt++ <= AML_NAND_BUSY_TIMEOUT);
- if (time_out_cnt > AML_NAND_BUSY_TIMEOUT)
- return 0;
- }
- #else
- do {
- if (aml_chip->ops_mode & AML_CHIP_NONE_RB) {
- //udelay(chip->chip_delay);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_STATUS, -1, -1, chipnr);
- udelay(2);
- status = (int)chip->read_byte(mtd);
- if (status & NAND_STATUS_READY)
- break;
- udelay(20);
- }
- else {
- if (chip->dev_ready(mtd))
- break;
- }
- } while (time_out_cnt++ <= AML_NAND_BUSY_TIMEOUT);
- if (time_out_cnt > AML_NAND_BUSY_TIMEOUT)
- return 0;
- #endif
- return 1;
- }
- static int aml_nand_dev_ready(struct mtd_info *mtd)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- return NFC_GET_RB_STATUS(aml_chip->rb_received);
- }
- static int aml_nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct nand_chip *chip = mtd->priv;
- chip->read_buf(mtd, aml_chip->aml_nand_data_buf, len);
- if (memcmp(buf, aml_chip->aml_nand_data_buf, len))
- return -EFAULT;
- return 0;
- }
- static void aml_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- aml_chip->aml_nand_cmd_ctrl(aml_chip, cmd, ctrl);
- }
- static int aml_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- int status[MAX_CHIP_NUM], state = chip->state, i = 0, time_cnt = 0, chip_nr = 1;
- /* Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine. */
- ndelay(100);
- if (state == FL_ERASING)
- chip_nr = aml_chip->chip_num;
- for (i=0; i<chip_nr; i++) {
- if (aml_chip->valid_chip[i]) {
- //active ce for operation chip and send cmd
- aml_chip->aml_nand_select_chip(aml_chip, i);
- if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_STATUS_MULTI, -1, -1, i);
- else
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_STATUS, -1, -1, i);
- time_cnt = 0;
- while (time_cnt++ < 0x40000) {
- if (chip->dev_ready) {
- if (chip->dev_ready(mtd))
- break;
- udelay(2);
- } else {
- if(time_cnt == 1)
- udelay(500);
- if (chip->read_byte(mtd) & NAND_STATUS_READY) {
- break;
- }
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_STATUS, -1, -1, i);
- udelay(50);
- }
- }
- status[i] = (int)chip->read_byte(mtd);
- status[0] |= status[i];
- }
- }
- return status[0];
- }
- static void aml_nand_base_command(struct aml_nand_chip *aml_chip, unsigned command, int column, int page_addr, int chipnr)
- {
- struct nand_chip *chip = &aml_chip->chip;
- struct mtd_info *mtd = &aml_chip->mtd;
- unsigned command_temp, pages_per_blk_shift, plane_page_addr = 0, plane_blk_addr = 0;
- pages_per_blk_shift = (chip->phys_erase_shift - chip->page_shift);
- if (page_addr != -1) {
- page_addr /= aml_chip->plane_num;
- plane_page_addr = (page_addr & ((1 << pages_per_blk_shift) - 1));
- plane_blk_addr = (page_addr >> pages_per_blk_shift);
- plane_blk_addr = (plane_blk_addr << 1);
- }
- if (aml_chip->plane_num == 2) {
- switch (command) {
- case NAND_CMD_READ0:
- if ((aml_chip->mfr_type == NAND_MFR_MICRON) || (aml_chip->mfr_type == NAND_MFR_INTEL)) {
- command_temp = command;
- }
- else {
- command_temp = NAND_CMD_TWOPLANE_PREVIOS_READ;
- column = -1;
- }
- plane_page_addr |= (plane_blk_addr << pages_per_blk_shift);
- break;
- case NAND_CMD_TWOPLANE_READ1:
- command_temp = NAND_CMD_READ0;
- if ((aml_chip->mfr_type == NAND_MFR_MICRON) || (aml_chip->mfr_type == NAND_MFR_INTEL))
- //plane_page_addr |= ((plane_blk_addr + 1) << 8);
- return;
- else
- plane_page_addr |= (plane_blk_addr << pages_per_blk_shift);
- break;
- case NAND_CMD_TWOPLANE_READ2:
- if ((aml_chip->mfr_type == NAND_MFR_MICRON) || (aml_chip->mfr_type == NAND_MFR_INTEL)) {
- command_temp = NAND_CMD_PLANE2_READ_START;
- }
- else {
- command_temp = NAND_CMD_READ0;
- }
- plane_page_addr |= ((plane_blk_addr + 1) << pages_per_blk_shift);
- break;
- case NAND_CMD_SEQIN:
- command_temp = command;
- plane_page_addr |= (plane_blk_addr << pages_per_blk_shift);
- break;
- case NAND_CMD_TWOPLANE_WRITE2:
- if ((aml_chip->mfr_type == NAND_MFR_HYNIX) || (aml_chip->mfr_type == NAND_MFR_SAMSUNG))
- command_temp = command;
- else
- command_temp = NAND_CMD_TWOPLANE_WRITE2_MICRO;
- plane_page_addr |= ((plane_blk_addr + 1) << pages_per_blk_shift);
- break;
- case NAND_CMD_ERASE1:
- command_temp = command;
- plane_page_addr |= (plane_blk_addr << pages_per_blk_shift);
- break;
- case NAND_CMD_MULTI_CHIP_STATUS:
- command_temp = command;
- plane_page_addr |= (plane_blk_addr << pages_per_blk_shift);
- break;
- default:
- command_temp = command;
- break;
- }
- chip->cmd_ctrl(mtd, command_temp & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- //if ((command_temp == NAND_CMD_SEQIN) || (command_temp == NAND_CMD_TWOPLANE_WRITE2) || (command_temp == NAND_CMD_READ0))
- //printk(" NAND plane_page_addr: %x plane_blk_addr %x command: %x \n", plane_page_addr, plane_blk_addr, command);
- if (column != -1 || page_addr != -1) {
- int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (chip->options & NAND_BUSWIDTH_16)
- column >>= 1;
- chip->cmd_ctrl(mtd, column, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- chip->cmd_ctrl(mtd, column >> 8, ctrl);
- }
- if (page_addr != -1) {
- chip->cmd_ctrl(mtd, plane_page_addr, ctrl);
- chip->cmd_ctrl(mtd, plane_page_addr >> 8, NAND_NCE | NAND_ALE);
- /* One more address cycle for devices > 128MiB */
- if (chip->chipsize > (128 << 20))
- chip->cmd_ctrl(mtd, plane_page_addr >> 16, NAND_NCE | NAND_ALE);
- }
- }
- switch (command) {
- case NAND_CMD_READ0:
- plane_page_addr = page_addr % (1 << pages_per_blk_shift);
-
- if ((aml_chip->mfr_type == NAND_MFR_MICRON) || (aml_chip->mfr_type == NAND_MFR_INTEL)) {
- plane_page_addr |= ((plane_blk_addr + 1) << pages_per_blk_shift);
- command_temp = command;
- chip->cmd_ctrl(mtd, command_temp & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- }
- else {
- command_temp = NAND_CMD_TWOPLANE_PREVIOS_READ;
- column = -1;
- plane_page_addr |= ((plane_blk_addr + 1) << pages_per_blk_shift);
- chip->cmd_ctrl(mtd, command_temp & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- }
- break;
- case NAND_CMD_TWOPLANE_READ1:
- if ((aml_chip->mfr_type == NAND_MFR_MICRON) || (aml_chip->mfr_type == NAND_MFR_INTEL)) {
- page_addr = -1;
- column = -1;
- }
- else {
- command_temp = NAND_CMD_RNDOUT;
- page_addr = -1;
- chip->cmd_ctrl(mtd, command_temp & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- }
- break;
- case NAND_CMD_TWOPLANE_READ2:
- if ((aml_chip->mfr_type == NAND_MFR_MICRON) || (aml_chip->mfr_type == NAND_MFR_INTEL)) {
- page_addr = -1;
- column = -1;
- }
- else {
- command_temp = NAND_CMD_RNDOUT;
- page_addr = -1;
- chip->cmd_ctrl(mtd, command_temp & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- }
- break;
- case NAND_CMD_ERASE1:
- if ((aml_chip->mfr_type == NAND_MFR_MICRON) || (aml_chip->mfr_type == NAND_MFR_INTEL)) {
- command_temp = NAND_CMD_ERASE1_END;
- chip->cmd_ctrl(mtd, command_temp & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- aml_chip->aml_nand_wait_devready(aml_chip, chipnr);
- }
- command_temp = command;
- chip->cmd_ctrl(mtd, command_temp & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- plane_page_addr = page_addr % (1 << pages_per_blk_shift);
- plane_page_addr |= ((plane_blk_addr + 1) << pages_per_blk_shift);
- break;
- default:
- column = -1;
- page_addr = -1;
- break;
- }
- if (column != -1 || page_addr != -1) {
- int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (chip->options & NAND_BUSWIDTH_16)
- column >>= 1;
- chip->cmd_ctrl(mtd, column, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- chip->cmd_ctrl(mtd, column >> 8, ctrl);
- }
- if (page_addr != -1) {
- //plane_page_addr |= (1 << (pages_per_blk_shift + 1));
- //BUG_ON((plane_page_addr & 0x7FF) == 0);
- chip->cmd_ctrl(mtd, plane_page_addr, ctrl);
- chip->cmd_ctrl(mtd, plane_page_addr >> 8, NAND_NCE | NAND_ALE);
- /* One more address cycle for devices > 128MiB */
- if (chip->chipsize > (128 << 20))
- chip->cmd_ctrl(mtd, plane_page_addr >> 16, NAND_NCE | NAND_ALE);
- }
- }
- if ((command == NAND_CMD_RNDOUT) || (command == NAND_CMD_TWOPLANE_READ2))
- chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- else if ((command == NAND_CMD_TWOPLANE_READ1)) {
- chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- }
- else if (command == NAND_CMD_READ0) {
- chip->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- }
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
- }
- else {
- chip->cmd_ctrl(mtd, command & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- if (column != -1 || page_addr != -1) {
- int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (chip->options & NAND_BUSWIDTH_16)
- column >>= 1;
- chip->cmd_ctrl(mtd, column, ctrl);
- ctrl &= ~NAND_CTRL_CHANGE;
- chip->cmd_ctrl(mtd, column >> 8, ctrl);
- }
- if (page_addr != -1) {
- chip->cmd_ctrl(mtd, page_addr, ctrl);
- chip->cmd_ctrl(mtd, page_addr >> 8, NAND_NCE | NAND_ALE);
- /* One more address cycle for devices > 128MiB */
- if (chip->chipsize > (128 << 20))
- chip->cmd_ctrl(mtd, page_addr >> 16, NAND_NCE | NAND_ALE);
- }
- }
- if (command == NAND_CMD_RNDOUT)
- chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- else if (command == NAND_CMD_READ0)
- chip->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
- }
- /*
- * program and erase have their own busy handlers
- * status, sequential in, and deplete1 need no delay
- */
- switch (command) {
- case NAND_CMD_CACHEDPROG:
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_RNDIN:
- case NAND_CMD_STATUS:
- case NAND_CMD_DEPLETE1:
- return;
- /*
- * read error status commands require only a short delay
- */
- case NAND_CMD_STATUS_ERROR:
- case NAND_CMD_STATUS_ERROR0:
- case NAND_CMD_STATUS_ERROR1:
- case NAND_CMD_STATUS_ERROR2:
- case NAND_CMD_STATUS_ERROR3:
- udelay(chip->chip_delay);
- return;
- case NAND_CMD_RESET:
- if (!aml_chip->aml_nand_wait_devready(aml_chip, chipnr))
- aml_nand_debug ("couldn't found selected chip: %d ready\n", chipnr);
- if (chip->dev_ready)
- break;
- udelay(chip->chip_delay);
- chip->cmd_ctrl(mtd, NAND_CMD_STATUS, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
- while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;
- return;
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- break;
- }
- /* Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine. */
- ndelay(100);
- }
- static void aml_nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct nand_chip *chip = &aml_chip->chip;
- int i = 0, valid_page_num = 1, internal_chip;
- if (page_addr != -1) {
- valid_page_num = (mtd->writesize >> chip->page_shift);
- valid_page_num /= aml_chip->plane_num;
- aml_chip->page_addr = page_addr / valid_page_num;
- if (unlikely(aml_chip->page_addr >= aml_chip->internal_page_nums)) {
- internal_chip = aml_chip->page_addr / aml_chip->internal_page_nums;
- aml_chip->page_addr -= aml_chip->internal_page_nums;
- aml_chip->page_addr |= (1 << aml_chip->internal_chip_shift) * internal_chip;
- }
- }
- /* Emulate NAND_CMD_READOOB */
- if (command == NAND_CMD_READOOB) {
- command = NAND_CMD_READ0;
- aml_chip->aml_nand_wait_devready(aml_chip, 0);
- aml_chip->aml_nand_command(aml_chip, command, column, aml_chip->page_addr, 0);
- return;
- }
- if (command == NAND_CMD_PAGEPROG)
- return;
- if (command == NAND_CMD_SEQIN) {
- aml_chip->aml_nand_wait_devready(aml_chip, 0);
- aml_chip->aml_nand_command(aml_chip, command, column, aml_chip->page_addr, 0);
- return;
- }
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- //active ce for operation chip and send cmd
- aml_chip->aml_nand_wait_devready(aml_chip, i);
- aml_chip->aml_nand_command(aml_chip, command, column, aml_chip->page_addr, i);
- }
- }
- return;
- }
- static void aml_nand_erase_cmd(struct mtd_info *mtd, int page)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct nand_chip *chip = mtd->priv;
- unsigned pages_per_blk_shift = (chip->phys_erase_shift - chip->page_shift);
- unsigned vt_page_num, i = 0, j = 0, internal_chipnr = 1, page_addr, valid_page_num;
- vt_page_num = (mtd->writesize / (1 << chip->page_shift));
- vt_page_num *= (1 << pages_per_blk_shift);
- if (page % vt_page_num)
- return;
- /* Send commands to erase a block */
- valid_page_num = (mtd->writesize >> chip->page_shift);
- valid_page_num /= aml_chip->plane_num;
- aml_chip->page_addr = page / valid_page_num;
- if (unlikely(aml_chip->page_addr >= aml_chip->internal_page_nums)) {
- internal_chipnr = aml_chip->page_addr / aml_chip->internal_page_nums;
- aml_chip->page_addr -= aml_chip->internal_page_nums;
- aml_chip->page_addr |= (1 << aml_chip->internal_chip_shift) * internal_chipnr;
- }
- if (unlikely(aml_chip->ops_mode & AML_INTERLEAVING_MODE))
- internal_chipnr = aml_chip->internal_chipnr;
- else
- internal_chipnr = 1;
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- aml_chip->aml_nand_select_chip(aml_chip, i);
- page_addr = aml_chip->page_addr;
- for (j=0; j<internal_chipnr; j++) {
- if (j > 0) {
- page_addr = aml_chip->page_addr;
- page_addr |= (1 << aml_chip->internal_chip_shift) * j;
- }
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_ERASE1, -1, page_addr, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_ERASE2, -1, -1, i);
- }
- }
- }
- return ;
- }
- #ifdef CONFIG_ARCH_MESON
- static int aml_platform_dma_waiting(struct aml_nand_chip *aml_chip)
- {
- unsigned time_out_cnt = 0;
- NFC_SEND_CMD_IDLE(aml_chip->chip_selected, 0);
- NFC_SEND_CMD_IDLE(aml_chip->chip_selected, 0);
- do {
- if (NFC_CMDFIFO_SIZE() <= 0)
- break;
- }while (time_out_cnt++ <= AML_DMA_BUSY_TIMEOUT);
- if (time_out_cnt < AML_DMA_BUSY_TIMEOUT)
- return 0;
- return -EBUSY;
- }
- static int aml_platform_hwecc_correct(struct aml_nand_chip *aml_chip, unsigned char *buf, unsigned size, unsigned char *oob_buf)
- {
- struct nand_chip *chip = &aml_chip->chip;
- struct mtd_info *mtd = &aml_chip->mtd;
- unsigned ecc_step_num;
- int error = 0;
- if (size % chip->ecc.size) {
- printk ("error parameter size for ecc correct %x\n", size);
- return -EINVAL;
- }
- for (ecc_step_num = 0; ecc_step_num < (size / chip->ecc.size); ecc_step_num++) {
- //check if there have uncorrectable sector
- if (NAND_ECC_FAIL(aml_chip->user_info_buf[ecc_step_num])
- || (NAND_ECC_CNT(aml_chip->user_info_buf[ecc_step_num]) == 0x1f)) {
- printk ("nand communication have uncorrectable ecc error %d %d %d\n", ecc_step_num, NAND_ECC_CNT(aml_chip->user_info_buf[ecc_step_num-1]), NAND_ECC_CNT(aml_chip->user_info_buf[ecc_step_num+1]));
- error = -EIO;
- }
- else {
- mtd->ecc_stats.corrected += NAND_ECC_CNT(aml_chip->user_info_buf[ecc_step_num]);
- }
- }
- return error;
- }
- static int aml_platform_dma_write(struct aml_nand_chip *aml_chip, unsigned char *buf, int len, unsigned bch_mode)
- {
- int ret = 0;
- memcpy(aml_chip->aml_nand_data_buf, buf, len);
- wmb();
- NFC_SEND_CMD_ADL(aml_chip->data_dma_addr);
- NFC_SEND_CMD_ADH(aml_chip->data_dma_addr);
- NFC_SEND_CMD_AIL(aml_chip->nand_info_dma_addr);
- NFC_SEND_CMD_AIH((aml_chip->nand_info_dma_addr));
- NFC_SEND_CMD_M2N(len, bch_mode);
- ret = aml_platform_dma_waiting(aml_chip);
- return ret;
- }
- static int aml_platform_dma_read(struct aml_nand_chip *aml_chip, unsigned char *buf, int len, unsigned bch_mode)
- {
- volatile unsigned int * info_buf;
- struct nand_chip *chip = &aml_chip->chip;
- unsigned dma_unit_size;
- int ret = 0;
- if (chip->ecc.size >= 512)
- dma_unit_size = chip->ecc.size;
- else
- dma_unit_size = 512;
- info_buf = aml_chip->user_info_buf + (((len + dma_unit_size - 1) / dma_unit_size) - 1);
- memset((unsigned char *)aml_chip->user_info_buf, 0, ((len + dma_unit_size - 1) / dma_unit_size)*sizeof(int));
- wmb();
- NFC_SEND_CMD_ADL(aml_chip->data_dma_addr);
- NFC_SEND_CMD_ADH(aml_chip->data_dma_addr);
- NFC_SEND_CMD_AIL(aml_chip->nand_info_dma_addr);
- NFC_SEND_CMD_AIH((aml_chip->nand_info_dma_addr));
- NFC_SEND_CMD_N2M(len, bch_mode);
- ret = aml_platform_dma_waiting(aml_chip);
- if (ret)
- return ret;
- while(NAND_INFO_DONE(*info_buf) == 0);
- rmb();
- if (buf != aml_chip->aml_nand_data_buf)
- memcpy(buf, aml_chip->aml_nand_data_buf, len);
- wmb();
- return 0;
- }
- #else
- static int aml_platform_hwecc_correct(struct aml_nand_chip *aml_chip, unsigned char *buf, unsigned size, unsigned char *oob_buf)
- {
- return 0;
- }
- static int aml_platform_dma_write(struct aml_nand_chip *aml_chip, unsigned char *buf, int len, unsigned bch_mode)
- {
- return 0;
- }
- static int aml_platform_dma_read(struct aml_nand_chip *aml_chip, unsigned char *buf, int len, unsigned bch_mode)
- {
- return 0;
- }
- #endif
- static void aml_nand_dma_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
-
- aml_chip->aml_nand_dma_read(aml_chip, buf, len, 0);
- }
- static void aml_nand_dma_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- aml_chip->aml_nand_dma_write(aml_chip, (unsigned char *)buf, len, 0);
- }
- static int aml_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- unsigned nand_page_size = aml_chip->page_size;
- unsigned nand_oob_size = aml_chip->oob_size;
- uint8_t *oob_buf = chip->oob_poi;
- int i, error = 0, j = 0, page_addr, internal_chipnr = 1;
- if (aml_chip->ops_mode & AML_INTERLEAVING_MODE)
- internal_chipnr = aml_chip->internal_chipnr;
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- page_addr = aml_chip->page_addr;
- for (j=0; j<internal_chipnr; j++) {
- if (j > 0) {
- page_addr = aml_chip->page_addr;
- page_addr |= (1 << aml_chip->internal_chip_shift) * j;
- aml_chip->aml_nand_select_chip(aml_chip, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_READ0, 0, page_addr, i);
- }
- if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) {
- printk ("couldn`t found selected chip: %d ready\n", i);
- error = -EBUSY;
- goto exit;
- }
- if (aml_chip->ops_mode & AML_CHIP_NONE_RB)
- chip->cmd_ctrl(mtd, NAND_CMD_READ0 & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- if (aml_chip->plane_num == 2) {
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TWOPLANE_READ1, 0x00, page_addr, i);
- aml_chip->aml_nand_dma_read(aml_chip, aml_chip->aml_nand_data_buf, nand_page_size + nand_oob_size, 0);
- memcpy(buf, aml_chip->aml_nand_data_buf, (nand_page_size + nand_oob_size));
- memcpy(oob_buf, aml_chip->aml_nand_data_buf + nand_page_size, nand_oob_size);
- oob_buf += nand_oob_size;
- buf += (nand_page_size + nand_oob_size);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TWOPLANE_READ2, 0x00, page_addr, i);
- aml_chip->aml_nand_dma_read(aml_chip, aml_chip->aml_nand_data_buf, nand_page_size + nand_oob_size, 0);
- memcpy(buf, aml_chip->aml_nand_data_buf, (nand_page_size + nand_oob_size));
- memcpy(oob_buf, aml_chip->aml_nand_data_buf + nand_page_size, nand_oob_size);
- oob_buf += nand_oob_size;
- buf += (nand_page_size + nand_oob_size);
- }
- else if (aml_chip->plane_num == 1) {
- aml_chip->aml_nand_dma_read(aml_chip, aml_chip->aml_nand_data_buf, nand_page_size + nand_oob_size, 0);
- memcpy(buf, aml_chip->aml_nand_data_buf, (nand_page_size + nand_oob_size));
- memcpy(oob_buf, aml_chip->aml_nand_data_buf + nand_page_size, nand_oob_size);
- oob_buf += nand_oob_size;
- buf += nand_page_size;
- }
- else {
- error = -ENODEV;
- aml_nand_debug ("plane_num mistake\n");
- goto exit;
- }
- }
- }
- }
- exit:
- return error;
- }
- static void aml_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- unsigned nand_page_size = aml_chip->page_size;
- unsigned nand_oob_size = aml_chip->oob_size;
- uint8_t *oob_buf = chip->oob_poi;
- int i, error = 0, j = 0, page_addr, internal_chipnr = 1;
- if (aml_chip->ops_mode & AML_INTERLEAVING_MODE)
- internal_chipnr = aml_chip->internal_chipnr;
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- aml_chip->aml_nand_select_chip(aml_chip, i);
- page_addr = aml_chip->page_addr;
- for (j=0; j<internal_chipnr; j++) {
- if (j > 0) {
- page_addr = aml_chip->page_addr;
- page_addr |= (1 << aml_chip->internal_chip_shift) * j;
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_SEQIN, 0, page_addr, i);
- }
-
- if (aml_chip->plane_num == 2) {
-
- memcpy(aml_chip->aml_nand_data_buf, buf, nand_page_size);
- memcpy(aml_chip->aml_nand_data_buf + nand_page_size, oob_buf, nand_oob_size);
- aml_chip->aml_nand_dma_write(aml_chip, aml_chip->aml_nand_data_buf, nand_page_size + nand_oob_size, 0);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_DUMMY_PROGRAM, -1, -1, i);
-
- oob_buf += nand_oob_size;
- buf += nand_page_size;
-
- if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) {
- aml_nand_debug ("couldn`t found selected chip: %d ready\n", i);
- error = -EBUSY;
- goto exit;
- }
-
- memcpy(aml_chip->aml_nand_data_buf, buf, nand_page_size);
- memcpy(aml_chip->aml_nand_data_buf + nand_page_size, oob_buf, nand_oob_size);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TWOPLANE_WRITE2, 0x00, page_addr, i);
- aml_chip->aml_nand_dma_write(aml_chip, aml_chip->aml_nand_data_buf, nand_page_size + nand_oob_size, 0);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_PAGEPROG, -1, -1, i);
-
- oob_buf += nand_oob_size;
- buf += nand_page_size;
- }
- else if (aml_chip->plane_num == 1) {
-
- memcpy(aml_chip->aml_nand_data_buf, buf, nand_page_size);
- memcpy(aml_chip->aml_nand_data_buf + nand_page_size, oob_buf, nand_oob_size);
- aml_chip->aml_nand_dma_write(aml_chip, aml_chip->aml_nand_data_buf, nand_page_size + nand_oob_size, 0);
- if (chip->cmdfunc == aml_nand_command)
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_PAGEPROG, -1, -1, i);
-
- oob_buf += nand_oob_size;
- buf += nand_page_size;
- }
- else {
- error = -ENODEV;
- aml_nand_debug ("plane_num mistake\n");
- goto exit;
- }
- }
- }
- }
- exit:
- return ;
- }
- static int aml_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- uint8_t *oob_buf = chip->oob_poi;
- unsigned nand_page_size = (1 << chip->page_shift);
- unsigned pages_per_blk_shift = (chip->phys_erase_shift - chip->page_shift);
- int user_byte_num = (((nand_page_size + chip->ecc.size - 1) / chip->ecc.size) * aml_chip->user_byte_mode);
- int error = 0, i = 0, stat = 0, j = 0, page_addr, internal_chipnr = 1;
- int readretry_failed_cnt = 0;
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- int ran_mode = aml_chip->ran_mode;
- #endif
- if (aml_chip->ops_mode & AML_INTERLEAVING_MODE)
- internal_chipnr = aml_chip->internal_chipnr;
- if (nand_page_size > chip->ecc.steps * chip->ecc.size) {
- nand_page_size = chip->ecc.steps * chip->ecc.size;
- user_byte_num = chip->ecc.steps;
- }
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- readretry_failed_cnt = 0;
- read_retry:
- page_addr = aml_chip->page_addr;
- for (j=0; j<internal_chipnr; j++) {
- if (j > 0) {
- page_addr = aml_chip->page_addr;
- page_addr |= (1 << aml_chip->internal_chip_shift) * j;
- aml_chip->aml_nand_select_chip(aml_chip, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_READ0, 0, page_addr, i);
- }
- if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) {
- printk ("read couldn`t found selected chip: %d ready\n", i);
- mdelay(50);
- if (!aml_chip->aml_nand_wait_devready(aml_chip, i))
- {
- printk ("read couldn`t found selected chip: %d ready\n", i);
- mdelay(100);
- error = -EBUSY;
- goto exit;
- }
- }
- if (aml_chip->ops_mode & AML_CHIP_NONE_RB)
- chip->cmd_ctrl(mtd, NAND_CMD_READ0 & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
- if (aml_chip->plane_num == 2) {
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TWOPLANE_READ1, 0x00, page_addr, i);
- dma_retry_plane0:
- error = aml_chip->aml_nand_dma_read(aml_chip, buf, nand_page_size, aml_chip->bch_mode);
- if (error){
- mdelay(50);
- printk("aml nand read data ecc plane0 failed at page %d chip %d\n", page_addr, i);
- error = aml_chip->aml_nand_dma_read(aml_chip, buf, nand_page_size, aml_chip->bch_mode);
- if(error){
- mdelay(100);
- goto exit;
- }
- }
- aml_chip->aml_nand_get_user_byte(aml_chip, oob_buf, user_byte_num);
- stat = aml_chip->aml_nand_hwecc_correct(aml_chip, buf, nand_page_size, oob_buf);
- if (stat < 0) {
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ran_mode && (aml_chip->zero_cnt < aml_chip->ecc_max)){
- memset(buf, 0xff, nand_page_size);
- memset(oob_buf, 0xff, user_byte_num);
- goto plane0_ff;
- }
-
- if(ran_mode && aml_chip->ran_mode){
- //printk("%s dma retry here at page:%d blk %d chip %d\n", __func__, page_addr, (page_addr >> pages_per_blk_shift), i);
- aml_chip->ran_mode = 0;
- ndelay(300);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_RNDOUT, 0, -1, i);
- ndelay(500);
- goto dma_retry_plane0;
- }
- #endif
- memset(buf, 0xff, nand_page_size);
- memset(oob_buf, 0xff, user_byte_num);
- mtd->ecc_stats.failed++;
- printk("aml nand read data ecc plane0 failed at page %d chip %d \n", page_addr, i);
- }
- else{
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ecc_cnt_cur > aml_chip->ecc_cnt_limit){
- printk("%s line:%d uncorrected ecc_cnt_cur:%d, and limit:%d and at page:%d, blk:%d chip[%d]\n",\
- __func__, __LINE__, aml_chip->ecc_cnt_cur, aml_chip->ecc_cnt_limit, page_addr, (page_addr >> pages_per_blk_shift), i);
- mtd->ecc_stats.corrected++;
- }
- #endif
- mtd->ecc_stats.corrected += stat;
- }
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- plane0_ff:
- aml_chip->ran_mode = ran_mode;
- #endif
- oob_buf += user_byte_num;
- buf += nand_page_size;
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TWOPLANE_READ2, 0x00, page_addr, i);
- dma_retry_plane1:
- error = aml_chip->aml_nand_dma_read(aml_chip, buf, nand_page_size, aml_chip->bch_mode);
- if (error){
- printk("aml nand read data dma plane1 failed at page %d chip %d\n", page_addr, i);
- mdelay(50);
- error = aml_chip->aml_nand_dma_read(aml_chip, buf, nand_page_size, aml_chip->bch_mode);
- if(error){
- mdelay(100);
- goto exit;
- }
- }
- aml_chip->aml_nand_get_user_byte(aml_chip, oob_buf, user_byte_num);
- stat = aml_chip->aml_nand_hwecc_correct(aml_chip, buf, nand_page_size, oob_buf);
- if (stat < 0) {
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ran_mode && (aml_chip->zero_cnt < aml_chip->ecc_max)){
- memset(buf, 0xff, nand_page_size);
- memset(oob_buf, 0xff, user_byte_num);
- oob_buf += user_byte_num;
- buf += nand_page_size;
- continue;
- }
-
- if(ran_mode && aml_chip->ran_mode){
- //printk("%s dma retry here at page:%d blk %d chip %d\n", __func__, page_addr, (page_addr >> pages_per_blk_shift), i);
- aml_chip->ran_mode = 0;
- ndelay(300);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_RNDOUT, 0, -1, i);
- ndelay(500);
- goto dma_retry_plane1;
- }
- #endif
- memset(buf, 0xff, nand_page_size);
- memset(oob_buf, 0xff, user_byte_num);
- mtd->ecc_stats.failed++;
- printk("aml nand read data ecc plane1 failed at page %d chip %d \n", page_addr, i);
- }
- else{
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ecc_cnt_cur > aml_chip->ecc_cnt_limit) {
- printk("%s line:%d uncorrected ecc_cnt_cur:%d, and limit:%d and at page:%d, blk:%d chip[%d]\n",
- __func__, __LINE__, aml_chip->ecc_cnt_cur, aml_chip->ecc_cnt_limit, page_addr, (page_addr >> pages_per_blk_shift), i);
- mtd->ecc_stats.corrected++;
- }
- #endif
- mtd->ecc_stats.corrected += stat;
- }
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- aml_chip->ran_mode = ran_mode;
- #endif
- oob_buf += user_byte_num;
- buf += nand_page_size;
- }
- else if (aml_chip->plane_num == 1) {
- dma_retry_3:
- error = aml_chip->aml_nand_dma_read(aml_chip, buf, nand_page_size, aml_chip->bch_mode);
- if (error){
- printk("aml nand read data dma plane failed at page %d chip %d\n", page_addr, i);
- mdelay(50);
- error = aml_chip->aml_nand_dma_read(aml_chip, buf, nand_page_size, aml_chip->bch_mode);
- if(error){
- mdelay(100);
- goto exit;
- }
- }
-
- aml_chip->aml_nand_get_user_byte(aml_chip, oob_buf, user_byte_num);
- stat = aml_chip->aml_nand_hwecc_correct(aml_chip, buf, nand_page_size, oob_buf);
- if (stat < 0) {
- //mtd->ecc_stats.failed++;
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ran_mode && (aml_chip->zero_cnt < aml_chip->ecc_max)){
- memset(buf, 0xff, nand_page_size);
- memset(oob_buf, 0xff, user_byte_num);
- oob_buf += user_byte_num;
- buf += nand_page_size;
- continue;
- }
- if(ran_mode && aml_chip->ran_mode && (readretry_failed_cnt == 0)){
- //printk("%s dma retry here at page:%d blk %d chip %d\n", __func__, page_addr, (page_addr >> pages_per_blk_shift), i);
- aml_chip->ran_mode = 0;
- ndelay(300);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_RNDOUT, 0, -1, i);
- ndelay(500);
- goto dma_retry_3;
- }
-
- aml_chip->ran_mode = ran_mode;
- #endif
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->new_nand_info.type) && (readretry_failed_cnt++ < aml_chip->new_nand_info.read_rety_info.retry_cnt)){
- printk("aml nand read data ecc failed at page:%d blk %d chip %d, readretry_failed_cnt:%d\n",
- page_addr, (page_addr >> pages_per_blk_shift), i, readretry_failed_cnt);
- aml_chip->new_nand_info.read_rety_info.read_retry_handle(mtd, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_READ0, 0, page_addr, i);
- goto read_retry;
- }
- #endif
- memset(buf, 0xff, nand_page_size);
- memset(oob_buf, 0xff, user_byte_num);
- printk("########%s %d read ecc failed here at at page:%d, blk:%d chip[%d]\n", __func__, __LINE__, page_addr, (page_addr >> pages_per_blk_shift), i);
- mtd->ecc_stats.failed++;
- }
- else{
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- aml_chip->ran_mode = ran_mode;
- #endif
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->ecc_cnt_cur > aml_chip->ecc_cnt_limit) ||((readretry_failed_cnt > (aml_chip->new_nand_info.read_rety_info.retry_cnt-2)) && aml_chip->new_nand_info.type)){
- printk("%s line:%d uncorrected ecc_cnt_cur:%d, and limit:%d and at page:%d, blk:%d chip[%d], readretry_failed_cnt:%d\n",
- __func__, __LINE__, aml_chip->ecc_cnt_cur, aml_chip->ecc_cnt_limit, page_addr, (page_addr >> pages_per_blk_shift), i, readretry_failed_cnt);
- mtd->ecc_stats.corrected++;
- }
- #endif
- mtd->ecc_stats.corrected += stat;
- }
- #ifdef NEW_NAND_SUPPORT
- if(readretry_failed_cnt && aml_chip->new_nand_info.read_rety_info.read_retry_exit){
- aml_chip->new_nand_info.read_rety_info.read_retry_exit(mtd, i);
- }
- #endif
- oob_buf += user_byte_num;
- buf += nand_page_size;
- }
- else {
- error = -ENODEV;
- mdelay(100);
- goto exit;
- }
- }
- }
- }
- exit:
- return 0; //do not return error when failed
- }
- static void aml_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- uint8_t *oob_buf = chip->oob_poi;
- unsigned nand_page_size = (1 << chip->page_shift);
- int user_byte_num = (((nand_page_size + chip->ecc.size - 1) / chip->ecc.size) * aml_chip->user_byte_mode);
- int error = 0, i = 0, j = 0, page_addr, internal_chipnr = 1;
- if (aml_chip->ops_mode & AML_INTERLEAVING_MODE)
- internal_chipnr = aml_chip->internal_chipnr;
- memset(oob_buf + mtd->oobavail, 0xa5, user_byte_num * (mtd->writesize / nand_page_size));
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- aml_chip->aml_nand_select_chip(aml_chip, i);
- page_addr = aml_chip->page_addr;
- if (i > 0) {
- if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) {
- printk ("chip: %d: busy\n", i);
- error = -EBUSY;
- goto exit;
- }
- page_addr = aml_chip->page_addr;
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_SEQIN, 0, page_addr, i);
- }
- for (j=0; j<internal_chipnr; j++) {
- if (j > 0) {
- page_addr = aml_chip->page_addr;
- page_addr |= (1 << aml_chip->internal_chip_shift) * j;
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_SEQIN, 0, page_addr, i);
- }
- if (aml_chip->plane_num == 2) {
-
- aml_chip->aml_nand_set_user_byte(aml_chip, oob_buf, user_byte_num);
- error = aml_chip->aml_nand_dma_write(aml_chip, (unsigned char *)buf, nand_page_size, aml_chip->bch_mode);
- if (error)
- goto exit;
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_DUMMY_PROGRAM, -1, -1, i);
- oob_buf += user_byte_num;
- buf += nand_page_size;
-
- if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) {
- printk ("write couldn`t found selected chip: %d ready\n", i);
- error = -EBUSY;
- goto exit;
- }
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TWOPLANE_WRITE2, 0x00, page_addr, i);
- aml_chip->aml_nand_set_user_byte(aml_chip, oob_buf, user_byte_num);
- error = aml_chip->aml_nand_dma_write(aml_chip, (unsigned char *)buf, nand_page_size, aml_chip->bch_mode);
- if (error)
- goto exit;
- if (aml_chip->cached_prog_status)
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_CACHEDPROG, -1, -1, i);
- else
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_PAGEPROG, -1, -1, i);
- oob_buf += user_byte_num;
- buf += nand_page_size;
- }
- else if (aml_chip->plane_num == 1) {
- aml_chip->aml_nand_set_user_byte(aml_chip, oob_buf, user_byte_num);
- error = aml_chip->aml_nand_dma_write(aml_chip, (unsigned char *)buf, nand_page_size, aml_chip->bch_mode);
- if (error)
- goto exit;
- if (chip->cmdfunc == aml_nand_command) {
- if (aml_chip->cached_prog_status)
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_CACHEDPROG, -1, -1, i);
- else
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_PAGEPROG, -1, -1, i);
- }
- oob_buf += user_byte_num;
- buf += nand_page_size;
- }
- else {
- error = -ENODEV;
- goto exit;
- }
- }
- }
- }
- exit:
- return;
- }
- static int aml_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, int cached, int raw)
- {
- int status;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
- /*if ((cached) && (chip->options & NAND_CACHEPRG))
- aml_chip->cached_prog_status = 1;
- else
- aml_chip->cached_prog_status = 0;*/
- if (unlikely(raw))
- chip->ecc.write_page_raw(mtd, chip, buf);
- else
- chip->ecc.write_page(mtd, chip, buf);
- if (!cached || !(chip->options & NAND_CACHEPRG)) {
- //chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
- /*
- * See if operation failed and additional status checks are
- * available
- */
- if ((status & NAND_STATUS_FAIL) && (chip->errstat))
- status = chip->errstat(mtd, chip, FL_WRITING, status, page);
- if (status & NAND_STATUS_FAIL) {
- printk("aml nand write failed at %d \n", page);
- return -EIO;
- }
- } else {
- //chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
- }
- aml_chip->cached_prog_status = 0;
- #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
- status = chip->ecc.read_page(mtd, chip, chip->buffers->databuf, page);
- if (status == -EUCLEAN)
- status = 0;
- chip->pagebuf = page;
- if (memcmp(buf, chip->buffers->databuf, mtd->writesize)) {
- printk("nand verify failed at %d \n", page);
- return -EFAULT;
- }
- #endif
- return 0;
- }
- static int aml_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, int readlen)
- {
- int32_t error = 0, i, stat = 0, j = 0, page_addr, user_byte_num, internal_chipnr = 1;
- unsigned dma_once_size;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- unsigned char *nand_buffer = aml_chip->aml_nand_data_buf;
- unsigned char *oob_buffer = chip->oob_poi;
- unsigned pages_per_blk_shift = (chip->phys_erase_shift - chip->page_shift);
- unsigned nand_page_size = (1 << chip->page_shift);
- //unsigned nand_read_size = ((readlen / (aml_chip->user_byte_mode * aml_chip->plane_num)) * chip->ecc.size);
- unsigned nand_read_size = ((readlen / aml_chip->user_byte_mode) * chip->ecc.size);
- unsigned read_chip_num = (((nand_read_size + (aml_chip->plane_num * nand_page_size) - 1) / (aml_chip->plane_num * nand_page_size)));
- int readretry_failed_cnt = 0;
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- int ran_mode = aml_chip->ran_mode;
- #endif
- if (nand_read_size >= nand_page_size)
- user_byte_num = (((nand_page_size + chip->ecc.size - 1) / chip->ecc.size) * aml_chip->user_byte_mode);
- else
- user_byte_num = (((nand_read_size + chip->ecc.size - 1) / chip->ecc.size) * aml_chip->user_byte_mode);
- page_addr = page;
- if (aml_chip->ops_mode & AML_INTERLEAVING_MODE) {
- internal_chipnr = aml_chip->internal_chipnr;
- if (read_chip_num < internal_chipnr) {
- internal_chipnr = (read_chip_num + aml_chip->internal_chipnr - 1) / aml_chip->internal_chipnr;
- read_chip_num = 1;
- }
- else {
- read_chip_num = (read_chip_num + aml_chip->internal_chipnr - 1) / aml_chip->internal_chipnr;
- }
- }
-
- if (chip->cmdfunc == aml_nand_command)
- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page_addr);
- else {
- aml_chip->aml_nand_select_chip(aml_chip, 0);
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page_addr);
- }
- for (i=0; i<read_chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- readretry_failed_cnt = 0;
- read_retry:
- page_addr = aml_chip->page_addr;
- if (i > 0) {
- aml_chip->aml_nand_select_chip(aml_chip, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_READ0, 0, page_addr, i);
- }
- for (j=0; j<internal_chipnr; j++) {
- if (j > 0) {
- page_addr = aml_chip->page_addr;
- page_addr |= (1 << aml_chip->internal_chip_shift) * j;
- aml_chip->aml_nand_select_chip(aml_chip, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_READ0, 0, page_addr, i);
- }
- if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) {
- mdelay(50);
- if (!aml_chip->aml_nand_wait_devready(aml_chip, i)) {
- printk ("read oob couldn`t found selected chip: %d ready\n", i);
- error = -EBUSY;
- mdelay(100);
- goto exit;
- }
- }
- if (aml_chip->ops_mode & AML_CHIP_NONE_RB)
- chip->cmd_ctrl(mtd, NAND_CMD_READ0 & 0xff, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
-
- if (aml_chip->plane_num == 2) {
- dma_once_size = min(nand_read_size, nand_page_size);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TWOPLANE_READ1, 0x00, page_addr, i);
- dma_retry_plane0:
- error = aml_chip->aml_nand_dma_read(aml_chip, nand_buffer, dma_once_size, aml_chip->bch_mode);
- if (error)
- {
- printk("read oob dma failed at page %d\n", page_addr);
- mdelay(50);
- error = aml_chip->aml_nand_dma_read(aml_chip, nand_buffer, dma_once_size, aml_chip->bch_mode);
- if(error)
- {
- printk("read oob dma failed again at page %d\n", page_addr);
- mdelay(100);
- return 0;//error;
- }
- }
- aml_chip->aml_nand_get_user_byte(aml_chip, oob_buffer, user_byte_num);
- stat = aml_chip->aml_nand_hwecc_correct(aml_chip, nand_buffer, dma_once_size, oob_buffer);
- if (stat < 0) {
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ran_mode && (aml_chip->zero_cnt < aml_chip->ecc_max)){
- memset(oob_buffer, 0xff, user_byte_num);
- goto plane0_ff;
- }
-
- if(ran_mode && aml_chip->ran_mode){
- //printk("%s dma retry here at page:%d blk %d chip %d\n", __func__, page_addr, (page_addr >> pages_per_blk_shift), i);
- aml_chip->ran_mode = 0;
- ndelay(300);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_RNDOUT, 0, -1, i);
- ndelay(500);
- goto dma_retry_plane0;
- }
- #endif
- memset(oob_buffer, 0xff, user_byte_num);
- mtd->ecc_stats.failed++;
- printk("aml nand read oob plane0 failed at page %d chip %d \n", page_addr, i);
- }
- else{
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ecc_cnt_cur > aml_chip->ecc_cnt_limit){
- printk("%s line:%d uncorrected ecc_cnt_cur:%d, and limit:%d and at page:%d, blk:%d chip[%d]\n",
- __func__, __LINE__, aml_chip->ecc_cnt_cur, aml_chip->ecc_cnt_limit, page_addr, (page_addr >> pages_per_blk_shift), i);
- mtd->ecc_stats.corrected++;
- }
- #endif
- mtd->ecc_stats.corrected += stat;
- }
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- plane0_ff:
- aml_chip->ran_mode = ran_mode;
- #endif
- oob_buffer += user_byte_num;
- nand_read_size -= dma_once_size;
- if (nand_read_size > 0) {
- dma_once_size = min(nand_read_size, nand_page_size);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_TWOPLANE_READ2, 0x00, page_addr, i);
- dma_retry_plane1:
- error = aml_chip->aml_nand_dma_read(aml_chip, nand_buffer, dma_once_size, aml_chip->bch_mode);
- if (error){
- printk("read oob dma failed at page %d\n", page_addr);
- mdelay(50);
- error = aml_chip->aml_nand_dma_read(aml_chip, nand_buffer, dma_once_size, aml_chip->bch_mode);
- if(error){
- printk("read oob dma failed again at page %d\n", page_addr);
- mdelay(100);
- return 0;//error;
- }
- }
- aml_chip->aml_nand_get_user_byte(aml_chip, oob_buffer, user_byte_num);
- stat = aml_chip->aml_nand_hwecc_correct(aml_chip, nand_buffer, dma_once_size, oob_buffer);
- if (stat < 0) {
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ran_mode && (aml_chip->zero_cnt < aml_chip->ecc_max)){
- memset(oob_buffer, 0xff, user_byte_num);
- oob_buffer += user_byte_num;
- nand_read_size -= dma_once_size;
- continue;
- }
-
- if(ran_mode && aml_chip->ran_mode){
- //printk("%s dma retry here at page:%d blk %d chip %d\n", __func__, page_addr, (page_addr >> pages_per_blk_shift), i);
- aml_chip->ran_mode = 0;
- ndelay(300);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_RNDOUT, 0, -1, i);
- ndelay(500);
- goto dma_retry_plane1;
- }
- #endif
- memset(oob_buffer, 0xff, user_byte_num);
- mtd->ecc_stats.failed++;
- printk("aml nand read oob plane1 failed at page %d chip %d \n", page_addr, i);
- }
- else{
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ecc_cnt_cur > aml_chip->ecc_cnt_limit){
- printk("%s line:%d uncorrected ecc_cnt_cur:%d, and limit:%d and at page:%d, blk:%d chip[%d]\n",
- __func__, __LINE__, aml_chip->ecc_cnt_cur, aml_chip->ecc_cnt_limit, page_addr, (page_addr >> pages_per_blk_shift), i);
-
- mtd->ecc_stats.corrected++;
- }
- #endif
- mtd->ecc_stats.corrected += stat;
- }
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- aml_chip->ran_mode = ran_mode;
- #endif
- oob_buffer += user_byte_num;
- nand_read_size -= dma_once_size;
- }
- }
- else if (aml_chip->plane_num == 1) {
- dma_once_size = min(nand_read_size, nand_page_size);
- dma_retry:
- error = aml_chip->aml_nand_dma_read(aml_chip, nand_buffer, dma_once_size, aml_chip->bch_mode);
- if (error){
- printk("read oob dma failed at page %d\n", page_addr);
- mdelay(50);
- error = aml_chip->aml_nand_dma_read(aml_chip, nand_buffer, dma_once_size, aml_chip->bch_mode);
- if(error){
- printk("read oob dma failed again at page %d\n", page_addr);
- mdelay(100);
- return 0;//error;
- }
- }
- aml_chip->aml_nand_get_user_byte(aml_chip, oob_buffer, user_byte_num);
- stat = aml_chip->aml_nand_hwecc_correct(aml_chip, nand_buffer, dma_once_size, oob_buffer);
- if (stat < 0) {
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- if(aml_chip->ran_mode && (aml_chip->zero_cnt < aml_chip->ecc_max)){
- memset(oob_buffer, 0xff, user_byte_num);
- oob_buffer += user_byte_num;
- nand_read_size -= dma_once_size;
- continue;
- }
- if(ran_mode && aml_chip->ran_mode && (readretry_failed_cnt == 0)){
- //printk("%s dma retry here at page:%d blk %d chip %d\n", __func__, page_addr, (page_addr >> pages_per_blk_shift), i);
- aml_chip->ran_mode = 0;
- ndelay(300);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_RNDOUT, 0, -1, i);
- ndelay(500);
- goto dma_retry;
- }
-
- aml_chip->ran_mode = ran_mode;
- #endif
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->new_nand_info.type) && (readretry_failed_cnt++ < aml_chip->new_nand_info.read_rety_info.retry_cnt)){
- printk("aml nand read oob failed at page:%d blk %d chip %d, readretry_failed_cnt:%d\n",
- page_addr, (page_addr >> pages_per_blk_shift), i, readretry_failed_cnt);
- aml_chip->new_nand_info.read_rety_info.read_retry_handle(mtd, i);
- aml_chip->aml_nand_command(aml_chip, NAND_CMD_READ0, 0, page_addr, i);
- goto read_retry;
- }
- #endif
- printk("########%s %d read oob failed here at at page:%d, blk:%d chip[%d]\n", __func__, __LINE__, page_addr, (page_addr >> pages_per_blk_shift), i);
-
- memset(oob_buffer, 0xff, user_byte_num);
- mtd->ecc_stats.failed++;
- }
- else{
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- aml_chip->ran_mode = ran_mode;
- #endif
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->ecc_cnt_cur > aml_chip->ecc_cnt_limit) ||((readretry_failed_cnt > (aml_chip->new_nand_info.read_rety_info.retry_cnt-2)) && aml_chip->new_nand_info.type)){
- printk("%s line:%d uncorrected ecc_cnt_cur:%d, and limit:%d and at page:%d, blk:%d chip[%d], readretry_failed_cnt:%d\n",
- __func__, __LINE__, aml_chip->ecc_cnt_cur, aml_chip->ecc_cnt_limit, page_addr, (page_addr >> pages_per_blk_shift), i, readretry_failed_cnt);
-
- mtd->ecc_stats.corrected++;
- }
- #endif
- mtd->ecc_stats.corrected += stat;
- }
- #ifdef NEW_NAND_SUPPORT
- if(readretry_failed_cnt && aml_chip->new_nand_info.read_rety_info.read_retry_exit){
- aml_chip->new_nand_info.read_rety_info.read_retry_exit(mtd, i);
- }
- #endif
- oob_buffer += user_byte_num;
- nand_read_size -= dma_once_size;
- }
- else {
- error = -ENODEV;
- mdelay(100);
- goto exit;
- }
- }
- }
- }
- exit:
- return readlen;
- }
- static int aml_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
- {
- printk("our host controller`s structure couldn`t support oob write\n");
- BUG();
- return 0;
- }
- static int aml_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
- {
- struct nand_chip * chip = mtd->priv;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct aml_nand_platform *plat = aml_chip->platform;
- struct mtd_oob_ops aml_oob_ops;
- int32_t ret = 0, read_cnt, page, mtd_erase_shift, blk_addr, pages_per_blk;
- loff_t addr;
- if ((!strncmp((char*)plat->name, NAND_BOOT_NAME, strlen((const char*)NAND_BOOT_NAME)))/* && ((chip->ecc.read_page == aml_nand_read_page_hwecc) || (!getchip))*/)
- return 0;
- mtd_erase_shift = fls(mtd->erasesize) - 1;
- blk_addr = (int)(ofs >> mtd_erase_shift);
- if (aml_chip->block_status != NULL) {
- if (aml_chip->block_status[blk_addr] == NAND_BLOCK_BAD) {
- printk(" NAND bbt detect Bad block at %llx \n", (uint64_t)ofs);
- return EFAULT;
- }
- else if (aml_chip->block_status[blk_addr] == NAND_BLOCK_GOOD) {
- return 0;
- }
- }
- chip->pagebuf = -1;
- pages_per_blk = (1 << (chip->phys_erase_shift - chip->page_shift));
- if (getchip) {
- aml_oob_ops.mode = MTD_OOB_AUTO;
- aml_oob_ops.len = mtd->writesize;
- aml_oob_ops.ooblen = mtd->oobavail;
- aml_oob_ops.ooboffs = chip->ecc.layout->oobfree[0].offset;
- aml_oob_ops.datbuf = chip->buffers->databuf;
- aml_oob_ops.oobbuf = chip->oob_poi;
- for (read_cnt=0; read_cnt<2; read_cnt++) {
- addr = ofs + (pages_per_blk - 1) * read_cnt * mtd->writesize;
- ret = mtd->read_oob(mtd, addr, &aml_oob_ops);
- if (ret == -EUCLEAN)
- ret = 0;
- if (ret < 0) {
- printk(" NAND detect Bad block at %llx \n", (uint64_t)addr);
- return EFAULT;
- }
- if (aml_oob_ops.oobbuf[chip->badblockpos] == 0xFF)
- continue;
- if (aml_oob_ops.oobbuf[chip->badblockpos] == 0) {
- memset(aml_chip->aml_nand_data_buf, 0, aml_oob_ops.ooblen);
- if (!memcmp(aml_chip->aml_nand_data_buf, aml_oob_ops.oobbuf, aml_oob_ops.ooblen)) {
- printk(" NAND detect Bad block at %llx \n", (uint64_t)addr);
- return EFAULT;
- }
- }
- }
- }
- else {
- for (read_cnt=0; read_cnt<2; read_cnt++) {
- addr = ofs + (pages_per_blk - 1) * read_cnt * mtd->writesize;
- page = (int)(addr >> chip->page_shift);
- ret = chip->ecc.read_oob(mtd, chip, page, mtd->oobavail);
- if (ret == -EUCLEAN)
- ret = 0;
- if (ret < 0)
- return EFAULT;
- if (chip->oob_poi[chip->badblockpos] == 0xFF)
- return 0;
- if (chip->oob_poi[chip->badblockpos] == 0) {
- memset(aml_chip->aml_nand_data_buf, 0, (mtd->writesize + mtd->oobsize));
- if (!memcmp(aml_chip->aml_nand_data_buf + mtd->writesize, chip->oob_poi, mtd->oobavail)) {
- printk(" NAND detect Bad block at %llx \n", (uint64_t)addr);
- return EFAULT;
- }
- }
- }
- }
- return 0;
- }
- static int aml_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
- {
- struct nand_chip * chip = mtd->priv;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct mtd_oob_ops aml_oob_ops;
- int blk_addr, mtd_erase_shift, j;
- mtd_erase_shift = fls(mtd->erasesize) - 1;
- blk_addr = (int)(ofs >> mtd_erase_shift);
- if (aml_chip->block_status != NULL) {
- if (aml_chip->block_status[blk_addr] == NAND_BLOCK_BAD) {
- return 0;
- }
- else if (aml_chip->block_status[blk_addr] == NAND_BLOCK_GOOD) {
- aml_chip->block_status[blk_addr] = NAND_BLOCK_BAD;
- for (j=0; j<MAX_BAD_BLK_NUM; j++) {
- if (aml_chip->aml_nandenv_info->nand_bbt_info.nand_bbt[j] == 0) {
- aml_chip->aml_nandenv_info->nand_bbt_info.nand_bbt[j] = blk_addr;
- if (aml_nand_update_env(mtd))
- printk("update env bbt failed %d \n", blk_addr);
- break;
- }
- }
- }
- }
- aml_oob_ops.mode = MTD_OOB_AUTO;
- aml_oob_ops.len = mtd->writesize;
- aml_oob_ops.ooblen = mtd->oobavail;
- aml_oob_ops.ooboffs = chip->ecc.layout->oobfree[0].offset;
- aml_oob_ops.datbuf = chip->buffers->databuf;
- aml_oob_ops.oobbuf = chip->oob_poi;
- chip->pagebuf = -1;
- memset((unsigned char *)aml_oob_ops.datbuf, 0x0, mtd->writesize);
- memset((unsigned char *)aml_oob_ops.oobbuf, 0x0, aml_oob_ops.ooblen);
- return mtd->write_oob(mtd, ofs, &aml_oob_ops);
- }
- #ifdef CONFIG_HAS_EARLYSUSPEND
- static void aml_platform_nand_suspend(struct early_suspend *nand_early_suspend)
- {
- struct aml_nand_chip *aml_chip = (struct aml_nand_chip *)nand_early_suspend->param;
- struct nand_chip *chip = &aml_chip->chip;
- spinlock_t *lock = &chip->controller->lock;
- if (nand_erarly_suspend_flag == 1)
- return;
- spin_lock(lock);
- nand_erarly_suspend_flag = 1;
- spin_unlock(lock);
- printk("aml_m1_nand_early suspend entered\n");
- return;
- }
- static void aml_platform_nand_resume(struct early_suspend *nand_early_suspend)
- {
- struct aml_nand_chip *aml_chip = (struct aml_nand_chip *)nand_early_suspend->param;
- if (((READ_CBUS_REG(HHI_MPEG_CLK_CNTL)&(1<<8))) && (nand_erarly_suspend_flag == 2)) {
- aml_chip->aml_nand_adjust_timing(aml_chip);
- nand_erarly_suspend_flag = 0;
- }
- printk("aml_m1_nand_early resume entered\n");
- return;
- }
- #endif
- static int aml_nand_suspend(struct mtd_info *mtd)
- {
- printk("aml_nand suspend entered\n");
- return 0;
- }
- static void aml_nand_resume(struct mtd_info *mtd)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- if (((READ_CBUS_REG(HHI_MPEG_CLK_CNTL)&(1<<8))) && (nand_erarly_suspend_flag == 2)) {
- aml_chip->aml_nand_adjust_timing(aml_chip);
- nand_erarly_suspend_flag = 0;
- }
- printk("aml_m1_nand resume entered\n");
- return;
- }
- static struct aml_nand_flash_dev *aml_nand_get_flash_type(struct mtd_info *mtd,
- struct nand_chip *chip,
- int busw, int *maf_id)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct aml_nand_platform *plat = aml_chip->platform;
- struct aml_nand_flash_dev *type = NULL;
- int i, maf_idx;
- u8 dev_id[MAX_ID_LEN];
- #ifdef NEW_NAND_SUPPORT
- u8 dev_id_hynix_26nm_8g[MAX_ID_LEN] = {NAND_MFR_HYNIX, 0xde, 0x94, 0xd2, 0x04, 0x43};
- u8 dev_id_hynix_26nm_4g[MAX_ID_LEN] = {NAND_MFR_HYNIX, 0xd7, 0x94, 0xda, 0x74, 0xc3};
- u8 dev_id_toshiba_24nm_4g[MAX_ID_LEN] = {NAND_MFR_TOSHIBA, 0xD7, 0x94, 0x32, 0x76, 0x56};
- u8 dev_id_toshiba_24nm_8g[MAX_ID_LEN] = {NAND_MFR_TOSHIBA, 0xDE, 0x94, 0x82, 0x76, 0x56};
- #endif
- //int tmp_id, tmp_manf;
- /* Send the command for reading device ID */
- chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
- /* Read manufacturer and device IDs */
- for (i=0; i<MAX_ID_LEN; i++) {
- dev_id[i] = chip->read_byte(mtd);
- }
- *maf_id = dev_id[0];
- printk("NAND device id: %x %x %x %x %x %x \n", dev_id[0], dev_id[1], dev_id[2], dev_id[3], dev_id[4], dev_id[5]);
- /* Lookup the flash id */
- for (i = 0; aml_nand_flash_ids[i].name != NULL; i++) {
- if(!strncmp((char*)aml_nand_flash_ids[i].id, (char*)dev_id, strlen((const char*)aml_nand_flash_ids[i].id))){
- type = &aml_nand_flash_ids[i];
- break;
- }
- }
- if (!type) {
- if (plat->nand_flash_dev) {
- if(!strncmp((char*)plat->nand_flash_dev->id, (char*)dev_id, strlen((const char*)plat->nand_flash_dev->id))){
- type = plat->nand_flash_dev;
- }
- }
- if (!type)
- return ERR_PTR(-ENODEV);
- }
- #ifdef NEW_NAND_SUPPORT
- memset(&aml_chip->new_nand_info, 0, sizeof(struct new_tech_nand_t));
- if(!strncmp((char*)type->id, (char*)dev_id_hynix_26nm_8g, strlen((const char*)aml_nand_flash_ids[i].id))){
- aml_chip->new_nand_info.type = 1;
- printk("aml_chip->hynix_new_nand_type =: %d \n", aml_chip->new_nand_info.type);
- //read retry
- aml_chip->new_nand_info.read_rety_info.reg_cnt = 4;
- aml_chip->new_nand_info.read_rety_info.retry_cnt = 6;
- aml_chip->new_nand_info.read_rety_info.reg_addr[0] = 0xAC;
- aml_chip->new_nand_info.read_rety_info.reg_addr[1] = 0xAD;
- aml_chip->new_nand_info.read_rety_info.reg_addr[2] = 0xAE;
- aml_chip->new_nand_info.read_rety_info.reg_addr[3] = 0xAF;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][0] = 0;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][1] = 0x06;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][2] = 0x0A;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][3] = 0x06;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][1] = -0x03;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][2] = -0x07;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][3] = -0x08;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][1] = -0x06;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][2] = -0x0D;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][3] = -0x0F;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][1] = -0x0B;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][2] = -0x14;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][3] = -0x17;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][1] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][2] = -0x1A;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][3] = -0x1E;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][1] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][2] = -0x20;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][3] = -0x25;
- aml_chip->new_nand_info.slc_program_info.reg_cnt = 5;
- aml_chip->new_nand_info.slc_program_info.reg_addr[0] = 0xA4; //not same
- aml_chip->new_nand_info.slc_program_info.reg_addr[1] = 0xA5;
- aml_chip->new_nand_info.slc_program_info.reg_addr[2] = 0xB0;
- aml_chip->new_nand_info.slc_program_info.reg_addr[3] = 0xB1;
- aml_chip->new_nand_info.slc_program_info.reg_addr[4] = 0xC9;
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[0] = 0x25; //not same
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[1] = 0x25;
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[2] = 0x25;
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[3] = 0x25;
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[4] = 0x01;
- aml_chip->new_nand_info.read_rety_info.get_default_value = aml_nand_get_read_default_value_hynix;
- aml_chip->new_nand_info.read_rety_info.read_retry_handle = aml_nand_read_retry_handle_hynix;
- aml_chip->new_nand_info.read_rety_info.set_default_value= aml_nand_set_readretry_default_value_hynix;
-
- aml_chip->new_nand_info.slc_program_info.enter_enslc_mode = aml_nand_enter_enslc_mode_hynix;
- aml_chip->new_nand_info.slc_program_info.exit_enslc_mode = aml_nand_exit_enslc_mode_hynix;
- aml_chip->new_nand_info.slc_program_info.get_default_value = aml_nand_get_slc_default_value_hynix;
-
- }
- else if(!strncmp((char*)type->id, (char*)dev_id_hynix_26nm_4g, strlen((const char*)aml_nand_flash_ids[i].id))){
- aml_chip->new_nand_info.type = 2;
- printk("aml_chip->hynix_new_nand_type =: %d \n", aml_chip->new_nand_info.type);
- //read retry
- aml_chip->new_nand_info.read_rety_info.reg_cnt = 4;
- aml_chip->new_nand_info.read_rety_info.retry_cnt = 6;
- aml_chip->new_nand_info.read_rety_info.reg_addr[0] = 0xA7; //not same
- aml_chip->new_nand_info.read_rety_info.reg_addr[1] = 0xAD;
- aml_chip->new_nand_info.read_rety_info.reg_addr[2] = 0xAE;
- aml_chip->new_nand_info.read_rety_info.reg_addr[3] = 0xAF;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][0] = 0;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][1] = 0x06;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][2] = 0x0A;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][3] = 0x06;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][1] = -0x03;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][2] = -0x07;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][3] = -0x08;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][1] = -0x06;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][2] = -0x0D;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][3] = -0x0F;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][1] = -0x09; //not same
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][2] = -0x14;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][3] = -0x17;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][1] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][2] = -0x1A;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][3] = -0x1E;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][0] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][1] = READ_RETRY_ZERO;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][2] = -0x20;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][3] = -0x25;
- aml_chip->new_nand_info.slc_program_info.reg_cnt = 5;
- aml_chip->new_nand_info.slc_program_info.reg_addr[0] = 0xA0; //not same
- aml_chip->new_nand_info.slc_program_info.reg_addr[1] = 0xA1;
- aml_chip->new_nand_info.slc_program_info.reg_addr[2] = 0xB0;
- aml_chip->new_nand_info.slc_program_info.reg_addr[3] = 0xB1;
- aml_chip->new_nand_info.slc_program_info.reg_addr[4] = 0xC9;
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[0] = 0x26; //not same
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[1] = 0x26;
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[2] = 0x26;
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[3] = 0x26;
- aml_chip->new_nand_info.slc_program_info.reg_offset_value[4] = 0x01;
- aml_chip->new_nand_info.read_rety_info.get_default_value = aml_nand_get_read_default_value_hynix;
- aml_chip->new_nand_info.read_rety_info.read_retry_handle = aml_nand_read_retry_handle_hynix;
- aml_chip->new_nand_info.read_rety_info.set_default_value= aml_nand_set_readretry_default_value_hynix;
-
- aml_chip->new_nand_info.slc_program_info.enter_enslc_mode = aml_nand_enter_enslc_mode_hynix;
- aml_chip->new_nand_info.slc_program_info.exit_enslc_mode = aml_nand_exit_enslc_mode_hynix;
- aml_chip->new_nand_info.slc_program_info.get_default_value = aml_nand_get_slc_default_value_hynix;
-
- }
- else if((!strncmp((char*)type->id, (char*)dev_id_toshiba_24nm_4g, strlen((const char*)aml_nand_flash_ids[i].id)))
- ||(!strncmp((char*)type->id, (char*)dev_id_toshiba_24nm_8g, strlen((const char*)aml_nand_flash_ids[i].id)))){
- aml_chip->new_nand_info.type = TOSHIBA_24NM;
- aml_chip->new_nand_info.read_rety_info.reg_addr[0] = 0x04;
- aml_chip->new_nand_info.read_rety_info.reg_addr[1] = 0x05;
- aml_chip->new_nand_info.read_rety_info.reg_addr[2] = 0x06;
- aml_chip->new_nand_info.read_rety_info.reg_addr[3] = 0x07;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][0] = 0;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][1] = 0;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][2] = 0;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[0][3] = 0;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][0] = 0x04;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][1] = 0x04;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][2] = 0x04;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[1][3] = 0x04;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][0] = 0x7c;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][1] = 0x7c;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][2] = 0x7c;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[2][3] = 0x7c;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][0] = 0x78;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][1] = 0x78;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][2] = 0x78;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[3][3] = 0x78;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][0] = 0x74;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][1] = 0x74;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][2] = 0x74;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[4][3] = 0x74;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][0] = 0x08;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][1] = 0x08;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][2] = 0x08;
- aml_chip->new_nand_info.read_rety_info.reg_offset_value[5][3] = 0x08;
- aml_chip->new_nand_info.read_rety_info.reg_cnt = 4;
- aml_chip->new_nand_info.read_rety_info.retry_cnt = 6;
-
- aml_chip->new_nand_info.read_rety_info.read_retry_handle = aml_nand_read_retry_handle_toshiba;
- aml_chip->new_nand_info.read_rety_info.read_retry_exit = aml_nand_read_retry_exit_toshiba;
-
- }
- #endif
- if (!mtd->name)
- mtd->name = type->name;
- chip->chipsize = type->chipsize;
- chip->chipsize = chip->chipsize << 20;
- /* Newer devices have all the information in additional id bytes */
- if (!type->pagesize) {
- int extid;
- /* The 3rd id byte holds MLC / multichip data */
- chip->cellinfo = chip->read_byte(mtd);
- /* The 4th id byte is the important one */
- extid = chip->read_byte(mtd);
- /* Calc pagesize */
- mtd->writesize = 1024 << (extid & 0x3);
- extid >>= 2;
- /* Calc oobsize */
- mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
- extid >>= 2;
- /* Calc blocksize. Blocksize is multiples of 64KiB */
- mtd->erasesize = (64 * 1024) << (extid & 0x03);
- extid >>= 2;
- /* Get buswidth information */
- busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
- } else {
- /*
- * Old devices have chip data hardcoded in the device id table
- */
- mtd->erasesize = type->erasesize;
- mtd->writesize = type->pagesize;
- mtd->oobsize = type->oobsize;
- busw = type->options & NAND_BUSW_OPTIONS_MASK;
- }
- /* Try to identify manufacturer */
- for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
- if (nand_manuf_ids[maf_idx].id == *maf_id)
- break;
- }
- /*
- * Check, if buswidth is correct. Hardware drivers should set
- * chip correct !
- */
- if (busw != (chip->options & NAND_BUSWIDTH_16)) {
- printk(KERN_INFO "NAND device: Manufacturer ID:"
- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
- dev_id[0], nand_manuf_ids[maf_idx].name, mtd->name);
- printk(KERN_WARNING "NAND bus width %d instead %d bit\n",
- (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
- busw ? 16 : 8);
- return ERR_PTR(-EINVAL);
- }
- /* Calculate the address shift from the page size */
- chip->page_shift = ffs(mtd->writesize) - 1;
- /* Convert chipsize to number of pages per chip -1. */
- chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
- chip->bbt_erase_shift = chip->phys_erase_shift = ffs(mtd->erasesize) - 1;
- chip->chip_shift = ffs(chip->chipsize) - 1;
- /* Set the bad block position */
- chip->badblockpos = AML_BADBLK_POS;
- /* Get chip options, preserve non chip based options */
- //chip->options &= ~NAND_CHIPOPTIONS_MSK;
- //chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
- /*
- * Set chip as a default. Board drivers can override it, if necessary
- */
- chip->options |= NAND_NO_AUTOINCR;
- /* Check if chip is a not a samsung device. Do not clear the
- * options for chips which are not having an extended id.
- */
- //if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
- //chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
- printk(KERN_INFO "NAND device: Manufacturer ID:"
- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id[0],
- nand_manuf_ids[maf_idx].name, type->name);
- return type;
- }
- static int aml_nand_scan_ident(struct mtd_info *mtd, int maxchips)
- {
- int i, busw, nand_maf_id, valid_chip_num = 1;
- struct nand_chip *chip = mtd->priv;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct aml_nand_flash_dev *aml_type;
- u8 dev_id[MAX_ID_LEN], onfi_features[4];
- unsigned temp_chip_shift;
- /* Get buswidth to select the correct functions */
- busw = chip->options & NAND_BUSWIDTH_16;
- /* Select the device */
- chip->select_chip(mtd, 0);
- //reset chip for some nand need reset after power up
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
- aml_chip->aml_nand_wait_devready(aml_chip, 0);
- /* Read the flash type */
- aml_type = aml_nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
- if (IS_ERR(aml_type)) {
- printk(KERN_WARNING "No NAND device found!!!\n");
- chip->select_chip(mtd, -1);
- return PTR_ERR(aml_type);
- }
- chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
- for (i=0; i<MAX_ID_LEN; i++) {
- dev_id[i] = chip->read_byte(mtd);
- }
- if(!memcmp((char*)dev_id, "ONFI", 4))
- aml_chip->onfi_mode = aml_type->onfi_mode;
- aml_chip->T_REA = aml_type->T_REA;
- aml_chip->T_RHOH = aml_type->T_RHOH;
- aml_chip->mfr_type = aml_type->id[0];
- /* Check for a chip array */
- for (i = 1; i < maxchips; i++) {
- aml_chip->aml_nand_select_chip(aml_chip, i);
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
- aml_chip->aml_nand_wait_devready(aml_chip, i);
- /* Send the command for reading device ID */
- chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
- /* Read manufacturer and device IDs */
- if (nand_maf_id != chip->read_byte(mtd) || aml_type->id[1] != chip->read_byte(mtd))
- //if (nand_maf_id != dev_id[0] || aml_type->id[1] != dev_id[1])
- aml_chip->valid_chip[i] = 0;
- else
- valid_chip_num ++;
- }
- if (i > 1) {
- printk(KERN_INFO "%d NAND chips detected\n", valid_chip_num);
- /*if ((aml_chip->valid_chip[1] == 0) && (aml_chip->valid_chip[2] == 1)) {
- printk("ce1 and ce2 connected\n");
- aml_chip->chip_enable[2] = (aml_chip->chip_enable[1] & aml_chip->chip_enable[2]);
- }*/
- }
- if (aml_chip->onfi_mode) {
- aml_nand_set_onfi_features(aml_chip, (uint8_t *)(&aml_chip->onfi_mode), ONFI_TIMING_ADDR);
- aml_nand_get_onfi_features(aml_chip, onfi_features, ONFI_TIMING_ADDR);
- if (onfi_features[0] != aml_chip->onfi_mode) {
- aml_chip->T_REA = DEFAULT_T_REA;
- aml_chip->T_RHOH = DEFAULT_T_RHOH;
- printk("onfi timing mode set failed: %x\n", onfi_features[0]);
- }
- }
- /* Store the number of chips and calc total size for mtd */
- chip->numchips = 1;
- if ((chip->chipsize >> 32) & 0xffffffff)
- chip->chip_shift = fls((unsigned)(chip->chipsize >> 32))-1 + fls(valid_chip_num)-1 + 32;
- else
- chip->chip_shift = fls((unsigned)chip->chipsize)-1 + fls(valid_chip_num)-1;
- chip->pagemask = ((chip->chipsize * valid_chip_num) >> chip->page_shift) - 1;
- chip->options &= ~NAND_CACHEPRG;
- aml_chip->internal_chipnr = aml_type->internal_chipnr;
- aml_chip->internal_page_nums = (chip->chipsize >> chip->page_shift);
- aml_chip->internal_page_nums /= aml_chip->internal_chipnr;
- aml_chip->internal_chip_shift = fls((unsigned)aml_chip->internal_page_nums) - 1;
- temp_chip_shift = ffs((unsigned)aml_chip->internal_page_nums) - 1;
- if (aml_chip->internal_chip_shift != temp_chip_shift) {
- aml_chip->internal_chip_shift += 1;
- chip->chip_shift += 1;
- chip->pagemask = ((1 << (chip->chip_shift + 1)) >> chip->page_shift) - 1;
- }
- aml_chip->options = aml_type->options;
- aml_chip->page_size = aml_type->pagesize;
- aml_chip->block_size = aml_type->erasesize;
- aml_chip->oob_size = aml_type->oobsize;
- mtd->erasesize = valid_chip_num * aml_type->erasesize;
- mtd->writesize = valid_chip_num * aml_type->pagesize;
- mtd->oobsize = valid_chip_num * aml_type->oobsize;
- mtd->size = valid_chip_num * chip->chipsize;
- chip->cmdfunc = aml_nand_command;
- chip->waitfunc = aml_nand_wait;
- chip->erase_cmd = aml_nand_erase_cmd;
- chip->write_page = aml_nand_write_page;
- return 0;
- }
- int aml_nand_scan(struct mtd_info *mtd, int maxchips)
- {
- int ret;
- ret = aml_nand_scan_ident(mtd, maxchips);
- if (!ret)
- ret = nand_scan_tail(mtd);
- return ret;
- }
- static int aml_platform_options_confirm(struct aml_nand_chip *aml_chip)
- {
- struct mtd_info *mtd = &aml_chip->mtd;
- struct nand_chip *chip = &aml_chip->chip;
- struct aml_nand_platform *plat = aml_chip->platform;
- unsigned options_selected = 0, options_support = 0, ecc_bytes, options_define;
- int error = 0;
- options_selected = (plat->platform_nand_data.chip.options & NAND_ECC_OPTIONS_MASK);
- options_define = (aml_chip->options & NAND_ECC_OPTIONS_MASK);
- ecc_unit_change:
- ecc_bytes = aml_chip->oob_size / (aml_chip->page_size / chip->ecc.size);
- if (chip->ecc.size == NAND_ECC_UNIT_1KSIZE) {
- if (ecc_bytes >= (NAND_BCH24_1K_ECC_SIZE + 2))
- options_support = NAND_ECC_BCH24_1K_MODE;
- else {
- aml_nand_debug("oob size is not enough for 1K UNIT ECC mode: %d try 512 UNIT ECC\n", aml_chip->oob_size);
- chip->ecc.size = NAND_ECC_UNIT_SIZE;
- goto ecc_unit_change;
- }
- }
- else {
- if (ecc_bytes >= (NAND_BCH16_ECC_SIZE + 2))
- options_support = NAND_ECC_BCH16_MODE;
- else if (ecc_bytes >= (NAND_BCH12_ECC_SIZE + 2))
- options_support = NAND_ECC_BCH12_MODE;
- else if (ecc_bytes >= (NAND_BCH8_ECC_SIZE + 2))
- options_support = NAND_ECC_BCH8_MODE;
- else {
- options_support = NAND_ECC_SOFT_MODE;
- aml_nand_debug("page size: %d oob size %d is not enough for HW ECC\n", aml_chip->page_size, aml_chip->oob_size);
- }
- }
- if (options_define != options_support) {
- options_define = options_support;
- aml_nand_debug("define oob size: %d could support bch mode: %s\n", aml_chip->oob_size, aml_nand_bch_string[options_support]);
- }
- if ((options_selected > options_define) && (strncmp((char*)plat->name, NAND_BOOT_NAME, strlen((const char*)NAND_BOOT_NAME)))) {
- aml_nand_debug("oob size is not enough for selected bch mode: %s force bch to mode: %s\n", aml_nand_bch_string[options_selected], aml_nand_bch_string[options_define]);
- options_selected = options_define;
- }
- switch (options_selected) {
- case NAND_ECC_BCH9_MODE:
- chip->ecc.size = NAND_ECC_UNIT_SIZE; //our hardware ecc unit is 512bytes
- chip->ecc.bytes = NAND_BCH9_ECC_SIZE;
- aml_chip->bch_mode = NAND_ECC_BCH9;
- aml_chip->user_byte_mode = 1;
- break;
- case NAND_ECC_BCH8_MODE:
- chip->ecc.size = NAND_ECC_UNIT_SIZE;
- chip->ecc.bytes = NAND_BCH8_ECC_SIZE;
- aml_chip->bch_mode = NAND_ECC_BCH8;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH12_MODE:
- chip->ecc.size = NAND_ECC_UNIT_SIZE;
- chip->ecc.bytes = NAND_BCH12_ECC_SIZE;
- aml_chip->bch_mode = NAND_ECC_BCH12;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH16_MODE:
- chip->ecc.size = NAND_ECC_UNIT_SIZE;
- chip->ecc.bytes = NAND_BCH16_ECC_SIZE;
- aml_chip->bch_mode = NAND_ECC_BCH16;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH24_1K_MODE:
- chip->ecc.size = NAND_ECC_UNIT_1KSIZE;
- chip->ecc.bytes = NAND_BCH24_1K_ECC_SIZE;
- aml_chip->bch_mode = NAND_ECC_BCH24_1K;
- aml_chip->user_byte_mode = 2;
- break;
- default :
- if ((plat->platform_nand_data.chip.options & NAND_ECC_OPTIONS_MASK) != NAND_ECC_SOFT_MODE) {
- aml_nand_debug("soft ecc or none ecc just support in linux self nand base please selected it at platform options\n");
- error = -ENXIO;
- }
- break;
- }
- options_selected = (plat->platform_nand_data.chip.options & NAND_PLANE_OPTIONS_MASK);
- options_define = (aml_chip->options & NAND_PLANE_OPTIONS_MASK);
- if (options_selected > options_define) {
- aml_nand_debug("multi plane error for selected plane mode: %s force plane to : %s\n", aml_nand_plane_string[options_selected >> 4], aml_nand_plane_string[options_define >> 4]);
- options_selected = options_define;
- }
- switch (options_selected) {
- case NAND_TWO_PLANE_MODE:
- aml_chip->plane_num = 2;
- mtd->erasesize *= 2;
- mtd->writesize *= 2;
- mtd->oobsize *= 2;
- break;
- default:
- aml_chip->plane_num = 1;
- break;
- }
- options_selected = (plat->platform_nand_data.chip.options & NAND_INTERLEAVING_OPTIONS_MASK);
- options_define = (aml_chip->options & NAND_INTERLEAVING_OPTIONS_MASK);
- if (options_selected > options_define) {
- aml_nand_debug("internal mode error for selected internal mode: %s force internal mode to : %s\n", aml_nand_internal_string[options_selected >> 16], aml_nand_internal_string[options_define >> 16]);
- options_selected = options_define;
- }
- switch (options_selected) {
- case NAND_INTERLEAVING_MODE:
- aml_chip->ops_mode |= AML_INTERLEAVING_MODE;
- mtd->erasesize *= aml_chip->internal_chipnr;
- mtd->writesize *= aml_chip->internal_chipnr;
- mtd->oobsize *= aml_chip->internal_chipnr;
- break;
- default:
- break;
- }
- return error;
- }
- static uint8_t aml_platform_read_byte(struct mtd_info *mtd)
- {
- struct nand_chip *chip = mtd->priv;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- NFC_SEND_CMD(aml_chip->chip_selected | DRD | 0);
- NFC_SEND_CMD(aml_chip->chip_selected | IDLE | 5);
- while(NFC_CMDFIFO_SIZE()>0);
- return readb(chip->IO_ADDR_R);
- }
- static void aml_platform_write_byte(struct aml_nand_chip *aml_chip, uint8_t data)
- {
- NFC_SEND_CMD(aml_chip->chip_selected | IDLE | 5);
- NFC_SEND_CMD(aml_chip->chip_selected | DWR | data);
- NFC_SEND_CMD(aml_chip->chip_selected | IDLE | 5);
- while(NFC_CMDFIFO_SIZE()>0);
- return;
- }
- static int aml_nand_read_env (struct mtd_info *mtd, size_t offset, u_char * buf)
- {
- struct env_oobinfo_t *env_oobinfo;
- int error = 0, start_blk, total_blk;
- size_t addr = 0;
- size_t amount_loaded = 0;
- size_t len;
- struct mtd_oob_ops aml_oob_ops;
- unsigned char *data_buf;
- unsigned char env_oob_buf[sizeof(struct env_oobinfo_t)];
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- if (!aml_chip->aml_nandenv_info->env_valid)
- return 1;
- addr = (1024 * mtd->writesize / aml_chip->plane_num);
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->new_nand_info.type) && (aml_chip->new_nand_info.type < 10))
- addr += RETRY_NAND_BLK_NUM* mtd->erasesize;
- #endif
- start_blk = addr / mtd->erasesize;
- total_blk = mtd->size / mtd->erasesize;
- addr = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
- addr *= mtd->erasesize;
- addr += aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr * mtd->writesize;
- data_buf = kzalloc(mtd->writesize, GFP_KERNEL);
- if (data_buf == NULL)
- return -ENOMEM;
- env_oobinfo = (struct env_oobinfo_t *)env_oob_buf;
- while (amount_loaded < CONFIG_ENV_SIZE ) {
- aml_oob_ops.mode = MTD_OOB_AUTO;
- aml_oob_ops.len = mtd->writesize;
- aml_oob_ops.ooblen = sizeof(struct env_oobinfo_t);
- aml_oob_ops.ooboffs = mtd->ecclayout->oobfree[0].offset;
- aml_oob_ops.datbuf = data_buf;
- aml_oob_ops.oobbuf = env_oob_buf;
- memset((unsigned char *)aml_oob_ops.datbuf, 0x0, mtd->writesize);
- memset((unsigned char *)aml_oob_ops.oobbuf, 0x0, aml_oob_ops.ooblen);
- error = mtd->read_oob(mtd, addr, &aml_oob_ops);
- if ((error != 0) && (error != -EUCLEAN)) {
- printk("blk check good but read failed: %llx, %d\n", (uint64_t)addr, error);
- return 1;
- }
- if (memcmp(env_oobinfo->name, ENV_NAND_MAGIC, 4))
- printk("invalid nand env magic: %llx\n", (uint64_t)addr);
- addr += mtd->writesize;
- len = min(mtd->writesize, CONFIG_ENV_SIZE - amount_loaded);
- memcpy(buf + amount_loaded, data_buf, len);
- amount_loaded += mtd->writesize;
- }
- if (amount_loaded < CONFIG_ENV_SIZE)
- return 1;
- kfree(data_buf);
- return 0;
- }
- static int aml_nand_write_env(struct mtd_info *mtd, loff_t offset, u_char *buf)
- {
- struct env_oobinfo_t *env_oobinfo;
- int error = 0;
- loff_t addr = 0;
- size_t amount_saved = 0;
- size_t len;
- struct mtd_oob_ops aml_oob_ops;
- unsigned char *data_buf;
- unsigned char env_oob_buf[sizeof(struct env_oobinfo_t)];
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- data_buf = kzalloc(mtd->writesize, GFP_KERNEL);
- if (data_buf == NULL)
- return -ENOMEM;
- addr = offset;
- env_oobinfo = (struct env_oobinfo_t *)env_oob_buf;
- memcpy(env_oobinfo->name, ENV_NAND_MAGIC, 4);
- env_oobinfo->ec = aml_chip->aml_nandenv_info->env_valid_node->ec;
- env_oobinfo->timestamp = aml_chip->aml_nandenv_info->env_valid_node->timestamp;
- env_oobinfo->status_page = 1;
- while (amount_saved < CONFIG_ENV_SIZE ) {
- aml_oob_ops.mode = MTD_OOB_AUTO;
- aml_oob_ops.len = mtd->writesize;
- aml_oob_ops.ooblen = sizeof(struct env_oobinfo_t);
- aml_oob_ops.ooboffs = mtd->ecclayout->oobfree[0].offset;
- aml_oob_ops.datbuf = data_buf;
- aml_oob_ops.oobbuf = env_oob_buf;
- memset((unsigned char *)aml_oob_ops.datbuf, 0x0, mtd->writesize);
- len = min(mtd->writesize, CONFIG_ENV_SIZE - amount_saved);
- memcpy((unsigned char *)aml_oob_ops.datbuf, buf + amount_saved, len);
- error = mtd->write_oob(mtd, addr, &aml_oob_ops);
- if (error) {
- printk("blk check good but write failed: %llx, %d\n", (uint64_t)addr, error);
- return 1;
- }
- addr += mtd->writesize;;
- amount_saved += mtd->writesize;
- }
- if (amount_saved < CONFIG_ENV_SIZE)
- return 1;
- kfree(data_buf);
- return 0;
- }
- static int aml_nand_save_env(struct mtd_info *mtd, u_char *buf)
- {
- struct aml_nand_bbt_info *nand_bbt_info;
- struct env_free_node_t *env_free_node, *env_tmp_node;
- int error = 0, pages_per_blk, i = 1;
- loff_t addr = 0;
- struct erase_info aml_env_erase_info;
- env_t *env_ptr = (env_t *)buf;
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- if (!aml_chip->aml_nandenv_info->env_init)
- return 1;
- pages_per_blk = mtd->erasesize / mtd->writesize;
- if ((mtd->writesize < CONFIG_ENV_SIZE) && (aml_chip->aml_nandenv_info->env_valid == 1))
- i = (CONFIG_ENV_SIZE + mtd->writesize - 1) / mtd->writesize;
- if (aml_chip->aml_nandenv_info->env_valid) {
- aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr += i;
- if ((aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr + i) > pages_per_blk) {
- env_free_node = kzalloc(sizeof(struct env_free_node_t), GFP_KERNEL);
- if (env_free_node == NULL)
- return -ENOMEM;
- env_free_node->phy_blk_addr = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
- env_free_node->ec = aml_chip->aml_nandenv_info->env_valid_node->ec;
- env_tmp_node = aml_chip->aml_nandenv_info->env_free_node;
- while (env_tmp_node->next != NULL) {
- env_tmp_node = env_tmp_node->next;
- }
- env_tmp_node->next = env_free_node;
- env_tmp_node = aml_chip->aml_nandenv_info->env_free_node;
- aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr = env_tmp_node->phy_blk_addr;
- aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr = 0;
- aml_chip->aml_nandenv_info->env_valid_node->ec = env_tmp_node->ec;
- aml_chip->aml_nandenv_info->env_valid_node->timestamp += 1;
- aml_chip->aml_nandenv_info->env_free_node = env_tmp_node->next;
- kfree(env_tmp_node);
- }
- }
- else {
- env_tmp_node = aml_chip->aml_nandenv_info->env_free_node;
- aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr = env_tmp_node->phy_blk_addr;
- aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr = 0;
- aml_chip->aml_nandenv_info->env_valid_node->ec = env_tmp_node->ec;
- aml_chip->aml_nandenv_info->env_valid_node->timestamp += 1;
- aml_chip->aml_nandenv_info->env_free_node = env_tmp_node->next;
- kfree(env_tmp_node);
- }
- addr = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
- addr *= mtd->erasesize;
- addr += aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr * mtd->writesize;
- if (aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr == 0) {
- memset(&aml_env_erase_info, 0, sizeof(struct erase_info));
- aml_env_erase_info.mtd = mtd;
- aml_env_erase_info.addr = addr;
- aml_env_erase_info.len = mtd->erasesize;
- error = mtd->erase(mtd, &aml_env_erase_info);
- if (error) {
- printk("env free blk erase failed %d\n", error);
- mtd->block_markbad(mtd, addr);
- return error;
- }
- aml_chip->aml_nandenv_info->env_valid_node->ec++;
- }
- nand_bbt_info = &aml_chip->aml_nandenv_info->nand_bbt_info;
- if ((!memcmp(nand_bbt_info->bbt_head_magic, BBT_HEAD_MAGIC, 4)) && (!memcmp(nand_bbt_info->bbt_tail_magic, BBT_TAIL_MAGIC, 4))) {
- memcpy(env_ptr->data + default_environment_size, aml_chip->aml_nandenv_info->nand_bbt_info.bbt_head_magic, sizeof(struct aml_nand_bbt_info));
- env_ptr->crc = (crc32((0 ^ 0xffffffffL), env_ptr->data, ENV_SIZE) ^ 0xffffffffL);
- }
- if (aml_nand_write_env(mtd, addr, (u_char *) env_ptr)) {
- printk("update nand env FAILED!\n");
- return 1;
- }
-
- return error;
- }
- static int aml_nand_env_init(struct mtd_info *mtd)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct nand_chip *chip = &aml_chip->chip;
- struct env_oobinfo_t *env_oobinfo;
- struct env_free_node_t *env_free_node, *env_tmp_node, *env_prev_node;
- int error = 0, start_blk, total_blk, env_blk, i, pages_per_blk, bad_blk_cnt = 0, max_env_blk, phys_erase_shift;
- loff_t offset;
- unsigned char *data_buf;
- struct mtd_oob_ops aml_oob_ops;
- unsigned char env_oob_buf[sizeof(struct env_oobinfo_t)];
- data_buf = kzalloc(mtd->writesize, GFP_KERNEL);
- if (data_buf == NULL)
- return -ENOMEM;
- aml_chip->aml_nandenv_info = kzalloc(sizeof(struct aml_nandenv_info_t), GFP_KERNEL);
- if (aml_chip->aml_nandenv_info == NULL)
- return -ENOMEM;
- aml_chip->aml_nandenv_info->mtd = mtd;
- aml_chip->aml_nandenv_info->env_valid_node = kzalloc(sizeof(struct env_valid_node_t), GFP_KERNEL);
- if (aml_chip->aml_nandenv_info->env_valid_node == NULL)
- return -ENOMEM;
- aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr = -1;
- phys_erase_shift = fls(mtd->erasesize) - 1;
- max_env_blk = (NAND_MINI_PART_SIZE >> phys_erase_shift);
- if (max_env_blk < 2)
- max_env_blk = 2;
- if (nand_boot_flag)
- offset = (1024 * mtd->writesize / aml_chip->plane_num);
- else {
- default_environment_size = 0;
- offset = 0;
- }
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->new_nand_info.type) && (aml_chip->new_nand_info.type < 10))
- offset += RETRY_NAND_BLK_NUM* mtd->erasesize;
- #endif
- start_blk = (int)(offset >> phys_erase_shift);
- total_blk = (int)(mtd->size >> phys_erase_shift);
- pages_per_blk = (1 << (chip->phys_erase_shift - chip->page_shift));
- env_oobinfo = (struct env_oobinfo_t *)env_oob_buf;
- if ((default_environment_size + sizeof(struct aml_nand_bbt_info)) > ENV_SIZE)
- total_blk = start_blk + max_env_blk;
- env_blk = 0;
- do {
- offset = mtd->erasesize;
- offset *= start_blk;
- error = mtd->block_isbad(mtd, offset);
- if (error) {
- aml_chip->aml_nandenv_info->nand_bbt_info.nand_bbt[bad_blk_cnt++] = start_blk;
- continue;
- }
- aml_oob_ops.mode = MTD_OOB_AUTO;
- aml_oob_ops.len = mtd->writesize;
- aml_oob_ops.ooblen = sizeof(struct env_oobinfo_t);
- aml_oob_ops.ooboffs = mtd->ecclayout->oobfree[0].offset;
- aml_oob_ops.datbuf = data_buf;
- aml_oob_ops.oobbuf = env_oob_buf;
- memset((unsigned char *)aml_oob_ops.datbuf, 0x0, mtd->writesize);
- memset((unsigned char *)aml_oob_ops.oobbuf, 0x0, aml_oob_ops.ooblen);
- error = mtd->read_oob(mtd, offset, &aml_oob_ops);
- if ((error != 0) && (error != -EUCLEAN)) {
- printk("blk check good but read failed: %llx, %d\n", (uint64_t)offset, error);
- continue;
- }
- aml_chip->aml_nandenv_info->env_init = 1;
- if (!memcmp(env_oobinfo->name, ENV_NAND_MAGIC, 4)) {
- aml_chip->aml_nandenv_info->env_valid = 1;
- if (aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr >= 0) {
- env_free_node = kzalloc(sizeof(struct env_free_node_t), GFP_KERNEL);
- if (env_free_node == NULL)
- return -ENOMEM;
- env_free_node->dirty_flag = 1;
- if (env_oobinfo->timestamp > aml_chip->aml_nandenv_info->env_valid_node->timestamp) {
- env_free_node->phy_blk_addr = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
- env_free_node->ec = aml_chip->aml_nandenv_info->env_valid_node->ec;
- aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr = start_blk;
- aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr = 0;
- aml_chip->aml_nandenv_info->env_valid_node->ec = env_oobinfo->ec;
- aml_chip->aml_nandenv_info->env_valid_node->timestamp = env_oobinfo->timestamp;
- }
- else {
- env_free_node->phy_blk_addr = start_blk;
- env_free_node->ec = env_oobinfo->ec;
- }
- if (aml_chip->aml_nandenv_info->env_free_node == NULL)
- aml_chip->aml_nandenv_info->env_free_node = env_free_node;
- else {
- env_tmp_node = aml_chip->aml_nandenv_info->env_free_node;
- while (env_tmp_node->next != NULL) {
- env_tmp_node = env_tmp_node->next;
- }
- env_tmp_node->next = env_free_node;
- }
- }
- else {
- aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr = start_blk;
- aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr = 0;
- aml_chip->aml_nandenv_info->env_valid_node->ec = env_oobinfo->ec;
- aml_chip->aml_nandenv_info->env_valid_node->timestamp = env_oobinfo->timestamp;
- }
- }
- else if (env_blk < max_env_blk) {
- env_free_node = kzalloc(sizeof(struct env_free_node_t), GFP_KERNEL);
- if (env_free_node == NULL)
- return -ENOMEM;
- env_free_node->phy_blk_addr = start_blk;
- env_free_node->ec = env_oobinfo->ec;
- if (aml_chip->aml_nandenv_info->env_free_node == NULL)
- aml_chip->aml_nandenv_info->env_free_node = env_free_node;
- else {
- env_tmp_node = aml_chip->aml_nandenv_info->env_free_node;
- env_prev_node = env_tmp_node;
- while (env_tmp_node != NULL) {
- if (env_tmp_node->dirty_flag == 1)
- break;
- env_prev_node = env_tmp_node;
- env_tmp_node = env_tmp_node->next;
- }
- if (env_prev_node == env_tmp_node) {
- env_free_node->next = env_tmp_node;
- aml_chip->aml_nandenv_info->env_free_node = env_free_node;
- }
- else {
- env_prev_node->next = env_free_node;
- env_free_node->next = env_tmp_node;
- }
- }
- }
- env_blk++;
- if ((env_blk >= max_env_blk) && (aml_chip->aml_nandenv_info->env_valid == 1))
- break;
- } while ((++start_blk) < total_blk);
- if (start_blk >= total_blk) {
- memcpy(aml_chip->aml_nandenv_info->nand_bbt_info.bbt_head_magic, BBT_HEAD_MAGIC, 4);
- memcpy(aml_chip->aml_nandenv_info->nand_bbt_info.bbt_tail_magic, BBT_TAIL_MAGIC, 4);
- }
- if (aml_chip->aml_nandenv_info->env_valid == 1) {
- aml_oob_ops.mode = MTD_OOB_AUTO;
- aml_oob_ops.len = mtd->writesize;
- aml_oob_ops.ooblen = sizeof(struct env_oobinfo_t);
- aml_oob_ops.ooboffs = mtd->ecclayout->oobfree[0].offset;
- aml_oob_ops.datbuf = data_buf;
- aml_oob_ops.oobbuf = env_oob_buf;
- for (i=0; i<pages_per_blk; i++) {
- memset((unsigned char *)aml_oob_ops.datbuf, 0x0, mtd->writesize);
- memset((unsigned char *)aml_oob_ops.oobbuf, 0x0, aml_oob_ops.ooblen);
- offset = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
- offset *= mtd->erasesize;
- offset += i * mtd->writesize;
- error = mtd->read_oob(mtd, offset, &aml_oob_ops);
- if ((error != 0) && (error != -EUCLEAN)) {
- printk("blk check good but read failed: %llx, %d\n", (uint64_t)offset, error);
- continue;
- }
- if (!memcmp(env_oobinfo->name, ENV_NAND_MAGIC, 4))
- aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr = i;
- else
- break;
- }
- }
- if ((mtd->writesize < CONFIG_ENV_SIZE) && (aml_chip->aml_nandenv_info->env_valid == 1)) {
- i = (CONFIG_ENV_SIZE + mtd->writesize - 1) / mtd->writesize;
- aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr -= (i - 1);
- }
- offset = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
- offset *= mtd->erasesize;
- offset += aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr * mtd->writesize;
- printk("aml nand env valid addr: %llx \n", (uint64_t)offset);
- printk(KERN_DEBUG "CONFIG_ENV_SIZE=0x%x; ENV_SIZE=0x%x; bbt=0x%x; default_environment_size=0x%x\n",
- CONFIG_ENV_SIZE, ENV_SIZE, sizeof(struct aml_nand_bbt_info), default_environment_size);
- kfree(data_buf);
- return 0;
- }
- static int aml_nand_update_env(struct mtd_info *mtd)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- env_t *env_ptr;
- loff_t offset;
- int error = 0;
- env_ptr = kzalloc(sizeof(env_t), GFP_KERNEL);
- if (env_ptr == NULL)
- return -ENOMEM;
- if (aml_chip->aml_nandenv_info->env_valid == 1) {
- offset = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
- offset *= mtd->erasesize;
- offset += aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr * mtd->writesize;
- error = aml_nand_read_env (mtd, offset, (u_char *)env_ptr);
- if (error) {
- printk("nand env read failed: %llx, %d\n", (uint64_t)offset, error);
- return error;
- }
- error = aml_nand_save_env(mtd, (u_char *)env_ptr);
- if (error) {
- printk("update env bbt failed %d \n", error);
- return error;
- }
- }
- return error;
- }
- static int aml_nand_env_check(struct mtd_info *mtd)
- {
- struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd);
- struct aml_nand_platform *plat = aml_chip->platform;
- struct platform_nand_chip *chip = &plat->platform_nand_data.chip;
- struct aml_nand_bbt_info *nand_bbt_info;
- struct aml_nand_part_info *aml_nand_part;
- struct mtd_partition *parts;
- env_t *env_ptr;
- int error = 0, start_blk, total_blk, update_env_flag = 0, i, j, nr, phys_erase_shift;
- loff_t offset;
- error = aml_nand_env_init(mtd);
- if (error)
- return error;
- env_ptr = kzalloc(sizeof(env_t), GFP_KERNEL);
- if (env_ptr == NULL)
- return -ENOMEM;
- if (aml_chip->aml_nandenv_info->env_valid == 1) {
- offset = aml_chip->aml_nandenv_info->env_valid_node->phy_blk_addr;
- offset *= mtd->erasesize;
- offset += aml_chip->aml_nandenv_info->env_valid_node->phy_page_addr * mtd->writesize;
- error = aml_nand_read_env (mtd, offset, (u_char *)env_ptr);
- if (error) {
- printk("nand env read failed: %llx, %d\n", (uint64_t)offset, error);
- goto exit;
- }
- phys_erase_shift = fls(mtd->erasesize) - 1;
- offset = (1024 * mtd->writesize / aml_chip->plane_num);
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->new_nand_info.type) && (aml_chip->new_nand_info.type < 10))
- offset += RETRY_NAND_BLK_NUM* mtd->erasesize;
- #endif
- start_blk = (int)(offset >> phys_erase_shift);
- total_blk = (int)(mtd->size >> phys_erase_shift);
- nand_bbt_info = (struct aml_nand_bbt_info *)(env_ptr->data + default_environment_size);
- if ((!memcmp(nand_bbt_info->bbt_head_magic, BBT_HEAD_MAGIC, 4)) && (!memcmp(nand_bbt_info->bbt_tail_magic, BBT_TAIL_MAGIC, 4))) {
- for (i=start_blk; i<total_blk; i++) {
- aml_chip->block_status[i] = NAND_BLOCK_GOOD;
- for (j=0; j<MAX_BAD_BLK_NUM; j++) {
- if (nand_bbt_info->nand_bbt[j] == i) {
- aml_chip->block_status[i] = NAND_BLOCK_BAD;
- break;
- }
- }
- }
- if (chip->set_parts)
- chip->set_parts(mtd->size, chip);
- aml_nand_part = nand_bbt_info->aml_nand_part;
- if (plat->platform_nand_data.chip.nr_partitions == 0) {
- parts = kzalloc((MAX_MTD_PART_NUM * sizeof(struct mtd_partition)), GFP_KERNEL);
- if (!parts) {
- error = -ENOMEM;
- goto exit;
- }
- plat->platform_nand_data.chip.partitions = parts;
- nr = 0;
- while(memcmp(aml_nand_part->mtd_part_magic, MTD_PART_MAGIC, 4) == 0) {
- parts->name = kzalloc(MAX_MTD_PART_NAME_LEN, GFP_KERNEL);
- if (!parts->name) {
- error = -ENOMEM;
- goto exit;
- }
- strncpy(parts->name, aml_nand_part->mtd_part_name, MAX_MTD_PART_NAME_LEN);
- parts->offset = aml_nand_part->offset;
- parts->size = aml_nand_part->size;
- parts->mask_flags = aml_nand_part->mask_flags;
- nr++;
- parts++;
- aml_nand_part++;
- }
- plat->platform_nand_data.chip.nr_partitions = nr;
- }
- else {
- parts = plat->platform_nand_data.chip.partitions;
- nr = 0;
- if (strlen(parts->name) >= MAX_MTD_PART_NAME_LEN)
- parts->name[MAX_MTD_PART_NAME_LEN - 1] = '\0';
- while(memcmp(aml_nand_part->mtd_part_magic, MTD_PART_MAGIC, 4) == 0) {
- nr++;
- if (nr > plat->platform_nand_data.chip.nr_partitions) {
- update_env_flag = 1;
- memset((unsigned char *)aml_nand_part, 0, sizeof(struct aml_nand_part_info));
- aml_nand_part++;
- continue;
- }
- if (strcmp(parts->name, aml_nand_part->mtd_part_name)) {
- printk("mtd parttion %d name %s changed to %s \n", nr, parts->name, aml_nand_part->mtd_part_name);
- update_env_flag = 1;
- strncpy(aml_nand_part->mtd_part_name, parts->name, MAX_MTD_PART_NAME_LEN);
- }
- if (parts->offset != aml_nand_part->offset) {
- printk("mtd parttion %d offset %llx changed to %llx \n", nr, aml_nand_part->offset, parts->offset);
- update_env_flag = 1;
- aml_nand_part->offset = parts->offset;
- }
- if (parts->size != aml_nand_part->size) {
- printk("mtd parttion %d size %llx changed to %llx \n", nr, aml_nand_part->size, parts->size);
- update_env_flag = 1;
- aml_nand_part->size = parts->size;
- }
- if (parts->mask_flags != aml_nand_part->mask_flags) {
- printk("mtd parttion %d mask_flags %x changed to %x \n", nr, aml_nand_part->mask_flags, parts->mask_flags);
- update_env_flag = 1;
- aml_nand_part->mask_flags = parts->mask_flags;
- }
- parts++;
- aml_nand_part++;
- }
- if (nr < plat->platform_nand_data.chip.nr_partitions) {
- update_env_flag = 1;
- for (i=nr; i<plat->platform_nand_data.chip.nr_partitions; i++) {
- parts = plat->platform_nand_data.chip.partitions + i;
- aml_nand_part = nand_bbt_info->aml_nand_part + i;
- memcpy(aml_nand_part->mtd_part_magic, MTD_PART_MAGIC, 4);
- strncpy(aml_nand_part->mtd_part_name, parts->name, MAX_MTD_PART_NAME_LEN);
- aml_nand_part->offset = parts->offset;
- aml_nand_part->size = parts->size;
- aml_nand_part->mask_flags = parts->mask_flags;
- }
- }
- }
- memcpy((unsigned char *)aml_chip->aml_nandenv_info->nand_bbt_info.bbt_head_magic, (unsigned char *)nand_bbt_info, sizeof(struct aml_nand_bbt_info));
- }
- }
- if (update_env_flag) {
- error = aml_nand_save_env(mtd, (u_char *)env_ptr);
- if (error) {
- printk("nand env save failed: %d\n", error);
- goto exit;
- }
- }
- exit:
- kfree(env_ptr);
- return 0;
- }
- static int aml_nand_scan_bbt(struct mtd_info *mtd)
- {
- return 0;
- }
- #ifdef CONFIG_AML_NAND_ENV
- static struct mtd_info *nand_env_mtd = NULL;
- #define NAND_ENV_DEVICE_NAME "nand_env"
- static int nand_env_open(struct inode * inode, struct file * filp)
- {
- return 0;
- }
- /*
- * This funcion reads the u-boot envionment variables.
- * The f_pos points directly to the env location.
- */
- static ssize_t nand_env_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
- {
- env_t *env_ptr = NULL;
- ssize_t read_size;
- int error = 0;
- if(*ppos == CONFIG_ENV_SIZE)
- {
- return 0;
- }
- if(*ppos >= CONFIG_ENV_SIZE)
- {
- printk(KERN_ERR "nand env: data access violation!\n");
- return -EFAULT;
- }
- env_ptr = kzalloc(sizeof(env_t), GFP_KERNEL);
- if (env_ptr == NULL)
- {
- return -ENOMEM;
- }
-
- error = aml_nand_read_env (nand_env_mtd, 0, (u_char *)env_ptr);
- if (error)
- {
- printk("nand_env_read: nand env read failed: %llx, %d\n", (uint64_t)*ppos, error);
- kfree(env_ptr);
- return -EFAULT;
- }
- if((*ppos + count) > CONFIG_ENV_SIZE)
- {
- read_size = CONFIG_ENV_SIZE - *ppos;
- }
- else
- {
- read_size = count;
- }
- copy_to_user(buf, (env_ptr + *ppos), read_size);
- *ppos += read_size;
-
- kfree(env_ptr);
- return read_size;
- }
- static ssize_t nand_env_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
- {
- u_char *env_ptr = NULL;
- ssize_t write_size;
- int error = 0;
-
- if(*ppos == CONFIG_ENV_SIZE)
- {
- return 0;
- }
- if(*ppos >= CONFIG_ENV_SIZE)
- {
- printk(KERN_ERR "nand env: data access violation!\n");
- return -EFAULT;
- }
- env_ptr = kzalloc(sizeof(env_t), GFP_KERNEL);
- if (env_ptr == NULL)
- {
- return -ENOMEM;
- }
- error = aml_nand_read_env (nand_env_mtd, 0, (u_char *)env_ptr);
- if (error)
- {
- printk("nand_env_read: nand env read failed: %llx, %d\n", (uint64_t)*ppos, error);
- kfree(env_ptr);
- return -EFAULT;
- }
- if((*ppos + count) > CONFIG_ENV_SIZE)
- {
- write_size = CONFIG_ENV_SIZE - *ppos;
- }
- else
- {
- write_size = count;
- }
- copy_from_user((env_ptr + *ppos), buf, write_size);
- error = aml_nand_save_env(nand_env_mtd, env_ptr);
- if (error)
- {
- printk("nand_env_read: nand env read failed: %llx, %d\n", (uint64_t)*ppos, error);
- kfree(env_ptr);
- return -EFAULT;
- }
- *ppos += write_size;
-
- kfree(env_ptr);
- return write_size;
- }
- static int nand_env_close(struct inode *inode, struct file *file)
- {
- return 0;
- }
- //static int nand_env_ioctl(struct inode *inode, struct file *file,
- // u_int cmd, u_long arg)
- //{
- // return 0;
- //}
- static int nand_env_cls_suspend(struct device *dev, pm_message_t state)
- {
- return 0;
- }
- static int nand_env_cls_resume(struct device *dev)
- {
- return 0;
- }
- static struct class nand_env_class = {
-
- .name = "nand_env",
- .owner = THIS_MODULE,
- .suspend = nand_env_cls_suspend,
- .resume = nand_env_cls_resume,
- };
- static struct file_operations nand_env_fops = {
- .owner = THIS_MODULE,
- .open = nand_env_open,
- .read = nand_env_read,
- .write = nand_env_write,
- .release = nand_env_close,
- // .ioctl = nand_env_ioctl,
- };
- #endif
- static ssize_t show_nand_info(struct class *class,
- struct class_attribute *attr, char *buf)
- {
- struct aml_nand_chip *aml_chip = container_of(class, struct aml_nand_chip, cls);
- printk("mfr_type:\t\t0x%x\n", aml_chip->mfr_type);
- printk("onfi_mode:\t\t0x%x\n", aml_chip->onfi_mode);
- printk("T_REA:\t\t0x%x\n", aml_chip->T_REA);
- printk("T_RHOH:\t\t0x%x\n", aml_chip->T_RHOH);
- printk("options:\t\t0x%x\n", aml_chip->options);
- printk("page_size:\t\t0x%x\n", aml_chip->page_size);
- printk("block_size:\t\t0x%x\n", aml_chip->block_size);
- printk("oob_size:\t\t0x%x\n", aml_chip->oob_size);
- printk("virtual_page_size:\t\t0x%x\n", aml_chip->virtual_page_size);
- printk("virtual_block_size:\t\t0x%x\n", aml_chip->virtual_block_size);
- printk("plane_num:\t\t0x%x\n", aml_chip->plane_num);
- printk("chip_num:\t\t0x%x\n", aml_chip->chip_num);
- printk("internal_chipnr:\t\t0x%x\n", aml_chip->internal_chipnr);
- printk("internal_page_nums:\t\t0x%x\n", aml_chip->internal_page_nums);
- printk("internal_chip_shift:\t\t0x%x\n", aml_chip->internal_chip_shift);
- printk("bch_mode:\t\t0x%x\n", aml_chip->bch_mode);
- printk("user_byte_mode:\t\t0x%x\n", aml_chip->user_byte_mode);
- printk("ops_mode:\t\t0x%x\n", aml_chip->ops_mode);
- printk("cached_prog_status:\t\t0x%x\n", aml_chip->cached_prog_status);
- printk("max_bch_mode:\t\t0x%x\n", aml_chip->max_bch_mode);
- return 0;
- }
- static ssize_t show_bbt_table(struct class *class,
- struct class_attribute *attr, char *buf)
- {
- struct aml_nand_chip *aml_chip = container_of(class, struct aml_nand_chip, cls);
- struct mtd_info *mtd = &aml_chip->mtd;
- int start_blk, total_blk, i, phys_erase_shift;
- loff_t offset;
- phys_erase_shift = fls(mtd->erasesize) - 1;
- offset = (1024 * mtd->writesize / aml_chip->plane_num);
- start_blk = (int)(offset >> phys_erase_shift);
- total_blk = (int)(mtd->size >> phys_erase_shift);
- for (i = start_blk; i < total_blk; i++) {
- if(NAND_BLOCK_BAD == aml_chip->block_status[i])
- printk("block %d is a bad block\n", i);
- }
- return 0;
- }
- static ssize_t nand_page_dump(struct class *class,
- struct class_attribute *attr, const char *buf, size_t count)
- {
- struct aml_nand_chip *aml_chip = container_of(class, struct aml_nand_chip, cls);
- struct mtd_info *mtd = &aml_chip->mtd;
- struct mtd_oob_ops ops;
- loff_t off;
- loff_t addr;
- u_char *datbuf, *oobbuf, *p;
- int ret, i;
- printk(KERN_DEBUG "enter %s\n", __FUNCTION__);
- ret = sscanf(buf, "%llx", &off);
- datbuf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
- oobbuf = kmalloc(mtd->oobsize, GFP_KERNEL);
- if (!datbuf || !oobbuf) {
- printk("No memory for page buffer\n");
- return 1;
- }
- addr = ~((loff_t)mtd->writesize - 1);
- addr &= off;
- memset(&ops, 0, sizeof(ops));
- ops.datbuf = datbuf;
- ops.oobbuf = NULL; /* must exist, but oob data will be appended to ops.datbuf */
- ops.len = mtd->writesize;
- ops.ooblen = mtd->oobsize;
- ops.mode = MTD_OOB_RAW;
- i = mtd->read_oob(mtd, addr, &ops);
- if (i < 0) {
- printk("Error (%d) reading page %09llx\n", i, off);
- kfree(datbuf);
- kfree(oobbuf);
- return 1;
- }
- printk("Page %09llx dump,page size %d:\n", off,mtd->writesize);
- i = (mtd->writesize + mtd->oobsize) >> 4;
- p = datbuf;
- while (i--) {
- printk("\t%02x %02x %02x %02x %02x %02x %02x %02x"
- " %02x %02x %02x %02x %02x %02x %02x %02x\n",
- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
- p[8], p[9], p[10], p[11], p[12], p[13], p[14],
- p[15]);
- p += 16;
- }
- /*printf("OOB oob size %d:\n",nand->oobsize);
- i = nand->oobsize >> 3;
- while (i--) {
- printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
- p += 8;
- }*/
- kfree(datbuf);
- kfree(oobbuf);
- printk(KERN_DEBUG "exit %s\n", __FUNCTION__);
- return count;
- }
- static ssize_t nand_page_read(struct class *class,
- struct class_attribute *attr, const char *buf, size_t count)
- {
- struct aml_nand_chip *aml_chip = container_of(class, struct aml_nand_chip, cls);
- struct mtd_info *mtd = &aml_chip->mtd;
- struct mtd_oob_ops ops;
- loff_t off;
- loff_t addr;
- u_char *datbuf, *oobbuf, *p;
- size_t ret;
- int i;
- printk(KERN_DEBUG "enter %s\n", __FUNCTION__);
- ret = sscanf(buf, "%llx", &off);
- datbuf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
- oobbuf = kmalloc(mtd->oobsize, GFP_KERNEL);
- if (!datbuf || !oobbuf) {
- printk("No memory for page buffer\n");
- return 1;
- }
- addr = ~((loff_t)mtd->writesize - 1);
- addr &= off;
- mtd->read(mtd, addr, mtd->writesize, &ret, datbuf);
- if (ret < 0) {
- printk("Error (%d) reading page %09llx\n", i, off);
- kfree(datbuf);
- kfree(oobbuf);
- return 1;
- }
- printk("Page %09llx read,page size %d:\n", off,mtd->writesize);
- i = (mtd->writesize ) >> 4;
- p = datbuf;
- while (i--) {
- printk("\t%02x %02x %02x %02x %02x %02x %02x %02x"
- " %02x %02x %02x %02x %02x %02x %02x %02x\n",
- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
- p[8], p[9], p[10], p[11], p[12], p[13], p[14],
- p[15]);
- p += 16;
- }
- kfree(datbuf);
- kfree(oobbuf);
- printk(KERN_DEBUG "exit %s\n", __FUNCTION__);
- return count;
- }
- static struct class_attribute nand_class_attrs[] = {
- __ATTR(info, S_IRUGO | S_IWUSR, show_nand_info, NULL),
- __ATTR(bbt_table, S_IRUGO | S_IWUSR, show_bbt_table, NULL),
- __ATTR(page_dump, S_IRUGO | S_IWUSR, NULL, nand_page_dump),
- __ATTR(page_read, S_IRUGO | S_IWUSR, NULL, nand_page_read),
- __ATTR_NULL
- };
- int aml_nand_init(struct aml_nand_chip *aml_chip)
- {
- struct aml_nand_platform *plat = aml_chip->platform;
- struct nand_chip *chip = &aml_chip->chip;
- struct mtd_info *mtd = &aml_chip->mtd;
- int err = 0, i = 0, phys_erase_shift;
- int oobmul ;
- unsigned por_cfg, valid_chip_num = 0;
- #ifdef CONFIG_HAS_EARLYSUSPEND
- aml_chip->nand_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
- if (!aml_chip->nand_early_suspend.suspend)
- aml_chip->nand_early_suspend.suspend = aml_platform_nand_suspend;
- if (!aml_chip->nand_early_suspend.resume)
- aml_chip->nand_early_suspend.resume = aml_platform_nand_resume;
- aml_chip->nand_early_suspend.param = aml_chip;
- register_early_suspend(&aml_chip->nand_early_suspend);
- #endif
- switch (plat->platform_nand_data.chip.options & NAND_ECC_OPTIONS_MASK) {
- case NAND_ECC_SOFT_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.mode = NAND_ECC_SOFT;
- aml_chip->user_byte_mode = 1;
- aml_chip->bch_mode = 0;
- break;
- case NAND_ECC_BCH9_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_SIZE;
- chip->ecc.bytes = NAND_BCH9_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH9;
- aml_chip->user_byte_mode = 1;
- break;
- case NAND_ECC_BCH8_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_SIZE;
- chip->ecc.bytes = NAND_BCH8_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH8;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH12_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_SIZE;
- chip->ecc.bytes = NAND_BCH12_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH12;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH16_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_SIZE;
- chip->ecc.bytes = NAND_BCH16_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH16;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH8_1K_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_1KSIZE;
- chip->ecc.bytes = NAND_BCH8_1K_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH8_1K;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH16_1K_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_1KSIZE;
- chip->ecc.bytes = NAND_BCH16_1K_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH16_1K;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH24_1K_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_1KSIZE;
- chip->ecc.bytes = NAND_BCH24_1K_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH24_1K;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH30_1K_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_1KSIZE;
- chip->ecc.bytes = NAND_BCH30_1K_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH30_1K;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH40_1K_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_1KSIZE;
- chip->ecc.bytes = NAND_BCH40_1K_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH40_1K;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_BCH60_1K_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_1KSIZE;
- chip->ecc.bytes = NAND_BCH60_1K_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH60_1K;
- aml_chip->user_byte_mode = 2;
- break;
- case NAND_ECC_SHORT_MODE:
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->block_bad = aml_nand_block_bad;
- chip->block_markbad = aml_nand_block_markbad;
- chip->ecc.mode = NAND_ECC_HW;
- chip->ecc.size = NAND_ECC_UNIT_SHORT;
- chip->ecc.bytes = NAND_BCH60_1K_ECC_SIZE;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.read_page = aml_nand_read_page_hwecc;
- chip->ecc.write_page = aml_nand_write_page_hwecc;
- chip->ecc.read_oob = aml_nand_read_oob;
- chip->ecc.write_oob = aml_nand_write_oob;
- aml_chip->bch_mode = NAND_ECC_BCH_SHORT;
- aml_chip->user_byte_mode = 2;
- break;
- default :
- printk(KERN_WARNING "haven`t found any ecc mode just selected NAND_ECC_NONE\n");
- chip->write_buf = aml_nand_dma_write_buf;
- chip->read_buf = aml_nand_dma_read_buf;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- chip->ecc.mode = NAND_ECC_NONE;
- aml_chip->user_byte_mode = 1;
- aml_chip->bch_mode = 0;
- break;
- }
- if (!aml_chip->aml_nand_hw_init)
- aml_chip->aml_nand_hw_init = aml_platform_hw_init;
- if (!aml_chip->aml_nand_adjust_timing)
- aml_chip->aml_nand_adjust_timing = aml_platform_adjust_timing;
- if (!aml_chip->aml_nand_options_confirm)
- aml_chip->aml_nand_options_confirm = aml_platform_options_confirm;
- if (!aml_chip->aml_nand_cmd_ctrl)
- aml_chip->aml_nand_cmd_ctrl = aml_platform_cmd_ctrl;
- if (!aml_chip->aml_nand_select_chip)
- aml_chip->aml_nand_select_chip = aml_platform_select_chip;
- if (!aml_chip->aml_nand_write_byte)
- aml_chip->aml_nand_write_byte = aml_platform_write_byte;
- if (!aml_chip->aml_nand_wait_devready)
- aml_chip->aml_nand_wait_devready = aml_platform_wait_devready;
- if (!aml_chip->aml_nand_get_user_byte)
- aml_chip->aml_nand_get_user_byte = aml_platform_get_user_byte;
- if (!aml_chip->aml_nand_set_user_byte)
- aml_chip->aml_nand_set_user_byte = aml_platform_set_user_byte;
- if (!aml_chip->aml_nand_command)
- aml_chip->aml_nand_command = aml_nand_base_command;
- if (!aml_chip->aml_nand_dma_read)
- aml_chip->aml_nand_dma_read = aml_platform_dma_read;
- if (!aml_chip->aml_nand_dma_write)
- aml_chip->aml_nand_dma_write = aml_platform_dma_write;
- if (!aml_chip->aml_nand_hwecc_correct)
- aml_chip->aml_nand_hwecc_correct = aml_platform_hwecc_correct;
- if (!chip->IO_ADDR_R)
- chip->IO_ADDR_R = (void __iomem *) CBUS_REG_ADDR(NAND_BUF);
- if (!chip->IO_ADDR_W)
- chip->IO_ADDR_W = (void __iomem *) CBUS_REG_ADDR(NAND_BUF);
- chip->options |= NAND_SKIP_BBTSCAN;
- chip->options |= NAND_NO_SUBPAGE_WRITE;
- if (chip->ecc.mode != NAND_ECC_SOFT) {
- if (aml_chip->user_byte_mode == 2)
- chip->ecc.layout = &aml_nand_oob_64_2info;
- else
- chip->ecc.layout = &aml_nand_oob_64;
- }
- chip->select_chip = aml_nand_select_chip;
- chip->cmd_ctrl = aml_nand_cmd_ctrl;
- //chip->dev_ready = aml_nand_dev_ready;
- chip->verify_buf = aml_nand_verify_buf;
- chip->read_byte = aml_platform_read_byte;
- aml_chip->chip_num = plat->platform_nand_data.chip.nr_chips;
- if (aml_chip->chip_num > MAX_CHIP_NUM) {
- dev_err(aml_chip->device, "couldn`t support for so many chips\n");
- err = -ENXIO;
- goto exit_error;
- }
- for (i=0; i<aml_chip->chip_num; i++) {
- aml_chip->valid_chip[i] = 1;
- aml_chip->chip_enable[i] = (((plat->chip_enable_pad >> i*4) & 0xf) << 10);
- aml_chip->rb_enable[i] = (((plat->ready_busy_pad >> i*4) & 0xf) << 10);
- }
- //use NO RB mode to detect nand chip num
- aml_chip->ops_mode |= AML_CHIP_NONE_RB;
- chip->chip_delay = 100;
- aml_chip->aml_nand_hw_init(aml_chip);
- if (nand_scan(mtd, aml_chip->chip_num) == -ENODEV) {
- chip->options = 0;
- chip->options |= NAND_SKIP_BBTSCAN;
- chip->options |= NAND_NO_SUBPAGE_WRITE;
if (aml_nand_scan(mtd, aml_chip->chip_num)) {
- err = -ENXIO;
- goto exit_error;
- }
- }
- else {
- for (i=1; i<aml_chip->chip_num; i++) {
- aml_chip->valid_chip[i] = 0;
- }
- aml_chip->options = NAND_DEFAULT_OPTIONS;
- aml_chip->page_size = mtd->writesize;
- aml_chip->block_size = mtd->erasesize;
- aml_chip->oob_size = mtd->oobsize;
- aml_chip->plane_num = 1;
- aml_chip->internal_chipnr = 1;
- chip->ecc.read_page_raw = aml_nand_read_page_raw;
- chip->ecc.write_page_raw = aml_nand_write_page_raw;
- }
-
- valid_chip_num = 0;
- for (i=0; i<aml_chip->chip_num; i++) {
- if (aml_chip->valid_chip[i]) {
- valid_chip_num++;
- }
- }
-
- //due to hardware limit, for chip num over 2, must use NO RB mode.
- if(valid_chip_num > 2){
- printk("dect valid_chip_num:%d over 2, using NO RB mode\n", valid_chip_num);
- }
- else{
-
- if(aml_chip->rbpin_detect){
- por_cfg = READ_CBUS_REG(ASSIST_POR_CONFIG);
- printk("%s auto detect RB pin here and por_cfg:%x\n", __func__, por_cfg);
- if(por_cfg&4){
- if(por_cfg&1){
- printk("%s detect without RB pin here\n", __func__);
- aml_chip->rb_enable[0] = NULL;
- }
- else{
- printk("%s detect with RB pin here\n", __func__);
- }
- }
- else{
- printk("%s power config ERROR and force using NO RB mode here\n", __func__);
- aml_chip->rb_enable[0] = NULL;
- }
- }
-
- if (!aml_chip->rb_enable[0]) {
- aml_chip->ops_mode |= AML_CHIP_NONE_RB;
- chip->dev_ready = NULL;
- chip->chip_delay = 100;
- printk("#####%s, none RB and chip->chip_delay:%d\n", __func__, chip->chip_delay);
- }
- else{
- chip->chip_delay = 20;
- chip->dev_ready = aml_nand_dev_ready;
- aml_chip->ops_mode &= ~AML_CHIP_NONE_RB;
- printk("#####%s, with RB pins and chip->chip_delay:%d\n", __func__, chip->chip_delay);
- }
- }
-
- chip->scan_bbt = aml_nand_scan_bbt;
- mtd->suspend = aml_nand_suspend;
- mtd->resume = aml_nand_resume;
- if (aml_chip->aml_nand_adjust_timing)
- aml_chip->aml_nand_adjust_timing(aml_chip);
- if (chip->ecc.mode != NAND_ECC_SOFT) {
- if (aml_chip->aml_nand_options_confirm(aml_chip)) {
- err = -ENXIO;
- goto exit_error;
- }
- }
- mtd->writebufsize = mtd->writesize;
- #if ((defined CONFIG_ARCH_MESON3) || (defined CONFIG_ARCH_MESON6))
- switch(aml_chip->bch_mode){
- case NAND_ECC_BCH8:
- case NAND_ECC_BCH8_1K:
- aml_chip->ecc_cnt_limit = 6;
- aml_chip->ecc_max = 8;
- break;
- case NAND_ECC_BCH9:
- aml_chip->ecc_cnt_limit = 6;
- aml_chip->ecc_max = 9;
- break;
- case NAND_ECC_BCH12:
- aml_chip->ecc_cnt_limit = 6;
- aml_chip->ecc_max = 12;
- break;
- case NAND_ECC_BCH16:
- case NAND_ECC_BCH16_1K:
- aml_chip->ecc_cnt_limit = 13;
- aml_chip->ecc_max = 16;
- break;
- case NAND_ECC_BCH24_1K:
- aml_chip->ecc_cnt_limit = 20;
- aml_chip->ecc_max = 24;
- break;
- case NAND_ECC_BCH30_1K:
- aml_chip->ecc_cnt_limit = 25;
- aml_chip->ecc_max = 30;
- break;
- case NAND_ECC_BCH40_1K:
- aml_chip->ecc_cnt_limit = 35;
- aml_chip->ecc_max = 40;
- break;
- case NAND_ECC_BCH60_1K:
- aml_chip->ecc_cnt_limit = 50;
- aml_chip->ecc_max = 60;
- break;
- default:
- aml_chip->ecc_cnt_limit = 9;
- aml_chip->ecc_max = 16;
- break;
- }
- #endif
- if (plat->platform_nand_data.chip.ecclayout) {
- chip->ecc.layout = plat->platform_nand_data.chip.ecclayout;
- }
- else {
- oobmul =mtd->oobsize /aml_chip->oob_size ;
- if (!strncmp((char*)plat->name, NAND_BOOT_NAME, strlen((const char*)NAND_BOOT_NAME))) {
- chip->ecc.layout = &aml_nand_uboot_oob;
- }
- else if (chip->ecc.mode != NAND_ECC_SOFT) {
- /* switch (mtd->oobsize) {*/
- switch (aml_chip->oob_size) {
- case 64:
- chip->ecc.layout = &aml_nand_oob_64_2info;
- break;
- case 128:
- chip->ecc.layout = &aml_nand_oob_128;
- break;
- case 218:
- chip->ecc.layout = &aml_nand_oob_218;
- break;
- case 224:
- chip->ecc.layout = &aml_nand_oob_224;
- break;
- case 256:
- chip->ecc.layout = &aml_nand_oob_256;
- break;
- case 376:
- chip->ecc.layout = &aml_nand_oob_376;
- break;
- case 436:
- chip->ecc.layout = &aml_nand_oob_436;
- break;
- case 448:
- chip->ecc.layout = &aml_nand_oob_448;
- break;
- case 640:
- chip->ecc.layout = &aml_nand_oob_640;
- break;
- default:
- printk("havn`t found any oob layout use nand base oob layout " "oobsize %d\n", mtd->oobsize);
- chip->ecc.layout = kzalloc(sizeof(struct nand_ecclayout), GFP_KERNEL);
- if (!chip->ecc.layout)
- chip->ecc.layout = &aml_nand_oob_64_2info;
- else
- chip->ecc.layout->oobfree[0].length = ((mtd->writesize / chip->ecc.size) * aml_chip->user_byte_mode);
- break;
- }
- chip->ecc.layout->eccbytes *= oobmul;
- chip->ecc.layout->oobfree[0].length *=oobmul;
- printk(" oob layout use nand base oob layout oobsize = %d,oobmul =%d,mtd->oobsize =%d,aml_chip->oob_size =%d\n", chip->ecc.layout->oobfree[0].length,oobmul,mtd->oobsize,aml_chip->oob_size);
- }
- }
- /*
- * The number of bytes available for a client to place data into
- * the out of band area
- */
- chip->ecc.layout->oobavail = 0;
- for (i = 0; chip->ecc.layout->oobfree[i].length && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
- chip->ecc.layout->oobavail += chip->ecc.layout->oobfree[i].length;
- mtd->oobavail = chip->ecc.layout->oobavail;
- mtd->ecclayout = chip->ecc.layout;
- aml_chip->virtual_page_size = mtd->writesize;
- aml_chip->virtual_block_size = mtd->erasesize;
- aml_chip->aml_nand_data_buf = dma_alloc_coherent(aml_chip->device, (mtd->writesize + mtd->oobsize), &aml_chip->data_dma_addr, GFP_KERNEL);
- if (aml_chip->aml_nand_data_buf == NULL) {
- printk("no memory for flash data buf\n");
- err = -ENOMEM;
- goto exit_error;
- }
- aml_chip->user_info_buf = dma_alloc_coherent(aml_chip->device, (mtd->writesize / chip->ecc.size)*sizeof(int), &(aml_chip->nand_info_dma_addr), GFP_KERNEL);
- if (aml_chip->user_info_buf == NULL) {
- printk("no memory for flash info buf\n");
- err = -ENOMEM;
- goto exit_error;
- }
- if (chip->buffers)
- kfree(chip->buffers);
- if (mtd->oobsize >= NAND_MAX_OOBSIZE)
- chip->buffers = kzalloc((mtd->writesize + 3*mtd->oobsize), GFP_KERNEL);
- else
- chip->buffers = kzalloc((mtd->writesize + 3*NAND_MAX_OOBSIZE), GFP_KERNEL);
- if (chip->buffers == NULL) {
- printk("no memory for flash data buf\n");
- err = -ENOMEM;
- goto exit_error;
- }
- chip->oob_poi = chip->buffers->databuf + mtd->writesize;
- chip->options |= NAND_OWN_BUFFERS;
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->new_nand_info.type) && (aml_chip->new_nand_info.type < 10)){
- aml_chip->new_nand_info.slc_program_info.get_default_value(mtd);
- }
- #endif
- if (strncmp((char*)plat->name, NAND_BOOT_NAME, strlen((const char*)NAND_BOOT_NAME))) {
- #ifdef NEW_NAND_SUPPORT
- if((aml_chip->new_nand_info.type) && (aml_chip->new_nand_info.type < 10)){
-
- aml_chip->new_nand_info.read_rety_info.get_default_value(mtd);
- }
- #endif
- phys_erase_shift = fls(mtd->erasesize) - 1;
- aml_chip->block_status = kzalloc((mtd->size >> phys_erase_shift), GFP_KERNEL);
- if (aml_chip->block_status == NULL) {
- printk("no memory for flash block status\n");
- err = -ENOMEM;
- goto exit_error;
- }
- memset(aml_chip->block_status, 0xff, (mtd->size >> phys_erase_shift));
- err = aml_nand_env_check(mtd);
- if (err)
- printk("invalid nand env\n");
- #ifdef CONFIG_AML_NAND_ENV
- int ret;
- struct device *devp;
- static dev_t nand_env_devno;
- pr_info("nand env: nand_env_probe. \n");
- nand_env_mtd = mtd;
-
- ret = alloc_chrdev_region(&nand_env_devno, 0, 1, NAND_ENV_DEVICE_NAME);
-
- if (ret < 0) {
- pr_err("nand_env: failed to allocate chrdev. \n");
- return 0;
- }
- /* connect the file operations with cdev */
- cdev_init(&aml_chip->nand_env_cdev, &nand_env_fops);
- aml_chip->nand_env_cdev.owner = THIS_MODULE;
- /* connect the major/minor number to the cdev */
- ret = cdev_add(&aml_chip->nand_env_cdev, nand_env_devno, 1);
- if (ret) {
- pr_err("nand env: failed to add device. \n");
- /* @todo do with error */
- return ret;
- }
- ret = class_register(&nand_env_class);
- if (ret < 0) {
- printk(KERN_NOTICE "class_register(&nand_env_class) failed!\n");
- }
- devp = device_create(&nand_env_class, NULL, nand_env_devno, NULL, "nand_env");
- if (IS_ERR(devp)) {
- printk(KERN_ERR "nand_env: failed to create device node\n");
- ret = PTR_ERR(devp);
- }
- #endif
- /*setup class*/
- aml_chip->cls.name = kzalloc(strlen((const char*)NAND_MULTI_NAME)+1, GFP_KERNEL);
- strcpy(aml_chip->cls.name, (const char*)NAND_MULTI_NAME);
- //sprintf(aml_chip->cls.name, NAND_MULTI_NAME);
- aml_chip->cls.class_attrs = nand_class_attrs;
- err = class_register(&aml_chip->cls);
- if(err)
- printk(" class register nand_class fail!\n");
- }
- if (aml_nand_add_partition(aml_chip) != 0) {
- err = -ENXIO;
- goto exit_error;
- }
- dev_dbg(aml_chip->device, "initialized ok\n");
- return 0;
- exit_error:
- unregister_early_suspend(&aml_chip->nand_early_suspend);
- if (aml_chip->user_info_buf) {
- dma_free_coherent(aml_chip->device, (mtd->writesize / chip->ecc.size)*sizeof(int), aml_chip->user_info_buf, (dma_addr_t)aml_chip->nand_info_dma_addr);
- aml_chip->user_info_buf = NULL;
- }
- if (chip->buffers) {
- kfree(chip->buffers);
- chip->buffers = NULL;
- }
- if (aml_chip->aml_nand_data_buf) {
- dma_free_coherent(aml_chip->device, (mtd->writesize + mtd->oobsize), aml_chip->aml_nand_data_buf, (dma_addr_t)aml_chip->data_dma_addr);
- aml_chip->aml_nand_data_buf = NULL;
- }
- if (aml_chip->block_status) {
- kfree(aml_chip->block_status);
- aml_chip->block_status = NULL;
- }
- return err;
- }
- #define DRV_NAME "aml-nand"
- #define DRV_VERSION "1.1"
- #define DRV_AUTHOR "xiaojun_yoyo"
- #define DRV_DESC "Amlogic nand flash host controll driver for M1"
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR(DRV_AUTHOR);
- MODULE_DESCRIPTION(DRV_DESC);
- MODULE_ALIAS("platform:" DRV_NAME);
|