12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250 |
- /*
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/slab.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/nand.h>
- #include <linux/mtd/partitions.h>
- #include <linux/platform_device.h>
- #include <linux/sched.h>
- #include <linux/dma-mapping.h>
- #include <linux/io.h>
- #include <linux/crc16.h>
- #include <linux/bitrev.h>
- #include <asm/dma.h>
- #include <asm/mach/flash.h>
- #include <mach/dma.h>
- #include "msm_nand.h"
- unsigned long msm_nand_phys;
- unsigned long msm_nandc01_phys;
- unsigned long msm_nandc10_phys;
- unsigned long msm_nandc11_phys;
- unsigned long ebi2_register_base;
- uint32_t dual_nand_ctlr_present;
- uint32_t interleave_enable;
- uint32_t enable_bch_ecc;
- #define MSM_NAND_DMA_BUFFER_SIZE SZ_8K
- #define MSM_NAND_DMA_BUFFER_SLOTS \
- (MSM_NAND_DMA_BUFFER_SIZE / (sizeof(((atomic_t *)0)->counter) * 8))
- #define MSM_NAND_CFG0_RAW_ONFI_IDENTIFIER 0x88000800
- #define MSM_NAND_CFG0_RAW_ONFI_PARAM_INFO 0x88040000
- #define MSM_NAND_CFG1_RAW_ONFI_IDENTIFIER 0x0005045d
- #define MSM_NAND_CFG1_RAW_ONFI_PARAM_INFO 0x0005045d
- #define ONFI_IDENTIFIER_LENGTH 0x0004
- #define ONFI_PARAM_INFO_LENGTH 0x0200
- #define ONFI_PARAM_PAGE_LENGTH 0x0100
- #define ONFI_PARAMETER_PAGE_SIGNATURE 0x49464E4F
- #define FLASH_READ_ONFI_IDENTIFIER_COMMAND 0x90
- #define FLASH_READ_ONFI_IDENTIFIER_ADDRESS 0x20
- #define FLASH_READ_ONFI_PARAMETERS_COMMAND 0xEC
- #define FLASH_READ_ONFI_PARAMETERS_ADDRESS 0x00
- #define VERBOSE 0
- struct msm_nand_chip {
- struct device *dev;
- wait_queue_head_t wait_queue;
- atomic_t dma_buffer_busy;
- unsigned dma_channel;
- uint8_t *dma_buffer;
- dma_addr_t dma_addr;
- unsigned CFG0, CFG1, CFG0_RAW, CFG1_RAW;
- uint32_t ecc_buf_cfg;
- uint32_t ecc_bch_cfg;
- uint32_t ecc_parity_bytes;
- unsigned cw_size;
- unsigned int uncorrectable_bit_mask;
- unsigned int num_err_mask;
- };
- #define CFG1_WIDE_FLASH (1U << 1)
- /* TODO: move datamover code out */
- #define SRC_CRCI_NAND_CMD CMD_SRC_CRCI(DMOV_NAND_CRCI_CMD)
- #define DST_CRCI_NAND_CMD CMD_DST_CRCI(DMOV_NAND_CRCI_CMD)
- #define SRC_CRCI_NAND_DATA CMD_SRC_CRCI(DMOV_NAND_CRCI_DATA)
- #define DST_CRCI_NAND_DATA CMD_DST_CRCI(DMOV_NAND_CRCI_DATA)
- #define msm_virt_to_dma(chip, vaddr) \
- ((chip)->dma_addr + \
- ((uint8_t *)(vaddr) - (chip)->dma_buffer))
- /**
- * msm_nand_oob_64 - oob info for 2KB page
- */
- static struct nand_ecclayout msm_nand_oob_64 = {
- .eccbytes = 40,
- .eccpos = {
- 0, 1, 2, 3, 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,
- 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
- },
- .oobavail = 16,
- .oobfree = {
- {30, 16},
- }
- };
- /**
- * msm_nand_oob_128 - oob info for 4KB page
- */
- static struct nand_ecclayout msm_nand_oob_128 = {
- .eccbytes = 80,
- .eccpos = {
- 0, 1, 2, 3, 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, 64, 65, 66, 67, 68, 69,
- 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- },
- .oobavail = 32,
- .oobfree = {
- {70, 32},
- }
- };
- /**
- * msm_nand_oob_224 - oob info for 4KB page 8Bit interface
- */
- static struct nand_ecclayout msm_nand_oob_224_x8 = {
- .eccbytes = 104,
- .eccpos = {
- 0, 1, 2, 3, 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, 64,
- 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
- },
- .oobavail = 32,
- .oobfree = {
- {91, 32},
- }
- };
- /**
- * msm_nand_oob_224 - oob info for 4KB page 16Bit interface
- */
- static struct nand_ecclayout msm_nand_oob_224_x16 = {
- .eccbytes = 112,
- .eccpos = {
- 0, 1, 2, 3, 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, 64, 65, 66, 67, 68, 69,
- 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
- 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
- 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
- },
- .oobavail = 32,
- .oobfree = {
- {98, 32},
- }
- };
- /**
- * msm_nand_oob_256 - oob info for 8KB page
- */
- static struct nand_ecclayout msm_nand_oob_256 = {
- .eccbytes = 160,
- .eccpos = {
- 0, 1, 2, 3, 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, 64, 65, 66, 67, 68, 69,
- 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
- 90, 91, 92, 93, 94, 96, 97, 98 , 99, 100,
- 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
- 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
- 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
- 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
- 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
- 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
- },
- .oobavail = 64,
- .oobfree = {
- {151, 64},
- }
- };
- /**
- * msm_onenand_oob_64 - oob info for large (2KB) page
- */
- static struct nand_ecclayout msm_onenand_oob_64 = {
- .eccbytes = 20,
- .eccpos = {
- 8, 9, 10, 11, 12,
- 24, 25, 26, 27, 28,
- 40, 41, 42, 43, 44,
- 56, 57, 58, 59, 60,
- },
- .oobavail = 20,
- .oobfree = {
- {2, 3}, {14, 2}, {18, 3}, {30, 2},
- {34, 3}, {46, 2}, {50, 3}, {62, 2}
- }
- };
- static void *msm_nand_get_dma_buffer(struct msm_nand_chip *chip, size_t size)
- {
- unsigned int bitmask, free_bitmask, old_bitmask;
- unsigned int need_mask, current_need_mask;
- int free_index;
- need_mask = (1UL << DIV_ROUND_UP(size, MSM_NAND_DMA_BUFFER_SLOTS)) - 1;
- bitmask = atomic_read(&chip->dma_buffer_busy);
- free_bitmask = ~bitmask;
- do {
- free_index = __ffs(free_bitmask);
- current_need_mask = need_mask << free_index;
- if (size + free_index * MSM_NAND_DMA_BUFFER_SLOTS >=
- MSM_NAND_DMA_BUFFER_SIZE)
- return NULL;
- if ((bitmask & current_need_mask) == 0) {
- old_bitmask =
- atomic_cmpxchg(&chip->dma_buffer_busy,
- bitmask,
- bitmask | current_need_mask);
- if (old_bitmask == bitmask)
- return chip->dma_buffer +
- free_index * MSM_NAND_DMA_BUFFER_SLOTS;
- free_bitmask = 0; /* force return */
- }
- /* current free range was too small, clear all free bits */
- /* below the top busy bit within current_need_mask */
- free_bitmask &=
- ~(~0U >> (32 - fls(bitmask & current_need_mask)));
- } while (free_bitmask);
- return NULL;
- }
- static void msm_nand_release_dma_buffer(struct msm_nand_chip *chip,
- void *buffer, size_t size)
- {
- int index;
- unsigned int used_mask;
- used_mask = (1UL << DIV_ROUND_UP(size, MSM_NAND_DMA_BUFFER_SLOTS)) - 1;
- index = ((uint8_t *)buffer - chip->dma_buffer) /
- MSM_NAND_DMA_BUFFER_SLOTS;
- atomic_sub(used_mask << index, &chip->dma_buffer_busy);
- wake_up(&chip->wait_queue);
- }
- unsigned flash_rd_reg(struct msm_nand_chip *chip, unsigned addr)
- {
- struct {
- dmov_s cmd;
- unsigned cmdptr;
- unsigned data;
- } *dma_buffer;
- unsigned rv;
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(
- chip, sizeof(*dma_buffer))));
- dma_buffer->cmd.cmd = CMD_LC | CMD_OCB | CMD_OCU;
- dma_buffer->cmd.src = addr;
- dma_buffer->cmd.dst = msm_virt_to_dma(chip, &dma_buffer->data);
- dma_buffer->cmd.len = 4;
- dma_buffer->cmdptr =
- (msm_virt_to_dma(chip, &dma_buffer->cmd) >> 3) | CMD_PTR_LP;
- dma_buffer->data = 0xeeeeeeee;
- mb();
- msm_dmov_exec_cmd(
- chip->dma_channel, DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- rv = dma_buffer->data;
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- return rv;
- }
- void flash_wr_reg(struct msm_nand_chip *chip, unsigned addr, unsigned val)
- {
- struct {
- dmov_s cmd;
- unsigned cmdptr;
- unsigned data;
- } *dma_buffer;
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(
- chip, sizeof(*dma_buffer))));
- dma_buffer->cmd.cmd = CMD_LC | CMD_OCB | CMD_OCU;
- dma_buffer->cmd.src = msm_virt_to_dma(chip, &dma_buffer->data);
- dma_buffer->cmd.dst = addr;
- dma_buffer->cmd.len = 4;
- dma_buffer->cmdptr =
- (msm_virt_to_dma(chip, &dma_buffer->cmd) >> 3) | CMD_PTR_LP;
- dma_buffer->data = val;
- mb();
- msm_dmov_exec_cmd(
- chip->dma_channel, DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- }
- static dma_addr_t
- msm_nand_dma_map(struct device *dev, void *addr, size_t size,
- enum dma_data_direction dir)
- {
- struct page *page;
- unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
- if (virt_addr_valid(addr))
- page = virt_to_page(addr);
- else {
- if (WARN_ON(size + offset > PAGE_SIZE))
- return ~0;
- page = vmalloc_to_page(addr);
- }
- return dma_map_page(dev, page, offset, size, dir);
- }
- uint32_t flash_read_id(struct msm_nand_chip *chip)
- {
- struct {
- dmov_s cmd[7];
- unsigned cmdptr;
- unsigned data[7];
- } *dma_buffer;
- uint32_t rv;
- wait_event(chip->wait_queue, (dma_buffer = msm_nand_get_dma_buffer
- (chip, sizeof(*dma_buffer))));
- dma_buffer->data[0] = 0 | 4;
- dma_buffer->data[1] = MSM_NAND_CMD_FETCH_ID;
- dma_buffer->data[2] = 1;
- dma_buffer->data[3] = 0xeeeeeeee;
- dma_buffer->data[4] = 0xeeeeeeee;
- dma_buffer->data[5] = flash_rd_reg(chip, MSM_NAND_SFLASHC_BURST_CFG);
- dma_buffer->data[6] = 0x00000000;
- BUILD_BUG_ON(6 != ARRAY_SIZE(dma_buffer->data) - 1);
- dma_buffer->cmd[0].cmd = 0 | CMD_OCB;
- dma_buffer->cmd[0].src = msm_virt_to_dma(chip, &dma_buffer->data[6]);
- dma_buffer->cmd[0].dst = MSM_NAND_SFLASHC_BURST_CFG;
- dma_buffer->cmd[0].len = 4;
- dma_buffer->cmd[1].cmd = 0;
- dma_buffer->cmd[1].src = msm_virt_to_dma(chip, &dma_buffer->data[0]);
- dma_buffer->cmd[1].dst = MSM_NAND_FLASH_CHIP_SELECT;
- dma_buffer->cmd[1].len = 4;
- dma_buffer->cmd[2].cmd = DST_CRCI_NAND_CMD;
- dma_buffer->cmd[2].src = msm_virt_to_dma(chip, &dma_buffer->data[1]);
- dma_buffer->cmd[2].dst = MSM_NAND_FLASH_CMD;
- dma_buffer->cmd[2].len = 4;
- dma_buffer->cmd[3].cmd = 0;
- dma_buffer->cmd[3].src = msm_virt_to_dma(chip, &dma_buffer->data[2]);
- dma_buffer->cmd[3].dst = MSM_NAND_EXEC_CMD;
- dma_buffer->cmd[3].len = 4;
- dma_buffer->cmd[4].cmd = SRC_CRCI_NAND_DATA;
- dma_buffer->cmd[4].src = MSM_NAND_FLASH_STATUS;
- dma_buffer->cmd[4].dst = msm_virt_to_dma(chip, &dma_buffer->data[3]);
- dma_buffer->cmd[4].len = 4;
- dma_buffer->cmd[5].cmd = 0;
- dma_buffer->cmd[5].src = MSM_NAND_READ_ID;
- dma_buffer->cmd[5].dst = msm_virt_to_dma(chip, &dma_buffer->data[4]);
- dma_buffer->cmd[5].len = 4;
- dma_buffer->cmd[6].cmd = CMD_OCU | CMD_LC;
- dma_buffer->cmd[6].src = msm_virt_to_dma(chip, &dma_buffer->data[5]);
- dma_buffer->cmd[6].dst = MSM_NAND_SFLASHC_BURST_CFG;
- dma_buffer->cmd[6].len = 4;
- BUILD_BUG_ON(6 != ARRAY_SIZE(dma_buffer->cmd) - 1);
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd) >> 3
- ) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- pr_info("status: %x\n", dma_buffer->data[3]);
- pr_info("nandid: %x maker %02x device %02x\n",
- dma_buffer->data[4], dma_buffer->data[4] & 0xff,
- (dma_buffer->data[4] >> 8) & 0xff);
- rv = dma_buffer->data[4];
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- return rv;
- }
- struct flash_identification {
- uint32_t flash_id;
- uint32_t density;
- uint32_t widebus;
- uint32_t pagesize;
- uint32_t blksize;
- uint32_t oobsize;
- uint32_t ecc_correctability;
- } supported_flash;
- uint16_t flash_onfi_crc_check(uint8_t *buffer, uint16_t count)
- {
- int i;
- uint16_t result;
- for (i = 0; i < count; i++)
- buffer[i] = bitrev8(buffer[i]);
- result = bitrev16(crc16(bitrev16(0x4f4e), buffer, count));
- for (i = 0; i < count; i++)
- buffer[i] = bitrev8(buffer[i]);
- return result;
- }
- uint32_t flash_onfi_probe(struct msm_nand_chip *chip)
- {
- struct onfi_param_page {
- uint32_t parameter_page_signature;
- uint16_t revision_number;
- uint16_t features_supported;
- uint16_t optional_commands_supported;
- uint8_t reserved0[22];
- uint8_t device_manufacturer[12];
- uint8_t device_model[20];
- uint8_t jedec_manufacturer_id;
- uint16_t date_code;
- uint8_t reserved1[13];
- uint32_t number_of_data_bytes_per_page;
- uint16_t number_of_spare_bytes_per_page;
- uint32_t number_of_data_bytes_per_partial_page;
- uint16_t number_of_spare_bytes_per_partial_page;
- uint32_t number_of_pages_per_block;
- uint32_t number_of_blocks_per_logical_unit;
- uint8_t number_of_logical_units;
- uint8_t number_of_address_cycles;
- uint8_t number_of_bits_per_cell;
- uint16_t maximum_bad_blocks_per_logical_unit;
- uint16_t block_endurance;
- uint8_t guaranteed_valid_begin_blocks;
- uint16_t guaranteed_valid_begin_blocks_endurance;
- uint8_t number_of_programs_per_page;
- uint8_t partial_program_attributes;
- uint8_t number_of_bits_ecc_correctability;
- uint8_t number_of_interleaved_address_bits;
- uint8_t interleaved_operation_attributes;
- uint8_t reserved2[13];
- uint8_t io_pin_capacitance;
- uint16_t timing_mode_support;
- uint16_t program_cache_timing_mode_support;
- uint16_t maximum_page_programming_time;
- uint16_t maximum_block_erase_time;
- uint16_t maximum_page_read_time;
- uint16_t maximum_change_column_setup_time;
- uint8_t reserved3[23];
- uint16_t vendor_specific_revision_number;
- uint8_t vendor_specific[88];
- uint16_t integrity_crc;
- } __attribute__((__packed__));
- struct onfi_param_page *onfi_param_page_ptr;
- uint8_t *onfi_identifier_buf = NULL;
- uint8_t *onfi_param_info_buf = NULL;
- struct {
- dmov_s cmd[11];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t addr0;
- uint32_t addr1;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t exec;
- uint32_t flash_status;
- uint32_t devcmd1_orig;
- uint32_t devcmdvld_orig;
- uint32_t devcmd1_mod;
- uint32_t devcmdvld_mod;
- uint32_t sflash_bcfg_orig;
- uint32_t sflash_bcfg_mod;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- unsigned page_address = 0;
- int err = 0;
- dma_addr_t dma_addr_param_info = 0;
- dma_addr_t dma_addr_identifier = 0;
- unsigned cmd_set_count = 2;
- unsigned crc_chk_count = 0;
- if (msm_nand_data.nr_parts) {
- page_address = ((msm_nand_data.parts[0]).offset << 6);
- } else {
- pr_err("flash_onfi_probe: "
- "No partition info available\n");
- err = -EIO;
- return err;
- }
- wait_event(chip->wait_queue, (onfi_identifier_buf =
- msm_nand_get_dma_buffer(chip, ONFI_IDENTIFIER_LENGTH)));
- dma_addr_identifier = msm_virt_to_dma(chip, onfi_identifier_buf);
- wait_event(chip->wait_queue, (onfi_param_info_buf =
- msm_nand_get_dma_buffer(chip, ONFI_PARAM_INFO_LENGTH)));
- dma_addr_param_info = msm_virt_to_dma(chip, onfi_param_info_buf);
- wait_event(chip->wait_queue, (dma_buffer = msm_nand_get_dma_buffer
- (chip, sizeof(*dma_buffer))));
- dma_buffer->data.sflash_bcfg_orig = flash_rd_reg
- (chip, MSM_NAND_SFLASHC_BURST_CFG);
- dma_buffer->data.devcmd1_orig = flash_rd_reg(chip, MSM_NAND_DEV_CMD1);
- dma_buffer->data.devcmdvld_orig = flash_rd_reg(chip,
- MSM_NAND_DEV_CMD_VLD);
- while (cmd_set_count-- > 0) {
- cmd = dma_buffer->cmd;
- dma_buffer->data.devcmd1_mod = (dma_buffer->data.devcmd1_orig &
- 0xFFFFFF00) | (cmd_set_count
- ? FLASH_READ_ONFI_IDENTIFIER_COMMAND
- : FLASH_READ_ONFI_PARAMETERS_COMMAND);
- dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ;
- dma_buffer->data.addr0 = (page_address << 16) | (cmd_set_count
- ? FLASH_READ_ONFI_IDENTIFIER_ADDRESS
- : FLASH_READ_ONFI_PARAMETERS_ADDRESS);
- dma_buffer->data.addr1 = (page_address >> 16) & 0xFF;
- dma_buffer->data.cfg0 = (cmd_set_count
- ? MSM_NAND_CFG0_RAW_ONFI_IDENTIFIER
- : MSM_NAND_CFG0_RAW_ONFI_PARAM_INFO);
- dma_buffer->data.cfg1 = (cmd_set_count
- ? MSM_NAND_CFG1_RAW_ONFI_IDENTIFIER
- : MSM_NAND_CFG1_RAW_ONFI_PARAM_INFO);
- dma_buffer->data.sflash_bcfg_mod = 0x00000000;
- dma_buffer->data.devcmdvld_mod = (dma_buffer->
- data.devcmdvld_orig & 0xFFFFFFFE);
- dma_buffer->data.exec = 1;
- dma_buffer->data.flash_status = 0xeeeeeeee;
- /* Put the Nand ctlr in Async mode and disable SFlash ctlr */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.sflash_bcfg_mod);
- cmd->dst = MSM_NAND_SFLASHC_BURST_CFG;
- cmd->len = 4;
- cmd++;
- /* Block on cmd ready, & write CMD,ADDR0,ADDR1,CHIPSEL regs */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = MSM_NAND_FLASH_CMD;
- cmd->len = 12;
- cmd++;
- /* Configure the CFG0 and CFG1 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = MSM_NAND_DEV0_CFG0;
- cmd->len = 8;
- cmd++;
- /* Configure the DEV_CMD_VLD register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.devcmdvld_mod);
- cmd->dst = MSM_NAND_DEV_CMD_VLD;
- cmd->len = 4;
- cmd++;
- /* Configure the DEV_CMD1 register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.devcmd1_mod);
- cmd->dst = MSM_NAND_DEV_CMD1;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.exec);
- cmd->dst = MSM_NAND_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the two status registers */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_FLASH_STATUS;
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.flash_status);
- cmd->len = 4;
- cmd++;
- /* Read data block - valid only if status says success */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_FLASH_BUFFER;
- cmd->dst = (cmd_set_count ? dma_addr_identifier :
- dma_addr_param_info);
- cmd->len = (cmd_set_count ? ONFI_IDENTIFIER_LENGTH :
- ONFI_PARAM_INFO_LENGTH);
- cmd++;
- /* Restore the DEV_CMD1 register */
- cmd->cmd = 0 ;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.devcmd1_orig);
- cmd->dst = MSM_NAND_DEV_CMD1;
- cmd->len = 4;
- cmd++;
- /* Restore the DEV_CMD_VLD register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.devcmdvld_orig);
- cmd->dst = MSM_NAND_DEV_CMD_VLD;
- cmd->len = 4;
- cmd++;
- /* Restore the SFLASH_BURST_CONFIG register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.sflash_bcfg_orig);
- cmd->dst = MSM_NAND_SFLASHC_BURST_CFG;
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(11 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd)
- >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- /* Check for errors, protection violations etc */
- if (dma_buffer->data.flash_status & 0x110) {
- pr_info("MPU/OP error (0x%x) during "
- "ONFI probe\n",
- dma_buffer->data.flash_status);
- err = -EIO;
- break;
- }
- if (cmd_set_count) {
- onfi_param_page_ptr = (struct onfi_param_page *)
- (&(onfi_identifier_buf[0]));
- if (onfi_param_page_ptr->parameter_page_signature !=
- ONFI_PARAMETER_PAGE_SIGNATURE) {
- pr_info("ONFI probe : Found a non"
- "ONFI Compliant device \n");
- err = -EIO;
- break;
- }
- } else {
- for (crc_chk_count = 0; crc_chk_count <
- ONFI_PARAM_INFO_LENGTH
- / ONFI_PARAM_PAGE_LENGTH;
- crc_chk_count++) {
- onfi_param_page_ptr =
- (struct onfi_param_page *)
- (&(onfi_param_info_buf
- [ONFI_PARAM_PAGE_LENGTH *
- crc_chk_count]));
- if (flash_onfi_crc_check(
- (uint8_t *)onfi_param_page_ptr,
- ONFI_PARAM_PAGE_LENGTH - 2) ==
- onfi_param_page_ptr->integrity_crc) {
- break;
- }
- }
- if (crc_chk_count >= ONFI_PARAM_INFO_LENGTH
- / ONFI_PARAM_PAGE_LENGTH) {
- pr_info("ONFI probe : CRC Check "
- "failed on ONFI Parameter "
- "data \n");
- err = -EIO;
- break;
- } else {
- supported_flash.flash_id =
- flash_read_id(chip);
- supported_flash.widebus =
- onfi_param_page_ptr->
- features_supported & 0x01;
- supported_flash.pagesize =
- onfi_param_page_ptr->
- number_of_data_bytes_per_page;
- supported_flash.blksize =
- onfi_param_page_ptr->
- number_of_pages_per_block *
- supported_flash.pagesize;
- supported_flash.oobsize =
- onfi_param_page_ptr->
- number_of_spare_bytes_per_page;
- supported_flash.density =
- onfi_param_page_ptr->
- number_of_blocks_per_logical_unit
- * supported_flash.blksize;
- supported_flash.ecc_correctability =
- onfi_param_page_ptr->
- number_of_bits_ecc_correctability;
- pr_info("ONFI probe : Found an ONFI "
- "compliant device %s\n",
- onfi_param_page_ptr->device_model);
- /* Temporary hack for MT29F4G08ABC device.
- * Since the device is not properly adhering
- * to ONFi specification it is reporting
- * as 16 bit device though it is 8 bit device!!!
- */
- if (!strncmp(onfi_param_page_ptr->device_model,
- "MT29F4G08ABC", 12))
- supported_flash.widebus = 0;
- }
- }
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- msm_nand_release_dma_buffer(chip, onfi_param_info_buf,
- ONFI_PARAM_INFO_LENGTH);
- msm_nand_release_dma_buffer(chip, onfi_identifier_buf,
- ONFI_IDENTIFIER_LENGTH);
- return err;
- }
- static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[8 * 5 + 2];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t addr0;
- uint32_t addr1;
- uint32_t chipsel;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t eccbchcfg;
- uint32_t exec;
- uint32_t ecccfg;
- struct {
- uint32_t flash_status;
- uint32_t buffer_status;
- } result[8];
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- unsigned n;
- unsigned page = 0;
- uint32_t oob_len;
- uint32_t sectordatasize;
- uint32_t sectoroobsize;
- int err, pageerr, rawerr;
- dma_addr_t data_dma_addr = 0;
- dma_addr_t oob_dma_addr = 0;
- dma_addr_t data_dma_addr_curr = 0;
- dma_addr_t oob_dma_addr_curr = 0;
- uint32_t oob_col = 0;
- unsigned page_count;
- unsigned pages_read = 0;
- unsigned start_sector = 0;
- uint32_t ecc_errors;
- uint32_t total_ecc_errors = 0;
- unsigned cwperpage;
- #if VERBOSE
- pr_info("================================================="
- "================\n");
- pr_info("%s:\nfrom 0x%llx mode %d\ndatbuf 0x%p datlen 0x%x"
- "\noobbuf 0x%p ooblen 0x%x\n",
- __func__, from, ops->mode, ops->datbuf, ops->len,
- ops->oobbuf, ops->ooblen);
- #endif
- if (mtd->writesize == 2048)
- page = from >> 11;
- if (mtd->writesize == 4096)
- page = from >> 12;
- oob_len = ops->ooblen;
- cwperpage = (mtd->writesize >> 9);
- if (from & (mtd->writesize - 1)) {
- pr_err("%s: unsupported from, 0x%llx\n",
- __func__, from);
- return -EINVAL;
- }
- if (ops->mode != MTD_OPS_RAW) {
- if (ops->datbuf != NULL && (ops->len % mtd->writesize) != 0) {
- /* when ops->datbuf is NULL, ops->len can be ooblen */
- pr_err("%s: unsupported ops->len, %d\n",
- __func__, ops->len);
- return -EINVAL;
- }
- } else {
- if (ops->datbuf != NULL &&
- (ops->len % (mtd->writesize + mtd->oobsize)) != 0) {
- pr_err("%s: unsupported ops->len,"
- " %d for MTD_OPS_RAW\n", __func__, ops->len);
- return -EINVAL;
- }
- }
- if (ops->mode != MTD_OPS_RAW && ops->ooblen != 0 && ops->ooboffs != 0) {
- pr_err("%s: unsupported ops->ooboffs, %d\n",
- __func__, ops->ooboffs);
- return -EINVAL;
- }
- if (ops->oobbuf && !ops->datbuf && ops->mode == MTD_OPS_AUTO_OOB)
- start_sector = cwperpage - 1;
- if (ops->oobbuf && !ops->datbuf) {
- page_count = ops->ooblen / ((ops->mode == MTD_OPS_AUTO_OOB) ?
- mtd->oobavail : mtd->oobsize);
- if ((page_count == 0) && (ops->ooblen))
- page_count = 1;
- } else if (ops->mode != MTD_OPS_RAW)
- page_count = ops->len / mtd->writesize;
- else
- page_count = ops->len / (mtd->writesize + mtd->oobsize);
- if (ops->datbuf) {
- data_dma_addr_curr = data_dma_addr =
- msm_nand_dma_map(chip->dev, ops->datbuf, ops->len,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(chip->dev, data_dma_addr)) {
- pr_err("msm_nand_read_oob: failed to get dma addr "
- "for %p\n", ops->datbuf);
- return -EIO;
- }
- }
- if (ops->oobbuf) {
- memset(ops->oobbuf, 0xff, ops->ooblen);
- oob_dma_addr_curr = oob_dma_addr =
- msm_nand_dma_map(chip->dev, ops->oobbuf,
- ops->ooblen, DMA_BIDIRECTIONAL);
- if (dma_mapping_error(chip->dev, oob_dma_addr)) {
- pr_err("msm_nand_read_oob: failed to get dma addr "
- "for %p\n", ops->oobbuf);
- err = -EIO;
- goto err_dma_map_oobbuf_failed;
- }
- }
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(
- chip, sizeof(*dma_buffer))));
- oob_col = start_sector * chip->cw_size;
- if (chip->CFG1 & CFG1_WIDE_FLASH)
- oob_col >>= 1;
- err = 0;
- while (page_count-- > 0) {
- cmd = dma_buffer->cmd;
- /* CMD / ADDR0 / ADDR1 / CHIPSEL program values */
- if (ops->mode != MTD_OPS_RAW) {
- dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ_ECC;
- dma_buffer->data.cfg0 =
- (chip->CFG0 & ~(7U << 6))
- | (((cwperpage-1) - start_sector) << 6);
- dma_buffer->data.cfg1 = chip->CFG1;
- if (enable_bch_ecc)
- dma_buffer->data.eccbchcfg = chip->ecc_bch_cfg;
- } else {
- dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ;
- dma_buffer->data.cfg0 = (chip->CFG0_RAW
- & ~(7U << 6)) | ((cwperpage-1) << 6);
- dma_buffer->data.cfg1 = chip->CFG1_RAW |
- (chip->CFG1 & CFG1_WIDE_FLASH);
- }
- dma_buffer->data.addr0 = (page << 16) | oob_col;
- dma_buffer->data.addr1 = (page >> 16) & 0xff;
- /* chipsel_0 + enable DM interface */
- dma_buffer->data.chipsel = 0 | 4;
- /* GO bit for the EXEC register */
- dma_buffer->data.exec = 1;
- BUILD_BUG_ON(8 != ARRAY_SIZE(dma_buffer->data.result));
- for (n = start_sector; n < cwperpage; n++) {
- /* flash + buffer status return words */
- dma_buffer->data.result[n].flash_status = 0xeeeeeeee;
- dma_buffer->data.result[n].buffer_status = 0xeeeeeeee;
- /* block on cmd ready, then
- * write CMD / ADDR0 / ADDR1 / CHIPSEL
- * regs in a burst
- */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = MSM_NAND_FLASH_CMD;
- if (n == start_sector)
- cmd->len = 16;
- else
- cmd->len = 4;
- cmd++;
- if (n == start_sector) {
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = MSM_NAND_DEV0_CFG0;
- if (enable_bch_ecc)
- cmd->len = 12;
- else
- cmd->len = 8;
- cmd++;
- dma_buffer->data.ecccfg = chip->ecc_buf_cfg;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.ecccfg);
- cmd->dst = MSM_NAND_EBI2_ECC_BUF_CFG;
- cmd->len = 4;
- cmd++;
- }
- /* kick the execute register */
- cmd->cmd = 0;
- cmd->src =
- msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = MSM_NAND_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* block on data ready, then
- * read the status register
- */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_FLASH_STATUS;
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.result[n]);
- /* MSM_NAND_FLASH_STATUS + MSM_NAND_BUFFER_STATUS */
- cmd->len = 8;
- cmd++;
- /* read data block
- * (only valid if status says success)
- */
- if (ops->datbuf) {
- if (ops->mode != MTD_OPS_RAW)
- sectordatasize = (n < (cwperpage - 1))
- ? 516 : (512 - ((cwperpage - 1) << 2));
- else
- sectordatasize = chip->cw_size;
- cmd->cmd = 0;
- cmd->src = MSM_NAND_FLASH_BUFFER;
- cmd->dst = data_dma_addr_curr;
- data_dma_addr_curr += sectordatasize;
- cmd->len = sectordatasize;
- cmd++;
- }
- if (ops->oobbuf && (n == (cwperpage - 1)
- || ops->mode != MTD_OPS_AUTO_OOB)) {
- cmd->cmd = 0;
- if (n == (cwperpage - 1)) {
- cmd->src = MSM_NAND_FLASH_BUFFER +
- (512 - ((cwperpage - 1) << 2));
- sectoroobsize = (cwperpage << 2);
- if (ops->mode != MTD_OPS_AUTO_OOB)
- sectoroobsize +=
- chip->ecc_parity_bytes;
- } else {
- cmd->src = MSM_NAND_FLASH_BUFFER + 516;
- sectoroobsize = chip->ecc_parity_bytes;
- }
- cmd->dst = oob_dma_addr_curr;
- if (sectoroobsize < oob_len)
- cmd->len = sectoroobsize;
- else
- cmd->len = oob_len;
- oob_dma_addr_curr += cmd->len;
- oob_len -= cmd->len;
- if (cmd->len > 0)
- cmd++;
- }
- }
- BUILD_BUG_ON(8 * 5 + 2 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr =
- (msm_virt_to_dma(chip, dma_buffer->cmd) >> 3)
- | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- /* if any of the writes failed (0x10), or there
- * was a protection violation (0x100), we lose
- */
- pageerr = rawerr = 0;
- for (n = start_sector; n < cwperpage; n++) {
- if (dma_buffer->data.result[n].flash_status & 0x110) {
- rawerr = -EIO;
- break;
- }
- }
- if (rawerr) {
- if (ops->datbuf && ops->mode != MTD_OPS_RAW) {
- uint8_t *datbuf = ops->datbuf +
- pages_read * mtd->writesize;
- dma_sync_single_for_cpu(chip->dev,
- data_dma_addr_curr-mtd->writesize,
- mtd->writesize, DMA_BIDIRECTIONAL);
- for (n = 0; n < mtd->writesize; n++) {
- /* empty blocks read 0x54 at
- * these offsets
- */
- if ((n % 516 == 3 || n % 516 == 175)
- && datbuf[n] == 0x54)
- datbuf[n] = 0xff;
- if (datbuf[n] != 0xff) {
- pageerr = rawerr;
- break;
- }
- }
- dma_sync_single_for_device(chip->dev,
- data_dma_addr_curr-mtd->writesize,
- mtd->writesize, DMA_BIDIRECTIONAL);
- }
- if (ops->oobbuf) {
- dma_sync_single_for_cpu(chip->dev,
- oob_dma_addr_curr - (ops->ooblen - oob_len),
- ops->ooblen - oob_len, DMA_BIDIRECTIONAL);
- for (n = 0; n < ops->ooblen; n++) {
- if (ops->oobbuf[n] != 0xff) {
- pageerr = rawerr;
- break;
- }
- }
- dma_sync_single_for_device(chip->dev,
- oob_dma_addr_curr - (ops->ooblen - oob_len),
- ops->ooblen - oob_len, DMA_BIDIRECTIONAL);
- }
- }
- if (pageerr) {
- for (n = start_sector; n < cwperpage; n++) {
- if (dma_buffer->data.result[n].buffer_status &
- chip->uncorrectable_bit_mask) {
- /* not thread safe */
- mtd->ecc_stats.failed++;
- pageerr = -EBADMSG;
- break;
- }
- }
- }
- if (!rawerr) { /* check for corretable errors */
- for (n = start_sector; n < cwperpage; n++) {
- ecc_errors =
- (dma_buffer->data.result[n].buffer_status
- & chip->num_err_mask);
- if (ecc_errors) {
- total_ecc_errors += ecc_errors;
- /* not thread safe */
- mtd->ecc_stats.corrected += ecc_errors;
- if (ecc_errors > 1)
- pageerr = -EUCLEAN;
- }
- }
- }
- if (pageerr && (pageerr != -EUCLEAN || err == 0))
- err = pageerr;
- #if VERBOSE
- if (rawerr && !pageerr) {
- pr_err("msm_nand_read_oob %llx %x %x empty page\n",
- (loff_t)page * mtd->writesize, ops->len,
- ops->ooblen);
- } else {
- for (n = start_sector; n < cwperpage; n++)
- pr_info("flash_status[%d] = %x,\
- buffr_status[%d] = %x\n",
- n, dma_buffer->data.result[n].flash_status,
- n, dma_buffer->data.result[n].buffer_status);
- }
- #endif
- if (err && err != -EUCLEAN && err != -EBADMSG)
- break;
- pages_read++;
- page++;
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- if (ops->oobbuf) {
- dma_unmap_page(chip->dev, oob_dma_addr,
- ops->ooblen, DMA_FROM_DEVICE);
- }
- err_dma_map_oobbuf_failed:
- if (ops->datbuf) {
- dma_unmap_page(chip->dev, data_dma_addr,
- ops->len, DMA_BIDIRECTIONAL);
- }
- if (ops->mode != MTD_OPS_RAW)
- ops->retlen = mtd->writesize * pages_read;
- else
- ops->retlen = (mtd->writesize + mtd->oobsize) *
- pages_read;
- ops->oobretlen = ops->ooblen - oob_len;
- if (err)
- pr_err("msm_nand_read_oob %llx %x %x failed %d, corrected %d\n",
- from, ops->datbuf ? ops->len : 0, ops->ooblen, err,
- total_ecc_errors);
- #if VERBOSE
- pr_info("\n%s: ret %d, retlen %d oobretlen %d\n",
- __func__, err, ops->retlen, ops->oobretlen);
- pr_info("==================================================="
- "==============\n");
- #endif
- return err;
- }
- static int msm_nand_read_oob_dualnandc(struct mtd_info *mtd, loff_t from,
- struct mtd_oob_ops *ops)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[16 * 6 + 20];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t nandc01_addr0;
- uint32_t nandc10_addr0;
- uint32_t nandc11_addr1;
- uint32_t chipsel_cs0;
- uint32_t chipsel_cs1;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t eccbchcfg;
- uint32_t exec;
- uint32_t ecccfg;
- uint32_t ebi2_chip_select_cfg0;
- uint32_t adm_mux_data_ack_req_nc01;
- uint32_t adm_mux_cmd_ack_req_nc01;
- uint32_t adm_mux_data_ack_req_nc10;
- uint32_t adm_mux_cmd_ack_req_nc10;
- uint32_t adm_default_mux;
- uint32_t default_ebi2_chip_select_cfg0;
- uint32_t nc10_flash_dev_cmd_vld;
- uint32_t nc10_flash_dev_cmd1;
- uint32_t nc10_flash_dev_cmd_vld_default;
- uint32_t nc10_flash_dev_cmd1_default;
- struct {
- uint32_t flash_status;
- uint32_t buffer_status;
- } result[16];
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- unsigned n;
- unsigned page = 0;
- uint32_t oob_len;
- uint32_t sectordatasize;
- uint32_t sectoroobsize;
- int err, pageerr, rawerr;
- dma_addr_t data_dma_addr = 0;
- dma_addr_t oob_dma_addr = 0;
- dma_addr_t data_dma_addr_curr = 0;
- dma_addr_t oob_dma_addr_curr = 0;
- uint32_t oob_col = 0;
- unsigned page_count;
- unsigned pages_read = 0;
- unsigned start_sector = 0;
- uint32_t ecc_errors;
- uint32_t total_ecc_errors = 0;
- unsigned cwperpage;
- unsigned cw_offset = chip->cw_size;
- #if VERBOSE
- pr_info("================================================="
- "============\n");
- pr_info("%s:\nfrom 0x%llx mode %d\ndatbuf 0x%p datlen 0x%x"
- "\noobbuf 0x%p ooblen 0x%x\n\n",
- __func__, from, ops->mode, ops->datbuf,
- ops->len, ops->oobbuf, ops->ooblen);
- #endif
- if (mtd->writesize == 2048)
- page = from >> 11;
- if (mtd->writesize == 4096)
- page = from >> 12;
- if (interleave_enable)
- page = (from >> 1) >> 12;
- oob_len = ops->ooblen;
- cwperpage = (mtd->writesize >> 9);
- if (from & (mtd->writesize - 1)) {
- pr_err("%s: unsupported from, 0x%llx\n",
- __func__, from);
- return -EINVAL;
- }
- if (ops->mode != MTD_OPS_RAW) {
- if (ops->datbuf != NULL && (ops->len % mtd->writesize) != 0) {
- pr_err("%s: unsupported ops->len, %d\n",
- __func__, ops->len);
- return -EINVAL;
- }
- } else {
- if (ops->datbuf != NULL &&
- (ops->len % (mtd->writesize + mtd->oobsize)) != 0) {
- pr_err("%s: unsupported ops->len,"
- " %d for MTD_OPS_RAW\n", __func__, ops->len);
- return -EINVAL;
- }
- }
- if (ops->mode != MTD_OPS_RAW && ops->ooblen != 0 && ops->ooboffs != 0) {
- pr_err("%s: unsupported ops->ooboffs, %d\n",
- __func__, ops->ooboffs);
- return -EINVAL;
- }
- if (ops->oobbuf && !ops->datbuf && ops->mode == MTD_OPS_AUTO_OOB)
- start_sector = cwperpage - 1;
- if (ops->oobbuf && !ops->datbuf) {
- page_count = ops->ooblen / ((ops->mode == MTD_OPS_AUTO_OOB) ?
- mtd->oobavail : mtd->oobsize);
- if ((page_count == 0) && (ops->ooblen))
- page_count = 1;
- } else if (ops->mode != MTD_OPS_RAW)
- page_count = ops->len / mtd->writesize;
- else
- page_count = ops->len / (mtd->writesize + mtd->oobsize);
- if (ops->datbuf) {
- data_dma_addr_curr = data_dma_addr =
- msm_nand_dma_map(chip->dev, ops->datbuf, ops->len,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(chip->dev, data_dma_addr)) {
- pr_err("msm_nand_read_oob_dualnandc: "
- "failed to get dma addr for %p\n",
- ops->datbuf);
- return -EIO;
- }
- }
- if (ops->oobbuf) {
- memset(ops->oobbuf, 0xff, ops->ooblen);
- oob_dma_addr_curr = oob_dma_addr =
- msm_nand_dma_map(chip->dev, ops->oobbuf,
- ops->ooblen, DMA_BIDIRECTIONAL);
- if (dma_mapping_error(chip->dev, oob_dma_addr)) {
- pr_err("msm_nand_read_oob_dualnandc: "
- "failed to get dma addr for %p\n",
- ops->oobbuf);
- err = -EIO;
- goto err_dma_map_oobbuf_failed;
- }
- }
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(
- chip, sizeof(*dma_buffer))));
- oob_col = start_sector * chip->cw_size;
- if (chip->CFG1 & CFG1_WIDE_FLASH) {
- oob_col >>= 1;
- cw_offset >>= 1;
- }
- err = 0;
- while (page_count-- > 0) {
- cmd = dma_buffer->cmd;
- if (ops->mode != MTD_OPS_RAW) {
- dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ_ECC;
- if (start_sector == (cwperpage - 1)) {
- dma_buffer->data.cfg0 = (chip->CFG0 &
- ~(7U << 6));
- } else {
- dma_buffer->data.cfg0 = (chip->CFG0 &
- ~(7U << 6))
- | (((cwperpage >> 1)-1) << 6);
- }
- dma_buffer->data.cfg1 = chip->CFG1;
- if (enable_bch_ecc)
- dma_buffer->data.eccbchcfg = chip->ecc_bch_cfg;
- } else {
- dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ;
- dma_buffer->data.cfg0 = ((chip->CFG0_RAW &
- ~(7U << 6)) | ((((cwperpage >> 1)-1) << 6)));
- dma_buffer->data.cfg1 = chip->CFG1_RAW |
- (chip->CFG1 & CFG1_WIDE_FLASH);
- }
- if (!interleave_enable) {
- if (start_sector == (cwperpage - 1)) {
- dma_buffer->data.nandc10_addr0 =
- (page << 16) | oob_col;
- dma_buffer->data.nc10_flash_dev_cmd_vld = 0xD;
- dma_buffer->data.nc10_flash_dev_cmd1 =
- 0xF00F3000;
- } else {
- dma_buffer->data.nandc01_addr0 = page << 16;
- /* NC10 ADDR0 points to the next code word */
- dma_buffer->data.nandc10_addr0 = (page << 16) |
- cw_offset;
- dma_buffer->data.nc10_flash_dev_cmd_vld = 0x1D;
- dma_buffer->data.nc10_flash_dev_cmd1 =
- 0xF00FE005;
- }
- } else {
- dma_buffer->data.nandc01_addr0 =
- dma_buffer->data.nandc10_addr0 =
- (page << 16) | oob_col;
- }
- /* ADDR1 */
- dma_buffer->data.nandc11_addr1 = (page >> 16) & 0xff;
- dma_buffer->data.adm_mux_data_ack_req_nc01 = 0x00000A3C;
- dma_buffer->data.adm_mux_cmd_ack_req_nc01 = 0x0000053C;
- dma_buffer->data.adm_mux_data_ack_req_nc10 = 0x00000F28;
- dma_buffer->data.adm_mux_cmd_ack_req_nc10 = 0x00000F14;
- dma_buffer->data.adm_default_mux = 0x00000FC0;
- dma_buffer->data.nc10_flash_dev_cmd_vld_default = 0x1D;
- dma_buffer->data.nc10_flash_dev_cmd1_default = 0xF00F3000;
- dma_buffer->data.ebi2_chip_select_cfg0 = 0x00000805;
- dma_buffer->data.default_ebi2_chip_select_cfg0 = 0x00000801;
- /* chipsel_0 + enable DM interface */
- dma_buffer->data.chipsel_cs0 = (1<<4) | 4;
- /* chipsel_1 + enable DM interface */
- dma_buffer->data.chipsel_cs1 = (1<<4) | 5;
- /* GO bit for the EXEC register */
- dma_buffer->data.exec = 1;
- BUILD_BUG_ON(16 != ARRAY_SIZE(dma_buffer->data.result));
- for (n = start_sector; n < cwperpage; n++) {
- /* flash + buffer status return words */
- dma_buffer->data.result[n].flash_status = 0xeeeeeeee;
- dma_buffer->data.result[n].buffer_status = 0xeeeeeeee;
- if (n == start_sector) {
- if (!interleave_enable) {
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.nc10_flash_dev_cmd_vld);
- cmd->dst = NC10(MSM_NAND_DEV_CMD_VLD);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nc10_flash_dev_cmd1);
- cmd->dst = NC10(MSM_NAND_DEV_CMD1);
- cmd->len = 4;
- cmd++;
- /* NC01, NC10 --> ADDR1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc11_addr1);
- cmd->dst = NC11(MSM_NAND_ADDR1);
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = NC11(MSM_NAND_DEV0_CFG0);
- if (enable_bch_ecc)
- cmd->len = 12;
- else
- cmd->len = 8;
- cmd++;
- } else {
- /* enable CS0 & CS1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.ebi2_chip_select_cfg0);
- cmd->dst = EBI2_CHIP_SELECT_CFG0;
- cmd->len = 4;
- cmd++;
- /* NC01, NC10 --> ADDR1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc11_addr1);
- cmd->dst = NC11(MSM_NAND_ADDR1);
- cmd->len = 4;
- cmd++;
- /* Enable CS0 for NC01 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.chipsel_cs0);
- cmd->dst =
- NC01(MSM_NAND_FLASH_CHIP_SELECT);
- cmd->len = 4;
- cmd++;
- /* Enable CS1 for NC10 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.chipsel_cs1);
- cmd->dst =
- NC10(MSM_NAND_FLASH_CHIP_SELECT);
- cmd->len = 4;
- cmd++;
- /* config DEV0_CFG0 & CFG1 for CS0 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = NC01(MSM_NAND_DEV0_CFG0);
- cmd->len = 8;
- cmd++;
- /* config DEV1_CFG0 & CFG1 for CS1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = NC10(MSM_NAND_DEV1_CFG0);
- cmd->len = 8;
- cmd++;
- }
- dma_buffer->data.ecccfg = chip->ecc_buf_cfg;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.ecccfg);
- cmd->dst = NC11(MSM_NAND_EBI2_ECC_BUF_CFG);
- cmd->len = 4;
- cmd++;
- /* if 'only' the last code word */
- if (n == cwperpage - 1) {
- /* MASK CMD ACK/REQ --> NC01 (0x53C)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.adm_mux_cmd_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* CMD */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cmd);
- cmd->dst = NC10(MSM_NAND_FLASH_CMD);
- cmd->len = 4;
- cmd++;
- /* NC10 --> ADDR0 ( 0x0 ) */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc10_addr0);
- cmd->dst = NC10(MSM_NAND_ADDR0);
- cmd->len = 4;
- cmd++;
- /* kick the execute reg for NC10 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.exec);
- cmd->dst = NC10(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- /* MASK DATA ACK/REQ --> NC01 (0xA3C)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.adm_mux_data_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* block on data ready from NC10, then
- * read the status register
- */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC10(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.result[n]);
- /* MSM_NAND_FLASH_STATUS +
- * MSM_NAND_BUFFER_STATUS
- */
- cmd->len = 8;
- cmd++;
- } else {
- /* NC01 --> ADDR0 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc01_addr0);
- cmd->dst = NC01(MSM_NAND_ADDR0);
- cmd->len = 4;
- cmd++;
- /* NC10 --> ADDR1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc10_addr0);
- cmd->dst = NC10(MSM_NAND_ADDR0);
- cmd->len = 4;
- cmd++;
- /* MASK CMD ACK/REQ --> NC10 (0xF14)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.adm_mux_cmd_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* CMD */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cmd);
- cmd->dst = NC01(MSM_NAND_FLASH_CMD);
- cmd->len = 4;
- cmd++;
- /* kick the execute register for NC01*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.exec);
- cmd->dst = NC01(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- }
- }
- /* read data block
- * (only valid if status says success)
- */
- if (ops->datbuf || (ops->oobbuf &&
- ops->mode != MTD_OPS_AUTO_OOB)) {
- if (ops->mode != MTD_OPS_RAW)
- sectordatasize = (n < (cwperpage - 1))
- ? 516 : (512 - ((cwperpage - 1) << 2));
- else
- sectordatasize = chip->cw_size;
- if (n % 2 == 0) {
- /* MASK DATA ACK/REQ --> NC10 (0xF28)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.adm_mux_data_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* block on data ready from NC01, then
- * read the status register
- */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC01(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.result[n]);
- /* MSM_NAND_FLASH_STATUS +
- * MSM_NAND_BUFFER_STATUS
- */
- cmd->len = 8;
- cmd++;
- /* MASK CMD ACK/REQ --> NC01 (0x53C)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.adm_mux_cmd_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* CMD */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cmd);
- cmd->dst = NC10(MSM_NAND_FLASH_CMD);
- cmd->len = 4;
- cmd++;
- /* kick the execute register for NC10 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.exec);
- cmd->dst = NC10(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- /* Read only when there is data
- * buffer
- */
- if (ops->datbuf) {
- cmd->cmd = 0;
- cmd->src =
- NC01(MSM_NAND_FLASH_BUFFER);
- cmd->dst = data_dma_addr_curr;
- data_dma_addr_curr +=
- sectordatasize;
- cmd->len = sectordatasize;
- cmd++;
- }
- } else {
- /* MASK DATA ACK/REQ -->
- * NC01 (0xA3C)
- */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.adm_mux_data_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* block on data ready from NC10
- * then read the status register
- */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src =
- NC10(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.result[n]);
- /* MSM_NAND_FLASH_STATUS +
- * MSM_NAND_BUFFER_STATUS
- */
- cmd->len = 8;
- cmd++;
- if (n != cwperpage - 1) {
- /* MASK CMD ACK/REQ -->
- * NC10 (0xF14)
- */
- cmd->cmd = 0;
- cmd->src =
- msm_virt_to_dma(chip,
- &dma_buffer->
- data.adm_mux_cmd_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* CMD */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cmd);
- cmd->dst =
- NC01(MSM_NAND_FLASH_CMD);
- cmd->len = 4;
- cmd++;
- /* EXEC */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.exec);
- cmd->dst =
- NC01(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- }
- /* Read only when there is data
- * buffer
- */
- if (ops->datbuf) {
- cmd->cmd = 0;
- cmd->src =
- NC10(MSM_NAND_FLASH_BUFFER);
- cmd->dst = data_dma_addr_curr;
- data_dma_addr_curr +=
- sectordatasize;
- cmd->len = sectordatasize;
- cmd++;
- }
- }
- }
- if (ops->oobbuf && (n == (cwperpage - 1)
- || ops->mode != MTD_OPS_AUTO_OOB)) {
- cmd->cmd = 0;
- if (n == (cwperpage - 1)) {
- /* Use NC10 for reading the
- * last codeword!!!
- */
- cmd->src = NC10(MSM_NAND_FLASH_BUFFER) +
- (512 - ((cwperpage - 1) << 2));
- sectoroobsize = (cwperpage << 2);
- if (ops->mode != MTD_OPS_AUTO_OOB)
- sectoroobsize +=
- chip->ecc_parity_bytes;
- } else {
- if (n % 2 == 0)
- cmd->src =
- NC01(MSM_NAND_FLASH_BUFFER)
- + 516;
- else
- cmd->src =
- NC10(MSM_NAND_FLASH_BUFFER)
- + 516;
- sectoroobsize = chip->ecc_parity_bytes;
- }
- cmd->dst = oob_dma_addr_curr;
- if (sectoroobsize < oob_len)
- cmd->len = sectoroobsize;
- else
- cmd->len = oob_len;
- oob_dma_addr_curr += cmd->len;
- oob_len -= cmd->len;
- if (cmd->len > 0)
- cmd++;
- }
- }
- /* ADM --> Default mux state (0xFC0) */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_default_mux);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- if (!interleave_enable) {
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nc10_flash_dev_cmd_vld_default);
- cmd->dst = NC10(MSM_NAND_DEV_CMD_VLD);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nc10_flash_dev_cmd1_default);
- cmd->dst = NC10(MSM_NAND_DEV_CMD1);
- cmd->len = 4;
- cmd++;
- } else {
- /* disable CS1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.default_ebi2_chip_select_cfg0);
- cmd->dst = EBI2_CHIP_SELECT_CFG0;
- cmd->len = 4;
- cmd++;
- }
- BUILD_BUG_ON(16 * 6 + 20 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr =
- (msm_virt_to_dma(chip, dma_buffer->cmd) >> 3)
- | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- /* if any of the writes failed (0x10), or there
- * was a protection violation (0x100), we lose
- */
- pageerr = rawerr = 0;
- for (n = start_sector; n < cwperpage; n++) {
- if (dma_buffer->data.result[n].flash_status & 0x110) {
- rawerr = -EIO;
- break;
- }
- }
- if (rawerr) {
- if (ops->datbuf && ops->mode != MTD_OPS_RAW) {
- uint8_t *datbuf = ops->datbuf +
- pages_read * mtd->writesize;
- dma_sync_single_for_cpu(chip->dev,
- data_dma_addr_curr-mtd->writesize,
- mtd->writesize, DMA_BIDIRECTIONAL);
- for (n = 0; n < mtd->writesize; n++) {
- /* empty blocks read 0x54 at
- * these offsets
- */
- if ((n % 516 == 3 || n % 516 == 175)
- && datbuf[n] == 0x54)
- datbuf[n] = 0xff;
- if (datbuf[n] != 0xff) {
- pageerr = rawerr;
- break;
- }
- }
- dma_sync_single_for_device(chip->dev,
- data_dma_addr_curr-mtd->writesize,
- mtd->writesize, DMA_BIDIRECTIONAL);
- }
- if (ops->oobbuf) {
- dma_sync_single_for_cpu(chip->dev,
- oob_dma_addr_curr - (ops->ooblen - oob_len),
- ops->ooblen - oob_len, DMA_BIDIRECTIONAL);
- for (n = 0; n < ops->ooblen; n++) {
- if (ops->oobbuf[n] != 0xff) {
- pageerr = rawerr;
- break;
- }
- }
- dma_sync_single_for_device(chip->dev,
- oob_dma_addr_curr - (ops->ooblen - oob_len),
- ops->ooblen - oob_len, DMA_BIDIRECTIONAL);
- }
- }
- if (pageerr) {
- for (n = start_sector; n < cwperpage; n++) {
- if (dma_buffer->data.result[n].buffer_status
- & chip->uncorrectable_bit_mask) {
- /* not thread safe */
- mtd->ecc_stats.failed++;
- pageerr = -EBADMSG;
- break;
- }
- }
- }
- if (!rawerr) { /* check for corretable errors */
- for (n = start_sector; n < cwperpage; n++) {
- ecc_errors = dma_buffer->data.
- result[n].buffer_status
- & chip->num_err_mask;
- if (ecc_errors) {
- total_ecc_errors += ecc_errors;
- /* not thread safe */
- mtd->ecc_stats.corrected += ecc_errors;
- if (ecc_errors > 1)
- pageerr = -EUCLEAN;
- }
- }
- }
- if (pageerr && (pageerr != -EUCLEAN || err == 0))
- err = pageerr;
- #if VERBOSE
- if (rawerr && !pageerr) {
- pr_err("msm_nand_read_oob_dualnandc "
- "%llx %x %x empty page\n",
- (loff_t)page * mtd->writesize, ops->len,
- ops->ooblen);
- } else {
- for (n = start_sector; n < cwperpage; n++) {
- if (n%2) {
- pr_info("NC10: flash_status[%d] = %x, "
- "buffr_status[%d] = %x\n",
- n, dma_buffer->
- data.result[n].flash_status,
- n, dma_buffer->
- data.result[n].buffer_status);
- } else {
- pr_info("NC01: flash_status[%d] = %x, "
- "buffr_status[%d] = %x\n",
- n, dma_buffer->
- data.result[n].flash_status,
- n, dma_buffer->
- data.result[n].buffer_status);
- }
- }
- }
- #endif
- if (err && err != -EUCLEAN && err != -EBADMSG)
- break;
- pages_read++;
- page++;
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- if (ops->oobbuf) {
- dma_unmap_page(chip->dev, oob_dma_addr,
- ops->ooblen, DMA_FROM_DEVICE);
- }
- err_dma_map_oobbuf_failed:
- if (ops->datbuf) {
- dma_unmap_page(chip->dev, data_dma_addr,
- ops->len, DMA_BIDIRECTIONAL);
- }
- if (ops->mode != MTD_OPS_RAW)
- ops->retlen = mtd->writesize * pages_read;
- else
- ops->retlen = (mtd->writesize + mtd->oobsize) *
- pages_read;
- ops->oobretlen = ops->ooblen - oob_len;
- if (err)
- pr_err("msm_nand_read_oob_dualnandc "
- "%llx %x %x failed %d, corrected %d\n",
- from, ops->datbuf ? ops->len : 0, ops->ooblen, err,
- total_ecc_errors);
- #if VERBOSE
- pr_info("\n%s: ret %d, retlen %d oobretlen %d\n",
- __func__, err, ops->retlen, ops->oobretlen);
- pr_info("==================================================="
- "==========\n");
- #endif
- return err;
- }
- static int
- msm_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
- {
- int ret;
- struct mtd_oob_ops ops;
- int (*read_oob)(struct mtd_info *, loff_t, struct mtd_oob_ops *);
- if (!dual_nand_ctlr_present)
- read_oob = msm_nand_read_oob;
- else
- read_oob = msm_nand_read_oob_dualnandc;
- ops.mode = MTD_OPS_PLACE_OOB;
- ops.retlen = 0;
- ops.ooblen = 0;
- ops.oobbuf = NULL;
- ret = 0;
- *retlen = 0;
- if ((from & (mtd->writesize - 1)) == 0 && len == mtd->writesize) {
- /* reading a page on page boundary */
- ops.len = len;
- ops.datbuf = buf;
- ret = read_oob(mtd, from, &ops);
- *retlen = ops.retlen;
- } else if (len > 0) {
- /* reading any size on any offset. partial page is supported */
- u8 *bounce_buf;
- loff_t aligned_from;
- loff_t offset;
- size_t actual_len;
- bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
- if (!bounce_buf) {
- pr_err("%s: could not allocate memory\n", __func__);
- ret = -ENOMEM;
- goto out;
- }
- ops.len = mtd->writesize;
- offset = from & (mtd->writesize - 1);
- aligned_from = from - offset;
- for (;;) {
- int no_copy;
- actual_len = mtd->writesize - offset;
- if (actual_len > len)
- actual_len = len;
- no_copy = (offset == 0 && actual_len == mtd->writesize);
- ops.datbuf = (no_copy) ? buf : bounce_buf;
- ret = read_oob(mtd, aligned_from, &ops);
- if (ret < 0)
- break;
- if (!no_copy)
- memcpy(buf, bounce_buf + offset, actual_len);
- len -= actual_len;
- *retlen += actual_len;
- if (len == 0)
- break;
- buf += actual_len;
- offset = 0;
- aligned_from += mtd->writesize;
- }
- kfree(bounce_buf);
- }
- out:
- return ret;
- }
- static int
- msm_nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[8 * 7 + 2];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t addr0;
- uint32_t addr1;
- uint32_t chipsel;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t eccbchcfg;
- uint32_t exec;
- uint32_t ecccfg;
- uint32_t clrfstatus;
- uint32_t clrrstatus;
- uint32_t flash_status[8];
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- unsigned n;
- unsigned page = 0;
- uint32_t oob_len;
- uint32_t sectordatawritesize;
- int err = 0;
- dma_addr_t data_dma_addr = 0;
- dma_addr_t oob_dma_addr = 0;
- dma_addr_t data_dma_addr_curr = 0;
- dma_addr_t oob_dma_addr_curr = 0;
- unsigned page_count;
- unsigned pages_written = 0;
- unsigned cwperpage;
- #if VERBOSE
- pr_info("================================================="
- "================\n");
- pr_info("%s:\nto 0x%llx mode %d\ndatbuf 0x%p datlen 0x%x"
- "\noobbuf 0x%p ooblen 0x%x\n",
- __func__, to, ops->mode, ops->datbuf, ops->len,
- ops->oobbuf, ops->ooblen);
- #endif
- if (mtd->writesize == 2048)
- page = to >> 11;
- if (mtd->writesize == 4096)
- page = to >> 12;
- oob_len = ops->ooblen;
- cwperpage = (mtd->writesize >> 9);
- if (to & (mtd->writesize - 1)) {
- pr_err("%s: unsupported to, 0x%llx\n", __func__, to);
- return -EINVAL;
- }
- if (ops->mode != MTD_OPS_RAW) {
- if (ops->ooblen != 0 && ops->mode != MTD_OPS_AUTO_OOB) {
- pr_err("%s: unsupported ops->mode,%d\n",
- __func__, ops->mode);
- return -EINVAL;
- }
- if ((ops->len % mtd->writesize) != 0) {
- pr_err("%s: unsupported ops->len, %d\n",
- __func__, ops->len);
- return -EINVAL;
- }
- } else {
- if ((ops->len % (mtd->writesize + mtd->oobsize)) != 0) {
- pr_err("%s: unsupported ops->len, "
- "%d for MTD_OPS_RAW mode\n",
- __func__, ops->len);
- return -EINVAL;
- }
- }
- if (ops->datbuf == NULL) {
- pr_err("%s: unsupported ops->datbuf == NULL\n", __func__);
- return -EINVAL;
- }
- if (ops->mode != MTD_OPS_RAW && ops->ooblen != 0 && ops->ooboffs != 0) {
- pr_err("%s: unsupported ops->ooboffs, %d\n",
- __func__, ops->ooboffs);
- return -EINVAL;
- }
- if (ops->datbuf) {
- data_dma_addr_curr = data_dma_addr =
- msm_nand_dma_map(chip->dev, ops->datbuf,
- ops->len, DMA_TO_DEVICE);
- if (dma_mapping_error(chip->dev, data_dma_addr)) {
- pr_err("msm_nand_write_oob: failed to get dma addr "
- "for %p\n", ops->datbuf);
- return -EIO;
- }
- }
- if (ops->oobbuf) {
- oob_dma_addr_curr = oob_dma_addr =
- msm_nand_dma_map(chip->dev, ops->oobbuf,
- ops->ooblen, DMA_TO_DEVICE);
- if (dma_mapping_error(chip->dev, oob_dma_addr)) {
- pr_err("msm_nand_write_oob: failed to get dma addr "
- "for %p\n", ops->oobbuf);
- err = -EIO;
- goto err_dma_map_oobbuf_failed;
- }
- }
- if (ops->mode != MTD_OPS_RAW)
- page_count = ops->len / mtd->writesize;
- else
- page_count = ops->len / (mtd->writesize + mtd->oobsize);
- wait_event(chip->wait_queue, (dma_buffer =
- msm_nand_get_dma_buffer(chip, sizeof(*dma_buffer))));
- while (page_count-- > 0) {
- cmd = dma_buffer->cmd;
- if (ops->mode != MTD_OPS_RAW) {
- dma_buffer->data.cfg0 = chip->CFG0;
- dma_buffer->data.cfg1 = chip->CFG1;
- if (enable_bch_ecc)
- dma_buffer->data.eccbchcfg = chip->ecc_bch_cfg;
- } else {
- dma_buffer->data.cfg0 = (chip->CFG0_RAW &
- ~(7U << 6)) | ((cwperpage-1) << 6);
- dma_buffer->data.cfg1 = chip->CFG1_RAW |
- (chip->CFG1 & CFG1_WIDE_FLASH);
- }
- /* CMD / ADDR0 / ADDR1 / CHIPSEL program values */
- dma_buffer->data.cmd = MSM_NAND_CMD_PRG_PAGE;
- dma_buffer->data.addr0 = page << 16;
- dma_buffer->data.addr1 = (page >> 16) & 0xff;
- /* chipsel_0 + enable DM interface */
- dma_buffer->data.chipsel = 0 | 4;
- /* GO bit for the EXEC register */
- dma_buffer->data.exec = 1;
- dma_buffer->data.clrfstatus = 0x00000020;
- dma_buffer->data.clrrstatus = 0x000000C0;
- BUILD_BUG_ON(8 != ARRAY_SIZE(dma_buffer->data.flash_status));
- for (n = 0; n < cwperpage ; n++) {
- /* status return words */
- dma_buffer->data.flash_status[n] = 0xeeeeeeee;
- /* block on cmd ready, then
- * write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst
- */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src =
- msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = MSM_NAND_FLASH_CMD;
- if (n == 0)
- cmd->len = 16;
- else
- cmd->len = 4;
- cmd++;
- if (n == 0) {
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = MSM_NAND_DEV0_CFG0;
- if (enable_bch_ecc)
- cmd->len = 12;
- else
- cmd->len = 8;
- cmd++;
- dma_buffer->data.ecccfg = chip->ecc_buf_cfg;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.ecccfg);
- cmd->dst = MSM_NAND_EBI2_ECC_BUF_CFG;
- cmd->len = 4;
- cmd++;
- }
- /* write data block */
- if (ops->mode != MTD_OPS_RAW)
- sectordatawritesize = (n < (cwperpage - 1)) ?
- 516 : (512 - ((cwperpage - 1) << 2));
- else
- sectordatawritesize = chip->cw_size;
- cmd->cmd = 0;
- cmd->src = data_dma_addr_curr;
- data_dma_addr_curr += sectordatawritesize;
- cmd->dst = MSM_NAND_FLASH_BUFFER;
- cmd->len = sectordatawritesize;
- cmd++;
- if (ops->oobbuf) {
- if (n == (cwperpage - 1)) {
- cmd->cmd = 0;
- cmd->src = oob_dma_addr_curr;
- cmd->dst = MSM_NAND_FLASH_BUFFER +
- (512 - ((cwperpage - 1) << 2));
- if ((cwperpage << 2) < oob_len)
- cmd->len = (cwperpage << 2);
- else
- cmd->len = oob_len;
- oob_dma_addr_curr += cmd->len;
- oob_len -= cmd->len;
- if (cmd->len > 0)
- cmd++;
- }
- if (ops->mode != MTD_OPS_AUTO_OOB) {
- /* skip ecc bytes in oobbuf */
- if (oob_len < chip->ecc_parity_bytes) {
- oob_dma_addr_curr +=
- chip->ecc_parity_bytes;
- oob_len -=
- chip->ecc_parity_bytes;
- } else {
- oob_dma_addr_curr += oob_len;
- oob_len = 0;
- }
- }
- }
- /* kick the execute register */
- cmd->cmd = 0;
- cmd->src =
- msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = MSM_NAND_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* block on data ready, then
- * read the status register
- */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_FLASH_STATUS;
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.flash_status[n]);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.clrfstatus);
- cmd->dst = MSM_NAND_FLASH_STATUS;
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.clrrstatus);
- cmd->dst = MSM_NAND_READ_STATUS;
- cmd->len = 4;
- cmd++;
- }
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- BUILD_BUG_ON(8 * 7 + 2 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmdptr =
- (msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) |
- CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(
- msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- /* if any of the writes failed (0x10), or there was a
- * protection violation (0x100), or the program success
- * bit (0x80) is unset, we lose
- */
- err = 0;
- for (n = 0; n < cwperpage; n++) {
- if (dma_buffer->data.flash_status[n] & 0x110) {
- err = -EIO;
- break;
- }
- if (!(dma_buffer->data.flash_status[n] & 0x80)) {
- err = -EIO;
- break;
- }
- }
- #if VERBOSE
- for (n = 0; n < cwperpage; n++)
- pr_info("write pg %d: flash_status[%d] = %x\n", page,
- n, dma_buffer->data.flash_status[n]);
- #endif
- if (err)
- break;
- pages_written++;
- page++;
- }
- if (ops->mode != MTD_OPS_RAW)
- ops->retlen = mtd->writesize * pages_written;
- else
- ops->retlen = (mtd->writesize + mtd->oobsize) * pages_written;
- ops->oobretlen = ops->ooblen - oob_len;
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- if (ops->oobbuf)
- dma_unmap_page(chip->dev, oob_dma_addr,
- ops->ooblen, DMA_TO_DEVICE);
- err_dma_map_oobbuf_failed:
- if (ops->datbuf)
- dma_unmap_page(chip->dev, data_dma_addr, ops->len,
- DMA_TO_DEVICE);
- if (err)
- pr_err("msm_nand_write_oob %llx %x %x failed %d\n",
- to, ops->len, ops->ooblen, err);
- #if VERBOSE
- pr_info("\n%s: ret %d, retlen %d oobretlen %d\n",
- __func__, err, ops->retlen, ops->oobretlen);
- pr_info("==================================================="
- "==============\n");
- #endif
- return err;
- }
- static int
- msm_nand_write_oob_dualnandc(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[16 * 6 + 18];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t nandc01_addr0;
- uint32_t nandc10_addr0;
- uint32_t nandc11_addr1;
- uint32_t chipsel_cs0;
- uint32_t chipsel_cs1;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t eccbchcfg;
- uint32_t exec;
- uint32_t ecccfg;
- uint32_t cfg0_nc01;
- uint32_t ebi2_chip_select_cfg0;
- uint32_t adm_mux_data_ack_req_nc01;
- uint32_t adm_mux_cmd_ack_req_nc01;
- uint32_t adm_mux_data_ack_req_nc10;
- uint32_t adm_mux_cmd_ack_req_nc10;
- uint32_t adm_default_mux;
- uint32_t default_ebi2_chip_select_cfg0;
- uint32_t nc01_flash_dev_cmd_vld;
- uint32_t nc10_flash_dev_cmd0;
- uint32_t nc01_flash_dev_cmd_vld_default;
- uint32_t nc10_flash_dev_cmd0_default;
- uint32_t flash_status[16];
- uint32_t clrfstatus;
- uint32_t clrrstatus;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- unsigned n;
- unsigned page = 0;
- uint32_t oob_len;
- uint32_t sectordatawritesize;
- int err = 0;
- dma_addr_t data_dma_addr = 0;
- dma_addr_t oob_dma_addr = 0;
- dma_addr_t data_dma_addr_curr = 0;
- dma_addr_t oob_dma_addr_curr = 0;
- unsigned page_count;
- unsigned pages_written = 0;
- unsigned cwperpage;
- unsigned cw_offset = chip->cw_size;
- #if VERBOSE
- pr_info("================================================="
- "============\n");
- pr_info("%s:\nto 0x%llx mode %d\ndatbuf 0x%p datlen 0x%x"
- "\noobbuf 0x%p ooblen 0x%x\n\n",
- __func__, to, ops->mode, ops->datbuf, ops->len,
- ops->oobbuf, ops->ooblen);
- #endif
- if (mtd->writesize == 2048)
- page = to >> 11;
- if (mtd->writesize == 4096)
- page = to >> 12;
- if (interleave_enable)
- page = (to >> 1) >> 12;
- oob_len = ops->ooblen;
- cwperpage = (mtd->writesize >> 9);
- if (to & (mtd->writesize - 1)) {
- pr_err("%s: unsupported to, 0x%llx\n", __func__, to);
- return -EINVAL;
- }
- if (ops->mode != MTD_OPS_RAW) {
- if (ops->ooblen != 0 && ops->mode != MTD_OPS_AUTO_OOB) {
- pr_err("%s: unsupported ops->mode,%d\n",
- __func__, ops->mode);
- return -EINVAL;
- }
- if ((ops->len % mtd->writesize) != 0) {
- pr_err("%s: unsupported ops->len, %d\n",
- __func__, ops->len);
- return -EINVAL;
- }
- } else {
- if ((ops->len % (mtd->writesize + mtd->oobsize)) != 0) {
- pr_err("%s: unsupported ops->len, "
- "%d for MTD_OPS_RAW mode\n",
- __func__, ops->len);
- return -EINVAL;
- }
- }
- if (ops->datbuf == NULL) {
- pr_err("%s: unsupported ops->datbuf == NULL\n", __func__);
- return -EINVAL;
- }
- if (ops->mode != MTD_OPS_RAW && ops->ooblen != 0 && ops->ooboffs != 0) {
- pr_err("%s: unsupported ops->ooboffs, %d\n",
- __func__, ops->ooboffs);
- return -EINVAL;
- }
- if (ops->datbuf) {
- data_dma_addr_curr = data_dma_addr =
- msm_nand_dma_map(chip->dev, ops->datbuf,
- ops->len, DMA_TO_DEVICE);
- if (dma_mapping_error(chip->dev, data_dma_addr)) {
- pr_err("msm_nand_write_oob_dualnandc:"
- "failed to get dma addr "
- "for %p\n", ops->datbuf);
- return -EIO;
- }
- }
- if (ops->oobbuf) {
- oob_dma_addr_curr = oob_dma_addr =
- msm_nand_dma_map(chip->dev, ops->oobbuf,
- ops->ooblen, DMA_TO_DEVICE);
- if (dma_mapping_error(chip->dev, oob_dma_addr)) {
- pr_err("msm_nand_write_oob_dualnandc:"
- "failed to get dma addr "
- "for %p\n", ops->oobbuf);
- err = -EIO;
- goto err_dma_map_oobbuf_failed;
- }
- }
- if (ops->mode != MTD_OPS_RAW)
- page_count = ops->len / mtd->writesize;
- else
- page_count = ops->len / (mtd->writesize + mtd->oobsize);
- wait_event(chip->wait_queue, (dma_buffer =
- msm_nand_get_dma_buffer(chip, sizeof(*dma_buffer))));
- if (chip->CFG1 & CFG1_WIDE_FLASH)
- cw_offset >>= 1;
- dma_buffer->data.ebi2_chip_select_cfg0 = 0x00000805;
- dma_buffer->data.adm_mux_data_ack_req_nc01 = 0x00000A3C;
- dma_buffer->data.adm_mux_cmd_ack_req_nc01 = 0x0000053C;
- dma_buffer->data.adm_mux_data_ack_req_nc10 = 0x00000F28;
- dma_buffer->data.adm_mux_cmd_ack_req_nc10 = 0x00000F14;
- dma_buffer->data.adm_default_mux = 0x00000FC0;
- dma_buffer->data.default_ebi2_chip_select_cfg0 = 0x00000801;
- dma_buffer->data.nc01_flash_dev_cmd_vld = 0x9;
- dma_buffer->data.nc10_flash_dev_cmd0 = 0x1085D060;
- dma_buffer->data.nc01_flash_dev_cmd_vld_default = 0x1D;
- dma_buffer->data.nc10_flash_dev_cmd0_default = 0x1080D060;
- dma_buffer->data.clrfstatus = 0x00000020;
- dma_buffer->data.clrrstatus = 0x000000C0;
- while (page_count-- > 0) {
- cmd = dma_buffer->cmd;
- if (ops->mode != MTD_OPS_RAW) {
- dma_buffer->data.cfg0 = ((chip->CFG0 & ~(7U << 6))
- & ~(1 << 4)) | ((((cwperpage >> 1)-1)) << 6);
- dma_buffer->data.cfg1 = chip->CFG1;
- if (enable_bch_ecc)
- dma_buffer->data.eccbchcfg = chip->ecc_bch_cfg;
- } else {
- dma_buffer->data.cfg0 = ((chip->CFG0_RAW &
- ~(7U << 6)) & ~(1 << 4)) | (((cwperpage >> 1)-1) << 6);
- dma_buffer->data.cfg1 = chip->CFG1_RAW |
- (chip->CFG1 & CFG1_WIDE_FLASH);
- }
- /* Disables the automatic issuing of the read
- * status command for first NAND controller.
- */
- if (!interleave_enable)
- dma_buffer->data.cfg0_nc01 = dma_buffer->data.cfg0
- | (1 << 4);
- else
- dma_buffer->data.cfg0 |= (1 << 4);
- dma_buffer->data.cmd = MSM_NAND_CMD_PRG_PAGE;
- dma_buffer->data.chipsel_cs0 = (1<<4) | 4;
- dma_buffer->data.chipsel_cs1 = (1<<4) | 5;
- /* GO bit for the EXEC register */
- dma_buffer->data.exec = 1;
- if (!interleave_enable) {
- dma_buffer->data.nandc01_addr0 = (page << 16) | 0x0;
- /* NC10 ADDR0 points to the next code word */
- dma_buffer->data.nandc10_addr0 =
- (page << 16) | cw_offset;
- } else {
- dma_buffer->data.nandc01_addr0 =
- dma_buffer->data.nandc10_addr0 = (page << 16) | 0x0;
- }
- /* ADDR1 */
- dma_buffer->data.nandc11_addr1 = (page >> 16) & 0xff;
- BUILD_BUG_ON(16 != ARRAY_SIZE(dma_buffer->data.flash_status));
- for (n = 0; n < cwperpage; n++) {
- /* status return words */
- dma_buffer->data.flash_status[n] = 0xeeeeeeee;
- if (n == 0) {
- if (!interleave_enable) {
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.nc01_flash_dev_cmd_vld);
- cmd->dst = NC01(MSM_NAND_DEV_CMD_VLD);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nc10_flash_dev_cmd0);
- cmd->dst = NC10(MSM_NAND_DEV_CMD0);
- cmd->len = 4;
- cmd++;
- /* common settings for both NC01 & NC10
- * NC01, NC10 --> ADDR1 / CHIPSEL
- */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc11_addr1);
- cmd->dst = NC11(MSM_NAND_ADDR1);
- cmd->len = 8;
- cmd++;
- /* Disables the automatic issue of the
- * read status command after the write
- * operation.
- */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0_nc01);
- cmd->dst = NC01(MSM_NAND_DEV0_CFG0);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = NC10(MSM_NAND_DEV0_CFG0);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg1);
- cmd->dst = NC11(MSM_NAND_DEV0_CFG1);
- if (enable_bch_ecc)
- cmd->len = 8;
- else
- cmd->len = 4;
- cmd++;
- } else {
- /* enable CS1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.ebi2_chip_select_cfg0);
- cmd->dst = EBI2_CHIP_SELECT_CFG0;
- cmd->len = 4;
- cmd++;
- /* NC11 --> ADDR1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc11_addr1);
- cmd->dst = NC11(MSM_NAND_ADDR1);
- cmd->len = 4;
- cmd++;
- /* Enable CS0 for NC01 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.chipsel_cs0);
- cmd->dst =
- NC01(MSM_NAND_FLASH_CHIP_SELECT);
- cmd->len = 4;
- cmd++;
- /* Enable CS1 for NC10 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.chipsel_cs1);
- cmd->dst =
- NC10(MSM_NAND_FLASH_CHIP_SELECT);
- cmd->len = 4;
- cmd++;
- /* config DEV0_CFG0 & CFG1 for CS0 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = NC01(MSM_NAND_DEV0_CFG0);
- cmd->len = 8;
- cmd++;
- /* config DEV1_CFG0 & CFG1 for CS1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cfg0);
- cmd->dst = NC10(MSM_NAND_DEV1_CFG0);
- cmd->len = 8;
- cmd++;
- }
- dma_buffer->data.ecccfg = chip->ecc_buf_cfg;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.ecccfg);
- cmd->dst = NC11(MSM_NAND_EBI2_ECC_BUF_CFG);
- cmd->len = 4;
- cmd++;
- /* NC01 --> ADDR0 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc01_addr0);
- cmd->dst = NC01(MSM_NAND_ADDR0);
- cmd->len = 4;
- cmd++;
- /* NC10 --> ADDR0 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nandc10_addr0);
- cmd->dst = NC10(MSM_NAND_ADDR0);
- cmd->len = 4;
- cmd++;
- }
- if (n % 2 == 0) {
- /* MASK CMD ACK/REQ --> NC10 (0xF14)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_cmd_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* CMD */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cmd);
- cmd->dst = NC01(MSM_NAND_FLASH_CMD);
- cmd->len = 4;
- cmd++;
- } else {
- /* MASK CMD ACK/REQ --> NC01 (0x53C)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_cmd_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* CMD */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.cmd);
- cmd->dst = NC10(MSM_NAND_FLASH_CMD);
- cmd->len = 4;
- cmd++;
- }
- if (ops->mode != MTD_OPS_RAW)
- sectordatawritesize = (n < (cwperpage - 1)) ?
- 516 : (512 - ((cwperpage - 1) << 2));
- else
- sectordatawritesize = chip->cw_size;
- cmd->cmd = 0;
- cmd->src = data_dma_addr_curr;
- data_dma_addr_curr += sectordatawritesize;
- if (n % 2 == 0)
- cmd->dst = NC01(MSM_NAND_FLASH_BUFFER);
- else
- cmd->dst = NC10(MSM_NAND_FLASH_BUFFER);
- cmd->len = sectordatawritesize;
- cmd++;
- if (ops->oobbuf) {
- if (n == (cwperpage - 1)) {
- cmd->cmd = 0;
- cmd->src = oob_dma_addr_curr;
- cmd->dst = NC10(MSM_NAND_FLASH_BUFFER) +
- (512 - ((cwperpage - 1) << 2));
- if ((cwperpage << 2) < oob_len)
- cmd->len = (cwperpage << 2);
- else
- cmd->len = oob_len;
- oob_dma_addr_curr += cmd->len;
- oob_len -= cmd->len;
- if (cmd->len > 0)
- cmd++;
- }
- if (ops->mode != MTD_OPS_AUTO_OOB) {
- /* skip ecc bytes in oobbuf */
- if (oob_len < chip->ecc_parity_bytes) {
- oob_dma_addr_curr +=
- chip->ecc_parity_bytes;
- oob_len -=
- chip->ecc_parity_bytes;
- } else {
- oob_dma_addr_curr += oob_len;
- oob_len = 0;
- }
- }
- }
- if (n % 2 == 0) {
- if (n != 0) {
- /* MASK DATA ACK/REQ --> NC01 (0xA3C)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->
- data.adm_mux_data_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* block on data ready from NC10, then
- * read the status register
- */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC10(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.flash_status[n-1]);
- cmd->len = 4;
- cmd++;
- }
- /* kick the NC01 execute register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.exec);
- cmd->dst = NC01(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- } else {
- /* MASK DATA ACK/REQ --> NC10 (0xF28)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_data_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* block on data ready from NC01, then
- * read the status register
- */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC01(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.flash_status[n-1]);
- cmd->len = 4;
- cmd++;
- /* kick the execute register */
- cmd->cmd = 0;
- cmd->src =
- msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = NC10(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- }
- }
- /* MASK DATA ACK/REQ --> NC01 (0xA3C)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_data_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* we should process outstanding request */
- /* block on data ready, then
- * read the status register
- */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC10(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.flash_status[n-1]);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.clrfstatus);
- cmd->dst = NC11(MSM_NAND_FLASH_STATUS);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.clrrstatus);
- cmd->dst = NC11(MSM_NAND_READ_STATUS);
- cmd->len = 4;
- cmd++;
- /* MASK DATA ACK/REQ --> NC01 (0xFC0)*/
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_default_mux);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- if (!interleave_enable) {
- /* setting to defalut values back */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nc01_flash_dev_cmd_vld_default);
- cmd->dst = NC01(MSM_NAND_DEV_CMD_VLD);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.nc10_flash_dev_cmd0_default);
- cmd->dst = NC10(MSM_NAND_DEV_CMD0);
- cmd->len = 4;
- cmd++;
- } else {
- /* disable CS1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.default_ebi2_chip_select_cfg0);
- cmd->dst = EBI2_CHIP_SELECT_CFG0;
- cmd->len = 4;
- cmd++;
- }
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- BUILD_BUG_ON(16 * 6 + 18 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmdptr =
- ((msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) | CMD_PTR_LP);
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(
- msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- /* if any of the writes failed (0x10), or there was a
- * protection violation (0x100), or the program success
- * bit (0x80) is unset, we lose
- */
- err = 0;
- for (n = 0; n < cwperpage; n++) {
- if (dma_buffer->data.flash_status[n] & 0x110) {
- err = -EIO;
- break;
- }
- if (!(dma_buffer->data.flash_status[n] & 0x80)) {
- err = -EIO;
- break;
- }
- }
- /* check for flash status busy for the last codeword */
- if (!interleave_enable)
- if (!(dma_buffer->data.flash_status[cwperpage - 1]
- & 0x20)) {
- err = -EIO;
- break;
- }
- #if VERBOSE
- for (n = 0; n < cwperpage; n++) {
- if (n%2) {
- pr_info("NC10: write pg %d: flash_status[%d] = %x\n",
- page, n, dma_buffer->data.flash_status[n]);
- } else {
- pr_info("NC01: write pg %d: flash_status[%d] = %x\n",
- page, n, dma_buffer->data.flash_status[n]);
- }
- }
- #endif
- if (err)
- break;
- pages_written++;
- page++;
- }
- if (ops->mode != MTD_OPS_RAW)
- ops->retlen = mtd->writesize * pages_written;
- else
- ops->retlen = (mtd->writesize + mtd->oobsize) * pages_written;
- ops->oobretlen = ops->ooblen - oob_len;
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- if (ops->oobbuf)
- dma_unmap_page(chip->dev, oob_dma_addr,
- ops->ooblen, DMA_TO_DEVICE);
- err_dma_map_oobbuf_failed:
- if (ops->datbuf)
- dma_unmap_page(chip->dev, data_dma_addr, ops->len,
- DMA_TO_DEVICE);
- if (err)
- pr_err("msm_nand_write_oob_dualnandc %llx %x %x failed %d\n",
- to, ops->len, ops->ooblen, err);
- #if VERBOSE
- pr_info("\n%s: ret %d, retlen %d oobretlen %d\n",
- __func__, err, ops->retlen, ops->oobretlen);
- pr_info("==================================================="
- "==========\n");
- #endif
- return err;
- }
- static int msm_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
- {
- int ret;
- struct mtd_oob_ops ops;
- int (*write_oob)(struct mtd_info *, loff_t, struct mtd_oob_ops *);
- if (!dual_nand_ctlr_present)
- write_oob = msm_nand_write_oob;
- else
- write_oob = msm_nand_write_oob_dualnandc;
- ops.mode = MTD_OPS_PLACE_OOB;
- ops.retlen = 0;
- ops.ooblen = 0;
- ops.oobbuf = NULL;
- ret = 0;
- *retlen = 0;
- if (!virt_addr_valid(buf) &&
- ((to | len) & (mtd->writesize - 1)) == 0 &&
- ((unsigned long) buf & ~PAGE_MASK) + len > PAGE_SIZE) {
- /*
- * Handle writing of large size write buffer in vmalloc
- * address space that does not fit in an MMU page.
- * The destination address must be on page boundary,
- * and the size must be multiple of NAND page size.
- * Writing partial page is not supported.
- */
- ops.len = mtd->writesize;
- for (;;) {
- ops.datbuf = (uint8_t *) buf;
- ret = write_oob(mtd, to, &ops);
- if (ret < 0)
- break;
- len -= mtd->writesize;
- *retlen += mtd->writesize;
- if (len == 0)
- break;
- buf += mtd->writesize;
- to += mtd->writesize;
- }
- } else {
- ops.len = len;
- ops.datbuf = (uint8_t *) buf;
- ret = write_oob(mtd, to, &ops);
- *retlen = ops.retlen;
- }
- return ret;
- }
- static int
- msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
- int err;
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[6];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t addr0;
- uint32_t addr1;
- uint32_t chipsel;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t exec;
- uint32_t flash_status;
- uint32_t clrfstatus;
- uint32_t clrrstatus;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- unsigned page = 0;
- if (mtd->writesize == 2048)
- page = instr->addr >> 11;
- if (mtd->writesize == 4096)
- page = instr->addr >> 12;
- if (instr->addr & (mtd->erasesize - 1)) {
- pr_err("%s: unsupported erase address, 0x%llx\n",
- __func__, instr->addr);
- return -EINVAL;
- }
- if (instr->len != mtd->erasesize) {
- pr_err("%s: unsupported erase len, %lld\n",
- __func__, instr->len);
- return -EINVAL;
- }
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(
- chip, sizeof(*dma_buffer))));
- cmd = dma_buffer->cmd;
- dma_buffer->data.cmd = MSM_NAND_CMD_BLOCK_ERASE;
- dma_buffer->data.addr0 = page;
- dma_buffer->data.addr1 = 0;
- dma_buffer->data.chipsel = 0 | 4;
- dma_buffer->data.exec = 1;
- dma_buffer->data.flash_status = 0xeeeeeeee;
- dma_buffer->data.cfg0 = chip->CFG0 & (~(7 << 6)); /* CW_PER_PAGE = 0 */
- dma_buffer->data.cfg1 = chip->CFG1;
- dma_buffer->data.clrfstatus = 0x00000020;
- dma_buffer->data.clrrstatus = 0x000000C0;
- cmd->cmd = DST_CRCI_NAND_CMD | CMD_OCB;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = MSM_NAND_FLASH_CMD;
- cmd->len = 16;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cfg0);
- cmd->dst = MSM_NAND_DEV0_CFG0;
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = MSM_NAND_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_FLASH_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.flash_status);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.clrfstatus);
- cmd->dst = MSM_NAND_FLASH_STATUS;
- cmd->len = 4;
- cmd++;
- cmd->cmd = CMD_OCU | CMD_LC;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.clrrstatus);
- cmd->dst = MSM_NAND_READ_STATUS;
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(5 != ARRAY_SIZE(dma_buffer->cmd) - 1);
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmdptr =
- (msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(
- chip->dma_channel, DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- /* we fail if there was an operation error, a mpu error, or the
- * erase success bit was not set.
- */
- if (dma_buffer->data.flash_status & 0x110 ||
- !(dma_buffer->data.flash_status & 0x80))
- err = -EIO;
- else
- err = 0;
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- if (err) {
- pr_err("%s: erase failed, 0x%llx\n", __func__, instr->addr);
- instr->fail_addr = instr->addr;
- instr->state = MTD_ERASE_FAILED;
- } else {
- instr->state = MTD_ERASE_DONE;
- instr->fail_addr = 0xffffffff;
- mtd_erase_callback(instr);
- }
- return err;
- }
- static int
- msm_nand_erase_dualnandc(struct mtd_info *mtd, struct erase_info *instr)
- {
- int err;
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[18];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t addr0;
- uint32_t addr1;
- uint32_t chipsel_cs0;
- uint32_t chipsel_cs1;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t exec;
- uint32_t ecccfg;
- uint32_t ebi2_chip_select_cfg0;
- uint32_t adm_mux_data_ack_req_nc01;
- uint32_t adm_mux_cmd_ack_req_nc01;
- uint32_t adm_mux_data_ack_req_nc10;
- uint32_t adm_mux_cmd_ack_req_nc10;
- uint32_t adm_default_mux;
- uint32_t default_ebi2_chip_select_cfg0;
- uint32_t nc01_flash_dev_cmd0;
- uint32_t nc01_flash_dev_cmd0_default;
- uint32_t flash_status[2];
- uint32_t clrfstatus;
- uint32_t clrrstatus;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- unsigned page = 0;
- if (mtd->writesize == 2048)
- page = instr->addr >> 11;
- if (mtd->writesize == 4096)
- page = instr->addr >> 12;
- if (mtd->writesize == 8192)
- page = (instr->addr >> 1) >> 12;
- if (instr->addr & (mtd->erasesize - 1)) {
- pr_err("%s: unsupported erase address, 0x%llx\n",
- __func__, instr->addr);
- return -EINVAL;
- }
- if (instr->len != mtd->erasesize) {
- pr_err("%s: unsupported erase len, %lld\n",
- __func__, instr->len);
- return -EINVAL;
- }
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(
- chip, sizeof(*dma_buffer))));
- cmd = dma_buffer->cmd;
- dma_buffer->data.cmd = MSM_NAND_CMD_BLOCK_ERASE;
- dma_buffer->data.addr0 = page;
- dma_buffer->data.addr1 = 0;
- dma_buffer->data.chipsel_cs0 = (1<<4) | 4;
- dma_buffer->data.chipsel_cs1 = (1<<4) | 5;
- dma_buffer->data.exec = 1;
- dma_buffer->data.flash_status[0] = 0xeeeeeeee;
- dma_buffer->data.flash_status[1] = 0xeeeeeeee;
- dma_buffer->data.cfg0 = chip->CFG0 & (~(7 << 6)); /* CW_PER_PAGE = 0 */
- dma_buffer->data.cfg1 = chip->CFG1;
- dma_buffer->data.clrfstatus = 0x00000020;
- dma_buffer->data.clrrstatus = 0x000000C0;
- dma_buffer->data.ebi2_chip_select_cfg0 = 0x00000805;
- dma_buffer->data.adm_mux_data_ack_req_nc01 = 0x00000A3C;
- dma_buffer->data.adm_mux_cmd_ack_req_nc01 = 0x0000053C;
- dma_buffer->data.adm_mux_data_ack_req_nc10 = 0x00000F28;
- dma_buffer->data.adm_mux_cmd_ack_req_nc10 = 0x00000F14;
- dma_buffer->data.adm_default_mux = 0x00000FC0;
- dma_buffer->data.default_ebi2_chip_select_cfg0 = 0x00000801;
- /* enable CS1 */
- cmd->cmd = 0 | CMD_OCB;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.ebi2_chip_select_cfg0);
- cmd->dst = EBI2_CHIP_SELECT_CFG0;
- cmd->len = 4;
- cmd++;
- /* erase CS0 block now !!! */
- /* 0xF14 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_cmd_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = NC01(MSM_NAND_FLASH_CMD);
- cmd->len = 16;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cfg0);
- cmd->dst = NC01(MSM_NAND_DEV0_CFG0);
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = NC01(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- /* 0xF28 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_data_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC01(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.flash_status[0]);
- cmd->len = 4;
- cmd++;
- /* erase CS1 block now !!! */
- /* 0x53C */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_cmd_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = NC10(MSM_NAND_FLASH_CMD);
- cmd->len = 12;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.chipsel_cs1);
- cmd->dst = NC10(MSM_NAND_FLASH_CHIP_SELECT);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cfg0);
- cmd->dst = NC10(MSM_NAND_DEV1_CFG0);
- cmd->len = 8;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = NC10(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- /* 0xA3C */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_data_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC10(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.flash_status[1]);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.clrfstatus);
- cmd->dst = NC11(MSM_NAND_FLASH_STATUS);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.clrrstatus);
- cmd->dst = NC11(MSM_NAND_READ_STATUS);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_default_mux);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* disable CS1 */
- cmd->cmd = CMD_OCU | CMD_LC;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.default_ebi2_chip_select_cfg0);
- cmd->dst = EBI2_CHIP_SELECT_CFG0;
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(17 != ARRAY_SIZE(dma_buffer->cmd) - 1);
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmdptr =
- (msm_virt_to_dma(chip, dma_buffer->cmd) >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(
- chip->dma_channel, DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- /* we fail if there was an operation error, a mpu error, or the
- * erase success bit was not set.
- */
- if (dma_buffer->data.flash_status[0] & 0x110 ||
- !(dma_buffer->data.flash_status[0] & 0x80) ||
- dma_buffer->data.flash_status[1] & 0x110 ||
- !(dma_buffer->data.flash_status[1] & 0x80))
- err = -EIO;
- else
- err = 0;
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- if (err) {
- pr_err("%s: erase failed, 0x%llx\n", __func__, instr->addr);
- instr->fail_addr = instr->addr;
- instr->state = MTD_ERASE_FAILED;
- } else {
- instr->state = MTD_ERASE_DONE;
- instr->fail_addr = 0xffffffff;
- mtd_erase_callback(instr);
- }
- return err;
- }
- static int
- msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
- {
- struct msm_nand_chip *chip = mtd->priv;
- int ret;
- struct {
- dmov_s cmd[5];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t addr0;
- uint32_t addr1;
- uint32_t chipsel;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t eccbchcfg;
- uint32_t exec;
- uint32_t ecccfg;
- struct {
- uint32_t flash_status;
- uint32_t buffer_status;
- } result;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- uint8_t *buf;
- unsigned page = 0;
- unsigned cwperpage;
- if (mtd->writesize == 2048)
- page = ofs >> 11;
- if (mtd->writesize == 4096)
- page = ofs >> 12;
- cwperpage = (mtd->writesize >> 9);
- /* Check for invalid offset */
- if (ofs > mtd->size)
- return -EINVAL;
- if (ofs & (mtd->erasesize - 1)) {
- pr_err("%s: unsupported block address, 0x%x\n",
- __func__, (uint32_t)ofs);
- return -EINVAL;
- }
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(chip ,
- sizeof(*dma_buffer) + 4)));
- buf = (uint8_t *)dma_buffer + sizeof(*dma_buffer);
- /* Read 4 bytes starting from the bad block marker location
- * in the last code word of the page
- */
- cmd = dma_buffer->cmd;
- dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ;
- dma_buffer->data.cfg0 = chip->CFG0_RAW & ~(7U << 6);
- dma_buffer->data.cfg1 = chip->CFG1_RAW |
- (chip->CFG1 & CFG1_WIDE_FLASH);
- if (enable_bch_ecc)
- dma_buffer->data.eccbchcfg = chip->ecc_bch_cfg;
- if (chip->CFG1 & CFG1_WIDE_FLASH)
- dma_buffer->data.addr0 = (page << 16) |
- ((chip->cw_size * (cwperpage-1)) >> 1);
- else
- dma_buffer->data.addr0 = (page << 16) |
- (chip->cw_size * (cwperpage-1));
- dma_buffer->data.addr1 = (page >> 16) & 0xff;
- dma_buffer->data.chipsel = 0 | 4;
- dma_buffer->data.exec = 1;
- dma_buffer->data.result.flash_status = 0xeeeeeeee;
- dma_buffer->data.result.buffer_status = 0xeeeeeeee;
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = MSM_NAND_FLASH_CMD;
- cmd->len = 16;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cfg0);
- cmd->dst = MSM_NAND_DEV0_CFG0;
- if (enable_bch_ecc)
- cmd->len = 12;
- else
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = MSM_NAND_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_FLASH_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.result);
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = MSM_NAND_FLASH_BUFFER +
- (mtd->writesize - (chip->cw_size * (cwperpage-1)));
- cmd->dst = msm_virt_to_dma(chip, buf);
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(5 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip,
- dma_buffer->cmd) >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- ret = 0;
- if (dma_buffer->data.result.flash_status & 0x110)
- ret = -EIO;
- if (!ret) {
- /* Check for bad block marker byte */
- if (chip->CFG1 & CFG1_WIDE_FLASH) {
- if (buf[0] != 0xFF || buf[1] != 0xFF)
- ret = 1;
- } else {
- if (buf[0] != 0xFF)
- ret = 1;
- }
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer) + 4);
- return ret;
- }
- static int
- msm_nand_block_isbad_dualnandc(struct mtd_info *mtd, loff_t ofs)
- {
- struct msm_nand_chip *chip = mtd->priv;
- int ret;
- struct {
- dmov_s cmd[18];
- unsigned cmdptr;
- struct {
- uint32_t cmd;
- uint32_t addr0;
- uint32_t addr1;
- uint32_t chipsel_cs0;
- uint32_t chipsel_cs1;
- uint32_t cfg0;
- uint32_t cfg1;
- uint32_t exec;
- uint32_t ecccfg;
- uint32_t ebi2_chip_select_cfg0;
- uint32_t adm_mux_data_ack_req_nc01;
- uint32_t adm_mux_cmd_ack_req_nc01;
- uint32_t adm_mux_data_ack_req_nc10;
- uint32_t adm_mux_cmd_ack_req_nc10;
- uint32_t adm_default_mux;
- uint32_t default_ebi2_chip_select_cfg0;
- struct {
- uint32_t flash_status;
- uint32_t buffer_status;
- } result[2];
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- uint8_t *buf01;
- uint8_t *buf10;
- unsigned page = 0;
- unsigned cwperpage;
- if (mtd->writesize == 2048)
- page = ofs >> 11;
- if (mtd->writesize == 4096)
- page = ofs >> 12;
- if (mtd->writesize == 8192)
- page = (ofs >> 1) >> 12;
- cwperpage = ((mtd->writesize >> 1) >> 9);
- /* Check for invalid offset */
- if (ofs > mtd->size)
- return -EINVAL;
- if (ofs & (mtd->erasesize - 1)) {
- pr_err("%s: unsupported block address, 0x%x\n",
- __func__, (uint32_t)ofs);
- return -EINVAL;
- }
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(chip ,
- sizeof(*dma_buffer) + 8)));
- buf01 = (uint8_t *)dma_buffer + sizeof(*dma_buffer);
- buf10 = buf01 + 4;
- /* Read 4 bytes starting from the bad block marker location
- * in the last code word of the page
- */
- cmd = dma_buffer->cmd;
- dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ;
- dma_buffer->data.cfg0 = chip->CFG0_RAW & ~(7U << 6);
- dma_buffer->data.cfg1 = chip->CFG1_RAW |
- (chip->CFG1 & CFG1_WIDE_FLASH);
- if (chip->CFG1 & CFG1_WIDE_FLASH)
- dma_buffer->data.addr0 = (page << 16) |
- ((528*(cwperpage-1)) >> 1);
- else
- dma_buffer->data.addr0 = (page << 16) |
- (528*(cwperpage-1));
- dma_buffer->data.addr1 = (page >> 16) & 0xff;
- dma_buffer->data.chipsel_cs0 = (1<<4) | 4;
- dma_buffer->data.chipsel_cs1 = (1<<4) | 5;
- dma_buffer->data.exec = 1;
- dma_buffer->data.result[0].flash_status = 0xeeeeeeee;
- dma_buffer->data.result[0].buffer_status = 0xeeeeeeee;
- dma_buffer->data.result[1].flash_status = 0xeeeeeeee;
- dma_buffer->data.result[1].buffer_status = 0xeeeeeeee;
- dma_buffer->data.ebi2_chip_select_cfg0 = 0x00000805;
- dma_buffer->data.adm_mux_data_ack_req_nc01 = 0x00000A3C;
- dma_buffer->data.adm_mux_cmd_ack_req_nc01 = 0x0000053C;
- dma_buffer->data.adm_mux_data_ack_req_nc10 = 0x00000F28;
- dma_buffer->data.adm_mux_cmd_ack_req_nc10 = 0x00000F14;
- dma_buffer->data.adm_default_mux = 0x00000FC0;
- dma_buffer->data.default_ebi2_chip_select_cfg0 = 0x00000801;
- /* Reading last code word from NC01 */
- /* enable CS1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.ebi2_chip_select_cfg0);
- cmd->dst = EBI2_CHIP_SELECT_CFG0;
- cmd->len = 4;
- cmd++;
- /* 0xF14 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_cmd_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = NC01(MSM_NAND_FLASH_CMD);
- cmd->len = 16;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cfg0);
- cmd->dst = NC01(MSM_NAND_DEV0_CFG0);
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = NC01(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- /* 0xF28 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_data_ack_req_nc10);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC01(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.result[0]);
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = NC01(MSM_NAND_FLASH_BUFFER) + ((mtd->writesize >> 1) -
- (528*(cwperpage-1)));
- cmd->dst = msm_virt_to_dma(chip, buf01);
- cmd->len = 4;
- cmd++;
- /* Reading last code word from NC10 */
- /* 0x53C */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_cmd_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = NC10(MSM_NAND_FLASH_CMD);
- cmd->len = 12;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.chipsel_cs1);
- cmd->dst = NC10(MSM_NAND_FLASH_CHIP_SELECT);
- cmd->len = 4;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cfg0);
- cmd->dst = NC10(MSM_NAND_DEV1_CFG0);
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = NC10(MSM_NAND_EXEC_CMD);
- cmd->len = 4;
- cmd++;
- /* A3C */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_mux_data_ack_req_nc01);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = NC10(MSM_NAND_FLASH_STATUS);
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.result[1]);
- cmd->len = 8;
- cmd++;
- cmd->cmd = 0;
- cmd->src = NC10(MSM_NAND_FLASH_BUFFER) + ((mtd->writesize >> 1) -
- (528*(cwperpage-1)));
- cmd->dst = msm_virt_to_dma(chip, buf10);
- cmd->len = 4;
- cmd++;
- /* FC0 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.adm_default_mux);
- cmd->dst = EBI2_NAND_ADM_MUX;
- cmd->len = 4;
- cmd++;
- /* disble CS1 */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.ebi2_chip_select_cfg0);
- cmd->dst = EBI2_CHIP_SELECT_CFG0;
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(18 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip,
- dma_buffer->cmd) >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
- mb();
- ret = 0;
- if ((dma_buffer->data.result[0].flash_status & 0x110) ||
- (dma_buffer->data.result[1].flash_status & 0x110))
- ret = -EIO;
- if (!ret) {
- /* Check for bad block marker byte for NC01 & NC10 */
- if (chip->CFG1 & CFG1_WIDE_FLASH) {
- if ((buf01[0] != 0xFF || buf01[1] != 0xFF) ||
- (buf10[0] != 0xFF || buf10[1] != 0xFF))
- ret = 1;
- } else {
- if (buf01[0] != 0xFF || buf10[0] != 0xFF)
- ret = 1;
- }
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer) + 8);
- return ret;
- }
- static int
- msm_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
- {
- struct mtd_oob_ops ops;
- int ret;
- uint8_t *buf;
- /* Check for invalid offset */
- if (ofs > mtd->size)
- return -EINVAL;
- if (ofs & (mtd->erasesize - 1)) {
- pr_err("%s: unsupported block address, 0x%x\n",
- __func__, (uint32_t)ofs);
- return -EINVAL;
- }
- /*
- Write all 0s to the first page
- This will set the BB marker to 0
- */
- buf = page_address(ZERO_PAGE());
- ops.mode = MTD_OPS_RAW;
- ops.len = mtd->writesize + mtd->oobsize;
- ops.retlen = 0;
- ops.ooblen = 0;
- ops.datbuf = buf;
- ops.oobbuf = NULL;
- if (!interleave_enable)
- ret = msm_nand_write_oob(mtd, ofs, &ops);
- else
- ret = msm_nand_write_oob_dualnandc(mtd, ofs, &ops);
- return ret;
- }
- /**
- * msm_nand_suspend - [MTD Interface] Suspend the msm_nand flash
- * @param mtd MTD device structure
- */
- static int msm_nand_suspend(struct mtd_info *mtd)
- {
- return 0;
- }
- /**
- * msm_nand_resume - [MTD Interface] Resume the msm_nand flash
- * @param mtd MTD device structure
- */
- static void msm_nand_resume(struct mtd_info *mtd)
- {
- }
- struct onenand_information {
- uint16_t manufacturer_id;
- uint16_t device_id;
- uint16_t version_id;
- uint16_t data_buf_size;
- uint16_t boot_buf_size;
- uint16_t num_of_buffers;
- uint16_t technology;
- };
- static struct onenand_information onenand_info;
- static uint32_t nand_sfcmd_mode;
- uint32_t flash_onenand_probe(struct msm_nand_chip *chip)
- {
- struct {
- dmov_s cmd[7];
- unsigned cmdptr;
- struct {
- uint32_t bcfg;
- uint32_t cmd;
- uint32_t exec;
- uint32_t status;
- uint32_t addr0;
- uint32_t addr1;
- uint32_t addr2;
- uint32_t addr3;
- uint32_t addr4;
- uint32_t addr5;
- uint32_t addr6;
- uint32_t data0;
- uint32_t data1;
- uint32_t data2;
- uint32_t data3;
- uint32_t data4;
- uint32_t data5;
- uint32_t data6;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- int err = 0;
- uint32_t initialsflashcmd = 0;
- initialsflashcmd = flash_rd_reg(chip, MSM_NAND_SFLASHC_CMD);
- if ((initialsflashcmd & 0x10) == 0x10)
- nand_sfcmd_mode = MSM_NAND_SFCMD_ASYNC;
- else
- nand_sfcmd_mode = MSM_NAND_SFCMD_BURST;
- printk(KERN_INFO "SFLASHC Async Mode bit: %x \n", nand_sfcmd_mode);
- wait_event(chip->wait_queue, (dma_buffer = msm_nand_get_dma_buffer
- (chip, sizeof(*dma_buffer))));
- cmd = dma_buffer->cmd;
- dma_buffer->data.bcfg = SFLASH_BCFG |
- (nand_sfcmd_mode ? 0 : (1 << 24));
- dma_buffer->data.cmd = SFLASH_PREPCMD(7, 0, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGRD);
- dma_buffer->data.exec = 1;
- dma_buffer->data.status = CLEAN_DATA_32;
- dma_buffer->data.addr0 = (ONENAND_DEVICE_ID << 16) |
- (ONENAND_MANUFACTURER_ID);
- dma_buffer->data.addr1 = (ONENAND_DATA_BUFFER_SIZE << 16) |
- (ONENAND_VERSION_ID);
- dma_buffer->data.addr2 = (ONENAND_AMOUNT_OF_BUFFERS << 16) |
- (ONENAND_BOOT_BUFFER_SIZE);
- dma_buffer->data.addr3 = (CLEAN_DATA_16 << 16) |
- (ONENAND_TECHNOLOGY << 0);
- dma_buffer->data.data0 = CLEAN_DATA_32;
- dma_buffer->data.data1 = CLEAN_DATA_32;
- dma_buffer->data.data2 = CLEAN_DATA_32;
- dma_buffer->data.data3 = CLEAN_DATA_32;
- /* Enable and configure the SFlash controller */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.bcfg);
- cmd->dst = MSM_NAND_SFLASHC_BURST_CFG;
- cmd->len = 4;
- cmd++;
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.cmd);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Configure the ADDR0 and ADDR1 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr0);
- cmd->dst = MSM_NAND_ADDR0;
- cmd->len = 8;
- cmd++;
- /* Configure the ADDR2 and ADDR3 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr2);
- cmd->dst = MSM_NAND_ADDR2;
- cmd->len = 8;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.exec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the two status registers */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.status);
- cmd->len = 4;
- cmd++;
- /* Read data registers - valid only if status says success */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_GENP_REG0;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data0);
- cmd->len = 16;
- cmd++;
- BUILD_BUG_ON(7 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd)
- >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST
- | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- /* Check for errors, protection violations etc */
- if (dma_buffer->data.status & 0x110) {
- pr_info("%s: MPU/OP error"
- "(0x%x) during Onenand probe\n",
- __func__, dma_buffer->data.status);
- err = -EIO;
- } else {
- onenand_info.manufacturer_id =
- (dma_buffer->data.data0 >> 0) & 0x0000FFFF;
- onenand_info.device_id =
- (dma_buffer->data.data0 >> 16) & 0x0000FFFF;
- onenand_info.version_id =
- (dma_buffer->data.data1 >> 0) & 0x0000FFFF;
- onenand_info.data_buf_size =
- (dma_buffer->data.data1 >> 16) & 0x0000FFFF;
- onenand_info.boot_buf_size =
- (dma_buffer->data.data2 >> 0) & 0x0000FFFF;
- onenand_info.num_of_buffers =
- (dma_buffer->data.data2 >> 16) & 0x0000FFFF;
- onenand_info.technology =
- (dma_buffer->data.data3 >> 0) & 0x0000FFFF;
- pr_info("======================================="
- "==========================\n");
- pr_info("%s: manufacturer_id = 0x%x\n"
- , __func__, onenand_info.manufacturer_id);
- pr_info("%s: device_id = 0x%x\n"
- , __func__, onenand_info.device_id);
- pr_info("%s: version_id = 0x%x\n"
- , __func__, onenand_info.version_id);
- pr_info("%s: data_buf_size = 0x%x\n"
- , __func__, onenand_info.data_buf_size);
- pr_info("%s: boot_buf_size = 0x%x\n"
- , __func__, onenand_info.boot_buf_size);
- pr_info("%s: num_of_buffers = 0x%x\n"
- , __func__, onenand_info.num_of_buffers);
- pr_info("%s: technology = 0x%x\n"
- , __func__, onenand_info.technology);
- pr_info("======================================="
- "==========================\n");
- if ((onenand_info.manufacturer_id != 0x00EC)
- || ((onenand_info.device_id & 0x0040) != 0x0040)
- || (onenand_info.data_buf_size != 0x0800)
- || (onenand_info.boot_buf_size != 0x0200)
- || (onenand_info.num_of_buffers != 0x0201)
- || (onenand_info.technology != 0)) {
- pr_info("%s: Detected an unsupported device\n"
- , __func__);
- err = -EIO;
- }
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- return err;
- }
- int msm_onenand_read_oob(struct mtd_info *mtd,
- loff_t from, struct mtd_oob_ops *ops)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[53];
- unsigned cmdptr;
- struct {
- uint32_t sfbcfg;
- uint32_t sfcmd[9];
- uint32_t sfexec;
- uint32_t sfstat[9];
- uint32_t addr0;
- uint32_t addr1;
- uint32_t addr2;
- uint32_t addr3;
- uint32_t addr4;
- uint32_t addr5;
- uint32_t addr6;
- uint32_t data0;
- uint32_t data1;
- uint32_t data2;
- uint32_t data3;
- uint32_t data4;
- uint32_t data5;
- uint32_t data6;
- uint32_t macro[5];
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- int err = 0;
- int i;
- dma_addr_t data_dma_addr = 0;
- dma_addr_t oob_dma_addr = 0;
- dma_addr_t data_dma_addr_curr = 0;
- dma_addr_t oob_dma_addr_curr = 0;
- loff_t from_curr = 0;
- unsigned page_count;
- unsigned pages_read = 0;
- uint16_t onenand_startaddr1;
- uint16_t onenand_startaddr8;
- uint16_t onenand_startaddr2;
- uint16_t onenand_startbuffer;
- uint16_t onenand_sysconfig1;
- uint16_t controller_status;
- uint16_t interrupt_status;
- uint16_t ecc_status;
- #if VERBOSE
- pr_info("================================================="
- "================\n");
- pr_info("%s: from 0x%llx mode %d \ndatbuf 0x%p datlen 0x%x"
- "\noobbuf 0x%p ooblen 0x%x\n",
- __func__, from, ops->mode, ops->datbuf, ops->len,
- ops->oobbuf, ops->ooblen);
- #endif
- if (!mtd) {
- pr_err("%s: invalid mtd pointer, 0x%x\n", __func__,
- (uint32_t)mtd);
- return -EINVAL;
- }
- if (from & (mtd->writesize - 1)) {
- pr_err("%s: unsupported from, 0x%llx\n", __func__,
- from);
- return -EINVAL;
- }
- if ((ops->mode != MTD_OPS_PLACE_OOB) && (ops->mode != MTD_OPS_AUTO_OOB) &&
- (ops->mode != MTD_OPS_RAW)) {
- pr_err("%s: unsupported ops->mode, %d\n", __func__,
- ops->mode);
- return -EINVAL;
- }
- if (((ops->datbuf == NULL) || (ops->len == 0)) &&
- ((ops->oobbuf == NULL) || (ops->ooblen == 0))) {
- pr_err("%s: incorrect ops fields - nothing to do\n",
- __func__);
- return -EINVAL;
- }
- if ((ops->datbuf != NULL) && (ops->len == 0)) {
- pr_err("%s: data buffer passed but length 0\n",
- __func__);
- return -EINVAL;
- }
- if ((ops->oobbuf != NULL) && (ops->ooblen == 0)) {
- pr_err("%s: oob buffer passed but length 0\n",
- __func__);
- return -EINVAL;
- }
- if (ops->mode != MTD_OPS_RAW) {
- if (ops->datbuf != NULL && (ops->len % mtd->writesize) != 0) {
- /* when ops->datbuf is NULL, ops->len can be ooblen */
- pr_err("%s: unsupported ops->len, %d\n", __func__,
- ops->len);
- return -EINVAL;
- }
- } else {
- if (ops->datbuf != NULL &&
- (ops->len % (mtd->writesize + mtd->oobsize)) != 0) {
- pr_err("%s: unsupported ops->len,"
- " %d for MTD_OPS_RAW\n", __func__, ops->len);
- return -EINVAL;
- }
- }
- if ((ops->mode == MTD_OPS_RAW) && (ops->oobbuf)) {
- pr_err("%s: unsupported operation, oobbuf pointer "
- "passed in for RAW mode, %x\n", __func__,
- (uint32_t)ops->oobbuf);
- return -EINVAL;
- }
- if (ops->oobbuf && !ops->datbuf) {
- page_count = ops->ooblen / ((ops->mode == MTD_OPS_AUTO_OOB) ?
- mtd->oobavail : mtd->oobsize);
- if ((page_count == 0) && (ops->ooblen))
- page_count = 1;
- } else if (ops->mode != MTD_OPS_RAW)
- page_count = ops->len / mtd->writesize;
- else
- page_count = ops->len / (mtd->writesize + mtd->oobsize);
- if ((ops->mode == MTD_OPS_PLACE_OOB) && (ops->oobbuf != NULL)) {
- if (page_count * mtd->oobsize > ops->ooblen) {
- pr_err("%s: unsupported ops->ooblen for "
- "PLACE, %d\n", __func__, ops->ooblen);
- return -EINVAL;
- }
- }
- if ((ops->mode == MTD_OPS_PLACE_OOB) && (ops->ooblen != 0) &&
- (ops->ooboffs != 0)) {
- pr_err("%s: unsupported ops->ooboffs, %d\n", __func__,
- ops->ooboffs);
- return -EINVAL;
- }
- if (ops->datbuf) {
- memset(ops->datbuf, 0x55, ops->len);
- data_dma_addr_curr = data_dma_addr = msm_nand_dma_map(chip->dev,
- ops->datbuf, ops->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(chip->dev, data_dma_addr)) {
- pr_err("%s: failed to get dma addr for %p\n",
- __func__, ops->datbuf);
- return -EIO;
- }
- }
- if (ops->oobbuf) {
- memset(ops->oobbuf, 0x55, ops->ooblen);
- oob_dma_addr_curr = oob_dma_addr = msm_nand_dma_map(chip->dev,
- ops->oobbuf, ops->ooblen, DMA_FROM_DEVICE);
- if (dma_mapping_error(chip->dev, oob_dma_addr)) {
- pr_err("%s: failed to get dma addr for %p\n",
- __func__, ops->oobbuf);
- err = -EIO;
- goto err_dma_map_oobbuf_failed;
- }
- }
- wait_event(chip->wait_queue, (dma_buffer = msm_nand_get_dma_buffer
- (chip, sizeof(*dma_buffer))));
- from_curr = from;
- while (page_count-- > 0) {
- cmd = dma_buffer->cmd;
- if ((onenand_info.device_id & ONENAND_DEVICE_IS_DDP)
- && (from_curr >= (mtd->size>>1))) { /* DDP Device */
- onenand_startaddr1 = DEVICE_FLASHCORE_1 |
- (((uint32_t)(from_curr-(mtd->size>>1))
- / mtd->erasesize));
- onenand_startaddr2 = DEVICE_BUFFERRAM_1;
- } else {
- onenand_startaddr1 = DEVICE_FLASHCORE_0 |
- ((uint32_t)from_curr / mtd->erasesize) ;
- onenand_startaddr2 = DEVICE_BUFFERRAM_0;
- }
- onenand_startaddr8 = (((uint32_t)from_curr &
- (mtd->erasesize - 1)) / mtd->writesize) << 2;
- onenand_startbuffer = DATARAM0_0 << 8;
- onenand_sysconfig1 = (ops->mode == MTD_OPS_RAW) ?
- ONENAND_SYSCFG1_ECCDIS(nand_sfcmd_mode) :
- ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode);
- dma_buffer->data.sfbcfg = SFLASH_BCFG |
- (nand_sfcmd_mode ? 0 : (1 << 24));
- dma_buffer->data.sfcmd[0] = SFLASH_PREPCMD(7, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfcmd[1] = SFLASH_PREPCMD(0, 0, 32,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_INTHI);
- dma_buffer->data.sfcmd[2] = SFLASH_PREPCMD(3, 7, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGRD);
- dma_buffer->data.sfcmd[3] = SFLASH_PREPCMD(256, 0, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATRD);
- dma_buffer->data.sfcmd[4] = SFLASH_PREPCMD(256, 0, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATRD);
- dma_buffer->data.sfcmd[5] = SFLASH_PREPCMD(256, 0, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATRD);
- dma_buffer->data.sfcmd[6] = SFLASH_PREPCMD(256, 0, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATRD);
- dma_buffer->data.sfcmd[7] = SFLASH_PREPCMD(32, 0, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATRD);
- dma_buffer->data.sfcmd[8] = SFLASH_PREPCMD(4, 10, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfexec = 1;
- dma_buffer->data.sfstat[0] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[1] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[2] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[3] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[4] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[5] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[6] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[7] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[8] = CLEAN_DATA_32;
- dma_buffer->data.addr0 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr1 = (ONENAND_START_ADDRESS_8 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.addr2 = (ONENAND_START_BUFFER << 16) |
- (ONENAND_START_ADDRESS_2);
- dma_buffer->data.addr3 = (ONENAND_ECC_STATUS << 16) |
- (ONENAND_COMMAND);
- dma_buffer->data.addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
- (ONENAND_INTERRUPT_STATUS);
- dma_buffer->data.addr5 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr6 = (ONENAND_START_ADDRESS_3 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.data0 = (ONENAND_CLRINTR << 16) |
- (onenand_sysconfig1);
- dma_buffer->data.data1 = (onenand_startaddr8 << 16) |
- (onenand_startaddr1);
- dma_buffer->data.data2 = (onenand_startbuffer << 16) |
- (onenand_startaddr2);
- dma_buffer->data.data3 = (CLEAN_DATA_16 << 16) |
- (ONENAND_CMDLOADSPARE);
- dma_buffer->data.data4 = (CLEAN_DATA_16 << 16) |
- (CLEAN_DATA_16);
- dma_buffer->data.data5 = (ONENAND_CLRINTR << 16) |
- (ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode));
- dma_buffer->data.data6 = (ONENAND_STARTADDR3_RES << 16) |
- (ONENAND_STARTADDR1_RES);
- dma_buffer->data.macro[0] = 0x0200;
- dma_buffer->data.macro[1] = 0x0300;
- dma_buffer->data.macro[2] = 0x0400;
- dma_buffer->data.macro[3] = 0x0500;
- dma_buffer->data.macro[4] = 0x8010;
- /*************************************************************/
- /* Write necessary address registers in the onenand device */
- /*************************************************************/
- /* Enable and configure the SFlash controller */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfbcfg);
- cmd->dst = MSM_NAND_SFLASHC_BURST_CFG;
- cmd->len = 4;
- cmd++;
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[0]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Write the ADDR0 and ADDR1 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr0);
- cmd->dst = MSM_NAND_ADDR0;
- cmd->len = 8;
- cmd++;
- /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr2);
- cmd->dst = MSM_NAND_ADDR2;
- cmd->len = 16;
- cmd++;
- /* Write the ADDR6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr6);
- cmd->dst = MSM_NAND_ADDR6;
- cmd->len = 4;
- cmd++;
- /* Write the GENP0, GENP1, GENP2, GENP3 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data0);
- cmd->dst = MSM_NAND_GENP_REG0;
- cmd->len = 16;
- cmd++;
- /* Write the FLASH_DEV_CMD4,5,6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->dst = MSM_NAND_DEV_CMD4;
- cmd->len = 12;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[0]);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Wait for the interrupt from the Onenand device controller */
- /*************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[1]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[1]);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Read necessary status registers from the onenand device */
- /*************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[2]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[2]);
- cmd->len = 4;
- cmd++;
- /* Read the GENP3 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_GENP_REG3;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data3);
- cmd->len = 4;
- cmd++;
- /* Read the DEVCMD4 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_DEV_CMD4;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Read the data ram area from the onenand buffer ram */
- /*************************************************************/
- if (ops->datbuf) {
- dma_buffer->data.data3 = (CLEAN_DATA_16 << 16) |
- (ONENAND_CMDLOAD);
- for (i = 0; i < 4; i++) {
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.sfcmd[3+i]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Write the MACRO1 register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.macro[i]);
- cmd->dst = MSM_NAND_MACRO1_REG;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data rdy, & read status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.sfstat[3+i]);
- cmd->len = 4;
- cmd++;
- /* Transfer nand ctlr buf contents to usr buf */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_FLASH_BUFFER;
- cmd->dst = data_dma_addr_curr;
- cmd->len = 512;
- data_dma_addr_curr += 512;
- cmd++;
- }
- }
- if ((ops->oobbuf) || (ops->mode == MTD_OPS_RAW)) {
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.sfcmd[7]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Write the MACRO1 register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.macro[4]);
- cmd->dst = MSM_NAND_MACRO1_REG;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.sfstat[7]);
- cmd->len = 4;
- cmd++;
- /* Transfer nand ctlr buffer contents into usr buf */
- if (ops->mode == MTD_OPS_AUTO_OOB) {
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
- cmd->cmd = 0;
- cmd->src = MSM_NAND_FLASH_BUFFER +
- mtd->ecclayout->oobfree[i].offset;
- cmd->dst = oob_dma_addr_curr;
- cmd->len =
- mtd->ecclayout->oobfree[i].length;
- oob_dma_addr_curr +=
- mtd->ecclayout->oobfree[i].length;
- cmd++;
- }
- }
- if (ops->mode == MTD_OPS_PLACE_OOB) {
- cmd->cmd = 0;
- cmd->src = MSM_NAND_FLASH_BUFFER;
- cmd->dst = oob_dma_addr_curr;
- cmd->len = mtd->oobsize;
- oob_dma_addr_curr += mtd->oobsize;
- cmd++;
- }
- if (ops->mode == MTD_OPS_RAW) {
- cmd->cmd = 0;
- cmd->src = MSM_NAND_FLASH_BUFFER;
- cmd->dst = data_dma_addr_curr;
- cmd->len = mtd->oobsize;
- data_dma_addr_curr += mtd->oobsize;
- cmd++;
- }
- }
- /*************************************************************/
- /* Restore the necessary registers to proper values */
- /*************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[8]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[8]);
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(53 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd)
- >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- ecc_status = (dma_buffer->data.data3 >> 16) &
- 0x0000FFFF;
- interrupt_status = (dma_buffer->data.data4 >> 0) &
- 0x0000FFFF;
- controller_status = (dma_buffer->data.data4 >> 16) &
- 0x0000FFFF;
- #if VERBOSE
- pr_info("\n%s: sflash status %x %x %x %x %x %x %x"
- "%x %x\n", __func__,
- dma_buffer->data.sfstat[0],
- dma_buffer->data.sfstat[1],
- dma_buffer->data.sfstat[2],
- dma_buffer->data.sfstat[3],
- dma_buffer->data.sfstat[4],
- dma_buffer->data.sfstat[5],
- dma_buffer->data.sfstat[6],
- dma_buffer->data.sfstat[7],
- dma_buffer->data.sfstat[8]);
- pr_info("%s: controller_status = %x\n", __func__,
- controller_status);
- pr_info("%s: interrupt_status = %x\n", __func__,
- interrupt_status);
- pr_info("%s: ecc_status = %x\n", __func__,
- ecc_status);
- #endif
- /* Check for errors, protection violations etc */
- if ((controller_status != 0)
- || (dma_buffer->data.sfstat[0] & 0x110)
- || (dma_buffer->data.sfstat[1] & 0x110)
- || (dma_buffer->data.sfstat[2] & 0x110)
- || (dma_buffer->data.sfstat[8] & 0x110)
- || ((dma_buffer->data.sfstat[3] & 0x110) &&
- (ops->datbuf))
- || ((dma_buffer->data.sfstat[4] & 0x110) &&
- (ops->datbuf))
- || ((dma_buffer->data.sfstat[5] & 0x110) &&
- (ops->datbuf))
- || ((dma_buffer->data.sfstat[6] & 0x110) &&
- (ops->datbuf))
- || ((dma_buffer->data.sfstat[7] & 0x110) &&
- ((ops->oobbuf)
- || (ops->mode == MTD_OPS_RAW)))) {
- pr_info("%s: ECC/MPU/OP error\n", __func__);
- err = -EIO;
- }
- if (err)
- break;
- pages_read++;
- from_curr += mtd->writesize;
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- if (ops->oobbuf) {
- dma_unmap_page(chip->dev, oob_dma_addr, ops->ooblen,
- DMA_FROM_DEVICE);
- }
- err_dma_map_oobbuf_failed:
- if (ops->datbuf) {
- dma_unmap_page(chip->dev, data_dma_addr, ops->len,
- DMA_FROM_DEVICE);
- }
- if (err) {
- pr_err("%s: %llx %x %x failed\n", __func__, from_curr,
- ops->datbuf ? ops->len : 0, ops->ooblen);
- } else {
- ops->retlen = ops->oobretlen = 0;
- if (ops->datbuf != NULL) {
- if (ops->mode != MTD_OPS_RAW)
- ops->retlen = mtd->writesize * pages_read;
- else
- ops->retlen = (mtd->writesize + mtd->oobsize)
- * pages_read;
- }
- if (ops->oobbuf != NULL) {
- if (ops->mode == MTD_OPS_AUTO_OOB)
- ops->oobretlen = mtd->oobavail * pages_read;
- else
- ops->oobretlen = mtd->oobsize * pages_read;
- }
- }
- #if VERBOSE
- pr_info("\n%s: ret %d, retlen %d oobretlen %d\n",
- __func__, err, ops->retlen, ops->oobretlen);
- pr_info("==================================================="
- "==============\n");
- #endif
- return err;
- }
- int msm_onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
- {
- int ret;
- struct mtd_oob_ops ops;
- ops.mode = MTD_OPS_PLACE_OOB;
- ops.datbuf = buf;
- ops.len = len;
- ops.retlen = 0;
- ops.oobbuf = NULL;
- ops.ooblen = 0;
- ops.oobretlen = 0;
- ret = msm_onenand_read_oob(mtd, from, &ops);
- *retlen = ops.retlen;
- return ret;
- }
- static int msm_onenand_write_oob(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[53];
- unsigned cmdptr;
- struct {
- uint32_t sfbcfg;
- uint32_t sfcmd[10];
- uint32_t sfexec;
- uint32_t sfstat[10];
- uint32_t addr0;
- uint32_t addr1;
- uint32_t addr2;
- uint32_t addr3;
- uint32_t addr4;
- uint32_t addr5;
- uint32_t addr6;
- uint32_t data0;
- uint32_t data1;
- uint32_t data2;
- uint32_t data3;
- uint32_t data4;
- uint32_t data5;
- uint32_t data6;
- uint32_t macro[5];
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- int err = 0;
- int i, j, k;
- dma_addr_t data_dma_addr = 0;
- dma_addr_t oob_dma_addr = 0;
- dma_addr_t init_dma_addr = 0;
- dma_addr_t data_dma_addr_curr = 0;
- dma_addr_t oob_dma_addr_curr = 0;
- uint8_t *init_spare_bytes;
- loff_t to_curr = 0;
- unsigned page_count;
- unsigned pages_written = 0;
- uint16_t onenand_startaddr1;
- uint16_t onenand_startaddr8;
- uint16_t onenand_startaddr2;
- uint16_t onenand_startbuffer;
- uint16_t onenand_sysconfig1;
- uint16_t controller_status;
- uint16_t interrupt_status;
- uint16_t ecc_status;
- #if VERBOSE
- pr_info("================================================="
- "================\n");
- pr_info("%s: to 0x%llx mode %d \ndatbuf 0x%p datlen 0x%x"
- "\noobbuf 0x%p ooblen 0x%x\n",
- __func__, to, ops->mode, ops->datbuf, ops->len,
- ops->oobbuf, ops->ooblen);
- #endif
- if (!mtd) {
- pr_err("%s: invalid mtd pointer, 0x%x\n", __func__,
- (uint32_t)mtd);
- return -EINVAL;
- }
- if (to & (mtd->writesize - 1)) {
- pr_err("%s: unsupported to, 0x%llx\n", __func__, to);
- return -EINVAL;
- }
- if ((ops->mode != MTD_OPS_PLACE_OOB) && (ops->mode != MTD_OPS_AUTO_OOB) &&
- (ops->mode != MTD_OPS_RAW)) {
- pr_err("%s: unsupported ops->mode, %d\n", __func__,
- ops->mode);
- return -EINVAL;
- }
- if (((ops->datbuf == NULL) || (ops->len == 0)) &&
- ((ops->oobbuf == NULL) || (ops->ooblen == 0))) {
- pr_err("%s: incorrect ops fields - nothing to do\n",
- __func__);
- return -EINVAL;
- }
- if ((ops->datbuf != NULL) && (ops->len == 0)) {
- pr_err("%s: data buffer passed but length 0\n",
- __func__);
- return -EINVAL;
- }
- if ((ops->oobbuf != NULL) && (ops->ooblen == 0)) {
- pr_err("%s: oob buffer passed but length 0\n",
- __func__);
- return -EINVAL;
- }
- if (ops->mode != MTD_OPS_RAW) {
- if (ops->datbuf != NULL && (ops->len % mtd->writesize) != 0) {
- /* when ops->datbuf is NULL, ops->len can be ooblen */
- pr_err("%s: unsupported ops->len, %d\n", __func__,
- ops->len);
- return -EINVAL;
- }
- } else {
- if (ops->datbuf != NULL &&
- (ops->len % (mtd->writesize + mtd->oobsize)) != 0) {
- pr_err("%s: unsupported ops->len,"
- " %d for MTD_OPS_RAW\n", __func__, ops->len);
- return -EINVAL;
- }
- }
- if ((ops->mode == MTD_OPS_RAW) && (ops->oobbuf)) {
- pr_err("%s: unsupported operation, oobbuf pointer "
- "passed in for RAW mode, %x\n", __func__,
- (uint32_t)ops->oobbuf);
- return -EINVAL;
- }
- if (ops->oobbuf && !ops->datbuf) {
- page_count = ops->ooblen / ((ops->mode == MTD_OPS_AUTO_OOB) ?
- mtd->oobavail : mtd->oobsize);
- if ((page_count == 0) && (ops->ooblen))
- page_count = 1;
- } else if (ops->mode != MTD_OPS_RAW)
- page_count = ops->len / mtd->writesize;
- else
- page_count = ops->len / (mtd->writesize + mtd->oobsize);
- if ((ops->mode == MTD_OPS_AUTO_OOB) && (ops->oobbuf != NULL)) {
- if (page_count > 1) {
- pr_err("%s: unsupported ops->ooblen for"
- "AUTO, %d\n", __func__, ops->ooblen);
- return -EINVAL;
- }
- }
- if ((ops->mode == MTD_OPS_PLACE_OOB) && (ops->oobbuf != NULL)) {
- if (page_count * mtd->oobsize > ops->ooblen) {
- pr_err("%s: unsupported ops->ooblen for"
- "PLACE, %d\n", __func__, ops->ooblen);
- return -EINVAL;
- }
- }
- if ((ops->mode == MTD_OPS_PLACE_OOB) && (ops->ooblen != 0) &&
- (ops->ooboffs != 0)) {
- pr_err("%s: unsupported ops->ooboffs, %d\n",
- __func__, ops->ooboffs);
- return -EINVAL;
- }
- init_spare_bytes = kmalloc(64, GFP_KERNEL);
- if (!init_spare_bytes) {
- pr_err("%s: failed to alloc init_spare_bytes buffer\n",
- __func__);
- return -ENOMEM;
- }
- for (i = 0; i < 64; i++)
- init_spare_bytes[i] = 0xFF;
- if ((ops->oobbuf) && (ops->mode == MTD_OPS_AUTO_OOB)) {
- for (i = 0, k = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++)
- for (j = 0; j < mtd->ecclayout->oobfree[i].length;
- j++) {
- init_spare_bytes[j +
- mtd->ecclayout->oobfree[i].offset]
- = (ops->oobbuf)[k];
- k++;
- }
- }
- if (ops->datbuf) {
- data_dma_addr_curr = data_dma_addr = msm_nand_dma_map(chip->dev,
- ops->datbuf, ops->len, DMA_TO_DEVICE);
- if (dma_mapping_error(chip->dev, data_dma_addr)) {
- pr_err("%s: failed to get dma addr for %p\n",
- __func__, ops->datbuf);
- return -EIO;
- }
- }
- if (ops->oobbuf) {
- oob_dma_addr_curr = oob_dma_addr = msm_nand_dma_map(chip->dev,
- ops->oobbuf, ops->ooblen, DMA_TO_DEVICE);
- if (dma_mapping_error(chip->dev, oob_dma_addr)) {
- pr_err("%s: failed to get dma addr for %p\n",
- __func__, ops->oobbuf);
- err = -EIO;
- goto err_dma_map_oobbuf_failed;
- }
- }
- init_dma_addr = msm_nand_dma_map(chip->dev, init_spare_bytes, 64,
- DMA_TO_DEVICE);
- if (dma_mapping_error(chip->dev, init_dma_addr)) {
- pr_err("%s: failed to get dma addr for %p\n",
- __func__, init_spare_bytes);
- err = -EIO;
- goto err_dma_map_initbuf_failed;
- }
- wait_event(chip->wait_queue, (dma_buffer = msm_nand_get_dma_buffer
- (chip, sizeof(*dma_buffer))));
- to_curr = to;
- while (page_count-- > 0) {
- cmd = dma_buffer->cmd;
- if ((onenand_info.device_id & ONENAND_DEVICE_IS_DDP)
- && (to_curr >= (mtd->size>>1))) { /* DDP Device */
- onenand_startaddr1 = DEVICE_FLASHCORE_1 |
- (((uint32_t)(to_curr-(mtd->size>>1))
- / mtd->erasesize));
- onenand_startaddr2 = DEVICE_BUFFERRAM_1;
- } else {
- onenand_startaddr1 = DEVICE_FLASHCORE_0 |
- ((uint32_t)to_curr / mtd->erasesize) ;
- onenand_startaddr2 = DEVICE_BUFFERRAM_0;
- }
- onenand_startaddr8 = (((uint32_t)to_curr &
- (mtd->erasesize - 1)) / mtd->writesize) << 2;
- onenand_startbuffer = DATARAM0_0 << 8;
- onenand_sysconfig1 = (ops->mode == MTD_OPS_RAW) ?
- ONENAND_SYSCFG1_ECCDIS(nand_sfcmd_mode) :
- ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode);
- dma_buffer->data.sfbcfg = SFLASH_BCFG |
- (nand_sfcmd_mode ? 0 : (1 << 24));
- dma_buffer->data.sfcmd[0] = SFLASH_PREPCMD(6, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfcmd[1] = SFLASH_PREPCMD(256, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATWR);
- dma_buffer->data.sfcmd[2] = SFLASH_PREPCMD(256, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATWR);
- dma_buffer->data.sfcmd[3] = SFLASH_PREPCMD(256, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATWR);
- dma_buffer->data.sfcmd[4] = SFLASH_PREPCMD(256, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATWR);
- dma_buffer->data.sfcmd[5] = SFLASH_PREPCMD(32, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_DATWR);
- dma_buffer->data.sfcmd[6] = SFLASH_PREPCMD(1, 6, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfcmd[7] = SFLASH_PREPCMD(0, 0, 32,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_INTHI);
- dma_buffer->data.sfcmd[8] = SFLASH_PREPCMD(3, 7, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGRD);
- dma_buffer->data.sfcmd[9] = SFLASH_PREPCMD(4, 10, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfexec = 1;
- dma_buffer->data.sfstat[0] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[1] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[2] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[3] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[4] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[5] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[6] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[7] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[8] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[9] = CLEAN_DATA_32;
- dma_buffer->data.addr0 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr1 = (ONENAND_START_ADDRESS_8 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.addr2 = (ONENAND_START_BUFFER << 16) |
- (ONENAND_START_ADDRESS_2);
- dma_buffer->data.addr3 = (ONENAND_ECC_STATUS << 16) |
- (ONENAND_COMMAND);
- dma_buffer->data.addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
- (ONENAND_INTERRUPT_STATUS);
- dma_buffer->data.addr5 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr6 = (ONENAND_START_ADDRESS_3 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.data0 = (ONENAND_CLRINTR << 16) |
- (onenand_sysconfig1);
- dma_buffer->data.data1 = (onenand_startaddr8 << 16) |
- (onenand_startaddr1);
- dma_buffer->data.data2 = (onenand_startbuffer << 16) |
- (onenand_startaddr2);
- dma_buffer->data.data3 = (CLEAN_DATA_16 << 16) |
- (ONENAND_CMDPROGSPARE);
- dma_buffer->data.data4 = (CLEAN_DATA_16 << 16) |
- (CLEAN_DATA_16);
- dma_buffer->data.data5 = (ONENAND_CLRINTR << 16) |
- (ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode));
- dma_buffer->data.data6 = (ONENAND_STARTADDR3_RES << 16) |
- (ONENAND_STARTADDR1_RES);
- dma_buffer->data.macro[0] = 0x0200;
- dma_buffer->data.macro[1] = 0x0300;
- dma_buffer->data.macro[2] = 0x0400;
- dma_buffer->data.macro[3] = 0x0500;
- dma_buffer->data.macro[4] = 0x8010;
- /*************************************************************/
- /* Write necessary address registers in the onenand device */
- /*************************************************************/
- /* Enable and configure the SFlash controller */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfbcfg);
- cmd->dst = MSM_NAND_SFLASHC_BURST_CFG;
- cmd->len = 4;
- cmd++;
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[0]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Write the ADDR0 and ADDR1 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr0);
- cmd->dst = MSM_NAND_ADDR0;
- cmd->len = 8;
- cmd++;
- /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr2);
- cmd->dst = MSM_NAND_ADDR2;
- cmd->len = 16;
- cmd++;
- /* Write the ADDR6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr6);
- cmd->dst = MSM_NAND_ADDR6;
- cmd->len = 4;
- cmd++;
- /* Write the GENP0, GENP1, GENP2, GENP3 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data0);
- cmd->dst = MSM_NAND_GENP_REG0;
- cmd->len = 16;
- cmd++;
- /* Write the FLASH_DEV_CMD4,5,6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->dst = MSM_NAND_DEV_CMD4;
- cmd->len = 12;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[0]);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Write the data ram area in the onenand buffer ram */
- /*************************************************************/
- if (ops->datbuf) {
- dma_buffer->data.data3 = (CLEAN_DATA_16 << 16) |
- (ONENAND_CMDPROG);
- for (i = 0; i < 4; i++) {
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.sfcmd[1+i]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Trnsfr usr buf contents to nand ctlr buf */
- cmd->cmd = 0;
- cmd->src = data_dma_addr_curr;
- cmd->dst = MSM_NAND_FLASH_BUFFER;
- cmd->len = 512;
- data_dma_addr_curr += 512;
- cmd++;
- /* Write the MACRO1 register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.macro[i]);
- cmd->dst = MSM_NAND_MACRO1_REG;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip,
- &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data rdy, & read status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip,
- &dma_buffer->data.sfstat[1+i]);
- cmd->len = 4;
- cmd++;
- }
- }
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[5]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- if ((ops->oobbuf) || (ops->mode == MTD_OPS_RAW)) {
- /* Transfer user buf contents into nand ctlr buffer */
- if (ops->mode == MTD_OPS_AUTO_OOB) {
- cmd->cmd = 0;
- cmd->src = init_dma_addr;
- cmd->dst = MSM_NAND_FLASH_BUFFER;
- cmd->len = mtd->oobsize;
- cmd++;
- }
- if (ops->mode == MTD_OPS_PLACE_OOB) {
- cmd->cmd = 0;
- cmd->src = oob_dma_addr_curr;
- cmd->dst = MSM_NAND_FLASH_BUFFER;
- cmd->len = mtd->oobsize;
- oob_dma_addr_curr += mtd->oobsize;
- cmd++;
- }
- if (ops->mode == MTD_OPS_RAW) {
- cmd->cmd = 0;
- cmd->src = data_dma_addr_curr;
- cmd->dst = MSM_NAND_FLASH_BUFFER;
- cmd->len = mtd->oobsize;
- data_dma_addr_curr += mtd->oobsize;
- cmd++;
- }
- } else {
- cmd->cmd = 0;
- cmd->src = init_dma_addr;
- cmd->dst = MSM_NAND_FLASH_BUFFER;
- cmd->len = mtd->oobsize;
- cmd++;
- }
- /* Write the MACRO1 register */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.macro[4]);
- cmd->dst = MSM_NAND_MACRO1_REG;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[5]);
- cmd->len = 4;
- cmd++;
- /*********************************************************/
- /* Issuing write command */
- /*********************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[6]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[6]);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Wait for the interrupt from the Onenand device controller */
- /*************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[7]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[7]);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Read necessary status registers from the onenand device */
- /*************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[8]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[8]);
- cmd->len = 4;
- cmd++;
- /* Read the GENP3 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_GENP_REG3;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data3);
- cmd->len = 4;
- cmd++;
- /* Read the DEVCMD4 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_DEV_CMD4;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Restore the necessary registers to proper values */
- /*************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[9]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[9]);
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(53 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd)
- >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- ecc_status = (dma_buffer->data.data3 >> 16) & 0x0000FFFF;
- interrupt_status = (dma_buffer->data.data4 >> 0)&0x0000FFFF;
- controller_status = (dma_buffer->data.data4 >> 16)&0x0000FFFF;
- #if VERBOSE
- pr_info("\n%s: sflash status %x %x %x %x %x %x %x"
- " %x %x %x\n", __func__,
- dma_buffer->data.sfstat[0],
- dma_buffer->data.sfstat[1],
- dma_buffer->data.sfstat[2],
- dma_buffer->data.sfstat[3],
- dma_buffer->data.sfstat[4],
- dma_buffer->data.sfstat[5],
- dma_buffer->data.sfstat[6],
- dma_buffer->data.sfstat[7],
- dma_buffer->data.sfstat[8],
- dma_buffer->data.sfstat[9]);
- pr_info("%s: controller_status = %x\n", __func__,
- controller_status);
- pr_info("%s: interrupt_status = %x\n", __func__,
- interrupt_status);
- pr_info("%s: ecc_status = %x\n", __func__,
- ecc_status);
- #endif
- /* Check for errors, protection violations etc */
- if ((controller_status != 0)
- || (dma_buffer->data.sfstat[0] & 0x110)
- || (dma_buffer->data.sfstat[6] & 0x110)
- || (dma_buffer->data.sfstat[7] & 0x110)
- || (dma_buffer->data.sfstat[8] & 0x110)
- || (dma_buffer->data.sfstat[9] & 0x110)
- || ((dma_buffer->data.sfstat[1] & 0x110) &&
- (ops->datbuf))
- || ((dma_buffer->data.sfstat[2] & 0x110) &&
- (ops->datbuf))
- || ((dma_buffer->data.sfstat[3] & 0x110) &&
- (ops->datbuf))
- || ((dma_buffer->data.sfstat[4] & 0x110) &&
- (ops->datbuf))
- || ((dma_buffer->data.sfstat[5] & 0x110) &&
- ((ops->oobbuf)
- || (ops->mode == MTD_OPS_RAW)))) {
- pr_info("%s: ECC/MPU/OP error\n", __func__);
- err = -EIO;
- }
- if (err)
- break;
- pages_written++;
- to_curr += mtd->writesize;
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- dma_unmap_page(chip->dev, init_dma_addr, 64, DMA_TO_DEVICE);
- err_dma_map_initbuf_failed:
- if (ops->oobbuf) {
- dma_unmap_page(chip->dev, oob_dma_addr, ops->ooblen,
- DMA_TO_DEVICE);
- }
- err_dma_map_oobbuf_failed:
- if (ops->datbuf) {
- dma_unmap_page(chip->dev, data_dma_addr, ops->len,
- DMA_TO_DEVICE);
- }
- if (err) {
- pr_err("%s: %llx %x %x failed\n", __func__, to_curr,
- ops->datbuf ? ops->len : 0, ops->ooblen);
- } else {
- ops->retlen = ops->oobretlen = 0;
- if (ops->datbuf != NULL) {
- if (ops->mode != MTD_OPS_RAW)
- ops->retlen = mtd->writesize * pages_written;
- else
- ops->retlen = (mtd->writesize + mtd->oobsize)
- * pages_written;
- }
- if (ops->oobbuf != NULL) {
- if (ops->mode == MTD_OPS_AUTO_OOB)
- ops->oobretlen = mtd->oobavail * pages_written;
- else
- ops->oobretlen = mtd->oobsize * pages_written;
- }
- }
- #if VERBOSE
- pr_info("\n%s: ret %d, retlen %d oobretlen %d\n",
- __func__, err, ops->retlen, ops->oobretlen);
- pr_info("================================================="
- "================\n");
- #endif
- kfree(init_spare_bytes);
- return err;
- }
- static int msm_onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
- {
- int ret;
- struct mtd_oob_ops ops;
- ops.mode = MTD_OPS_PLACE_OOB;
- ops.datbuf = (uint8_t *)buf;
- ops.len = len;
- ops.retlen = 0;
- ops.oobbuf = NULL;
- ops.ooblen = 0;
- ops.oobretlen = 0;
- ret = msm_onenand_write_oob(mtd, to, &ops);
- *retlen = ops.retlen;
- return ret;
- }
- static int msm_onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[20];
- unsigned cmdptr;
- struct {
- uint32_t sfbcfg;
- uint32_t sfcmd[4];
- uint32_t sfexec;
- uint32_t sfstat[4];
- uint32_t addr0;
- uint32_t addr1;
- uint32_t addr2;
- uint32_t addr3;
- uint32_t addr4;
- uint32_t addr5;
- uint32_t addr6;
- uint32_t data0;
- uint32_t data1;
- uint32_t data2;
- uint32_t data3;
- uint32_t data4;
- uint32_t data5;
- uint32_t data6;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- int err = 0;
- uint16_t onenand_startaddr1;
- uint16_t onenand_startaddr8;
- uint16_t onenand_startaddr2;
- uint16_t onenand_startbuffer;
- uint16_t controller_status;
- uint16_t interrupt_status;
- uint16_t ecc_status;
- uint64_t temp;
- #if VERBOSE
- pr_info("================================================="
- "================\n");
- pr_info("%s: addr 0x%llx len 0x%llx\n",
- __func__, instr->addr, instr->len);
- #endif
- if (instr->addr & (mtd->erasesize - 1)) {
- pr_err("%s: Unsupported erase address, 0x%llx\n",
- __func__, instr->addr);
- return -EINVAL;
- }
- if (instr->len != mtd->erasesize) {
- pr_err("%s: Unsupported erase len, %lld\n",
- __func__, instr->len);
- return -EINVAL;
- }
- wait_event(chip->wait_queue, (dma_buffer = msm_nand_get_dma_buffer
- (chip, sizeof(*dma_buffer))));
- cmd = dma_buffer->cmd;
- temp = instr->addr;
- if ((onenand_info.device_id & ONENAND_DEVICE_IS_DDP)
- && (temp >= (mtd->size>>1))) { /* DDP Device */
- onenand_startaddr1 = DEVICE_FLASHCORE_1 |
- (((uint32_t)(temp-(mtd->size>>1))
- / mtd->erasesize));
- onenand_startaddr2 = DEVICE_BUFFERRAM_1;
- } else {
- onenand_startaddr1 = DEVICE_FLASHCORE_0 |
- ((uint32_t)temp / mtd->erasesize) ;
- onenand_startaddr2 = DEVICE_BUFFERRAM_0;
- }
- onenand_startaddr8 = 0x0000;
- onenand_startbuffer = DATARAM0_0 << 8;
- dma_buffer->data.sfbcfg = SFLASH_BCFG |
- (nand_sfcmd_mode ? 0 : (1 << 24));
- dma_buffer->data.sfcmd[0] = SFLASH_PREPCMD(7, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfcmd[1] = SFLASH_PREPCMD(0, 0, 32,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_INTHI);
- dma_buffer->data.sfcmd[2] = SFLASH_PREPCMD(3, 7, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGRD);
- dma_buffer->data.sfcmd[3] = SFLASH_PREPCMD(4, 10, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfexec = 1;
- dma_buffer->data.sfstat[0] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[1] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[2] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[3] = CLEAN_DATA_32;
- dma_buffer->data.addr0 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr1 = (ONENAND_START_ADDRESS_8 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.addr2 = (ONENAND_START_BUFFER << 16) |
- (ONENAND_START_ADDRESS_2);
- dma_buffer->data.addr3 = (ONENAND_ECC_STATUS << 16) |
- (ONENAND_COMMAND);
- dma_buffer->data.addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
- (ONENAND_INTERRUPT_STATUS);
- dma_buffer->data.addr5 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr6 = (ONENAND_START_ADDRESS_3 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.data0 = (ONENAND_CLRINTR << 16) |
- (ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode));
- dma_buffer->data.data1 = (onenand_startaddr8 << 16) |
- (onenand_startaddr1);
- dma_buffer->data.data2 = (onenand_startbuffer << 16) |
- (onenand_startaddr2);
- dma_buffer->data.data3 = (CLEAN_DATA_16 << 16) |
- (ONENAND_CMDERAS);
- dma_buffer->data.data4 = (CLEAN_DATA_16 << 16) |
- (CLEAN_DATA_16);
- dma_buffer->data.data5 = (ONENAND_CLRINTR << 16) |
- (ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode));
- dma_buffer->data.data6 = (ONENAND_STARTADDR3_RES << 16) |
- (ONENAND_STARTADDR1_RES);
- /***************************************************************/
- /* Write the necessary address registers in the onenand device */
- /***************************************************************/
- /* Enable and configure the SFlash controller */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfbcfg);
- cmd->dst = MSM_NAND_SFLASHC_BURST_CFG;
- cmd->len = 4;
- cmd++;
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[0]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Write the ADDR0 and ADDR1 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr0);
- cmd->dst = MSM_NAND_ADDR0;
- cmd->len = 8;
- cmd++;
- /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr2);
- cmd->dst = MSM_NAND_ADDR2;
- cmd->len = 16;
- cmd++;
- /* Write the ADDR6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr6);
- cmd->dst = MSM_NAND_ADDR6;
- cmd->len = 4;
- cmd++;
- /* Write the GENP0, GENP1, GENP2, GENP3, GENP4 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data0);
- cmd->dst = MSM_NAND_GENP_REG0;
- cmd->len = 16;
- cmd++;
- /* Write the FLASH_DEV_CMD4,5,6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->dst = MSM_NAND_DEV_CMD4;
- cmd->len = 12;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[0]);
- cmd->len = 4;
- cmd++;
- /***************************************************************/
- /* Wait for the interrupt from the Onenand device controller */
- /***************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[1]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[1]);
- cmd->len = 4;
- cmd++;
- /***************************************************************/
- /* Read the necessary status registers from the onenand device */
- /***************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[2]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[2]);
- cmd->len = 4;
- cmd++;
- /* Read the GENP3 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_GENP_REG3;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data3);
- cmd->len = 4;
- cmd++;
- /* Read the DEVCMD4 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_DEV_CMD4;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->len = 4;
- cmd++;
- /***************************************************************/
- /* Restore the necessary registers to proper values */
- /***************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[3]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[3]);
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(20 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd)
- >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST
- | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- ecc_status = (dma_buffer->data.data3 >> 16) & 0x0000FFFF;
- interrupt_status = (dma_buffer->data.data4 >> 0) & 0x0000FFFF;
- controller_status = (dma_buffer->data.data4 >> 16) & 0x0000FFFF;
- #if VERBOSE
- pr_info("\n%s: sflash status %x %x %x %x\n", __func__,
- dma_buffer->data.sfstat[0],
- dma_buffer->data.sfstat[1],
- dma_buffer->data.sfstat[2],
- dma_buffer->data.sfstat[3]);
- pr_info("%s: controller_status = %x\n", __func__,
- controller_status);
- pr_info("%s: interrupt_status = %x\n", __func__,
- interrupt_status);
- pr_info("%s: ecc_status = %x\n", __func__,
- ecc_status);
- #endif
- /* Check for errors, protection violations etc */
- if ((controller_status != 0)
- || (dma_buffer->data.sfstat[0] & 0x110)
- || (dma_buffer->data.sfstat[1] & 0x110)
- || (dma_buffer->data.sfstat[2] & 0x110)
- || (dma_buffer->data.sfstat[3] & 0x110)) {
- pr_err("%s: ECC/MPU/OP error\n", __func__);
- err = -EIO;
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- if (err) {
- pr_err("%s: Erase failed, 0x%llx\n", __func__,
- instr->addr);
- instr->fail_addr = instr->addr;
- instr->state = MTD_ERASE_FAILED;
- } else {
- instr->state = MTD_ERASE_DONE;
- instr->fail_addr = 0xffffffff;
- mtd_erase_callback(instr);
- }
- #if VERBOSE
- pr_info("\n%s: ret %d\n", __func__, err);
- pr_info("===================================================="
- "=============\n");
- #endif
- return err;
- }
- static int msm_onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
- {
- struct mtd_oob_ops ops;
- int rval, i;
- int ret = 0;
- uint8_t *buffer;
- uint8_t *oobptr;
- if ((ofs > mtd->size) || (ofs & (mtd->erasesize - 1))) {
- pr_err("%s: unsupported block address, 0x%x\n",
- __func__, (uint32_t)ofs);
- return -EINVAL;
- }
- buffer = kmalloc(2112, GFP_KERNEL|GFP_DMA);
- if (buffer == 0) {
- pr_err("%s: Could not kmalloc for buffer\n",
- __func__);
- return -ENOMEM;
- }
- memset(buffer, 0x00, 2112);
- oobptr = &(buffer[2048]);
- ops.mode = MTD_OPS_RAW;
- ops.len = 2112;
- ops.retlen = 0;
- ops.ooblen = 0;
- ops.oobretlen = 0;
- ops.ooboffs = 0;
- ops.datbuf = buffer;
- ops.oobbuf = NULL;
- for (i = 0; i < 2; i++) {
- ofs = ofs + i*mtd->writesize;
- rval = msm_onenand_read_oob(mtd, ofs, &ops);
- if (rval) {
- pr_err("%s: Error in reading bad blk info\n",
- __func__);
- ret = rval;
- break;
- }
- if ((oobptr[0] != 0xFF) || (oobptr[1] != 0xFF) ||
- (oobptr[16] != 0xFF) || (oobptr[17] != 0xFF) ||
- (oobptr[32] != 0xFF) || (oobptr[33] != 0xFF) ||
- (oobptr[48] != 0xFF) || (oobptr[49] != 0xFF)
- ) {
- ret = 1;
- break;
- }
- }
- kfree(buffer);
- #if VERBOSE
- if (ret == 1)
- pr_info("%s : Block containing 0x%x is bad\n",
- __func__, (unsigned int)ofs);
- #endif
- return ret;
- }
- static int msm_onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
- {
- struct mtd_oob_ops ops;
- int rval, i;
- int ret = 0;
- uint8_t *buffer;
- if ((ofs > mtd->size) || (ofs & (mtd->erasesize - 1))) {
- pr_err("%s: unsupported block address, 0x%x\n",
- __func__, (uint32_t)ofs);
- return -EINVAL;
- }
- buffer = page_address(ZERO_PAGE());
- ops.mode = MTD_OPS_RAW;
- ops.len = 2112;
- ops.retlen = 0;
- ops.ooblen = 0;
- ops.oobretlen = 0;
- ops.ooboffs = 0;
- ops.datbuf = buffer;
- ops.oobbuf = NULL;
- for (i = 0; i < 2; i++) {
- ofs = ofs + i*mtd->writesize;
- rval = msm_onenand_write_oob(mtd, ofs, &ops);
- if (rval) {
- pr_err("%s: Error in writing bad blk info\n",
- __func__);
- ret = rval;
- break;
- }
- }
- return ret;
- }
- static int msm_onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[20];
- unsigned cmdptr;
- struct {
- uint32_t sfbcfg;
- uint32_t sfcmd[4];
- uint32_t sfexec;
- uint32_t sfstat[4];
- uint32_t addr0;
- uint32_t addr1;
- uint32_t addr2;
- uint32_t addr3;
- uint32_t addr4;
- uint32_t addr5;
- uint32_t addr6;
- uint32_t data0;
- uint32_t data1;
- uint32_t data2;
- uint32_t data3;
- uint32_t data4;
- uint32_t data5;
- uint32_t data6;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- int err = 0;
- uint16_t onenand_startaddr1;
- uint16_t onenand_startaddr8;
- uint16_t onenand_startaddr2;
- uint16_t onenand_startblock;
- uint16_t controller_status;
- uint16_t interrupt_status;
- uint16_t write_prot_status;
- uint64_t start_ofs;
- #if VERBOSE
- pr_info("===================================================="
- "=============\n");
- pr_info("%s: ofs 0x%llx len %lld\n", __func__, ofs, len);
- #endif
- /* 'ofs' & 'len' should align to block size */
- if (ofs&(mtd->erasesize - 1)) {
- pr_err("%s: Unsupported ofs address, 0x%llx\n",
- __func__, ofs);
- return -EINVAL;
- }
- if (len&(mtd->erasesize - 1)) {
- pr_err("%s: Unsupported len, %lld\n",
- __func__, len);
- return -EINVAL;
- }
- if (ofs+len > mtd->size) {
- pr_err("%s: Maximum chip size exceeded\n", __func__);
- return -EINVAL;
- }
- wait_event(chip->wait_queue, (dma_buffer = msm_nand_get_dma_buffer
- (chip, sizeof(*dma_buffer))));
- for (start_ofs = ofs; ofs < start_ofs+len; ofs = ofs+mtd->erasesize) {
- #if VERBOSE
- pr_info("%s: ofs 0x%llx len %lld\n", __func__, ofs, len);
- #endif
- cmd = dma_buffer->cmd;
- if ((onenand_info.device_id & ONENAND_DEVICE_IS_DDP)
- && (ofs >= (mtd->size>>1))) { /* DDP Device */
- onenand_startaddr1 = DEVICE_FLASHCORE_1 |
- (((uint32_t)(ofs - (mtd->size>>1))
- / mtd->erasesize));
- onenand_startaddr2 = DEVICE_BUFFERRAM_1;
- onenand_startblock = ((uint32_t)(ofs - (mtd->size>>1))
- / mtd->erasesize);
- } else {
- onenand_startaddr1 = DEVICE_FLASHCORE_0 |
- ((uint32_t)ofs / mtd->erasesize) ;
- onenand_startaddr2 = DEVICE_BUFFERRAM_0;
- onenand_startblock = ((uint32_t)ofs
- / mtd->erasesize);
- }
- onenand_startaddr8 = 0x0000;
- dma_buffer->data.sfbcfg = SFLASH_BCFG |
- (nand_sfcmd_mode ? 0 : (1 << 24));
- dma_buffer->data.sfcmd[0] = SFLASH_PREPCMD(7, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfcmd[1] = SFLASH_PREPCMD(0, 0, 32,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_INTHI);
- dma_buffer->data.sfcmd[2] = SFLASH_PREPCMD(3, 7, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGRD);
- dma_buffer->data.sfcmd[3] = SFLASH_PREPCMD(4, 10, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfexec = 1;
- dma_buffer->data.sfstat[0] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[1] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[2] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[3] = CLEAN_DATA_32;
- dma_buffer->data.addr0 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr1 = (ONENAND_START_ADDRESS_8 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.addr2 = (ONENAND_START_BLOCK_ADDRESS << 16) |
- (ONENAND_START_ADDRESS_2);
- dma_buffer->data.addr3 = (ONENAND_WRITE_PROT_STATUS << 16) |
- (ONENAND_COMMAND);
- dma_buffer->data.addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
- (ONENAND_INTERRUPT_STATUS);
- dma_buffer->data.addr5 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr6 = (ONENAND_START_ADDRESS_3 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.data0 = (ONENAND_CLRINTR << 16) |
- (ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode));
- dma_buffer->data.data1 = (onenand_startaddr8 << 16) |
- (onenand_startaddr1);
- dma_buffer->data.data2 = (onenand_startblock << 16) |
- (onenand_startaddr2);
- dma_buffer->data.data3 = (CLEAN_DATA_16 << 16) |
- (ONENAND_CMD_UNLOCK);
- dma_buffer->data.data4 = (CLEAN_DATA_16 << 16) |
- (CLEAN_DATA_16);
- dma_buffer->data.data5 = (ONENAND_CLRINTR << 16) |
- (ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode));
- dma_buffer->data.data6 = (ONENAND_STARTADDR3_RES << 16) |
- (ONENAND_STARTADDR1_RES);
- /*************************************************************/
- /* Write the necessary address reg in the onenand device */
- /*************************************************************/
- /* Enable and configure the SFlash controller */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfbcfg);
- cmd->dst = MSM_NAND_SFLASHC_BURST_CFG;
- cmd->len = 4;
- cmd++;
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[0]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Write the ADDR0 and ADDR1 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr0);
- cmd->dst = MSM_NAND_ADDR0;
- cmd->len = 8;
- cmd++;
- /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr2);
- cmd->dst = MSM_NAND_ADDR2;
- cmd->len = 16;
- cmd++;
- /* Write the ADDR6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr6);
- cmd->dst = MSM_NAND_ADDR6;
- cmd->len = 4;
- cmd++;
- /* Write the GENP0, GENP1, GENP2, GENP3, GENP4 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data0);
- cmd->dst = MSM_NAND_GENP_REG0;
- cmd->len = 16;
- cmd++;
- /* Write the FLASH_DEV_CMD4,5,6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->dst = MSM_NAND_DEV_CMD4;
- cmd->len = 12;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[0]);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Wait for the interrupt from the Onenand device controller */
- /*************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[1]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[1]);
- cmd->len = 4;
- cmd++;
- /*********************************************************/
- /* Read the necessary status reg from the onenand device */
- /*********************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[2]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[2]);
- cmd->len = 4;
- cmd++;
- /* Read the GENP3 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_GENP_REG3;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data3);
- cmd->len = 4;
- cmd++;
- /* Read the DEVCMD4 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_DEV_CMD4;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->len = 4;
- cmd++;
- /************************************************************/
- /* Restore the necessary registers to proper values */
- /************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[3]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[3]);
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(20 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd)
- >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- write_prot_status = (dma_buffer->data.data3 >> 16) & 0x0000FFFF;
- interrupt_status = (dma_buffer->data.data4 >> 0) & 0x0000FFFF;
- controller_status = (dma_buffer->data.data4 >> 16) & 0x0000FFFF;
- #if VERBOSE
- pr_info("\n%s: sflash status %x %x %x %x\n", __func__,
- dma_buffer->data.sfstat[0],
- dma_buffer->data.sfstat[1],
- dma_buffer->data.sfstat[2],
- dma_buffer->data.sfstat[3]);
- pr_info("%s: controller_status = %x\n", __func__,
- controller_status);
- pr_info("%s: interrupt_status = %x\n", __func__,
- interrupt_status);
- pr_info("%s: write_prot_status = %x\n", __func__,
- write_prot_status);
- #endif
- /* Check for errors, protection violations etc */
- if ((controller_status != 0)
- || (dma_buffer->data.sfstat[0] & 0x110)
- || (dma_buffer->data.sfstat[1] & 0x110)
- || (dma_buffer->data.sfstat[2] & 0x110)
- || (dma_buffer->data.sfstat[3] & 0x110)) {
- pr_err("%s: ECC/MPU/OP error\n", __func__);
- err = -EIO;
- }
- if (!(write_prot_status & ONENAND_WP_US)) {
- pr_err("%s: Unexpected status ofs = 0x%llx,"
- "wp_status = %x\n",
- __func__, ofs, write_prot_status);
- err = -EIO;
- }
- if (err)
- break;
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- #if VERBOSE
- pr_info("\n%s: ret %d\n", __func__, err);
- pr_info("===================================================="
- "=============\n");
- #endif
- return err;
- }
- static int msm_onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[20];
- unsigned cmdptr;
- struct {
- uint32_t sfbcfg;
- uint32_t sfcmd[4];
- uint32_t sfexec;
- uint32_t sfstat[4];
- uint32_t addr0;
- uint32_t addr1;
- uint32_t addr2;
- uint32_t addr3;
- uint32_t addr4;
- uint32_t addr5;
- uint32_t addr6;
- uint32_t data0;
- uint32_t data1;
- uint32_t data2;
- uint32_t data3;
- uint32_t data4;
- uint32_t data5;
- uint32_t data6;
- } data;
- } *dma_buffer;
- dmov_s *cmd;
- int err = 0;
- uint16_t onenand_startaddr1;
- uint16_t onenand_startaddr8;
- uint16_t onenand_startaddr2;
- uint16_t onenand_startblock;
- uint16_t controller_status;
- uint16_t interrupt_status;
- uint16_t write_prot_status;
- uint64_t start_ofs;
- #if VERBOSE
- pr_info("===================================================="
- "=============\n");
- pr_info("%s: ofs 0x%llx len %lld\n", __func__, ofs, len);
- #endif
- /* 'ofs' & 'len' should align to block size */
- if (ofs&(mtd->erasesize - 1)) {
- pr_err("%s: Unsupported ofs address, 0x%llx\n",
- __func__, ofs);
- return -EINVAL;
- }
- if (len&(mtd->erasesize - 1)) {
- pr_err("%s: Unsupported len, %lld\n",
- __func__, len);
- return -EINVAL;
- }
- if (ofs+len > mtd->size) {
- pr_err("%s: Maximum chip size exceeded\n", __func__);
- return -EINVAL;
- }
- wait_event(chip->wait_queue, (dma_buffer = msm_nand_get_dma_buffer
- (chip, sizeof(*dma_buffer))));
- for (start_ofs = ofs; ofs < start_ofs+len; ofs = ofs+mtd->erasesize) {
- #if VERBOSE
- pr_info("%s: ofs 0x%llx len %lld\n", __func__, ofs, len);
- #endif
- cmd = dma_buffer->cmd;
- if ((onenand_info.device_id & ONENAND_DEVICE_IS_DDP)
- && (ofs >= (mtd->size>>1))) { /* DDP Device */
- onenand_startaddr1 = DEVICE_FLASHCORE_1 |
- (((uint32_t)(ofs - (mtd->size>>1))
- / mtd->erasesize));
- onenand_startaddr2 = DEVICE_BUFFERRAM_1;
- onenand_startblock = ((uint32_t)(ofs - (mtd->size>>1))
- / mtd->erasesize);
- } else {
- onenand_startaddr1 = DEVICE_FLASHCORE_0 |
- ((uint32_t)ofs / mtd->erasesize) ;
- onenand_startaddr2 = DEVICE_BUFFERRAM_0;
- onenand_startblock = ((uint32_t)ofs
- / mtd->erasesize);
- }
- onenand_startaddr8 = 0x0000;
- dma_buffer->data.sfbcfg = SFLASH_BCFG |
- (nand_sfcmd_mode ? 0 : (1 << 24));
- dma_buffer->data.sfcmd[0] = SFLASH_PREPCMD(7, 0, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfcmd[1] = SFLASH_PREPCMD(0, 0, 32,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_INTHI);
- dma_buffer->data.sfcmd[2] = SFLASH_PREPCMD(3, 7, 0,
- MSM_NAND_SFCMD_DATXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGRD);
- dma_buffer->data.sfcmd[3] = SFLASH_PREPCMD(4, 10, 0,
- MSM_NAND_SFCMD_CMDXS,
- nand_sfcmd_mode,
- MSM_NAND_SFCMD_REGWR);
- dma_buffer->data.sfexec = 1;
- dma_buffer->data.sfstat[0] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[1] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[2] = CLEAN_DATA_32;
- dma_buffer->data.sfstat[3] = CLEAN_DATA_32;
- dma_buffer->data.addr0 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr1 = (ONENAND_START_ADDRESS_8 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.addr2 = (ONENAND_START_BLOCK_ADDRESS << 16) |
- (ONENAND_START_ADDRESS_2);
- dma_buffer->data.addr3 = (ONENAND_WRITE_PROT_STATUS << 16) |
- (ONENAND_COMMAND);
- dma_buffer->data.addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
- (ONENAND_INTERRUPT_STATUS);
- dma_buffer->data.addr5 = (ONENAND_INTERRUPT_STATUS << 16) |
- (ONENAND_SYSTEM_CONFIG_1);
- dma_buffer->data.addr6 = (ONENAND_START_ADDRESS_3 << 16) |
- (ONENAND_START_ADDRESS_1);
- dma_buffer->data.data0 = (ONENAND_CLRINTR << 16) |
- (ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode));
- dma_buffer->data.data1 = (onenand_startaddr8 << 16) |
- (onenand_startaddr1);
- dma_buffer->data.data2 = (onenand_startblock << 16) |
- (onenand_startaddr2);
- dma_buffer->data.data3 = (CLEAN_DATA_16 << 16) |
- (ONENAND_CMD_LOCK);
- dma_buffer->data.data4 = (CLEAN_DATA_16 << 16) |
- (CLEAN_DATA_16);
- dma_buffer->data.data5 = (ONENAND_CLRINTR << 16) |
- (ONENAND_SYSCFG1_ECCENA(nand_sfcmd_mode));
- dma_buffer->data.data6 = (ONENAND_STARTADDR3_RES << 16) |
- (ONENAND_STARTADDR1_RES);
- /*************************************************************/
- /* Write the necessary address reg in the onenand device */
- /*************************************************************/
- /* Enable and configure the SFlash controller */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfbcfg);
- cmd->dst = MSM_NAND_SFLASHC_BURST_CFG;
- cmd->len = 4;
- cmd++;
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[0]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Write the ADDR0 and ADDR1 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr0);
- cmd->dst = MSM_NAND_ADDR0;
- cmd->len = 8;
- cmd++;
- /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr2);
- cmd->dst = MSM_NAND_ADDR2;
- cmd->len = 16;
- cmd++;
- /* Write the ADDR6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.addr6);
- cmd->dst = MSM_NAND_ADDR6;
- cmd->len = 4;
- cmd++;
- /* Write the GENP0, GENP1, GENP2, GENP3, GENP4 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data0);
- cmd->dst = MSM_NAND_GENP_REG0;
- cmd->len = 16;
- cmd++;
- /* Write the FLASH_DEV_CMD4,5,6 registers */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->dst = MSM_NAND_DEV_CMD4;
- cmd->len = 12;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[0]);
- cmd->len = 4;
- cmd++;
- /*************************************************************/
- /* Wait for the interrupt from the Onenand device controller */
- /*************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[1]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[1]);
- cmd->len = 4;
- cmd++;
- /*********************************************************/
- /* Read the necessary status reg from the onenand device */
- /*********************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[2]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[2]);
- cmd->len = 4;
- cmd++;
- /* Read the GENP3 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_GENP_REG3;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data3);
- cmd->len = 4;
- cmd++;
- /* Read the DEVCMD4 register */
- cmd->cmd = 0;
- cmd->src = MSM_NAND_DEV_CMD4;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.data4);
- cmd->len = 4;
- cmd++;
- /************************************************************/
- /* Restore the necessary registers to proper values */
- /************************************************************/
- /* Block on cmd ready and write CMD register */
- cmd->cmd = DST_CRCI_NAND_CMD;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfcmd[3]);
- cmd->dst = MSM_NAND_SFLASHC_CMD;
- cmd->len = 4;
- cmd++;
- /* Kick the execute command */
- cmd->cmd = 0;
- cmd->src = msm_virt_to_dma(chip, &dma_buffer->data.sfexec);
- cmd->dst = MSM_NAND_SFLASHC_EXEC_CMD;
- cmd->len = 4;
- cmd++;
- /* Block on data ready, and read the status register */
- cmd->cmd = SRC_CRCI_NAND_DATA;
- cmd->src = MSM_NAND_SFLASHC_STATUS;
- cmd->dst = msm_virt_to_dma(chip, &dma_buffer->data.sfstat[3]);
- cmd->len = 4;
- cmd++;
- BUILD_BUG_ON(20 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd)
- >> 3) | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel,
- DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- write_prot_status = (dma_buffer->data.data3 >> 16) & 0x0000FFFF;
- interrupt_status = (dma_buffer->data.data4 >> 0) & 0x0000FFFF;
- controller_status = (dma_buffer->data.data4 >> 16) & 0x0000FFFF;
- #if VERBOSE
- pr_info("\n%s: sflash status %x %x %x %x\n", __func__,
- dma_buffer->data.sfstat[0],
- dma_buffer->data.sfstat[1],
- dma_buffer->data.sfstat[2],
- dma_buffer->data.sfstat[3]);
- pr_info("%s: controller_status = %x\n", __func__,
- controller_status);
- pr_info("%s: interrupt_status = %x\n", __func__,
- interrupt_status);
- pr_info("%s: write_prot_status = %x\n", __func__,
- write_prot_status);
- #endif
- /* Check for errors, protection violations etc */
- if ((controller_status != 0)
- || (dma_buffer->data.sfstat[0] & 0x110)
- || (dma_buffer->data.sfstat[1] & 0x110)
- || (dma_buffer->data.sfstat[2] & 0x110)
- || (dma_buffer->data.sfstat[3] & 0x110)) {
- pr_err("%s: ECC/MPU/OP error\n", __func__);
- err = -EIO;
- }
- if (!(write_prot_status & ONENAND_WP_LS)) {
- pr_err("%s: Unexpected status ofs = 0x%llx,"
- "wp_status = %x\n",
- __func__, ofs, write_prot_status);
- err = -EIO;
- }
- if (err)
- break;
- }
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- #if VERBOSE
- pr_info("\n%s: ret %d\n", __func__, err);
- pr_info("===================================================="
- "=============\n");
- #endif
- return err;
- }
- static int msm_onenand_suspend(struct mtd_info *mtd)
- {
- return 0;
- }
- static void msm_onenand_resume(struct mtd_info *mtd)
- {
- }
- int msm_onenand_scan(struct mtd_info *mtd, int maxchips)
- {
- struct msm_nand_chip *chip = mtd->priv;
- /* Probe and check whether onenand device is present */
- if (flash_onenand_probe(chip))
- return -ENODEV;
- mtd->size = 0x1000000 << ((onenand_info.device_id & 0xF0) >> 4);
- mtd->writesize = onenand_info.data_buf_size;
- mtd->oobsize = mtd->writesize >> 5;
- mtd->erasesize = mtd->writesize << 6;
- mtd->oobavail = msm_onenand_oob_64.oobavail;
- mtd->ecclayout = &msm_onenand_oob_64;
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH;
- mtd->_erase = msm_onenand_erase;
- mtd->_point = NULL;
- mtd->_unpoint = NULL;
- mtd->_read = msm_onenand_read;
- mtd->_write = msm_onenand_write;
- mtd->_read_oob = msm_onenand_read_oob;
- mtd->_write_oob = msm_onenand_write_oob;
- mtd->_lock = msm_onenand_lock;
- mtd->_unlock = msm_onenand_unlock;
- mtd->_suspend = msm_onenand_suspend;
- mtd->_resume = msm_onenand_resume;
- mtd->_block_isbad = msm_onenand_block_isbad;
- mtd->_block_markbad = msm_onenand_block_markbad;
- mtd->owner = THIS_MODULE;
- pr_info("Found a supported onenand device\n");
- return 0;
- }
- static const unsigned int bch_sup_cntrl[] = {
- 0x307, /* MSM7x2xA */
- 0x4030, /* MDM 9x15 */
- };
- static inline bool msm_nand_has_bch_ecc_engine(unsigned int hw_id)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(bch_sup_cntrl); i++) {
- if (hw_id == bch_sup_cntrl[i])
- return true;
- }
- return false;
- }
- /**
- * msm_nand_scan - [msm_nand Interface] Scan for the msm_nand device
- * @param mtd MTD device structure
- * @param maxchips Number of chips to scan for
- *
- * This fills out all the not initialized function pointers
- * with the defaults.
- * The flash ID is read and the mtd/chip structures are
- * filled with the appropriate values.
- */
- int msm_nand_scan(struct mtd_info *mtd, int maxchips)
- {
- struct msm_nand_chip *chip = mtd->priv;
- uint32_t flash_id = 0, i, mtd_writesize;
- uint8_t dev_found = 0;
- uint8_t wide_bus;
- uint32_t manid;
- uint32_t devid;
- uint32_t devcfg;
- struct nand_flash_dev *flashdev = NULL;
- struct nand_manufacturers *flashman = NULL;
- unsigned int hw_id;
- /* Probe the Flash device for ONFI compliance */
- if (!flash_onfi_probe(chip)) {
- dev_found = 1;
- } else {
- /* Read the Flash ID from the Nand Flash Device */
- flash_id = flash_read_id(chip);
- manid = flash_id & 0xFF;
- devid = (flash_id >> 8) & 0xFF;
- devcfg = (flash_id >> 24) & 0xFF;
- for (i = 0; !flashman && nand_manuf_ids[i].id; ++i)
- if (nand_manuf_ids[i].id == manid)
- flashman = &nand_manuf_ids[i];
- for (i = 0; !flashdev && nand_flash_ids[i].id; ++i)
- if (nand_flash_ids[i].id == devid)
- flashdev = &nand_flash_ids[i];
- if (!flashdev || !flashman) {
- pr_err("ERROR: unknown nand device manuf=%x devid=%x\n",
- manid, devid);
- return -ENOENT;
- } else
- dev_found = 1;
- if (!flashdev->pagesize) {
- supported_flash.flash_id = flash_id;
- supported_flash.density = flashdev->chipsize << 20;
- supported_flash.widebus = devcfg & (1 << 6) ? 1 : 0;
- supported_flash.pagesize = 1024 << (devcfg & 0x3);
- supported_flash.blksize = (64 * 1024) <<
- ((devcfg >> 4) & 0x3);
- supported_flash.oobsize = (8 << ((devcfg >> 2) & 0x3)) *
- (supported_flash.pagesize >> 9);
- if ((supported_flash.oobsize > 64) &&
- (supported_flash.pagesize == 2048)) {
- pr_info("msm_nand: Found a 2K page device with"
- " %d oobsize - changing oobsize to 64 "
- "bytes.\n", supported_flash.oobsize);
- supported_flash.oobsize = 64;
- }
- } else {
- supported_flash.flash_id = flash_id;
- supported_flash.density = flashdev->chipsize << 20;
- supported_flash.widebus = flashdev->options &
- NAND_BUSWIDTH_16 ? 1 : 0;
- supported_flash.pagesize = flashdev->pagesize;
- supported_flash.blksize = flashdev->erasesize;
- supported_flash.oobsize = flashdev->pagesize >> 5;
- }
- }
- if (dev_found) {
- (!interleave_enable) ? (i = 1) : (i = 2);
- wide_bus = supported_flash.widebus;
- mtd->size = supported_flash.density * i;
- mtd->writesize = supported_flash.pagesize * i;
- mtd->oobsize = supported_flash.oobsize * i;
- mtd->erasesize = supported_flash.blksize * i;
- mtd->writebufsize = mtd->writesize;
- if (!interleave_enable)
- mtd_writesize = mtd->writesize;
- else
- mtd_writesize = mtd->writesize >> 1;
- /* Check whether controller and NAND device support 8bit ECC*/
- hw_id = flash_rd_reg(chip, MSM_NAND_HW_INFO);
- if (msm_nand_has_bch_ecc_engine(hw_id)
- && (supported_flash.ecc_correctability >= 8)) {
- pr_info("Found supported NAND device for %dbit ECC\n",
- supported_flash.ecc_correctability);
- enable_bch_ecc = 1;
- } else {
- pr_info("Found a supported NAND device\n");
- }
- pr_info("NAND Controller ID : 0x%x\n", hw_id);
- pr_info("NAND Device ID : 0x%x\n", supported_flash.flash_id);
- pr_info("Buswidth : %d Bits\n", (wide_bus) ? 16 : 8);
- pr_info("Density : %lld MByte\n", (mtd->size>>20));
- pr_info("Pagesize : %d Bytes\n", mtd->writesize);
- pr_info("Erasesize: %d Bytes\n", mtd->erasesize);
- pr_info("Oobsize : %d Bytes\n", mtd->oobsize);
- } else {
- pr_err("Unsupported Nand,Id: 0x%x \n", flash_id);
- return -ENODEV;
- }
- /* Size of each codeword is 532Bytes incase of 8bit BCH ECC*/
- chip->cw_size = enable_bch_ecc ? 532 : 528;
- chip->CFG0 = (((mtd_writesize >> 9)-1) << 6) /* 4/8 cw/pg for 2/4k */
- | (516 << 9) /* 516 user data bytes */
- | (10 << 19) /* 10 parity bytes */
- | (5 << 27) /* 5 address cycles */
- | (0 << 30) /* Do not read status before data */
- | (1 << 31) /* Send read cmd */
- /* 0 spare bytes for 16 bit nand or 1/2 spare bytes for 8 bit */
- | (wide_bus ? 0 << 23 : (enable_bch_ecc ? 2 << 23 : 1 << 23));
- chip->CFG1 = (0 << 0) /* Enable ecc */
- | (7 << 2) /* 8 recovery cycles */
- | (0 << 5) /* Allow CS deassertion */
- /* Bad block marker location */
- | ((mtd_writesize - (chip->cw_size * (
- (mtd_writesize >> 9) - 1)) + 1) << 6)
- | (0 << 16) /* Bad block in user data area */
- | (2 << 17) /* 6 cycle tWB/tRB */
- | ((wide_bus) ? CFG1_WIDE_FLASH : 0); /* Wide flash bit */
- chip->ecc_buf_cfg = 0x203;
- chip->CFG0_RAW = 0xA80420C0;
- chip->CFG1_RAW = 0x5045D;
- if (enable_bch_ecc) {
- chip->CFG1 |= (1 << 27); /* Enable BCH engine */
- chip->ecc_bch_cfg = (0 << 0) /* Enable ECC*/
- | (0 << 1) /* Enable/Disable SW reset of ECC engine */
- | (1 << 4) /* 8bit ecc*/
- | ((wide_bus) ? (14 << 8) : (13 << 8))/*parity bytes*/
- | (516 << 16) /* 516 user data bytes */
- | (1 << 30); /* Turn on ECC engine clocks always */
- chip->CFG0_RAW = 0xA80428C0; /* CW size is increased to 532B */
- }
- /*
- * For 4bit RS ECC (default ECC), parity bytes = 10 (for x8 and x16 I/O)
- * For 8bit BCH ECC, parity bytes = 13 (x8) or 14 (x16 I/O).
- */
- chip->ecc_parity_bytes = enable_bch_ecc ? (wide_bus ? 14 : 13) : 10;
- pr_info("CFG0 Init : 0x%08x\n", chip->CFG0);
- pr_info("CFG1 Init : 0x%08x\n", chip->CFG1);
- pr_info("ECCBUFCFG : 0x%08x\n", chip->ecc_buf_cfg);
- if (mtd->oobsize == 64) {
- mtd->oobavail = msm_nand_oob_64.oobavail;
- mtd->ecclayout = &msm_nand_oob_64;
- } else if (mtd->oobsize == 128) {
- mtd->oobavail = msm_nand_oob_128.oobavail;
- mtd->ecclayout = &msm_nand_oob_128;
- } else if (mtd->oobsize == 224) {
- mtd->oobavail = wide_bus ? msm_nand_oob_224_x16.oobavail :
- msm_nand_oob_224_x8.oobavail;
- mtd->ecclayout = wide_bus ? &msm_nand_oob_224_x16 :
- &msm_nand_oob_224_x8;
- } else if (mtd->oobsize == 256) {
- mtd->oobavail = msm_nand_oob_256.oobavail;
- mtd->ecclayout = &msm_nand_oob_256;
- } else {
- pr_err("Unsupported Nand, oobsize: 0x%x \n",
- mtd->oobsize);
- return -ENODEV;
- }
- /* Fill in remaining MTD driver data */
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH;
- /* mtd->ecctype = MTD_ECC_SW; */
- mtd->_erase = msm_nand_erase;
- mtd->_block_isbad = msm_nand_block_isbad;
- mtd->_block_markbad = msm_nand_block_markbad;
- mtd->_point = NULL;
- mtd->_unpoint = NULL;
- mtd->_read = msm_nand_read;
- mtd->_write = msm_nand_write;
- mtd->_read_oob = msm_nand_read_oob;
- mtd->_write_oob = msm_nand_write_oob;
- if (dual_nand_ctlr_present) {
- mtd->_read_oob = msm_nand_read_oob_dualnandc;
- mtd->_write_oob = msm_nand_write_oob_dualnandc;
- if (interleave_enable) {
- mtd->_erase = msm_nand_erase_dualnandc;
- mtd->_block_isbad = msm_nand_block_isbad_dualnandc;
- }
- }
- /* mtd->sync = msm_nand_sync; */
- mtd->_lock = NULL;
- /* mtd->_unlock = msm_nand_unlock; */
- mtd->_suspend = msm_nand_suspend;
- mtd->_resume = msm_nand_resume;
- mtd->owner = THIS_MODULE;
- /* Unlock whole block */
- /* msm_nand_unlock_all(mtd); */
- /* return this->scan_bbt(mtd); */
- return 0;
- }
- EXPORT_SYMBOL_GPL(msm_nand_scan);
- /**
- * msm_nand_release - [msm_nand Interface] Free resources held by the msm_nand device
- * @param mtd MTD device structure
- */
- void msm_nand_release(struct mtd_info *mtd)
- {
- /* struct msm_nand_chip *this = mtd->priv; */
- /* Deregister the device */
- mtd_device_unregister(mtd);
- }
- EXPORT_SYMBOL_GPL(msm_nand_release);
- struct msm_nand_info {
- struct mtd_info mtd;
- struct mtd_partition *parts;
- struct msm_nand_chip msm_nand;
- };
- /* duplicating the NC01 XFR contents to NC10 */
- static int msm_nand_nc10_xfr_settings(struct mtd_info *mtd)
- {
- struct msm_nand_chip *chip = mtd->priv;
- struct {
- dmov_s cmd[2];
- unsigned cmdptr;
- } *dma_buffer;
- dmov_s *cmd;
- wait_event(chip->wait_queue,
- (dma_buffer = msm_nand_get_dma_buffer(
- chip, sizeof(*dma_buffer))));
- cmd = dma_buffer->cmd;
- /* Copying XFR register contents from NC01 --> NC10 */
- cmd->cmd = 0;
- cmd->src = NC01(MSM_NAND_XFR_STEP1);
- cmd->dst = NC10(MSM_NAND_XFR_STEP1);
- cmd->len = 28;
- cmd++;
- BUILD_BUG_ON(2 != ARRAY_SIZE(dma_buffer->cmd));
- BUG_ON(cmd - dma_buffer->cmd > ARRAY_SIZE(dma_buffer->cmd));
- dma_buffer->cmd[0].cmd |= CMD_OCB;
- cmd[-1].cmd |= CMD_OCU | CMD_LC;
- dma_buffer->cmdptr = (msm_virt_to_dma(chip, dma_buffer->cmd) >> 3)
- | CMD_PTR_LP;
- mb();
- msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST
- | DMOV_CMD_ADDR(msm_virt_to_dma(chip,
- &dma_buffer->cmdptr)));
- mb();
- msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
- return 0;
- }
- static int setup_mtd_device(struct platform_device *pdev,
- struct msm_nand_info *info)
- {
- int i, err;
- struct flash_platform_data *pdata = pdev->dev.platform_data;
- if (pdata) {
- for (i = 0; i < pdata->nr_parts; i++) {
- pdata->parts[i].offset = pdata->parts[i].offset
- * info->mtd.erasesize;
- pdata->parts[i].size = pdata->parts[i].size
- * info->mtd.erasesize;
- }
- err = mtd_device_register(&info->mtd, pdata->parts,
- pdata->nr_parts);
- } else {
- err = mtd_device_register(&info->mtd, NULL, 0);
- }
- return err;
- }
- static int __devinit msm_nand_probe(struct platform_device *pdev)
- {
- struct msm_nand_info *info;
- struct resource *res;
- int err;
- struct flash_platform_data *plat_data;
- plat_data = pdev->dev.platform_data;
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "msm_nand_phys");
- if (!res || !res->start) {
- pr_err("%s: msm_nand_phys resource invalid/absent\n",
- __func__);
- return -ENODEV;
- }
- msm_nand_phys = res->start;
- pr_info("%s: phys addr 0x%lx \n", __func__, msm_nand_phys);
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "msm_nandc01_phys");
- if (!res || !res->start)
- goto no_dual_nand_ctlr_support;
- msm_nandc01_phys = res->start;
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "msm_nandc10_phys");
- if (!res || !res->start)
- goto no_dual_nand_ctlr_support;
- msm_nandc10_phys = res->start;
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "msm_nandc11_phys");
- if (!res || !res->start)
- goto no_dual_nand_ctlr_support;
- msm_nandc11_phys = res->start;
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "ebi2_reg_base");
- if (!res || !res->start)
- goto no_dual_nand_ctlr_support;
- ebi2_register_base = res->start;
- dual_nand_ctlr_present = 1;
- if (plat_data != NULL)
- interleave_enable = plat_data->interleave;
- else
- interleave_enable = 0;
- if (!interleave_enable)
- pr_info("%s: Dual Nand Ctrl in ping-pong mode\n", __func__);
- else
- pr_info("%s: Dual Nand Ctrl in interleave mode\n", __func__);
- no_dual_nand_ctlr_support:
- res = platform_get_resource_byname(pdev,
- IORESOURCE_DMA, "msm_nand_dmac");
- if (!res || !res->start) {
- pr_err("%s: invalid msm_nand_dmac resource\n", __func__);
- return -ENODEV;
- }
- info = kzalloc(sizeof(struct msm_nand_info), GFP_KERNEL);
- if (!info) {
- pr_err("%s: No memory for msm_nand_info\n", __func__);
- return -ENOMEM;
- }
- info->msm_nand.dev = &pdev->dev;
- init_waitqueue_head(&info->msm_nand.wait_queue);
- info->msm_nand.dma_channel = res->start;
- pr_info("%s: dmac 0x%x\n", __func__, info->msm_nand.dma_channel);
- /* this currently fails if dev is passed in */
- info->msm_nand.dma_buffer =
- dma_alloc_coherent(/*dev*/ NULL, MSM_NAND_DMA_BUFFER_SIZE,
- &info->msm_nand.dma_addr, GFP_KERNEL);
- if (info->msm_nand.dma_buffer == NULL) {
- pr_err("%s: No memory for msm_nand.dma_buffer\n", __func__);
- err = -ENOMEM;
- goto out_free_info;
- }
- pr_info("%s: allocated dma buffer at %p, dma_addr %x\n",
- __func__, info->msm_nand.dma_buffer, info->msm_nand.dma_addr);
- /* Let default be VERSION_1 for backward compatibility */
- info->msm_nand.uncorrectable_bit_mask = BIT(3);
- info->msm_nand.num_err_mask = 0x7;
- if (plat_data && (plat_data->version == VERSION_2)) {
- info->msm_nand.uncorrectable_bit_mask = BIT(8);
- info->msm_nand.num_err_mask = 0x1F;
- }
- info->mtd.name = dev_name(&pdev->dev);
- info->mtd.priv = &info->msm_nand;
- info->mtd.owner = THIS_MODULE;
- /* config ebi2_cfg register only for ping pong mode!!! */
- if (!interleave_enable && dual_nand_ctlr_present)
- flash_wr_reg(&info->msm_nand, EBI2_CFG_REG, 0x4010080);
- if (dual_nand_ctlr_present)
- msm_nand_nc10_xfr_settings(&info->mtd);
- if (msm_nand_scan(&info->mtd, 1))
- if (msm_onenand_scan(&info->mtd, 1)) {
- pr_err("%s: No nand device found\n", __func__);
- err = -ENXIO;
- goto out_free_dma_buffer;
- }
- err = setup_mtd_device(pdev, info);
- if (err < 0) {
- pr_err("%s: setup_mtd_device failed with err=%d\n",
- __func__, err);
- goto out_free_dma_buffer;
- }
- dev_set_drvdata(&pdev->dev, info);
- return 0;
- out_free_dma_buffer:
- dma_free_coherent(NULL, MSM_NAND_DMA_BUFFER_SIZE,
- info->msm_nand.dma_buffer,
- info->msm_nand.dma_addr);
- out_free_info:
- kfree(info);
- return err;
- }
- static int __devexit msm_nand_remove(struct platform_device *pdev)
- {
- struct msm_nand_info *info = dev_get_drvdata(&pdev->dev);
- dev_set_drvdata(&pdev->dev, NULL);
- if (info) {
- msm_nand_release(&info->mtd);
- dma_free_coherent(NULL, MSM_NAND_DMA_BUFFER_SIZE,
- info->msm_nand.dma_buffer,
- info->msm_nand.dma_addr);
- kfree(info);
- }
- return 0;
- }
- #define DRIVER_NAME "msm_nand"
- static struct platform_driver msm_nand_driver = {
- .probe = msm_nand_probe,
- .remove = __devexit_p(msm_nand_remove),
- .driver = {
- .name = DRIVER_NAME,
- }
- };
- MODULE_ALIAS(DRIVER_NAME);
- static int __init msm_nand_init(void)
- {
- return platform_driver_register(&msm_nand_driver);
- }
- static void __exit msm_nand_exit(void)
- {
- platform_driver_unregister(&msm_nand_driver);
- }
- module_init(msm_nand_init);
- module_exit(msm_nand_exit);
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("msm_nand flash driver code");
|