| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601 |
- diff -Nur linux-3.16.6.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts linux-3.16.6/arch/arm/boot/dts/imx6dl-hummingboard.dts
- --- linux-3.16.6.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/arch/arm/boot/dts/imx6dl-hummingboard.dts 2014-10-23 12:37:45.114220003 -0500
- @@ -56,15 +56,32 @@
- };
- };
-
- + sound-sgtl5000 {
- + audio-codec = <&sgtl5000>;
- + audio-routing =
- + "MIC_IN", "Mic Jack",
- + "Mic Jack", "Mic Bias",
- + "Headphone Jack", "HP_OUT";
- + compatible = "fsl,imx-audio-sgtl5000";
- + model = "On-board Codec";
- + mux-ext-port = <5>;
- + mux-int-port = <1>;
- + ssi-controller = <&ssi1>;
- + };
- +
- sound-spdif {
- compatible = "fsl,imx-audio-spdif";
- - model = "imx-spdif";
- + model = "On-board SPDIF";
- /* IMX6 doesn't implement this yet */
- spdif-controller = <&spdif>;
- spdif-out;
- };
- };
-
- +&audmux {
- + status = "okay";
- +};
- +
- &can1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_hummingboard_flexcan1>;
- @@ -81,16 +98,24 @@
- &i2c1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_hummingboard_i2c1>;
- -
- - /*
- - * Not fitted on Carrier-1 board... yet
- status = "okay";
-
- + /* Pro model */
- rtc: pcf8523@68 {
- compatible = "nxp,pcf8523";
- reg = <0x68>;
- };
- - */
- +
- + /* Pro model */
- + sgtl5000: sgtl5000@0a {
- + clocks = <&clks 201>;
- + compatible = "fsl,sgtl5000";
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_hummingboard_sgtl5000>;
- + reg = <0x0a>;
- + VDDA-supply = <®_3p3v>;
- + VDDIO-supply = <®_3p3v>;
- + };
- };
-
- &i2c2 {
- @@ -135,6 +160,16 @@
- >;
- };
-
- + pinctrl_hummingboard_sgtl5000: hummingboard-sgtl5000 {
- + fsl,pins = <
- + MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 /*brk*/
- + MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 /*ok*/
- + MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 /*brk*/
- + MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 /*ok*/
- + MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0
- + >;
- + };
- +
- pinctrl_hummingboard_spdif: hummingboard-spdif {
- fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
- };
- @@ -180,12 +215,19 @@
- status = "okay";
- };
-
- +&ssi1 {
- + fsl,mode = "i2s-slave";
- + status = "okay";
- +};
- +
- &usbh1 {
- + disable-over-current;
- vbus-supply = <®_usbh1_vbus>;
- status = "okay";
- };
-
- &usbotg {
- + disable-over-current;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_hummingboard_usbotg_id>;
- vbus-supply = <®_usbotg_vbus>;
- diff -Nur linux-3.16.6.orig/arch/arm/boot/dts/imx6q-cubox-i.dts linux-3.16.6/arch/arm/boot/dts/imx6q-cubox-i.dts
- --- linux-3.16.6.orig/arch/arm/boot/dts/imx6q-cubox-i.dts 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/arch/arm/boot/dts/imx6q-cubox-i.dts 2014-10-23 12:26:42.106220014 -0500
- @@ -13,4 +13,8 @@
-
- &sata {
- status = "okay";
- + fsl,transmit-level-mV = <1104>;
- + fsl,transmit-boost-mdB = <0>;
- + fsl,transmit-atten-16ths = <9>;
- + fsl,no-spread-spectrum;
- };
- diff -Nur linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi linux-3.16.6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
- --- linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2014-10-23 12:34:41.266219992 -0500
- @@ -61,7 +61,7 @@
-
- sound-spdif {
- compatible = "fsl,imx-audio-spdif";
- - model = "imx-spdif";
- + model = "Integrated SPDIF";
- /* IMX6 doesn't implement this yet */
- spdif-controller = <&spdif>;
- spdif-out;
- @@ -130,16 +130,23 @@
- fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
- };
-
- + pinctrl_cubox_i_usbh1: cubox-i-usbh1 {
- + fsl,pins = <MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0>;
- + };
- +
- pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus {
- fsl,pins = <MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x4001b0b0>;
- };
-
- - pinctrl_cubox_i_usbotg_id: cubox-i-usbotg-id {
- + pinctrl_cubox_i_usbotg: cubox-i-usbotg {
- /*
- - * The Cubox-i pulls this low, but as it's pointless
- + * The Cubox-i pulls ID low, but as it's pointless
- * leaving it as a pull-up, even if it is just 10uA.
- */
- - fsl,pins = <MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059>;
- + fsl,pins = <
- + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059
- + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0
- + >;
- };
-
- pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus {
- @@ -163,6 +170,28 @@
- MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059
- >;
- };
- +
- + pinctrl_cubox_i_usdhc2_100mhz: cubox-i-usdhc2-100mhz {
- + fsl,pins = <
- + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9
- + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9
- + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9
- + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9
- + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9
- + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9
- + >;
- + };
- +
- + pinctrl_cubox_i_usdhc2_200mhz: cubox-i-usdhc2-200mhz {
- + fsl,pins = <
- + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9
- + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9
- + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9
- + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9
- + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9
- + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9
- + >;
- + };
- };
- };
-
- @@ -173,20 +202,24 @@
- };
-
- &usbh1 {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_usbh1>;
- vbus-supply = <®_usbh1_vbus>;
- status = "okay";
- };
-
- &usbotg {
- pinctrl-names = "default";
- - pinctrl-0 = <&pinctrl_cubox_i_usbotg_id>;
- + pinctrl-0 = <&pinctrl_cubox_i_usbotg>;
- vbus-supply = <®_usbotg_vbus>;
- status = "okay";
- };
-
- &usdhc2 {
- - pinctrl-names = "default";
- + pinctrl-names = "default", "state_100mhz", "state_200mhz";
- pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
- + pinctrl-1 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_100mhz>;
- + pinctrl-2 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_200mhz>;
- vmmc-supply = <®_3p3v>;
- cd-gpios = <&gpio1 4 0>;
- status = "okay";
- diff -Nur linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi.orig linux-3.16.6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi.orig
- --- linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi.orig 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi.orig 2014-10-23 12:27:10.986220036 -0500
- @@ -0,0 +1,202 @@
- +/*
- + * Copyright (C) 2014 Russell King
- + */
- +#include "imx6qdl-microsom.dtsi"
- +#include "imx6qdl-microsom-ar8035.dtsi"
- +
- +/ {
- + ir_recv: ir-receiver {
- + compatible = "gpio-ir-receiver";
- + gpios = <&gpio3 9 1>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_ir>;
- + };
- +
- + pwmleds {
- + compatible = "pwm-leds";
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_pwm1>;
- +
- + front {
- + active-low;
- + label = "imx6:red:front";
- + max-brightness = <248>;
- + pwms = <&pwm1 0 50000>;
- + };
- + };
- +
- + regulators {
- + compatible = "simple-bus";
- +
- + reg_3p3v: 3p3v {
- + compatible = "regulator-fixed";
- + regulator-name = "3P3V";
- + regulator-min-microvolt = <3300000>;
- + regulator-max-microvolt = <3300000>;
- + regulator-always-on;
- + };
- +
- + reg_usbh1_vbus: usb-h1-vbus {
- + compatible = "regulator-fixed";
- + enable-active-high;
- + gpio = <&gpio1 0 0>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_usbh1_vbus>;
- + regulator-name = "usb_h1_vbus";
- + regulator-min-microvolt = <5000000>;
- + regulator-max-microvolt = <5000000>;
- + };
- +
- + reg_usbotg_vbus: usb-otg-vbus {
- + compatible = "regulator-fixed";
- + enable-active-high;
- + gpio = <&gpio3 22 0>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_usbotg_vbus>;
- + regulator-name = "usb_otg_vbus";
- + regulator-min-microvolt = <5000000>;
- + regulator-max-microvolt = <5000000>;
- + };
- + };
- +
- + sound-spdif {
- + compatible = "fsl,imx-audio-spdif";
- + model = "Integrated SPDIF";
- + /* IMX6 doesn't implement this yet */
- + spdif-controller = <&spdif>;
- + spdif-out;
- + };
- +};
- +
- +&hdmi {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_hdmi>;
- + ddc-i2c-bus = <&i2c2>;
- + status = "okay";
- +};
- +
- +&i2c2 {
- + clock-frequency = <100000>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_i2c2>;
- + status = "okay";
- +};
- +
- +&i2c3 {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_i2c3>;
- +
- + status = "okay";
- +
- + rtc: pcf8523@68 {
- + compatible = "nxp,pcf8523";
- + reg = <0x68>;
- + };
- +};
- +
- +&iomuxc {
- + cubox_i {
- + pinctrl_cubox_i_hdmi: cubox-i-hdmi {
- + fsl,pins = <
- + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
- + >;
- + };
- +
- + pinctrl_cubox_i_i2c2: cubox-i-i2c2 {
- + fsl,pins = <
- + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
- + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
- + >;
- + };
- +
- + pinctrl_cubox_i_i2c3: cubox-i-i2c3 {
- + fsl,pins = <
- + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
- + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
- + >;
- + };
- +
- + pinctrl_cubox_i_ir: cubox-i-ir {
- + fsl,pins = <
- + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000
- + >;
- + };
- +
- + pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led {
- + fsl,pins = <MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b0>;
- + };
- +
- + pinctrl_cubox_i_spdif: cubox-i-spdif {
- + fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
- + };
- +
- + pinctrl_cubox_i_usbh1: cubox-i-usbh1 {
- + fsl,pins = <MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0>;
- + };
- +
- + pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus {
- + fsl,pins = <MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x4001b0b0>;
- + };
- +
- + pinctrl_cubox_i_usbotg: cubox-i-usbotg {
- + /*
- + * The Cubox-i pulls ID low, but as it's pointless
- + * leaving it as a pull-up, even if it is just 10uA.
- + */
- + fsl,pins = <
- + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059
- + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0
- + >;
- + };
- +
- + pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus {
- + fsl,pins = <MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x4001b0b0>;
- + };
- +
- + pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-aux {
- + fsl,pins = <
- + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071
- + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071
- + >;
- + };
- +
- + pinctrl_cubox_i_usdhc2: cubox-i-usdhc2 {
- + fsl,pins = <
- + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059
- + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059
- + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
- + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
- + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
- + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059
- + >;
- + };
- + };
- +};
- +
- +&spdif {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_spdif>;
- + status = "okay";
- +};
- +
- +&usbh1 {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_usbh1>;
- + vbus-supply = <®_usbh1_vbus>;
- + status = "okay";
- +};
- +
- +&usbotg {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_usbotg>;
- + vbus-supply = <®_usbotg_vbus>;
- + status = "okay";
- +};
- +
- +&usdhc2 {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
- + vmmc-supply = <®_3p3v>;
- + cd-gpios = <&gpio1 4 0>;
- + status = "okay";
- +};
- diff -Nur linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi linux-3.16.6/arch/arm/boot/dts/imx6qdl-microsom.dtsi
- --- linux-3.16.6.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2014-10-23 12:34:48.394220240 -0500
- @@ -1,15 +1,95 @@
- /*
- * Copyright (C) 2013,2014 Russell King
- */
- +#include <dt-bindings/gpio/gpio.h>
- +/ {
- + regulators {
- + compatible = "simple-bus";
- +
- + reg_brcm_osc: brcm-osc-reg {
- + compatible = "regulator-fixed";
- + enable-active-high;
- + gpio = <&gpio5 5 0>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_microsom_brcm_osc_reg>;
- + regulator-name = "brcm_osc_reg";
- + regulator-min-microvolt = <3300000>;
- + regulator-max-microvolt = <3300000>;
- + regulator-always-on;
- + regulator-boot-on;
- + };
- +
- + reg_brcm: brcm-reg {
- + compatible = "regulator-fixed";
- + enable-active-high;
- + gpio = <&gpio3 19 0>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_microsom_brcm_reg>;
- + regulator-name = "brcm_reg";
- + regulator-min-microvolt = <3300000>;
- + regulator-max-microvolt = <3300000>;
- + startup-delay-us = <200000>;
- + };
- + };
- +};
-
- &iomuxc {
- microsom {
- + pinctrl_microsom_brcm_bt: microsom-brcm-bt {
- + fsl,pins = <
- + MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070
- + MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x40013070
- + MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070
- + >;
- + };
- +
- + pinctrl_microsom_brcm_osc_reg: microsom-brcm-osc-reg {
- + fsl,pins = <
- + MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070
- + >;
- + };
- +
- + pinctrl_microsom_brcm_reg: microsom-brcm-reg {
- + fsl,pins = <
- + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070
- + >;
- + };
- +
- + pinctrl_microsom_brcm_wifi: microsom-brcm-wifi {
- + fsl,pins = <
- + MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0
- + MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x40013070
- + MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070
- + MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x40013070
- + >;
- + };
- +
- pinctrl_microsom_uart1: microsom-uart1 {
- fsl,pins = <
- MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
- MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
- >;
- };
- +
- + pinctrl_microsom_uart4_1: microsom-uart4 {
- + fsl,pins = <
- + MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1
- + MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1
- + MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1
- + MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1
- + >;
- + };
- +
- + pinctrl_microsom_usdhc1: microsom-usdhc1 {
- + fsl,pins = <
- + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059
- + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059
- + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
- + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
- + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
- + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
- + >;
- + };
- };
- };
-
- @@ -18,3 +98,23 @@
- pinctrl-0 = <&pinctrl_microsom_uart1>;
- status = "okay";
- };
- +
- +/* UART4 - Connected to optional BRCM Wifi/BT/FM */
- +&uart4 {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4_1>;
- + fsl,uart-has-rtscts;
- + status = "okay";
- +};
- +
- +/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */
- +&usdhc1 {
- + card-external-vcc-supply = <®_brcm>;
- + card-reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>, <&gpio6 0 GPIO_ACTIVE_LOW>;
- + keep-power-in-suspend;
- + non-removable;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>;
- + vmmc-supply = <®_brcm>;
- + status = "okay";
- +};
- diff -Nur linux-3.16.6.orig/arch/arm/mach-imx/clk-imx6q.c linux-3.16.6/arch/arm/mach-imx/clk-imx6q.c
- --- linux-3.16.6.orig/arch/arm/mach-imx/clk-imx6q.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/arch/arm/mach-imx/clk-imx6q.c 2014-10-23 12:36:09.214219998 -0500
- @@ -461,6 +461,9 @@
- clk_set_parent(clk[ipu2_di0_sel], clk[ipu2_di0_pre]);
- clk_set_parent(clk[ipu2_di1_sel], clk[ipu2_di1_pre]);
-
- + if (cpu_is_imx6dl())
- + clk_set_parent(clk[ipu1_sel], clk[pll3_pfd1_540m]);
- +
- /*
- * The gpmi needs 100MHz frequency in the EDO/Sync mode,
- * We can not get the 100MHz from the pll2_pfd0_352m.
- diff -Nur linux-3.16.6.orig/arch/arm/mach-imx/clk-pllv3.c linux-3.16.6/arch/arm/mach-imx/clk-pllv3.c
- --- linux-3.16.6.orig/arch/arm/mach-imx/clk-pllv3.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/arch/arm/mach-imx/clk-pllv3.c 2014-10-23 12:36:01.390219997 -0500
- @@ -273,9 +273,10 @@
- struct clk_pllv3 *pll = to_clk_pllv3(hw);
- unsigned long min_rate = parent_rate * 27;
- unsigned long max_rate = parent_rate * 54;
- - u32 val, div;
- + u32 val, newval, div;
- u32 mfn, mfd = 1000000;
- s64 temp64;
- + int ret;
-
- if (rate < min_rate || rate > max_rate)
- return -EINVAL;
- @@ -287,13 +288,27 @@
- mfn = temp64;
-
- val = readl_relaxed(pll->base);
- - val &= ~pll->div_mask;
- - val |= div;
- - writel_relaxed(val, pll->base);
- +
- + /* set the PLL into bypass mode */
- + newval = val | BM_PLL_BYPASS;
- + writel_relaxed(newval, pll->base);
- +
- + /* configure the new frequency */
- + newval &= ~pll->div_mask;
- + newval |= div;
- + writel_relaxed(newval, pll->base);
- writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
- - writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
- + writel(mfd, pll->base + PLL_DENOM_OFFSET);
- +
- + ret = clk_pllv3_wait_lock(pll);
- + if (ret == 0 && val & BM_PLL_POWER) {
- + /* only if it locked can we switch back to the PLL */
- + newval &= ~BM_PLL_BYPASS;
- + newval |= val & BM_PLL_BYPASS;
- + writel(newval, pll->base);
- + }
-
- - return clk_pllv3_wait_lock(pll);
- + return ret;
- }
-
- static const struct clk_ops clk_pllv3_av_ops = {
- diff -Nur linux-3.16.6.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt linux-3.16.6/Documentation/devicetree/bindings/ata/ahci-platform.txt
- --- linux-3.16.6.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/Documentation/devicetree/bindings/ata/ahci-platform.txt 2014-10-23 12:15:35.154220017 -0500
- @@ -6,8 +6,6 @@
- Required properties:
- - compatible : compatible string, one of:
- - "allwinner,sun4i-a10-ahci"
- - - "fsl,imx53-ahci"
- - - "fsl,imx6q-ahci"
- - "hisilicon,hisi-ahci"
- - "ibm,476gtr-ahci"
- - "marvell,armada-380-ahci"
- @@ -22,10 +20,6 @@
- - clocks : a list of phandle + clock specifier pairs
- - target-supply : regulator for SATA target power
-
- -"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties:
- -- clocks : must contain the sata, sata_ref and ahb clocks
- -- clock-names : must contain "ahb" for the ahb clock
- -
- Examples:
- sata@ffe08000 {
- compatible = "snps,spear-ahci";
- diff -Nur linux-3.16.6.orig/Documentation/devicetree/bindings/ata/imx-sata.txt linux-3.16.6/Documentation/devicetree/bindings/ata/imx-sata.txt
- --- linux-3.16.6.orig/Documentation/devicetree/bindings/ata/imx-sata.txt 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/Documentation/devicetree/bindings/ata/imx-sata.txt 2014-10-23 12:26:27.434219953 -0500
- @@ -0,0 +1,36 @@
- +* Freescale i.MX AHCI SATA Controller
- +
- +The Freescale i.MX SATA controller mostly conforms to the AHCI interface
- +with some special extensions at integration level.
- +
- +Required properties:
- +- compatible : should be one of the following:
- + - "fsl,imx53-ahci" for i.MX53 SATA controller
- + - "fsl,imx6q-ahci" for i.MX6Q SATA controller
- +- interrupts : interrupt mapping for SATA IRQ
- +- reg : registers mapping
- +- clocks : list of clock specifiers, must contain an entry for each
- + required entry in clock-names
- +- clock-names : should include "sata", "sata_ref" and "ahb" entries
- +
- +Optional properties:
- +- fsl,transmit-level-mV : transmit voltage level, in millivolts.
- +- fsl,transmit-boost-mdB : transmit boost level, in milli-decibels
- +- fsl,transmit-atten-16ths : transmit attenuation, in 16ths
- +- fsl,receive-eq-mdB : receive equalisation, in milli-decibels
- + Please refer to the technical documentation or the driver source code
- + for the list of legal values for these options.
- +- fsl,no-spread-spectrum : disable spread-spectrum clocking on the SATA
- + link.
- +
- +Examples:
- +
- +sata@02200000 {
- + compatible = "fsl,imx6q-ahci";
- + reg = <0x02200000 0x4000>;
- + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>;
- + clocks = <&clks IMX6QDL_CLK_SATA>,
- + <&clks IMX6QDL_CLK_SATA_REF_100M>,
- + <&clks IMX6QDL_CLK_AHB>;
- + clock-names = "sata", "sata_ref", "ahb";
- +};
- diff -Nur linux-3.16.6.orig/Documentation/devicetree/bindings/mmc/mmc.txt linux-3.16.6/Documentation/devicetree/bindings/mmc/mmc.txt
- --- linux-3.16.6.orig/Documentation/devicetree/bindings/mmc/mmc.txt 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/Documentation/devicetree/bindings/mmc/mmc.txt 2014-10-23 12:34:18.694220003 -0500
- @@ -5,6 +5,8 @@
- Interpreted by the OF core:
- - reg: Registers location and length.
- - interrupts: Interrupts used by the MMC controller.
- +- clocks: Clocks needed for the host controller, if any.
- +- clock-names: Goes with clocks above.
-
- Card detection:
- If no property below is supplied, host native card detect is used.
- @@ -41,6 +43,15 @@
- - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
- - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
-
- +Card power and reset control:
- +The following properties can be specified for cases where the MMC
- +peripheral needs additional reset, regulator and clock lines. It is for
- +example common for WiFi/BT adapters to have these separate from the main
- +MMC bus:
- + - card-reset-gpios: Specify GPIOs for card reset (reset active low)
- + - card-external-vcc-supply: Regulator to drive (independent) card VCC
- + - clock with name "card_ext_clock": External clock provided to the card
- +
- *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
- polarity properties, we have to fix the meaning of the "normal" and "inverted"
- line levels. We choose to follow the SDHCI standard, which specifies both those
- diff -Nur linux-3.16.6.orig/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt linux-3.16.6/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
- --- linux-3.16.6.orig/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt 2014-10-23 12:35:30.946219998 -0500
- @@ -60,8 +60,8 @@
- - compatible: Should be "fsl,imx-parallel-display"
- Optional properties:
- - interface_pix_fmt: How this display is connected to the
- - display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
- - and "lvds666".
- + display interface. Currently supported types: "rgb24", "rgb565", "bgr666",
- + "rgb666" and "lvds666".
- - edid: verbatim EDID data block describing attached display.
- - ddc: phandle describing the i2c bus handling the display data
- channel
- diff -Nur linux-3.16.6.orig/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml linux-3.16.6/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
- --- linux-3.16.6.orig/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml 2014-10-23 12:35:23.678220004 -0500
- @@ -279,6 +279,45 @@
- <entry></entry>
- <entry></entry>
- </row>
- + <row id="V4L2-PIX-FMT-RGB666">
- + <entry><constant>V4L2_PIX_FMT_RGB666</constant></entry>
- + <entry>'RGBH'</entry>
- + <entry></entry>
- + <entry>r<subscript>5</subscript></entry>
- + <entry>r<subscript>4</subscript></entry>
- + <entry>r<subscript>3</subscript></entry>
- + <entry>r<subscript>2</subscript></entry>
- + <entry>r<subscript>1</subscript></entry>
- + <entry>r<subscript>0</subscript></entry>
- + <entry>g<subscript>5</subscript></entry>
- + <entry>g<subscript>4</subscript></entry>
- + <entry></entry>
- + <entry>g<subscript>3</subscript></entry>
- + <entry>g<subscript>2</subscript></entry>
- + <entry>g<subscript>1</subscript></entry>
- + <entry>g<subscript>0</subscript></entry>
- + <entry>b<subscript>5</subscript></entry>
- + <entry>b<subscript>4</subscript></entry>
- + <entry>b<subscript>3</subscript></entry>
- + <entry>b<subscript>2</subscript></entry>
- + <entry></entry>
- + <entry>b<subscript>1</subscript></entry>
- + <entry>b<subscript>0</subscript></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + </row>
- <row id="V4L2-PIX-FMT-BGR24">
- <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
- <entry>'BGR3'</entry>
- diff -Nur linux-3.16.6.orig/drivers/ata/ahci_imx.c linux-3.16.6/drivers/ata/ahci_imx.c
- --- linux-3.16.6.orig/drivers/ata/ahci_imx.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/ata/ahci_imx.c 2014-10-23 12:26:19.770220044 -0500
- @@ -64,6 +64,7 @@
- struct regmap *gpr;
- bool no_device;
- bool first_time;
- + u32 phy_params;
- };
-
- static int ahci_imx_hotplug;
- @@ -248,14 +249,7 @@
- IMX6Q_GPR13_SATA_TX_LVL_MASK |
- IMX6Q_GPR13_SATA_MPLL_CLK_EN |
- IMX6Q_GPR13_SATA_TX_EDGE_RATE,
- - IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
- - IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
- - IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
- - IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
- - IMX6Q_GPR13_SATA_MPLL_SS_EN |
- - IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
- - IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
- - IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
- + imxpriv->phy_params);
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- @@ -369,6 +363,165 @@
- };
- MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
-
- +struct reg_value {
- + u32 of_value;
- + u32 reg_value;
- +};
- +
- +struct reg_property {
- + const char *name;
- + const struct reg_value *values;
- + size_t num_values;
- + u32 def_value;
- + u32 set_value;
- +};
- +
- +static const struct reg_value gpr13_tx_level[] = {
- + { 937, IMX6Q_GPR13_SATA_TX_LVL_0_937_V },
- + { 947, IMX6Q_GPR13_SATA_TX_LVL_0_947_V },
- + { 957, IMX6Q_GPR13_SATA_TX_LVL_0_957_V },
- + { 966, IMX6Q_GPR13_SATA_TX_LVL_0_966_V },
- + { 976, IMX6Q_GPR13_SATA_TX_LVL_0_976_V },
- + { 986, IMX6Q_GPR13_SATA_TX_LVL_0_986_V },
- + { 996, IMX6Q_GPR13_SATA_TX_LVL_0_996_V },
- + { 1005, IMX6Q_GPR13_SATA_TX_LVL_1_005_V },
- + { 1015, IMX6Q_GPR13_SATA_TX_LVL_1_015_V },
- + { 1025, IMX6Q_GPR13_SATA_TX_LVL_1_025_V },
- + { 1035, IMX6Q_GPR13_SATA_TX_LVL_1_035_V },
- + { 1045, IMX6Q_GPR13_SATA_TX_LVL_1_045_V },
- + { 1054, IMX6Q_GPR13_SATA_TX_LVL_1_054_V },
- + { 1064, IMX6Q_GPR13_SATA_TX_LVL_1_064_V },
- + { 1074, IMX6Q_GPR13_SATA_TX_LVL_1_074_V },
- + { 1084, IMX6Q_GPR13_SATA_TX_LVL_1_084_V },
- + { 1094, IMX6Q_GPR13_SATA_TX_LVL_1_094_V },
- + { 1104, IMX6Q_GPR13_SATA_TX_LVL_1_104_V },
- + { 1113, IMX6Q_GPR13_SATA_TX_LVL_1_113_V },
- + { 1123, IMX6Q_GPR13_SATA_TX_LVL_1_123_V },
- + { 1133, IMX6Q_GPR13_SATA_TX_LVL_1_133_V },
- + { 1143, IMX6Q_GPR13_SATA_TX_LVL_1_143_V },
- + { 1152, IMX6Q_GPR13_SATA_TX_LVL_1_152_V },
- + { 1162, IMX6Q_GPR13_SATA_TX_LVL_1_162_V },
- + { 1172, IMX6Q_GPR13_SATA_TX_LVL_1_172_V },
- + { 1182, IMX6Q_GPR13_SATA_TX_LVL_1_182_V },
- + { 1191, IMX6Q_GPR13_SATA_TX_LVL_1_191_V },
- + { 1201, IMX6Q_GPR13_SATA_TX_LVL_1_201_V },
- + { 1211, IMX6Q_GPR13_SATA_TX_LVL_1_211_V },
- + { 1221, IMX6Q_GPR13_SATA_TX_LVL_1_221_V },
- + { 1230, IMX6Q_GPR13_SATA_TX_LVL_1_230_V },
- + { 1240, IMX6Q_GPR13_SATA_TX_LVL_1_240_V }
- +};
- +
- +static const struct reg_value gpr13_tx_boost[] = {
- + { 0, IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB },
- + { 370, IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB },
- + { 740, IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB },
- + { 1110, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB },
- + { 1480, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB },
- + { 1850, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB },
- + { 2220, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB },
- + { 2590, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB },
- + { 2960, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB },
- + { 3330, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB },
- + { 3700, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB },
- + { 4070, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB },
- + { 4440, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB },
- + { 4810, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB },
- + { 5280, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB },
- + { 5750, IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB }
- +};
- +
- +static const struct reg_value gpr13_tx_atten[] = {
- + { 8, IMX6Q_GPR13_SATA_TX_ATTEN_8_16 },
- + { 9, IMX6Q_GPR13_SATA_TX_ATTEN_9_16 },
- + { 10, IMX6Q_GPR13_SATA_TX_ATTEN_10_16 },
- + { 12, IMX6Q_GPR13_SATA_TX_ATTEN_12_16 },
- + { 14, IMX6Q_GPR13_SATA_TX_ATTEN_14_16 },
- + { 16, IMX6Q_GPR13_SATA_TX_ATTEN_16_16 },
- +};
- +
- +static const struct reg_value gpr13_rx_eq[] = {
- + { 500, IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB },
- + { 1000, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB },
- + { 1500, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB },
- + { 2000, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB },
- + { 2500, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB },
- + { 3000, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB },
- + { 3500, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB },
- + { 4000, IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB },
- +};
- +
- +static const struct reg_property gpr13_props[] = {
- + {
- + .name = "fsl,transmit-level-mV",
- + .values = gpr13_tx_level,
- + .num_values = ARRAY_SIZE(gpr13_tx_level),
- + .def_value = IMX6Q_GPR13_SATA_TX_LVL_1_025_V,
- + }, {
- + .name = "fsl,transmit-boost-mdB",
- + .values = gpr13_tx_boost,
- + .num_values = ARRAY_SIZE(gpr13_tx_boost),
- + .def_value = IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB,
- + }, {
- + .name = "fsl,transmit-atten-16ths",
- + .values = gpr13_tx_atten,
- + .num_values = ARRAY_SIZE(gpr13_tx_atten),
- + .def_value = IMX6Q_GPR13_SATA_TX_ATTEN_9_16,
- + }, {
- + .name = "fsl,receive-eq-mdB",
- + .values = gpr13_rx_eq,
- + .num_values = ARRAY_SIZE(gpr13_rx_eq),
- + .def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB,
- + }, {
- + .name = "fsl,no-spread-spectrum",
- + .def_value = IMX6Q_GPR13_SATA_MPLL_SS_EN,
- + .set_value = 0,
- + },
- +};
- +
- +static u32 imx_ahci_parse_props(struct device *dev,
- + const struct reg_property *prop, size_t num)
- +{
- + struct device_node *np = dev->of_node;
- + u32 reg_value = 0;
- + int i, j;
- +
- + for (i = 0; i < num; i++, prop++) {
- + u32 of_val;
- +
- + if (prop->num_values == 0) {
- + if (of_property_read_bool(np, prop->name))
- + reg_value |= prop->set_value;
- + else
- + reg_value |= prop->def_value;
- + continue;
- + }
- +
- + if (of_property_read_u32(np, prop->name, &of_val)) {
- + dev_info(dev, "%s not specified, using %08x\n",
- + prop->name, prop->def_value);
- + reg_value |= prop->def_value;
- + continue;
- + }
- +
- + for (j = 0; j < prop->num_values; j++) {
- + if (prop->values[j].of_value == of_val) {
- + dev_info(dev, "%s value %u, using %08x\n",
- + prop->name, of_val, prop->values[j].reg_value);
- + reg_value |= prop->values[j].reg_value;
- + break;
- + }
- + }
- +
- + if (j == prop->num_values) {
- + dev_err(dev, "DT property %s is not a valid value\n",
- + prop->name);
- + reg_value |= prop->def_value;
- + }
- + }
- +
- + return reg_value;
- +}
- +
- static int imx_ahci_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- @@ -410,6 +563,8 @@
- }
-
- if (imxpriv->type == AHCI_IMX6Q) {
- + u32 reg_value;
- +
- imxpriv->gpr = syscon_regmap_lookup_by_compatible(
- "fsl,imx6q-iomuxc-gpr");
- if (IS_ERR(imxpriv->gpr)) {
- @@ -417,6 +572,15 @@
- "failed to find fsl,imx6q-iomux-gpr regmap\n");
- return PTR_ERR(imxpriv->gpr);
- }
- +
- + reg_value = imx_ahci_parse_props(dev, gpr13_props,
- + ARRAY_SIZE(gpr13_props));
- +
- + imxpriv->phy_params =
- + IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
- + IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
- + IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
- + reg_value;
- }
-
- hpriv = ahci_platform_get_resources(pdev);
- diff -Nur linux-3.16.6.orig/drivers/ata/ahci_imx.c.orig linux-3.16.6/drivers/ata/ahci_imx.c.orig
- --- linux-3.16.6.orig/drivers/ata/ahci_imx.c.orig 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/ata/ahci_imx.c.orig 2014-10-23 12:18:59.602219672 -0500
- @@ -0,0 +1,679 @@
- +/*
- + * copyright (c) 2013 Freescale Semiconductor, Inc.
- + * Freescale IMX AHCI SATA platform driver
- + *
- + * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
- + *
- + * This program is free software; you can redistribute it and/or modify it
- + * under the terms and conditions of the GNU General Public License,
- + * version 2, as published by the Free Software Foundation.
- + *
- + * This program is distributed in the hope 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.
- + *
- + * You should have received a copy of the GNU General Public License along with
- + * this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/platform_device.h>
- +#include <linux/regmap.h>
- +#include <linux/ahci_platform.h>
- +#include <linux/of_device.h>
- +#include <linux/mfd/syscon.h>
- +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
- +#include <linux/libata.h>
- +#include "ahci.h"
- +
- +enum {
- + /* Timer 1-ms Register */
- + IMX_TIMER1MS = 0x00e0,
- + /* Port0 PHY Control Register */
- + IMX_P0PHYCR = 0x0178,
- + IMX_P0PHYCR_TEST_PDDQ = 1 << 20,
- + IMX_P0PHYCR_CR_READ = 1 << 19,
- + IMX_P0PHYCR_CR_WRITE = 1 << 18,
- + IMX_P0PHYCR_CR_CAP_DATA = 1 << 17,
- + IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16,
- + /* Port0 PHY Status Register */
- + IMX_P0PHYSR = 0x017c,
- + IMX_P0PHYSR_CR_ACK = 1 << 18,
- + IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0,
- + /* Lane0 Output Status Register */
- + IMX_LANE0_OUT_STAT = 0x2003,
- + IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1,
- + /* Clock Reset Register */
- + IMX_CLOCK_RESET = 0x7f3f,
- + IMX_CLOCK_RESET_RESET = 1 << 0,
- +};
- +
- +enum ahci_imx_type {
- + AHCI_IMX53,
- + AHCI_IMX6Q,
- +};
- +
- +struct imx_ahci_priv {
- + struct platform_device *ahci_pdev;
- + enum ahci_imx_type type;
- + struct clk *sata_clk;
- + struct clk *sata_ref_clk;
- + struct clk *ahb_clk;
- + struct regmap *gpr;
- + bool no_device;
- + bool first_time;
- + u32 phy_params;
- +};
- +
- +static int ahci_imx_hotplug;
- +module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
- +MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
- +
- +static void ahci_imx_host_stop(struct ata_host *host);
- +
- +static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert)
- +{
- + int timeout = 10;
- + u32 crval;
- + u32 srval;
- +
- + /* Assert or deassert the bit */
- + crval = readl(mmio + IMX_P0PHYCR);
- + if (assert)
- + crval |= bit;
- + else
- + crval &= ~bit;
- + writel(crval, mmio + IMX_P0PHYCR);
- +
- + /* Wait for the cr_ack signal */
- + do {
- + srval = readl(mmio + IMX_P0PHYSR);
- + if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK)
- + break;
- + usleep_range(100, 200);
- + } while (--timeout);
- +
- + return timeout ? 0 : -ETIMEDOUT;
- +}
- +
- +static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio)
- +{
- + u32 crval = addr;
- + int ret;
- +
- + /* Supply the address on cr_data_in */
- + writel(crval, mmio + IMX_P0PHYCR);
- +
- + /* Assert the cr_cap_addr signal */
- + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true);
- + if (ret)
- + return ret;
- +
- + /* Deassert cr_cap_addr */
- + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false);
- + if (ret)
- + return ret;
- +
- + return 0;
- +}
- +
- +static int imx_phy_reg_write(u16 val, void __iomem *mmio)
- +{
- + u32 crval = val;
- + int ret;
- +
- + /* Supply the data on cr_data_in */
- + writel(crval, mmio + IMX_P0PHYCR);
- +
- + /* Assert the cr_cap_data signal */
- + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true);
- + if (ret)
- + return ret;
- +
- + /* Deassert cr_cap_data */
- + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false);
- + if (ret)
- + return ret;
- +
- + if (val & IMX_CLOCK_RESET_RESET) {
- + /*
- + * In case we're resetting the phy, it's unable to acknowledge,
- + * so we return immediately here.
- + */
- + crval |= IMX_P0PHYCR_CR_WRITE;
- + writel(crval, mmio + IMX_P0PHYCR);
- + goto out;
- + }
- +
- + /* Assert the cr_write signal */
- + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true);
- + if (ret)
- + return ret;
- +
- + /* Deassert cr_write */
- + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false);
- + if (ret)
- + return ret;
- +
- +out:
- + return 0;
- +}
- +
- +static int imx_phy_reg_read(u16 *val, void __iomem *mmio)
- +{
- + int ret;
- +
- + /* Assert the cr_read signal */
- + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true);
- + if (ret)
- + return ret;
- +
- + /* Capture the data from cr_data_out[] */
- + *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT;
- +
- + /* Deassert cr_read */
- + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false);
- + if (ret)
- + return ret;
- +
- + return 0;
- +}
- +
- +static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
- +{
- + void __iomem *mmio = hpriv->mmio;
- + int timeout = 10;
- + u16 val;
- + int ret;
- +
- + /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */
- + ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio);
- + if (ret)
- + return ret;
- + ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio);
- + if (ret)
- + return ret;
- +
- + /* Wait for PHY RX_PLL to be stable */
- + do {
- + usleep_range(100, 200);
- + ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio);
- + if (ret)
- + return ret;
- + ret = imx_phy_reg_read(&val, mmio);
- + if (ret)
- + return ret;
- + if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE)
- + break;
- + } while (--timeout);
- +
- + return timeout ? 0 : -ETIMEDOUT;
- +}
- +
- +static int imx_sata_enable(struct ahci_host_priv *hpriv)
- +{
- + struct imx_ahci_priv *imxpriv = hpriv->plat_data;
- + struct device *dev = &imxpriv->ahci_pdev->dev;
- + int ret;
- +
- + if (imxpriv->no_device)
- + return 0;
- +
- + if (hpriv->target_pwr) {
- + ret = regulator_enable(hpriv->target_pwr);
- + if (ret)
- + return ret;
- + }
- +
- + ret = clk_prepare_enable(imxpriv->sata_ref_clk);
- + if (ret < 0)
- + goto disable_regulator;
- +
- + if (imxpriv->type == AHCI_IMX6Q) {
- + /*
- + * set PHY Paremeters, two steps to configure the GPR13,
- + * one write for rest of parameters, mask of first write
- + * is 0x07ffffff, and the other one write for setting
- + * the mpll_clk_en.
- + */
- + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- + IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
- + IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
- + IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
- + IMX6Q_GPR13_SATA_SPD_MODE_MASK |
- + IMX6Q_GPR13_SATA_MPLL_SS_EN |
- + IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
- + IMX6Q_GPR13_SATA_TX_BOOST_MASK |
- + IMX6Q_GPR13_SATA_TX_LVL_MASK |
- + IMX6Q_GPR13_SATA_MPLL_CLK_EN |
- + IMX6Q_GPR13_SATA_TX_EDGE_RATE,
- + imxpriv->phy_params);
- + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- + IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- + IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- +
- + usleep_range(100, 200);
- +
- + ret = imx_sata_phy_reset(hpriv);
- + if (ret) {
- + dev_err(dev, "failed to reset phy: %d\n", ret);
- + goto disable_regulator;
- + }
- + }
- +
- + usleep_range(1000, 2000);
- +
- + return 0;
- +
- +disable_regulator:
- + if (hpriv->target_pwr)
- + regulator_disable(hpriv->target_pwr);
- +
- + return ret;
- +}
- +
- +static void imx_sata_disable(struct ahci_host_priv *hpriv)
- +{
- + struct imx_ahci_priv *imxpriv = hpriv->plat_data;
- +
- + if (imxpriv->no_device)
- + return;
- +
- + if (imxpriv->type == AHCI_IMX6Q) {
- + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- + IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- + !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- + }
- +
- + clk_disable_unprepare(imxpriv->sata_ref_clk);
- +
- + if (hpriv->target_pwr)
- + regulator_disable(hpriv->target_pwr);
- +}
- +
- +static void ahci_imx_error_handler(struct ata_port *ap)
- +{
- + u32 reg_val;
- + struct ata_device *dev;
- + struct ata_host *host = dev_get_drvdata(ap->dev);
- + struct ahci_host_priv *hpriv = host->private_data;
- + void __iomem *mmio = hpriv->mmio;
- + struct imx_ahci_priv *imxpriv = hpriv->plat_data;
- +
- + ahci_error_handler(ap);
- +
- + if (!(imxpriv->first_time) || ahci_imx_hotplug)
- + return;
- +
- + imxpriv->first_time = false;
- +
- + ata_for_each_dev(dev, &ap->link, ENABLED)
- + return;
- + /*
- + * Disable link to save power. An imx ahci port can't be recovered
- + * without full reset once the pddq mode is enabled making it
- + * impossible to use as part of libata LPM.
- + */
- + reg_val = readl(mmio + IMX_P0PHYCR);
- + writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR);
- + imx_sata_disable(hpriv);
- + imxpriv->no_device = true;
- +
- + dev_info(ap->dev, "no device found, disabling link.\n");
- + dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX ".hotplug=1 to enable hotplug\n");
- +}
- +
- +static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
- + unsigned long deadline)
- +{
- + struct ata_port *ap = link->ap;
- + struct ata_host *host = dev_get_drvdata(ap->dev);
- + struct ahci_host_priv *hpriv = host->private_data;
- + struct imx_ahci_priv *imxpriv = hpriv->plat_data;
- + int ret = -EIO;
- +
- + if (imxpriv->type == AHCI_IMX53)
- + ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
- + else if (imxpriv->type == AHCI_IMX6Q)
- + ret = ahci_ops.softreset(link, class, deadline);
- +
- + return ret;
- +}
- +
- +static struct ata_port_operations ahci_imx_ops = {
- + .inherits = &ahci_ops,
- + .host_stop = ahci_imx_host_stop,
- + .error_handler = ahci_imx_error_handler,
- + .softreset = ahci_imx_softreset,
- +};
- +
- +static const struct ata_port_info ahci_imx_port_info = {
- + .flags = AHCI_FLAG_COMMON,
- + .pio_mask = ATA_PIO4,
- + .udma_mask = ATA_UDMA6,
- + .port_ops = &ahci_imx_ops,
- +};
- +
- +static const struct of_device_id imx_ahci_of_match[] = {
- + { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
- + { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
- + {},
- +};
- +MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
- +
- +struct reg_value {
- + u32 of_value;
- + u32 reg_value;
- +};
- +
- +struct reg_property {
- + const char *name;
- + const struct reg_value *values;
- + size_t num_values;
- + u32 def_value;
- +};
- +
- +static const struct reg_value gpr13_tx_level[] = {
- + { 937, IMX6Q_GPR13_SATA_TX_LVL_0_937_V },
- + { 947, IMX6Q_GPR13_SATA_TX_LVL_0_947_V },
- + { 957, IMX6Q_GPR13_SATA_TX_LVL_0_957_V },
- + { 966, IMX6Q_GPR13_SATA_TX_LVL_0_966_V },
- + { 976, IMX6Q_GPR13_SATA_TX_LVL_0_976_V },
- + { 986, IMX6Q_GPR13_SATA_TX_LVL_0_986_V },
- + { 996, IMX6Q_GPR13_SATA_TX_LVL_0_996_V },
- + { 1005, IMX6Q_GPR13_SATA_TX_LVL_1_005_V },
- + { 1015, IMX6Q_GPR13_SATA_TX_LVL_1_015_V },
- + { 1025, IMX6Q_GPR13_SATA_TX_LVL_1_025_V },
- + { 1035, IMX6Q_GPR13_SATA_TX_LVL_1_035_V },
- + { 1045, IMX6Q_GPR13_SATA_TX_LVL_1_045_V },
- + { 1054, IMX6Q_GPR13_SATA_TX_LVL_1_054_V },
- + { 1064, IMX6Q_GPR13_SATA_TX_LVL_1_064_V },
- + { 1074, IMX6Q_GPR13_SATA_TX_LVL_1_074_V },
- + { 1084, IMX6Q_GPR13_SATA_TX_LVL_1_084_V },
- + { 1094, IMX6Q_GPR13_SATA_TX_LVL_1_094_V },
- + { 1104, IMX6Q_GPR13_SATA_TX_LVL_1_104_V },
- + { 1113, IMX6Q_GPR13_SATA_TX_LVL_1_113_V },
- + { 1123, IMX6Q_GPR13_SATA_TX_LVL_1_123_V },
- + { 1133, IMX6Q_GPR13_SATA_TX_LVL_1_133_V },
- + { 1143, IMX6Q_GPR13_SATA_TX_LVL_1_143_V },
- + { 1152, IMX6Q_GPR13_SATA_TX_LVL_1_152_V },
- + { 1162, IMX6Q_GPR13_SATA_TX_LVL_1_162_V },
- + { 1172, IMX6Q_GPR13_SATA_TX_LVL_1_172_V },
- + { 1182, IMX6Q_GPR13_SATA_TX_LVL_1_182_V },
- + { 1191, IMX6Q_GPR13_SATA_TX_LVL_1_191_V },
- + { 1201, IMX6Q_GPR13_SATA_TX_LVL_1_201_V },
- + { 1211, IMX6Q_GPR13_SATA_TX_LVL_1_211_V },
- + { 1221, IMX6Q_GPR13_SATA_TX_LVL_1_221_V },
- + { 1230, IMX6Q_GPR13_SATA_TX_LVL_1_230_V },
- + { 1240, IMX6Q_GPR13_SATA_TX_LVL_1_240_V }
- +};
- +
- +static const struct reg_value gpr13_tx_boost[] = {
- + { 0, IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB },
- + { 370, IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB },
- + { 740, IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB },
- + { 1110, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB },
- + { 1480, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB },
- + { 1850, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB },
- + { 2220, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB },
- + { 2590, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB },
- + { 2960, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB },
- + { 3330, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB },
- + { 3700, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB },
- + { 4070, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB },
- + { 4440, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB },
- + { 4810, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB },
- + { 5280, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB },
- + { 5750, IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB }
- +};
- +
- +static const struct reg_value gpr13_tx_atten[] = {
- + { 8, IMX6Q_GPR13_SATA_TX_ATTEN_8_16 },
- + { 9, IMX6Q_GPR13_SATA_TX_ATTEN_9_16 },
- + { 10, IMX6Q_GPR13_SATA_TX_ATTEN_10_16 },
- + { 12, IMX6Q_GPR13_SATA_TX_ATTEN_12_16 },
- + { 14, IMX6Q_GPR13_SATA_TX_ATTEN_14_16 },
- + { 16, IMX6Q_GPR13_SATA_TX_ATTEN_16_16 },
- +};
- +
- +static const struct reg_value gpr13_rx_eq[] = {
- + { 500, IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB },
- + { 1000, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB },
- + { 1500, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB },
- + { 2000, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB },
- + { 2500, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB },
- + { 3000, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB },
- + { 3500, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB },
- + { 4000, IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB },
- +};
- +
- +static const struct reg_property gpr13_props[] = {
- + {
- + .name = "fsl,transmit-level-mV",
- + .values = gpr13_tx_level,
- + .num_values = ARRAY_SIZE(gpr13_tx_level),
- + .def_value = IMX6Q_GPR13_SATA_TX_LVL_1_025_V,
- + }, {
- + .name = "fsl,transmit-boost-mdB",
- + .values = gpr13_tx_boost,
- + .num_values = ARRAY_SIZE(gpr13_tx_boost),
- + .def_value = IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB,
- + }, {
- + .name = "fsl,transmit-atten-16ths",
- + .values = gpr13_tx_atten,
- + .num_values = ARRAY_SIZE(gpr13_tx_atten),
- + .def_value = IMX6Q_GPR13_SATA_TX_ATTEN_9_16,
- + }, {
- + .name = "fsl,receive-eq-mdB",
- + .values = gpr13_rx_eq,
- + .num_values = ARRAY_SIZE(gpr13_rx_eq),
- + .def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB,
- + },
- +};
- +
- +static u32 imx_ahci_parse_props(struct device *dev,
- + const struct reg_property *prop, size_t num)
- +{
- + struct device_node *np = dev->of_node;
- + u32 reg_value = 0;
- + int i, j;
- +
- + for (i = 0; i < num; i++, prop++) {
- + u32 of_val;
- +
- + if (of_property_read_u32(np, prop->name, &of_val)) {
- + dev_info(dev, "%s not specified, using %08x\n",
- + prop->name, prop->def_value);
- + reg_value |= prop->def_value;
- + continue;
- + }
- +
- + for (j = 0; j < prop->num_values; j++) {
- + if (prop->values[j].of_value == of_val) {
- + dev_info(dev, "%s value %u, using %08x\n",
- + prop->name, of_val, prop->values[j].reg_value);
- + reg_value |= prop->values[j].reg_value;
- + break;
- + }
- + }
- +
- + if (j == prop->num_values) {
- + dev_err(dev, "DT property %s is not a valid value\n",
- + prop->name);
- + reg_value |= prop->def_value;
- + }
- + }
- +
- + return reg_value;
- +}
- +
- +static int imx_ahci_probe(struct platform_device *pdev)
- +{
- + struct device *dev = &pdev->dev;
- + const struct of_device_id *of_id;
- + struct ahci_host_priv *hpriv;
- + struct imx_ahci_priv *imxpriv;
- + unsigned int reg_val;
- + int ret;
- +
- + of_id = of_match_device(imx_ahci_of_match, dev);
- + if (!of_id)
- + return -EINVAL;
- +
- + imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
- + if (!imxpriv)
- + return -ENOMEM;
- +
- + imxpriv->ahci_pdev = pdev;
- + imxpriv->no_device = false;
- + imxpriv->first_time = true;
- + imxpriv->type = (enum ahci_imx_type)of_id->data;
- +
- + imxpriv->sata_clk = devm_clk_get(dev, "sata");
- + if (IS_ERR(imxpriv->sata_clk)) {
- + dev_err(dev, "can't get sata clock.\n");
- + return PTR_ERR(imxpriv->sata_clk);
- + }
- +
- + imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
- + if (IS_ERR(imxpriv->sata_ref_clk)) {
- + dev_err(dev, "can't get sata_ref clock.\n");
- + return PTR_ERR(imxpriv->sata_ref_clk);
- + }
- +
- + imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
- + if (IS_ERR(imxpriv->ahb_clk)) {
- + dev_err(dev, "can't get ahb clock.\n");
- + return PTR_ERR(imxpriv->ahb_clk);
- + }
- +
- + if (imxpriv->type == AHCI_IMX6Q) {
- + u32 reg_value;
- +
- + imxpriv->gpr = syscon_regmap_lookup_by_compatible(
- + "fsl,imx6q-iomuxc-gpr");
- + if (IS_ERR(imxpriv->gpr)) {
- + dev_err(dev,
- + "failed to find fsl,imx6q-iomux-gpr regmap\n");
- + return PTR_ERR(imxpriv->gpr);
- + }
- +
- + reg_value = imx_ahci_parse_props(dev, gpr13_props,
- + ARRAY_SIZE(gpr13_props));
- +
- + imxpriv->phy_params =
- + IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
- + IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
- + IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
- + IMX6Q_GPR13_SATA_MPLL_SS_EN |
- + reg_value;
- + }
- +
- + hpriv = ahci_platform_get_resources(pdev);
- + if (IS_ERR(hpriv))
- + return PTR_ERR(hpriv);
- +
- + hpriv->plat_data = imxpriv;
- +
- + ret = clk_prepare_enable(imxpriv->sata_clk);
- + if (ret)
- + return ret;
- +
- + ret = imx_sata_enable(hpriv);
- + if (ret)
- + goto disable_clk;
- +
- + /*
- + * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
- + * and IP vendor specific register IMX_TIMER1MS.
- + * Configure CAP_SSS (support stagered spin up).
- + * Implement the port0.
- + * Get the ahb clock rate, and configure the TIMER1MS register.
- + */
- + reg_val = readl(hpriv->mmio + HOST_CAP);
- + if (!(reg_val & HOST_CAP_SSS)) {
- + reg_val |= HOST_CAP_SSS;
- + writel(reg_val, hpriv->mmio + HOST_CAP);
- + }
- + reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
- + if (!(reg_val & 0x1)) {
- + reg_val |= 0x1;
- + writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
- + }
- +
- + reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
- + writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
- +
- + ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info,
- + 0, 0, 0);
- + if (ret)
- + goto disable_sata;
- +
- + return 0;
- +
- +disable_sata:
- + imx_sata_disable(hpriv);
- +disable_clk:
- + clk_disable_unprepare(imxpriv->sata_clk);
- + return ret;
- +}
- +
- +static void ahci_imx_host_stop(struct ata_host *host)
- +{
- + struct ahci_host_priv *hpriv = host->private_data;
- + struct imx_ahci_priv *imxpriv = hpriv->plat_data;
- +
- + imx_sata_disable(hpriv);
- + clk_disable_unprepare(imxpriv->sata_clk);
- +}
- +
- +#ifdef CONFIG_PM_SLEEP
- +static int imx_ahci_suspend(struct device *dev)
- +{
- + struct ata_host *host = dev_get_drvdata(dev);
- + struct ahci_host_priv *hpriv = host->private_data;
- + int ret;
- +
- + ret = ahci_platform_suspend_host(dev);
- + if (ret)
- + return ret;
- +
- + imx_sata_disable(hpriv);
- +
- + return 0;
- +}
- +
- +static int imx_ahci_resume(struct device *dev)
- +{
- + struct ata_host *host = dev_get_drvdata(dev);
- + struct ahci_host_priv *hpriv = host->private_data;
- + int ret;
- +
- + ret = imx_sata_enable(hpriv);
- + if (ret)
- + return ret;
- +
- + return ahci_platform_resume_host(dev);
- +}
- +#endif
- +
- +static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
- +
- +static struct platform_driver imx_ahci_driver = {
- + .probe = imx_ahci_probe,
- + .remove = ata_platform_remove_one,
- + .driver = {
- + .name = "ahci-imx",
- + .owner = THIS_MODULE,
- + .of_match_table = imx_ahci_of_match,
- + .pm = &ahci_imx_pm_ops,
- + },
- +};
- +module_platform_driver(imx_ahci_driver);
- +
- +MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver");
- +MODULE_AUTHOR("Richard Zhu <Hong-Xing.Zhu@freescale.com>");
- +MODULE_LICENSE("GPL");
- +MODULE_ALIAS("ahci:imx");
- diff -Nur linux-3.16.6.orig/drivers/cec/cec-dev.c linux-3.16.6/drivers/cec/cec-dev.c
- --- linux-3.16.6.orig/drivers/cec/cec-dev.c 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/cec/cec-dev.c 2014-10-23 12:37:18.374219998 -0500
- @@ -0,0 +1,384 @@
- +/*
- + * HDMI Consumer Electronics Control
- + *
- + * This provides the user API for communication with HDMI CEC complaint
- + * devices in kernel drivers, and is based upon the protocol developed
- + * by Freescale for their i.MX SoCs.
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License version 2 as
- + * published by the Free Software Foundation.
- + */
- +#include <linux/cec-dev.h>
- +#include <linux/device.h>
- +#include <linux/fs.h>
- +#include <linux/module.h>
- +#include <linux/poll.h>
- +#include <linux/sched.h>
- +#include <linux/slab.h>
- +
- +struct cec_event {
- + struct cec_user_event usr;
- + struct list_head node;
- +};
- +
- +static struct class *cec_class;
- +static int cec_major;
- +
- +static void cec_dev_send_message(struct cec_dev *cec_dev, u8 *msg,
- + size_t count)
- +{
- + unsigned long flags;
- +
- + spin_lock_irqsave(&cec_dev->lock, flags);
- + cec_dev->retries = 5;
- + cec_dev->write_busy = 1;
- + cec_dev->send_message(cec_dev, msg, count);
- + spin_unlock_irqrestore(&cec_dev->lock, flags);
- +}
- +
- +void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len)
- +{
- + struct cec_event *event;
- + unsigned long flags;
- +
- + event = kzalloc(sizeof(*event), GFP_ATOMIC);
- + if (event) {
- + event->usr.event_type = type;
- + event->usr.msg_len = len;
- + if (msg)
- + memcpy(event->usr.msg, msg, len);
- +
- + spin_lock_irqsave(&cec_dev->lock, flags);
- + list_add_tail(&event->node, &cec_dev->events);
- + spin_unlock_irqrestore(&cec_dev->lock, flags);
- + wake_up(&cec_dev->waitq);
- + }
- +}
- +EXPORT_SYMBOL_GPL(cec_dev_event);
- +
- +static int cec_dev_lock_write(struct cec_dev *cec_dev, struct file *file)
- + __acquires(cec_dev->mutex)
- +{
- + int ret;
- +
- + do {
- + if (file->f_flags & O_NONBLOCK) {
- + if (cec_dev->write_busy)
- + return -EAGAIN;
- + } else {
- + ret = wait_event_interruptible(cec_dev->waitq,
- + !cec_dev->write_busy);
- + if (ret)
- + break;
- + }
- +
- + ret = mutex_lock_interruptible(&cec_dev->mutex);
- + if (ret)
- + break;
- +
- + if (!cec_dev->write_busy)
- + break;
- +
- + mutex_unlock(&cec_dev->mutex);
- + } while (1);
- +
- + return ret;
- +}
- +
- +static ssize_t cec_dev_read(struct file *file, char __user *buf,
- + size_t count, loff_t *ppos)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- + ssize_t ret;
- +
- + if (count > sizeof(struct cec_user_event))
- + count = sizeof(struct cec_user_event);
- +
- + if (!access_ok(VERIFY_WRITE, buf, count))
- + return -EFAULT;
- +
- + do {
- + struct cec_event *event = NULL;
- + unsigned long flags;
- +
- + spin_lock_irqsave(&cec_dev->lock, flags);
- + if (!list_empty(&cec_dev->events)) {
- + event = list_first_entry(&cec_dev->events,
- + struct cec_event, node);
- + list_del(&event->node);
- + }
- + spin_unlock_irqrestore(&cec_dev->lock, flags);
- +
- + if (event) {
- + ret = __copy_to_user(buf, &event->usr, count) ?
- + -EFAULT : count;
- + kfree(event);
- + break;
- + }
- +
- + if (file->f_flags & O_NONBLOCK) {
- + ret = -EAGAIN;
- + break;
- + }
- +
- + ret = wait_event_interruptible(cec_dev->waitq,
- + !list_empty(&cec_dev->events));
- + if (ret)
- + break;
- + } while (1);
- +
- + return ret;
- +}
- +
- +static ssize_t cec_dev_write(struct file *file, const char __user *buf,
- + size_t count, loff_t *ppos)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- + u8 msg[MAX_MESSAGE_LEN];
- + int ret;
- +
- + if (count > sizeof(msg))
- + return -E2BIG;
- +
- + if (copy_from_user(msg, buf, count))
- + return -EFAULT;
- +
- + ret = cec_dev_lock_write(cec_dev, file);
- + if (ret)
- + return ret;
- +
- + cec_dev_send_message(cec_dev, msg, count);
- +
- + mutex_unlock(&cec_dev->mutex);
- +
- + return count;
- +}
- +
- +static long cec_dev_ioctl(struct file *file, u_int cmd, unsigned long arg)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- + int ret;
- +
- + switch (cmd) {
- + case HDMICEC_IOC_O_SETLOGICALADDRESS:
- + case HDMICEC_IOC_SETLOGICALADDRESS:
- + if (arg > 15) {
- + ret = -EINVAL;
- + break;
- + }
- +
- + ret = cec_dev_lock_write(cec_dev, file);
- + if (ret == 0) {
- + unsigned char msg[1];
- +
- + cec_dev->addresses = BIT(arg);
- + cec_dev->set_address(cec_dev, cec_dev->addresses);
- +
- + /*
- + * Send a ping message with the source and destination
- + * set to our address; the result indicates whether
- + * unit has chosen our address simultaneously.
- + */
- + msg[0] = arg << 4 | arg;
- + cec_dev_send_message(cec_dev, msg, sizeof(msg));
- + mutex_unlock(&cec_dev->mutex);
- + }
- + break;
- +
- + case HDMICEC_IOC_STARTDEVICE:
- + ret = mutex_lock_interruptible(&cec_dev->mutex);
- + if (ret == 0) {
- + cec_dev->addresses = BIT(15);
- + cec_dev->set_address(cec_dev, cec_dev->addresses);
- + mutex_unlock(&cec_dev->mutex);
- + }
- + break;
- +
- + case HDMICEC_IOC_STOPDEVICE:
- + ret = 0;
- + break;
- +
- + case HDMICEC_IOC_GETPHYADDRESS:
- + ret = put_user(cec_dev->physical, (u16 __user *)arg);
- + ret = -ENOIOCTLCMD;
- + break;
- +
- + default:
- + ret = -ENOIOCTLCMD;
- + break;
- + }
- +
- + return ret;
- +}
- +
- +static unsigned cec_dev_poll(struct file *file, poll_table *wait)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- + unsigned mask = 0;
- +
- + poll_wait(file, &cec_dev->waitq, wait);
- +
- + if (cec_dev->write_busy == 0)
- + mask |= POLLOUT | POLLWRNORM;
- + if (!list_empty(&cec_dev->events))
- + mask |= POLLIN | POLLRDNORM;
- +
- + return mask;
- +}
- +
- +static int cec_dev_release(struct inode *inode, struct file *file)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- +
- + mutex_lock(&cec_dev->mutex);
- + if (cec_dev->users >= 1)
- + cec_dev->users -= 1;
- + if (cec_dev->users == 0) {
- + /*
- + * Wait for any write to complete before shutting down.
- + * A message should complete in a maximum of 2.75ms *
- + * 160 bits + 4.7ms, or 444.7ms. Let's call that 500ms.
- + * If we time out, shutdown anyway.
- + */
- + wait_event_timeout(cec_dev->waitq, !cec_dev->write_busy,
- + msecs_to_jiffies(500));
- +
- + cec_dev->release(cec_dev);
- +
- + while (!list_empty(&cec_dev->events)) {
- + struct cec_event *event;
- +
- + event = list_first_entry(&cec_dev->events,
- + struct cec_event, node);
- + list_del(&event->node);
- + kfree(event);
- + }
- + }
- + mutex_unlock(&cec_dev->mutex);
- + return 0;
- +}
- +
- +static int cec_dev_open(struct inode *inode, struct file *file)
- +{
- + struct cec_dev *cec_dev = container_of(inode->i_cdev, struct cec_dev,
- + cdev);
- + int ret = 0;
- +
- + nonseekable_open(inode, file);
- +
- + file->private_data = cec_dev;
- +
- + ret = mutex_lock_interruptible(&cec_dev->mutex);
- + if (ret)
- + return ret;
- +
- + if (cec_dev->users++ == 0) {
- + cec_dev->addresses = BIT(15);
- +
- + ret = cec_dev->open(cec_dev);
- + if (ret < 0)
- + cec_dev->users = 0;
- + }
- + mutex_unlock(&cec_dev->mutex);
- +
- + return ret;
- +}
- +
- +static const struct file_operations hdmi_cec_fops = {
- + .owner = THIS_MODULE,
- + .read = cec_dev_read,
- + .write = cec_dev_write,
- + .open = cec_dev_open,
- + .unlocked_ioctl = cec_dev_ioctl,
- + .release = cec_dev_release,
- + .poll = cec_dev_poll,
- +};
- +
- +void cec_dev_init(struct cec_dev *cec_dev, struct module *module)
- +{
- + cec_dev->devn = MKDEV(cec_major, 0);
- +
- + INIT_LIST_HEAD(&cec_dev->events);
- + init_waitqueue_head(&cec_dev->waitq);
- + spin_lock_init(&cec_dev->lock);
- + mutex_init(&cec_dev->mutex);
- +
- + cec_dev->addresses = BIT(15);
- +
- + cdev_init(&cec_dev->cdev, &hdmi_cec_fops);
- + cec_dev->cdev.owner = module;
- +}
- +EXPORT_SYMBOL_GPL(cec_dev_init);
- +
- +int cec_dev_add(struct cec_dev *cec_dev, struct device *dev, const char *name)
- +{
- + struct device *cd;
- + int ret;
- +
- + ret = cdev_add(&cec_dev->cdev, cec_dev->devn, 1);
- + if (ret < 0)
- + goto err_cdev;
- +
- + cd = device_create(cec_class, dev, cec_dev->devn, NULL, name);
- + if (IS_ERR(cd)) {
- + ret = PTR_ERR(cd);
- + dev_err(dev, "can't create device: %d\n", ret);
- + goto err_dev;
- + }
- +
- + return 0;
- +
- + err_dev:
- + cdev_del(&cec_dev->cdev);
- + err_cdev:
- + return ret;
- +}
- +EXPORT_SYMBOL_GPL(cec_dev_add);
- +
- +void cec_dev_remove(struct cec_dev *cec_dev)
- +{
- + device_destroy(cec_class, cec_dev->devn);
- + cdev_del(&cec_dev->cdev);
- +}
- +EXPORT_SYMBOL_GPL(cec_dev_remove);
- +
- +static int cec_init(void)
- +{
- + dev_t dev;
- + int ret;
- +
- + cec_class = class_create(THIS_MODULE, "hdmi-cec");
- + if (IS_ERR(cec_class)) {
- + ret = PTR_ERR(cec_class);
- + pr_err("cec: can't create cec class: %d\n", ret);
- + goto err_class;
- + }
- +
- + ret = alloc_chrdev_region(&dev, 0, 1, "hdmi-cec");
- + if (ret) {
- + pr_err("cec: can't create character devices: %d\n", ret);
- + goto err_chrdev;
- + }
- +
- + cec_major = MAJOR(dev);
- +
- + return 0;
- +
- + err_chrdev:
- + class_destroy(cec_class);
- + err_class:
- + return ret;
- +}
- +subsys_initcall(cec_init);
- +
- +static void cec_exit(void)
- +{
- + unregister_chrdev_region(MKDEV(cec_major, 0), 1);
- + class_destroy(cec_class);
- +}
- +module_exit(cec_exit);
- +
- +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
- +MODULE_DESCRIPTION("Generic HDMI CEC driver");
- +MODULE_LICENSE("GPL");
- diff -Nur linux-3.16.6.orig/drivers/cec/Kconfig linux-3.16.6/drivers/cec/Kconfig
- --- linux-3.16.6.orig/drivers/cec/Kconfig 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/cec/Kconfig 2014-10-23 12:37:18.350220009 -0500
- @@ -0,0 +1,14 @@
- +#
- +# Consumer Electroncs Control support
- +#
- +
- +menu "Consumer Electronics Control devices"
- +
- +config CEC
- + bool
- +
- +config HDMI_CEC_CORE
- + tristate
- + select CEC
- +
- +endmenu
- diff -Nur linux-3.16.6.orig/drivers/cec/Makefile linux-3.16.6/drivers/cec/Makefile
- --- linux-3.16.6.orig/drivers/cec/Makefile 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/cec/Makefile 2014-10-23 12:37:18.374219998 -0500
- @@ -0,0 +1 @@
- +obj-$(CONFIG_HDMI_CEC_CORE) += cec-dev.o
- diff -Nur linux-3.16.6.orig/drivers/dma/imx-sdma.c linux-3.16.6/drivers/dma/imx-sdma.c
- --- linux-3.16.6.orig/drivers/dma/imx-sdma.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/dma/imx-sdma.c 2014-10-23 12:35:52.990220019 -0500
- @@ -255,7 +255,6 @@
- enum dma_slave_buswidth word_size;
- unsigned int buf_tail;
- unsigned int num_bd;
- - unsigned int period_len;
- struct sdma_buffer_descriptor *bd;
- dma_addr_t bd_phys;
- unsigned int pc_from_device, pc_to_device;
- @@ -594,12 +593,6 @@
-
- static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
- {
- - if (sdmac->desc.callback)
- - sdmac->desc.callback(sdmac->desc.callback_param);
- -}
- -
- -static void sdma_update_channel_loop(struct sdma_channel *sdmac)
- -{
- struct sdma_buffer_descriptor *bd;
-
- /*
- @@ -618,6 +611,9 @@
- bd->mode.status |= BD_DONE;
- sdmac->buf_tail++;
- sdmac->buf_tail %= sdmac->num_bd;
- +
- + if (sdmac->desc.callback)
- + sdmac->desc.callback(sdmac->desc.callback_param);
- }
- }
-
- @@ -673,9 +669,6 @@
- int channel = fls(stat) - 1;
- struct sdma_channel *sdmac = &sdma->channel[channel];
-
- - if (sdmac->flags & IMX_DMA_SG_LOOP)
- - sdma_update_channel_loop(sdmac);
- -
- tasklet_schedule(&sdmac->tasklet);
-
- __clear_bit(channel, &stat);
- @@ -1136,7 +1129,6 @@
- sdmac->status = DMA_IN_PROGRESS;
-
- sdmac->buf_tail = 0;
- - sdmac->period_len = period_len;
-
- sdmac->flags |= IMX_DMA_SG_LOOP;
- sdmac->direction = direction;
- @@ -1233,15 +1225,9 @@
- struct dma_tx_state *txstate)
- {
- struct sdma_channel *sdmac = to_sdma_chan(chan);
- - u32 residue;
- -
- - if (sdmac->flags & IMX_DMA_SG_LOOP)
- - residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len;
- - else
- - residue = sdmac->chn_count - sdmac->chn_real_count;
-
- dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
- - residue);
- + sdmac->chn_count - sdmac->chn_real_count);
-
- return sdmac->status;
- }
- diff -Nur linux-3.16.6.orig/drivers/dma/imx-sdma.c.orig linux-3.16.6/drivers/dma/imx-sdma.c.orig
- --- linux-3.16.6.orig/drivers/dma/imx-sdma.c.orig 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/dma/imx-sdma.c.orig 2014-10-15 05:05:43.000000000 -0500
- @@ -0,0 +1,1656 @@
- +/*
- + * drivers/dma/imx-sdma.c
- + *
- + * This file contains a driver for the Freescale Smart DMA engine
- + *
- + * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- + *
- + * Based on code from Freescale:
- + *
- + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- + *
- + * The code contained herein is licensed under the GNU General Public
- + * License. You may obtain a copy of the GNU General Public License
- + * Version 2 or later at the following locations:
- + *
- + * http://www.opensource.org/licenses/gpl-license.html
- + * http://www.gnu.org/copyleft/gpl.html
- + */
- +
- +#include <linux/init.h>
- +#include <linux/module.h>
- +#include <linux/types.h>
- +#include <linux/bitops.h>
- +#include <linux/mm.h>
- +#include <linux/interrupt.h>
- +#include <linux/clk.h>
- +#include <linux/delay.h>
- +#include <linux/sched.h>
- +#include <linux/semaphore.h>
- +#include <linux/spinlock.h>
- +#include <linux/device.h>
- +#include <linux/dma-mapping.h>
- +#include <linux/firmware.h>
- +#include <linux/slab.h>
- +#include <linux/platform_device.h>
- +#include <linux/dmaengine.h>
- +#include <linux/of.h>
- +#include <linux/of_device.h>
- +#include <linux/of_dma.h>
- +
- +#include <asm/irq.h>
- +#include <linux/platform_data/dma-imx-sdma.h>
- +#include <linux/platform_data/dma-imx.h>
- +
- +#include "dmaengine.h"
- +
- +/* SDMA registers */
- +#define SDMA_H_C0PTR 0x000
- +#define SDMA_H_INTR 0x004
- +#define SDMA_H_STATSTOP 0x008
- +#define SDMA_H_START 0x00c
- +#define SDMA_H_EVTOVR 0x010
- +#define SDMA_H_DSPOVR 0x014
- +#define SDMA_H_HOSTOVR 0x018
- +#define SDMA_H_EVTPEND 0x01c
- +#define SDMA_H_DSPENBL 0x020
- +#define SDMA_H_RESET 0x024
- +#define SDMA_H_EVTERR 0x028
- +#define SDMA_H_INTRMSK 0x02c
- +#define SDMA_H_PSW 0x030
- +#define SDMA_H_EVTERRDBG 0x034
- +#define SDMA_H_CONFIG 0x038
- +#define SDMA_ONCE_ENB 0x040
- +#define SDMA_ONCE_DATA 0x044
- +#define SDMA_ONCE_INSTR 0x048
- +#define SDMA_ONCE_STAT 0x04c
- +#define SDMA_ONCE_CMD 0x050
- +#define SDMA_EVT_MIRROR 0x054
- +#define SDMA_ILLINSTADDR 0x058
- +#define SDMA_CHN0ADDR 0x05c
- +#define SDMA_ONCE_RTB 0x060
- +#define SDMA_XTRIG_CONF1 0x070
- +#define SDMA_XTRIG_CONF2 0x074
- +#define SDMA_CHNENBL0_IMX35 0x200
- +#define SDMA_CHNENBL0_IMX31 0x080
- +#define SDMA_CHNPRI_0 0x100
- +
- +/*
- + * Buffer descriptor status values.
- + */
- +#define BD_DONE 0x01
- +#define BD_WRAP 0x02
- +#define BD_CONT 0x04
- +#define BD_INTR 0x08
- +#define BD_RROR 0x10
- +#define BD_LAST 0x20
- +#define BD_EXTD 0x80
- +
- +/*
- + * Data Node descriptor status values.
- + */
- +#define DND_END_OF_FRAME 0x80
- +#define DND_END_OF_XFER 0x40
- +#define DND_DONE 0x20
- +#define DND_UNUSED 0x01
- +
- +/*
- + * IPCV2 descriptor status values.
- + */
- +#define BD_IPCV2_END_OF_FRAME 0x40
- +
- +#define IPCV2_MAX_NODES 50
- +/*
- + * Error bit set in the CCB status field by the SDMA,
- + * in setbd routine, in case of a transfer error
- + */
- +#define DATA_ERROR 0x10000000
- +
- +/*
- + * Buffer descriptor commands.
- + */
- +#define C0_ADDR 0x01
- +#define C0_LOAD 0x02
- +#define C0_DUMP 0x03
- +#define C0_SETCTX 0x07
- +#define C0_GETCTX 0x03
- +#define C0_SETDM 0x01
- +#define C0_SETPM 0x04
- +#define C0_GETDM 0x02
- +#define C0_GETPM 0x08
- +/*
- + * Change endianness indicator in the BD command field
- + */
- +#define CHANGE_ENDIANNESS 0x80
- +
- +/*
- + * Mode/Count of data node descriptors - IPCv2
- + */
- +struct sdma_mode_count {
- + u32 count : 16; /* size of the buffer pointed by this BD */
- + u32 status : 8; /* E,R,I,C,W,D status bits stored here */
- + u32 command : 8; /* command mostlky used for channel 0 */
- +};
- +
- +/*
- + * Buffer descriptor
- + */
- +struct sdma_buffer_descriptor {
- + struct sdma_mode_count mode;
- + u32 buffer_addr; /* address of the buffer described */
- + u32 ext_buffer_addr; /* extended buffer address */
- +} __attribute__ ((packed));
- +
- +/**
- + * struct sdma_channel_control - Channel control Block
- + *
- + * @current_bd_ptr current buffer descriptor processed
- + * @base_bd_ptr first element of buffer descriptor array
- + * @unused padding. The SDMA engine expects an array of 128 byte
- + * control blocks
- + */
- +struct sdma_channel_control {
- + u32 current_bd_ptr;
- + u32 base_bd_ptr;
- + u32 unused[2];
- +} __attribute__ ((packed));
- +
- +/**
- + * struct sdma_state_registers - SDMA context for a channel
- + *
- + * @pc: program counter
- + * @t: test bit: status of arithmetic & test instruction
- + * @rpc: return program counter
- + * @sf: source fault while loading data
- + * @spc: loop start program counter
- + * @df: destination fault while storing data
- + * @epc: loop end program counter
- + * @lm: loop mode
- + */
- +struct sdma_state_registers {
- + u32 pc :14;
- + u32 unused1: 1;
- + u32 t : 1;
- + u32 rpc :14;
- + u32 unused0: 1;
- + u32 sf : 1;
- + u32 spc :14;
- + u32 unused2: 1;
- + u32 df : 1;
- + u32 epc :14;
- + u32 lm : 2;
- +} __attribute__ ((packed));
- +
- +/**
- + * struct sdma_context_data - sdma context specific to a channel
- + *
- + * @channel_state: channel state bits
- + * @gReg: general registers
- + * @mda: burst dma destination address register
- + * @msa: burst dma source address register
- + * @ms: burst dma status register
- + * @md: burst dma data register
- + * @pda: peripheral dma destination address register
- + * @psa: peripheral dma source address register
- + * @ps: peripheral dma status register
- + * @pd: peripheral dma data register
- + * @ca: CRC polynomial register
- + * @cs: CRC accumulator register
- + * @dda: dedicated core destination address register
- + * @dsa: dedicated core source address register
- + * @ds: dedicated core status register
- + * @dd: dedicated core data register
- + */
- +struct sdma_context_data {
- + struct sdma_state_registers channel_state;
- + u32 gReg[8];
- + u32 mda;
- + u32 msa;
- + u32 ms;
- + u32 md;
- + u32 pda;
- + u32 psa;
- + u32 ps;
- + u32 pd;
- + u32 ca;
- + u32 cs;
- + u32 dda;
- + u32 dsa;
- + u32 ds;
- + u32 dd;
- + u32 scratch0;
- + u32 scratch1;
- + u32 scratch2;
- + u32 scratch3;
- + u32 scratch4;
- + u32 scratch5;
- + u32 scratch6;
- + u32 scratch7;
- +} __attribute__ ((packed));
- +
- +#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor))
- +
- +struct sdma_engine;
- +
- +/**
- + * struct sdma_channel - housekeeping for a SDMA channel
- + *
- + * @sdma pointer to the SDMA engine for this channel
- + * @channel the channel number, matches dmaengine chan_id + 1
- + * @direction transfer type. Needed for setting SDMA script
- + * @peripheral_type Peripheral type. Needed for setting SDMA script
- + * @event_id0 aka dma request line
- + * @event_id1 for channels that use 2 events
- + * @word_size peripheral access size
- + * @buf_tail ID of the buffer that was processed
- + * @num_bd max NUM_BD. number of descriptors currently handling
- + */
- +struct sdma_channel {
- + struct sdma_engine *sdma;
- + unsigned int channel;
- + enum dma_transfer_direction direction;
- + enum sdma_peripheral_type peripheral_type;
- + unsigned int event_id0;
- + unsigned int event_id1;
- + enum dma_slave_buswidth word_size;
- + unsigned int buf_tail;
- + unsigned int num_bd;
- + unsigned int period_len;
- + struct sdma_buffer_descriptor *bd;
- + dma_addr_t bd_phys;
- + unsigned int pc_from_device, pc_to_device;
- + unsigned long flags;
- + dma_addr_t per_address;
- + unsigned long event_mask[2];
- + unsigned long watermark_level;
- + u32 shp_addr, per_addr;
- + struct dma_chan chan;
- + spinlock_t lock;
- + struct dma_async_tx_descriptor desc;
- + enum dma_status status;
- + unsigned int chn_count;
- + unsigned int chn_real_count;
- + struct tasklet_struct tasklet;
- +};
- +
- +#define IMX_DMA_SG_LOOP BIT(0)
- +
- +#define MAX_DMA_CHANNELS 32
- +#define MXC_SDMA_DEFAULT_PRIORITY 1
- +#define MXC_SDMA_MIN_PRIORITY 1
- +#define MXC_SDMA_MAX_PRIORITY 7
- +
- +#define SDMA_FIRMWARE_MAGIC 0x414d4453
- +
- +/**
- + * struct sdma_firmware_header - Layout of the firmware image
- + *
- + * @magic "SDMA"
- + * @version_major increased whenever layout of struct sdma_script_start_addrs
- + * changes.
- + * @version_minor firmware minor version (for binary compatible changes)
- + * @script_addrs_start offset of struct sdma_script_start_addrs in this image
- + * @num_script_addrs Number of script addresses in this image
- + * @ram_code_start offset of SDMA ram image in this firmware image
- + * @ram_code_size size of SDMA ram image
- + * @script_addrs Stores the start address of the SDMA scripts
- + * (in SDMA memory space)
- + */
- +struct sdma_firmware_header {
- + u32 magic;
- + u32 version_major;
- + u32 version_minor;
- + u32 script_addrs_start;
- + u32 num_script_addrs;
- + u32 ram_code_start;
- + u32 ram_code_size;
- +};
- +
- +struct sdma_driver_data {
- + int chnenbl0;
- + int num_events;
- + struct sdma_script_start_addrs *script_addrs;
- +};
- +
- +struct sdma_engine {
- + struct device *dev;
- + struct device_dma_parameters dma_parms;
- + struct sdma_channel channel[MAX_DMA_CHANNELS];
- + struct sdma_channel_control *channel_control;
- + void __iomem *regs;
- + struct sdma_context_data *context;
- + dma_addr_t context_phys;
- + struct dma_device dma_device;
- + struct clk *clk_ipg;
- + struct clk *clk_ahb;
- + spinlock_t channel_0_lock;
- + u32 script_number;
- + struct sdma_script_start_addrs *script_addrs;
- + const struct sdma_driver_data *drvdata;
- +};
- +
- +static struct sdma_driver_data sdma_imx31 = {
- + .chnenbl0 = SDMA_CHNENBL0_IMX31,
- + .num_events = 32,
- +};
- +
- +static struct sdma_script_start_addrs sdma_script_imx25 = {
- + .ap_2_ap_addr = 729,
- + .uart_2_mcu_addr = 904,
- + .per_2_app_addr = 1255,
- + .mcu_2_app_addr = 834,
- + .uartsh_2_mcu_addr = 1120,
- + .per_2_shp_addr = 1329,
- + .mcu_2_shp_addr = 1048,
- + .ata_2_mcu_addr = 1560,
- + .mcu_2_ata_addr = 1479,
- + .app_2_per_addr = 1189,
- + .app_2_mcu_addr = 770,
- + .shp_2_per_addr = 1407,
- + .shp_2_mcu_addr = 979,
- +};
- +
- +static struct sdma_driver_data sdma_imx25 = {
- + .chnenbl0 = SDMA_CHNENBL0_IMX35,
- + .num_events = 48,
- + .script_addrs = &sdma_script_imx25,
- +};
- +
- +static struct sdma_driver_data sdma_imx35 = {
- + .chnenbl0 = SDMA_CHNENBL0_IMX35,
- + .num_events = 48,
- +};
- +
- +static struct sdma_script_start_addrs sdma_script_imx51 = {
- + .ap_2_ap_addr = 642,
- + .uart_2_mcu_addr = 817,
- + .mcu_2_app_addr = 747,
- + .mcu_2_shp_addr = 961,
- + .ata_2_mcu_addr = 1473,
- + .mcu_2_ata_addr = 1392,
- + .app_2_per_addr = 1033,
- + .app_2_mcu_addr = 683,
- + .shp_2_per_addr = 1251,
- + .shp_2_mcu_addr = 892,
- +};
- +
- +static struct sdma_driver_data sdma_imx51 = {
- + .chnenbl0 = SDMA_CHNENBL0_IMX35,
- + .num_events = 48,
- + .script_addrs = &sdma_script_imx51,
- +};
- +
- +static struct sdma_script_start_addrs sdma_script_imx53 = {
- + .ap_2_ap_addr = 642,
- + .app_2_mcu_addr = 683,
- + .mcu_2_app_addr = 747,
- + .uart_2_mcu_addr = 817,
- + .shp_2_mcu_addr = 891,
- + .mcu_2_shp_addr = 960,
- + .uartsh_2_mcu_addr = 1032,
- + .spdif_2_mcu_addr = 1100,
- + .mcu_2_spdif_addr = 1134,
- + .firi_2_mcu_addr = 1193,
- + .mcu_2_firi_addr = 1290,
- +};
- +
- +static struct sdma_driver_data sdma_imx53 = {
- + .chnenbl0 = SDMA_CHNENBL0_IMX35,
- + .num_events = 48,
- + .script_addrs = &sdma_script_imx53,
- +};
- +
- +static struct sdma_script_start_addrs sdma_script_imx6q = {
- + .ap_2_ap_addr = 642,
- + .uart_2_mcu_addr = 817,
- + .mcu_2_app_addr = 747,
- + .per_2_per_addr = 6331,
- + .uartsh_2_mcu_addr = 1032,
- + .mcu_2_shp_addr = 960,
- + .app_2_mcu_addr = 683,
- + .shp_2_mcu_addr = 891,
- + .spdif_2_mcu_addr = 1100,
- + .mcu_2_spdif_addr = 1134,
- +};
- +
- +static struct sdma_driver_data sdma_imx6q = {
- + .chnenbl0 = SDMA_CHNENBL0_IMX35,
- + .num_events = 48,
- + .script_addrs = &sdma_script_imx6q,
- +};
- +
- +static struct platform_device_id sdma_devtypes[] = {
- + {
- + .name = "imx25-sdma",
- + .driver_data = (unsigned long)&sdma_imx25,
- + }, {
- + .name = "imx31-sdma",
- + .driver_data = (unsigned long)&sdma_imx31,
- + }, {
- + .name = "imx35-sdma",
- + .driver_data = (unsigned long)&sdma_imx35,
- + }, {
- + .name = "imx51-sdma",
- + .driver_data = (unsigned long)&sdma_imx51,
- + }, {
- + .name = "imx53-sdma",
- + .driver_data = (unsigned long)&sdma_imx53,
- + }, {
- + .name = "imx6q-sdma",
- + .driver_data = (unsigned long)&sdma_imx6q,
- + }, {
- + /* sentinel */
- + }
- +};
- +MODULE_DEVICE_TABLE(platform, sdma_devtypes);
- +
- +static const struct of_device_id sdma_dt_ids[] = {
- + { .compatible = "fsl,imx6q-sdma", .data = &sdma_imx6q, },
- + { .compatible = "fsl,imx53-sdma", .data = &sdma_imx53, },
- + { .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, },
- + { .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
- + { .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
- + { .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
- + { /* sentinel */ }
- +};
- +MODULE_DEVICE_TABLE(of, sdma_dt_ids);
- +
- +#define SDMA_H_CONFIG_DSPDMA BIT(12) /* indicates if the DSPDMA is used */
- +#define SDMA_H_CONFIG_RTD_PINS BIT(11) /* indicates if Real-Time Debug pins are enabled */
- +#define SDMA_H_CONFIG_ACR BIT(4) /* indicates if AHB freq /core freq = 2 or 1 */
- +#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/
- +
- +static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
- +{
- + u32 chnenbl0 = sdma->drvdata->chnenbl0;
- + return chnenbl0 + event * 4;
- +}
- +
- +static int sdma_config_ownership(struct sdma_channel *sdmac,
- + bool event_override, bool mcu_override, bool dsp_override)
- +{
- + struct sdma_engine *sdma = sdmac->sdma;
- + int channel = sdmac->channel;
- + unsigned long evt, mcu, dsp;
- +
- + if (event_override && mcu_override && dsp_override)
- + return -EINVAL;
- +
- + evt = readl_relaxed(sdma->regs + SDMA_H_EVTOVR);
- + mcu = readl_relaxed(sdma->regs + SDMA_H_HOSTOVR);
- + dsp = readl_relaxed(sdma->regs + SDMA_H_DSPOVR);
- +
- + if (dsp_override)
- + __clear_bit(channel, &dsp);
- + else
- + __set_bit(channel, &dsp);
- +
- + if (event_override)
- + __clear_bit(channel, &evt);
- + else
- + __set_bit(channel, &evt);
- +
- + if (mcu_override)
- + __clear_bit(channel, &mcu);
- + else
- + __set_bit(channel, &mcu);
- +
- + writel_relaxed(evt, sdma->regs + SDMA_H_EVTOVR);
- + writel_relaxed(mcu, sdma->regs + SDMA_H_HOSTOVR);
- + writel_relaxed(dsp, sdma->regs + SDMA_H_DSPOVR);
- +
- + return 0;
- +}
- +
- +static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
- +{
- + writel(BIT(channel), sdma->regs + SDMA_H_START);
- +}
- +
- +/*
- + * sdma_run_channel0 - run a channel and wait till it's done
- + */
- +static int sdma_run_channel0(struct sdma_engine *sdma)
- +{
- + int ret;
- + unsigned long timeout = 500;
- +
- + sdma_enable_channel(sdma, 0);
- +
- + while (!(ret = readl_relaxed(sdma->regs + SDMA_H_INTR) & 1)) {
- + if (timeout-- <= 0)
- + break;
- + udelay(1);
- + }
- +
- + if (ret) {
- + /* Clear the interrupt status */
- + writel_relaxed(ret, sdma->regs + SDMA_H_INTR);
- + } else {
- + dev_err(sdma->dev, "Timeout waiting for CH0 ready\n");
- + }
- +
- + return ret ? 0 : -ETIMEDOUT;
- +}
- +
- +static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
- + u32 address)
- +{
- + struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
- + void *buf_virt;
- + dma_addr_t buf_phys;
- + int ret;
- + unsigned long flags;
- +
- + buf_virt = dma_alloc_coherent(NULL,
- + size,
- + &buf_phys, GFP_KERNEL);
- + if (!buf_virt) {
- + return -ENOMEM;
- + }
- +
- + spin_lock_irqsave(&sdma->channel_0_lock, flags);
- +
- + bd0->mode.command = C0_SETPM;
- + bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
- + bd0->mode.count = size / 2;
- + bd0->buffer_addr = buf_phys;
- + bd0->ext_buffer_addr = address;
- +
- + memcpy(buf_virt, buf, size);
- +
- + ret = sdma_run_channel0(sdma);
- +
- + spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
- +
- + dma_free_coherent(NULL, size, buf_virt, buf_phys);
- +
- + return ret;
- +}
- +
- +static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
- +{
- + struct sdma_engine *sdma = sdmac->sdma;
- + int channel = sdmac->channel;
- + unsigned long val;
- + u32 chnenbl = chnenbl_ofs(sdma, event);
- +
- + val = readl_relaxed(sdma->regs + chnenbl);
- + __set_bit(channel, &val);
- + writel_relaxed(val, sdma->regs + chnenbl);
- +}
- +
- +static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
- +{
- + struct sdma_engine *sdma = sdmac->sdma;
- + int channel = sdmac->channel;
- + u32 chnenbl = chnenbl_ofs(sdma, event);
- + unsigned long val;
- +
- + val = readl_relaxed(sdma->regs + chnenbl);
- + __clear_bit(channel, &val);
- + writel_relaxed(val, sdma->regs + chnenbl);
- +}
- +
- +static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
- +{
- + if (sdmac->desc.callback)
- + sdmac->desc.callback(sdmac->desc.callback_param);
- +}
- +
- +static void sdma_update_channel_loop(struct sdma_channel *sdmac)
- +{
- + struct sdma_buffer_descriptor *bd;
- +
- + /*
- + * loop mode. Iterate over descriptors, re-setup them and
- + * call callback function.
- + */
- + while (1) {
- + bd = &sdmac->bd[sdmac->buf_tail];
- +
- + if (bd->mode.status & BD_DONE)
- + break;
- +
- + if (bd->mode.status & BD_RROR)
- + sdmac->status = DMA_ERROR;
- +
- + bd->mode.status |= BD_DONE;
- + sdmac->buf_tail++;
- + sdmac->buf_tail %= sdmac->num_bd;
- + }
- +}
- +
- +static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
- +{
- + struct sdma_buffer_descriptor *bd;
- + int i, error = 0;
- +
- + sdmac->chn_real_count = 0;
- + /*
- + * non loop mode. Iterate over all descriptors, collect
- + * errors and call callback function
- + */
- + for (i = 0; i < sdmac->num_bd; i++) {
- + bd = &sdmac->bd[i];
- +
- + if (bd->mode.status & (BD_DONE | BD_RROR))
- + error = -EIO;
- + sdmac->chn_real_count += bd->mode.count;
- + }
- +
- + if (error)
- + sdmac->status = DMA_ERROR;
- + else
- + sdmac->status = DMA_COMPLETE;
- +
- + dma_cookie_complete(&sdmac->desc);
- + if (sdmac->desc.callback)
- + sdmac->desc.callback(sdmac->desc.callback_param);
- +}
- +
- +static void sdma_tasklet(unsigned long data)
- +{
- + struct sdma_channel *sdmac = (struct sdma_channel *) data;
- +
- + if (sdmac->flags & IMX_DMA_SG_LOOP)
- + sdma_handle_channel_loop(sdmac);
- + else
- + mxc_sdma_handle_channel_normal(sdmac);
- +}
- +
- +static irqreturn_t sdma_int_handler(int irq, void *dev_id)
- +{
- + struct sdma_engine *sdma = dev_id;
- + unsigned long stat;
- +
- + stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
- + /* not interested in channel 0 interrupts */
- + stat &= ~1;
- + writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
- +
- + while (stat) {
- + int channel = fls(stat) - 1;
- + struct sdma_channel *sdmac = &sdma->channel[channel];
- +
- + if (sdmac->flags & IMX_DMA_SG_LOOP)
- + sdma_update_channel_loop(sdmac);
- +
- + tasklet_schedule(&sdmac->tasklet);
- +
- + __clear_bit(channel, &stat);
- + }
- +
- + return IRQ_HANDLED;
- +}
- +
- +/*
- + * sets the pc of SDMA script according to the peripheral type
- + */
- +static void sdma_get_pc(struct sdma_channel *sdmac,
- + enum sdma_peripheral_type peripheral_type)
- +{
- + struct sdma_engine *sdma = sdmac->sdma;
- + int per_2_emi = 0, emi_2_per = 0;
- + /*
- + * These are needed once we start to support transfers between
- + * two peripherals or memory-to-memory transfers
- + */
- + int per_2_per = 0, emi_2_emi = 0;
- +
- + sdmac->pc_from_device = 0;
- + sdmac->pc_to_device = 0;
- +
- + switch (peripheral_type) {
- + case IMX_DMATYPE_MEMORY:
- + emi_2_emi = sdma->script_addrs->ap_2_ap_addr;
- + break;
- + case IMX_DMATYPE_DSP:
- + emi_2_per = sdma->script_addrs->bp_2_ap_addr;
- + per_2_emi = sdma->script_addrs->ap_2_bp_addr;
- + break;
- + case IMX_DMATYPE_FIRI:
- + per_2_emi = sdma->script_addrs->firi_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_firi_addr;
- + break;
- + case IMX_DMATYPE_UART:
- + per_2_emi = sdma->script_addrs->uart_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_app_addr;
- + break;
- + case IMX_DMATYPE_UART_SP:
- + per_2_emi = sdma->script_addrs->uartsh_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
- + break;
- + case IMX_DMATYPE_ATA:
- + per_2_emi = sdma->script_addrs->ata_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_ata_addr;
- + break;
- + case IMX_DMATYPE_CSPI:
- + case IMX_DMATYPE_EXT:
- + case IMX_DMATYPE_SSI:
- + per_2_emi = sdma->script_addrs->app_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_app_addr;
- + break;
- + case IMX_DMATYPE_SSI_DUAL:
- + per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
- + break;
- + case IMX_DMATYPE_SSI_SP:
- + case IMX_DMATYPE_MMC:
- + case IMX_DMATYPE_SDHC:
- + case IMX_DMATYPE_CSPI_SP:
- + case IMX_DMATYPE_ESAI:
- + case IMX_DMATYPE_MSHC_SP:
- + per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
- + break;
- + case IMX_DMATYPE_ASRC:
- + per_2_emi = sdma->script_addrs->asrc_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->asrc_2_mcu_addr;
- + per_2_per = sdma->script_addrs->per_2_per_addr;
- + break;
- + case IMX_DMATYPE_MSHC:
- + per_2_emi = sdma->script_addrs->mshc_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_mshc_addr;
- + break;
- + case IMX_DMATYPE_CCM:
- + per_2_emi = sdma->script_addrs->dptc_dvfs_addr;
- + break;
- + case IMX_DMATYPE_SPDIF:
- + per_2_emi = sdma->script_addrs->spdif_2_mcu_addr;
- + emi_2_per = sdma->script_addrs->mcu_2_spdif_addr;
- + break;
- + case IMX_DMATYPE_IPU_MEMORY:
- + emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr;
- + break;
- + default:
- + break;
- + }
- +
- + sdmac->pc_from_device = per_2_emi;
- + sdmac->pc_to_device = emi_2_per;
- +}
- +
- +static int sdma_load_context(struct sdma_channel *sdmac)
- +{
- + struct sdma_engine *sdma = sdmac->sdma;
- + int channel = sdmac->channel;
- + int load_address;
- + struct sdma_context_data *context = sdma->context;
- + struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
- + int ret;
- + unsigned long flags;
- +
- + if (sdmac->direction == DMA_DEV_TO_MEM) {
- + load_address = sdmac->pc_from_device;
- + } else {
- + load_address = sdmac->pc_to_device;
- + }
- +
- + if (load_address < 0)
- + return load_address;
- +
- + dev_dbg(sdma->dev, "load_address = %d\n", load_address);
- + dev_dbg(sdma->dev, "wml = 0x%08x\n", (u32)sdmac->watermark_level);
- + dev_dbg(sdma->dev, "shp_addr = 0x%08x\n", sdmac->shp_addr);
- + dev_dbg(sdma->dev, "per_addr = 0x%08x\n", sdmac->per_addr);
- + dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", (u32)sdmac->event_mask[0]);
- + dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", (u32)sdmac->event_mask[1]);
- +
- + spin_lock_irqsave(&sdma->channel_0_lock, flags);
- +
- + memset(context, 0, sizeof(*context));
- + context->channel_state.pc = load_address;
- +
- + /* Send by context the event mask,base address for peripheral
- + * and watermark level
- + */
- + context->gReg[0] = sdmac->event_mask[1];
- + context->gReg[1] = sdmac->event_mask[0];
- + context->gReg[2] = sdmac->per_addr;
- + context->gReg[6] = sdmac->shp_addr;
- + context->gReg[7] = sdmac->watermark_level;
- +
- + bd0->mode.command = C0_SETDM;
- + bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
- + bd0->mode.count = sizeof(*context) / 4;
- + bd0->buffer_addr = sdma->context_phys;
- + bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
- + ret = sdma_run_channel0(sdma);
- +
- + spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
- +
- + return ret;
- +}
- +
- +static void sdma_disable_channel(struct sdma_channel *sdmac)
- +{
- + struct sdma_engine *sdma = sdmac->sdma;
- + int channel = sdmac->channel;
- +
- + writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
- + sdmac->status = DMA_ERROR;
- +}
- +
- +static int sdma_config_channel(struct sdma_channel *sdmac)
- +{
- + int ret;
- +
- + sdma_disable_channel(sdmac);
- +
- + sdmac->event_mask[0] = 0;
- + sdmac->event_mask[1] = 0;
- + sdmac->shp_addr = 0;
- + sdmac->per_addr = 0;
- +
- + if (sdmac->event_id0) {
- + if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
- + return -EINVAL;
- + sdma_event_enable(sdmac, sdmac->event_id0);
- + }
- +
- + switch (sdmac->peripheral_type) {
- + case IMX_DMATYPE_DSP:
- + sdma_config_ownership(sdmac, false, true, true);
- + break;
- + case IMX_DMATYPE_MEMORY:
- + sdma_config_ownership(sdmac, false, true, false);
- + break;
- + default:
- + sdma_config_ownership(sdmac, true, true, false);
- + break;
- + }
- +
- + sdma_get_pc(sdmac, sdmac->peripheral_type);
- +
- + if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) &&
- + (sdmac->peripheral_type != IMX_DMATYPE_DSP)) {
- + /* Handle multiple event channels differently */
- + if (sdmac->event_id1) {
- + sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32);
- + if (sdmac->event_id1 > 31)
- + __set_bit(31, &sdmac->watermark_level);
- + sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32);
- + if (sdmac->event_id0 > 31)
- + __set_bit(30, &sdmac->watermark_level);
- + } else {
- + __set_bit(sdmac->event_id0, sdmac->event_mask);
- + }
- + /* Watermark Level */
- + sdmac->watermark_level |= sdmac->watermark_level;
- + /* Address */
- + sdmac->shp_addr = sdmac->per_address;
- + } else {
- + sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
- + }
- +
- + ret = sdma_load_context(sdmac);
- +
- + return ret;
- +}
- +
- +static int sdma_set_channel_priority(struct sdma_channel *sdmac,
- + unsigned int priority)
- +{
- + struct sdma_engine *sdma = sdmac->sdma;
- + int channel = sdmac->channel;
- +
- + if (priority < MXC_SDMA_MIN_PRIORITY
- + || priority > MXC_SDMA_MAX_PRIORITY) {
- + return -EINVAL;
- + }
- +
- + writel_relaxed(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
- +
- + return 0;
- +}
- +
- +static int sdma_request_channel(struct sdma_channel *sdmac)
- +{
- + struct sdma_engine *sdma = sdmac->sdma;
- + int channel = sdmac->channel;
- + int ret = -EBUSY;
- +
- + sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL);
- + if (!sdmac->bd) {
- + ret = -ENOMEM;
- + goto out;
- + }
- +
- + memset(sdmac->bd, 0, PAGE_SIZE);
- +
- + sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
- + sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
- +
- + sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
- + return 0;
- +out:
- +
- + return ret;
- +}
- +
- +static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
- +{
- + return container_of(chan, struct sdma_channel, chan);
- +}
- +
- +static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
- +{
- + unsigned long flags;
- + struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
- + dma_cookie_t cookie;
- +
- + spin_lock_irqsave(&sdmac->lock, flags);
- +
- + cookie = dma_cookie_assign(tx);
- +
- + spin_unlock_irqrestore(&sdmac->lock, flags);
- +
- + return cookie;
- +}
- +
- +static int sdma_alloc_chan_resources(struct dma_chan *chan)
- +{
- + struct sdma_channel *sdmac = to_sdma_chan(chan);
- + struct imx_dma_data *data = chan->private;
- + int prio, ret;
- +
- + if (!data)
- + return -EINVAL;
- +
- + switch (data->priority) {
- + case DMA_PRIO_HIGH:
- + prio = 3;
- + break;
- + case DMA_PRIO_MEDIUM:
- + prio = 2;
- + break;
- + case DMA_PRIO_LOW:
- + default:
- + prio = 1;
- + break;
- + }
- +
- + sdmac->peripheral_type = data->peripheral_type;
- + sdmac->event_id0 = data->dma_request;
- +
- + clk_enable(sdmac->sdma->clk_ipg);
- + clk_enable(sdmac->sdma->clk_ahb);
- +
- + ret = sdma_request_channel(sdmac);
- + if (ret)
- + return ret;
- +
- + ret = sdma_set_channel_priority(sdmac, prio);
- + if (ret)
- + return ret;
- +
- + dma_async_tx_descriptor_init(&sdmac->desc, chan);
- + sdmac->desc.tx_submit = sdma_tx_submit;
- + /* txd.flags will be overwritten in prep funcs */
- + sdmac->desc.flags = DMA_CTRL_ACK;
- +
- + return 0;
- +}
- +
- +static void sdma_free_chan_resources(struct dma_chan *chan)
- +{
- + struct sdma_channel *sdmac = to_sdma_chan(chan);
- + struct sdma_engine *sdma = sdmac->sdma;
- +
- + sdma_disable_channel(sdmac);
- +
- + if (sdmac->event_id0)
- + sdma_event_disable(sdmac, sdmac->event_id0);
- + if (sdmac->event_id1)
- + sdma_event_disable(sdmac, sdmac->event_id1);
- +
- + sdmac->event_id0 = 0;
- + sdmac->event_id1 = 0;
- +
- + sdma_set_channel_priority(sdmac, 0);
- +
- + dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
- +
- + clk_disable(sdma->clk_ipg);
- + clk_disable(sdma->clk_ahb);
- +}
- +
- +static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
- + struct dma_chan *chan, struct scatterlist *sgl,
- + unsigned int sg_len, enum dma_transfer_direction direction,
- + unsigned long flags, void *context)
- +{
- + struct sdma_channel *sdmac = to_sdma_chan(chan);
- + struct sdma_engine *sdma = sdmac->sdma;
- + int ret, i, count;
- + int channel = sdmac->channel;
- + struct scatterlist *sg;
- +
- + if (sdmac->status == DMA_IN_PROGRESS)
- + return NULL;
- + sdmac->status = DMA_IN_PROGRESS;
- +
- + sdmac->flags = 0;
- +
- + sdmac->buf_tail = 0;
- +
- + dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
- + sg_len, channel);
- +
- + sdmac->direction = direction;
- + ret = sdma_load_context(sdmac);
- + if (ret)
- + goto err_out;
- +
- + if (sg_len > NUM_BD) {
- + dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
- + channel, sg_len, NUM_BD);
- + ret = -EINVAL;
- + goto err_out;
- + }
- +
- + sdmac->chn_count = 0;
- + for_each_sg(sgl, sg, sg_len, i) {
- + struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
- + int param;
- +
- + bd->buffer_addr = sg->dma_address;
- +
- + count = sg_dma_len(sg);
- +
- + if (count > 0xffff) {
- + dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
- + channel, count, 0xffff);
- + ret = -EINVAL;
- + goto err_out;
- + }
- +
- + bd->mode.count = count;
- + sdmac->chn_count += count;
- +
- + if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
- + ret = -EINVAL;
- + goto err_out;
- + }
- +
- + switch (sdmac->word_size) {
- + case DMA_SLAVE_BUSWIDTH_4_BYTES:
- + bd->mode.command = 0;
- + if (count & 3 || sg->dma_address & 3)
- + return NULL;
- + break;
- + case DMA_SLAVE_BUSWIDTH_2_BYTES:
- + bd->mode.command = 2;
- + if (count & 1 || sg->dma_address & 1)
- + return NULL;
- + break;
- + case DMA_SLAVE_BUSWIDTH_1_BYTE:
- + bd->mode.command = 1;
- + break;
- + default:
- + return NULL;
- + }
- +
- + param = BD_DONE | BD_EXTD | BD_CONT;
- +
- + if (i + 1 == sg_len) {
- + param |= BD_INTR;
- + param |= BD_LAST;
- + param &= ~BD_CONT;
- + }
- +
- + dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n",
- + i, count, (u64)sg->dma_address,
- + param & BD_WRAP ? "wrap" : "",
- + param & BD_INTR ? " intr" : "");
- +
- + bd->mode.status = param;
- + }
- +
- + sdmac->num_bd = sg_len;
- + sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
- +
- + return &sdmac->desc;
- +err_out:
- + sdmac->status = DMA_ERROR;
- + return NULL;
- +}
- +
- +static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
- + struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
- + size_t period_len, enum dma_transfer_direction direction,
- + unsigned long flags, void *context)
- +{
- + struct sdma_channel *sdmac = to_sdma_chan(chan);
- + struct sdma_engine *sdma = sdmac->sdma;
- + int num_periods = buf_len / period_len;
- + int channel = sdmac->channel;
- + int ret, i = 0, buf = 0;
- +
- + dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
- +
- + if (sdmac->status == DMA_IN_PROGRESS)
- + return NULL;
- +
- + sdmac->status = DMA_IN_PROGRESS;
- +
- + sdmac->buf_tail = 0;
- + sdmac->period_len = period_len;
- +
- + sdmac->flags |= IMX_DMA_SG_LOOP;
- + sdmac->direction = direction;
- + ret = sdma_load_context(sdmac);
- + if (ret)
- + goto err_out;
- +
- + if (num_periods > NUM_BD) {
- + dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
- + channel, num_periods, NUM_BD);
- + goto err_out;
- + }
- +
- + if (period_len > 0xffff) {
- + dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %d > %d\n",
- + channel, period_len, 0xffff);
- + goto err_out;
- + }
- +
- + while (buf < buf_len) {
- + struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
- + int param;
- +
- + bd->buffer_addr = dma_addr;
- +
- + bd->mode.count = period_len;
- +
- + if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
- + goto err_out;
- + if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
- + bd->mode.command = 0;
- + else
- + bd->mode.command = sdmac->word_size;
- +
- + param = BD_DONE | BD_EXTD | BD_CONT | BD_INTR;
- + if (i + 1 == num_periods)
- + param |= BD_WRAP;
- +
- + dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n",
- + i, period_len, (u64)dma_addr,
- + param & BD_WRAP ? "wrap" : "",
- + param & BD_INTR ? " intr" : "");
- +
- + bd->mode.status = param;
- +
- + dma_addr += period_len;
- + buf += period_len;
- +
- + i++;
- + }
- +
- + sdmac->num_bd = num_periods;
- + sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
- +
- + return &sdmac->desc;
- +err_out:
- + sdmac->status = DMA_ERROR;
- + return NULL;
- +}
- +
- +static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- + unsigned long arg)
- +{
- + struct sdma_channel *sdmac = to_sdma_chan(chan);
- + struct dma_slave_config *dmaengine_cfg = (void *)arg;
- +
- + switch (cmd) {
- + case DMA_TERMINATE_ALL:
- + sdma_disable_channel(sdmac);
- + return 0;
- + case DMA_SLAVE_CONFIG:
- + if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
- + sdmac->per_address = dmaengine_cfg->src_addr;
- + sdmac->watermark_level = dmaengine_cfg->src_maxburst *
- + dmaengine_cfg->src_addr_width;
- + sdmac->word_size = dmaengine_cfg->src_addr_width;
- + } else {
- + sdmac->per_address = dmaengine_cfg->dst_addr;
- + sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
- + dmaengine_cfg->dst_addr_width;
- + sdmac->word_size = dmaengine_cfg->dst_addr_width;
- + }
- + sdmac->direction = dmaengine_cfg->direction;
- + return sdma_config_channel(sdmac);
- + default:
- + return -ENOSYS;
- + }
- +
- + return -EINVAL;
- +}
- +
- +static enum dma_status sdma_tx_status(struct dma_chan *chan,
- + dma_cookie_t cookie,
- + struct dma_tx_state *txstate)
- +{
- + struct sdma_channel *sdmac = to_sdma_chan(chan);
- + u32 residue;
- +
- + if (sdmac->flags & IMX_DMA_SG_LOOP)
- + residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len;
- + else
- + residue = sdmac->chn_count - sdmac->chn_real_count;
- +
- + dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
- + residue);
- +
- + return sdmac->status;
- +}
- +
- +static void sdma_issue_pending(struct dma_chan *chan)
- +{
- + struct sdma_channel *sdmac = to_sdma_chan(chan);
- + struct sdma_engine *sdma = sdmac->sdma;
- +
- + if (sdmac->status == DMA_IN_PROGRESS)
- + sdma_enable_channel(sdma, sdmac->channel);
- +}
- +
- +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
- +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38
- +
- +static void sdma_add_scripts(struct sdma_engine *sdma,
- + const struct sdma_script_start_addrs *addr)
- +{
- + s32 *addr_arr = (u32 *)addr;
- + s32 *saddr_arr = (u32 *)sdma->script_addrs;
- + int i;
- +
- + /* use the default firmware in ROM if missing external firmware */
- + if (!sdma->script_number)
- + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
- +
- + for (i = 0; i < sdma->script_number; i++)
- + if (addr_arr[i] > 0)
- + saddr_arr[i] = addr_arr[i];
- +}
- +
- +static void sdma_load_firmware(const struct firmware *fw, void *context)
- +{
- + struct sdma_engine *sdma = context;
- + const struct sdma_firmware_header *header;
- + const struct sdma_script_start_addrs *addr;
- + unsigned short *ram_code;
- +
- + if (!fw) {
- + dev_err(sdma->dev, "firmware not found\n");
- + return;
- + }
- +
- + if (fw->size < sizeof(*header))
- + goto err_firmware;
- +
- + header = (struct sdma_firmware_header *)fw->data;
- +
- + if (header->magic != SDMA_FIRMWARE_MAGIC)
- + goto err_firmware;
- + if (header->ram_code_start + header->ram_code_size > fw->size)
- + goto err_firmware;
- + switch (header->version_major) {
- + case 1:
- + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
- + break;
- + case 2:
- + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2;
- + break;
- + default:
- + dev_err(sdma->dev, "unknown firmware version\n");
- + goto err_firmware;
- + }
- +
- + addr = (void *)header + header->script_addrs_start;
- + ram_code = (void *)header + header->ram_code_start;
- +
- + clk_enable(sdma->clk_ipg);
- + clk_enable(sdma->clk_ahb);
- + /* download the RAM image for SDMA */
- + sdma_load_script(sdma, ram_code,
- + header->ram_code_size,
- + addr->ram_code_start_addr);
- + clk_disable(sdma->clk_ipg);
- + clk_disable(sdma->clk_ahb);
- +
- + sdma_add_scripts(sdma, addr);
- +
- + dev_info(sdma->dev, "loaded firmware %d.%d\n",
- + header->version_major,
- + header->version_minor);
- +
- +err_firmware:
- + release_firmware(fw);
- +}
- +
- +static int __init sdma_get_firmware(struct sdma_engine *sdma,
- + const char *fw_name)
- +{
- + int ret;
- +
- + ret = request_firmware_nowait(THIS_MODULE,
- + FW_ACTION_HOTPLUG, fw_name, sdma->dev,
- + GFP_KERNEL, sdma, sdma_load_firmware);
- +
- + return ret;
- +}
- +
- +static int __init sdma_init(struct sdma_engine *sdma)
- +{
- + int i, ret;
- + dma_addr_t ccb_phys;
- +
- + clk_enable(sdma->clk_ipg);
- + clk_enable(sdma->clk_ahb);
- +
- + /* Be sure SDMA has not started yet */
- + writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
- +
- + sdma->channel_control = dma_alloc_coherent(NULL,
- + MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
- + sizeof(struct sdma_context_data),
- + &ccb_phys, GFP_KERNEL);
- +
- + if (!sdma->channel_control) {
- + ret = -ENOMEM;
- + goto err_dma_alloc;
- + }
- +
- + sdma->context = (void *)sdma->channel_control +
- + MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
- + sdma->context_phys = ccb_phys +
- + MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
- +
- + /* Zero-out the CCB structures array just allocated */
- + memset(sdma->channel_control, 0,
- + MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control));
- +
- + /* disable all channels */
- + for (i = 0; i < sdma->drvdata->num_events; i++)
- + writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i));
- +
- + /* All channels have priority 0 */
- + for (i = 0; i < MAX_DMA_CHANNELS; i++)
- + writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
- +
- + ret = sdma_request_channel(&sdma->channel[0]);
- + if (ret)
- + goto err_dma_alloc;
- +
- + sdma_config_ownership(&sdma->channel[0], false, true, false);
- +
- + /* Set Command Channel (Channel Zero) */
- + writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR);
- +
- + /* Set bits of CONFIG register but with static context switching */
- + /* FIXME: Check whether to set ACR bit depending on clock ratios */
- + writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
- +
- + writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
- +
- + /* Set bits of CONFIG register with given context switching mode */
- + writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
- +
- + /* Initializes channel's priorities */
- + sdma_set_channel_priority(&sdma->channel[0], 7);
- +
- + clk_disable(sdma->clk_ipg);
- + clk_disable(sdma->clk_ahb);
- +
- + return 0;
- +
- +err_dma_alloc:
- + clk_disable(sdma->clk_ipg);
- + clk_disable(sdma->clk_ahb);
- + dev_err(sdma->dev, "initialisation failed with %d\n", ret);
- + return ret;
- +}
- +
- +static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
- +{
- + struct imx_dma_data *data = fn_param;
- +
- + if (!imx_dma_is_general_purpose(chan))
- + return false;
- +
- + chan->private = data;
- +
- + return true;
- +}
- +
- +static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
- + struct of_dma *ofdma)
- +{
- + struct sdma_engine *sdma = ofdma->of_dma_data;
- + dma_cap_mask_t mask = sdma->dma_device.cap_mask;
- + struct imx_dma_data data;
- +
- + if (dma_spec->args_count != 3)
- + return NULL;
- +
- + data.dma_request = dma_spec->args[0];
- + data.peripheral_type = dma_spec->args[1];
- + data.priority = dma_spec->args[2];
- +
- + return dma_request_channel(mask, sdma_filter_fn, &data);
- +}
- +
- +static int __init sdma_probe(struct platform_device *pdev)
- +{
- + const struct of_device_id *of_id =
- + of_match_device(sdma_dt_ids, &pdev->dev);
- + struct device_node *np = pdev->dev.of_node;
- + const char *fw_name;
- + int ret;
- + int irq;
- + struct resource *iores;
- + struct sdma_platform_data *pdata = dev_get_platdata(&pdev->dev);
- + int i;
- + struct sdma_engine *sdma;
- + s32 *saddr_arr;
- + const struct sdma_driver_data *drvdata = NULL;
- +
- + if (of_id)
- + drvdata = of_id->data;
- + else if (pdev->id_entry)
- + drvdata = (void *)pdev->id_entry->driver_data;
- +
- + if (!drvdata) {
- + dev_err(&pdev->dev, "unable to find driver data\n");
- + return -EINVAL;
- + }
- +
- + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
- + if (ret)
- + return ret;
- +
- + sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
- + if (!sdma)
- + return -ENOMEM;
- +
- + spin_lock_init(&sdma->channel_0_lock);
- +
- + sdma->dev = &pdev->dev;
- + sdma->drvdata = drvdata;
- +
- + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- + irq = platform_get_irq(pdev, 0);
- + if (!iores || irq < 0) {
- + ret = -EINVAL;
- + goto err_irq;
- + }
- +
- + if (!request_mem_region(iores->start, resource_size(iores), pdev->name)) {
- + ret = -EBUSY;
- + goto err_request_region;
- + }
- +
- + sdma->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
- + if (IS_ERR(sdma->clk_ipg)) {
- + ret = PTR_ERR(sdma->clk_ipg);
- + goto err_clk;
- + }
- +
- + sdma->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
- + if (IS_ERR(sdma->clk_ahb)) {
- + ret = PTR_ERR(sdma->clk_ahb);
- + goto err_clk;
- + }
- +
- + clk_prepare(sdma->clk_ipg);
- + clk_prepare(sdma->clk_ahb);
- +
- + sdma->regs = ioremap(iores->start, resource_size(iores));
- + if (!sdma->regs) {
- + ret = -ENOMEM;
- + goto err_ioremap;
- + }
- +
- + ret = request_irq(irq, sdma_int_handler, 0, "sdma", sdma);
- + if (ret)
- + goto err_request_irq;
- +
- + sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
- + if (!sdma->script_addrs) {
- + ret = -ENOMEM;
- + goto err_alloc;
- + }
- +
- + /* initially no scripts available */
- + saddr_arr = (s32 *)sdma->script_addrs;
- + for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++)
- + saddr_arr[i] = -EINVAL;
- +
- + dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
- + dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
- +
- + INIT_LIST_HEAD(&sdma->dma_device.channels);
- + /* Initialize channel parameters */
- + for (i = 0; i < MAX_DMA_CHANNELS; i++) {
- + struct sdma_channel *sdmac = &sdma->channel[i];
- +
- + sdmac->sdma = sdma;
- + spin_lock_init(&sdmac->lock);
- +
- + sdmac->chan.device = &sdma->dma_device;
- + dma_cookie_init(&sdmac->chan);
- + sdmac->channel = i;
- +
- + tasklet_init(&sdmac->tasklet, sdma_tasklet,
- + (unsigned long) sdmac);
- + /*
- + * Add the channel to the DMAC list. Do not add channel 0 though
- + * because we need it internally in the SDMA driver. This also means
- + * that channel 0 in dmaengine counting matches sdma channel 1.
- + */
- + if (i)
- + list_add_tail(&sdmac->chan.device_node,
- + &sdma->dma_device.channels);
- + }
- +
- + ret = sdma_init(sdma);
- + if (ret)
- + goto err_init;
- +
- + if (sdma->drvdata->script_addrs)
- + sdma_add_scripts(sdma, sdma->drvdata->script_addrs);
- + if (pdata && pdata->script_addrs)
- + sdma_add_scripts(sdma, pdata->script_addrs);
- +
- + if (pdata) {
- + ret = sdma_get_firmware(sdma, pdata->fw_name);
- + if (ret)
- + dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
- + } else {
- + /*
- + * Because that device tree does not encode ROM script address,
- + * the RAM script in firmware is mandatory for device tree
- + * probe, otherwise it fails.
- + */
- + ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
- + &fw_name);
- + if (ret)
- + dev_warn(&pdev->dev, "failed to get firmware name\n");
- + else {
- + ret = sdma_get_firmware(sdma, fw_name);
- + if (ret)
- + dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
- + }
- + }
- +
- + sdma->dma_device.dev = &pdev->dev;
- +
- + sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
- + sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources;
- + sdma->dma_device.device_tx_status = sdma_tx_status;
- + sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
- + sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
- + sdma->dma_device.device_control = sdma_control;
- + sdma->dma_device.device_issue_pending = sdma_issue_pending;
- + sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
- + dma_set_max_seg_size(sdma->dma_device.dev, 65535);
- +
- + ret = dma_async_device_register(&sdma->dma_device);
- + if (ret) {
- + dev_err(&pdev->dev, "unable to register\n");
- + goto err_init;
- + }
- +
- + if (np) {
- + ret = of_dma_controller_register(np, sdma_xlate, sdma);
- + if (ret) {
- + dev_err(&pdev->dev, "failed to register controller\n");
- + goto err_register;
- + }
- + }
- +
- + dev_info(sdma->dev, "initialized\n");
- +
- + return 0;
- +
- +err_register:
- + dma_async_device_unregister(&sdma->dma_device);
- +err_init:
- + kfree(sdma->script_addrs);
- +err_alloc:
- + free_irq(irq, sdma);
- +err_request_irq:
- + iounmap(sdma->regs);
- +err_ioremap:
- +err_clk:
- + release_mem_region(iores->start, resource_size(iores));
- +err_request_region:
- +err_irq:
- + kfree(sdma);
- + return ret;
- +}
- +
- +static int sdma_remove(struct platform_device *pdev)
- +{
- + return -EBUSY;
- +}
- +
- +static struct platform_driver sdma_driver = {
- + .driver = {
- + .name = "imx-sdma",
- + .of_match_table = sdma_dt_ids,
- + },
- + .id_table = sdma_devtypes,
- + .remove = sdma_remove,
- +};
- +
- +static int __init sdma_module_init(void)
- +{
- + return platform_driver_probe(&sdma_driver, sdma_probe);
- +}
- +module_init(sdma_module_init);
- +
- +MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
- +MODULE_DESCRIPTION("i.MX SDMA driver");
- +MODULE_LICENSE("GPL");
- diff -Nur linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-dc.c linux-3.16.6/drivers/gpu/ipu-v3/ipu-dc.c
- --- linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-dc.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/gpu/ipu-v3/ipu-dc.c 2014-10-23 12:35:30.966220009 -0500
- @@ -93,6 +93,7 @@
- IPU_DC_MAP_BGR666,
- IPU_DC_MAP_LVDS666,
- IPU_DC_MAP_BGR24,
- + IPU_DC_MAP_RGB666,
- };
-
- struct ipu_dc {
- @@ -161,6 +162,8 @@
- return IPU_DC_MAP_LVDS666;
- case V4L2_PIX_FMT_BGR24:
- return IPU_DC_MAP_BGR24;
- + case V4L2_PIX_FMT_RGB666:
- + return IPU_DC_MAP_RGB666;
- default:
- return -EINVAL;
- }
- @@ -452,6 +455,12 @@
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
-
- + /* rgb666 */
- + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB666);
- + ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 0, 5, 0xfc); /* blue */
- + ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 1, 11, 0xfc); /* green */
- + ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 2, 17, 0xfc); /* red */
- +
- return 0;
- }
-
- diff -Nur linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-di.c linux-3.16.6/drivers/gpu/ipu-v3/ipu-di.c
- --- linux-3.16.6.orig/drivers/gpu/ipu-v3/ipu-di.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/gpu/ipu-v3/ipu-di.c 2014-10-23 12:35:38.078220007 -0500
- @@ -595,7 +595,7 @@
- }
- }
-
- - if (sig->clk_pol)
- + if (sig->clk_pol == CLK_POL_POSEDGE)
- di_gen |= DI_GEN_POLARITY_DISP_CLK;
-
- ipu_di_write(di, di_gen, DI_GENERAL);
- @@ -606,7 +606,7 @@
- reg = ipu_di_read(di, DI_POL);
- reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
-
- - if (sig->enable_pol)
- + if (sig->enable_pol == ENABLE_POL_HIGH)
- reg |= DI_POL_DRDY_POLARITY_15;
- if (sig->data_pol)
- reg |= DI_POL_DRDY_DATA_POLARITY;
- diff -Nur linux-3.16.6.orig/drivers/Kconfig linux-3.16.6/drivers/Kconfig
- --- linux-3.16.6.orig/drivers/Kconfig 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/Kconfig 2014-10-23 12:37:18.314220004 -0500
- @@ -176,4 +176,6 @@
-
- source "drivers/mcb/Kconfig"
-
- +source "drivers/cec/Kconfig"
- +
- endmenu
- diff -Nur linux-3.16.6.orig/drivers/Makefile linux-3.16.6/drivers/Makefile
- --- linux-3.16.6.orig/drivers/Makefile 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/Makefile 2014-10-23 12:37:18.350220009 -0500
- @@ -158,3 +158,4 @@
- obj-$(CONFIG_FMC) += fmc/
- obj-$(CONFIG_POWERCAP) += powercap/
- obj-$(CONFIG_MCB) += mcb/
- +obj-$(CONFIG_CEC) += cec/
- diff -Nur linux-3.16.6.orig/drivers/mmc/core/core.c linux-3.16.6/drivers/mmc/core/core.c
- --- linux-3.16.6.orig/drivers/mmc/core/core.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/mmc/core/core.c 2014-10-23 12:34:18.710219997 -0500
- @@ -13,11 +13,13 @@
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- +#include <linux/clk.h>
- #include <linux/completion.h>
- #include <linux/device.h>
- #include <linux/delay.h>
- #include <linux/pagemap.h>
- #include <linux/err.h>
- +#include <linux/gpio/consumer.h>
- #include <linux/leds.h>
- #include <linux/scatterlist.h>
- #include <linux/log2.h>
- @@ -1515,6 +1517,43 @@
- mmc_host_clk_release(host);
- }
-
- +static void mmc_card_power_up(struct mmc_host *host)
- +{
- + int i;
- + struct gpio_desc **gds = host->card_reset_gpios;
- +
- + for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
- + if (gds[i]) {
- + dev_dbg(host->parent, "Asserting reset line %d", i);
- + gpiod_set_value(gds[i], 1);
- + }
- + }
- +
- + if (host->card_regulator) {
- + dev_dbg(host->parent, "Enabling external regulator");
- + if (regulator_enable(host->card_regulator))
- + dev_err(host->parent, "Failed to enable external regulator");
- + }
- +
- + if (host->card_clk) {
- + dev_dbg(host->parent, "Enabling external clock");
- + clk_prepare_enable(host->card_clk);
- + }
- +
- + /* 2ms delay to let clocks and power settle */
- + mmc_delay(20);
- +
- + for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
- + if (gds[i]) {
- + dev_dbg(host->parent, "Deasserting reset line %d", i);
- + gpiod_set_value(gds[i], 0);
- + }
- + }
- +
- + /* 2ms delay to after reset release */
- + mmc_delay(20);
- +}
- +
- /*
- * Apply power to the MMC stack. This is a two-stage process.
- * First, we enable power to the card without the clock running.
- @@ -1531,6 +1570,9 @@
- if (host->ios.power_mode == MMC_POWER_ON)
- return;
-
- + /* Power up the card/module first, if needed */
- + mmc_card_power_up(host);
- +
- mmc_host_clk_hold(host);
-
- host->ios.vdd = fls(ocr) - 1;
- diff -Nur linux-3.16.6.orig/drivers/mmc/core/host.c linux-3.16.6/drivers/mmc/core/host.c
- --- linux-3.16.6.orig/drivers/mmc/core/host.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/mmc/core/host.c 2014-10-23 12:34:34.134220000 -0500
- @@ -12,14 +12,18 @@
- * MMC host class device management
- */
-
- +#include <linux/kernel.h>
- +#include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/err.h>
- +#include <linux/gpio/consumer.h>
- #include <linux/idr.h>
- #include <linux/of.h>
- #include <linux/of_gpio.h>
- #include <linux/pagemap.h>
- #include <linux/export.h>
- #include <linux/leds.h>
- +#include <linux/regulator/consumer.h>
- #include <linux/slab.h>
- #include <linux/suspend.h>
-
- @@ -461,6 +465,66 @@
-
- EXPORT_SYMBOL(mmc_of_parse);
-
- +static int mmc_of_parse_child(struct mmc_host *host)
- +{
- + struct device_node *np;
- + struct clk *clk;
- + int i;
- +
- + if (!host->parent || !host->parent->of_node)
- + return 0;
- +
- + np = host->parent->of_node;
- +
- + host->card_regulator = regulator_get(host->parent, "card-external-vcc");
- + if (IS_ERR(host->card_regulator)) {
- + if (PTR_ERR(host->card_regulator) == -EPROBE_DEFER)
- + return PTR_ERR(host->card_regulator);
- + host->card_regulator = NULL;
- + }
- +
- + /* Parse card power/reset/clock control */
- + if (of_find_property(np, "card-reset-gpios", NULL)) {
- + struct gpio_desc *gpd;
- + int level = 0;
- +
- + /*
- + * If the regulator is enabled, then we can hold the
- + * card in reset with an active high resets. Otherwise,
- + * hold the resets low.
- + */
- + if (host->card_regulator && regulator_is_enabled(host->card_regulator))
- + level = 1;
- +
- + for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
- + gpd = devm_gpiod_get_index(host->parent, "card-reset", i);
- + if (IS_ERR(gpd)) {
- + if (PTR_ERR(gpd) == -EPROBE_DEFER)
- + return PTR_ERR(gpd);
- + break;
- + }
- + gpiod_direction_output(gpd, gpiod_is_active_low(gpd) | level);
- + host->card_reset_gpios[i] = gpd;
- + }
- +
- + gpd = devm_gpiod_get_index(host->parent, "card-reset", ARRAY_SIZE(host->card_reset_gpios));
- + if (!IS_ERR(gpd)) {
- + dev_warn(host->parent, "More reset gpios than we can handle");
- + gpiod_put(gpd);
- + }
- + }
- +
- + clk = of_clk_get_by_name(np, "card_ext_clock");
- + if (IS_ERR(clk)) {
- + if (PTR_ERR(clk) == -EPROBE_DEFER)
- + return PTR_ERR(clk);
- + clk = NULL;
- + }
- + host->card_clk = clk;
- +
- + return 0;
- +}
- +
- /**
- * mmc_alloc_host - initialise the per-host structure.
- * @extra: sizeof private data structure
- @@ -540,6 +604,10 @@
- {
- int err;
-
- + err = mmc_of_parse_child(host);
- + if (err)
- + return err;
- +
- WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
- !host->ops->enable_sdio_irq);
-
- diff -Nur linux-3.16.6.orig/drivers/mmc/host/dw_mmc.c linux-3.16.6/drivers/mmc/host/dw_mmc.c
- --- linux-3.16.6.orig/drivers/mmc/host/dw_mmc.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/mmc/host/dw_mmc.c 2014-10-23 12:34:26.238219996 -0500
- @@ -2049,6 +2049,8 @@
- if (!mmc)
- return -ENOMEM;
-
- + mmc_of_parse(mmc);
- +
- slot = mmc_priv(mmc);
- slot->id = id;
- slot->mmc = mmc;
- diff -Nur linux-3.16.6.orig/drivers/mmc/host/Kconfig linux-3.16.6/drivers/mmc/host/Kconfig
- --- linux-3.16.6.orig/drivers/mmc/host/Kconfig 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/mmc/host/Kconfig 2014-10-23 12:34:04.318220041 -0500
- @@ -25,8 +25,7 @@
- If unsure, say N.
-
- config MMC_SDHCI
- - tristate "Secure Digital Host Controller Interface support"
- - depends on HAS_DMA
- + tristate
- help
- This selects the generic Secure Digital Host Controller Interface.
- It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
- @@ -59,7 +58,8 @@
-
- config MMC_SDHCI_PCI
- tristate "SDHCI support on PCI bus"
- - depends on MMC_SDHCI && PCI
- + depends on PCI && HAS_DMA
- + select MMC_SDHCI
- help
- This selects the PCI Secure Digital Host Controller Interface.
- Most controllers found today are PCI devices.
- @@ -83,7 +83,8 @@
-
- config MMC_SDHCI_ACPI
- tristate "SDHCI support for ACPI enumerated SDHCI controllers"
- - depends on MMC_SDHCI && ACPI
- + depends on ACPI && HAS_DMA
- + select MMC_SDHCI
- help
- This selects support for ACPI enumerated SDHCI controllers,
- identified by ACPI Compatibility ID PNP0D40 or specific
- @@ -94,8 +95,8 @@
- If unsure, say N.
-
- config MMC_SDHCI_PLTFM
- - tristate "SDHCI platform and OF driver helper"
- - depends on MMC_SDHCI
- + tristate
- + select MMC_SDHCI
- help
- This selects the common helper functions support for Secure Digital
- Host Controller Interface based platform and OF drivers.
- @@ -106,8 +107,8 @@
-
- config MMC_SDHCI_OF_ARASAN
- tristate "SDHCI OF support for the Arasan SDHCI controllers"
- - depends on MMC_SDHCI_PLTFM
- - depends on OF
- + depends on OF && HAS_DMA
- + select MMC_SDHCI_PLTFM
- help
- This selects the Arasan Secure Digital Host Controller Interface
- (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC.
- @@ -118,9 +119,9 @@
-
- config MMC_SDHCI_OF_ESDHC
- tristate "SDHCI OF support for the Freescale eSDHC controller"
- - depends on MMC_SDHCI_PLTFM
- - depends on PPC_OF
- + depends on PPC_OF && HAS_DMA
- select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
- + select MMC_SDHCI_PLTFM
- help
- This selects the Freescale eSDHC controller support.
-
- @@ -130,9 +131,9 @@
-
- config MMC_SDHCI_OF_HLWD
- tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers"
- - depends on MMC_SDHCI_PLTFM
- - depends on PPC_OF
- + depends on PPC_OF && HAS_DMA
- select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
- + select MMC_SDHCI_PLTFM
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- found in the "Hollywood" chipset of the Nintendo Wii video game
- @@ -144,8 +145,8 @@
-
- config MMC_SDHCI_CNS3XXX
- tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
- - depends on ARCH_CNS3XXX
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_CNS3XXX && HAS_DMA
- + select MMC_SDHCI_PLTFM
- help
- This selects the SDHCI support for CNS3xxx System-on-Chip devices.
-
- @@ -155,9 +156,9 @@
-
- config MMC_SDHCI_ESDHC_IMX
- tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
- - depends on ARCH_MXC
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_MXC && HAS_DMA
- select MMC_SDHCI_IO_ACCESSORS
- + select MMC_SDHCI_PLTFM
- help
- This selects the Freescale eSDHC/uSDHC controller support
- found on i.MX25, i.MX35 i.MX5x and i.MX6x.
- @@ -168,9 +169,9 @@
-
- config MMC_SDHCI_DOVE
- tristate "SDHCI support on Marvell's Dove SoC"
- - depends on ARCH_DOVE || MACH_DOVE
- - depends on MMC_SDHCI_PLTFM
- + depends on (ARCH_DOVE || MACH_DOVE) && HAS_DMA
- select MMC_SDHCI_IO_ACCESSORS
- + select MMC_SDHCI_PLTFM
- help
- This selects the Secure Digital Host Controller Interface in
- Marvell's Dove SoC.
- @@ -181,9 +182,9 @@
-
- config MMC_SDHCI_TEGRA
- tristate "SDHCI platform support for the Tegra SD/MMC Controller"
- - depends on ARCH_TEGRA
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_TEGRA && HAS_DMA
- select MMC_SDHCI_IO_ACCESSORS
- + select MMC_SDHCI_PLTFM
- help
- This selects the Tegra SD/MMC controller. If you have a Tegra
- platform with SD or MMC devices, say Y or M here.
- @@ -192,7 +193,8 @@
-
- config MMC_SDHCI_S3C
- tristate "SDHCI support on Samsung S3C SoC"
- - depends on MMC_SDHCI && PLAT_SAMSUNG
- + depends on PLAT_SAMSUNG && HAS_DMA
- + select MMC_SDHCI
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- often referrered to as the HSMMC block in some of the Samsung S3C
- @@ -204,8 +206,8 @@
-
- config MMC_SDHCI_SIRF
- tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs"
- - depends on ARCH_SIRF
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_SIRF && HAS_DMA
- + select MMC_SDHCI_PLTFM
- help
- This selects the SDHCI support for SiRF System-on-Chip devices.
-
- @@ -215,8 +217,8 @@
-
- config MMC_SDHCI_PXAV3
- tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
- - depends on CLKDEV_LOOKUP
- - depends on MMC_SDHCI_PLTFM
- + depends on CLKDEV_LOOKUP && HAS_DMA
- + select MMC_SDHCI_PLTFM
- default CPU_MMP2
- help
- This selects the Marvell(R) PXAV3 SD Host Controller.
- @@ -227,8 +229,8 @@
-
- config MMC_SDHCI_PXAV2
- tristate "Marvell PXA9XX SD Host Controller support (PXAV2)"
- - depends on CLKDEV_LOOKUP
- - depends on MMC_SDHCI_PLTFM
- + depends on CLKDEV_LOOKUP && HAS_DMA
- + select MMC_SDHCI_PLTFM
- default CPU_PXA910
- help
- This selects the Marvell(R) PXAV2 SD Host Controller.
- @@ -239,7 +241,8 @@
-
- config MMC_SDHCI_SPEAR
- tristate "SDHCI support on ST SPEAr platform"
- - depends on MMC_SDHCI && PLAT_SPEAR
- + depends on PLAT_SPEAR && HAS_DMA
- + select MMC_SDHCI
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- often referrered to as the HSMMC block in some of the ST SPEAR range
- @@ -261,8 +264,8 @@
-
- config MMC_SDHCI_BCM_KONA
- tristate "SDHCI support on Broadcom KONA platform"
- - depends on ARCH_BCM_MOBILE
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_BCM_MOBILE && HAS_DMA
- + select MMC_SDHCI_PLTFM
- help
- This selects the Broadcom Kona Secure Digital Host Controller
- Interface(SDHCI) support.
- @@ -272,9 +275,9 @@
-
- config MMC_SDHCI_BCM2835
- tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
- - depends on ARCH_BCM2835
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_BCM2835 && HAS_DMA
- select MMC_SDHCI_IO_ACCESSORS
- + select MMC_SDHCI_PLTFM
- help
- This selects the BCM2835 SD/MMC controller. If you have a BCM2835
- platform with SD or MMC devices, say Y or M here.
- diff -Nur linux-3.16.6.orig/drivers/mmc/host/sdhci.c linux-3.16.6/drivers/mmc/host/sdhci.c
- --- linux-3.16.6.orig/drivers/mmc/host/sdhci.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/mmc/host/sdhci.c 2014-10-23 12:34:10.650220104 -0500
- @@ -1530,7 +1530,6 @@
- host->ops->set_clock(host, host->clock);
- }
-
- -
- /* Reset SD Clock Enable */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- @@ -1763,9 +1762,6 @@
- ctrl |= SDHCI_CTRL_VDD_180;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- - /* Wait for 5ms */
- - usleep_range(5000, 5500);
- -
- /* 1.8V regulator output should be stable within 5 ms */
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (ctrl & SDHCI_CTRL_VDD_180)
- diff -Nur linux-3.16.6.orig/drivers/regulator/anatop-regulator.c linux-3.16.6/drivers/regulator/anatop-regulator.c
- --- linux-3.16.6.orig/drivers/regulator/anatop-regulator.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/regulator/anatop-regulator.c 2014-10-23 12:36:22.798219997 -0500
- @@ -267,6 +267,7 @@
- config.driver_data = sreg;
- config.of_node = pdev->dev.of_node;
- config.regmap = sreg->anatop;
- + config.ena_gpio = -EINVAL;
-
- /* Only core regulators have the ramp up delay configuration. */
- if (sreg->control_reg && sreg->delay_bit_width) {
- diff -Nur linux-3.16.6.orig/drivers/regulator/core.c linux-3.16.6/drivers/regulator/core.c
- --- linux-3.16.6.orig/drivers/regulator/core.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/regulator/core.c 2014-10-23 12:36:22.802220004 -0500
- @@ -24,6 +24,7 @@
- #include <linux/suspend.h>
- #include <linux/delay.h>
- #include <linux/gpio.h>
- +#include <linux/gpio/consumer.h>
- #include <linux/of.h>
- #include <linux/regmap.h>
- #include <linux/regulator/of_regulator.h>
- @@ -77,7 +78,7 @@
- */
- struct regulator_enable_gpio {
- struct list_head list;
- - int gpio;
- + struct gpio_desc *gpiod;
- u32 enable_count; /* a number of enabled shared GPIO */
- u32 request_count; /* a number of requested shared GPIO */
- unsigned int ena_gpio_invert:1;
- @@ -1660,10 +1661,13 @@
- const struct regulator_config *config)
- {
- struct regulator_enable_gpio *pin;
- + struct gpio_desc *gpiod;
- int ret;
-
- + gpiod = gpio_to_desc(config->ena_gpio);
- +
- list_for_each_entry(pin, ®ulator_ena_gpio_list, list) {
- - if (pin->gpio == config->ena_gpio) {
- + if (pin->gpiod == gpiod) {
- rdev_dbg(rdev, "GPIO %d is already used\n",
- config->ena_gpio);
- goto update_ena_gpio_to_rdev;
- @@ -1682,7 +1686,7 @@
- return -ENOMEM;
- }
-
- - pin->gpio = config->ena_gpio;
- + pin->gpiod = gpiod;
- pin->ena_gpio_invert = config->ena_gpio_invert;
- list_add(&pin->list, ®ulator_ena_gpio_list);
-
- @@ -1701,10 +1705,10 @@
-
- /* Free the GPIO only in case of no use */
- list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) {
- - if (pin->gpio == rdev->ena_pin->gpio) {
- + if (pin->gpiod == rdev->ena_pin->gpiod) {
- if (pin->request_count <= 1) {
- pin->request_count = 0;
- - gpio_free(pin->gpio);
- + gpiod_put(pin->gpiod);
- list_del(&pin->list);
- kfree(pin);
- } else {
- @@ -1732,8 +1736,8 @@
- if (enable) {
- /* Enable GPIO at initial use */
- if (pin->enable_count == 0)
- - gpio_set_value_cansleep(pin->gpio,
- - !pin->ena_gpio_invert);
- + gpiod_set_value_cansleep(pin->gpiod,
- + !pin->ena_gpio_invert);
-
- pin->enable_count++;
- } else {
- @@ -1744,8 +1748,8 @@
-
- /* Disable GPIO if not used */
- if (pin->enable_count <= 1) {
- - gpio_set_value_cansleep(pin->gpio,
- - pin->ena_gpio_invert);
- + gpiod_set_value_cansleep(pin->gpiod,
- + pin->ena_gpio_invert);
- pin->enable_count = 0;
- }
- }
- @@ -3470,7 +3474,7 @@
-
- dev_set_drvdata(&rdev->dev, rdev);
-
- - if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
- + if (gpio_is_valid(config->ena_gpio)) {
- ret = regulator_ena_gpio_request(rdev, config);
- if (ret != 0) {
- rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
- diff -Nur linux-3.16.6.orig/drivers/regulator/dummy.c linux-3.16.6/drivers/regulator/dummy.c
- --- linux-3.16.6.orig/drivers/regulator/dummy.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/regulator/dummy.c 2014-10-23 12:36:22.810220006 -0500
- @@ -48,6 +48,7 @@
-
- config.dev = &pdev->dev;
- config.init_data = &dummy_initdata;
- + config.ena_gpio = -EINVAL;
-
- dummy_regulator_rdev = regulator_register(&dummy_desc, &config);
- if (IS_ERR(dummy_regulator_rdev)) {
- diff -Nur linux-3.16.6.orig/drivers/regulator/fixed.c linux-3.16.6/drivers/regulator/fixed.c
- --- linux-3.16.6.orig/drivers/regulator/fixed.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/regulator/fixed.c 2014-10-23 12:36:22.810220006 -0500
- @@ -156,9 +156,7 @@
- drvdata->desc.n_voltages = 1;
-
- drvdata->desc.fixed_uV = config->microvolts;
- -
- - if (config->gpio >= 0)
- - cfg.ena_gpio = config->gpio;
- + cfg.ena_gpio = config->gpio;
- cfg.ena_gpio_invert = !config->enable_high;
- if (config->enabled_at_boot) {
- if (config->enable_high)
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.c linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.c 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.c 2014-10-23 12:37:30.178219970 -0500
- @@ -0,0 +1,88 @@
- +#include <linux/i2c.h>
- +#include <linux/module.h>
- +#include <drm/drmP.h>
- +#include <drm/drm_crtc_helper.h>
- +#include <drm/drm_edid.h>
- +
- +#include "drm-ddc-connector.h"
- +
- +enum drm_connector_status
- +drm_ddc_connector_always_connected(struct drm_connector *connector, bool force)
- +{
- + return connector_status_connected;
- +}
- +EXPORT_SYMBOL_GPL(drm_ddc_connector_always_connected);
- +
- +int drm_ddc_connector_get_modes(struct drm_connector *connector)
- +{
- + struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
- + struct edid *edid;
- + int ret = 0;
- +
- + if (!ddc_conn->ddc)
- + return 0;
- +
- + edid = drm_get_edid(connector, ddc_conn->ddc);
- + if (edid) {
- + drm_mode_connector_update_edid_property(connector, edid);
- + ret = drm_add_edid_modes(connector, edid);
- + /* Store the ELD */
- + drm_edid_to_eld(connector, edid);
- + kfree(edid);
- + }
- +
- + return ret;
- +}
- +EXPORT_SYMBOL_GPL(drm_ddc_connector_get_modes);
- +
- +void drm_ddc_connector_destroy(struct drm_connector *connector)
- +{
- + struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
- +
- + pr_info("%s: %p\n", __func__, ddc_conn);
- +
- + drm_sysfs_connector_remove(connector);
- + drm_connector_cleanup(connector);
- + if (ddc_conn->ddc)
- + i2c_put_adapter(ddc_conn->ddc);
- + kfree(ddc_conn);
- +}
- +EXPORT_SYMBOL_GPL(drm_ddc_connector_destroy);
- +
- +void drm_ddc_connector_add(struct drm_device *drm,
- + struct drm_ddc_connector *ddc_conn,
- + struct drm_connector_funcs *funcs, int connector_type)
- +{
- + drm_connector_init(drm, &ddc_conn->connector, funcs, connector_type);
- +}
- +EXPORT_SYMBOL_GPL(drm_ddc_connector_add);
- +
- +struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm,
- + struct device_node *np, void *private)
- +{
- + struct drm_ddc_connector *ddc_conn;
- + struct device_node *ddc_node;
- +
- + ddc_conn = kzalloc(sizeof(*ddc_conn), GFP_KERNEL);
- + if (!ddc_conn)
- + return ERR_PTR(-ENOMEM);
- +
- + ddc_conn->private = private;
- +
- + ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
- + if (ddc_node) {
- + ddc_conn->ddc = of_find_i2c_adapter_by_node(ddc_node);
- + of_node_put(ddc_node);
- + if (!ddc_conn->ddc) {
- + kfree(ddc_conn);
- + return ERR_PTR(-EPROBE_DEFER);
- + }
- + }
- +
- + return ddc_conn;
- +}
- +EXPORT_SYMBOL_GPL(drm_ddc_connector_create);
- +
- +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
- +MODULE_DESCRIPTION("Generic DRM DDC connector module");
- +MODULE_LICENSE("GPL v2");
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.h linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.h
- --- linux-3.16.6.orig/drivers/staging/imx-drm/drm-ddc-connector.h 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/drm-ddc-connector.h 2014-10-23 12:37:30.178219970 -0500
- @@ -0,0 +1,31 @@
- +#ifndef DRM_DDC_CONNECTOR_H
- +#define DRM_DDC_CONNECTOR_H
- +
- +#include <drm/drm_crtc.h>
- +
- +struct drm_ddc_connector {
- + struct i2c_adapter *ddc;
- + struct drm_connector connector;
- + void *private;
- +};
- +
- +#define to_ddc_conn(c) container_of(c, struct drm_ddc_connector, connector)
- +
- +enum drm_connector_status drm_ddc_connector_always_connected(
- + struct drm_connector *connector, bool force);
- +int drm_ddc_connector_get_modes(struct drm_connector *connector);
- +void drm_ddc_connector_add(struct drm_device *drm,
- + struct drm_ddc_connector *ddc_conn,
- + struct drm_connector_funcs *funcs, int connector_type);
- +void drm_ddc_connector_destroy(struct drm_connector *connector);
- +struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm,
- + struct device_node *np, void *private);
- +
- +static inline void *drm_ddc_private(struct drm_connector *connector)
- +{
- + struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
- +
- + return ddc_conn->private;
- +}
- +
- +#endif
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.c linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.c 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.c 2014-10-23 12:37:11.394219951 -0500
- @@ -0,0 +1,654 @@
- +/*
- + * DesignWare HDMI audio driver
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License version 2 as
- + * published by the Free Software Foundation.
- + *
- + * Written and tested against the (alleged) DW HDMI Tx found in iMX6S.
- + */
- +#include <linux/delay.h>
- +#include <linux/io.h>
- +#include <linux/interrupt.h>
- +#include <linux/module.h>
- +#include <linux/platform_device.h>
- +
- +#include <sound/asoundef.h>
- +#include <sound/core.h>
- +#include <sound/initval.h>
- +#include <sound/pcm.h>
- +
- +#include "dw-hdmi-audio.h"
- +
- +#define DRIVER_NAME "dw-hdmi-audio"
- +
- +/* Provide some bits rather than bit offsets */
- +enum {
- + HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7),
- + HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3),
- + HDMI_AHB_DMA_START_START = BIT(0),
- + HDMI_AHB_DMA_STOP_STOP = BIT(0),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL =
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY,
- + HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5),
- + HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4),
- + HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3),
- + HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2),
- + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
- + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
- + HDMI_IH_AHBDMAAUD_STAT0_ALL =
- + HDMI_IH_AHBDMAAUD_STAT0_ERROR |
- + HDMI_IH_AHBDMAAUD_STAT0_LOST |
- + HDMI_IH_AHBDMAAUD_STAT0_RETRY |
- + HDMI_IH_AHBDMAAUD_STAT0_DONE |
- + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL |
- + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY,
- + HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1,
- + HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1,
- + HDMI_AHB_DMA_CONF0_INCR4 = 0,
- + HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0),
- + HDMI_AHB_DMA_MASK_DONE = BIT(7),
- + HDMI_REVISION_ID = 0x0001,
- + HDMI_IH_AHBDMAAUD_STAT0 = 0x0109,
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189,
- + HDMI_AUD_N1 = 0x3200,
- + HDMI_AUD_CTS1 = 0x3203,
- + HDMI_AHB_DMA_CONF0 = 0x3600,
- + HDMI_AHB_DMA_START = 0x3601,
- + HDMI_AHB_DMA_STOP = 0x3602,
- + HDMI_AHB_DMA_THRSLD = 0x3603,
- + HDMI_AHB_DMA_STRADDR0 = 0x3604,
- + HDMI_AHB_DMA_STPADDR0 = 0x3608,
- + HDMI_AHB_DMA_STAT = 0x3612,
- + HDMI_AHB_DMA_STAT_FULL = BIT(1),
- + HDMI_AHB_DMA_MASK = 0x3614,
- + HDMI_AHB_DMA_POL = 0x3615,
- + HDMI_AHB_DMA_CONF1 = 0x3616,
- + HDMI_AHB_DMA_BUFFPOL = 0x361a,
- +};
- +
- +struct snd_dw_hdmi {
- + struct snd_card *card;
- + struct snd_pcm *pcm;
- + struct dw_hdmi_audio_data data;
- + struct snd_pcm_substream *substream;
- + void (*reformat)(struct snd_dw_hdmi *, size_t, size_t);
- + void *buf_src;
- + void *buf_dst;
- + dma_addr_t buf_addr;
- + unsigned buf_offset;
- + unsigned buf_period;
- + unsigned buf_size;
- + unsigned channels;
- + uint8_t revision;
- + uint8_t iec_offset;
- + uint8_t cs[192][8];
- +};
- +
- +static void dw_hdmi_writel(unsigned long val, void __iomem *ptr)
- +{
- + writeb_relaxed(val, ptr);
- + writeb_relaxed(val >> 8, ptr + 1);
- + writeb_relaxed(val >> 16, ptr + 2);
- + writeb_relaxed(val >> 24, ptr + 3);
- +}
- +
- +/*
- + * Convert to hardware format: The userspace buffer contains IEC958 samples,
- + * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We
- + * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio
- + * samples in 23..0.
- + *
- + * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd
- + *
- + * Ideally, we could do with having the data properly formatted in userspace.
- + */
- +static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw,
- + size_t offset, size_t bytes)
- +{
- + uint32_t *src = dw->buf_src + offset;
- + uint32_t *dst = dw->buf_dst + offset;
- + uint32_t *end = dw->buf_src + offset + bytes;
- +
- + do {
- + uint32_t b, sample = *src++;
- +
- + b = (sample & 8) << (28 - 3);
- +
- + sample >>= 4;
- +
- + *dst++ = sample | b;
- + } while (src < end);
- +}
- +
- +static uint32_t parity(uint32_t sample)
- +{
- + sample ^= sample >> 16;
- + sample ^= sample >> 8;
- + sample ^= sample >> 4;
- + sample ^= sample >> 2;
- + sample ^= sample >> 1;
- + return (sample & 1) << 27;
- +}
- +
- +static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw,
- + size_t offset, size_t bytes)
- +{
- + uint32_t *src = dw->buf_src + offset;
- + uint32_t *dst = dw->buf_dst + offset;
- + uint32_t *end = dw->buf_src + offset + bytes;
- +
- + do {
- + unsigned i;
- + uint8_t *cs;
- +
- + cs = dw->cs[dw->iec_offset++];
- + if (dw->iec_offset >= 192)
- + dw->iec_offset = 0;
- +
- + i = dw->channels;
- + do {
- + uint32_t sample = *src++;
- +
- + sample &= ~0xff000000;
- + sample |= *cs++ << 24;
- + sample |= parity(sample & ~0xf8000000);
- +
- + *dst++ = sample;
- + } while (--i);
- + } while (src < end);
- +}
- +
- +static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
- + struct snd_pcm_runtime *runtime)
- +{
- + uint8_t cs[4];
- + unsigned ch, i, j;
- +
- + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
- + cs[1] = IEC958_AES1_CON_GENERAL;
- + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC;
- + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
- +
- + switch (runtime->rate) {
- + case 32000:
- + cs[3] |= IEC958_AES3_CON_FS_32000;
- + break;
- + case 44100:
- + cs[3] |= IEC958_AES3_CON_FS_44100;
- + break;
- + case 48000:
- + cs[3] |= IEC958_AES3_CON_FS_48000;
- + break;
- + case 88200:
- + cs[3] |= IEC958_AES3_CON_FS_88200;
- + break;
- + case 96000:
- + cs[3] |= IEC958_AES3_CON_FS_96000;
- + break;
- + case 176400:
- + cs[3] |= IEC958_AES3_CON_FS_176400;
- + break;
- + case 192000:
- + cs[3] |= IEC958_AES3_CON_FS_192000;
- + break;
- + }
- +
- + memset(dw->cs, 0, sizeof(dw->cs));
- +
- + for (ch = 0; ch < 8; ch++) {
- + cs[2] &= ~IEC958_AES2_CON_CHANNEL;
- + cs[2] |= (ch + 1) << 4;
- +
- + for (i = 0; i < ARRAY_SIZE(cs); i++) {
- + unsigned c = cs[i];
- +
- + for (j = 0; j < 8; j++, c >>= 1)
- + dw->cs[i * 8 + j][ch] = (c & 1) << 2;
- + }
- + }
- + dw->cs[0][0] |= BIT(4);
- +}
- +
- +static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
- +{
- + void __iomem *base = dw->data.base;
- + unsigned offset = dw->buf_offset;
- + unsigned period = dw->buf_period;
- + u32 start, stop;
- +
- + dw->reformat(dw, offset, period);
- +
- + /* Clear all irqs before enabling irqs and starting DMA */
- + writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL,
- + base + HDMI_IH_AHBDMAAUD_STAT0);
- +
- + start = dw->buf_addr + offset;
- + stop = start + period - 1;
- +
- + /* Setup the hardware start/stop addresses */
- + dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0);
- + dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0);
- +
- + writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK);
- + writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START);
- +
- + offset += period;
- + if (offset >= dw->buf_size)
- + offset = 0;
- + dw->buf_offset = offset;
- +}
- +
- +static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
- +{
- + dw->substream = NULL;
- +
- + /* Disable interrupts before disabling DMA */
- + writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK);
- + writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP);
- + synchronize_irq(dw->data.irq);
- +}
- +
- +static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
- +{
- + struct snd_dw_hdmi *dw = data;
- + struct snd_pcm_substream *substream;
- + unsigned stat;
- +
- + stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
- + if (!stat)
- + return IRQ_NONE;
- +
- + writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
- +
- + substream = dw->substream;
- + if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
- + snd_pcm_period_elapsed(substream);
- + if (dw->substream)
- + dw_hdmi_start_dma(dw);
- + }
- +
- + return IRQ_HANDLED;
- +}
- +
- +static struct snd_pcm_hardware dw_hdmi_hw = {
- + .info = SNDRV_PCM_INFO_INTERLEAVED |
- + SNDRV_PCM_INFO_BLOCK_TRANSFER |
- + SNDRV_PCM_INFO_MMAP |
- + SNDRV_PCM_INFO_MMAP_VALID,
- + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
- + SNDRV_PCM_FMTBIT_S24_LE,
- + .rates = SNDRV_PCM_RATE_32000 |
- + SNDRV_PCM_RATE_44100 |
- + SNDRV_PCM_RATE_48000 |
- + SNDRV_PCM_RATE_88200 |
- + SNDRV_PCM_RATE_96000 |
- + SNDRV_PCM_RATE_176400 |
- + SNDRV_PCM_RATE_192000,
- + .channels_min = 2,
- + .channels_max = 8,
- + .buffer_bytes_max = 64 * 1024,
- + .period_bytes_min = 256,
- + .period_bytes_max = 8192, /* ERR004323: must limit to 8k */
- + .periods_min = 2,
- + .periods_max = 16,
- + .fifo_size = 0,
- +};
- +
- +static unsigned rates_mask[] = {
- + SNDRV_PCM_RATE_32000,
- + SNDRV_PCM_RATE_44100,
- + SNDRV_PCM_RATE_48000,
- + SNDRV_PCM_RATE_88200,
- + SNDRV_PCM_RATE_96000,
- + SNDRV_PCM_RATE_176400,
- + SNDRV_PCM_RATE_192000,
- +};
- +
- +static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw,
- + struct snd_pcm_runtime *runtime)
- +{
- + u8 *sad, *eld = dw->data.eld;
- + unsigned eld_ver, mnl, sad_count, rates, rate_mask, i;
- + unsigned max_channels;
- +
- + eld_ver = eld[0] >> 3;
- + if (eld_ver != 2 && eld_ver != 31)
- + return;
- +
- + mnl = eld[4] & 0x1f;
- + if (mnl > 16)
- + return;
- +
- + sad_count = eld[5] >> 4;
- + sad = eld + 20 + mnl;
- +
- + /* Start from the basic audio settings */
- + max_channels = 2;
- + rates = 7;
- + while (sad_count > 0) {
- + switch (sad[0] & 0x78) {
- + case 0x08: /* PCM */
- + max_channels = max(max_channels, (sad[0] & 7) + 1u);
- + rates |= sad[1];
- + break;
- + }
- + sad += 3;
- + sad_count -= 1;
- + }
- +
- + for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++)
- + if (rates & 1 << i)
- + rate_mask |= rates_mask[i];
- +
- + runtime->hw.rates &= rate_mask;
- + runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels);
- +}
- +
- +static int dw_hdmi_open(struct snd_pcm_substream *substream)
- +{
- + struct snd_pcm_runtime *runtime = substream->runtime;
- + struct snd_dw_hdmi *dw = substream->private_data;
- + void __iomem *base = dw->data.base;
- + int ret;
- +
- + /* Clear FIFO */
- + writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
- + base + HDMI_AHB_DMA_CONF0);
- +
- + /* Configure interrupt polarities */
- + writeb_relaxed(~0, base + HDMI_AHB_DMA_POL);
- + writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL);
- +
- + /* Keep interrupts masked, and clear any pending */
- + writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK);
- + writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0);
- +
- + ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED,
- + "dw-hdmi-audio", dw);
- + if (ret)
- + return ret;
- +
- + /* Un-mute done interrupt */
- + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
- + ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
- + base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
- +
- + runtime->hw = dw_hdmi_hw;
- + dw_hdmi_parse_eld(dw, runtime);
- + snd_pcm_limit_hw_rates(runtime);
- + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- +
- + return 0;
- +}
- +
- +static int dw_hdmi_close(struct snd_pcm_substream *substream)
- +{
- + struct snd_dw_hdmi *dw = substream->private_data;
- +
- + /* Mute all interrupts */
- + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
- + dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
- +
- + free_irq(dw->data.irq, dw);
- +
- + return 0;
- +}
- +
- +static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
- +{
- + return snd_pcm_lib_free_vmalloc_buffer(substream);
- +}
- +
- +static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
- + struct snd_pcm_hw_params *params)
- +{
- + return snd_pcm_lib_alloc_vmalloc_buffer(substream,
- + params_buffer_bytes(params));
- +}
- +
- +static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
- +{
- + struct snd_pcm_runtime *runtime = substream->runtime;
- + struct snd_dw_hdmi *dw = substream->private_data;
- + uint8_t threshold, conf0, conf1;
- +
- + /* Setup as per 3.0.5 FSL 4.1.0 BSP */
- + switch (dw->revision) {
- + case 0x0a:
- + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
- + HDMI_AHB_DMA_CONF0_INCR4;
- + if (runtime->channels == 2)
- + threshold = 126;
- + else
- + threshold = 124;
- + break;
- + case 0x1a:
- + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
- + HDMI_AHB_DMA_CONF0_INCR8;
- + threshold = 128;
- + break;
- + default:
- + /* NOTREACHED */
- + return -EINVAL;
- + }
- +
- + dw->data.set_sample_rate(dw->data.hdmi, runtime->rate);
- +
- + /* Minimum number of bytes in the fifo. */
- + runtime->hw.fifo_size = threshold * 32;
- +
- + conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
- + conf1 = (1 << runtime->channels) - 1;
- +
- + writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD);
- + writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0);
- + writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1);
- +
- + switch (runtime->format) {
- + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
- + dw->reformat = dw_hdmi_reformat_iec958;
- + break;
- + case SNDRV_PCM_FORMAT_S24_LE:
- + dw_hdmi_create_cs(dw, runtime);
- + dw->reformat = dw_hdmi_reformat_s24;
- + break;
- + }
- + dw->iec_offset = 0;
- + dw->channels = runtime->channels;
- + dw->buf_src = runtime->dma_area;
- + dw->buf_dst = substream->dma_buffer.area;
- + dw->buf_addr = substream->dma_buffer.addr;
- + dw->buf_period = snd_pcm_lib_period_bytes(substream);
- + dw->buf_size = snd_pcm_lib_buffer_bytes(substream);
- +
- + return 0;
- +}
- +
- +static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
- +{
- + struct snd_dw_hdmi *dw = substream->private_data;
- + void __iomem *base = dw->data.base;
- + unsigned n[3], cts[3];
- + int ret = 0, i;
- + bool err005174;
- +
- + switch (cmd) {
- + case SNDRV_PCM_TRIGGER_START:
- + err005174 = dw->revision == 0x0a;
- + if (err005174) {
- + for (i = 2; i >= 1; i--) {
- + n[i] = readb_relaxed(base + HDMI_AUD_N1 + i);
- + cts[i] = readb_relaxed(base + HDMI_AUD_CTS1 + i);
- + writeb_relaxed(0, base + HDMI_AUD_N1 + i);
- + writeb_relaxed(0, base + HDMI_AUD_CTS1 + i);
- + }
- + }
- +
- + dw->buf_offset = 0;
- + dw->substream = substream;
- + dw_hdmi_start_dma(dw);
- +
- + if (err005174) {
- + for (i = 2; i >= 1; i--)
- + writeb_relaxed(cts[i], base + HDMI_AUD_CTS1 + i);
- + for (i = 2; i >= 1; i--)
- + writeb_relaxed(n[i], base + HDMI_AUD_N1 + i);
- + }
- +
- + substream->runtime->delay = substream->runtime->period_size;
- + break;
- +
- + case SNDRV_PCM_TRIGGER_STOP:
- + dw_hdmi_stop_dma(dw);
- + break;
- +
- + default:
- + ret = -EINVAL;
- + break;
- + }
- +
- + return ret;
- +}
- +
- +static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream)
- +{
- + struct snd_pcm_runtime *runtime = substream->runtime;
- + struct snd_dw_hdmi *dw = substream->private_data;
- +
- + return bytes_to_frames(runtime, dw->buf_offset);
- +}
- +
- +static struct snd_pcm_ops snd_dw_hdmi_ops = {
- + .open = dw_hdmi_open,
- + .close = dw_hdmi_close,
- + .ioctl = snd_pcm_lib_ioctl,
- + .hw_params = dw_hdmi_hw_params,
- + .hw_free = dw_hdmi_hw_free,
- + .prepare = dw_hdmi_prepare,
- + .trigger = dw_hdmi_trigger,
- + .pointer = dw_hdmi_pointer,
- + .page = snd_pcm_lib_get_vmalloc_page,
- +};
- +
- +static int snd_dw_hdmi_probe(struct platform_device *pdev)
- +{
- + const struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
- + struct device *dev = pdev->dev.parent;
- + struct snd_dw_hdmi *dw;
- + struct snd_card *card;
- + struct snd_pcm *pcm;
- + unsigned revision;
- + int ret;
- +
- + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
- + data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
- + revision = readb_relaxed(data->base + HDMI_REVISION_ID);
- + if (revision != 0x0a && revision != 0x1a) {
- + dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
- + revision);
- + return -ENXIO;
- + }
- +
- + ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- + THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);
- + if (ret < 0)
- + return ret;
- +
- + strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
- + strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname));
- + snprintf(card->longname, sizeof(card->longname),
- + "%s rev 0x%02x, irq %d", card->shortname, revision,
- + data->irq);
- +
- + dw = card->private_data;
- + dw->card = card;
- + dw->data = *data;
- + dw->revision = revision;
- +
- + ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm);
- + if (ret < 0)
- + goto err;
- +
- + dw->pcm = pcm;
- + pcm->private_data = dw;
- + strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
- + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops);
- +
- + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- + dev, 64 * 1024, 64 * 1024);
- +
- + ret = snd_card_register(card);
- + if (ret < 0)
- + goto err;
- +
- + platform_set_drvdata(pdev, dw);
- +
- + return 0;
- +
- +err:
- + snd_card_free(card);
- + return ret;
- +}
- +
- +static int snd_dw_hdmi_remove(struct platform_device *pdev)
- +{
- + struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
- +
- + snd_card_free(dw->card);
- +
- + return 0;
- +}
- +
- +#ifdef CONFIG_PM_SLEEP
- +static int snd_dw_hdmi_suspend(struct device *dev)
- +{
- + struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
- +
- + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold);
- + snd_pcm_suspend_all(dw->pcm);
- +
- + return 0;
- +}
- +
- +static int snd_dw_hdmi_resume(struct device *dev)
- +{
- + struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
- +
- + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0);
- +
- + return 0;
- +}
- +
- +static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend,
- + snd_dw_hdmi_resume);
- +#define PM_OPS &snd_dw_hdmi_pm
- +#else
- +#define PM_OPS NULL
- +#endif
- +
- +static struct platform_driver snd_dw_hdmi_driver = {
- + .probe = snd_dw_hdmi_probe,
- + .remove = snd_dw_hdmi_remove,
- + .driver = {
- + .name = "dw-hdmi-audio",
- + .owner = THIS_MODULE,
- + .pm = PM_OPS,
- + },
- +};
- +
- +module_platform_driver(snd_dw_hdmi_driver);
- +
- +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
- +MODULE_LICENSE("GPL");
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.h linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.h
- --- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-audio.h 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-audio.h 2014-10-23 12:36:44.258220010 -0500
- @@ -0,0 +1,15 @@
- +#ifndef DW_HDMI_AUDIO_H
- +#define DW_HDMI_AUDIO_H
- +
- +struct imx_hdmi;
- +
- +struct dw_hdmi_audio_data {
- + phys_addr_t phys;
- + void __iomem *base;
- + int irq;
- + struct imx_hdmi *hdmi;
- + u8 *eld;
- + void (*set_sample_rate)(struct imx_hdmi *, unsigned);
- +};
- +
- +#endif
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.c linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.c 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.c 2014-10-23 12:37:23.890220362 -0500
- @@ -0,0 +1,207 @@
- +/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */
- +#include <linux/cec-dev.h>
- +#include <linux/interrupt.h>
- +#include <linux/io.h>
- +#include <linux/module.h>
- +#include <linux/platform_device.h>
- +#include <linux/sched.h>
- +#include <linux/slab.h>
- +
- +#include "imx-hdmi.h"
- +#include "dw-hdmi-cec.h"
- +
- +#define DEV_NAME "mxc_hdmi_cec"
- +
- +enum {
- + CEC_STAT_DONE = BIT(0),
- + CEC_STAT_EOM = BIT(1),
- + CEC_STAT_NACK = BIT(2),
- + CEC_STAT_ARBLOST = BIT(3),
- + CEC_STAT_ERROR_INIT = BIT(4),
- + CEC_STAT_ERROR_FOLL = BIT(5),
- + CEC_STAT_WAKEUP = BIT(6),
- +
- + CEC_CTRL_START = BIT(0),
- + CEC_CTRL_NORMAL = 1 << 1,
- +};
- +
- +struct dw_hdmi_cec {
- + struct cec_dev cec;
- +
- + struct device *dev;
- + void __iomem *base;
- + const struct dw_hdmi_cec_ops *ops;
- + void *ops_data;
- + int irq;
- +};
- +
- +static void dw_hdmi_set_address(struct cec_dev *cec_dev, unsigned addresses)
- +{
- + struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
- +
- + writeb(addresses & 255, cec->base + HDMI_CEC_ADDR_L);
- + writeb(addresses >> 8, cec->base + HDMI_CEC_ADDR_H);
- +}
- +
- +static void dw_hdmi_send_message(struct cec_dev *cec_dev, u8 *msg,
- + size_t count)
- +{
- + struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
- + unsigned i;
- +
- + for (i = 0; i < count; i++)
- + writeb(msg[i], cec->base + HDMI_CEC_TX_DATA0 + i);
- +
- + writeb(count, cec->base + HDMI_CEC_TX_CNT);
- + writeb(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
- +}
- +
- +static irqreturn_t dw_hdmi_cec_irq(int irq, void *data)
- +{
- + struct dw_hdmi_cec *cec = data;
- + struct cec_dev *cec_dev = &cec->cec;
- + unsigned stat = readb(cec->base + HDMI_IH_CEC_STAT0);
- +
- + if (stat == 0)
- + return IRQ_NONE;
- +
- + writeb(stat, cec->base + HDMI_IH_CEC_STAT0);
- +
- + if (stat & CEC_STAT_ERROR_INIT) {
- + if (cec->cec.retries) {
- + unsigned v = readb(cec->base + HDMI_CEC_CTRL);
- + writeb(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
- + cec->cec.retries -= 1;
- + } else {
- + cec->cec.write_busy = 0;
- + cec_dev_event(cec_dev, MESSAGE_TYPE_SEND_ERROR, NULL, 0);
- + }
- + } else if (stat & (CEC_STAT_DONE | CEC_STAT_NACK))
- + cec_dev_send_complete(cec_dev, stat & CEC_STAT_DONE);
- +
- + if (stat & CEC_STAT_EOM) {
- + unsigned len, i;
- + u8 msg[MAX_MESSAGE_LEN];
- +
- + len = readb(cec->base + HDMI_CEC_RX_CNT);
- + if (len > sizeof(msg))
- + len = sizeof(msg);
- +
- + for (i = 0; i < len; i++)
- + msg[i] = readb(cec->base + HDMI_CEC_RX_DATA0 + i);
- +
- + writeb(0, cec->base + HDMI_CEC_LOCK);
- +
- + cec_dev_receive(cec_dev, msg, len);
- + }
- +
- + return IRQ_HANDLED;
- +}
- +EXPORT_SYMBOL(dw_hdmi_cec_irq);
- +
- +static void dw_hdmi_cec_release(struct cec_dev *cec_dev)
- +{
- + struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
- +
- + writeb(~0, cec->base + HDMI_CEC_MASK);
- + writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
- + writeb(0, cec->base + HDMI_CEC_POLARITY);
- +
- + free_irq(cec->irq, cec);
- +
- + cec->ops->disable(cec->ops_data);
- +}
- +
- +static int dw_hdmi_cec_open(struct cec_dev *cec_dev)
- +{
- + struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
- + unsigned irqs;
- + int ret;
- +
- + writeb(0, cec->base + HDMI_CEC_CTRL);
- + writeb(~0, cec->base + HDMI_IH_CEC_STAT0);
- + writeb(0, cec->base + HDMI_CEC_LOCK);
- +
- + ret = request_irq(cec->irq, dw_hdmi_cec_irq, IRQF_SHARED,
- + DEV_NAME, cec);
- + if (ret < 0)
- + return ret;
- +
- + dw_hdmi_set_address(cec_dev, cec_dev->addresses);
- +
- + cec->ops->enable(cec->ops_data);
- +
- + irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM |
- + CEC_STAT_DONE;
- + writeb(irqs, cec->base + HDMI_CEC_POLARITY);
- + writeb(~irqs, cec->base + HDMI_CEC_MASK);
- + writeb(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0);
- +
- + return 0;
- +}
- +
- +static int dw_hdmi_cec_probe(struct platform_device *pdev)
- +{
- + struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev);
- + struct dw_hdmi_cec *cec;
- +
- + if (!data)
- + return -ENXIO;
- +
- + cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
- + if (!cec)
- + return -ENOMEM;
- +
- + cec->dev = &pdev->dev;
- + cec->base = data->base;
- + cec->irq = data->irq;
- + cec->ops = data->ops;
- + cec->ops_data = data->ops_data;
- + cec->cec.open = dw_hdmi_cec_open;
- + cec->cec.release = dw_hdmi_cec_release;
- + cec->cec.send_message = dw_hdmi_send_message;
- + cec->cec.set_address = dw_hdmi_set_address;
- +
- + cec_dev_init(&cec->cec, THIS_MODULE);
- +
- + /* FIXME: soft-reset the CEC interface */
- +
- + dw_hdmi_set_address(&cec->cec, cec->cec.addresses);
- + writeb(0, cec->base + HDMI_CEC_TX_CNT);
- + writeb(~0, cec->base + HDMI_CEC_MASK);
- + writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
- + writeb(0, cec->base + HDMI_CEC_POLARITY);
- +
- + platform_set_drvdata(pdev, cec);
- +
- + /*
- + * Our device is just a convenience - we want to link to the real
- + * hardware device here, so that userspace can see the association
- + * between the HDMI hardware and its associated CEC chardev.
- + */
- + return cec_dev_add(&cec->cec, cec->dev->parent, DEV_NAME);
- +}
- +
- +static int dw_hdmi_cec_remove(struct platform_device *pdev)
- +{
- + struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
- +
- + cec_dev_remove(&cec->cec);
- +
- + return 0;
- +}
- +
- +static struct platform_driver dw_hdmi_cec_driver = {
- + .probe = dw_hdmi_cec_probe,
- + .remove = dw_hdmi_cec_remove,
- + .driver = {
- + .name = "dw-hdmi-cec",
- + .owner = THIS_MODULE,
- + },
- +};
- +module_platform_driver(dw_hdmi_cec_driver);
- +
- +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
- +MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX");
- +MODULE_LICENSE("GPL");
- +MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec");
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.h linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.h
- --- linux-3.16.6.orig/drivers/staging/imx-drm/dw-hdmi-cec.h 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/dw-hdmi-cec.h 2014-10-23 12:37:23.890220362 -0500
- @@ -0,0 +1,16 @@
- +#ifndef DW_HDMI_CEC_H
- +#define DW_HDMI_CEC_H
- +
- +struct dw_hdmi_cec_ops {
- + void (*enable)(void *);
- + void (*disable)(void *);
- +};
- +
- +struct dw_hdmi_cec_data {
- + void __iomem *base;
- + int irq;
- + const struct dw_hdmi_cec_ops *ops;
- + void *ops_data;
- +};
- +
- +#endif
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm-core.c linux-3.16.6/drivers/staging/imx-drm/imx-drm-core.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm-core.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/imx-drm-core.c 2014-10-23 12:37:37.690220197 -0500
- @@ -115,8 +115,7 @@
- helper = &imx_crtc->imx_drm_helper_funcs;
- if (helper->set_interface_pix_fmt)
- return helper->set_interface_pix_fmt(encoder->crtc,
- - encoder->encoder_type, interface_pix_fmt,
- - hsync_pin, vsync_pin);
- + interface_pix_fmt, hsync_pin, vsync_pin);
- return 0;
- }
- EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm.h linux-3.16.6/drivers/staging/imx-drm/imx-drm.h
- --- linux-3.16.6.orig/drivers/staging/imx-drm/imx-drm.h 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/imx-drm.h 2014-10-23 12:37:37.690220197 -0500
- @@ -17,7 +17,7 @@
- struct imx_drm_crtc_helper_funcs {
- int (*enable_vblank)(struct drm_crtc *crtc);
- void (*disable_vblank)(struct drm_crtc *crtc);
- - int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
- + int (*set_interface_pix_fmt)(struct drm_crtc *crtc,
- u32 pix_fmt, int hsync_pin, int vsync_pin);
- const struct drm_crtc_helper_funcs *crtc_helper_funcs;
- const struct drm_crtc_funcs *crtc_funcs;
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-hdmi.c linux-3.16.6/drivers/staging/imx-drm/imx-hdmi.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/imx-hdmi.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/imx-hdmi.c 2014-10-23 12:37:30.178219970 -0500
- @@ -29,6 +29,9 @@
- #include <drm/drm_encoder_slave.h>
- #include <video/imx-ipu-v3.h>
-
- +#include "drm-ddc-connector.h"
- +#include "dw-hdmi-audio.h"
- +#include "dw-hdmi-cec.h"
- #include "imx-hdmi.h"
- #include "imx-drm.h"
-
- @@ -112,9 +115,11 @@
- };
-
- struct imx_hdmi {
- - struct drm_connector connector;
- + struct drm_ddc_connector *ddc_conn;
- struct drm_encoder encoder;
-
- + struct platform_device *audio;
- + struct platform_device *cec;
- enum imx_hdmi_devtype dev_type;
- struct device *dev;
- struct clk *isfr_clk;
- @@ -124,13 +129,13 @@
- int vic;
-
- u8 edid[HDMI_EDID_LEN];
- + u8 mc_clkdis;
- bool cable_plugin;
-
- bool phy_enabled;
- struct drm_display_mode previous_mode;
-
- struct regmap *regmap;
- - struct i2c_adapter *ddc;
- void __iomem *regs;
-
- unsigned int sample_rate;
- @@ -361,6 +366,12 @@
- hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
- }
-
- +static void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned rate)
- +{
- + hdmi->sample_rate = rate;
- + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
- +}
- +
- /*
- * this submodule is responsible for the video data synchronization.
- * for example, for RGB 4:4:4 input, the data map is defined as
- @@ -1144,8 +1155,6 @@
- /* HDMI Initialization Step B.4 */
- static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
- {
- - u8 clkdis;
- -
- /* control period minimum duration */
- hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
- hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
- @@ -1157,23 +1166,28 @@
- hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
-
- /* Enable pixel clock and tmds data path */
- - clkdis = 0x7F;
- - clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
- + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE |
- + HDMI_MC_CLKDIS_CSCCLK_DISABLE |
- + HDMI_MC_CLKDIS_AUDCLK_DISABLE |
- + HDMI_MC_CLKDIS_PREPCLK_DISABLE |
- + HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
-
- - clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
-
- /* Enable csc path */
- if (is_color_space_conversion(hdmi)) {
- - clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
- - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- }
- }
-
- static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
- {
- - hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- }
-
- /* Workaround to clear the overflow condition */
- @@ -1376,43 +1390,16 @@
- static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
- *connector, bool force)
- {
- - struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- - connector);
- + struct imx_hdmi *hdmi = drm_ddc_private(connector);
-
- return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
- connector_status_connected : connector_status_disconnected;
- }
-
- -static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
- -{
- - struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- - connector);
- - struct edid *edid;
- - int ret;
- -
- - if (!hdmi->ddc)
- - return 0;
- -
- - edid = drm_get_edid(connector, hdmi->ddc);
- - if (edid) {
- - dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
- - edid->width_cm, edid->height_cm);
- -
- - drm_mode_connector_update_edid_property(connector, edid);
- - ret = drm_add_edid_modes(connector, edid);
- - kfree(edid);
- - } else {
- - dev_dbg(hdmi->dev, "failed to get edid\n");
- - }
- -
- - return 0;
- -}
- -
- static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
- *connector)
- {
- - struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- - connector);
- + struct imx_hdmi *hdmi = drm_ddc_private(connector);
-
- return &hdmi->encoder;
- }
- @@ -1485,11 +1472,11 @@
- .dpms = drm_helper_connector_dpms,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .detect = imx_hdmi_connector_detect,
- - .destroy = imx_drm_connector_destroy,
- + .destroy = drm_ddc_connector_destroy,
- };
-
- static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
- - .get_modes = imx_hdmi_connector_get_modes,
- + .get_modes = drm_ddc_connector_get_modes,
- .best_encoder = imx_hdmi_connector_best_encoder,
- };
-
- @@ -1530,7 +1517,7 @@
-
- imx_hdmi_poweroff(hdmi);
- }
- - drm_helper_hpd_irq_event(hdmi->connector.dev);
- + drm_helper_hpd_irq_event(hdmi->ddc_conn->connector.dev);
- }
-
- hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
- @@ -1548,24 +1535,43 @@
- if (ret)
- return ret;
-
- - hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
- + hdmi->ddc_conn->connector.polled = DRM_CONNECTOR_POLL_HPD;
-
- drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
-
- - drm_connector_helper_add(&hdmi->connector,
- + drm_connector_helper_add(&hdmi->ddc_conn->connector,
- &imx_hdmi_connector_helper_funcs);
- - drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
- - DRM_MODE_CONNECTOR_HDMIA);
- + drm_ddc_connector_add(drm, hdmi->ddc_conn, &imx_hdmi_connector_funcs,
- + DRM_MODE_CONNECTOR_HDMIA);
-
- - hdmi->connector.encoder = &hdmi->encoder;
- -
- - drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
- + drm_mode_connector_attach_encoder(&hdmi->ddc_conn->connector, &hdmi->encoder);
-
- return 0;
- }
-
- +static void imx_hdmi_cec_enable(void *data)
- +{
- + struct imx_hdmi *hdmi = data;
- +
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- +}
- +
- +static void imx_hdmi_cec_disable(void *data)
- +{
- + struct imx_hdmi *hdmi = data;
- +
- + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- +}
- +
- +static const struct dw_hdmi_cec_ops imx_hdmi_cec_ops = {
- + .enable = imx_hdmi_cec_enable,
- + .disable = imx_hdmi_cec_disable,
- +};
- +
- static struct platform_device_id imx_hdmi_devtype[] = {
- {
- .name = "imx6q-hdmi",
- @@ -1587,11 +1593,13 @@
- static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
- {
- struct platform_device *pdev = to_platform_device(dev);
- + struct platform_device_info pdevinfo;
- const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, dev);
- struct drm_device *drm = data;
- struct device_node *np = dev->of_node;
- - struct device_node *ddc_node;
- + struct dw_hdmi_audio_data audio;
- + struct dw_hdmi_cec_data cec;
- struct imx_hdmi *hdmi;
- struct resource *iores;
- int ret, irq;
- @@ -1600,9 +1608,14 @@
- if (!hdmi)
- return -ENOMEM;
-
- + hdmi->ddc_conn = drm_ddc_connector_create(drm, np, hdmi);
- + if (IS_ERR(hdmi->ddc_conn))
- + return PTR_ERR(hdmi->ddc_conn);
- +
- hdmi->dev = dev;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
- + hdmi->mc_clkdis = 0x7f;
-
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
- @@ -1610,17 +1623,6 @@
- hdmi->dev_type = device_id->driver_data;
- }
-
- - ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
- - if (ddc_node) {
- - hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
- - if (!hdmi->ddc)
- - dev_dbg(hdmi->dev, "failed to read ddc node\n");
- -
- - of_node_put(ddc_node);
- - } else {
- - dev_dbg(hdmi->dev, "no ddc property found\n");
- - }
- -
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
- @@ -1706,6 +1708,35 @@
- /* Unmute interrupts */
- hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
- + memset(&pdevinfo, 0, sizeof(pdevinfo));
- + pdevinfo.parent = dev;
- + pdevinfo.id = PLATFORM_DEVID_AUTO;
- +
- + audio.phys = iores->start;
- + audio.base = hdmi->regs;
- + audio.irq = irq;
- + audio.hdmi = hdmi;
- + audio.eld = hdmi->ddc_conn->connector.eld;
- + audio.set_sample_rate = imx_hdmi_set_sample_rate;
- +
- + pdevinfo.name = "dw-hdmi-audio";
- + pdevinfo.data = &audio;
- + pdevinfo.size_data = sizeof(audio);
- + pdevinfo.dma_mask = DMA_BIT_MASK(32);
- + hdmi->audio = platform_device_register_full(&pdevinfo);
- +
- + cec.base = hdmi->regs;
- + cec.irq = irq;
- + cec.ops = &imx_hdmi_cec_ops;
- + cec.ops_data = hdmi;
- +
- + pdevinfo.name = "dw-hdmi-cec";
- + pdevinfo.data = &cec;
- + pdevinfo.size_data = sizeof(cec);
- + pdevinfo.dma_mask = 0;
- +
- + hdmi->cec = platform_device_register_full(&pdevinfo);
- +
- dev_set_drvdata(dev, hdmi);
-
- return 0;
- @@ -1723,15 +1754,18 @@
- {
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
-
- + if (!IS_ERR(hdmi->audio))
- + platform_device_unregister(hdmi->audio);
- + if (!IS_ERR(hdmi->cec))
- + platform_device_unregister(hdmi->cec);
- +
- /* Disable all interrupts */
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-
- - hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
- clk_disable_unprepare(hdmi->iahb_clk);
- clk_disable_unprepare(hdmi->isfr_clk);
- - i2c_put_adapter(hdmi->ddc);
- }
-
- static const struct component_ops hdmi_ops = {
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-ldb.c linux-3.16.6/drivers/staging/imx-drm/imx-ldb.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/imx-ldb.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/imx-ldb.c 2014-10-23 12:35:16.922220006 -0500
- @@ -24,6 +24,7 @@
- #include <drm/drmP.h>
- #include <drm/drm_fb_helper.h>
- #include <drm/drm_crtc_helper.h>
- +#include <drm/drm_panel.h>
- #include <linux/mfd/syscon.h>
- #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
- #include <linux/of_address.h>
- @@ -60,6 +61,7 @@
- struct imx_ldb *ldb;
- struct drm_connector connector;
- struct drm_encoder encoder;
- + struct drm_panel *panel;
- struct device_node *child;
- int chno;
- void *edid;
- @@ -96,6 +98,13 @@
- struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
- int num_modes = 0;
-
- + if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs &&
- + imx_ldb_ch->panel->funcs->get_modes) {
- + num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel);
- + if (num_modes > 0)
- + return num_modes;
- + }
- +
- if (imx_ldb_ch->edid) {
- drm_mode_connector_update_edid_property(connector,
- imx_ldb_ch->edid);
- @@ -243,6 +252,8 @@
- }
-
- regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
- +
- + drm_panel_enable(imx_ldb_ch->panel);
- }
-
- static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
- @@ -294,6 +305,8 @@
- (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
- return;
-
- + drm_panel_disable(imx_ldb_ch->panel);
- +
- if (imx_ldb_ch == &ldb->channel[0])
- ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
- else if (imx_ldb_ch == &ldb->channel[1])
- @@ -378,6 +391,9 @@
- drm_connector_init(drm, &imx_ldb_ch->connector,
- &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
-
- + if (imx_ldb_ch->panel)
- + drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector);
- +
- drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
- &imx_ldb_ch->encoder);
-
- @@ -492,6 +508,7 @@
-
- for_each_child_of_node(np, child) {
- struct imx_ldb_channel *channel;
- + struct device_node *panel_node;
-
- ret = of_property_read_u32(child, "reg", &i);
- if (ret || i < 0 || i > 1)
- @@ -555,6 +572,10 @@
- return -EINVAL;
- }
-
- + panel_node = of_parse_phandle(child, "fsl,panel", 0);
- + if (panel_node)
- + channel->panel = of_drm_find_panel(panel_node);
- +
- ret = imx_ldb_register(drm, channel);
- if (ret)
- return ret;
- @@ -574,9 +595,6 @@
- for (i = 0; i < 2; i++) {
- struct imx_ldb_channel *channel = &imx_ldb->channel[i];
-
- - if (!channel->connector.funcs)
- - continue;
- -
- channel->connector.funcs->destroy(&channel->connector);
- channel->encoder.funcs->destroy(&channel->encoder);
- }
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-ldb.c.orig linux-3.16.6/drivers/staging/imx-drm/imx-ldb.c.orig
- --- linux-3.16.6.orig/drivers/staging/imx-drm/imx-ldb.c.orig 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/imx-ldb.c.orig 2014-10-15 05:05:43.000000000 -0500
- @@ -0,0 +1,616 @@
- +/*
- + * i.MX drm driver - LVDS display bridge
- + *
- + * Copyright (C) 2012 Sascha Hauer, Pengutronix
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2
- + * of the License, or (at your option) any later version.
- + * 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.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- + * MA 02110-1301, USA.
- + */
- +
- +#include <linux/module.h>
- +#include <linux/clk.h>
- +#include <linux/component.h>
- +#include <drm/drmP.h>
- +#include <drm/drm_fb_helper.h>
- +#include <drm/drm_crtc_helper.h>
- +#include <linux/mfd/syscon.h>
- +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
- +#include <linux/of_address.h>
- +#include <linux/of_device.h>
- +#include <video/of_videomode.h>
- +#include <linux/regmap.h>
- +#include <linux/videodev2.h>
- +
- +#include "imx-drm.h"
- +
- +#define DRIVER_NAME "imx-ldb"
- +
- +#define LDB_CH0_MODE_EN_TO_DI0 (1 << 0)
- +#define LDB_CH0_MODE_EN_TO_DI1 (3 << 0)
- +#define LDB_CH0_MODE_EN_MASK (3 << 0)
- +#define LDB_CH1_MODE_EN_TO_DI0 (1 << 2)
- +#define LDB_CH1_MODE_EN_TO_DI1 (3 << 2)
- +#define LDB_CH1_MODE_EN_MASK (3 << 2)
- +#define LDB_SPLIT_MODE_EN (1 << 4)
- +#define LDB_DATA_WIDTH_CH0_24 (1 << 5)
- +#define LDB_BIT_MAP_CH0_JEIDA (1 << 6)
- +#define LDB_DATA_WIDTH_CH1_24 (1 << 7)
- +#define LDB_BIT_MAP_CH1_JEIDA (1 << 8)
- +#define LDB_DI0_VS_POL_ACT_LOW (1 << 9)
- +#define LDB_DI1_VS_POL_ACT_LOW (1 << 10)
- +#define LDB_BGREF_RMODE_INT (1 << 15)
- +
- +#define con_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, connector)
- +#define enc_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, encoder)
- +
- +struct imx_ldb;
- +
- +struct imx_ldb_channel {
- + struct imx_ldb *ldb;
- + struct drm_connector connector;
- + struct drm_encoder encoder;
- + struct device_node *child;
- + int chno;
- + void *edid;
- + int edid_len;
- + struct drm_display_mode mode;
- + int mode_valid;
- +};
- +
- +struct bus_mux {
- + int reg;
- + int shift;
- + int mask;
- +};
- +
- +struct imx_ldb {
- + struct regmap *regmap;
- + struct device *dev;
- + struct imx_ldb_channel channel[2];
- + struct clk *clk[2]; /* our own clock */
- + struct clk *clk_sel[4]; /* parent of display clock */
- + struct clk *clk_pll[2]; /* upstream clock we can adjust */
- + u32 ldb_ctrl;
- + const struct bus_mux *lvds_mux;
- +};
- +
- +static enum drm_connector_status imx_ldb_connector_detect(
- + struct drm_connector *connector, bool force)
- +{
- + return connector_status_connected;
- +}
- +
- +static int imx_ldb_connector_get_modes(struct drm_connector *connector)
- +{
- + struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
- + int num_modes = 0;
- +
- + if (imx_ldb_ch->edid) {
- + drm_mode_connector_update_edid_property(connector,
- + imx_ldb_ch->edid);
- + num_modes = drm_add_edid_modes(connector, imx_ldb_ch->edid);
- + }
- +
- + if (imx_ldb_ch->mode_valid) {
- + struct drm_display_mode *mode;
- +
- + mode = drm_mode_create(connector->dev);
- + if (!mode)
- + return -EINVAL;
- + drm_mode_copy(mode, &imx_ldb_ch->mode);
- + mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
- + drm_mode_probed_add(connector, mode);
- + num_modes++;
- + }
- +
- + return num_modes;
- +}
- +
- +static struct drm_encoder *imx_ldb_connector_best_encoder(
- + struct drm_connector *connector)
- +{
- + struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
- +
- + return &imx_ldb_ch->encoder;
- +}
- +
- +static void imx_ldb_encoder_dpms(struct drm_encoder *encoder, int mode)
- +{
- +}
- +
- +static bool imx_ldb_encoder_mode_fixup(struct drm_encoder *encoder,
- + const struct drm_display_mode *mode,
- + struct drm_display_mode *adjusted_mode)
- +{
- + return true;
- +}
- +
- +static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
- + unsigned long serial_clk, unsigned long di_clk)
- +{
- + int ret;
- +
- + dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
- + clk_get_rate(ldb->clk_pll[chno]), serial_clk);
- + clk_set_rate(ldb->clk_pll[chno], serial_clk);
- +
- + dev_dbg(ldb->dev, "%s after: %ld\n", __func__,
- + clk_get_rate(ldb->clk_pll[chno]));
- +
- + dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
- + clk_get_rate(ldb->clk[chno]),
- + (long int)di_clk);
- + clk_set_rate(ldb->clk[chno], di_clk);
- +
- + dev_dbg(ldb->dev, "%s after: %ld\n", __func__,
- + clk_get_rate(ldb->clk[chno]));
- +
- + /* set display clock mux to LDB input clock */
- + ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk[chno]);
- + if (ret)
- + dev_err(ldb->dev,
- + "unable to set di%d parent clock to ldb_di%d\n", mux,
- + chno);
- +}
- +
- +static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
- +{
- + struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
- + struct imx_ldb *ldb = imx_ldb_ch->ldb;
- + struct drm_display_mode *mode = &encoder->crtc->mode;
- + u32 pixel_fmt;
- + unsigned long serial_clk;
- + unsigned long di_clk = mode->clock * 1000;
- + int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
- +
- + if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
- + /* dual channel LVDS mode */
- + serial_clk = 3500UL * mode->clock;
- + imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
- + imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
- + } else {
- + serial_clk = 7000UL * mode->clock;
- + imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
- + di_clk);
- + }
- +
- + switch (imx_ldb_ch->chno) {
- + case 0:
- + pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ?
- + V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666;
- + break;
- + case 1:
- + pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ?
- + V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666;
- + break;
- + default:
- + dev_err(ldb->dev, "unable to config di%d panel format\n",
- + imx_ldb_ch->chno);
- + pixel_fmt = V4L2_PIX_FMT_RGB24;
- + }
- +
- + imx_drm_panel_format(encoder, pixel_fmt);
- +}
- +
- +static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
- +{
- + struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
- + struct imx_ldb *ldb = imx_ldb_ch->ldb;
- + int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
- + int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
- +
- + if (dual) {
- + clk_prepare_enable(ldb->clk[0]);
- + clk_prepare_enable(ldb->clk[1]);
- + }
- +
- + if (imx_ldb_ch == &ldb->channel[0] || dual) {
- + ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
- + if (mux == 0 || ldb->lvds_mux)
- + ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI0;
- + else if (mux == 1)
- + ldb->ldb_ctrl |= LDB_CH0_MODE_EN_TO_DI1;
- + }
- + if (imx_ldb_ch == &ldb->channel[1] || dual) {
- + ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
- + if (mux == 1 || ldb->lvds_mux)
- + ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI1;
- + else if (mux == 0)
- + ldb->ldb_ctrl |= LDB_CH1_MODE_EN_TO_DI0;
- + }
- +
- + if (ldb->lvds_mux) {
- + const struct bus_mux *lvds_mux = NULL;
- +
- + if (imx_ldb_ch == &ldb->channel[0])
- + lvds_mux = &ldb->lvds_mux[0];
- + else if (imx_ldb_ch == &ldb->channel[1])
- + lvds_mux = &ldb->lvds_mux[1];
- +
- + regmap_update_bits(ldb->regmap, lvds_mux->reg, lvds_mux->mask,
- + mux << lvds_mux->shift);
- + }
- +
- + regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
- +}
- +
- +static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
- + struct drm_display_mode *mode,
- + struct drm_display_mode *adjusted_mode)
- +{
- + struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
- + struct imx_ldb *ldb = imx_ldb_ch->ldb;
- + int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
- +
- + if (mode->clock > 170000) {
- + dev_warn(ldb->dev,
- + "%s: mode exceeds 170 MHz pixel clock\n", __func__);
- + }
- + if (mode->clock > 85000 && !dual) {
- + dev_warn(ldb->dev,
- + "%s: mode exceeds 85 MHz pixel clock\n", __func__);
- + }
- +
- + /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
- + if (imx_ldb_ch == &ldb->channel[0]) {
- + if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- + ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW;
- + else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
- + ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW;
- + }
- + if (imx_ldb_ch == &ldb->channel[1]) {
- + if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- + ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW;
- + else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
- + ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW;
- + }
- +}
- +
- +static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
- +{
- + struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
- + struct imx_ldb *ldb = imx_ldb_ch->ldb;
- +
- + /*
- + * imx_ldb_encoder_disable is called by
- + * drm_helper_disable_unused_functions without
- + * the encoder being enabled before.
- + */
- + if (imx_ldb_ch == &ldb->channel[0] &&
- + (ldb->ldb_ctrl & LDB_CH0_MODE_EN_MASK) == 0)
- + return;
- + else if (imx_ldb_ch == &ldb->channel[1] &&
- + (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
- + return;
- +
- + if (imx_ldb_ch == &ldb->channel[0])
- + ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
- + else if (imx_ldb_ch == &ldb->channel[1])
- + ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
- +
- + regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
- +
- + if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
- + clk_disable_unprepare(ldb->clk[0]);
- + clk_disable_unprepare(ldb->clk[1]);
- + }
- +}
- +
- +static struct drm_connector_funcs imx_ldb_connector_funcs = {
- + .dpms = drm_helper_connector_dpms,
- + .fill_modes = drm_helper_probe_single_connector_modes,
- + .detect = imx_ldb_connector_detect,
- + .destroy = imx_drm_connector_destroy,
- +};
- +
- +static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
- + .get_modes = imx_ldb_connector_get_modes,
- + .best_encoder = imx_ldb_connector_best_encoder,
- +};
- +
- +static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
- + .destroy = imx_drm_encoder_destroy,
- +};
- +
- +static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
- + .dpms = imx_ldb_encoder_dpms,
- + .mode_fixup = imx_ldb_encoder_mode_fixup,
- + .prepare = imx_ldb_encoder_prepare,
- + .commit = imx_ldb_encoder_commit,
- + .mode_set = imx_ldb_encoder_mode_set,
- + .disable = imx_ldb_encoder_disable,
- +};
- +
- +static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
- +{
- + char clkname[16];
- +
- + snprintf(clkname, sizeof(clkname), "di%d", chno);
- + ldb->clk[chno] = devm_clk_get(ldb->dev, clkname);
- + if (IS_ERR(ldb->clk[chno]))
- + return PTR_ERR(ldb->clk[chno]);
- +
- + snprintf(clkname, sizeof(clkname), "di%d_pll", chno);
- + ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname);
- +
- + return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
- +}
- +
- +static int imx_ldb_register(struct drm_device *drm,
- + struct imx_ldb_channel *imx_ldb_ch)
- +{
- + struct imx_ldb *ldb = imx_ldb_ch->ldb;
- + int ret;
- +
- + ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder,
- + imx_ldb_ch->child);
- + if (ret)
- + return ret;
- +
- + ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
- + if (ret)
- + return ret;
- +
- + if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
- + ret = imx_ldb_get_clk(ldb, 1);
- + if (ret)
- + return ret;
- + }
- +
- + drm_encoder_helper_add(&imx_ldb_ch->encoder,
- + &imx_ldb_encoder_helper_funcs);
- + drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
- + DRM_MODE_ENCODER_LVDS);
- +
- + drm_connector_helper_add(&imx_ldb_ch->connector,
- + &imx_ldb_connector_helper_funcs);
- + drm_connector_init(drm, &imx_ldb_ch->connector,
- + &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
- +
- + drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
- + &imx_ldb_ch->encoder);
- +
- + return 0;
- +}
- +
- +enum {
- + LVDS_BIT_MAP_SPWG,
- + LVDS_BIT_MAP_JEIDA
- +};
- +
- +static const char * const imx_ldb_bit_mappings[] = {
- + [LVDS_BIT_MAP_SPWG] = "spwg",
- + [LVDS_BIT_MAP_JEIDA] = "jeida",
- +};
- +
- +static const int of_get_data_mapping(struct device_node *np)
- +{
- + const char *bm;
- + int ret, i;
- +
- + ret = of_property_read_string(np, "fsl,data-mapping", &bm);
- + if (ret < 0)
- + return ret;
- +
- + for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++)
- + if (!strcasecmp(bm, imx_ldb_bit_mappings[i]))
- + return i;
- +
- + return -EINVAL;
- +}
- +
- +static struct bus_mux imx6q_lvds_mux[2] = {
- + {
- + .reg = IOMUXC_GPR3,
- + .shift = 6,
- + .mask = IMX6Q_GPR3_LVDS0_MUX_CTL_MASK,
- + }, {
- + .reg = IOMUXC_GPR3,
- + .shift = 8,
- + .mask = IMX6Q_GPR3_LVDS1_MUX_CTL_MASK,
- + }
- +};
- +
- +/*
- + * For a device declaring compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb",
- + * of_match_device will walk through this list and take the first entry
- + * matching any of its compatible values. Therefore, the more generic
- + * entries (in this case fsl,imx53-ldb) need to be ordered last.
- + */
- +static const struct of_device_id imx_ldb_dt_ids[] = {
- + { .compatible = "fsl,imx6q-ldb", .data = imx6q_lvds_mux, },
- + { .compatible = "fsl,imx53-ldb", .data = NULL, },
- + { }
- +};
- +MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
- +
- +static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
- +{
- + struct drm_device *drm = data;
- + struct device_node *np = dev->of_node;
- + const struct of_device_id *of_id =
- + of_match_device(imx_ldb_dt_ids, dev);
- + struct device_node *child;
- + const u8 *edidp;
- + struct imx_ldb *imx_ldb;
- + int datawidth;
- + int mapping;
- + int dual;
- + int ret;
- + int i;
- +
- + imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
- + if (!imx_ldb)
- + return -ENOMEM;
- +
- + imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
- + if (IS_ERR(imx_ldb->regmap)) {
- + dev_err(dev, "failed to get parent regmap\n");
- + return PTR_ERR(imx_ldb->regmap);
- + }
- +
- + imx_ldb->dev = dev;
- +
- + if (of_id)
- + imx_ldb->lvds_mux = of_id->data;
- +
- + dual = of_property_read_bool(np, "fsl,dual-channel");
- + if (dual)
- + imx_ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;
- +
- + /*
- + * There are three different possible clock mux configurations:
- + * i.MX53: ipu1_di0_sel, ipu1_di1_sel
- + * i.MX6q: ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, ipu2_di1_sel
- + * i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel
- + * Map them all to di0_sel...di3_sel.
- + */
- + for (i = 0; i < 4; i++) {
- + char clkname[16];
- +
- + sprintf(clkname, "di%d_sel", i);
- + imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev, clkname);
- + if (IS_ERR(imx_ldb->clk_sel[i])) {
- + ret = PTR_ERR(imx_ldb->clk_sel[i]);
- + imx_ldb->clk_sel[i] = NULL;
- + break;
- + }
- + }
- + if (i == 0)
- + return ret;
- +
- + for_each_child_of_node(np, child) {
- + struct imx_ldb_channel *channel;
- +
- + ret = of_property_read_u32(child, "reg", &i);
- + if (ret || i < 0 || i > 1)
- + return -EINVAL;
- +
- + if (dual && i > 0) {
- + dev_warn(dev, "dual-channel mode, ignoring second output\n");
- + continue;
- + }
- +
- + if (!of_device_is_available(child))
- + continue;
- +
- + channel = &imx_ldb->channel[i];
- + channel->ldb = imx_ldb;
- + channel->chno = i;
- + channel->child = child;
- +
- + edidp = of_get_property(child, "edid", &channel->edid_len);
- + if (edidp) {
- + channel->edid = kmemdup(edidp, channel->edid_len,
- + GFP_KERNEL);
- + } else {
- + ret = of_get_drm_display_mode(child, &channel->mode, 0);
- + if (!ret)
- + channel->mode_valid = 1;
- + }
- +
- + ret = of_property_read_u32(child, "fsl,data-width", &datawidth);
- + if (ret)
- + datawidth = 0;
- + else if (datawidth != 18 && datawidth != 24)
- + return -EINVAL;
- +
- + mapping = of_get_data_mapping(child);
- + switch (mapping) {
- + case LVDS_BIT_MAP_SPWG:
- + if (datawidth == 24) {
- + if (i == 0 || dual)
- + imx_ldb->ldb_ctrl |=
- + LDB_DATA_WIDTH_CH0_24;
- + if (i == 1 || dual)
- + imx_ldb->ldb_ctrl |=
- + LDB_DATA_WIDTH_CH1_24;
- + }
- + break;
- + case LVDS_BIT_MAP_JEIDA:
- + if (datawidth == 18) {
- + dev_err(dev, "JEIDA standard only supported in 24 bit\n");
- + return -EINVAL;
- + }
- + if (i == 0 || dual)
- + imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
- + LDB_BIT_MAP_CH0_JEIDA;
- + if (i == 1 || dual)
- + imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
- + LDB_BIT_MAP_CH1_JEIDA;
- + break;
- + default:
- + dev_err(dev, "data mapping not specified or invalid\n");
- + return -EINVAL;
- + }
- +
- + ret = imx_ldb_register(drm, channel);
- + if (ret)
- + return ret;
- + }
- +
- + dev_set_drvdata(dev, imx_ldb);
- +
- + return 0;
- +}
- +
- +static void imx_ldb_unbind(struct device *dev, struct device *master,
- + void *data)
- +{
- + struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
- + int i;
- +
- + for (i = 0; i < 2; i++) {
- + struct imx_ldb_channel *channel = &imx_ldb->channel[i];
- +
- + if (!channel->connector.funcs)
- + continue;
- +
- + channel->connector.funcs->destroy(&channel->connector);
- + channel->encoder.funcs->destroy(&channel->encoder);
- + }
- +}
- +
- +static const struct component_ops imx_ldb_ops = {
- + .bind = imx_ldb_bind,
- + .unbind = imx_ldb_unbind,
- +};
- +
- +static int imx_ldb_probe(struct platform_device *pdev)
- +{
- + return component_add(&pdev->dev, &imx_ldb_ops);
- +}
- +
- +static int imx_ldb_remove(struct platform_device *pdev)
- +{
- + component_del(&pdev->dev, &imx_ldb_ops);
- + return 0;
- +}
- +
- +static struct platform_driver imx_ldb_driver = {
- + .probe = imx_ldb_probe,
- + .remove = imx_ldb_remove,
- + .driver = {
- + .of_match_table = imx_ldb_dt_ids,
- + .name = DRIVER_NAME,
- + .owner = THIS_MODULE,
- + },
- +};
- +
- +module_platform_driver(imx_ldb_driver);
- +
- +MODULE_DESCRIPTION("i.MX LVDS driver");
- +MODULE_AUTHOR("Sascha Hauer, Pengutronix");
- +MODULE_LICENSE("GPL");
- +MODULE_ALIAS("platform:" DRIVER_NAME);
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/imx-tve.c linux-3.16.6/drivers/staging/imx-drm/imx-tve.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/imx-tve.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/imx-tve.c 2014-10-23 12:37:30.182220005 -0500
- @@ -22,7 +22,6 @@
- #include <linux/clk-provider.h>
- #include <linux/component.h>
- #include <linux/module.h>
- -#include <linux/i2c.h>
- #include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
- #include <linux/spinlock.h>
- @@ -32,6 +31,7 @@
- #include <drm/drm_crtc_helper.h>
- #include <video/imx-ipu-v3.h>
-
- +#include "drm-ddc-connector.h"
- #include "imx-drm.h"
-
- #define TVE_COM_CONF_REG 0x00
- @@ -111,7 +111,7 @@
- };
-
- struct imx_tve {
- - struct drm_connector connector;
- + struct drm_ddc_connector *ddc_conn;
- struct drm_encoder encoder;
- struct device *dev;
- spinlock_t lock; /* register lock */
- @@ -120,7 +120,6 @@
-
- struct regmap *regmap;
- struct regulator *dac_reg;
- - struct i2c_adapter *ddc;
- struct clk *clk;
- struct clk *di_sel_clk;
- struct clk_hw clk_hw_di;
- @@ -219,35 +218,10 @@
- return 0;
- }
-
- -static enum drm_connector_status imx_tve_connector_detect(
- - struct drm_connector *connector, bool force)
- -{
- - return connector_status_connected;
- -}
- -
- -static int imx_tve_connector_get_modes(struct drm_connector *connector)
- -{
- - struct imx_tve *tve = con_to_tve(connector);
- - struct edid *edid;
- - int ret = 0;
- -
- - if (!tve->ddc)
- - return 0;
- -
- - edid = drm_get_edid(connector, tve->ddc);
- - if (edid) {
- - drm_mode_connector_update_edid_property(connector, edid);
- - ret = drm_add_edid_modes(connector, edid);
- - kfree(edid);
- - }
- -
- - return ret;
- -}
- -
- static int imx_tve_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
- {
- - struct imx_tve *tve = con_to_tve(connector);
- + struct imx_tve *tve = to_ddc_conn(connector)->private;
- unsigned long rate;
-
- /* pixel clock with 2x oversampling */
- @@ -269,7 +243,7 @@
- static struct drm_encoder *imx_tve_connector_best_encoder(
- struct drm_connector *connector)
- {
- - struct imx_tve *tve = con_to_tve(connector);
- + struct imx_tve *tve = drm_ddc_private(connector);
-
- return &tve->encoder;
- }
- @@ -360,12 +334,12 @@
- static struct drm_connector_funcs imx_tve_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .fill_modes = drm_helper_probe_single_connector_modes,
- - .detect = imx_tve_connector_detect,
- - .destroy = imx_drm_connector_destroy,
- + .detect = drm_ddc_connector_always_connected,
- + .destroy = drm_ddc_connector_destroy,
- };
-
- static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
- - .get_modes = imx_tve_connector_get_modes,
- + .get_modes = drm_ddc_connector_get_modes,
- .best_encoder = imx_tve_connector_best_encoder,
- .mode_valid = imx_tve_connector_mode_valid,
- };
- @@ -508,12 +482,13 @@
- drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
- encoder_type);
-
- - drm_connector_helper_add(&tve->connector,
- + drm_connector_helper_add(&tve->ddc_conn->connector,
- &imx_tve_connector_helper_funcs);
- - drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
- - DRM_MODE_CONNECTOR_VGA);
- + drm_ddc_connector_add(drm, tve->ddc_conn, &imx_tve_connector_funcs,
- + DRM_MODE_CONNECTOR_VGA);
-
- - drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
- + drm_mode_connector_attach_encoder(&tve->ddc_conn->connector,
- + &tve->encoder);
-
- return 0;
- }
- @@ -562,7 +537,6 @@
- struct platform_device *pdev = to_platform_device(dev);
- struct drm_device *drm = data;
- struct device_node *np = dev->of_node;
- - struct device_node *ddc_node;
- struct imx_tve *tve;
- struct resource *res;
- void __iomem *base;
- @@ -574,15 +548,13 @@
- if (!tve)
- return -ENOMEM;
-
- + tve->ddc_conn = drm_ddc_connector_create(drm, np, tve);
- + if (IS_ERR(tve->ddc_conn))
- + return PTR_ERR(tve->ddc_conn);
- +
- tve->dev = dev;
- spin_lock_init(&tve->lock);
-
- - ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
- - if (ddc_node) {
- - tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
- - of_node_put(ddc_node);
- - }
- -
- tve->mode = of_get_tve_mode(np);
- if (tve->mode != TVE_MODE_VGA) {
- dev_err(dev, "only VGA mode supported, currently\n");
- @@ -689,7 +661,6 @@
- {
- struct imx_tve *tve = dev_get_drvdata(dev);
-
- - tve->connector.funcs->destroy(&tve->connector);
- tve->encoder.funcs->destroy(&tve->encoder);
-
- if (!IS_ERR(tve->dac_reg))
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/ipuv3-crtc.c linux-3.16.6/drivers/staging/imx-drm/ipuv3-crtc.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/ipuv3-crtc.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/ipuv3-crtc.c 2014-10-23 12:37:37.690220197 -0500
- @@ -51,7 +51,6 @@
- struct drm_framebuffer *newfb;
- int irq;
- u32 interface_pix_fmt;
- - unsigned long di_clkflags;
- int di_hsync_pin;
- int di_vsync_pin;
- };
- @@ -146,10 +145,13 @@
- int x, int y,
- struct drm_framebuffer *old_fb)
- {
- + struct drm_device *dev = crtc->dev;
- + struct drm_encoder *encoder;
- struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
- - int ret;
- struct ipu_di_signal_cfg sig_cfg = {};
- + unsigned long encoder_types = 0;
- u32 out_pixel_fmt;
- + int ret;
-
- dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
- mode->hdisplay);
- @@ -165,8 +167,26 @@
- if (mode->flags & DRM_MODE_FLAG_PVSYNC)
- sig_cfg.Vsync_pol = 1;
-
- - sig_cfg.enable_pol = 1;
- - sig_cfg.clk_pol = 0;
- + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
- + if (encoder->crtc == crtc)
- + encoder_types |= BIT(encoder->encoder_type);
- +
- + dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n",
- + __func__, encoder_types);
- +
- + /*
- + * If we have DAC, TVDAC or LDB, then we need the IPU DI clock
- + * to be the same as the LDB DI clock.
- + */
- + if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
- + BIT(DRM_MODE_ENCODER_TVDAC) |
- + BIT(DRM_MODE_ENCODER_LVDS)))
- + sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
- + else
- + sig_cfg.clkflags = 0;
- +
- + sig_cfg.enable_pol = ENABLE_POL_HIGH;
- + sig_cfg.clk_pol = CLK_POL_NEGEDGE;
- sig_cfg.width = mode->hdisplay;
- sig_cfg.height = mode->vdisplay;
- sig_cfg.pixel_fmt = out_pixel_fmt;
- @@ -178,7 +198,6 @@
- sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
- sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
- sig_cfg.pixelclock = mode->clock * 1000;
- - sig_cfg.clkflags = ipu_crtc->di_clkflags;
-
- sig_cfg.v_to_h_sync = 0;
-
- @@ -277,7 +296,7 @@
- ipu_crtc->newfb = NULL;
- }
-
- -static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
- +static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
- u32 pixfmt, int hsync_pin, int vsync_pin)
- {
- struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
- @@ -286,19 +305,6 @@
- ipu_crtc->di_hsync_pin = hsync_pin;
- ipu_crtc->di_vsync_pin = vsync_pin;
-
- - switch (encoder_type) {
- - case DRM_MODE_ENCODER_DAC:
- - case DRM_MODE_ENCODER_TVDAC:
- - case DRM_MODE_ENCODER_LVDS:
- - ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
- - IPU_DI_CLKMODE_EXT;
- - break;
- - case DRM_MODE_ENCODER_TMDS:
- - case DRM_MODE_ENCODER_NONE:
- - ipu_crtc->di_clkflags = 0;
- - break;
- - }
- -
- return 0;
- }
-
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/ipuv3-plane.c linux-3.16.6/drivers/staging/imx-drm/ipuv3-plane.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/ipuv3-plane.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/ipuv3-plane.c 2014-10-23 12:35:00.842220709 -0500
- @@ -281,8 +281,7 @@
-
- ipu_idmac_put(ipu_plane->ipu_ch);
- ipu_dmfc_put(ipu_plane->dmfc);
- - if (ipu_plane->dp)
- - ipu_dp_put(ipu_plane->dp);
- + ipu_dp_put(ipu_plane->dp);
- }
- }
-
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/ipuv3-plane.c.orig linux-3.16.6/drivers/staging/imx-drm/ipuv3-plane.c.orig
- --- linux-3.16.6.orig/drivers/staging/imx-drm/ipuv3-plane.c.orig 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/ipuv3-plane.c.orig 2014-10-15 05:05:43.000000000 -0500
- @@ -0,0 +1,388 @@
- +/*
- + * i.MX IPUv3 DP Overlay Planes
- + *
- + * Copyright (C) 2013 Philipp Zabel, Pengutronix
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation; either version 2
- + * of the License, or (at your option) any later version.
- + * 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 <drm/drmP.h>
- +#include <drm/drm_fb_cma_helper.h>
- +#include <drm/drm_gem_cma_helper.h>
- +
- +#include "video/imx-ipu-v3.h"
- +#include "ipuv3-plane.h"
- +
- +#define to_ipu_plane(x) container_of(x, struct ipu_plane, base)
- +
- +static const uint32_t ipu_plane_formats[] = {
- + DRM_FORMAT_XRGB1555,
- + DRM_FORMAT_XBGR1555,
- + DRM_FORMAT_ARGB8888,
- + DRM_FORMAT_XRGB8888,
- + DRM_FORMAT_ABGR8888,
- + DRM_FORMAT_XBGR8888,
- + DRM_FORMAT_YUYV,
- + DRM_FORMAT_YVYU,
- + DRM_FORMAT_YUV420,
- + DRM_FORMAT_YVU420,
- +};
- +
- +int ipu_plane_irq(struct ipu_plane *ipu_plane)
- +{
- + return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
- + IPU_IRQ_EOF);
- +}
- +
- +static int calc_vref(struct drm_display_mode *mode)
- +{
- + unsigned long htotal, vtotal;
- +
- + htotal = mode->htotal;
- + vtotal = mode->vtotal;
- +
- + if (!htotal || !vtotal)
- + return 60;
- +
- + return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
- +}
- +
- +static inline int calc_bandwidth(int width, int height, unsigned int vref)
- +{
- + return width * height * vref;
- +}
- +
- +int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
- + int x, int y)
- +{
- + struct ipu_ch_param __iomem *cpmem;
- + struct drm_gem_cma_object *cma_obj;
- + unsigned long eba;
- +
- + cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
- + if (!cma_obj) {
- + DRM_DEBUG_KMS("entry is null.\n");
- + return -EFAULT;
- + }
- +
- + dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
- + &cma_obj->paddr, x, y);
- +
- + cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
- + ipu_cpmem_set_stride(cpmem, fb->pitches[0]);
- +
- + eba = cma_obj->paddr + fb->offsets[0] +
- + fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
- + ipu_cpmem_set_buffer(cpmem, 0, eba);
- + ipu_cpmem_set_buffer(cpmem, 1, eba);
- +
- + /* cache offsets for subsequent pageflips */
- + ipu_plane->x = x;
- + ipu_plane->y = y;
- +
- + return 0;
- +}
- +
- +int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
- + struct drm_display_mode *mode,
- + struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- + unsigned int crtc_w, unsigned int crtc_h,
- + uint32_t src_x, uint32_t src_y,
- + uint32_t src_w, uint32_t src_h)
- +{
- + struct ipu_ch_param __iomem *cpmem;
- + struct device *dev = ipu_plane->base.dev->dev;
- + int ret;
- +
- + /* no scaling */
- + if (src_w != crtc_w || src_h != crtc_h)
- + return -EINVAL;
- +
- + /* clip to crtc bounds */
- + if (crtc_x < 0) {
- + if (-crtc_x > crtc_w)
- + return -EINVAL;
- + src_x += -crtc_x;
- + src_w -= -crtc_x;
- + crtc_w -= -crtc_x;
- + crtc_x = 0;
- + }
- + if (crtc_y < 0) {
- + if (-crtc_y > crtc_h)
- + return -EINVAL;
- + src_y += -crtc_y;
- + src_h -= -crtc_y;
- + crtc_h -= -crtc_y;
- + crtc_y = 0;
- + }
- + if (crtc_x + crtc_w > mode->hdisplay) {
- + if (crtc_x > mode->hdisplay)
- + return -EINVAL;
- + crtc_w = mode->hdisplay - crtc_x;
- + src_w = crtc_w;
- + }
- + if (crtc_y + crtc_h > mode->vdisplay) {
- + if (crtc_y > mode->vdisplay)
- + return -EINVAL;
- + crtc_h = mode->vdisplay - crtc_y;
- + src_h = crtc_h;
- + }
- + /* full plane minimum width is 13 pixels */
- + if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG))
- + return -EINVAL;
- + if (crtc_h < 2)
- + return -EINVAL;
- +
- + switch (ipu_plane->dp_flow) {
- + case IPU_DP_FLOW_SYNC_BG:
- + ret = ipu_dp_setup_channel(ipu_plane->dp,
- + IPUV3_COLORSPACE_RGB,
- + IPUV3_COLORSPACE_RGB);
- + if (ret) {
- + dev_err(dev,
- + "initializing display processor failed with %d\n",
- + ret);
- + return ret;
- + }
- + ipu_dp_set_global_alpha(ipu_plane->dp, 1, 0, 1);
- + break;
- + case IPU_DP_FLOW_SYNC_FG:
- + ipu_dp_setup_channel(ipu_plane->dp,
- + ipu_drm_fourcc_to_colorspace(fb->pixel_format),
- + IPUV3_COLORSPACE_UNKNOWN);
- + ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
- + break;
- + }
- +
- + ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w);
- + if (ret) {
- + dev_err(dev, "initializing dmfc channel failed with %d\n", ret);
- + return ret;
- + }
- +
- + ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
- + calc_bandwidth(crtc_w, crtc_h,
- + calc_vref(mode)), 64);
- + if (ret) {
- + dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
- + return ret;
- + }
- +
- + cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
- + ipu_ch_param_zero(cpmem);
- + ipu_cpmem_set_resolution(cpmem, src_w, src_h);
- + ret = ipu_cpmem_set_fmt(cpmem, fb->pixel_format);
- + if (ret < 0) {
- + dev_err(dev, "unsupported pixel format 0x%08x\n",
- + fb->pixel_format);
- + return ret;
- + }
- + ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
- +
- + ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
- + if (ret < 0)
- + return ret;
- +
- + return 0;
- +}
- +
- +void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
- +{
- + if (!IS_ERR_OR_NULL(ipu_plane->dp))
- + ipu_dp_put(ipu_plane->dp);
- + if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
- + ipu_dmfc_put(ipu_plane->dmfc);
- + if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
- + ipu_idmac_put(ipu_plane->ipu_ch);
- +}
- +
- +int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
- +{
- + int ret;
- +
- + ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
- + if (IS_ERR(ipu_plane->ipu_ch)) {
- + ret = PTR_ERR(ipu_plane->ipu_ch);
- + DRM_ERROR("failed to get idmac channel: %d\n", ret);
- + return ret;
- + }
- +
- + ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
- + if (IS_ERR(ipu_plane->dmfc)) {
- + ret = PTR_ERR(ipu_plane->dmfc);
- + DRM_ERROR("failed to get dmfc: ret %d\n", ret);
- + goto err_out;
- + }
- +
- + if (ipu_plane->dp_flow >= 0) {
- + ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
- + if (IS_ERR(ipu_plane->dp)) {
- + ret = PTR_ERR(ipu_plane->dp);
- + DRM_ERROR("failed to get dp flow: %d\n", ret);
- + goto err_out;
- + }
- + }
- +
- + return 0;
- +err_out:
- + ipu_plane_put_resources(ipu_plane);
- +
- + return ret;
- +}
- +
- +void ipu_plane_enable(struct ipu_plane *ipu_plane)
- +{
- + if (ipu_plane->dp)
- + ipu_dp_enable(ipu_plane->ipu);
- + ipu_dmfc_enable_channel(ipu_plane->dmfc);
- + ipu_idmac_enable_channel(ipu_plane->ipu_ch);
- + if (ipu_plane->dp)
- + ipu_dp_enable_channel(ipu_plane->dp);
- +
- + ipu_plane->enabled = true;
- +}
- +
- +void ipu_plane_disable(struct ipu_plane *ipu_plane)
- +{
- + ipu_plane->enabled = false;
- +
- + ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
- +
- + if (ipu_plane->dp)
- + ipu_dp_disable_channel(ipu_plane->dp);
- + ipu_idmac_disable_channel(ipu_plane->ipu_ch);
- + ipu_dmfc_disable_channel(ipu_plane->dmfc);
- + if (ipu_plane->dp)
- + ipu_dp_disable(ipu_plane->ipu);
- +}
- +
- +static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode)
- +{
- + bool enable;
- +
- + DRM_DEBUG_KMS("mode = %d", mode);
- +
- + enable = (mode == DRM_MODE_DPMS_ON);
- +
- + if (enable == ipu_plane->enabled)
- + return;
- +
- + if (enable) {
- + ipu_plane_enable(ipu_plane);
- + } else {
- + ipu_plane_disable(ipu_plane);
- +
- + ipu_idmac_put(ipu_plane->ipu_ch);
- + ipu_dmfc_put(ipu_plane->dmfc);
- + if (ipu_plane->dp)
- + ipu_dp_put(ipu_plane->dp);
- + }
- +}
- +
- +/*
- + * drm_plane API
- + */
- +
- +static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
- + struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- + unsigned int crtc_w, unsigned int crtc_h,
- + uint32_t src_x, uint32_t src_y,
- + uint32_t src_w, uint32_t src_h)
- +{
- + struct ipu_plane *ipu_plane = to_ipu_plane(plane);
- + int ret = 0;
- +
- + DRM_DEBUG_KMS("plane - %p\n", plane);
- +
- + if (!ipu_plane->enabled)
- + ret = ipu_plane_get_resources(ipu_plane);
- + if (ret < 0)
- + return ret;
- +
- + ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
- + crtc_x, crtc_y, crtc_w, crtc_h,
- + src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16);
- + if (ret < 0) {
- + ipu_plane_put_resources(ipu_plane);
- + return ret;
- + }
- +
- + if (crtc != plane->crtc)
- + dev_info(plane->dev->dev, "crtc change: %p -> %p\n",
- + plane->crtc, crtc);
- + plane->crtc = crtc;
- +
- + ipu_plane_dpms(ipu_plane, DRM_MODE_DPMS_ON);
- +
- + return 0;
- +}
- +
- +static int ipu_disable_plane(struct drm_plane *plane)
- +{
- + struct ipu_plane *ipu_plane = to_ipu_plane(plane);
- +
- + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
- +
- + ipu_plane_dpms(ipu_plane, DRM_MODE_DPMS_OFF);
- +
- + ipu_plane_put_resources(ipu_plane);
- +
- + return 0;
- +}
- +
- +static void ipu_plane_destroy(struct drm_plane *plane)
- +{
- + struct ipu_plane *ipu_plane = to_ipu_plane(plane);
- +
- + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
- +
- + ipu_disable_plane(plane);
- + drm_plane_cleanup(plane);
- + kfree(ipu_plane);
- +}
- +
- +static struct drm_plane_funcs ipu_plane_funcs = {
- + .update_plane = ipu_update_plane,
- + .disable_plane = ipu_disable_plane,
- + .destroy = ipu_plane_destroy,
- +};
- +
- +struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
- + int dma, int dp, unsigned int possible_crtcs,
- + bool priv)
- +{
- + struct ipu_plane *ipu_plane;
- + int ret;
- +
- + DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
- + dma, dp, possible_crtcs);
- +
- + ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
- + if (!ipu_plane) {
- + DRM_ERROR("failed to allocate plane\n");
- + return ERR_PTR(-ENOMEM);
- + }
- +
- + ipu_plane->ipu = ipu;
- + ipu_plane->dma = dma;
- + ipu_plane->dp_flow = dp;
- +
- + ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
- + &ipu_plane_funcs, ipu_plane_formats,
- + ARRAY_SIZE(ipu_plane_formats),
- + priv);
- + if (ret) {
- + DRM_ERROR("failed to initialize plane\n");
- + kfree(ipu_plane);
- + return ERR_PTR(ret);
- + }
- +
- + return ipu_plane;
- +}
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/Kconfig linux-3.16.6/drivers/staging/imx-drm/Kconfig
- --- linux-3.16.6.orig/drivers/staging/imx-drm/Kconfig 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/Kconfig 2014-10-23 12:37:23.890220362 -0500
- @@ -35,6 +35,7 @@
- config DRM_IMX_LDB
- tristate "Support for LVDS displays"
- depends on DRM_IMX && MFD_SYSCON
- + select DRM_PANEL
- help
- Choose this to enable the internal LVDS Display Bridge (LDB)
- found on i.MX53 and i.MX6 processors.
- @@ -51,3 +52,20 @@
- depends on DRM_IMX
- help
- Choose this if you want to use HDMI on i.MX6.
- +
- +config DRM_DW_HDMI_AUDIO
- + tristate "Synopsis Designware Audio interface"
- + depends on DRM_IMX_HDMI != n
- + help
- + Support the Audio interface which is part of the Synopsis
- + Designware HDMI block. This is used in conjunction with
- + the i.MX HDMI driver.
- +
- +config DRM_DW_HDMI_CEC
- + tristate "Synopsis Designware CEC interface"
- + depends on DRM_IMX_HDMI != n
- + select HDMI_CEC_CORE
- + help
- + Support the CEC interface which is part of the Synposis
- + Designware HDMI block. This is used in conjunction with
- + the i.MX HDMI driver.
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/Kconfig.orig linux-3.16.6/drivers/staging/imx-drm/Kconfig.orig
- --- linux-3.16.6.orig/drivers/staging/imx-drm/Kconfig.orig 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/drivers/staging/imx-drm/Kconfig.orig 2014-10-23 12:35:45.310219999 -0500
- @@ -0,0 +1,62 @@
- +config DRM_IMX
- + tristate "DRM Support for Freescale i.MX"
- + select DRM_KMS_HELPER
- + select DRM_KMS_FB_HELPER
- + select VIDEOMODE_HELPERS
- + select DRM_GEM_CMA_HELPER
- + select DRM_KMS_CMA_HELPER
- + depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
- + help
- + enable i.MX graphics support
- +
- +config DRM_IMX_FB_HELPER
- + tristate "provide legacy framebuffer /dev/fb0"
- + select DRM_KMS_CMA_HELPER
- + depends on DRM_IMX
- + help
- + The DRM framework can provide a legacy /dev/fb0 framebuffer
- + for your device. This is necessary to get a framebuffer console
- + and also for applications using the legacy framebuffer API
- +
- +config DRM_IMX_PARALLEL_DISPLAY
- + tristate "Support for parallel displays"
- + select DRM_PANEL
- + depends on DRM_IMX
- + select VIDEOMODE_HELPERS
- +
- +config DRM_IMX_TVE
- + tristate "Support for TV and VGA displays"
- + depends on DRM_IMX
- + select REGMAP_MMIO
- + help
- + Choose this to enable the internal Television Encoder (TVe)
- + found on i.MX53 processors.
- +
- +config DRM_IMX_LDB
- + tristate "Support for LVDS displays"
- + depends on DRM_IMX && MFD_SYSCON
- + select DRM_PANEL
- + help
- + Choose this to enable the internal LVDS Display Bridge (LDB)
- + found on i.MX53 and i.MX6 processors.
- +
- +config DRM_IMX_IPUV3
- + tristate "DRM Support for i.MX IPUv3"
- + depends on DRM_IMX
- + depends on IMX_IPUV3_CORE
- + help
- + Choose this if you have a i.MX5 or i.MX6 processor.
- +
- +config DRM_IMX_HDMI
- + tristate "Freescale i.MX DRM HDMI"
- + depends on DRM_IMX
- + help
- + Choose this if you want to use HDMI on i.MX6.
- +
- +config DRM_DW_HDMI_AUDIO
- + tristate "Synopsis Designware Audio interface"
- + depends on DRM_IMX_HDMI != n
- + help
- + Support the Audio interface which is part of the Synopsis
- + Designware HDMI block. This is used in conjunction with
- + the i.MX HDMI driver.
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/Makefile linux-3.16.6/drivers/staging/imx-drm/Makefile
- --- linux-3.16.6.orig/drivers/staging/imx-drm/Makefile 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/Makefile 2014-10-23 12:37:30.178219970 -0500
- @@ -3,6 +3,7 @@
-
- obj-$(CONFIG_DRM_IMX) += imxdrm.o
-
- +obj-$(CONFIG_DRM_IMX) += drm-ddc-connector.o
- obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
- obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
- obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
- @@ -10,3 +11,5 @@
- imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
- obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
- obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
- +obj-$(CONFIG_DRM_DW_HDMI_AUDIO) += dw-hdmi-audio.o
- +obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
- diff -Nur linux-3.16.6.orig/drivers/staging/imx-drm/parallel-display.c linux-3.16.6/drivers/staging/imx-drm/parallel-display.c
- --- linux-3.16.6.orig/drivers/staging/imx-drm/parallel-display.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/drivers/staging/imx-drm/parallel-display.c 2014-10-23 12:35:30.986219995 -0500
- @@ -225,6 +225,8 @@
- imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
- else if (!strcmp(fmt, "bgr666"))
- imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
- + else if (!strcmp(fmt, "rgb666"))
- + imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB666;
- else if (!strcmp(fmt, "lvds666"))
- imxpd->interface_pix_fmt = v4l2_fourcc('L', 'V', 'D', '6');
- }
- diff -Nur linux-3.16.6.orig/include/linux/cec-dev.h linux-3.16.6/include/linux/cec-dev.h
- --- linux-3.16.6.orig/include/linux/cec-dev.h 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/include/linux/cec-dev.h 2014-10-23 12:37:18.374219998 -0500
- @@ -0,0 +1,69 @@
- +#ifndef _LINUX_CEC_DEV_H
- +#define _LINUX_CEC_DEV_H
- +
- +#include <linux/cdev.h>
- +#include <linux/list.h>
- +#include <linux/mutex.h>
- +#include <linux/spinlock.h>
- +#include <linux/wait.h>
- +
- +#include <uapi/linux/cec-dev.h>
- +
- +struct device;
- +
- +struct cec_dev {
- + struct cdev cdev;
- + dev_t devn;
- +
- + struct mutex mutex;
- + unsigned users;
- +
- + spinlock_t lock;
- + wait_queue_head_t waitq;
- + struct list_head events;
- + u8 write_busy;
- +
- + u8 retries;
- + u16 addresses;
- + u16 physical;
- +
- + int (*open)(struct cec_dev *);
- + void (*release)(struct cec_dev *);
- + void (*send_message)(struct cec_dev *, u8 *, size_t);
- + void (*set_address)(struct cec_dev *, unsigned);
- +};
- +
- +void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len);
- +
- +static inline void cec_dev_receive(struct cec_dev *cec_dev, u8 *msg,
- + unsigned len)
- +{
- + cec_dev_event(cec_dev, MESSAGE_TYPE_RECEIVE_SUCCESS, msg, len);
- +}
- +
- +static inline void cec_dev_send_complete(struct cec_dev *cec_dev, int ack)
- +{
- + cec_dev->retries = 0;
- + cec_dev->write_busy = 0;
- +
- + cec_dev_event(cec_dev, ack ? MESSAGE_TYPE_SEND_SUCCESS :
- + MESSAGE_TYPE_NOACK, NULL, 0);
- +}
- +
- +static inline void cec_dev_disconnect(struct cec_dev *cec_dev)
- +{
- + cec_dev->physical = 0;
- + cec_dev_event(cec_dev, MESSAGE_TYPE_DISCONNECTED, NULL, 0);
- +}
- +
- +static inline void cec_dev_connect(struct cec_dev *cec_dev, u32 phys)
- +{
- + cec_dev->physical = phys;
- + cec_dev_event(cec_dev, MESSAGE_TYPE_CONNECTED, NULL, 0);
- +}
- +
- +void cec_dev_init(struct cec_dev *cec_dev, struct module *);
- +int cec_dev_add(struct cec_dev *cec_dev, struct device *, const char *name);
- +void cec_dev_remove(struct cec_dev *cec_dev);
- +
- +#endif
- diff -Nur linux-3.16.6.orig/include/linux/mmc/host.h linux-3.16.6/include/linux/mmc/host.h
- --- linux-3.16.6.orig/include/linux/mmc/host.h 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/include/linux/mmc/host.h 2014-10-23 12:34:18.742220000 -0500
- @@ -298,6 +298,11 @@
- unsigned long clkgate_delay;
- #endif
-
- + /* card specific properties to deal with power and reset */
- + struct regulator *card_regulator; /* External VCC needed by the card */
- + struct gpio_desc *card_reset_gpios[2]; /* External resets, active low */
- + struct clk *card_clk; /* External clock needed by the card */
- +
- /* host specific block data */
- unsigned int max_seg_size; /* see blk_queue_max_segment_size */
- unsigned short max_segs; /* see blk_queue_max_segments */
- diff -Nur linux-3.16.6.orig/include/uapi/linux/cec-dev.h linux-3.16.6/include/uapi/linux/cec-dev.h
- --- linux-3.16.6.orig/include/uapi/linux/cec-dev.h 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/include/uapi/linux/cec-dev.h 2014-10-23 12:37:18.374219998 -0500
- @@ -0,0 +1,34 @@
- +#ifndef _UAPI_LINUX_CEC_DEV_H
- +#define _UAPI_LINUX_CEC_DEV_H
- +
- +#include <linux/ioctl.h>
- +#include <linux/types.h>
- +
- +#define MAX_MESSAGE_LEN 16
- +
- +enum {
- + HDMICEC_IOC_MAGIC = 'H',
- + /* This is wrong: we pass the argument as a number, not a pointer */
- + HDMICEC_IOC_O_SETLOGICALADDRESS = _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char),
- + HDMICEC_IOC_SETLOGICALADDRESS = _IO(HDMICEC_IOC_MAGIC, 1),
- + HDMICEC_IOC_STARTDEVICE = _IO(HDMICEC_IOC_MAGIC, 2),
- + HDMICEC_IOC_STOPDEVICE = _IO(HDMICEC_IOC_MAGIC, 3),
- + HDMICEC_IOC_GETPHYADDRESS = _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4]),
- +};
- +
- +enum {
- + MESSAGE_TYPE_RECEIVE_SUCCESS = 1,
- + MESSAGE_TYPE_NOACK,
- + MESSAGE_TYPE_DISCONNECTED,
- + MESSAGE_TYPE_CONNECTED,
- + MESSAGE_TYPE_SEND_SUCCESS,
- + MESSAGE_TYPE_SEND_ERROR,
- +};
- +
- +struct cec_user_event {
- + __u32 event_type;
- + __u32 msg_len;
- + __u8 msg[MAX_MESSAGE_LEN];
- +};
- +
- +#endif
- diff -Nur linux-3.16.6.orig/include/uapi/linux/videodev2.h linux-3.16.6/include/uapi/linux/videodev2.h
- --- linux-3.16.6.orig/include/uapi/linux/videodev2.h 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/include/uapi/linux/videodev2.h 2014-10-23 12:35:23.722220002 -0500
- @@ -299,6 +299,7 @@
- #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */
- #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */
- #define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */
- +#define V4L2_PIX_FMT_RGB666 v4l2_fourcc('R', 'G', 'B', 'H') /* 18 RGB-6-6-6 */
- #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */
- #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
- #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */
- diff -Nur linux-3.16.6.orig/include/video/imx-ipu-v3.h linux-3.16.6/include/video/imx-ipu-v3.h
- --- linux-3.16.6.orig/include/video/imx-ipu-v3.h 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/include/video/imx-ipu-v3.h 2014-10-23 12:35:38.090219994 -0500
- @@ -27,6 +27,12 @@
-
- #define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3')
-
- +#define CLK_POL_NEGEDGE 0
- +#define CLK_POL_POSEDGE 1
- +
- +#define ENABLE_POL_LOW 0
- +#define ENABLE_POL_HIGH 1
- +
- /*
- * Bitfield of Display Interface signal polarities.
- */
- @@ -37,7 +43,7 @@
- unsigned clksel_en:1;
- unsigned clkidle_en:1;
- unsigned data_pol:1; /* true = inverted */
- - unsigned clk_pol:1; /* true = rising edge */
- + unsigned clk_pol:1;
- unsigned enable_pol:1;
- unsigned Hsync_pol:1; /* true = active high */
- unsigned Vsync_pol:1;
- diff -Nur linux-3.16.6.orig/sound/soc/codecs/sgtl5000.c linux-3.16.6/sound/soc/codecs/sgtl5000.c
- --- linux-3.16.6.orig/sound/soc/codecs/sgtl5000.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/sound/soc/codecs/sgtl5000.c 2014-10-23 12:37:45.114220003 -0500
- @@ -773,7 +773,7 @@
- struct ldo_regulator *ldo = rdev_get_drvdata(dev);
- struct snd_soc_codec *codec = (struct snd_soc_codec *)ldo->codec_data;
- int reg;
- -
- +dev_info(codec->dev, "%s(): enabled %u\n", __func__, ldo->enabled);
- if (ldo_regulator_is_enabled(dev))
- return 0;
-
- @@ -805,10 +805,16 @@
- {
- struct ldo_regulator *ldo = rdev_get_drvdata(dev);
- struct snd_soc_codec *codec = (struct snd_soc_codec *)ldo->codec_data;
- +dev_info(codec->dev, "%s(): enabled %u\n", __func__, ldo->enabled);
- +
- + snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
- + SGTL5000_LINREG_SIMPLE_POWERUP,
- + SGTL5000_LINREG_SIMPLE_POWERUP);
-
- snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
- SGTL5000_LINEREG_D_POWERUP,
- 0);
- +dev_info(codec->dev, "%s: ANA_POWER = 0x%04x\n", __func__, snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER));
-
- /* clear voltage info */
- snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
- @@ -866,6 +872,7 @@
- config.dev = codec->dev;
- config.driver_data = ldo;
- config.init_data = init_data;
- + config.ena_gpio = -EINVAL;
-
- ldo->dev = regulator_register(&ldo->desc, &config);
- if (IS_ERR(ldo->dev)) {
- @@ -1159,8 +1166,11 @@
- * if vddio and vddd > 3.1v,
- * charge pump should be clean before set ana_pwr
- */
- - snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
- - SGTL5000_VDDC_CHRGPMP_POWERUP, 0);
- +// FIXME: this is total crap - we have read this register above into
- +// ana_pwr, which we then modify (above), and then write back to the
- +// register below. This modification just gets completely overwritten.
- +// snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
- +// SGTL5000_VDDC_CHRGPMP_POWERUP, 0);
-
- /* VDDC use VDDIO rail */
- lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
- @@ -1304,6 +1314,9 @@
- int ret;
- struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
-
- + if (!devres_open_group(codec->dev, NULL, GFP_KERNEL))
- + return -ENOMEM;
- +
- ret = sgtl5000_enable_regulators(codec);
- if (ret)
- return ret;
- @@ -1361,6 +1374,9 @@
- err:
- regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
- +
- + devres_release_group(codec->dev, NULL);
- +
- ldo_regulator_remove(codec);
-
- return ret;
- @@ -1374,6 +1390,9 @@
-
- regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
- +
- + devres_release_group(codec->dev, NULL);
- +
- ldo_regulator_remove(codec);
-
- return 0;
- diff -Nur linux-3.16.6.orig/sound/soc/fsl/imx-pcm-dma.c linux-3.16.6/sound/soc/fsl/imx-pcm-dma.c
- --- linux-3.16.6.orig/sound/soc/fsl/imx-pcm-dma.c 2014-10-15 05:05:43.000000000 -0500
- +++ linux-3.16.6/sound/soc/fsl/imx-pcm-dma.c 2014-10-23 12:35:54.206220260 -0500
- @@ -43,7 +43,7 @@
- .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
- .period_bytes_min = 128,
- .period_bytes_max = 65535, /* Limited by SDMA engine */
- - .periods_min = 2,
- + .periods_min = 4,
- .periods_max = 255,
- .fifo_size = 0,
- };
- @@ -59,6 +59,7 @@
- {
- return devm_snd_dmaengine_pcm_register(&pdev->dev,
- &imx_dmaengine_pcm_config,
- + SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
- SND_DMAENGINE_PCM_FLAG_COMPAT);
- }
- EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
- diff -Nur linux-3.16.6.orig/sound/soc/fsl/imx-pcm-dma.c.orig linux-3.16.6/sound/soc/fsl/imx-pcm-dma.c.orig
- --- linux-3.16.6.orig/sound/soc/fsl/imx-pcm-dma.c.orig 1969-12-31 18:00:00.000000000 -0600
- +++ linux-3.16.6/sound/soc/fsl/imx-pcm-dma.c.orig 2014-10-23 12:26:49.542220041 -0500
- @@ -0,0 +1,66 @@
- +/*
- + * imx-pcm-dma-mx2.c -- ALSA Soc Audio Layer
- + *
- + * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
- + *
- + * This code is based on code copyrighted by Freescale,
- + * Liam Girdwood, Javier Martin and probably others.
- + *
- + * This program is free software; you can redistribute it and/or modify it
- + * under the terms of the GNU General Public License as published by the
- + * Free Software Foundation; either version 2 of the License, or (at your
- + * option) any later version.
- + */
- +#include <linux/platform_device.h>
- +#include <linux/dmaengine.h>
- +#include <linux/types.h>
- +#include <linux/module.h>
- +
- +#include <sound/core.h>
- +#include <sound/pcm.h>
- +#include <sound/soc.h>
- +#include <sound/dmaengine_pcm.h>
- +
- +#include "imx-pcm.h"
- +
- +static bool filter(struct dma_chan *chan, void *param)
- +{
- + if (!imx_dma_is_general_purpose(chan))
- + return false;
- +
- + chan->private = param;
- +
- + return true;
- +}
- +
- +static const struct snd_pcm_hardware imx_pcm_hardware = {
- + .info = SNDRV_PCM_INFO_INTERLEAVED |
- + SNDRV_PCM_INFO_BLOCK_TRANSFER |
- + SNDRV_PCM_INFO_MMAP |
- + SNDRV_PCM_INFO_MMAP_VALID |
- + SNDRV_PCM_INFO_PAUSE |
- + SNDRV_PCM_INFO_RESUME,
- + .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
- + .period_bytes_min = 128,
- + .period_bytes_max = 65535, /* Limited by SDMA engine */
- + .periods_min = 4,
- + .periods_max = 255,
- + .fifo_size = 0,
- +};
- +
- +static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = {
- + .pcm_hardware = &imx_pcm_hardware,
- + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
- + .compat_filter_fn = filter,
- + .prealloc_buffer_size = IMX_SSI_DMABUF_SIZE,
- +};
- +
- +int imx_pcm_dma_init(struct platform_device *pdev)
- +{
- + return devm_snd_dmaengine_pcm_register(&pdev->dev,
- + &imx_dmaengine_pcm_config,
- + SND_DMAENGINE_PCM_FLAG_COMPAT);
- +}
- +EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
- +
- +MODULE_LICENSE("GPL");
|