1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184 |
- /*
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
- */
- #define pr_fmt(fmt) "%s: " fmt, __func__
- #include <linux/module.h>
- #include <linux/cpu.h>
- #include <linux/cpu_pm.h>
- #include <linux/cpumask.h>
- #include <linux/delay.h>
- #include <linux/err.h>
- #include <linux/string.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
- #include <linux/init.h>
- #include <linux/io.h>
- #include <linux/bitops.h>
- #include <linux/slab.h>
- #include <linux/of.h>
- #include <linux/of_device.h>
- #include <linux/platform_device.h>
- #include <linux/pm_opp.h>
- #include <linux/interrupt.h>
- #include <linux/debugfs.h>
- #include <linux/sort.h>
- #include <linux/uaccess.h>
- #include <linux/regulator/driver.h>
- #include <linux/regulator/machine.h>
- #include <linux/regulator/of_regulator.h>
- #include <linux/regulator/cpr-regulator.h>
- #include <soc/qcom/scm.h>
- /* Register Offsets for RB-CPR and Bit Definitions */
- /* RBCPR Version Register */
- #define REG_RBCPR_VERSION 0
- #define RBCPR_VER_2 0x02
- /* RBCPR Gate Count and Target Registers */
- #define REG_RBCPR_GCNT_TARGET(n) (0x60 + 4 * n)
- #define RBCPR_GCNT_TARGET_GCNT_BITS 10
- #define RBCPR_GCNT_TARGET_GCNT_SHIFT 12
- #define RBCPR_GCNT_TARGET_GCNT_MASK ((1<<RBCPR_GCNT_TARGET_GCNT_BITS)-1)
- /* RBCPR Sensor Mask and Bypass Registers */
- #define REG_RBCPR_SENSOR_MASK0 0x20
- #define RBCPR_SENSOR_MASK0_SENSOR(n) (~BIT(n))
- #define REG_RBCPR_SENSOR_BYPASS0 0x30
- /* RBCPR Timer Control */
- #define REG_RBCPR_TIMER_INTERVAL 0x44
- #define REG_RBIF_TIMER_ADJUST 0x4C
- #define RBIF_TIMER_ADJ_CONS_UP_BITS 4
- #define RBIF_TIMER_ADJ_CONS_UP_MASK ((1<<RBIF_TIMER_ADJ_CONS_UP_BITS)-1)
- #define RBIF_TIMER_ADJ_CONS_DOWN_BITS 4
- #define RBIF_TIMER_ADJ_CONS_DOWN_MASK ((1<<RBIF_TIMER_ADJ_CONS_DOWN_BITS)-1)
- #define RBIF_TIMER_ADJ_CONS_DOWN_SHIFT 4
- #define RBIF_TIMER_ADJ_CLAMP_INT_BITS 8
- #define RBIF_TIMER_ADJ_CLAMP_INT_MASK ((1<<RBIF_TIMER_ADJ_CLAMP_INT_BITS)-1)
- #define RBIF_TIMER_ADJ_CLAMP_INT_SHIFT 8
- /* RBCPR Config Register */
- #define REG_RBIF_LIMIT 0x48
- #define REG_RBCPR_STEP_QUOT 0x80
- #define REG_RBIF_SW_VLEVEL 0x94
- #define RBIF_LIMIT_CEILING_BITS 6
- #define RBIF_LIMIT_CEILING_MASK ((1<<RBIF_LIMIT_CEILING_BITS)-1)
- #define RBIF_LIMIT_CEILING_SHIFT 6
- #define RBIF_LIMIT_FLOOR_BITS 6
- #define RBIF_LIMIT_FLOOR_MASK ((1<<RBIF_LIMIT_FLOOR_BITS)-1)
- #define RBIF_LIMIT_CEILING_DEFAULT RBIF_LIMIT_CEILING_MASK
- #define RBIF_LIMIT_FLOOR_DEFAULT 0
- #define RBIF_SW_VLEVEL_DEFAULT 0x20
- #define RBCPR_STEP_QUOT_STEPQUOT_BITS 8
- #define RBCPR_STEP_QUOT_STEPQUOT_MASK ((1<<RBCPR_STEP_QUOT_STEPQUOT_BITS)-1)
- #define RBCPR_STEP_QUOT_IDLE_CLK_BITS 4
- #define RBCPR_STEP_QUOT_IDLE_CLK_MASK ((1<<RBCPR_STEP_QUOT_IDLE_CLK_BITS)-1)
- #define RBCPR_STEP_QUOT_IDLE_CLK_SHIFT 8
- /* RBCPR Control Register */
- #define REG_RBCPR_CTL 0x90
- #define RBCPR_CTL_LOOP_EN BIT(0)
- #define RBCPR_CTL_TIMER_EN BIT(3)
- #define RBCPR_CTL_SW_AUTO_CONT_ACK_EN BIT(5)
- #define RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN BIT(6)
- #define RBCPR_CTL_COUNT_MODE BIT(10)
- #define RBCPR_CTL_UP_THRESHOLD_BITS 4
- #define RBCPR_CTL_UP_THRESHOLD_MASK ((1<<RBCPR_CTL_UP_THRESHOLD_BITS)-1)
- #define RBCPR_CTL_UP_THRESHOLD_SHIFT 24
- #define RBCPR_CTL_DN_THRESHOLD_BITS 4
- #define RBCPR_CTL_DN_THRESHOLD_MASK ((1<<RBCPR_CTL_DN_THRESHOLD_BITS)-1)
- #define RBCPR_CTL_DN_THRESHOLD_SHIFT 28
- /* RBCPR Ack/Nack Response */
- #define REG_RBIF_CONT_ACK_CMD 0x98
- #define REG_RBIF_CONT_NACK_CMD 0x9C
- /* RBCPR Result status Registers */
- #define REG_RBCPR_RESULT_0 0xA0
- #define REG_RBCPR_RESULT_1 0xA4
- #define RBCPR_RESULT_1_SEL_FAST_BITS 3
- #define RBCPR_RESULT_1_SEL_FAST(val) (val & \
- ((1<<RBCPR_RESULT_1_SEL_FAST_BITS) - 1))
- #define RBCPR_RESULT0_BUSY_SHIFT 19
- #define RBCPR_RESULT0_BUSY_MASK BIT(RBCPR_RESULT0_BUSY_SHIFT)
- #define RBCPR_RESULT0_ERROR_LT0_SHIFT 18
- #define RBCPR_RESULT0_ERROR_SHIFT 6
- #define RBCPR_RESULT0_ERROR_BITS 12
- #define RBCPR_RESULT0_ERROR_MASK ((1<<RBCPR_RESULT0_ERROR_BITS)-1)
- #define RBCPR_RESULT0_ERROR_STEPS_SHIFT 2
- #define RBCPR_RESULT0_ERROR_STEPS_BITS 4
- #define RBCPR_RESULT0_ERROR_STEPS_MASK ((1<<RBCPR_RESULT0_ERROR_STEPS_BITS)-1)
- #define RBCPR_RESULT0_STEP_UP_SHIFT 1
- /* RBCPR Interrupt Control Register */
- #define REG_RBIF_IRQ_EN(n) (0x100 + 4 * n)
- #define REG_RBIF_IRQ_CLEAR 0x110
- #define REG_RBIF_IRQ_STATUS 0x114
- #define CPR_INT_DONE BIT(0)
- #define CPR_INT_MIN BIT(1)
- #define CPR_INT_DOWN BIT(2)
- #define CPR_INT_MID BIT(3)
- #define CPR_INT_UP BIT(4)
- #define CPR_INT_MAX BIT(5)
- #define CPR_INT_CLAMP BIT(6)
- #define CPR_INT_ALL (CPR_INT_DONE | CPR_INT_MIN | CPR_INT_DOWN | \
- CPR_INT_MID | CPR_INT_UP | CPR_INT_MAX | CPR_INT_CLAMP)
- #define CPR_INT_DEFAULT (CPR_INT_UP | CPR_INT_DOWN)
- #define CPR_NUM_RING_OSC 8
- /* RBCPR Debug Resgister */
- #define REG_RBCPR_DEBUG1 0x120
- #define RBCPR_DEBUG1_QUOT_FAST_BITS 12
- #define RBCPR_DEBUG1_QUOT_SLOW_BITS 12
- #define RBCPR_DEBUG1_QUOT_SLOW_SHIFT 12
- #define RBCPR_DEBUG1_QUOT_FAST(val) (val & \
- ((1<<RBCPR_DEBUG1_QUOT_FAST_BITS)-1))
- #define RBCPR_DEBUG1_QUOT_SLOW(val) ((val>>RBCPR_DEBUG1_QUOT_SLOW_SHIFT) & \
- ((1<<RBCPR_DEBUG1_QUOT_SLOW_BITS)-1))
- /* RBCPR Aging Resgister */
- #define REG_RBCPR_HTOL_AGE 0x160
- #define RBCPR_HTOL_AGE_PAGE BIT(1)
- #define RBCPR_AGE_DATA_STATUS BIT(2)
- /* RBCPR Clock Control Register */
- #define RBCPR_CLK_SEL_MASK BIT(0)
- #define RBCPR_CLK_SEL_19P2_MHZ 0
- #define RBCPR_CLK_SEL_AHB_CLK BIT(0)
- /* CPR eFuse parameters */
- #define CPR_FUSE_TARGET_QUOT_BITS 12
- #define CPR_FUSE_TARGET_QUOT_BITS_MASK ((1<<CPR_FUSE_TARGET_QUOT_BITS)-1)
- #define CPR_FUSE_RO_SEL_BITS 3
- #define CPR_FUSE_RO_SEL_BITS_MASK ((1<<CPR_FUSE_RO_SEL_BITS)-1)
- #define CPR_FUSE_MIN_QUOT_DIFF 50
- #define BYTES_PER_FUSE_ROW 8
- #define SPEED_BIN_NONE UINT_MAX
- #define FUSE_REVISION_UNKNOWN (-1)
- #define FUSE_MAP_NO_MATCH (-1)
- #define FUSE_PARAM_MATCH_ANY 0xFFFFFFFF
- #define FLAGS_IGNORE_1ST_IRQ_STATUS BIT(0)
- #define FLAGS_SET_MIN_VOLTAGE BIT(1)
- #define FLAGS_UPLIFT_QUOT_VOLT BIT(2)
- /*
- * The number of individual aging measurements to perform which are then
- * averaged together in order to determine the final aging adjustment value.
- */
- #define CPR_AGING_MEASUREMENT_ITERATIONS 16
- /*
- * Aging measurements for the aged and unaged ring oscillators take place a few
- * microseconds apart. If the vdd-supply voltage fluctuates between the two
- * measurements, then the difference between them will be incorrect. The
- * difference could end up too high or too low. This constant defines the
- * number of lowest and highest measurements to ignore when averaging.
- */
- #define CPR_AGING_MEASUREMENT_FILTER 3
- #define CPR_REGULATOR_DRIVER_NAME "qcom,cpr-regulator"
- /**
- * enum vdd_mx_vmin_method - Method to determine vmin for vdd-mx
- * %VDD_MX_VMIN_APC: Equal to APC voltage
- * %VDD_MX_VMIN_APC_CORNER_CEILING: Equal to PVS corner ceiling voltage
- * %VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
- * Equal to slow speed corner ceiling
- * %VDD_MX_VMIN_MX_VMAX: Equal to specified vdd-mx-vmax voltage
- * %VDD_MX_VMIN_APC_CORNER_MAP: Equal to the APC corner mapped MX
- * voltage
- */
- enum vdd_mx_vmin_method {
- VDD_MX_VMIN_APC,
- VDD_MX_VMIN_APC_CORNER_CEILING,
- VDD_MX_VMIN_APC_SLOW_CORNER_CEILING,
- VDD_MX_VMIN_MX_VMAX,
- VDD_MX_VMIN_APC_FUSE_CORNER_MAP,
- VDD_MX_VMIN_APC_CORNER_MAP,
- };
- #define CPR_CORNER_MIN 1
- #define CPR_FUSE_CORNER_MIN 1
- /*
- * This is an arbitrary upper limit which is used in a sanity check in order to
- * avoid excessive memory allocation due to bad device tree data.
- */
- #define CPR_FUSE_CORNER_LIMIT 100
- struct quot_adjust_info {
- int speed_bin;
- int virtual_corner;
- int quot_adjust;
- };
- struct cpr_quot_scale {
- u32 offset;
- u32 multiplier;
- };
- struct cpr_aging_sensor_info {
- u32 sensor_id;
- int initial_quot_diff;
- int current_quot_diff;
- };
- struct cpr_aging_info {
- struct cpr_aging_sensor_info *sensor_info;
- int num_aging_sensors;
- int aging_corner;
- u32 aging_ro_kv;
- u32 *aging_derate;
- u32 aging_sensor_bypass;
- u32 max_aging_margin;
- u32 aging_ref_voltage;
- u32 cpr_ro_kv[CPR_NUM_RING_OSC];
- int *voltage_adjust;
- bool cpr_aging_error;
- bool cpr_aging_done;
- };
- static const char * const vdd_apc_name[] = {"vdd-apc-optional-prim",
- "vdd-apc-optional-sec",
- "vdd-apc"};
- enum voltage_change_dir {
- NO_CHANGE,
- DOWN,
- UP,
- };
- struct cpr_regulator {
- struct list_head list;
- struct regulator_desc rdesc;
- struct regulator_dev *rdev;
- bool vreg_enabled;
- int corner;
- int ceiling_max;
- struct dentry *debugfs;
- /* eFuse parameters */
- phys_addr_t efuse_addr;
- void __iomem *efuse_base;
- u64 *remapped_row;
- u32 remapped_row_base;
- int num_remapped_rows;
- /* Process voltage parameters */
- u32 *pvs_corner_v;
- /* Process voltage variables */
- u32 pvs_bin;
- u32 speed_bin;
- u32 pvs_version;
- /* APC voltage regulator */
- struct regulator *vdd_apc;
- /* Dependency parameters */
- struct regulator *vdd_mx;
- int vdd_mx_vmax;
- int vdd_mx_vmin_method;
- int vdd_mx_vmin;
- int *vdd_mx_corner_map;
- struct regulator *rpm_apc_vreg;
- int *rpm_apc_corner_map;
- /* mem-acc regulator */
- struct regulator *mem_acc_vreg;
- /* CPR parameters */
- u32 num_fuse_corners;
- u64 cpr_fuse_bits;
- bool cpr_fuse_disable;
- bool cpr_fuse_local;
- bool cpr_fuse_redundant;
- int cpr_fuse_revision;
- int cpr_fuse_map_count;
- int cpr_fuse_map_match;
- int *cpr_fuse_target_quot;
- int *cpr_fuse_ro_sel;
- int *fuse_quot_offset;
- int gcnt;
- unsigned int cpr_irq;
- void __iomem *rbcpr_base;
- phys_addr_t rbcpr_clk_addr;
- struct mutex cpr_mutex;
- int *cpr_max_ceiling;
- int *ceiling_volt;
- int *floor_volt;
- int *fuse_ceiling_volt;
- int *fuse_floor_volt;
- int *last_volt;
- int *open_loop_volt;
- int step_volt;
- int *save_ctl;
- int *save_irq;
- int *vsens_corner_map;
- /* vsens status */
- bool vsens_enabled;
- /* vsens regulators */
- struct regulator *vdd_vsens_corner;
- struct regulator *vdd_vsens_voltage;
- /* Config parameters */
- bool enable;
- u32 ref_clk_khz;
- u32 timer_delay_us;
- u32 timer_cons_up;
- u32 timer_cons_down;
- u32 irq_line;
- u32 *step_quotient;
- u32 up_threshold;
- u32 down_threshold;
- u32 idle_clocks;
- u32 gcnt_time_us;
- u32 clamp_timer_interval;
- u32 vdd_apc_step_up_limit;
- u32 vdd_apc_step_down_limit;
- u32 flags;
- int *corner_map;
- u32 num_corners;
- int *quot_adjust;
- int *mem_acc_corner_map;
- int num_adj_cpus;
- int online_cpus;
- int *adj_cpus;
- int **adj_cpus_save_ctl;
- int **adj_cpus_save_irq;
- int **adj_cpus_last_volt;
- int **adj_cpus_quot_adjust;
- int **adj_cpus_open_loop_volt;
- bool adj_cpus_open_loop_volt_as_ceiling;
- struct notifier_block cpu_notifier;
- cpumask_t cpu_mask;
- bool cpr_disabled_in_pc;
- struct notifier_block pm_notifier;
- bool is_cpr_suspended;
- bool skip_voltage_change_during_suspend;
- struct cpr_aging_info *aging_info;
- struct notifier_block panic_notifier;
- };
- #define CPR_DEBUG_MASK_IRQ BIT(0)
- #define CPR_DEBUG_MASK_API BIT(1)
- static int cpr_debug_enable;
- #if defined(CONFIG_DEBUG_FS)
- static struct dentry *cpr_debugfs_base;
- #endif
- static DEFINE_MUTEX(cpr_regulator_list_mutex);
- static LIST_HEAD(cpr_regulator_list);
- module_param_named(debug_enable, cpr_debug_enable, int, S_IRUGO | S_IWUSR);
- #define cpr_debug(cpr_vreg, message, ...) \
- do { \
- if (cpr_debug_enable & CPR_DEBUG_MASK_API) \
- pr_info("%s: " message, (cpr_vreg)->rdesc.name, \
- ##__VA_ARGS__); \
- } while (0)
- #define cpr_debug_irq(cpr_vreg, message, ...) \
- do { \
- if (cpr_debug_enable & CPR_DEBUG_MASK_IRQ) \
- pr_info("%s: " message, (cpr_vreg)->rdesc.name, \
- ##__VA_ARGS__); \
- else \
- pr_debug("%s: " message, (cpr_vreg)->rdesc.name, \
- ##__VA_ARGS__); \
- } while (0)
- #define cpr_info(cpr_vreg, message, ...) \
- pr_info("%s: " message, (cpr_vreg)->rdesc.name, ##__VA_ARGS__)
- #define cpr_err(cpr_vreg, message, ...) \
- pr_err("%s: " message, (cpr_vreg)->rdesc.name, ##__VA_ARGS__)
- static u64 cpr_read_remapped_efuse_row(struct cpr_regulator *cpr_vreg,
- u32 row_num)
- {
- if (row_num - cpr_vreg->remapped_row_base
- >= cpr_vreg->num_remapped_rows) {
- cpr_err(cpr_vreg, "invalid row=%u, max remapped row=%u\n",
- row_num, cpr_vreg->remapped_row_base
- + cpr_vreg->num_remapped_rows - 1);
- return 0;
- }
- return cpr_vreg->remapped_row[row_num - cpr_vreg->remapped_row_base];
- }
- static u64 cpr_read_efuse_row(struct cpr_regulator *cpr_vreg, u32 row_num,
- bool use_tz_api)
- {
- int rc;
- u64 efuse_bits;
- struct scm_desc desc = {0};
- struct cpr_read_req {
- u32 row_address;
- int addr_type;
- } req;
- struct cpr_read_rsp {
- u32 row_data[2];
- u32 status;
- } rsp;
- if (cpr_vreg->remapped_row && row_num >= cpr_vreg->remapped_row_base)
- return cpr_read_remapped_efuse_row(cpr_vreg, row_num);
- if (!use_tz_api) {
- efuse_bits = readq_relaxed(cpr_vreg->efuse_base
- + row_num * BYTES_PER_FUSE_ROW);
- return efuse_bits;
- }
- desc.args[0] = req.row_address = cpr_vreg->efuse_addr +
- row_num * BYTES_PER_FUSE_ROW;
- desc.args[1] = req.addr_type = 0;
- desc.arginfo = SCM_ARGS(2);
- efuse_bits = 0;
- if (!is_scm_armv8()) {
- rc = scm_call(SCM_SVC_FUSE, SCM_FUSE_READ,
- &req, sizeof(req), &rsp, sizeof(rsp));
- } else {
- rc = scm_call2(SCM_SIP_FNID(SCM_SVC_FUSE, SCM_FUSE_READ),
- &desc);
- rsp.row_data[0] = desc.ret[0];
- rsp.row_data[1] = desc.ret[1];
- rsp.status = desc.ret[2];
- }
- if (rc) {
- cpr_err(cpr_vreg, "read row %d failed, err code = %d",
- row_num, rc);
- } else {
- efuse_bits = ((u64)(rsp.row_data[1]) << 32) +
- (u64)rsp.row_data[0];
- }
- return efuse_bits;
- }
- /**
- * cpr_read_efuse_param() - read a parameter from one or two eFuse rows
- * @cpr_vreg: Pointer to cpr_regulator struct for this regulator.
- * @row_start: Fuse row number to start reading from.
- * @bit_start: The LSB of the parameter to read from the fuse.
- * @bit_len: The length of the parameter in bits.
- * @use_tz_api: Flag to indicate if an SCM call should be used to read the fuse.
- *
- * This function reads a parameter of specified offset and bit size out of one
- * or two consecutive eFuse rows. This allows for the reading of parameters
- * that happen to be split between two eFuse rows.
- *
- * Returns the fuse parameter on success or 0 on failure.
- */
- static u64 cpr_read_efuse_param(struct cpr_regulator *cpr_vreg, int row_start,
- int bit_start, int bit_len, bool use_tz_api)
- {
- u64 fuse[2];
- u64 param = 0;
- int bits_first, bits_second;
- if (bit_start < 0) {
- cpr_err(cpr_vreg, "Invalid LSB = %d specified\n", bit_start);
- return 0;
- }
- if (bit_len < 0 || bit_len > 64) {
- cpr_err(cpr_vreg, "Invalid bit length = %d specified\n",
- bit_len);
- return 0;
- }
- /* Allow bit indexing to start beyond the end of the start row. */
- if (bit_start >= 64) {
- row_start += bit_start >> 6; /* equivalent to bit_start / 64 */
- bit_start &= 0x3F;
- }
- fuse[0] = cpr_read_efuse_row(cpr_vreg, row_start, use_tz_api);
- if (bit_start == 0 && bit_len == 64) {
- param = fuse[0];
- } else if (bit_start + bit_len <= 64) {
- param = (fuse[0] >> bit_start) & ((1ULL << bit_len) - 1);
- } else {
- fuse[1] = cpr_read_efuse_row(cpr_vreg, row_start + 1,
- use_tz_api);
- bits_first = 64 - bit_start;
- bits_second = bit_len - bits_first;
- param = (fuse[0] >> bit_start) & ((1ULL << bits_first) - 1);
- param |= (fuse[1] & ((1ULL << bits_second) - 1)) << bits_first;
- }
- return param;
- }
- static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
- {
- if (cpr_vreg->cpr_fuse_disable || !cpr_vreg->enable)
- return false;
- else
- return true;
- }
- static void cpr_write(struct cpr_regulator *cpr_vreg, u32 offset, u32 value)
- {
- writel_relaxed(value, cpr_vreg->rbcpr_base + offset);
- }
- static u32 cpr_read(struct cpr_regulator *cpr_vreg, u32 offset)
- {
- return readl_relaxed(cpr_vreg->rbcpr_base + offset);
- }
- static void cpr_masked_write(struct cpr_regulator *cpr_vreg, u32 offset,
- u32 mask, u32 value)
- {
- u32 reg_val;
- reg_val = readl_relaxed(cpr_vreg->rbcpr_base + offset);
- reg_val &= ~mask;
- reg_val |= value & mask;
- writel_relaxed(reg_val, cpr_vreg->rbcpr_base + offset);
- }
- static void cpr_irq_clr(struct cpr_regulator *cpr_vreg)
- {
- cpr_write(cpr_vreg, REG_RBIF_IRQ_CLEAR, CPR_INT_ALL);
- }
- static void cpr_irq_clr_nack(struct cpr_regulator *cpr_vreg)
- {
- cpr_irq_clr(cpr_vreg);
- cpr_write(cpr_vreg, REG_RBIF_CONT_NACK_CMD, 1);
- }
- static void cpr_irq_clr_ack(struct cpr_regulator *cpr_vreg)
- {
- cpr_irq_clr(cpr_vreg);
- cpr_write(cpr_vreg, REG_RBIF_CONT_ACK_CMD, 1);
- }
- static void cpr_irq_set(struct cpr_regulator *cpr_vreg, u32 int_bits)
- {
- cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), int_bits);
- }
- static void cpr_ctl_modify(struct cpr_regulator *cpr_vreg, u32 mask, u32 value)
- {
- cpr_masked_write(cpr_vreg, REG_RBCPR_CTL, mask, value);
- }
- static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg, int corner)
- {
- u32 val;
- if (cpr_vreg->is_cpr_suspended)
- return;
- /* Program Consecutive Up & Down */
- val = ((cpr_vreg->timer_cons_down & RBIF_TIMER_ADJ_CONS_DOWN_MASK)
- << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT) |
- (cpr_vreg->timer_cons_up & RBIF_TIMER_ADJ_CONS_UP_MASK);
- cpr_masked_write(cpr_vreg, REG_RBIF_TIMER_ADJUST,
- RBIF_TIMER_ADJ_CONS_UP_MASK |
- RBIF_TIMER_ADJ_CONS_DOWN_MASK, val);
- cpr_masked_write(cpr_vreg, REG_RBCPR_CTL,
- RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
- RBCPR_CTL_SW_AUTO_CONT_ACK_EN,
- cpr_vreg->save_ctl[corner]);
- cpr_irq_set(cpr_vreg, cpr_vreg->save_irq[corner]);
- if (cpr_is_allowed(cpr_vreg) && cpr_vreg->vreg_enabled &&
- (cpr_vreg->ceiling_volt[corner] >
- cpr_vreg->floor_volt[corner]))
- val = RBCPR_CTL_LOOP_EN;
- else
- val = 0;
- cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, val);
- }
- static void cpr_ctl_disable(struct cpr_regulator *cpr_vreg)
- {
- if (cpr_vreg->is_cpr_suspended)
- return;
- cpr_irq_set(cpr_vreg, 0);
- cpr_ctl_modify(cpr_vreg, RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
- RBCPR_CTL_SW_AUTO_CONT_ACK_EN, 0);
- cpr_masked_write(cpr_vreg, REG_RBIF_TIMER_ADJUST,
- RBIF_TIMER_ADJ_CONS_UP_MASK |
- RBIF_TIMER_ADJ_CONS_DOWN_MASK, 0);
- cpr_irq_clr(cpr_vreg);
- cpr_write(cpr_vreg, REG_RBIF_CONT_ACK_CMD, 1);
- cpr_write(cpr_vreg, REG_RBIF_CONT_NACK_CMD, 1);
- cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
- }
- static bool cpr_ctl_is_enabled(struct cpr_regulator *cpr_vreg)
- {
- u32 reg_val;
- reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
- return reg_val & RBCPR_CTL_LOOP_EN;
- }
- static bool cpr_ctl_is_busy(struct cpr_regulator *cpr_vreg)
- {
- u32 reg_val;
- reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
- return reg_val & RBCPR_RESULT0_BUSY_MASK;
- }
- static void cpr_corner_save(struct cpr_regulator *cpr_vreg, int corner)
- {
- cpr_vreg->save_ctl[corner] = cpr_read(cpr_vreg, REG_RBCPR_CTL);
- cpr_vreg->save_irq[corner] =
- cpr_read(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line));
- }
- static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
- {
- u32 gcnt, ctl, irq, ro_sel, step_quot;
- int fuse_corner = cpr_vreg->corner_map[corner];
- int i;
- ro_sel = cpr_vreg->cpr_fuse_ro_sel[fuse_corner];
- gcnt = cpr_vreg->gcnt | (cpr_vreg->cpr_fuse_target_quot[fuse_corner] -
- cpr_vreg->quot_adjust[corner]);
- /* Program the step quotient and idle clocks */
- step_quot = ((cpr_vreg->idle_clocks & RBCPR_STEP_QUOT_IDLE_CLK_MASK)
- << RBCPR_STEP_QUOT_IDLE_CLK_SHIFT) |
- (cpr_vreg->step_quotient[fuse_corner]
- & RBCPR_STEP_QUOT_STEPQUOT_MASK);
- cpr_write(cpr_vreg, REG_RBCPR_STEP_QUOT, step_quot);
- /* Clear the target quotient value and gate count of all ROs */
- for (i = 0; i < CPR_NUM_RING_OSC; i++)
- cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(i), 0);
- cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
- ctl = cpr_vreg->save_ctl[corner];
- cpr_write(cpr_vreg, REG_RBCPR_CTL, ctl);
- irq = cpr_vreg->save_irq[corner];
- cpr_irq_set(cpr_vreg, irq);
- cpr_debug(cpr_vreg, "gcnt = 0x%08x, ctl = 0x%08x, irq = 0x%08x\n",
- gcnt, ctl, irq);
- }
- static void cpr_corner_switch(struct cpr_regulator *cpr_vreg, int corner)
- {
- if (cpr_vreg->corner == corner)
- return;
- cpr_corner_restore(cpr_vreg, corner);
- }
- static int cpr_apc_set(struct cpr_regulator *cpr_vreg, u32 new_volt)
- {
- int max_volt, rc;
- max_volt = cpr_vreg->ceiling_max;
- rc = regulator_set_voltage(cpr_vreg->vdd_apc, new_volt, max_volt);
- if (rc)
- cpr_err(cpr_vreg, "set: vdd_apc = %d uV: rc=%d\n",
- new_volt, rc);
- return rc;
- }
- static int cpr_mx_get(struct cpr_regulator *cpr_vreg, int corner, int apc_volt)
- {
- int vdd_mx;
- int fuse_corner = cpr_vreg->corner_map[corner];
- int highest_fuse_corner = cpr_vreg->num_fuse_corners;
- switch (cpr_vreg->vdd_mx_vmin_method) {
- case VDD_MX_VMIN_APC:
- vdd_mx = apc_volt;
- break;
- case VDD_MX_VMIN_APC_CORNER_CEILING:
- vdd_mx = cpr_vreg->fuse_ceiling_volt[fuse_corner];
- break;
- case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
- vdd_mx = cpr_vreg->fuse_ceiling_volt[highest_fuse_corner];
- break;
- case VDD_MX_VMIN_MX_VMAX:
- vdd_mx = cpr_vreg->vdd_mx_vmax;
- break;
- case VDD_MX_VMIN_APC_FUSE_CORNER_MAP:
- vdd_mx = cpr_vreg->vdd_mx_corner_map[fuse_corner];
- break;
- case VDD_MX_VMIN_APC_CORNER_MAP:
- vdd_mx = cpr_vreg->vdd_mx_corner_map[corner];
- break;
- default:
- vdd_mx = 0;
- break;
- }
- return vdd_mx;
- }
- static int cpr_mx_set(struct cpr_regulator *cpr_vreg, int corner,
- int vdd_mx_vmin)
- {
- int rc;
- int fuse_corner = cpr_vreg->corner_map[corner];
- rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmax);
- cpr_debug(cpr_vreg, "[corner:%d, fuse_corner:%d] %d uV\n", corner,
- fuse_corner, vdd_mx_vmin);
- if (!rc) {
- cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
- } else {
- cpr_err(cpr_vreg, "set: vdd_mx [corner:%d, fuse_corner:%d] = %d uV failed: rc=%d\n",
- corner, fuse_corner, vdd_mx_vmin, rc);
- }
- return rc;
- }
- static int cpr_scale_voltage(struct cpr_regulator *cpr_vreg, int corner,
- int new_apc_volt, enum voltage_change_dir dir)
- {
- int rc = 0, vdd_mx_vmin = 0;
- int mem_acc_corner = cpr_vreg->mem_acc_corner_map[corner];
- int fuse_corner = cpr_vreg->corner_map[corner];
- int apc_corner, vsens_corner;
- /* Determine the vdd_mx voltage */
- if (dir != NO_CHANGE && cpr_vreg->vdd_mx != NULL)
- vdd_mx_vmin = cpr_mx_get(cpr_vreg, corner, new_apc_volt);
- if (cpr_vreg->vdd_vsens_voltage && cpr_vreg->vsens_enabled) {
- rc = regulator_disable(cpr_vreg->vdd_vsens_voltage);
- if (!rc)
- cpr_vreg->vsens_enabled = false;
- }
- if (dir == DOWN) {
- if (!rc && cpr_vreg->mem_acc_vreg)
- rc = regulator_set_voltage(cpr_vreg->mem_acc_vreg,
- mem_acc_corner, mem_acc_corner);
- if (!rc && cpr_vreg->rpm_apc_vreg) {
- apc_corner = cpr_vreg->rpm_apc_corner_map[corner];
- rc = regulator_set_voltage(cpr_vreg->rpm_apc_vreg,
- apc_corner, apc_corner);
- if (rc)
- cpr_err(cpr_vreg, "apc_corner voting failed rc=%d\n",
- rc);
- }
- }
- if (!rc && vdd_mx_vmin && dir == UP) {
- if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
- rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
- }
- if (!rc)
- rc = cpr_apc_set(cpr_vreg, new_apc_volt);
- if (dir == UP) {
- if (!rc && cpr_vreg->mem_acc_vreg)
- rc = regulator_set_voltage(cpr_vreg->mem_acc_vreg,
- mem_acc_corner, mem_acc_corner);
- if (!rc && cpr_vreg->rpm_apc_vreg) {
- apc_corner = cpr_vreg->rpm_apc_corner_map[corner];
- rc = regulator_set_voltage(cpr_vreg->rpm_apc_vreg,
- apc_corner, apc_corner);
- if (rc)
- cpr_err(cpr_vreg, "apc_corner voting failed rc=%d\n",
- rc);
- }
- }
- if (!rc && vdd_mx_vmin && dir == DOWN) {
- if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
- rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
- }
- if (!rc && cpr_vreg->vdd_vsens_corner) {
- vsens_corner = cpr_vreg->vsens_corner_map[fuse_corner];
- rc = regulator_set_voltage(cpr_vreg->vdd_vsens_corner,
- vsens_corner, vsens_corner);
- }
- if (!rc && cpr_vreg->vdd_vsens_voltage) {
- rc = regulator_set_voltage(cpr_vreg->vdd_vsens_voltage,
- cpr_vreg->floor_volt[corner],
- cpr_vreg->ceiling_volt[corner]);
- if (!rc && !cpr_vreg->vsens_enabled) {
- rc = regulator_enable(cpr_vreg->vdd_vsens_voltage);
- if (!rc)
- cpr_vreg->vsens_enabled = true;
- }
- }
- return rc;
- }
- static void cpr_scale(struct cpr_regulator *cpr_vreg,
- enum voltage_change_dir dir)
- {
- u32 reg_val, error_steps, reg_mask;
- int last_volt, new_volt, corner, fuse_corner;
- u32 gcnt, quot;
- corner = cpr_vreg->corner;
- fuse_corner = cpr_vreg->corner_map[corner];
- reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
- error_steps = (reg_val >> RBCPR_RESULT0_ERROR_STEPS_SHIFT)
- & RBCPR_RESULT0_ERROR_STEPS_MASK;
- last_volt = cpr_vreg->last_volt[corner];
- cpr_debug_irq(cpr_vreg,
- "last_volt[corner:%d, fuse_corner:%d] = %d uV\n",
- corner, fuse_corner, last_volt);
- gcnt = cpr_read(cpr_vreg, REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[fuse_corner]));
- quot = gcnt & ((1 << RBCPR_GCNT_TARGET_GCNT_SHIFT) - 1);
- if (dir == UP) {
- if (cpr_vreg->clamp_timer_interval
- && error_steps < cpr_vreg->up_threshold) {
- /*
- * Handle the case where another measurement started
- * after the interrupt was triggered due to a core
- * exiting from power collapse.
- */
- error_steps = max(cpr_vreg->up_threshold,
- cpr_vreg->vdd_apc_step_up_limit);
- }
- cpr_debug_irq(cpr_vreg,
- "Up: cpr status = 0x%08x (error_steps=%d)\n",
- reg_val, error_steps);
- if (last_volt >= cpr_vreg->ceiling_volt[corner]) {
- cpr_debug_irq(cpr_vreg,
- "[corn:%d, fuse_corn:%d] @ ceiling: %d >= %d: NACK\n",
- corner, fuse_corner, last_volt,
- cpr_vreg->ceiling_volt[corner]);
- cpr_irq_clr_nack(cpr_vreg);
- cpr_debug_irq(cpr_vreg, "gcnt = 0x%08x (quot = %d)\n",
- gcnt, quot);
- /* Maximize the UP threshold */
- reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
- RBCPR_CTL_UP_THRESHOLD_SHIFT;
- reg_val = reg_mask;
- cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
- /* Disable UP interrupt */
- cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT & ~CPR_INT_UP);
- return;
- }
- if (error_steps > cpr_vreg->vdd_apc_step_up_limit) {
- cpr_debug_irq(cpr_vreg,
- "%d is over up-limit(%d): Clamp\n",
- error_steps,
- cpr_vreg->vdd_apc_step_up_limit);
- error_steps = cpr_vreg->vdd_apc_step_up_limit;
- }
- /* Calculate new voltage */
- new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
- if (new_volt > cpr_vreg->ceiling_volt[corner]) {
- cpr_debug_irq(cpr_vreg,
- "new_volt(%d) >= ceiling(%d): Clamp\n",
- new_volt,
- cpr_vreg->ceiling_volt[corner]);
- new_volt = cpr_vreg->ceiling_volt[corner];
- }
- if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
- cpr_irq_clr_nack(cpr_vreg);
- return;
- }
- cpr_vreg->last_volt[corner] = new_volt;
- /* Disable auto nack down */
- reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
- reg_val = 0;
- cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
- /* Re-enable default interrupts */
- cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
- /* Ack */
- cpr_irq_clr_ack(cpr_vreg);
- cpr_debug_irq(cpr_vreg,
- "UP: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
- corner, fuse_corner, new_volt);
- } else if (dir == DOWN) {
- if (cpr_vreg->clamp_timer_interval
- && error_steps < cpr_vreg->down_threshold) {
- /*
- * Handle the case where another measurement started
- * after the interrupt was triggered due to a core
- * exiting from power collapse.
- */
- error_steps = max(cpr_vreg->down_threshold,
- cpr_vreg->vdd_apc_step_down_limit);
- }
- cpr_debug_irq(cpr_vreg,
- "Down: cpr status = 0x%08x (error_steps=%d)\n",
- reg_val, error_steps);
- if (last_volt <= cpr_vreg->floor_volt[corner]) {
- cpr_debug_irq(cpr_vreg,
- "[corn:%d, fuse_corner:%d] @ floor: %d <= %d: NACK\n",
- corner, fuse_corner, last_volt,
- cpr_vreg->floor_volt[corner]);
- cpr_irq_clr_nack(cpr_vreg);
- cpr_debug_irq(cpr_vreg, "gcnt = 0x%08x (quot = %d)\n",
- gcnt, quot);
- /* Enable auto nack down */
- reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
- reg_val = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
- cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
- /* Disable DOWN interrupt */
- cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT & ~CPR_INT_DOWN);
- return;
- }
- if (error_steps > cpr_vreg->vdd_apc_step_down_limit) {
- cpr_debug_irq(cpr_vreg,
- "%d is over down-limit(%d): Clamp\n",
- error_steps,
- cpr_vreg->vdd_apc_step_down_limit);
- error_steps = cpr_vreg->vdd_apc_step_down_limit;
- }
- /* Calculte new voltage */
- new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
- if (new_volt < cpr_vreg->floor_volt[corner]) {
- cpr_debug_irq(cpr_vreg,
- "new_volt(%d) < floor(%d): Clamp\n",
- new_volt,
- cpr_vreg->floor_volt[corner]);
- new_volt = cpr_vreg->floor_volt[corner];
- }
- if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
- cpr_irq_clr_nack(cpr_vreg);
- return;
- }
- cpr_vreg->last_volt[corner] = new_volt;
- /* Restore default threshold for UP */
- reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
- RBCPR_CTL_UP_THRESHOLD_SHIFT;
- reg_val = cpr_vreg->up_threshold <<
- RBCPR_CTL_UP_THRESHOLD_SHIFT;
- cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
- /* Re-enable default interrupts */
- cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
- /* Ack */
- cpr_irq_clr_ack(cpr_vreg);
- cpr_debug_irq(cpr_vreg,
- "DOWN: -> new_volt[corner:%d, fuse_corner:%d] = %d uV\n",
- corner, fuse_corner, new_volt);
- }
- }
- static irqreturn_t cpr_irq_handler(int irq, void *dev)
- {
- struct cpr_regulator *cpr_vreg = dev;
- u32 reg_val;
- mutex_lock(&cpr_vreg->cpr_mutex);
- reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
- if (cpr_vreg->flags & FLAGS_IGNORE_1ST_IRQ_STATUS)
- reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
- cpr_debug_irq(cpr_vreg, "IRQ_STATUS = 0x%02X\n", reg_val);
- if (!cpr_ctl_is_enabled(cpr_vreg)) {
- cpr_debug_irq(cpr_vreg, "CPR is disabled\n");
- goto _exit;
- } else if (cpr_ctl_is_busy(cpr_vreg)
- && !cpr_vreg->clamp_timer_interval) {
- cpr_debug_irq(cpr_vreg, "CPR measurement is not ready\n");
- goto _exit;
- } else if (!cpr_is_allowed(cpr_vreg)) {
- reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
- cpr_err(cpr_vreg, "Interrupt broken? RBCPR_CTL = 0x%02X\n",
- reg_val);
- goto _exit;
- }
- /* Following sequence of handling is as per each IRQ's priority */
- if (reg_val & CPR_INT_UP) {
- cpr_scale(cpr_vreg, UP);
- } else if (reg_val & CPR_INT_DOWN) {
- cpr_scale(cpr_vreg, DOWN);
- } else if (reg_val & CPR_INT_MIN) {
- cpr_irq_clr_nack(cpr_vreg);
- } else if (reg_val & CPR_INT_MAX) {
- cpr_irq_clr_nack(cpr_vreg);
- } else if (reg_val & CPR_INT_MID) {
- /* RBCPR_CTL_SW_AUTO_CONT_ACK_EN is enabled */
- cpr_debug_irq(cpr_vreg, "IRQ occurred for Mid Flag\n");
- } else {
- cpr_debug_irq(cpr_vreg,
- "IRQ occurred for unknown flag (0x%08x)\n", reg_val);
- }
- /* Save register values for the corner */
- cpr_corner_save(cpr_vreg, cpr_vreg->corner);
- _exit:
- mutex_unlock(&cpr_vreg->cpr_mutex);
- return IRQ_HANDLED;
- }
- /**
- * cmp_int() - int comparison function to be passed into the sort() function
- * which leads to ascending sorting
- * @a: First int value
- * @b: Second int value
- *
- * Return: >0 if a > b, 0 if a == b, <0 if a < b
- */
- static int cmp_int(const void *a, const void *b)
- {
- return *(int *)a - *(int *)b;
- }
- static int cpr_get_aging_quot_delta(struct cpr_regulator *cpr_vreg,
- struct cpr_aging_sensor_info *aging_sensor_info)
- {
- int quot_min, quot_max, is_aging_measurement, aging_measurement_count;
- int quot_min_scaled, quot_max_scaled, quot_delta_scaled_sum;
- int retries, rc = 0, sel_fast = 0, i, quot_delta_scaled;
- u32 val, gcnt_ref, gcnt;
- int *quot_delta_results, filtered_count;
- quot_delta_results = kcalloc(CPR_AGING_MEASUREMENT_ITERATIONS,
- sizeof(*quot_delta_results), GFP_ATOMIC);
- if (!quot_delta_results)
- return -ENOMEM;
- /* Clear the target quotient value and gate count of all ROs */
- for (i = 0; i < CPR_NUM_RING_OSC; i++)
- cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(i), 0);
- /* Program GCNT0/1 for getting aging data */
- gcnt_ref = (cpr_vreg->ref_clk_khz * cpr_vreg->gcnt_time_us) / 1000;
- gcnt = gcnt_ref * 3 / 2;
- val = (gcnt & RBCPR_GCNT_TARGET_GCNT_MASK) <<
- RBCPR_GCNT_TARGET_GCNT_SHIFT;
- cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(0), val);
- cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(1), val);
- val = cpr_read(cpr_vreg, REG_RBCPR_GCNT_TARGET(0));
- cpr_debug(cpr_vreg, "RBCPR_GCNT_TARGET0 = 0x%08x\n", val);
- val = cpr_read(cpr_vreg, REG_RBCPR_GCNT_TARGET(1));
- cpr_debug(cpr_vreg, "RBCPR_GCNT_TARGET1 = 0x%08x\n", val);
- /* Program TIMER_INTERVAL to zero */
- cpr_write(cpr_vreg, REG_RBCPR_TIMER_INTERVAL, 0);
- /* Bypass sensors in collapsible domain */
- if (cpr_vreg->aging_info->aging_sensor_bypass)
- cpr_write(cpr_vreg, REG_RBCPR_SENSOR_BYPASS0,
- (cpr_vreg->aging_info->aging_sensor_bypass &
- RBCPR_SENSOR_MASK0_SENSOR(aging_sensor_info->sensor_id)));
- /* Mask other sensors */
- cpr_write(cpr_vreg, REG_RBCPR_SENSOR_MASK0,
- RBCPR_SENSOR_MASK0_SENSOR(aging_sensor_info->sensor_id));
- val = cpr_read(cpr_vreg, REG_RBCPR_SENSOR_MASK0);
- cpr_debug(cpr_vreg, "RBCPR_SENSOR_MASK0 = 0x%08x\n", val);
- /* Enable cpr controller */
- cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, RBCPR_CTL_LOOP_EN);
- /* Make sure cpr starts measurement with toggling busy bit */
- mb();
- /* Wait and Ignore the first measurement. Time-out after 5ms */
- retries = 50;
- while (retries-- && cpr_ctl_is_busy(cpr_vreg))
- udelay(100);
- if (retries < 0) {
- cpr_err(cpr_vreg, "Aging calibration failed\n");
- rc = -EBUSY;
- goto _exit;
- }
- /* Set age page mode */
- cpr_write(cpr_vreg, REG_RBCPR_HTOL_AGE, RBCPR_HTOL_AGE_PAGE);
- aging_measurement_count = 0;
- quot_delta_scaled_sum = 0;
- for (i = 0; i < CPR_AGING_MEASUREMENT_ITERATIONS; i++) {
- /* Send cont nack */
- cpr_write(cpr_vreg, REG_RBIF_CONT_NACK_CMD, 1);
- /*
- * Make sure cpr starts next measurement with
- * toggling busy bit
- */
- mb();
- /*
- * Wait for controller to finish measurement
- * and time-out after 5ms
- */
- retries = 50;
- while (retries-- && cpr_ctl_is_busy(cpr_vreg))
- udelay(100);
- if (retries < 0) {
- cpr_err(cpr_vreg, "Aging calibration failed\n");
- rc = -EBUSY;
- goto _exit;
- }
- /* Check for PAGE_IS_AGE flag in status register */
- val = cpr_read(cpr_vreg, REG_RBCPR_HTOL_AGE);
- is_aging_measurement = val & RBCPR_AGE_DATA_STATUS;
- val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_1);
- sel_fast = RBCPR_RESULT_1_SEL_FAST(val);
- cpr_debug(cpr_vreg, "RBCPR_RESULT_1 = 0x%08x\n", val);
- val = cpr_read(cpr_vreg, REG_RBCPR_DEBUG1);
- cpr_debug(cpr_vreg, "RBCPR_DEBUG1 = 0x%08x\n", val);
- if (sel_fast == 1) {
- quot_min = RBCPR_DEBUG1_QUOT_FAST(val);
- quot_max = RBCPR_DEBUG1_QUOT_SLOW(val);
- } else {
- quot_min = RBCPR_DEBUG1_QUOT_SLOW(val);
- quot_max = RBCPR_DEBUG1_QUOT_FAST(val);
- }
- /*
- * Scale the quotients so that they are equivalent to the fused
- * values. This accounts for the difference in measurement
- * interval times.
- */
- quot_min_scaled = quot_min * (gcnt_ref + 1) / (gcnt + 1);
- quot_max_scaled = quot_max * (gcnt_ref + 1) / (gcnt + 1);
- quot_delta_scaled = 0;
- if (is_aging_measurement) {
- quot_delta_scaled = quot_min_scaled - quot_max_scaled;
- quot_delta_results[aging_measurement_count++] =
- quot_delta_scaled;
- }
- cpr_debug(cpr_vreg,
- "Age sensor[%d]: measurement[%d]: page_is_age=%u quot_min = %d, quot_max = %d quot_min_scaled = %d, quot_max_scaled = %d quot_delta_scaled = %d\n",
- aging_sensor_info->sensor_id, i, is_aging_measurement,
- quot_min, quot_max, quot_min_scaled, quot_max_scaled,
- quot_delta_scaled);
- }
- filtered_count
- = aging_measurement_count - CPR_AGING_MEASUREMENT_FILTER * 2;
- if (filtered_count > 0) {
- sort(quot_delta_results, aging_measurement_count,
- sizeof(*quot_delta_results), cmp_int, NULL);
- quot_delta_scaled_sum = 0;
- for (i = 0; i < filtered_count; i++)
- quot_delta_scaled_sum
- += quot_delta_results[i
- + CPR_AGING_MEASUREMENT_FILTER];
- aging_sensor_info->current_quot_diff
- = quot_delta_scaled_sum / filtered_count;
- cpr_debug(cpr_vreg,
- "Age sensor[%d]: average aging quotient delta = %d (count = %d)\n",
- aging_sensor_info->sensor_id,
- aging_sensor_info->current_quot_diff, filtered_count);
- } else {
- cpr_err(cpr_vreg, "%d aging measurements completed after %d iterations\n",
- aging_measurement_count,
- CPR_AGING_MEASUREMENT_ITERATIONS);
- rc = -EBUSY;
- }
- _exit:
- /* Clear age page bit */
- cpr_write(cpr_vreg, REG_RBCPR_HTOL_AGE, 0x0);
- /* Disable the CPR controller after aging procedure */
- cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0x0);
- /* Clear the sensor bypass */
- if (cpr_vreg->aging_info->aging_sensor_bypass)
- cpr_write(cpr_vreg, REG_RBCPR_SENSOR_BYPASS0, 0x0);
- /* Unmask all sensors */
- cpr_write(cpr_vreg, REG_RBCPR_SENSOR_MASK0, 0x0);
- /* Clear gcnt0/1 registers */
- cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(0), 0x0);
- cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(1), 0x0);
- /* Program the delay count for the timer */
- val = (cpr_vreg->ref_clk_khz * cpr_vreg->timer_delay_us) / 1000;
- cpr_write(cpr_vreg, REG_RBCPR_TIMER_INTERVAL, val);
- kfree(quot_delta_results);
- return rc;
- }
- static void cpr_de_aging_adjustment(void *data)
- {
- struct cpr_regulator *cpr_vreg = (struct cpr_regulator *)data;
- struct cpr_aging_info *aging_info = cpr_vreg->aging_info;
- struct cpr_aging_sensor_info *aging_sensor_info;
- int i, num_aging_sensors, retries, rc = 0;
- int max_quot_diff = 0, ro_sel = 0;
- u32 voltage_adjust, aging_voltage_adjust = 0;
- aging_sensor_info = aging_info->sensor_info;
- num_aging_sensors = aging_info->num_aging_sensors;
- for (i = 0; i < num_aging_sensors; i++, aging_sensor_info++) {
- retries = 2;
- while (retries--) {
- rc = cpr_get_aging_quot_delta(cpr_vreg,
- aging_sensor_info);
- if (!rc)
- break;
- }
- if (rc && retries < 0) {
- cpr_err(cpr_vreg, "error in age calibration: rc = %d\n",
- rc);
- aging_info->cpr_aging_error = true;
- return;
- }
- max_quot_diff = max(max_quot_diff,
- (aging_sensor_info->current_quot_diff -
- aging_sensor_info->initial_quot_diff));
- }
- cpr_debug(cpr_vreg, "Max aging quot delta = %d\n",
- max_quot_diff);
- aging_voltage_adjust = DIV_ROUND_UP(max_quot_diff * 1000000,
- aging_info->aging_ro_kv);
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- /* Remove initial max aging adjustment */
- ro_sel = cpr_vreg->cpr_fuse_ro_sel[i];
- cpr_vreg->cpr_fuse_target_quot[i] -=
- (aging_info->cpr_ro_kv[ro_sel]
- * aging_info->max_aging_margin) / 1000000;
- aging_info->voltage_adjust[i] = 0;
- if (aging_voltage_adjust > 0) {
- /* Add required aging adjustment */
- voltage_adjust = (aging_voltage_adjust
- * aging_info->aging_derate[i]) / 1000;
- voltage_adjust = min(voltage_adjust,
- aging_info->max_aging_margin);
- cpr_vreg->cpr_fuse_target_quot[i] +=
- (aging_info->cpr_ro_kv[ro_sel]
- * voltage_adjust) / 1000000;
- aging_info->voltage_adjust[i] = voltage_adjust;
- }
- }
- }
- static int cpr_regulator_is_enabled(struct regulator_dev *rdev)
- {
- struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- return cpr_vreg->vreg_enabled;
- }
- static int cpr_regulator_enable(struct regulator_dev *rdev)
- {
- struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- int rc = 0;
- /* Enable dependency power before vdd_apc */
- if (cpr_vreg->vdd_mx) {
- rc = regulator_enable(cpr_vreg->vdd_mx);
- if (rc) {
- cpr_err(cpr_vreg, "regulator_enable: vdd_mx: rc=%d\n",
- rc);
- return rc;
- }
- }
- rc = regulator_enable(cpr_vreg->vdd_apc);
- if (rc) {
- cpr_err(cpr_vreg, "regulator_enable: vdd_apc: rc=%d\n", rc);
- return rc;
- }
- mutex_lock(&cpr_vreg->cpr_mutex);
- cpr_vreg->vreg_enabled = true;
- if (cpr_is_allowed(cpr_vreg) && cpr_vreg->corner) {
- cpr_irq_clr(cpr_vreg);
- cpr_corner_restore(cpr_vreg, cpr_vreg->corner);
- cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
- }
- mutex_unlock(&cpr_vreg->cpr_mutex);
- return rc;
- }
- static int cpr_regulator_disable(struct regulator_dev *rdev)
- {
- struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- int rc;
- rc = regulator_disable(cpr_vreg->vdd_apc);
- if (!rc) {
- if (cpr_vreg->vdd_mx)
- rc = regulator_disable(cpr_vreg->vdd_mx);
- if (rc) {
- cpr_err(cpr_vreg, "regulator_disable: vdd_mx: rc=%d\n",
- rc);
- return rc;
- }
- mutex_lock(&cpr_vreg->cpr_mutex);
- cpr_vreg->vreg_enabled = false;
- if (cpr_is_allowed(cpr_vreg))
- cpr_ctl_disable(cpr_vreg);
- mutex_unlock(&cpr_vreg->cpr_mutex);
- } else {
- cpr_err(cpr_vreg, "regulator_disable: vdd_apc: rc=%d\n", rc);
- }
- return rc;
- }
- static int cpr_calculate_de_aging_margin(struct cpr_regulator *cpr_vreg)
- {
- struct cpr_aging_info *aging_info = cpr_vreg->aging_info;
- enum voltage_change_dir change_dir = NO_CHANGE;
- u32 save_ctl, save_irq;
- cpumask_t tmp_mask;
- int rc = 0, i;
- save_ctl = cpr_read(cpr_vreg, REG_RBCPR_CTL);
- save_irq = cpr_read(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line));
- /* Disable interrupt and CPR */
- cpr_irq_set(cpr_vreg, 0);
- cpr_write(cpr_vreg, REG_RBCPR_CTL, 0);
- if (aging_info->aging_corner > cpr_vreg->corner)
- change_dir = UP;
- else if (aging_info->aging_corner < cpr_vreg->corner)
- change_dir = DOWN;
- /* set selected reference voltage for de-aging */
- rc = cpr_scale_voltage(cpr_vreg,
- aging_info->aging_corner,
- aging_info->aging_ref_voltage,
- change_dir);
- if (rc) {
- cpr_err(cpr_vreg, "Unable to set aging reference voltage, rc = %d\n",
- rc);
- return rc;
- }
- /* Force PWM mode */
- rc = regulator_set_mode(cpr_vreg->vdd_apc, REGULATOR_MODE_NORMAL);
- if (rc) {
- cpr_err(cpr_vreg, "unable to configure vdd-supply for mode=%u, rc=%d\n",
- REGULATOR_MODE_NORMAL, rc);
- return rc;
- }
- get_online_cpus();
- cpumask_and(&tmp_mask, &cpr_vreg->cpu_mask, cpu_online_mask);
- if (!cpumask_empty(&tmp_mask)) {
- smp_call_function_any(&tmp_mask,
- cpr_de_aging_adjustment,
- cpr_vreg, true);
- aging_info->cpr_aging_done = true;
- if (!aging_info->cpr_aging_error)
- for (i = CPR_FUSE_CORNER_MIN;
- i <= cpr_vreg->num_fuse_corners; i++)
- cpr_info(cpr_vreg, "Corner[%d]: age adjusted target quot = %d\n",
- i, cpr_vreg->cpr_fuse_target_quot[i]);
- }
- put_online_cpus();
- /* Set to initial mode */
- rc = regulator_set_mode(cpr_vreg->vdd_apc, REGULATOR_MODE_IDLE);
- if (rc) {
- cpr_err(cpr_vreg, "unable to configure vdd-supply for mode=%u, rc=%d\n",
- REGULATOR_MODE_IDLE, rc);
- return rc;
- }
- /* Clear interrupts */
- cpr_irq_clr(cpr_vreg);
- /* Restore register values */
- cpr_irq_set(cpr_vreg, save_irq);
- cpr_write(cpr_vreg, REG_RBCPR_CTL, save_ctl);
- return rc;
- }
- /* Note that cpr_vreg->cpr_mutex must be held by the caller. */
- static int cpr_regulator_set_voltage(struct regulator_dev *rdev,
- int corner, bool reset_quot)
- {
- struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- struct cpr_aging_info *aging_info = cpr_vreg->aging_info;
- int rc;
- int new_volt;
- enum voltage_change_dir change_dir = NO_CHANGE;
- int fuse_corner = cpr_vreg->corner_map[corner];
- if (cpr_is_allowed(cpr_vreg)) {
- cpr_ctl_disable(cpr_vreg);
- new_volt = cpr_vreg->last_volt[corner];
- } else {
- new_volt = cpr_vreg->open_loop_volt[corner];
- }
- cpr_debug(cpr_vreg, "[corner:%d, fuse_corner:%d] = %d uV\n",
- corner, fuse_corner, new_volt);
- if (corner > cpr_vreg->corner)
- change_dir = UP;
- else if (corner < cpr_vreg->corner)
- change_dir = DOWN;
- /* Read age sensor data and apply de-aging adjustments */
- if (cpr_vreg->vreg_enabled && aging_info && !aging_info->cpr_aging_done
- && (corner <= aging_info->aging_corner)) {
- rc = cpr_calculate_de_aging_margin(cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "failed in de-aging calibration: rc=%d\n",
- rc);
- } else {
- change_dir = NO_CHANGE;
- if (corner > aging_info->aging_corner)
- change_dir = UP;
- else if (corner < aging_info->aging_corner)
- change_dir = DOWN;
- }
- reset_quot = true;
- }
- rc = cpr_scale_voltage(cpr_vreg, corner, new_volt, change_dir);
- if (rc)
- return rc;
- if (cpr_is_allowed(cpr_vreg) && cpr_vreg->vreg_enabled) {
- cpr_irq_clr(cpr_vreg);
- if (reset_quot)
- cpr_corner_restore(cpr_vreg, corner);
- else
- cpr_corner_switch(cpr_vreg, corner);
- cpr_ctl_enable(cpr_vreg, corner);
- }
- cpr_vreg->corner = corner;
- return rc;
- }
- static int cpr_regulator_set_voltage_op(struct regulator_dev *rdev,
- int corner, int corner_max, unsigned *selector)
- {
- struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- int rc;
- mutex_lock(&cpr_vreg->cpr_mutex);
- rc = cpr_regulator_set_voltage(rdev, corner, false);
- mutex_unlock(&cpr_vreg->cpr_mutex);
- return rc;
- }
- static int cpr_regulator_get_voltage(struct regulator_dev *rdev)
- {
- struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- return cpr_vreg->corner;
- }
- /**
- * cpr_regulator_list_corner_voltage() - return the ceiling voltage mapped to
- * the specified voltage corner
- * @rdev: Regulator device pointer for the cpr-regulator
- * @corner: Voltage corner
- *
- * This function is passed as a callback function into the regulator ops that
- * are registered for each cpr-regulator device.
- *
- * Return: voltage value in microvolts or -EINVAL if the corner is out of range
- */
- static int cpr_regulator_list_corner_voltage(struct regulator_dev *rdev,
- int corner)
- {
- struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- if (corner >= CPR_CORNER_MIN && corner <= cpr_vreg->num_corners)
- return cpr_vreg->ceiling_volt[corner];
- else
- return -EINVAL;
- }
- static struct regulator_ops cpr_corner_ops = {
- .enable = cpr_regulator_enable,
- .disable = cpr_regulator_disable,
- .is_enabled = cpr_regulator_is_enabled,
- .set_voltage = cpr_regulator_set_voltage_op,
- .get_voltage = cpr_regulator_get_voltage,
- .list_corner_voltage = cpr_regulator_list_corner_voltage,
- };
- #ifdef CONFIG_PM
- static int cpr_suspend(struct cpr_regulator *cpr_vreg)
- {
- cpr_debug(cpr_vreg, "suspend\n");
- cpr_ctl_disable(cpr_vreg);
- cpr_irq_clr(cpr_vreg);
- return 0;
- }
- static int cpr_resume(struct cpr_regulator *cpr_vreg)
- {
- cpr_debug(cpr_vreg, "resume\n");
- cpr_irq_clr(cpr_vreg);
- cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
- return 0;
- }
- static int cpr_regulator_suspend(struct platform_device *pdev,
- pm_message_t state)
- {
- struct cpr_regulator *cpr_vreg = platform_get_drvdata(pdev);
- int rc = 0;
- mutex_lock(&cpr_vreg->cpr_mutex);
- if (cpr_is_allowed(cpr_vreg))
- rc = cpr_suspend(cpr_vreg);
- cpr_vreg->is_cpr_suspended = true;
- mutex_unlock(&cpr_vreg->cpr_mutex);
- return rc;
- }
- static int cpr_regulator_resume(struct platform_device *pdev)
- {
- struct cpr_regulator *cpr_vreg = platform_get_drvdata(pdev);
- int rc = 0;
- mutex_lock(&cpr_vreg->cpr_mutex);
- cpr_vreg->is_cpr_suspended = false;
- if (cpr_is_allowed(cpr_vreg))
- rc = cpr_resume(cpr_vreg);
- mutex_unlock(&cpr_vreg->cpr_mutex);
- return rc;
- }
- #else
- #define cpr_regulator_suspend NULL
- #define cpr_regulator_resume NULL
- #endif
- static int cpr_config(struct cpr_regulator *cpr_vreg, struct device *dev)
- {
- int i;
- u32 val, gcnt, reg;
- void __iomem *rbcpr_clk;
- int size;
- if (cpr_vreg->rbcpr_clk_addr) {
- /* Use 19.2 MHz clock for CPR. */
- rbcpr_clk = ioremap(cpr_vreg->rbcpr_clk_addr, 4);
- if (!rbcpr_clk) {
- cpr_err(cpr_vreg, "Unable to map rbcpr_clk\n");
- return -EINVAL;
- }
- reg = readl_relaxed(rbcpr_clk);
- reg &= ~RBCPR_CLK_SEL_MASK;
- reg |= RBCPR_CLK_SEL_19P2_MHZ & RBCPR_CLK_SEL_MASK;
- writel_relaxed(reg, rbcpr_clk);
- iounmap(rbcpr_clk);
- }
- /* Disable interrupt and CPR */
- cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), 0);
- cpr_write(cpr_vreg, REG_RBCPR_CTL, 0);
- /* Program the default HW Ceiling, Floor and vlevel */
- val = ((RBIF_LIMIT_CEILING_DEFAULT & RBIF_LIMIT_CEILING_MASK)
- << RBIF_LIMIT_CEILING_SHIFT)
- | (RBIF_LIMIT_FLOOR_DEFAULT & RBIF_LIMIT_FLOOR_MASK);
- cpr_write(cpr_vreg, REG_RBIF_LIMIT, val);
- cpr_write(cpr_vreg, REG_RBIF_SW_VLEVEL, RBIF_SW_VLEVEL_DEFAULT);
- /* Clear the target quotient value and gate count of all ROs */
- for (i = 0; i < CPR_NUM_RING_OSC; i++)
- cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(i), 0);
- /* Init and save gcnt */
- gcnt = (cpr_vreg->ref_clk_khz * cpr_vreg->gcnt_time_us) / 1000;
- gcnt = (gcnt & RBCPR_GCNT_TARGET_GCNT_MASK) <<
- RBCPR_GCNT_TARGET_GCNT_SHIFT;
- cpr_vreg->gcnt = gcnt;
- /* Program the delay count for the timer */
- val = (cpr_vreg->ref_clk_khz * cpr_vreg->timer_delay_us) / 1000;
- cpr_write(cpr_vreg, REG_RBCPR_TIMER_INTERVAL, val);
- cpr_info(cpr_vreg, "Timer count: 0x%0x (for %d us)\n", val,
- cpr_vreg->timer_delay_us);
- /* Program Consecutive Up & Down */
- val = ((cpr_vreg->timer_cons_down & RBIF_TIMER_ADJ_CONS_DOWN_MASK)
- << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT) |
- (cpr_vreg->timer_cons_up & RBIF_TIMER_ADJ_CONS_UP_MASK) |
- ((cpr_vreg->clamp_timer_interval & RBIF_TIMER_ADJ_CLAMP_INT_MASK)
- << RBIF_TIMER_ADJ_CLAMP_INT_SHIFT);
- cpr_write(cpr_vreg, REG_RBIF_TIMER_ADJUST, val);
- /* Program the control register */
- cpr_vreg->up_threshold &= RBCPR_CTL_UP_THRESHOLD_MASK;
- cpr_vreg->down_threshold &= RBCPR_CTL_DN_THRESHOLD_MASK;
- val = (cpr_vreg->up_threshold << RBCPR_CTL_UP_THRESHOLD_SHIFT)
- | (cpr_vreg->down_threshold << RBCPR_CTL_DN_THRESHOLD_SHIFT);
- val |= RBCPR_CTL_TIMER_EN | RBCPR_CTL_COUNT_MODE;
- val |= RBCPR_CTL_SW_AUTO_CONT_ACK_EN;
- cpr_write(cpr_vreg, REG_RBCPR_CTL, val);
- cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
- val = cpr_read(cpr_vreg, REG_RBCPR_VERSION);
- if (val <= RBCPR_VER_2)
- cpr_vreg->flags |= FLAGS_IGNORE_1ST_IRQ_STATUS;
- size = cpr_vreg->num_corners + 1;
- cpr_vreg->save_ctl = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
- cpr_vreg->save_irq = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
- if (!cpr_vreg->save_ctl || !cpr_vreg->save_irq)
- return -ENOMEM;
- for (i = 1; i < size; i++)
- cpr_corner_save(cpr_vreg, i);
- return 0;
- }
- static int cpr_fuse_is_setting_expected(struct cpr_regulator *cpr_vreg,
- u32 sel_array[5])
- {
- u64 fuse_bits;
- u32 ret;
- fuse_bits = cpr_read_efuse_row(cpr_vreg, sel_array[0], sel_array[4]);
- ret = (fuse_bits >> sel_array[1]) & ((1 << sel_array[2]) - 1);
- if (ret == sel_array[3])
- ret = 1;
- else
- ret = 0;
- cpr_info(cpr_vreg, "[row:%d] = 0x%llx @%d:%d == %d ?: %s\n",
- sel_array[0], fuse_bits,
- sel_array[1], sel_array[2],
- sel_array[3],
- (ret == 1) ? "yes" : "no");
- return ret;
- }
- static int cpr_voltage_uplift_wa_inc_volt(struct cpr_regulator *cpr_vreg,
- struct device_node *of_node)
- {
- u32 uplift_voltage;
- u32 uplift_max_volt = 0;
- int highest_fuse_corner = cpr_vreg->num_fuse_corners;
- int rc;
- rc = of_property_read_u32(of_node,
- "qcom,cpr-uplift-voltage", &uplift_voltage);
- if (rc < 0) {
- cpr_err(cpr_vreg, "cpr-uplift-voltage is missing, rc = %d", rc);
- return rc;
- }
- rc = of_property_read_u32(of_node,
- "qcom,cpr-uplift-max-volt", &uplift_max_volt);
- if (rc < 0) {
- cpr_err(cpr_vreg, "cpr-uplift-max-volt is missing, rc = %d",
- rc);
- return rc;
- }
- cpr_vreg->pvs_corner_v[highest_fuse_corner] += uplift_voltage;
- if (cpr_vreg->pvs_corner_v[highest_fuse_corner] > uplift_max_volt)
- cpr_vreg->pvs_corner_v[highest_fuse_corner] = uplift_max_volt;
- return rc;
- }
- static int cpr_adjust_init_voltages(struct device_node *of_node,
- struct cpr_regulator *cpr_vreg)
- {
- int tuple_count, tuple_match, i;
- u32 index;
- u32 volt_adjust = 0;
- int len = 0;
- int rc = 0;
- if (!of_find_property(of_node, "qcom,cpr-init-voltage-adjustment",
- &len)) {
- /* No initial voltage adjustment needed. */
- return 0;
- }
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) {
- /*
- * No matching index to use for initial voltage
- * adjustment.
- */
- return 0;
- }
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != cpr_vreg->num_fuse_corners * tuple_count * sizeof(u32)) {
- cpr_err(cpr_vreg, "qcom,cpr-init-voltage-adjustment length=%d is invalid\n",
- len);
- return -EINVAL;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- index = tuple_match * cpr_vreg->num_fuse_corners
- + i - CPR_FUSE_CORNER_MIN;
- rc = of_property_read_u32_index(of_node,
- "qcom,cpr-init-voltage-adjustment", index,
- &volt_adjust);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,cpr-init-voltage-adjustment index %u, rc=%d\n",
- index, rc);
- return rc;
- }
- if (volt_adjust) {
- cpr_vreg->pvs_corner_v[i] += volt_adjust;
- cpr_info(cpr_vreg, "adjusted initial voltage[%d]: %d -> %d uV\n",
- i, cpr_vreg->pvs_corner_v[i] - volt_adjust,
- cpr_vreg->pvs_corner_v[i]);
- }
- }
- return rc;
- }
- /*
- * Property qcom,cpr-fuse-init-voltage specifies the fuse position of the
- * initial voltage for each fuse corner. MSB of the fuse value is a sign
- * bit, and the remaining bits define the steps of the offset. Each step has
- * units of microvolts defined in the qcom,cpr-fuse-init-voltage-step property.
- * The initial voltages can be calculated using the formula:
- * pvs_corner_v[corner] = ceiling_volt[corner] + (sign * steps * step_size_uv)
- */
- static int cpr_pvs_per_corner_init(struct device_node *of_node,
- struct cpr_regulator *cpr_vreg)
- {
- u64 efuse_bits;
- int i, size, sign, steps, step_size_uv, rc;
- u32 *fuse_sel, *tmp, *ref_uv;
- struct property *prop;
- char *init_volt_str;
- init_volt_str = cpr_vreg->cpr_fuse_redundant
- ? "qcom,cpr-fuse-redun-init-voltage"
- : "qcom,cpr-fuse-init-voltage";
- prop = of_find_property(of_node, init_volt_str, NULL);
- if (!prop) {
- cpr_err(cpr_vreg, "%s is missing\n", init_volt_str);
- return -EINVAL;
- }
- size = prop->length / sizeof(u32);
- if (size != cpr_vreg->num_fuse_corners * 4) {
- cpr_err(cpr_vreg,
- "fuse position for init voltages is invalid\n");
- return -EINVAL;
- }
- fuse_sel = kzalloc(sizeof(u32) * size, GFP_KERNEL);
- if (!fuse_sel) {
- cpr_err(cpr_vreg, "memory alloc failed.\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(of_node, init_volt_str,
- fuse_sel, size);
- if (rc < 0) {
- cpr_err(cpr_vreg,
- "read cpr-fuse-init-voltage failed, rc = %d\n", rc);
- kfree(fuse_sel);
- return rc;
- }
- rc = of_property_read_u32(of_node, "qcom,cpr-init-voltage-step",
- &step_size_uv);
- if (rc < 0) {
- cpr_err(cpr_vreg,
- "read cpr-init-voltage-step failed, rc = %d\n", rc);
- kfree(fuse_sel);
- return rc;
- }
- ref_uv = kzalloc((cpr_vreg->num_fuse_corners + 1) * sizeof(*ref_uv),
- GFP_KERNEL);
- if (!ref_uv) {
- cpr_err(cpr_vreg,
- "Could not allocate memory for reference voltages\n");
- kfree(fuse_sel);
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(of_node, "qcom,cpr-init-voltage-ref",
- &ref_uv[CPR_FUSE_CORNER_MIN], cpr_vreg->num_fuse_corners);
- if (rc < 0) {
- cpr_err(cpr_vreg,
- "read qcom,cpr-init-voltage-ref failed, rc = %d\n", rc);
- kfree(fuse_sel);
- kfree(ref_uv);
- return rc;
- }
- tmp = fuse_sel;
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- efuse_bits = cpr_read_efuse_param(cpr_vreg, fuse_sel[0],
- fuse_sel[1], fuse_sel[2], fuse_sel[3]);
- sign = (efuse_bits & (1 << (fuse_sel[2] - 1))) ? -1 : 1;
- steps = efuse_bits & ((1 << (fuse_sel[2] - 1)) - 1);
- cpr_vreg->pvs_corner_v[i] =
- ref_uv[i] + sign * steps * step_size_uv;
- cpr_vreg->pvs_corner_v[i] = DIV_ROUND_UP(
- cpr_vreg->pvs_corner_v[i],
- cpr_vreg->step_volt) *
- cpr_vreg->step_volt;
- cpr_debug(cpr_vreg, "corner %d: sign = %d, steps = %d, volt = %d uV\n",
- i, sign, steps, cpr_vreg->pvs_corner_v[i]);
- fuse_sel += 4;
- }
- rc = cpr_adjust_init_voltages(of_node, cpr_vreg);
- if (rc)
- goto done;
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- if (cpr_vreg->pvs_corner_v[i]
- > cpr_vreg->fuse_ceiling_volt[i]) {
- cpr_info(cpr_vreg, "Warning: initial voltage[%d] %d above ceiling %d\n",
- i, cpr_vreg->pvs_corner_v[i],
- cpr_vreg->fuse_ceiling_volt[i]);
- cpr_vreg->pvs_corner_v[i]
- = cpr_vreg->fuse_ceiling_volt[i];
- } else if (cpr_vreg->pvs_corner_v[i] <
- cpr_vreg->fuse_floor_volt[i]) {
- cpr_info(cpr_vreg, "Warning: initial voltage[%d] %d below floor %d\n",
- i, cpr_vreg->pvs_corner_v[i],
- cpr_vreg->fuse_floor_volt[i]);
- cpr_vreg->pvs_corner_v[i]
- = cpr_vreg->fuse_floor_volt[i];
- }
- }
- done:
- kfree(tmp);
- kfree(ref_uv);
- return rc;
- }
- /*
- * A single PVS bin is stored in a fuse that's position is defined either
- * in the qcom,pvs-fuse-redun property or in the qcom,pvs-fuse property.
- * The fuse value defined in the qcom,pvs-fuse-redun-sel property is used
- * to pick between the primary or redudant PVS fuse position.
- * After the PVS bin value is read out successfully, it is used as the row
- * index to get initial voltages for each fuse corner from the voltage table
- * defined in the qcom,pvs-voltage-table property.
- */
- static int cpr_pvs_single_bin_init(struct device_node *of_node,
- struct cpr_regulator *cpr_vreg)
- {
- u64 efuse_bits;
- u32 pvs_fuse[4], pvs_fuse_redun_sel[5];
- int rc, i, stripe_size;
- bool redundant;
- size_t pvs_bins;
- u32 *tmp;
- rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun-sel",
- pvs_fuse_redun_sel, 5);
- if (rc < 0) {
- cpr_err(cpr_vreg, "pvs-fuse-redun-sel missing: rc=%d\n", rc);
- return rc;
- }
- redundant = cpr_fuse_is_setting_expected(cpr_vreg, pvs_fuse_redun_sel);
- if (redundant) {
- rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun",
- pvs_fuse, 4);
- if (rc < 0) {
- cpr_err(cpr_vreg, "pvs-fuse-redun missing: rc=%d\n",
- rc);
- return rc;
- }
- } else {
- rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse",
- pvs_fuse, 4);
- if (rc < 0) {
- cpr_err(cpr_vreg, "pvs-fuse missing: rc=%d\n", rc);
- return rc;
- }
- }
- /* Construct PVS process # from the efuse bits */
- efuse_bits = cpr_read_efuse_row(cpr_vreg, pvs_fuse[0], pvs_fuse[3]);
- cpr_vreg->pvs_bin = (efuse_bits >> pvs_fuse[1]) &
- ((1 << pvs_fuse[2]) - 1);
- pvs_bins = 1 << pvs_fuse[2];
- stripe_size = cpr_vreg->num_fuse_corners;
- tmp = kzalloc(sizeof(u32) * pvs_bins * stripe_size, GFP_KERNEL);
- if (!tmp) {
- cpr_err(cpr_vreg, "memory alloc failed\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(of_node, "qcom,pvs-voltage-table",
- tmp, pvs_bins * stripe_size);
- if (rc < 0) {
- cpr_err(cpr_vreg, "pvs-voltage-table missing: rc=%d\n", rc);
- kfree(tmp);
- return rc;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++)
- cpr_vreg->pvs_corner_v[i] = tmp[cpr_vreg->pvs_bin *
- stripe_size + i - 1];
- kfree(tmp);
- rc = cpr_adjust_init_voltages(of_node, cpr_vreg);
- if (rc)
- return rc;
- return 0;
- }
- /*
- * The function reads VDD_MX dependency parameters from device node.
- * Select the qcom,vdd-mx-corner-map length equal to either num_fuse_corners
- * or num_corners based on selected vdd-mx-vmin-method.
- */
- static int cpr_parse_vdd_mx_parameters(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- u32 corner_map_len;
- int rc, len, size;
- rc = of_property_read_u32(of_node, "qcom,vdd-mx-vmax",
- &cpr_vreg->vdd_mx_vmax);
- if (rc < 0) {
- cpr_err(cpr_vreg, "vdd-mx-vmax missing: rc=%d\n", rc);
- return rc;
- }
- rc = of_property_read_u32(of_node, "qcom,vdd-mx-vmin-method",
- &cpr_vreg->vdd_mx_vmin_method);
- if (rc < 0) {
- cpr_err(cpr_vreg, "vdd-mx-vmin-method missing: rc=%d\n",
- rc);
- return rc;
- }
- if (cpr_vreg->vdd_mx_vmin_method > VDD_MX_VMIN_APC_CORNER_MAP) {
- cpr_err(cpr_vreg, "Invalid vdd-mx-vmin-method(%d)\n",
- cpr_vreg->vdd_mx_vmin_method);
- return -EINVAL;
- }
- switch (cpr_vreg->vdd_mx_vmin_method) {
- case VDD_MX_VMIN_APC_FUSE_CORNER_MAP:
- corner_map_len = cpr_vreg->num_fuse_corners;
- break;
- case VDD_MX_VMIN_APC_CORNER_MAP:
- corner_map_len = cpr_vreg->num_corners;
- break;
- default:
- cpr_vreg->vdd_mx_corner_map = NULL;
- return 0;
- }
- if (!of_find_property(of_node, "qcom,vdd-mx-corner-map", &len)) {
- cpr_err(cpr_vreg, "qcom,vdd-mx-corner-map missing");
- return -EINVAL;
- }
- size = len / sizeof(u32);
- if (size != corner_map_len) {
- cpr_err(cpr_vreg,
- "qcom,vdd-mx-corner-map length=%d is invalid: required:%u\n",
- size, corner_map_len);
- return -EINVAL;
- }
- cpr_vreg->vdd_mx_corner_map = devm_kzalloc(&pdev->dev,
- (corner_map_len + 1) * sizeof(*cpr_vreg->vdd_mx_corner_map),
- GFP_KERNEL);
- if (!cpr_vreg->vdd_mx_corner_map) {
- cpr_err(cpr_vreg,
- "Can't allocate memory for cpr_vreg->vdd_mx_corner_map\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(of_node,
- "qcom,vdd-mx-corner-map",
- &cpr_vreg->vdd_mx_corner_map[1],
- corner_map_len);
- if (rc)
- cpr_err(cpr_vreg,
- "read qcom,vdd-mx-corner-map failed, rc = %d\n", rc);
- return rc;
- }
- #define MAX_CHARS_PER_INT 10
- /*
- * The initial voltage for each fuse corner may be determined by one of two
- * possible styles of fuse. If qcom,cpr-fuse-init-voltage is present, then
- * the initial voltages are encoded in a fuse for each fuse corner. If it is
- * not present, then the initial voltages are all determined using a single
- * PVS bin fuse value.
- */
- static int cpr_pvs_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int highest_fuse_corner = cpr_vreg->num_fuse_corners;
- int i, rc, pos;
- size_t buflen;
- char *buf;
- rc = of_property_read_u32(of_node, "qcom,cpr-apc-volt-step",
- &cpr_vreg->step_volt);
- if (rc < 0) {
- cpr_err(cpr_vreg, "read cpr-apc-volt-step failed, rc = %d\n",
- rc);
- return rc;
- } else if (cpr_vreg->step_volt == 0) {
- cpr_err(cpr_vreg, "apc voltage step size can't be set to 0.\n");
- return -EINVAL;
- }
- if (of_find_property(of_node, "qcom,cpr-fuse-init-voltage", NULL)) {
- rc = cpr_pvs_per_corner_init(of_node, cpr_vreg);
- if (rc < 0) {
- cpr_err(cpr_vreg, "get pvs per corner failed, rc = %d",
- rc);
- return rc;
- }
- } else {
- rc = cpr_pvs_single_bin_init(of_node, cpr_vreg);
- if (rc < 0) {
- cpr_err(cpr_vreg,
- "get pvs from single bin failed, rc = %d", rc);
- return rc;
- }
- }
- if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
- rc = cpr_voltage_uplift_wa_inc_volt(cpr_vreg, of_node);
- if (rc < 0) {
- cpr_err(cpr_vreg, "pvs volt uplift wa apply failed: %d",
- rc);
- return rc;
- }
- }
- /*
- * Allow the highest fuse corner's PVS voltage to define the ceiling
- * voltage for that corner in order to support SoC's in which variable
- * ceiling values are required.
- */
- if (cpr_vreg->pvs_corner_v[highest_fuse_corner] >
- cpr_vreg->fuse_ceiling_volt[highest_fuse_corner])
- cpr_vreg->fuse_ceiling_volt[highest_fuse_corner] =
- cpr_vreg->pvs_corner_v[highest_fuse_corner];
- /*
- * Restrict all fuse corner PVS voltages based upon per corner
- * ceiling and floor voltages.
- */
- for (i = CPR_FUSE_CORNER_MIN; i <= highest_fuse_corner; i++)
- if (cpr_vreg->pvs_corner_v[i] > cpr_vreg->fuse_ceiling_volt[i])
- cpr_vreg->pvs_corner_v[i]
- = cpr_vreg->fuse_ceiling_volt[i];
- else if (cpr_vreg->pvs_corner_v[i]
- < cpr_vreg->fuse_floor_volt[i])
- cpr_vreg->pvs_corner_v[i]
- = cpr_vreg->fuse_floor_volt[i];
- cpr_vreg->ceiling_max
- = cpr_vreg->fuse_ceiling_volt[highest_fuse_corner];
- /*
- * Log ceiling, floor, and inital voltages since they are critical for
- * all CPR debugging.
- */
- buflen = cpr_vreg->num_fuse_corners * (MAX_CHARS_PER_INT + 2)
- * sizeof(*buf);
- buf = kzalloc(buflen, GFP_KERNEL);
- if (buf == NULL) {
- cpr_err(cpr_vreg, "Could not allocate memory for corner voltage logging\n");
- return 0;
- }
- for (i = CPR_FUSE_CORNER_MIN, pos = 0; i <= highest_fuse_corner; i++)
- pos += scnprintf(buf + pos, buflen - pos, "%u%s",
- cpr_vreg->pvs_corner_v[i],
- i < highest_fuse_corner ? " " : "");
- cpr_info(cpr_vreg, "pvs voltage: [%s] uV\n", buf);
- for (i = CPR_FUSE_CORNER_MIN, pos = 0; i <= highest_fuse_corner; i++)
- pos += scnprintf(buf + pos, buflen - pos, "%d%s",
- cpr_vreg->fuse_ceiling_volt[i],
- i < highest_fuse_corner ? " " : "");
- cpr_info(cpr_vreg, "ceiling voltage: [%s] uV\n", buf);
- for (i = CPR_FUSE_CORNER_MIN, pos = 0; i <= highest_fuse_corner; i++)
- pos += scnprintf(buf + pos, buflen - pos, "%d%s",
- cpr_vreg->fuse_floor_volt[i],
- i < highest_fuse_corner ? " " : "");
- cpr_info(cpr_vreg, "floor voltage: [%s] uV\n", buf);
- kfree(buf);
- return 0;
- }
- #define CPR_PROP_READ_U32(cpr_vreg, of_node, cpr_property, cpr_config, rc) \
- do { \
- if (!rc) { \
- rc = of_property_read_u32(of_node, \
- "qcom," cpr_property, \
- cpr_config); \
- if (rc) { \
- cpr_err(cpr_vreg, "Missing " #cpr_property \
- ": rc = %d\n", rc); \
- } \
- } \
- } while (0)
- static int cpr_apc_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int i, rc = 0;
- for (i = 0; i < ARRAY_SIZE(vdd_apc_name); i++) {
- cpr_vreg->vdd_apc = devm_regulator_get_optional(&pdev->dev,
- vdd_apc_name[i]);
- rc = PTR_RET(cpr_vreg->vdd_apc);
- if (!IS_ERR_OR_NULL(cpr_vreg->vdd_apc))
- break;
- }
- if (rc) {
- if (rc != -EPROBE_DEFER)
- cpr_err(cpr_vreg, "devm_regulator_get: rc=%d\n", rc);
- return rc;
- }
- /* Check dependencies */
- if (of_find_property(of_node, "vdd-mx-supply", NULL)) {
- cpr_vreg->vdd_mx = devm_regulator_get(&pdev->dev, "vdd-mx");
- if (IS_ERR_OR_NULL(cpr_vreg->vdd_mx)) {
- rc = PTR_RET(cpr_vreg->vdd_mx);
- if (rc != -EPROBE_DEFER)
- cpr_err(cpr_vreg,
- "devm_regulator_get: vdd-mx: rc=%d\n",
- rc);
- return rc;
- }
- }
- return 0;
- }
- static void cpr_apc_exit(struct cpr_regulator *cpr_vreg)
- {
- if (cpr_vreg->vreg_enabled) {
- regulator_disable(cpr_vreg->vdd_apc);
- if (cpr_vreg->vdd_mx)
- regulator_disable(cpr_vreg->vdd_mx);
- }
- }
- static int cpr_voltage_uplift_wa_inc_quot(struct cpr_regulator *cpr_vreg,
- struct device_node *of_node)
- {
- u32 delta_quot[3];
- int rc, i;
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-uplift-quotient", delta_quot, 3);
- if (rc < 0) {
- cpr_err(cpr_vreg, "cpr-uplift-quotient is missing: %d", rc);
- return rc;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++)
- cpr_vreg->cpr_fuse_target_quot[i] += delta_quot[i-1];
- return rc;
- }
- static void cpr_parse_pvs_version_fuse(struct cpr_regulator *cpr_vreg,
- struct device_node *of_node)
- {
- int rc;
- u64 fuse_bits;
- u32 fuse_sel[4];
- rc = of_property_read_u32_array(of_node,
- "qcom,pvs-version-fuse-sel", fuse_sel, 4);
- if (!rc) {
- fuse_bits = cpr_read_efuse_row(cpr_vreg,
- fuse_sel[0], fuse_sel[3]);
- cpr_vreg->pvs_version = (fuse_bits >> fuse_sel[1]) &
- ((1 << fuse_sel[2]) - 1);
- cpr_info(cpr_vreg, "[row: %d]: 0x%llx, pvs_version = %d\n",
- fuse_sel[0], fuse_bits, cpr_vreg->pvs_version);
- } else {
- cpr_vreg->pvs_version = 0;
- }
- }
- /**
- * cpr_get_open_loop_voltage() - fill the open_loop_volt array with linearly
- * interpolated open-loop CPR voltage values.
- * @cpr_vreg: Handle to the cpr-regulator device
- * @dev: Device pointer for the cpr-regulator device
- * @corner_max: Array of length (cpr_vreg->num_fuse_corners + 1) which maps from
- * fuse corners to the highest virtual corner corresponding to a
- * given fuse corner
- * @freq_map: Array of length (cpr_vreg->num_corners + 1) which maps from
- * virtual corners to frequencies in Hz.
- * @maps_valid: Boolean which indicates if the values in corner_max and freq_map
- * are valid. If they are not valid, then the open_loop_volt
- * values are not interpolated.
- */
- static int cpr_get_open_loop_voltage(struct cpr_regulator *cpr_vreg,
- struct device *dev, const u32 *corner_max, const u32 *freq_map,
- bool maps_valid)
- {
- int rc = 0;
- int i, j;
- u64 volt_high, volt_low, freq_high, freq_low, freq, temp, temp_limit;
- u32 *max_factor = NULL;
- cpr_vreg->open_loop_volt = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_corners + 1), GFP_KERNEL);
- if (!cpr_vreg->open_loop_volt) {
- cpr_err(cpr_vreg,
- "Can't allocate memory for cpr_vreg->open_loop_volt\n");
- return -ENOMEM;
- }
- /*
- * Set open loop voltage to be equal to per-fuse-corner initial voltage
- * by default. This ensures that the open loop voltage is valid for
- * all virtual corners even if some virtual corner to frequency mappings
- * are missing. It also ensures that the voltage is valid for the
- * higher corners not utilized by a given speed-bin.
- */
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++)
- cpr_vreg->open_loop_volt[i]
- = cpr_vreg->pvs_corner_v[cpr_vreg->corner_map[i]];
- if (!maps_valid || !corner_max || !freq_map
- || !of_find_property(dev->of_node,
- "qcom,cpr-voltage-scaling-factor-max", NULL)) {
- /* Not using interpolation */
- return 0;
- }
- max_factor
- = kzalloc(sizeof(*max_factor) * (cpr_vreg->num_fuse_corners + 1),
- GFP_KERNEL);
- if (!max_factor) {
- cpr_err(cpr_vreg, "Could not allocate memory for max_factor array\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-voltage-scaling-factor-max",
- &max_factor[CPR_FUSE_CORNER_MIN],
- cpr_vreg->num_fuse_corners);
- if (rc) {
- cpr_debug(cpr_vreg, "failed to read qcom,cpr-voltage-scaling-factor-max; initial voltage interpolation not possible\n");
- kfree(max_factor);
- return 0;
- }
- for (j = CPR_FUSE_CORNER_MIN + 1; j <= cpr_vreg->num_fuse_corners;
- j++) {
- freq_high = freq_map[corner_max[j]];
- freq_low = freq_map[corner_max[j - 1]];
- volt_high = cpr_vreg->pvs_corner_v[j];
- volt_low = cpr_vreg->pvs_corner_v[j - 1];
- if (freq_high <= freq_low || volt_high <= volt_low)
- continue;
- for (i = corner_max[j - 1] + 1; i < corner_max[j]; i++) {
- freq = freq_map[i];
- if (freq_high <= freq)
- continue;
- temp = (freq_high - freq) * (volt_high - volt_low);
- do_div(temp, (u32)(freq_high - freq_low));
- /*
- * max_factor[j] has units of uV/MHz while freq values
- * have units of Hz. Divide by 1000000 to convert.
- */
- temp_limit = (freq_high - freq) * max_factor[j];
- do_div(temp_limit, 1000000);
- cpr_vreg->open_loop_volt[i]
- = volt_high - min(temp, temp_limit);
- cpr_vreg->open_loop_volt[i]
- = DIV_ROUND_UP(cpr_vreg->open_loop_volt[i],
- cpr_vreg->step_volt)
- * cpr_vreg->step_volt;
- }
- }
- kfree(max_factor);
- return 0;
- }
- /*
- * Limit the per-virtual-corner open-loop voltages using the per-virtual-corner
- * ceiling and floor voltage values. This must be called only after the
- * open_loop_volt, ceiling, and floor arrays have all been initialized.
- */
- static int cpr_limit_open_loop_voltage(struct cpr_regulator *cpr_vreg)
- {
- int i;
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++) {
- if (cpr_vreg->open_loop_volt[i] > cpr_vreg->ceiling_volt[i])
- cpr_vreg->open_loop_volt[i] = cpr_vreg->ceiling_volt[i];
- else if (cpr_vreg->open_loop_volt[i] < cpr_vreg->floor_volt[i])
- cpr_vreg->open_loop_volt[i] = cpr_vreg->floor_volt[i];
- }
- return 0;
- }
- /*
- * Fill an OPP table for the cpr-regulator device struct with pairs of
- * <virtual voltage corner number, open loop voltage> tuples.
- */
- static int cpr_populate_opp_table(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- int i, rc = 0;
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++) {
- rc |= dev_pm_opp_add(dev, i, cpr_vreg->open_loop_volt[i]);
- if (rc)
- cpr_debug(cpr_vreg, "could not add OPP entry <%d, %d>, rc=%d\n",
- i, cpr_vreg->open_loop_volt[i], rc);
- }
- if (rc)
- cpr_err(cpr_vreg, "adding OPP entry failed - OPP may not be enabled, rc=%d\n",
- rc);
- return 0;
- }
- /*
- * Conditionally reduce the per-virtual-corner ceiling voltages if certain
- * device tree flags are present. This must be called only after the ceiling
- * array has been initialized and the open_loop_volt array values have been
- * initialized and limited to the existing floor to ceiling voltage range.
- */
- static int cpr_reduce_ceiling_voltage(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- bool reduce_to_fuse_open_loop, reduce_to_interpolated_open_loop;
- int i;
- reduce_to_fuse_open_loop = of_property_read_bool(dev->of_node,
- "qcom,cpr-init-voltage-as-ceiling");
- reduce_to_interpolated_open_loop = of_property_read_bool(dev->of_node,
- "qcom,cpr-scaled-init-voltage-as-ceiling");
- if (!reduce_to_fuse_open_loop && !reduce_to_interpolated_open_loop)
- return 0;
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++) {
- if (reduce_to_interpolated_open_loop &&
- cpr_vreg->open_loop_volt[i] < cpr_vreg->ceiling_volt[i])
- cpr_vreg->ceiling_volt[i] = cpr_vreg->open_loop_volt[i];
- else if (reduce_to_fuse_open_loop &&
- cpr_vreg->pvs_corner_v[cpr_vreg->corner_map[i]]
- < cpr_vreg->ceiling_volt[i])
- cpr_vreg->ceiling_volt[i]
- = max((u32)cpr_vreg->floor_volt[i],
- cpr_vreg->pvs_corner_v[cpr_vreg->corner_map[i]]);
- cpr_debug(cpr_vreg, "lowered ceiling[%d] = %d uV\n",
- i, cpr_vreg->ceiling_volt[i]);
- }
- return 0;
- }
- static int cpr_adjust_target_quot_offsets(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int tuple_count, tuple_match, i;
- u32 index;
- u32 quot_offset_adjust = 0;
- int len = 0;
- int rc = 0;
- char *quot_offset_str;
- quot_offset_str = "qcom,cpr-quot-offset-adjustment";
- if (!of_find_property(of_node, quot_offset_str, &len)) {
- /* No static quotient adjustment needed. */
- return 0;
- }
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) {
- /* No matching index to use for quotient adjustment. */
- return 0;
- }
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != cpr_vreg->num_fuse_corners * tuple_count * sizeof(u32)) {
- cpr_err(cpr_vreg, "%s length=%d is invalid\n", quot_offset_str,
- len);
- return -EINVAL;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- index = tuple_match * cpr_vreg->num_fuse_corners
- + i - CPR_FUSE_CORNER_MIN;
- rc = of_property_read_u32_index(of_node, quot_offset_str, index,
- "_offset_adjust);
- if (rc) {
- cpr_err(cpr_vreg, "could not read %s index %u, rc=%d\n",
- quot_offset_str, index, rc);
- return rc;
- }
- if (quot_offset_adjust) {
- cpr_vreg->fuse_quot_offset[i] += quot_offset_adjust;
- cpr_info(cpr_vreg, "Corner[%d]: adjusted target quot = %d\n",
- i, cpr_vreg->fuse_quot_offset[i]);
- }
- }
- return rc;
- }
- static int cpr_get_fuse_quot_offset(struct cpr_regulator *cpr_vreg,
- struct platform_device *pdev,
- struct cpr_quot_scale *quot_scale)
- {
- struct device *dev = &pdev->dev;
- struct property *prop;
- u32 *fuse_sel, *tmp, *offset_multiplier = NULL;
- int rc = 0, i, size, len;
- char *quot_offset_str;
- quot_offset_str = cpr_vreg->cpr_fuse_redundant
- ? "qcom,cpr-fuse-redun-quot-offset"
- : "qcom,cpr-fuse-quot-offset";
- prop = of_find_property(dev->of_node, quot_offset_str, NULL);
- if (!prop) {
- cpr_debug(cpr_vreg, "%s not present\n", quot_offset_str);
- return 0;
- } else {
- size = prop->length / sizeof(u32);
- if (size != cpr_vreg->num_fuse_corners * 4) {
- cpr_err(cpr_vreg, "fuse position for quot offset is invalid\n");
- return -EINVAL;
- }
- }
- fuse_sel = kzalloc(sizeof(u32) * size, GFP_KERNEL);
- if (!fuse_sel) {
- cpr_err(cpr_vreg, "memory alloc failed.\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(dev->of_node, quot_offset_str,
- fuse_sel, size);
- if (rc < 0) {
- cpr_err(cpr_vreg, "read %s failed, rc = %d\n", quot_offset_str,
- rc);
- kfree(fuse_sel);
- return rc;
- }
- cpr_vreg->fuse_quot_offset = devm_kzalloc(dev,
- sizeof(u32) * (cpr_vreg->num_fuse_corners + 1),
- GFP_KERNEL);
- if (!cpr_vreg->fuse_quot_offset) {
- cpr_err(cpr_vreg, "Can't allocate memory for cpr_vreg->fuse_quot_offset\n");
- kfree(fuse_sel);
- return -ENOMEM;
- }
- if (!of_find_property(dev->of_node,
- "qcom,cpr-fuse-quot-offset-scale", &len)) {
- cpr_debug(cpr_vreg, "qcom,cpr-fuse-quot-offset-scale not present\n");
- } else {
- if (len != cpr_vreg->num_fuse_corners * sizeof(u32)) {
- cpr_err(cpr_vreg, "the size of qcom,cpr-fuse-quot-offset-scale is invalid\n");
- kfree(fuse_sel);
- return -EINVAL;
- }
- offset_multiplier = kzalloc(sizeof(*offset_multiplier)
- * (cpr_vreg->num_fuse_corners + 1),
- GFP_KERNEL);
- if (!offset_multiplier) {
- cpr_err(cpr_vreg, "memory alloc failed.\n");
- kfree(fuse_sel);
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-fuse-quot-offset-scale",
- &offset_multiplier[1],
- cpr_vreg->num_fuse_corners);
- if (rc < 0) {
- cpr_err(cpr_vreg, "read qcom,cpr-fuse-quot-offset-scale failed, rc = %d\n",
- rc);
- kfree(fuse_sel);
- goto out;
- }
- }
- tmp = fuse_sel;
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- cpr_vreg->fuse_quot_offset[i] = cpr_read_efuse_param(cpr_vreg,
- fuse_sel[0], fuse_sel[1], fuse_sel[2],
- fuse_sel[3]);
- if (offset_multiplier)
- cpr_vreg->fuse_quot_offset[i] *= offset_multiplier[i];
- fuse_sel += 4;
- }
- rc = cpr_adjust_target_quot_offsets(pdev, cpr_vreg);
- kfree(tmp);
- out:
- kfree(offset_multiplier);
- return rc;
- }
- /*
- * Adjust the per-virtual-corner open loop voltage with an offset specfied by a
- * device-tree property. This must be called after open-loop voltage scaling.
- */
- static int cpr_virtual_corner_voltage_adjust(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- char *prop_name = "qcom,cpr-virtual-corner-init-voltage-adjustment";
- int i, rc, tuple_count, tuple_match, index, len;
- u32 voltage_adjust;
- if (!of_find_property(dev->of_node, prop_name, &len)) {
- cpr_debug(cpr_vreg, "%s not specified\n", prop_name);
- return 0;
- }
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) {
- /* No matching index to use for voltage adjustment. */
- return 0;
- }
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != cpr_vreg->num_corners * tuple_count * sizeof(u32)) {
- cpr_err(cpr_vreg, "%s length=%d is invalid\n", prop_name,
- len);
- return -EINVAL;
- }
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++) {
- index = tuple_match * cpr_vreg->num_corners
- + i - CPR_CORNER_MIN;
- rc = of_property_read_u32_index(dev->of_node, prop_name,
- index, &voltage_adjust);
- if (rc) {
- cpr_err(cpr_vreg, "could not read %s index %u, rc=%d\n",
- prop_name, index, rc);
- return rc;
- }
- if (voltage_adjust) {
- cpr_vreg->open_loop_volt[i] += (int)voltage_adjust;
- cpr_info(cpr_vreg, "corner=%d adjusted open-loop voltage=%d\n",
- i, cpr_vreg->open_loop_volt[i]);
- }
- }
- return 0;
- }
- /*
- * Adjust the per-virtual-corner quot with an offset specfied by a
- * device-tree property. This must be called after the quot-scaling adjustments
- * are completed.
- */
- static int cpr_virtual_corner_quot_adjust(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- char *prop_name = "qcom,cpr-virtual-corner-quotient-adjustment";
- int i, rc, tuple_count, tuple_match, index, len;
- u32 quot_adjust;
- if (!of_find_property(dev->of_node, prop_name, &len)) {
- cpr_debug(cpr_vreg, "%s not specified\n", prop_name);
- return 0;
- }
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) {
- /* No matching index to use for quotient adjustment. */
- return 0;
- }
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != cpr_vreg->num_corners * tuple_count * sizeof(u32)) {
- cpr_err(cpr_vreg, "%s length=%d is invalid\n", prop_name,
- len);
- return -EINVAL;
- }
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++) {
- index = tuple_match * cpr_vreg->num_corners
- + i - CPR_CORNER_MIN;
- rc = of_property_read_u32_index(dev->of_node, prop_name,
- index, "_adjust);
- if (rc) {
- cpr_err(cpr_vreg, "could not read %s index %u, rc=%d\n",
- prop_name, index, rc);
- return rc;
- }
- if (quot_adjust) {
- cpr_vreg->quot_adjust[i] -= (int)quot_adjust;
- cpr_info(cpr_vreg, "corner=%d adjusted quotient=%d\n",
- i,
- cpr_vreg->cpr_fuse_target_quot[cpr_vreg->corner_map[i]]
- - cpr_vreg->quot_adjust[i]);
- }
- }
- return 0;
- }
- /*
- * cpr_get_corner_quot_adjustment() -- get the quot_adjust for each corner.
- *
- * Get the virtual corner to fuse corner mapping and virtual corner to APC clock
- * frequency mapping from device tree.
- * Calculate the quotient adjustment scaling factor for those corners mapping to
- * all fuse corners except for the lowest one using linear interpolation.
- * Calculate the quotient adjustment for each of these virtual corners using the
- * min of the calculated scaling factor and the constant max scaling factor
- * defined for each fuse corner in device tree.
- */
- static int cpr_get_corner_quot_adjustment(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- int rc = 0;
- int highest_fuse_corner = cpr_vreg->num_fuse_corners;
- int i, j, size;
- struct property *prop;
- bool corners_mapped, match_found;
- u32 *tmp, *freq_map = NULL;
- u32 corner, freq_corner;
- u32 *freq_max = NULL;
- u32 *scaling = NULL;
- u32 *max_factor = NULL;
- u32 *corner_max = NULL;
- bool maps_valid = false;
- prop = of_find_property(dev->of_node, "qcom,cpr-corner-map", NULL);
- if (prop) {
- size = prop->length / sizeof(u32);
- corners_mapped = true;
- } else {
- size = cpr_vreg->num_fuse_corners;
- corners_mapped = false;
- }
- cpr_vreg->corner_map = devm_kzalloc(dev, sizeof(int) * (size + 1),
- GFP_KERNEL);
- if (!cpr_vreg->corner_map) {
- cpr_err(cpr_vreg,
- "Can't allocate memory for cpr_vreg->corner_map\n");
- return -ENOMEM;
- }
- cpr_vreg->num_corners = size;
- cpr_vreg->quot_adjust = devm_kzalloc(dev,
- sizeof(u32) * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- if (!cpr_vreg->quot_adjust) {
- cpr_err(cpr_vreg,
- "Can't allocate memory for cpr_vreg->quot_adjust\n");
- return -ENOMEM;
- }
- if (!corners_mapped) {
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners;
- i++)
- cpr_vreg->corner_map[i] = i;
- goto free_arrays;
- } else {
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-corner-map", &cpr_vreg->corner_map[1], size);
- if (rc) {
- cpr_err(cpr_vreg,
- "qcom,cpr-corner-map missing, rc = %d\n", rc);
- return rc;
- }
- /*
- * Verify that the virtual corner to fuse corner mapping is
- * valid.
- */
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++) {
- if (cpr_vreg->corner_map[i] > cpr_vreg->num_fuse_corners
- || cpr_vreg->corner_map[i] < CPR_FUSE_CORNER_MIN) {
- cpr_err(cpr_vreg, "qcom,cpr-corner-map contains an element %d which isn't in the allowed range [%d, %d]\n",
- cpr_vreg->corner_map[i],
- CPR_FUSE_CORNER_MIN,
- cpr_vreg->num_fuse_corners);
- return -EINVAL;
- }
- }
- }
- prop = of_find_property(dev->of_node,
- "qcom,cpr-speed-bin-max-corners", NULL);
- if (!prop) {
- cpr_debug(cpr_vreg, "qcom,cpr-speed-bin-max-corner missing\n");
- goto free_arrays;
- }
- size = prop->length / sizeof(u32);
- tmp = kzalloc(size * sizeof(u32), GFP_KERNEL);
- if (!tmp) {
- cpr_err(cpr_vreg, "memory alloc failed\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-speed-bin-max-corners", tmp, size);
- if (rc < 0) {
- kfree(tmp);
- cpr_err(cpr_vreg,
- "get cpr-speed-bin-max-corners failed, rc = %d\n", rc);
- return rc;
- }
- corner_max = kzalloc((cpr_vreg->num_fuse_corners + 1)
- * sizeof(*corner_max), GFP_KERNEL);
- freq_max = kzalloc((cpr_vreg->num_fuse_corners + 1) * sizeof(*freq_max),
- GFP_KERNEL);
- if (corner_max == NULL || freq_max == NULL) {
- cpr_err(cpr_vreg, "Could not allocate memory for quotient scaling arrays\n");
- kfree(tmp);
- rc = -ENOMEM;
- goto free_arrays;
- }
- /*
- * Get the maximum virtual corner for each fuse corner based upon the
- * speed_bin and pvs_version values.
- */
- match_found = false;
- for (i = 0; i < size; i += cpr_vreg->num_fuse_corners + 2) {
- if (tmp[i] != cpr_vreg->speed_bin &&
- tmp[i] != FUSE_PARAM_MATCH_ANY)
- continue;
- if (tmp[i + 1] != cpr_vreg->pvs_version &&
- tmp[i + 1] != FUSE_PARAM_MATCH_ANY)
- continue;
- for (j = CPR_FUSE_CORNER_MIN;
- j <= cpr_vreg->num_fuse_corners; j++)
- corner_max[j] = tmp[i + 2 + j - CPR_FUSE_CORNER_MIN];
- match_found = true;
- break;
- }
- kfree(tmp);
- if (!match_found) {
- cpr_debug(cpr_vreg, "No quotient adjustment possible for speed bin=%u, pvs version=%u\n",
- cpr_vreg->speed_bin, cpr_vreg->pvs_version);
- goto free_arrays;
- }
- /* Verify that fuse corner to max virtual corner mapping is valid. */
- for (i = CPR_FUSE_CORNER_MIN; i <= highest_fuse_corner; i++) {
- if (corner_max[i] < CPR_CORNER_MIN
- || corner_max[i] > cpr_vreg->num_corners) {
- cpr_err(cpr_vreg, "Invalid corner=%d in qcom,cpr-speed-bin-max-corners\n",
- corner_max[i]);
- goto free_arrays;
- }
- }
- /*
- * Return success if the virtual corner values read from
- * qcom,cpr-speed-bin-max-corners property are incorrect. This allows
- * the driver to continue to run without quotient scaling.
- */
- for (i = CPR_FUSE_CORNER_MIN + 1; i <= highest_fuse_corner; i++) {
- if (corner_max[i] <= corner_max[i - 1]) {
- cpr_err(cpr_vreg, "fuse corner=%d (%u) should be larger than the fuse corner=%d (%u)\n",
- i, corner_max[i], i - 1, corner_max[i - 1]);
- goto free_arrays;
- }
- }
- prop = of_find_property(dev->of_node,
- "qcom,cpr-corner-frequency-map", NULL);
- if (!prop) {
- cpr_debug(cpr_vreg, "qcom,cpr-corner-frequency-map missing\n");
- goto free_arrays;
- }
- size = prop->length / sizeof(u32);
- tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
- if (!tmp) {
- cpr_err(cpr_vreg, "memory alloc failed\n");
- rc = -ENOMEM;
- goto free_arrays;
- }
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-corner-frequency-map", tmp, size);
- if (rc < 0) {
- cpr_err(cpr_vreg,
- "get cpr-corner-frequency-map failed, rc = %d\n", rc);
- kfree(tmp);
- goto free_arrays;
- }
- freq_map = kzalloc(sizeof(u32) * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- if (!freq_map) {
- cpr_err(cpr_vreg, "memory alloc for freq_map failed!\n");
- kfree(tmp);
- rc = -ENOMEM;
- goto free_arrays;
- }
- for (i = 0; i < size; i += 2) {
- corner = tmp[i];
- if ((corner < 1) || (corner > cpr_vreg->num_corners)) {
- cpr_err(cpr_vreg,
- "corner should be in 1~%d range: %d\n",
- cpr_vreg->num_corners, corner);
- continue;
- }
- freq_map[corner] = tmp[i + 1];
- cpr_debug(cpr_vreg,
- "Frequency at virtual corner %d is %d Hz.\n",
- corner, freq_map[corner]);
- }
- kfree(tmp);
- prop = of_find_property(dev->of_node,
- "qcom,cpr-quot-adjust-scaling-factor-max", NULL);
- if (!prop) {
- cpr_debug(cpr_vreg, "qcom,cpr-quot-adjust-scaling-factor-max missing\n");
- rc = 0;
- goto free_arrays;
- }
- size = prop->length / sizeof(u32);
- if ((size != 1) && (size != cpr_vreg->num_fuse_corners)) {
- cpr_err(cpr_vreg, "The size of qcom,cpr-quot-adjust-scaling-factor-max should be 1 or %d\n",
- cpr_vreg->num_fuse_corners);
- rc = 0;
- goto free_arrays;
- }
- max_factor = kzalloc(sizeof(u32) * (cpr_vreg->num_fuse_corners + 1),
- GFP_KERNEL);
- if (!max_factor) {
- cpr_err(cpr_vreg, "Could not allocate memory for max_factor array\n");
- rc = -ENOMEM;
- goto free_arrays;
- }
- /*
- * Leave max_factor[CPR_FUSE_CORNER_MIN ... highest_fuse_corner-1] = 0
- * if cpr-quot-adjust-scaling-factor-max is a single value in order to
- * maintain backward compatibility.
- */
- i = (size == cpr_vreg->num_fuse_corners) ? CPR_FUSE_CORNER_MIN
- : highest_fuse_corner;
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-quot-adjust-scaling-factor-max",
- &max_factor[i], size);
- if (rc < 0) {
- cpr_debug(cpr_vreg, "could not read qcom,cpr-quot-adjust-scaling-factor-max, rc=%d\n",
- rc);
- rc = 0;
- goto free_arrays;
- }
- /*
- * Get the quotient adjustment scaling factor, according to:
- * scaling = min(1000 * (QUOT(corner_N) - QUOT(corner_N-1))
- * / (freq(corner_N) - freq(corner_N-1)), max_factor)
- *
- * QUOT(corner_N): quotient read from fuse for fuse corner N
- * QUOT(corner_N-1): quotient read from fuse for fuse corner (N - 1)
- * freq(corner_N): max frequency in MHz supported by fuse corner N
- * freq(corner_N-1): max frequency in MHz supported by fuse corner
- * (N - 1)
- */
- for (i = CPR_FUSE_CORNER_MIN; i <= highest_fuse_corner; i++)
- freq_max[i] = freq_map[corner_max[i]];
- for (i = CPR_FUSE_CORNER_MIN + 1; i <= highest_fuse_corner; i++) {
- if (freq_max[i] <= freq_max[i - 1] || freq_max[i - 1] == 0) {
- cpr_err(cpr_vreg, "fuse corner %d freq=%u should be larger than fuse corner %d freq=%u\n",
- i, freq_max[i], i - 1, freq_max[i - 1]);
- rc = -EINVAL;
- goto free_arrays;
- }
- }
- scaling = kzalloc((cpr_vreg->num_fuse_corners + 1) * sizeof(*scaling),
- GFP_KERNEL);
- if (!scaling) {
- cpr_err(cpr_vreg, "Could not allocate memory for scaling array\n");
- rc = -ENOMEM;
- goto free_arrays;
- }
- /* Convert corner max frequencies from Hz to MHz. */
- for (i = CPR_FUSE_CORNER_MIN; i <= highest_fuse_corner; i++)
- freq_max[i] /= 1000000;
- for (i = CPR_FUSE_CORNER_MIN + 1; i <= highest_fuse_corner; i++) {
- if (cpr_vreg->fuse_quot_offset &&
- (cpr_vreg->cpr_fuse_ro_sel[i] !=
- cpr_vreg->cpr_fuse_ro_sel[i - 1])) {
- scaling[i] = 1000 * cpr_vreg->fuse_quot_offset[i]
- / (freq_max[i] - freq_max[i - 1]);
- } else {
- scaling[i] = 1000 * (cpr_vreg->cpr_fuse_target_quot[i]
- - cpr_vreg->cpr_fuse_target_quot[i - 1])
- / (freq_max[i] - freq_max[i - 1]);
- if (cpr_vreg->cpr_fuse_target_quot[i]
- < cpr_vreg->cpr_fuse_target_quot[i - 1])
- scaling[i] = 0;
- }
- scaling[i] = min(scaling[i], max_factor[i]);
- cpr_info(cpr_vreg, "fuse corner %d quotient adjustment scaling factor: %d.%03d\n",
- i, scaling[i] / 1000, scaling[i] % 1000);
- }
- /*
- * Walk through the virtual corners mapped to each fuse corner
- * and calculate the quotient adjustment for each one using the
- * following formula:
- * quot_adjust = (freq_max - freq_corner) * scaling / 1000
- *
- * @freq_max: max frequency in MHz supported by the fuse corner
- * @freq_corner: frequency in MHz corresponding to the virtual corner
- */
- for (j = CPR_FUSE_CORNER_MIN + 1; j <= highest_fuse_corner; j++) {
- for (i = corner_max[j - 1] + 1; i < corner_max[j]; i++) {
- freq_corner = freq_map[i] / 1000000; /* MHz */
- if (freq_corner > 0) {
- cpr_vreg->quot_adjust[i] = scaling[j] *
- (freq_max[j] - freq_corner) / 1000;
- }
- }
- }
- rc = cpr_virtual_corner_quot_adjust(cpr_vreg, dev);
- if (rc) {
- cpr_err(cpr_vreg, "count not adjust virtual-corner quot rc=%d\n",
- rc);
- goto free_arrays;
- }
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++)
- cpr_info(cpr_vreg, "adjusted quotient[%d] = %d\n", i,
- cpr_vreg->cpr_fuse_target_quot[cpr_vreg->corner_map[i]]
- - cpr_vreg->quot_adjust[i]);
- maps_valid = true;
- free_arrays:
- if (!rc) {
- rc = cpr_get_open_loop_voltage(cpr_vreg, dev, corner_max,
- freq_map, maps_valid);
- if (rc) {
- cpr_err(cpr_vreg, "could not fill open loop voltage array, rc=%d\n",
- rc);
- goto free_arrays_1;
- }
- rc = cpr_virtual_corner_voltage_adjust(cpr_vreg, dev);
- if (rc)
- cpr_err(cpr_vreg, "count not adjust virtual-corner voltage rc=%d\n",
- rc);
- }
- free_arrays_1:
- kfree(max_factor);
- kfree(scaling);
- kfree(freq_map);
- kfree(corner_max);
- kfree(freq_max);
- return rc;
- }
- /*
- * Check if the redundant set of CPR fuses should be used in place of the
- * primary set and configure the cpr_fuse_redundant element accordingly.
- */
- static int cpr_check_redundant(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- u32 cpr_fuse_redun_sel[5];
- int rc;
- if (of_find_property(of_node, "qcom,cpr-fuse-redun-sel", NULL)) {
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-redun-sel", cpr_fuse_redun_sel, 5);
- if (rc < 0) {
- cpr_err(cpr_vreg, "qcom,cpr-fuse-redun-sel missing: rc=%d\n",
- rc);
- return rc;
- }
- cpr_vreg->cpr_fuse_redundant
- = cpr_fuse_is_setting_expected(cpr_vreg,
- cpr_fuse_redun_sel);
- } else {
- cpr_vreg->cpr_fuse_redundant = false;
- }
- if (cpr_vreg->cpr_fuse_redundant)
- cpr_info(cpr_vreg, "using redundant fuse parameters\n");
- return 0;
- }
- static int cpr_read_fuse_revision(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- u32 fuse_sel[4];
- int rc;
- if (of_find_property(of_node, "qcom,cpr-fuse-revision", NULL)) {
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-revision", fuse_sel, 4);
- if (rc < 0) {
- cpr_err(cpr_vreg, "qcom,cpr-fuse-revision read failed: rc=%d\n",
- rc);
- return rc;
- }
- cpr_vreg->cpr_fuse_revision
- = cpr_read_efuse_param(cpr_vreg, fuse_sel[0],
- fuse_sel[1], fuse_sel[2], fuse_sel[3]);
- cpr_info(cpr_vreg, "fuse revision = %d\n",
- cpr_vreg->cpr_fuse_revision);
- } else {
- cpr_vreg->cpr_fuse_revision = FUSE_REVISION_UNKNOWN;
- }
- return 0;
- }
- static int cpr_read_ro_select(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int rc = 0;
- u32 cpr_fuse_row[2];
- char *ro_sel_str;
- int *bp_ro_sel;
- int i;
- bp_ro_sel
- = kzalloc((cpr_vreg->num_fuse_corners + 1) * sizeof(*bp_ro_sel),
- GFP_KERNEL);
- if (!bp_ro_sel) {
- cpr_err(cpr_vreg, "could not allocate memory for temp array\n");
- return -ENOMEM;
- }
- if (cpr_vreg->cpr_fuse_redundant) {
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-redun-row",
- cpr_fuse_row, 2);
- ro_sel_str = "qcom,cpr-fuse-redun-ro-sel";
- } else {
- rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-row",
- cpr_fuse_row, 2);
- ro_sel_str = "qcom,cpr-fuse-ro-sel";
- }
- if (rc)
- goto error;
- rc = of_property_read_u32_array(of_node, ro_sel_str,
- &bp_ro_sel[CPR_FUSE_CORNER_MIN], cpr_vreg->num_fuse_corners);
- if (rc) {
- cpr_err(cpr_vreg, "%s read error, rc=%d\n", ro_sel_str, rc);
- goto error;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++)
- cpr_vreg->cpr_fuse_ro_sel[i]
- = cpr_read_efuse_param(cpr_vreg, cpr_fuse_row[0],
- bp_ro_sel[i], CPR_FUSE_RO_SEL_BITS,
- cpr_fuse_row[1]);
- error:
- kfree(bp_ro_sel);
- return rc;
- }
- static int cpr_find_fuse_map_match(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int i, j, rc, tuple_size;
- int len = 0;
- u32 *tmp, val, ro;
- /* Specify default no match case. */
- cpr_vreg->cpr_fuse_map_match = FUSE_MAP_NO_MATCH;
- cpr_vreg->cpr_fuse_map_count = 0;
- if (!of_find_property(of_node, "qcom,cpr-fuse-version-map", &len)) {
- /* No mapping present. */
- return 0;
- }
- tuple_size = cpr_vreg->num_fuse_corners + 3;
- cpr_vreg->cpr_fuse_map_count = len / (sizeof(u32) * tuple_size);
- if (len == 0 || len % (sizeof(u32) * tuple_size)) {
- cpr_err(cpr_vreg, "qcom,cpr-fuse-version-map length=%d is invalid\n",
- len);
- return -EINVAL;
- }
- tmp = kzalloc(len, GFP_KERNEL);
- if (!tmp) {
- cpr_err(cpr_vreg, "could not allocate memory for temp array\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-version-map",
- tmp, cpr_vreg->cpr_fuse_map_count * tuple_size);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,cpr-fuse-version-map, rc=%d\n",
- rc);
- goto done;
- }
- /*
- * qcom,cpr-fuse-version-map tuple format:
- * <speed_bin, pvs_version, cpr_fuse_revision, ro_sel[1], ...,
- * ro_sel[n]> for n == number of fuse corners
- */
- for (i = 0; i < cpr_vreg->cpr_fuse_map_count; i++) {
- if (tmp[i * tuple_size] != cpr_vreg->speed_bin
- && tmp[i * tuple_size] != FUSE_PARAM_MATCH_ANY)
- continue;
- if (tmp[i * tuple_size + 1] != cpr_vreg->pvs_version
- && tmp[i * tuple_size + 1] != FUSE_PARAM_MATCH_ANY)
- continue;
- if (tmp[i * tuple_size + 2] != cpr_vreg->cpr_fuse_revision
- && tmp[i * tuple_size + 2] != FUSE_PARAM_MATCH_ANY)
- continue;
- for (j = 0; j < cpr_vreg->num_fuse_corners; j++) {
- val = tmp[i * tuple_size + 3 + j];
- ro = cpr_vreg->cpr_fuse_ro_sel[j + CPR_FUSE_CORNER_MIN];
- if (val != ro && val != FUSE_PARAM_MATCH_ANY)
- break;
- }
- if (j == cpr_vreg->num_fuse_corners) {
- cpr_vreg->cpr_fuse_map_match = i;
- break;
- }
- }
- if (cpr_vreg->cpr_fuse_map_match != FUSE_MAP_NO_MATCH)
- cpr_debug(cpr_vreg, "qcom,cpr-fuse-version-map tuple match found: %d\n",
- cpr_vreg->cpr_fuse_map_match);
- else
- cpr_debug(cpr_vreg, "qcom,cpr-fuse-version-map tuple match not found\n");
- done:
- kfree(tmp);
- return rc;
- }
- static int cpr_minimum_quot_difference_adjustment(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int tuple_count, tuple_match;
- int rc, i, len = 0;
- u32 index, adjust_quot = 0;
- u32 *min_diff_quot;
- if (!of_find_property(of_node, "qcom,cpr-fuse-min-quot-diff", NULL))
- /* No conditional adjustment needed on revised quotients. */
- return 0;
- if (!of_find_property(of_node, "qcom,cpr-min-quot-diff-adjustment",
- &len)) {
- cpr_err(cpr_vreg, "qcom,cpr-min-quot-diff-adjustment not specified\n");
- return -ENODEV;
- }
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH)
- /* No matching index to use for quotient adjustment. */
- return 0;
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != cpr_vreg->num_fuse_corners * tuple_count * sizeof(u32)) {
- cpr_err(cpr_vreg, "qcom,cpr-min-quot-diff-adjustment length=%d is invalid\n",
- len);
- return -EINVAL;
- }
- min_diff_quot = kzalloc(cpr_vreg->num_fuse_corners * sizeof(u32),
- GFP_KERNEL);
- if (!min_diff_quot) {
- cpr_err(cpr_vreg, "memory alloc failed\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-min-quot-diff",
- min_diff_quot,
- cpr_vreg->num_fuse_corners);
- if (rc < 0) {
- cpr_err(cpr_vreg, "qcom,cpr-fuse-min-quot-diff reading failed, rc = %d\n",
- rc);
- goto error;
- }
- for (i = CPR_FUSE_CORNER_MIN + 1;
- i <= cpr_vreg->num_fuse_corners; i++) {
- if ((cpr_vreg->cpr_fuse_target_quot[i]
- - cpr_vreg->cpr_fuse_target_quot[i - 1])
- <= (int)min_diff_quot[i - CPR_FUSE_CORNER_MIN]) {
- index = tuple_match * cpr_vreg->num_fuse_corners
- + i - CPR_FUSE_CORNER_MIN;
- rc = of_property_read_u32_index(of_node,
- "qcom,cpr-min-quot-diff-adjustment",
- index, &adjust_quot);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,cpr-min-quot-diff-adjustment index %u, rc=%d\n",
- index, rc);
- goto error;
- }
- cpr_vreg->cpr_fuse_target_quot[i]
- = cpr_vreg->cpr_fuse_target_quot[i - 1]
- + adjust_quot;
- cpr_info(cpr_vreg, "Corner[%d]: revised adjusted quotient = %d\n",
- i, cpr_vreg->cpr_fuse_target_quot[i]);
- };
- }
- error:
- kfree(min_diff_quot);
- return rc;
- }
- static int cpr_adjust_target_quots(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int tuple_count, tuple_match, i;
- u32 index;
- u32 quot_adjust = 0;
- int len = 0;
- int rc = 0;
- if (!of_find_property(of_node, "qcom,cpr-quotient-adjustment", &len)) {
- /* No static quotient adjustment needed. */
- return 0;
- }
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) {
- /* No matching index to use for quotient adjustment. */
- return 0;
- }
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != cpr_vreg->num_fuse_corners * tuple_count * sizeof(u32)) {
- cpr_err(cpr_vreg, "qcom,cpr-quotient-adjustment length=%d is invalid\n",
- len);
- return -EINVAL;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- index = tuple_match * cpr_vreg->num_fuse_corners
- + i - CPR_FUSE_CORNER_MIN;
- rc = of_property_read_u32_index(of_node,
- "qcom,cpr-quotient-adjustment", index, "_adjust);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,cpr-quotient-adjustment index %u, rc=%d\n",
- index, rc);
- return rc;
- }
- if (quot_adjust) {
- cpr_vreg->cpr_fuse_target_quot[i] += quot_adjust;
- cpr_info(cpr_vreg, "Corner[%d]: adjusted target quot = %d\n",
- i, cpr_vreg->cpr_fuse_target_quot[i]);
- }
- }
- rc = cpr_minimum_quot_difference_adjustment(pdev, cpr_vreg);
- if (rc)
- cpr_err(cpr_vreg, "failed to apply minimum quot difference rc=%d\n",
- rc);
- return rc;
- }
- static int cpr_check_allowed(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- char *allow_str = "qcom,cpr-allowed";
- int rc = 0, count;
- int tuple_count, tuple_match;
- u32 allow_status;
- if (!of_find_property(of_node, allow_str, &count))
- /* CPR is allowed for all fuse revisions. */
- return 0;
- count /= sizeof(u32);
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH)
- /* No matching index to use for CPR allowed. */
- return 0;
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (count != tuple_count) {
- cpr_err(cpr_vreg, "%s count=%d is invalid\n", allow_str,
- count);
- return -EINVAL;
- }
- rc = of_property_read_u32_index(of_node, allow_str, tuple_match,
- &allow_status);
- if (rc) {
- cpr_err(cpr_vreg, "could not read %s index %u, rc=%d\n",
- allow_str, tuple_match, rc);
- return rc;
- }
- if (allow_status && !cpr_vreg->cpr_fuse_disable)
- cpr_vreg->cpr_fuse_disable = false;
- else
- cpr_vreg->cpr_fuse_disable = true;
- cpr_info(cpr_vreg, "CPR closed loop is %s for fuse revision %d\n",
- cpr_vreg->cpr_fuse_disable ? "disabled" : "enabled",
- cpr_vreg->cpr_fuse_revision);
- return rc;
- }
- static int cpr_check_de_aging_allowed(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- struct device_node *of_node = dev->of_node;
- char *allow_str = "qcom,cpr-de-aging-allowed";
- int rc = 0, count;
- int tuple_count, tuple_match;
- u32 allow_status = 0;
- if (!of_find_property(of_node, allow_str, &count)) {
- /* CPR de-aging is not allowed for all fuse revisions. */
- return allow_status;
- }
- count /= sizeof(u32);
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH)
- /* No matching index to use for CPR de-aging allowed. */
- return 0;
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (count != tuple_count) {
- cpr_err(cpr_vreg, "%s count=%d is invalid\n", allow_str,
- count);
- return -EINVAL;
- }
- rc = of_property_read_u32_index(of_node, allow_str, tuple_match,
- &allow_status);
- if (rc) {
- cpr_err(cpr_vreg, "could not read %s index %u, rc=%d\n",
- allow_str, tuple_match, rc);
- return rc;
- }
- cpr_info(cpr_vreg, "CPR de-aging is %s for fuse revision %d\n",
- allow_status ? "allowed" : "not allowed",
- cpr_vreg->cpr_fuse_revision);
- return allow_status;
- }
- static int cpr_aging_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- struct cpr_aging_info *aging_info;
- struct cpr_aging_sensor_info *sensor_info;
- int num_fuse_corners = cpr_vreg->num_fuse_corners;
- int i, rc = 0, len = 0, num_aging_sensors, ro_sel, bits;
- u32 *aging_sensor_id, *fuse_sel, *fuse_sel_orig;
- u32 sensor = 0, non_collapsible_sensor_mask = 0;
- u64 efuse_val;
- struct property *prop;
- if (!of_find_property(of_node, "qcom,cpr-aging-sensor-id", &len)) {
- /* No CPR de-aging adjustments needed */
- return 0;
- }
- if (len == 0) {
- cpr_err(cpr_vreg, "qcom,cpr-aging-sensor-id property format is invalid\n");
- return -EINVAL;
- }
- num_aging_sensors = len / sizeof(u32);
- cpr_debug(cpr_vreg, "No of aging sensors = %d\n", num_aging_sensors);
- if (cpumask_empty(&cpr_vreg->cpu_mask)) {
- cpr_err(cpr_vreg, "qcom,cpr-cpus property missing\n");
- return -EINVAL;
- }
- rc = cpr_check_de_aging_allowed(cpr_vreg, &pdev->dev);
- if (rc < 0) {
- cpr_err(cpr_vreg, "cpr_check_de_aging_allowed failed: rc=%d\n",
- rc);
- return rc;
- } else if (rc == 0) {
- /* CPR de-aging is not allowed for the current fuse combo */
- return 0;
- }
- aging_info = devm_kzalloc(&pdev->dev, sizeof(*aging_info),
- GFP_KERNEL);
- if (!aging_info)
- return -ENOMEM;
- cpr_vreg->aging_info = aging_info;
- aging_info->num_aging_sensors = num_aging_sensors;
- rc = of_property_read_u32(of_node, "qcom,cpr-aging-ref-corner",
- &aging_info->aging_corner);
- if (rc) {
- cpr_err(cpr_vreg, "qcom,cpr-aging-ref-corner missing rc=%d\n",
- rc);
- return rc;
- }
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-aging-ref-voltage",
- &aging_info->aging_ref_voltage, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-max-aging-margin",
- &aging_info->max_aging_margin, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-aging-ro-scaling-factor",
- &aging_info->aging_ro_kv, rc);
- if (rc)
- return rc;
- /* Check for DIV by 0 error */
- if (aging_info->aging_ro_kv == 0) {
- cpr_err(cpr_vreg, "invalid cpr-aging-ro-scaling-factor value: %u\n",
- aging_info->aging_ro_kv);
- return -EINVAL;
- }
- rc = of_property_read_u32_array(of_node, "qcom,cpr-ro-scaling-factor",
- aging_info->cpr_ro_kv, CPR_NUM_RING_OSC);
- if (rc) {
- cpr_err(cpr_vreg, "qcom,cpr-ro-scaling-factor property read failed, rc = %d\n",
- rc);
- return rc;
- }
- if (of_find_property(of_node, "qcom,cpr-non-collapsible-sensors",
- &len)) {
- len = len / sizeof(u32);
- if (len <= 0 || len > 32) {
- cpr_err(cpr_vreg, "qcom,cpr-non-collapsible-sensors has an incorrect size\n");
- return -EINVAL;
- }
- for (i = 0; i < len; i++) {
- rc = of_property_read_u32_index(of_node,
- "qcom,cpr-non-collapsible-sensors",
- i, &sensor);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,cpr-non-collapsible-sensors index %u, rc=%d\n",
- i, rc);
- return rc;
- }
- if (sensor > 31) {
- cpr_err(cpr_vreg, "invalid non-collapsible sensor = %u\n",
- sensor);
- return -EINVAL;
- }
- non_collapsible_sensor_mask |= BIT(sensor);
- }
- /*
- * Bypass the sensors in collapsible domain for
- * de-aging measurements
- */
- aging_info->aging_sensor_bypass =
- ~(non_collapsible_sensor_mask);
- cpr_debug(cpr_vreg, "sensor bypass mask for aging = 0x%08x\n",
- aging_info->aging_sensor_bypass);
- }
- prop = of_find_property(pdev->dev.of_node, "qcom,cpr-aging-derate",
- NULL);
- if ((!prop) ||
- (prop->length != num_fuse_corners * sizeof(u32))) {
- cpr_err(cpr_vreg, "qcom,cpr-aging-derate incorrectly configured\n");
- return -EINVAL;
- }
- aging_sensor_id = kcalloc(num_aging_sensors, sizeof(*aging_sensor_id),
- GFP_KERNEL);
- fuse_sel = kcalloc(num_aging_sensors * 4, sizeof(*fuse_sel),
- GFP_KERNEL);
- aging_info->voltage_adjust = devm_kcalloc(&pdev->dev,
- num_fuse_corners + 1,
- sizeof(*aging_info->voltage_adjust),
- GFP_KERNEL);
- aging_info->sensor_info = devm_kcalloc(&pdev->dev, num_aging_sensors,
- sizeof(*aging_info->sensor_info),
- GFP_KERNEL);
- aging_info->aging_derate = devm_kcalloc(&pdev->dev,
- num_fuse_corners + 1,
- sizeof(*aging_info->aging_derate),
- GFP_KERNEL);
- if (!aging_info->aging_derate || !aging_sensor_id
- || !aging_info->sensor_info || !fuse_sel
- || !aging_info->voltage_adjust)
- goto err;
- rc = of_property_read_u32_array(of_node, "qcom,cpr-aging-sensor-id",
- aging_sensor_id, num_aging_sensors);
- if (rc) {
- cpr_err(cpr_vreg, "qcom,cpr-aging-sensor-id property read failed, rc = %d\n",
- rc);
- goto err;
- }
- for (i = 0; i < num_aging_sensors; i++)
- if (aging_sensor_id[i] < 0 || aging_sensor_id[i] > 31) {
- cpr_err(cpr_vreg, "Invalid aging sensor id: %u\n",
- aging_sensor_id[i]);
- rc = -EINVAL;
- goto err;
- }
- rc = of_property_read_u32_array(of_node, "qcom,cpr-aging-derate",
- &aging_info->aging_derate[CPR_FUSE_CORNER_MIN],
- num_fuse_corners);
- if (rc) {
- cpr_err(cpr_vreg, "qcom,cpr-aging-derate property read failed, rc = %d\n",
- rc);
- goto err;
- }
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-aging-init-quot-diff",
- fuse_sel, (num_aging_sensors * 4));
- if (rc) {
- cpr_err(cpr_vreg, "qcom,cpr-fuse-aging-init-quot-diff read failed, rc = %d\n",
- rc);
- goto err;
- }
- fuse_sel_orig = fuse_sel;
- sensor_info = aging_info->sensor_info;
- for (i = 0; i < num_aging_sensors; i++, sensor_info++) {
- sensor_info->sensor_id = aging_sensor_id[i];
- efuse_val = cpr_read_efuse_param(cpr_vreg, fuse_sel[0],
- fuse_sel[1], fuse_sel[2], fuse_sel[3]);
- bits = fuse_sel[2];
- sensor_info->initial_quot_diff = ((efuse_val & BIT(bits - 1)) ?
- -1 : 1) * (efuse_val & (BIT(bits - 1) - 1));
- cpr_debug(cpr_vreg, "Age sensor[%d] Initial quot diff = %d\n",
- sensor_info->sensor_id,
- sensor_info->initial_quot_diff);
- fuse_sel += 4;
- }
- /*
- * Add max aging margin here. This can be adjusted later in
- * de-aging algorithm.
- */
- for (i = CPR_FUSE_CORNER_MIN; i <= num_fuse_corners; i++) {
- ro_sel = cpr_vreg->cpr_fuse_ro_sel[i];
- cpr_vreg->cpr_fuse_target_quot[i] +=
- (aging_info->cpr_ro_kv[ro_sel]
- * aging_info->max_aging_margin) / 1000000;
- aging_info->voltage_adjust[i] = aging_info->max_aging_margin;
- cpr_info(cpr_vreg, "Corner[%d]: age margin adjusted quotient = %d\n",
- i, cpr_vreg->cpr_fuse_target_quot[i]);
- }
- kfree(fuse_sel_orig);
- err:
- kfree(aging_sensor_id);
- return rc;
- }
- static int cpr_cpu_map_init(struct cpr_regulator *cpr_vreg, struct device *dev)
- {
- struct device_node *cpu_node;
- int i, cpu;
- if (!of_find_property(dev->of_node, "qcom,cpr-cpus",
- &cpr_vreg->num_adj_cpus)) {
- /* No adjustments based on online cores */
- return 0;
- }
- cpr_vreg->num_adj_cpus /= sizeof(u32);
- cpr_vreg->adj_cpus = devm_kcalloc(dev, cpr_vreg->num_adj_cpus,
- sizeof(int), GFP_KERNEL);
- if (!cpr_vreg->adj_cpus)
- return -ENOMEM;
- for (i = 0; i < cpr_vreg->num_adj_cpus; i++) {
- cpu_node = of_parse_phandle(dev->of_node, "qcom,cpr-cpus", i);
- if (!cpu_node) {
- cpr_err(cpr_vreg, "could not find CPU node %d\n", i);
- return -EINVAL;
- }
- cpr_vreg->adj_cpus[i] = -1;
- for_each_possible_cpu(cpu) {
- if (of_get_cpu_node(cpu, NULL) == cpu_node) {
- cpr_vreg->adj_cpus[i] = cpu;
- cpumask_set_cpu(cpu, &cpr_vreg->cpu_mask);
- break;
- }
- }
- of_node_put(cpu_node);
- }
- return 0;
- }
- static int cpr_init_cpr_efuse(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int i, rc = 0;
- bool scheme_fuse_valid = false;
- bool disable_fuse_valid = false;
- char *targ_quot_str;
- u32 cpr_fuse_row[2];
- u32 bp_cpr_disable, bp_scheme;
- size_t len;
- int *bp_target_quot;
- u64 fuse_bits, fuse_bits_2;
- u32 *target_quot_size;
- struct cpr_quot_scale *quot_scale;
- len = cpr_vreg->num_fuse_corners + 1;
- bp_target_quot = kzalloc(len * sizeof(*bp_target_quot), GFP_KERNEL);
- target_quot_size = kzalloc(len * sizeof(*target_quot_size), GFP_KERNEL);
- quot_scale = kzalloc(len * sizeof(*quot_scale), GFP_KERNEL);
- if (!bp_target_quot || !target_quot_size || !quot_scale) {
- cpr_err(cpr_vreg,
- "Could not allocate memory for fuse parsing arrays\n");
- rc = -ENOMEM;
- goto error;
- }
- if (cpr_vreg->cpr_fuse_redundant) {
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-redun-row",
- cpr_fuse_row, 2);
- targ_quot_str = "qcom,cpr-fuse-redun-target-quot";
- } else {
- rc = of_property_read_u32_array(of_node, "qcom,cpr-fuse-row",
- cpr_fuse_row, 2);
- targ_quot_str = "qcom,cpr-fuse-target-quot";
- }
- if (rc)
- goto error;
- rc = of_property_read_u32_array(of_node, targ_quot_str,
- &bp_target_quot[CPR_FUSE_CORNER_MIN],
- cpr_vreg->num_fuse_corners);
- if (rc < 0) {
- cpr_err(cpr_vreg, "missing %s: rc=%d\n", targ_quot_str, rc);
- goto error;
- }
- if (of_find_property(of_node, "qcom,cpr-fuse-target-quot-size", NULL)) {
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-target-quot-size",
- &target_quot_size[CPR_FUSE_CORNER_MIN],
- cpr_vreg->num_fuse_corners);
- if (rc < 0) {
- cpr_err(cpr_vreg, "error while reading qcom,cpr-fuse-target-quot-size: rc=%d\n",
- rc);
- goto error;
- }
- } else {
- /*
- * Default fuse quotient parameter size to match target register
- * size.
- */
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners;
- i++)
- target_quot_size[i] = CPR_FUSE_TARGET_QUOT_BITS;
- }
- if (of_find_property(of_node, "qcom,cpr-fuse-target-quot-scale",
- NULL)) {
- for (i = 0; i < cpr_vreg->num_fuse_corners; i++) {
- rc = of_property_read_u32_index(of_node,
- "qcom,cpr-fuse-target-quot-scale", i * 2,
- "_scale[i + CPR_FUSE_CORNER_MIN].offset);
- if (rc < 0) {
- cpr_err(cpr_vreg, "error while reading qcom,cpr-fuse-target-quot-scale: rc=%d\n",
- rc);
- goto error;
- }
- rc = of_property_read_u32_index(of_node,
- "qcom,cpr-fuse-target-quot-scale", i * 2 + 1,
- "_scale[i + CPR_FUSE_CORNER_MIN].multiplier);
- if (rc < 0) {
- cpr_err(cpr_vreg, "error while reading qcom,cpr-fuse-target-quot-scale: rc=%d\n",
- rc);
- goto error;
- }
- }
- } else {
- /*
- * In the default case, target quotients require no scaling so
- * use offset = 0, multiplier = 1.
- */
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners;
- i++) {
- quot_scale[i].offset = 0;
- quot_scale[i].multiplier = 1;
- }
- }
- /* Read the control bits of eFuse */
- fuse_bits = cpr_read_efuse_row(cpr_vreg, cpr_fuse_row[0],
- cpr_fuse_row[1]);
- cpr_info(cpr_vreg, "[row:%d] = 0x%llx\n", cpr_fuse_row[0], fuse_bits);
- if (cpr_vreg->cpr_fuse_redundant) {
- if (of_find_property(of_node,
- "qcom,cpr-fuse-redun-bp-cpr-disable", NULL)) {
- CPR_PROP_READ_U32(cpr_vreg, of_node,
- "cpr-fuse-redun-bp-cpr-disable",
- &bp_cpr_disable, rc);
- disable_fuse_valid = true;
- if (of_find_property(of_node,
- "qcom,cpr-fuse-redun-bp-scheme",
- NULL)) {
- CPR_PROP_READ_U32(cpr_vreg, of_node,
- "cpr-fuse-redun-bp-scheme",
- &bp_scheme, rc);
- scheme_fuse_valid = true;
- }
- if (rc)
- goto error;
- fuse_bits_2 = fuse_bits;
- } else {
- u32 temp_row[2];
- /* Use original fuse if no optional property */
- if (of_find_property(of_node,
- "qcom,cpr-fuse-bp-cpr-disable", NULL)) {
- CPR_PROP_READ_U32(cpr_vreg, of_node,
- "cpr-fuse-bp-cpr-disable",
- &bp_cpr_disable, rc);
- disable_fuse_valid = true;
- }
- if (of_find_property(of_node,
- "qcom,cpr-fuse-bp-scheme",
- NULL)) {
- CPR_PROP_READ_U32(cpr_vreg, of_node,
- "cpr-fuse-bp-scheme",
- &bp_scheme, rc);
- scheme_fuse_valid = true;
- }
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-row",
- temp_row, 2);
- if (rc)
- goto error;
- fuse_bits_2 = cpr_read_efuse_row(cpr_vreg, temp_row[0],
- temp_row[1]);
- cpr_info(cpr_vreg, "[original row:%d] = 0x%llx\n",
- temp_row[0], fuse_bits_2);
- }
- } else {
- if (of_find_property(of_node, "qcom,cpr-fuse-bp-cpr-disable",
- NULL)) {
- CPR_PROP_READ_U32(cpr_vreg, of_node,
- "cpr-fuse-bp-cpr-disable", &bp_cpr_disable, rc);
- disable_fuse_valid = true;
- }
- if (of_find_property(of_node, "qcom,cpr-fuse-bp-scheme",
- NULL)) {
- CPR_PROP_READ_U32(cpr_vreg, of_node,
- "cpr-fuse-bp-scheme", &bp_scheme, rc);
- scheme_fuse_valid = true;
- }
- if (rc)
- goto error;
- fuse_bits_2 = fuse_bits;
- }
- if (disable_fuse_valid) {
- cpr_vreg->cpr_fuse_disable =
- (fuse_bits_2 >> bp_cpr_disable) & 0x01;
- cpr_info(cpr_vreg, "CPR disable fuse = %d\n",
- cpr_vreg->cpr_fuse_disable);
- } else {
- cpr_vreg->cpr_fuse_disable = false;
- }
- if (scheme_fuse_valid) {
- cpr_vreg->cpr_fuse_local = (fuse_bits_2 >> bp_scheme) & 0x01;
- cpr_info(cpr_vreg, "local = %d\n", cpr_vreg->cpr_fuse_local);
- } else {
- cpr_vreg->cpr_fuse_local = true;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- cpr_vreg->cpr_fuse_target_quot[i]
- = cpr_read_efuse_param(cpr_vreg, cpr_fuse_row[0],
- bp_target_quot[i], target_quot_size[i],
- cpr_fuse_row[1]);
- /* Unpack the target quotient by scaling. */
- cpr_vreg->cpr_fuse_target_quot[i] *= quot_scale[i].multiplier;
- cpr_vreg->cpr_fuse_target_quot[i] += quot_scale[i].offset;
- cpr_info(cpr_vreg,
- "Corner[%d]: ro_sel = %d, target quot = %d\n", i,
- cpr_vreg->cpr_fuse_ro_sel[i],
- cpr_vreg->cpr_fuse_target_quot[i]);
- }
- rc = cpr_cpu_map_init(cpr_vreg, &pdev->dev);
- if (rc) {
- cpr_err(cpr_vreg, "CPR cpu map init failed: rc=%d\n", rc);
- goto error;
- }
- rc = cpr_aging_init(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "CPR aging init failed: rc=%d\n", rc);
- goto error;
- }
- rc = cpr_adjust_target_quots(pdev, cpr_vreg);
- if (rc)
- goto error;
- for (i = CPR_FUSE_CORNER_MIN + 1;
- i <= cpr_vreg->num_fuse_corners; i++) {
- if (cpr_vreg->cpr_fuse_target_quot[i]
- < cpr_vreg->cpr_fuse_target_quot[i - 1] &&
- cpr_vreg->cpr_fuse_ro_sel[i] ==
- cpr_vreg->cpr_fuse_ro_sel[i - 1]) {
- cpr_vreg->cpr_fuse_disable = true;
- cpr_err(cpr_vreg, "invalid quotient values; permanently disabling CPR\n");
- }
- }
- if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
- cpr_voltage_uplift_wa_inc_quot(cpr_vreg, of_node);
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners;
- i++) {
- cpr_info(cpr_vreg,
- "Corner[%d]: uplifted target quot = %d\n",
- i, cpr_vreg->cpr_fuse_target_quot[i]);
- }
- }
- /*
- * Check whether the fuse-quot-offset is defined per fuse corner.
- * If it is defined, use it (quot_offset) in the calculation
- * below for obtaining scaling factor per fuse corner.
- */
- rc = cpr_get_fuse_quot_offset(cpr_vreg, pdev, quot_scale);
- if (rc < 0)
- goto error;
- rc = cpr_get_corner_quot_adjustment(cpr_vreg, &pdev->dev);
- if (rc)
- goto error;
- cpr_vreg->cpr_fuse_bits = fuse_bits;
- if (!cpr_vreg->cpr_fuse_bits) {
- cpr_vreg->cpr_fuse_disable = true;
- cpr_err(cpr_vreg,
- "cpr_fuse_bits == 0; permanently disabling CPR\n");
- } else if (!cpr_vreg->fuse_quot_offset) {
- /*
- * Check if the target quotients for the highest two fuse
- * corners are too close together.
- */
- int *quot = cpr_vreg->cpr_fuse_target_quot;
- int highest_fuse_corner = cpr_vreg->num_fuse_corners;
- u32 min_diff_quot;
- bool valid_fuse = true;
- min_diff_quot = CPR_FUSE_MIN_QUOT_DIFF;
- of_property_read_u32(of_node, "qcom,cpr-quot-min-diff",
- &min_diff_quot);
- if (quot[highest_fuse_corner] > quot[highest_fuse_corner - 1]) {
- if ((quot[highest_fuse_corner]
- - quot[highest_fuse_corner - 1])
- <= min_diff_quot)
- valid_fuse = false;
- } else {
- valid_fuse = false;
- }
- if (!valid_fuse) {
- cpr_vreg->cpr_fuse_disable = true;
- cpr_err(cpr_vreg, "invalid quotient values; permanently disabling CPR\n");
- }
- }
- rc = cpr_check_allowed(pdev, cpr_vreg);
- error:
- kfree(bp_target_quot);
- kfree(target_quot_size);
- kfree(quot_scale);
- return rc;
- }
- static int cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- int i;
- int size = cpr_vreg->num_corners + 1;
- cpr_vreg->last_volt = devm_kzalloc(dev, sizeof(int) * size, GFP_KERNEL);
- if (!cpr_vreg->last_volt)
- return -EINVAL;
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++)
- cpr_vreg->last_volt[i] = cpr_vreg->open_loop_volt[i];
- return 0;
- }
- /*
- * This function fills the virtual_limit array with voltages read from the
- * prop_name device tree property if a given tuple in the property matches
- * the speedbin and PVS version fuses found on the chip. Otherwise,
- * it fills the virtual_limit_array with corresponding values from the
- * fuse_limit_array.
- */
- static int cpr_fill_override_voltage(struct cpr_regulator *cpr_vreg,
- struct device *dev, const char *prop_name, const char *label,
- int *virtual_limit, int *fuse_limit)
- {
- int rc = 0;
- int i, j, size, pos;
- struct property *prop;
- bool match_found = false;
- size_t buflen;
- char *buf;
- u32 *tmp;
- prop = of_find_property(dev->of_node, prop_name, NULL);
- if (!prop)
- goto use_fuse_corner_limits;
- size = prop->length / sizeof(u32);
- if (size == 0 || size % (cpr_vreg->num_corners + 2)) {
- cpr_err(cpr_vreg, "%s property format is invalid; reusing per-fuse-corner limits\n",
- prop_name);
- goto use_fuse_corner_limits;
- }
- tmp = kzalloc(size * sizeof(u32), GFP_KERNEL);
- if (!tmp) {
- cpr_err(cpr_vreg, "memory alloc failed\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(dev->of_node, prop_name, tmp, size);
- if (rc < 0) {
- kfree(tmp);
- cpr_err(cpr_vreg, "%s reading failed, rc = %d\n", prop_name,
- rc);
- return rc;
- }
- /*
- * Get limit voltage for each virtual corner based upon the speed_bin
- * and pvs_version values.
- */
- for (i = 0; i < size; i += cpr_vreg->num_corners + 2) {
- if (tmp[i] != cpr_vreg->speed_bin &&
- tmp[i] != FUSE_PARAM_MATCH_ANY)
- continue;
- if (tmp[i + 1] != cpr_vreg->pvs_version &&
- tmp[i + 1] != FUSE_PARAM_MATCH_ANY)
- continue;
- for (j = CPR_CORNER_MIN; j <= cpr_vreg->num_corners; j++)
- virtual_limit[j] = tmp[i + 2 + j - CPR_FUSE_CORNER_MIN];
- match_found = true;
- break;
- }
- kfree(tmp);
- if (!match_found)
- goto use_fuse_corner_limits;
- /*
- * Log per-virtual-corner voltage limits since they are useful for
- * baseline CPR debugging.
- */
- buflen = cpr_vreg->num_corners * (MAX_CHARS_PER_INT + 2) * sizeof(*buf);
- buf = kzalloc(buflen, GFP_KERNEL);
- if (buf == NULL) {
- cpr_err(cpr_vreg, "Could not allocate memory for corner limit voltage logging\n");
- return 0;
- }
- for (i = CPR_CORNER_MIN, pos = 0; i <= cpr_vreg->num_corners; i++)
- pos += scnprintf(buf + pos, buflen - pos, "%d%s",
- virtual_limit[i], i < cpr_vreg->num_corners ? " " : "");
- cpr_info(cpr_vreg, "%s override voltage: [%s] uV\n", label, buf);
- kfree(buf);
- return rc;
- use_fuse_corner_limits:
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++)
- virtual_limit[i] = fuse_limit[cpr_vreg->corner_map[i]];
- return rc;
- }
- /*
- * This function loads per-virtual-corner ceiling and floor voltages from device
- * tree if their respective device tree properties are present. These limits
- * override those found in the per-fuse-corner arrays fuse_ceiling_volt and
- * fuse_floor_volt.
- */
- static int cpr_init_ceiling_floor_override_voltages(
- struct cpr_regulator *cpr_vreg, struct device *dev)
- {
- int rc, i;
- int size = cpr_vreg->num_corners + 1;
- cpr_vreg->ceiling_volt = devm_kzalloc(dev, sizeof(int) * size,
- GFP_KERNEL);
- cpr_vreg->floor_volt = devm_kzalloc(dev, sizeof(int) * size,
- GFP_KERNEL);
- cpr_vreg->cpr_max_ceiling = devm_kzalloc(dev, sizeof(int) * size,
- GFP_KERNEL);
- if (!cpr_vreg->ceiling_volt || !cpr_vreg->floor_volt ||
- !cpr_vreg->cpr_max_ceiling)
- return -ENOMEM;
- rc = cpr_fill_override_voltage(cpr_vreg, dev,
- "qcom,cpr-voltage-ceiling-override", "ceiling",
- cpr_vreg->ceiling_volt, cpr_vreg->fuse_ceiling_volt);
- if (rc)
- return rc;
- rc = cpr_fill_override_voltage(cpr_vreg, dev,
- "qcom,cpr-voltage-floor-override", "floor",
- cpr_vreg->floor_volt, cpr_vreg->fuse_floor_volt);
- if (rc)
- return rc;
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++) {
- if (cpr_vreg->floor_volt[i] > cpr_vreg->ceiling_volt[i]) {
- cpr_err(cpr_vreg, "virtual corner %d floor=%d uV > ceiling=%d uV\n",
- i, cpr_vreg->floor_volt[i],
- cpr_vreg->ceiling_volt[i]);
- return -EINVAL;
- }
- if (cpr_vreg->ceiling_max < cpr_vreg->ceiling_volt[i])
- cpr_vreg->ceiling_max = cpr_vreg->ceiling_volt[i];
- cpr_vreg->cpr_max_ceiling[i] = cpr_vreg->ceiling_volt[i];
- }
- return rc;
- }
- /*
- * This function computes the per-virtual-corner floor voltages from
- * per-virtual-corner ceiling voltages with an offset specified by a
- * device-tree property. This must be called after open-loop voltage
- * scaling, floor_volt array loading and the ceiling voltage is
- * conditionally reduced to the open-loop voltage. It selects the
- * maximum value between the calculated floor voltage values and
- * the floor_volt array values and stores them in the floor_volt array.
- */
- static int cpr_init_floor_to_ceiling_range(
- struct cpr_regulator *cpr_vreg, struct device *dev)
- {
- int rc, i, tuple_count, tuple_match, len, pos;
- u32 index, floor_volt_adjust = 0;
- char *prop_str, *buf;
- size_t buflen;
- prop_str = "qcom,cpr-floor-to-ceiling-max-range";
- if (!of_find_property(dev->of_node, prop_str, &len))
- return 0;
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) {
- /*
- * No matching index to use for floor-to-ceiling
- * max range.
- */
- return 0;
- }
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- if (len != cpr_vreg->num_corners * tuple_count * sizeof(u32)) {
- cpr_err(cpr_vreg, "%s length=%d is invalid\n", prop_str, len);
- return -EINVAL;
- }
- for (i = CPR_CORNER_MIN; i <= cpr_vreg->num_corners; i++) {
- index = tuple_match * cpr_vreg->num_corners
- + i - CPR_CORNER_MIN;
- rc = of_property_read_u32_index(dev->of_node, prop_str,
- index, &floor_volt_adjust);
- if (rc) {
- cpr_err(cpr_vreg, "could not read %s index %u, rc=%d\n",
- prop_str, index, rc);
- return rc;
- }
- if ((int)floor_volt_adjust >= 0) {
- cpr_vreg->floor_volt[i] = max(cpr_vreg->floor_volt[i],
- (cpr_vreg->ceiling_volt[i]
- - (int)floor_volt_adjust));
- cpr_vreg->floor_volt[i]
- = DIV_ROUND_UP(cpr_vreg->floor_volt[i],
- cpr_vreg->step_volt) *
- cpr_vreg->step_volt;
- if (cpr_vreg->open_loop_volt[i]
- < cpr_vreg->floor_volt[i])
- cpr_vreg->open_loop_volt[i]
- = cpr_vreg->floor_volt[i];
- }
- }
- /*
- * Log per-virtual-corner voltage limits resulted after considering the
- * floor-to-ceiling max range since they are useful for baseline CPR
- * debugging.
- */
- buflen = cpr_vreg->num_corners * (MAX_CHARS_PER_INT + 2) * sizeof(*buf);
- buf = kzalloc(buflen, GFP_KERNEL);
- if (buf == NULL) {
- cpr_err(cpr_vreg, "Could not allocate memory for corner limit voltage logging\n");
- return 0;
- }
- for (i = CPR_CORNER_MIN, pos = 0; i <= cpr_vreg->num_corners; i++)
- pos += scnprintf(buf + pos, buflen - pos, "%d%s",
- cpr_vreg->floor_volt[i],
- i < cpr_vreg->num_corners ? " " : "");
- cpr_info(cpr_vreg, "Final floor override voltages: [%s] uV\n", buf);
- kfree(buf);
- return 0;
- }
- static int cpr_init_step_quotient(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int len = 0;
- u32 step_quot[CPR_NUM_RING_OSC];
- int i, rc;
- if (!of_find_property(of_node, "qcom,cpr-step-quotient", &len)) {
- cpr_err(cpr_vreg, "qcom,cpr-step-quotient property missing\n");
- return -EINVAL;
- }
- if (len == sizeof(u32)) {
- /* Single step quotient used for all ring oscillators. */
- rc = of_property_read_u32(of_node, "qcom,cpr-step-quotient",
- step_quot);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,cpr-step-quotient, rc=%d\n",
- rc);
- return rc;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners;
- i++)
- cpr_vreg->step_quotient[i] = step_quot[0];
- } else if (len == sizeof(u32) * CPR_NUM_RING_OSC) {
- /* Unique step quotient used per ring oscillator. */
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-step-quotient", step_quot, CPR_NUM_RING_OSC);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,cpr-step-quotient, rc=%d\n",
- rc);
- return rc;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners;
- i++)
- cpr_vreg->step_quotient[i]
- = step_quot[cpr_vreg->cpr_fuse_ro_sel[i]];
- } else {
- cpr_err(cpr_vreg, "qcom,cpr-step-quotient has invalid length=%d\n",
- len);
- return -EINVAL;
- }
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++)
- cpr_debug(cpr_vreg, "step_quotient[%d]=%u\n", i,
- cpr_vreg->step_quotient[i]);
- return 0;
- }
- static int cpr_init_cpr_parameters(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int rc = 0;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-ref-clk",
- &cpr_vreg->ref_clk_khz, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-timer-delay",
- &cpr_vreg->timer_delay_us, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-timer-cons-up",
- &cpr_vreg->timer_cons_up, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-timer-cons-down",
- &cpr_vreg->timer_cons_down, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-irq-line",
- &cpr_vreg->irq_line, rc);
- if (rc)
- return rc;
- rc = cpr_init_step_quotient(pdev, cpr_vreg);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-up-threshold",
- &cpr_vreg->up_threshold, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-down-threshold",
- &cpr_vreg->down_threshold, rc);
- if (rc)
- return rc;
- cpr_info(cpr_vreg, "up threshold = %u, down threshold = %u\n",
- cpr_vreg->up_threshold, cpr_vreg->down_threshold);
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-idle-clocks",
- &cpr_vreg->idle_clocks, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-gcnt-time",
- &cpr_vreg->gcnt_time_us, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "vdd-apc-step-up-limit",
- &cpr_vreg->vdd_apc_step_up_limit, rc);
- if (rc)
- return rc;
- CPR_PROP_READ_U32(cpr_vreg, of_node, "vdd-apc-step-down-limit",
- &cpr_vreg->vdd_apc_step_down_limit, rc);
- if (rc)
- return rc;
- rc = of_property_read_u32(of_node, "qcom,cpr-clamp-timer-interval",
- &cpr_vreg->clamp_timer_interval);
- if (rc && rc != -EINVAL) {
- cpr_err(cpr_vreg,
- "error reading qcom,cpr-clamp-timer-interval, rc=%d\n",
- rc);
- return rc;
- }
- cpr_vreg->clamp_timer_interval = min(cpr_vreg->clamp_timer_interval,
- (u32)RBIF_TIMER_ADJ_CLAMP_INT_MASK);
- /* Init module parameter with the DT value */
- cpr_vreg->enable = of_property_read_bool(of_node, "qcom,cpr-enable");
- cpr_info(cpr_vreg, "CPR is %s by default.\n",
- cpr_vreg->enable ? "enabled" : "disabled");
- return 0;
- }
- static void cpr_regulator_switch_adj_cpus(struct cpr_regulator *cpr_vreg)
- {
- cpr_vreg->last_volt = cpr_vreg->adj_cpus_last_volt
- [cpr_vreg->online_cpus];
- cpr_vreg->save_ctl = cpr_vreg->adj_cpus_save_ctl[cpr_vreg->online_cpus];
- cpr_vreg->save_irq = cpr_vreg->adj_cpus_save_irq[cpr_vreg->online_cpus];
- if (cpr_vreg->adj_cpus_quot_adjust)
- cpr_vreg->quot_adjust = cpr_vreg->adj_cpus_quot_adjust
- [cpr_vreg->online_cpus];
- if (cpr_vreg->adj_cpus_open_loop_volt)
- cpr_vreg->open_loop_volt
- = cpr_vreg->adj_cpus_open_loop_volt
- [cpr_vreg->online_cpus];
- if (cpr_vreg->adj_cpus_open_loop_volt_as_ceiling)
- cpr_vreg->ceiling_volt = cpr_vreg->open_loop_volt;
- }
- static void cpr_regulator_set_online_cpus(struct cpr_regulator *cpr_vreg)
- {
- int i, j;
- cpr_vreg->online_cpus = 0;
- get_online_cpus();
- for_each_online_cpu(i)
- for (j = 0; j < cpr_vreg->num_adj_cpus; j++)
- if (i == cpr_vreg->adj_cpus[j])
- cpr_vreg->online_cpus++;
- put_online_cpus();
- }
- static int cpr_regulator_cpu_callback(struct notifier_block *nb,
- unsigned long action, void *data)
- {
- struct cpr_regulator *cpr_vreg = container_of(nb, struct cpr_regulator,
- cpu_notifier);
- int cpu = (long)data;
- int prev_online_cpus, rc, i;
- action &= ~CPU_TASKS_FROZEN;
- if (action != CPU_UP_PREPARE && action != CPU_UP_CANCELED
- && action != CPU_DEAD)
- return NOTIFY_OK;
- mutex_lock(&cpr_vreg->cpr_mutex);
- if (cpr_vreg->skip_voltage_change_during_suspend
- && cpr_vreg->is_cpr_suspended) {
- /* Do nothing during system suspend/resume */
- goto done;
- }
- prev_online_cpus = cpr_vreg->online_cpus;
- cpr_regulator_set_online_cpus(cpr_vreg);
- if (action == CPU_UP_PREPARE)
- for (i = 0; i < cpr_vreg->num_adj_cpus; i++)
- if (cpu == cpr_vreg->adj_cpus[i]) {
- cpr_vreg->online_cpus++;
- break;
- }
- if (cpr_vreg->online_cpus == prev_online_cpus)
- goto done;
- cpr_debug(cpr_vreg, "adjusting corner %d quotient for %d cpus\n",
- cpr_vreg->corner, cpr_vreg->online_cpus);
- cpr_regulator_switch_adj_cpus(cpr_vreg);
- if (cpr_vreg->corner) {
- rc = cpr_regulator_set_voltage(cpr_vreg->rdev,
- cpr_vreg->corner, true);
- if (rc)
- cpr_err(cpr_vreg, "could not update quotient, rc=%d\n",
- rc);
- }
- done:
- mutex_unlock(&cpr_vreg->cpr_mutex);
- return NOTIFY_OK;
- }
- static void cpr_pm_disable(struct cpr_regulator *cpr_vreg, bool disable)
- {
- u32 reg_val;
- if (cpr_vreg->is_cpr_suspended)
- return;
- reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
- if (disable) {
- /* Proceed only if CPR is enabled */
- if (!(reg_val & RBCPR_CTL_LOOP_EN))
- return;
- cpr_ctl_disable(cpr_vreg);
- cpr_vreg->cpr_disabled_in_pc = true;
- } else {
- /* Proceed only if CPR was disabled in PM_ENTER */
- if (!cpr_vreg->cpr_disabled_in_pc)
- return;
- cpr_vreg->cpr_disabled_in_pc = false;
- cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
- }
- /* Make sure register write is complete */
- mb();
- }
- static int cpr_pm_callback(struct notifier_block *nb,
- unsigned long action, void *data)
- {
- struct cpr_regulator *cpr_vreg = container_of(nb,
- struct cpr_regulator, pm_notifier);
- if (action != CPU_PM_ENTER && action != CPU_PM_ENTER_FAILED &&
- action != CPU_PM_EXIT)
- return NOTIFY_OK;
- switch (action) {
- case CPU_PM_ENTER:
- cpr_pm_disable(cpr_vreg, true);
- break;
- case CPU_PM_ENTER_FAILED:
- case CPU_PM_EXIT:
- cpr_pm_disable(cpr_vreg, false);
- break;
- }
- return NOTIFY_OK;
- }
- static int cpr_parse_adj_cpus_init_voltage(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- int rc, i, j, k, tuple_count, tuple_match, len, offset;
- int *temp;
- if (!of_find_property(dev->of_node,
- "qcom,cpr-online-cpu-virtual-corner-init-voltage-adjustment",
- NULL))
- return 0;
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) {
- /* No matching index to use for voltage adjustment. */
- return 0;
- }
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- len = (cpr_vreg->num_adj_cpus + 1) * tuple_count
- * cpr_vreg->num_corners;
- temp = kzalloc(sizeof(int) * len, GFP_KERNEL);
- if (!temp) {
- cpr_err(cpr_vreg, "Could not allocate memory\n");
- return -ENOMEM;
- }
- cpr_vreg->adj_cpus_open_loop_volt = devm_kzalloc(dev,
- sizeof(int *) * (cpr_vreg->num_adj_cpus + 1),
- GFP_KERNEL);
- if (!cpr_vreg->adj_cpus_open_loop_volt) {
- cpr_err(cpr_vreg, "Could not allocate memory\n");
- rc = -ENOMEM;
- goto done;
- }
- cpr_vreg->adj_cpus_open_loop_volt[0] = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_adj_cpus + 1)
- * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- if (!cpr_vreg->adj_cpus_open_loop_volt[0]) {
- cpr_err(cpr_vreg, "Could not allocate memory\n");
- rc = -ENOMEM;
- goto done;
- }
- for (i = 1; i <= cpr_vreg->num_adj_cpus; i++)
- cpr_vreg->adj_cpus_open_loop_volt[i] =
- cpr_vreg->adj_cpus_open_loop_volt[0] +
- i * (cpr_vreg->num_corners + 1);
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-online-cpu-virtual-corner-init-voltage-adjustment",
- temp, len);
- if (rc) {
- cpr_err(cpr_vreg, "failed to read qcom,cpr-online-cpu-virtual-corner-init-voltage-adjustment, rc=%d\n",
- rc);
- goto done;
- }
- cpr_debug(cpr_vreg, "Open loop voltage based on number of online CPUs:\n");
- offset = tuple_match * cpr_vreg->num_corners *
- (cpr_vreg->num_adj_cpus + 1);
- for (i = 0; i <= cpr_vreg->num_adj_cpus; i++) {
- for (j = CPR_CORNER_MIN; j <= cpr_vreg->num_corners; j++) {
- k = j - 1 + offset;
- cpr_vreg->adj_cpus_open_loop_volt[i][j]
- = cpr_vreg->open_loop_volt[j] + temp[k];
- cpr_vreg->adj_cpus_open_loop_volt[i][j]
- = DIV_ROUND_UP(cpr_vreg->
- adj_cpus_open_loop_volt[i][j],
- cpr_vreg->step_volt) * cpr_vreg->step_volt;
- if (cpr_vreg->adj_cpus_open_loop_volt[i][j]
- > cpr_vreg->ceiling_volt[j])
- cpr_vreg->adj_cpus_open_loop_volt[i][j]
- = cpr_vreg->ceiling_volt[j];
- if (cpr_vreg->adj_cpus_open_loop_volt[i][j]
- < cpr_vreg->floor_volt[j])
- cpr_vreg->adj_cpus_open_loop_volt[i][j]
- = cpr_vreg->floor_volt[j];
- cpr_debug(cpr_vreg, "cpus=%d, corner=%d, volt=%d\n",
- i, j, cpr_vreg->adj_cpus_open_loop_volt[i][j]);
- }
- offset += cpr_vreg->num_corners;
- }
- cpr_vreg->adj_cpus_open_loop_volt_as_ceiling
- = of_property_read_bool(dev->of_node,
- "qcom,cpr-online-cpu-init-voltage-as-ceiling");
- done:
- kfree(temp);
- return rc;
- }
- static int cpr_parse_adj_cpus_target_quot(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- int rc, i, j, k, tuple_count, tuple_match, len, offset;
- int *temp;
- if (!of_find_property(dev->of_node,
- "qcom,cpr-online-cpu-virtual-corner-quotient-adjustment",
- NULL))
- return 0;
- if (cpr_vreg->cpr_fuse_map_count) {
- if (cpr_vreg->cpr_fuse_map_match == FUSE_MAP_NO_MATCH) {
- /* No matching index to use for quotient adjustment. */
- return 0;
- }
- tuple_count = cpr_vreg->cpr_fuse_map_count;
- tuple_match = cpr_vreg->cpr_fuse_map_match;
- } else {
- tuple_count = 1;
- tuple_match = 0;
- }
- len = (cpr_vreg->num_adj_cpus + 1) * tuple_count
- * cpr_vreg->num_corners;
- temp = kzalloc(sizeof(int) * len, GFP_KERNEL);
- if (!temp) {
- cpr_err(cpr_vreg, "Could not allocate memory\n");
- return -ENOMEM;
- }
- cpr_vreg->adj_cpus_quot_adjust = devm_kzalloc(dev,
- sizeof(int *) * (cpr_vreg->num_adj_cpus + 1),
- GFP_KERNEL);
- if (!cpr_vreg->adj_cpus_quot_adjust) {
- cpr_err(cpr_vreg, "Could not allocate memory\n");
- rc = -ENOMEM;
- goto done;
- }
- cpr_vreg->adj_cpus_quot_adjust[0] = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_adj_cpus + 1)
- * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- if (!cpr_vreg->adj_cpus_quot_adjust[0]) {
- cpr_err(cpr_vreg, "Could not allocate memory\n");
- rc = -ENOMEM;
- goto done;
- }
- for (i = 1; i <= cpr_vreg->num_adj_cpus; i++)
- cpr_vreg->adj_cpus_quot_adjust[i] =
- cpr_vreg->adj_cpus_quot_adjust[0] +
- i * (cpr_vreg->num_corners + 1);
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-online-cpu-virtual-corner-quotient-adjustment",
- temp, len);
- if (rc) {
- cpr_err(cpr_vreg, "failed to read qcom,cpr-online-cpu-virtual-corner-quotient-adjustment, rc=%d\n",
- rc);
- goto done;
- }
- cpr_debug(cpr_vreg, "Target quotients based on number of online CPUs:\n");
- offset = tuple_match * cpr_vreg->num_corners *
- (cpr_vreg->num_adj_cpus + 1);
- for (i = 0; i <= cpr_vreg->num_adj_cpus; i++) {
- for (j = CPR_CORNER_MIN; j <= cpr_vreg->num_corners; j++) {
- k = j - 1 + offset;
- cpr_vreg->adj_cpus_quot_adjust[i][j] =
- cpr_vreg->quot_adjust[j] - temp[k];
- cpr_debug(cpr_vreg, "cpus=%d, corner=%d, quot=%d\n",
- i, j,
- cpr_vreg->cpr_fuse_target_quot[
- cpr_vreg->corner_map[j]]
- - cpr_vreg->adj_cpus_quot_adjust[i][j]);
- }
- offset += cpr_vreg->num_corners;
- }
- done:
- kfree(temp);
- return rc;
- }
- static int cpr_init_per_cpu_adjustments(struct cpr_regulator *cpr_vreg,
- struct device *dev)
- {
- int rc, i, j;
- if (!of_find_property(dev->of_node,
- "qcom,cpr-online-cpu-virtual-corner-init-voltage-adjustment",
- NULL)
- && !of_find_property(dev->of_node,
- "qcom,cpr-online-cpu-virtual-corner-quotient-adjustment",
- NULL)) {
- /* No per-online CPU adjustment needed */
- return 0;
- }
- if (!cpr_vreg->num_adj_cpus) {
- cpr_err(cpr_vreg, "qcom,cpr-cpus property missing\n");
- return -EINVAL;
- }
- rc = cpr_parse_adj_cpus_init_voltage(cpr_vreg, dev);
- if (rc) {
- cpr_err(cpr_vreg, "cpr_parse_adj_cpus_init_voltage failed: rc =%d\n",
- rc);
- return rc;
- }
- rc = cpr_parse_adj_cpus_target_quot(cpr_vreg, dev);
- if (rc) {
- cpr_err(cpr_vreg, "cpr_parse_adj_cpus_target_quot failed: rc =%d\n",
- rc);
- return rc;
- }
- cpr_vreg->adj_cpus_last_volt = devm_kzalloc(dev,
- sizeof(int *) * (cpr_vreg->num_adj_cpus + 1),
- GFP_KERNEL);
- cpr_vreg->adj_cpus_save_ctl = devm_kzalloc(dev,
- sizeof(int *) * (cpr_vreg->num_adj_cpus + 1),
- GFP_KERNEL);
- cpr_vreg->adj_cpus_save_irq = devm_kzalloc(dev,
- sizeof(int *) * (cpr_vreg->num_adj_cpus + 1),
- GFP_KERNEL);
- if (!cpr_vreg->adj_cpus_last_volt || !cpr_vreg->adj_cpus_save_ctl ||
- !cpr_vreg->adj_cpus_save_irq) {
- cpr_err(cpr_vreg, "Could not allocate memory\n");
- return -ENOMEM;
- }
- cpr_vreg->adj_cpus_last_volt[0] = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_adj_cpus + 1)
- * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- cpr_vreg->adj_cpus_save_ctl[0] = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_adj_cpus + 1)
- * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- cpr_vreg->adj_cpus_save_irq[0] = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_adj_cpus + 1)
- * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- if (!cpr_vreg->adj_cpus_last_volt[0] ||
- !cpr_vreg->adj_cpus_save_ctl[0] ||
- !cpr_vreg->adj_cpus_save_irq[0]) {
- cpr_err(cpr_vreg, "Could not allocate memory\n");
- return -ENOMEM;
- }
- for (i = 1; i <= cpr_vreg->num_adj_cpus; i++) {
- j = i * (cpr_vreg->num_corners + 1);
- cpr_vreg->adj_cpus_last_volt[i] =
- cpr_vreg->adj_cpus_last_volt[0] + j;
- cpr_vreg->adj_cpus_save_ctl[i] =
- cpr_vreg->adj_cpus_save_ctl[0] + j;
- cpr_vreg->adj_cpus_save_irq[i] =
- cpr_vreg->adj_cpus_save_irq[0] + j;
- }
- for (i = 0; i <= cpr_vreg->num_adj_cpus; i++) {
- for (j = CPR_CORNER_MIN; j <= cpr_vreg->num_corners; j++) {
- cpr_vreg->adj_cpus_save_ctl[i][j] =
- cpr_vreg->save_ctl[j];
- cpr_vreg->adj_cpus_save_irq[i][j] =
- cpr_vreg->save_irq[j];
- cpr_vreg->adj_cpus_last_volt[i][j]
- = cpr_vreg->adj_cpus_open_loop_volt
- ? cpr_vreg->adj_cpus_open_loop_volt[i][j]
- : cpr_vreg->open_loop_volt[j];
- }
- }
- cpr_regulator_set_online_cpus(cpr_vreg);
- cpr_debug(cpr_vreg, "%d cpus online\n", cpr_vreg->online_cpus);
- devm_kfree(dev, cpr_vreg->last_volt);
- devm_kfree(dev, cpr_vreg->save_ctl);
- devm_kfree(dev, cpr_vreg->save_irq);
- if (cpr_vreg->adj_cpus_quot_adjust)
- devm_kfree(dev, cpr_vreg->quot_adjust);
- if (cpr_vreg->adj_cpus_open_loop_volt)
- devm_kfree(dev, cpr_vreg->open_loop_volt);
- if (cpr_vreg->adj_cpus_open_loop_volt_as_ceiling)
- devm_kfree(dev, cpr_vreg->ceiling_volt);
- cpr_regulator_switch_adj_cpus(cpr_vreg);
- cpr_vreg->skip_voltage_change_during_suspend
- = of_property_read_bool(dev->of_node,
- "qcom,cpr-skip-voltage-change-during-suspend");
- cpr_vreg->cpu_notifier.notifier_call = cpr_regulator_cpu_callback;
- register_hotcpu_notifier(&cpr_vreg->cpu_notifier);
- return rc;
- }
- static int cpr_init_pm_notification(struct cpr_regulator *cpr_vreg)
- {
- int rc;
- /* enabled only for single-core designs */
- if (cpr_vreg->num_adj_cpus != 1) {
- pr_warn("qcom,cpr-cpus not defined or invalid %d\n",
- cpr_vreg->num_adj_cpus);
- return 0;
- }
- cpr_vreg->pm_notifier.notifier_call = cpr_pm_callback;
- rc = cpu_pm_register_notifier(&cpr_vreg->pm_notifier);
- if (rc)
- cpr_err(cpr_vreg, "Unable to register pm notifier rc=%d\n", rc);
- return rc;
- }
- static int cpr_rpm_apc_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- int rc, len = 0;
- struct device_node *of_node = pdev->dev.of_node;
- if (!of_find_property(of_node, "rpm-apc-supply", NULL))
- return 0;
- cpr_vreg->rpm_apc_vreg = devm_regulator_get(&pdev->dev, "rpm-apc");
- if (IS_ERR_OR_NULL(cpr_vreg->rpm_apc_vreg)) {
- rc = PTR_RET(cpr_vreg->rpm_apc_vreg);
- if (rc != -EPROBE_DEFER)
- cpr_err(cpr_vreg, "devm_regulator_get: rpm-apc: rc=%d\n",
- rc);
- return rc;
- }
- if (!of_find_property(of_node, "qcom,rpm-apc-corner-map", &len)) {
- cpr_err(cpr_vreg,
- "qcom,rpm-apc-corner-map missing:\n");
- return -EINVAL;
- }
- if (len != cpr_vreg->num_corners * sizeof(u32)) {
- cpr_err(cpr_vreg,
- "qcom,rpm-apc-corner-map length=%d is invalid: required:%d\n",
- len, cpr_vreg->num_corners);
- return -EINVAL;
- }
- cpr_vreg->rpm_apc_corner_map = devm_kzalloc(&pdev->dev,
- (cpr_vreg->num_corners + 1) *
- sizeof(*cpr_vreg->rpm_apc_corner_map), GFP_KERNEL);
- if (!cpr_vreg->rpm_apc_corner_map) {
- cpr_err(cpr_vreg, "Can't allocate memory for cpr_vreg->rpm_apc_corner_map\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(of_node, "qcom,rpm-apc-corner-map",
- &cpr_vreg->rpm_apc_corner_map[1], cpr_vreg->num_corners);
- if (rc)
- cpr_err(cpr_vreg, "read qcom,rpm-apc-corner-map failed, rc = %d\n",
- rc);
- return rc;
- }
- static int cpr_vsens_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- int rc = 0, len = 0;
- struct device_node *of_node = pdev->dev.of_node;
- if (of_find_property(of_node, "vdd-vsens-voltage-supply", NULL)) {
- cpr_vreg->vdd_vsens_voltage = devm_regulator_get(&pdev->dev,
- "vdd-vsens-voltage");
- if (IS_ERR_OR_NULL(cpr_vreg->vdd_vsens_voltage)) {
- rc = PTR_ERR(cpr_vreg->vdd_vsens_voltage);
- cpr_vreg->vdd_vsens_voltage = NULL;
- if (rc == -EPROBE_DEFER)
- return rc;
- /* device not found */
- cpr_debug(cpr_vreg, "regulator_get: vdd-vsens-voltage: rc=%d\n",
- rc);
- return 0;
- }
- }
- if (of_find_property(of_node, "vdd-vsens-corner-supply", NULL)) {
- cpr_vreg->vdd_vsens_corner = devm_regulator_get(&pdev->dev,
- "vdd-vsens-corner");
- if (IS_ERR_OR_NULL(cpr_vreg->vdd_vsens_corner)) {
- rc = PTR_ERR(cpr_vreg->vdd_vsens_corner);
- cpr_vreg->vdd_vsens_corner = NULL;
- if (rc == -EPROBE_DEFER)
- return rc;
- /* device not found */
- cpr_debug(cpr_vreg, "regulator_get: vdd-vsens-corner: rc=%d\n",
- rc);
- return 0;
- }
- if (!of_find_property(of_node, "qcom,vsens-corner-map", &len)) {
- cpr_err(cpr_vreg, "qcom,vsens-corner-map missing\n");
- return -EINVAL;
- }
- if (len != cpr_vreg->num_fuse_corners * sizeof(u32)) {
- cpr_err(cpr_vreg, "qcom,vsens-corner-map length=%d is invalid: required:%d\n",
- len, cpr_vreg->num_fuse_corners);
- return -EINVAL;
- }
- cpr_vreg->vsens_corner_map = devm_kcalloc(&pdev->dev,
- (cpr_vreg->num_fuse_corners + 1),
- sizeof(*cpr_vreg->vsens_corner_map), GFP_KERNEL);
- if (!cpr_vreg->vsens_corner_map)
- return -ENOMEM;
- rc = of_property_read_u32_array(of_node,
- "qcom,vsens-corner-map",
- &cpr_vreg->vsens_corner_map[1],
- cpr_vreg->num_fuse_corners);
- if (rc)
- cpr_err(cpr_vreg, "read qcom,vsens-corner-map failed, rc = %d\n",
- rc);
- }
- return rc;
- }
- static int cpr_init_cpr(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct resource *res;
- int rc = 0;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr_clk");
- if (res && res->start)
- cpr_vreg->rbcpr_clk_addr = res->start;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr");
- if (!res || !res->start) {
- cpr_err(cpr_vreg, "missing rbcpr address: res=%p\n", res);
- return -EINVAL;
- }
- cpr_vreg->rbcpr_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- /* Init CPR configuration parameters */
- rc = cpr_init_cpr_parameters(pdev, cpr_vreg);
- if (rc)
- return rc;
- rc = cpr_init_cpr_efuse(pdev, cpr_vreg);
- if (rc)
- return rc;
- /* Load per corner ceiling and floor voltages if they exist. */
- rc = cpr_init_ceiling_floor_override_voltages(cpr_vreg, &pdev->dev);
- if (rc)
- return rc;
- /*
- * Limit open loop voltages based upon per corner ceiling and floor
- * voltages.
- */
- rc = cpr_limit_open_loop_voltage(cpr_vreg);
- if (rc)
- return rc;
- /*
- * Fill the OPP table for this device with virtual voltage corner to
- * open-loop voltage pairs.
- */
- rc = cpr_populate_opp_table(cpr_vreg, &pdev->dev);
- if (rc)
- return rc;
- /* Reduce the ceiling voltage if allowed. */
- rc = cpr_reduce_ceiling_voltage(cpr_vreg, &pdev->dev);
- if (rc)
- return rc;
- /* Load CPR floor to ceiling range if exist. */
- rc = cpr_init_floor_to_ceiling_range(cpr_vreg, &pdev->dev);
- if (rc)
- return rc;
- /* Init all voltage set points of APC regulator for CPR */
- rc = cpr_init_cpr_voltages(cpr_vreg, &pdev->dev);
- if (rc)
- return rc;
- /* Get and Init interrupt */
- cpr_vreg->cpr_irq = platform_get_irq(pdev, 0);
- if (!cpr_vreg->cpr_irq) {
- cpr_err(cpr_vreg, "missing CPR IRQ\n");
- return -EINVAL;
- }
- /* Configure CPR HW but keep it disabled */
- rc = cpr_config(cpr_vreg, &pdev->dev);
- if (rc)
- return rc;
- rc = request_threaded_irq(cpr_vreg->cpr_irq, NULL, cpr_irq_handler,
- IRQF_ONESHOT | IRQF_TRIGGER_RISING, "cpr",
- cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "CPR: request irq failed for IRQ %d\n",
- cpr_vreg->cpr_irq);
- return rc;
- }
- return 0;
- }
- /*
- * Create a set of virtual fuse rows if optional device tree properties are
- * present.
- */
- static int cpr_remap_efuse_data(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- struct property *prop;
- u64 fuse_param;
- u32 *temp;
- int size, rc, i, bits, in_row, in_bit, out_row, out_bit;
- prop = of_find_property(of_node, "qcom,fuse-remap-source", NULL);
- if (!prop) {
- /* No fuse remapping needed. */
- return 0;
- }
- size = prop->length / sizeof(u32);
- if (size == 0 || size % 4) {
- cpr_err(cpr_vreg, "qcom,fuse-remap-source has invalid size=%d\n",
- size);
- return -EINVAL;
- }
- size /= 4;
- rc = of_property_read_u32(of_node, "qcom,fuse-remap-base-row",
- &cpr_vreg->remapped_row_base);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,fuse-remap-base-row, rc=%d\n",
- rc);
- return rc;
- }
- temp = kzalloc(sizeof(*temp) * size * 4, GFP_KERNEL);
- if (!temp) {
- cpr_err(cpr_vreg, "temp memory allocation failed\n");
- return -ENOMEM;
- }
- rc = of_property_read_u32_array(of_node, "qcom,fuse-remap-source", temp,
- size * 4);
- if (rc) {
- cpr_err(cpr_vreg, "could not read qcom,fuse-remap-source, rc=%d\n",
- rc);
- goto done;
- }
- /*
- * Format of tuples in qcom,fuse-remap-source property:
- * <row bit-offset bit-count fuse-read-method>
- */
- for (i = 0, bits = 0; i < size; i++)
- bits += temp[i * 4 + 2];
- cpr_vreg->num_remapped_rows = DIV_ROUND_UP(bits, 64);
- cpr_vreg->remapped_row = devm_kzalloc(&pdev->dev,
- sizeof(*cpr_vreg->remapped_row) * cpr_vreg->num_remapped_rows,
- GFP_KERNEL);
- if (!cpr_vreg->remapped_row) {
- cpr_err(cpr_vreg, "remapped_row memory allocation failed\n");
- rc = -ENOMEM;
- goto done;
- }
- for (i = 0, out_row = 0, out_bit = 0; i < size; i++) {
- in_row = temp[i * 4];
- in_bit = temp[i * 4 + 1];
- bits = temp[i * 4 + 2];
- while (bits > 64) {
- fuse_param = cpr_read_efuse_param(cpr_vreg, in_row,
- in_bit, 64, temp[i * 4 + 3]);
- cpr_vreg->remapped_row[out_row++]
- |= fuse_param << out_bit;
- if (out_bit > 0)
- cpr_vreg->remapped_row[out_row]
- |= fuse_param >> (64 - out_bit);
- bits -= 64;
- in_bit += 64;
- }
- fuse_param = cpr_read_efuse_param(cpr_vreg, in_row, in_bit,
- bits, temp[i * 4 + 3]);
- cpr_vreg->remapped_row[out_row] |= fuse_param << out_bit;
- if (bits < 64 - out_bit) {
- out_bit += bits;
- } else {
- out_row++;
- if (out_bit > 0)
- cpr_vreg->remapped_row[out_row]
- |= fuse_param >> (64 - out_bit);
- out_bit = bits - (64 - out_bit);
- }
- }
- done:
- kfree(temp);
- return rc;
- }
- static int cpr_efuse_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct resource *res;
- int len;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse_addr");
- if (!res || !res->start) {
- cpr_err(cpr_vreg, "efuse_addr missing: res=%p\n", res);
- return -EINVAL;
- }
- cpr_vreg->efuse_addr = res->start;
- len = res->end - res->start + 1;
- cpr_info(cpr_vreg, "efuse_addr = %pa (len=0x%x)\n", &res->start, len);
- cpr_vreg->efuse_base = ioremap(cpr_vreg->efuse_addr, len);
- if (!cpr_vreg->efuse_base) {
- cpr_err(cpr_vreg, "Unable to map efuse_addr %pa\n",
- &cpr_vreg->efuse_addr);
- return -EINVAL;
- }
- return 0;
- }
- static void cpr_efuse_free(struct cpr_regulator *cpr_vreg)
- {
- iounmap(cpr_vreg->efuse_base);
- }
- static void cpr_parse_cond_min_volt_fuse(struct cpr_regulator *cpr_vreg,
- struct device_node *of_node)
- {
- int rc;
- u32 fuse_sel[5];
- /*
- * Restrict all pvs corner voltages to a minimum value of
- * qcom,cpr-cond-min-voltage if the fuse defined in
- * qcom,cpr-fuse-cond-min-volt-sel does not read back with
- * the expected value.
- */
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-cond-min-volt-sel", fuse_sel, 5);
- if (!rc) {
- if (!cpr_fuse_is_setting_expected(cpr_vreg, fuse_sel))
- cpr_vreg->flags |= FLAGS_SET_MIN_VOLTAGE;
- }
- }
- static void cpr_parse_speed_bin_fuse(struct cpr_regulator *cpr_vreg,
- struct device_node *of_node)
- {
- int rc;
- u64 fuse_bits;
- u32 fuse_sel[4];
- u32 speed_bits;
- rc = of_property_read_u32_array(of_node,
- "qcom,speed-bin-fuse-sel", fuse_sel, 4);
- if (!rc) {
- fuse_bits = cpr_read_efuse_row(cpr_vreg,
- fuse_sel[0], fuse_sel[3]);
- speed_bits = (fuse_bits >> fuse_sel[1]) &
- ((1 << fuse_sel[2]) - 1);
- cpr_info(cpr_vreg, "[row: %d]: 0x%llx, speed_bits = %d\n",
- fuse_sel[0], fuse_bits, speed_bits);
- cpr_vreg->speed_bin = speed_bits;
- } else {
- cpr_vreg->speed_bin = SPEED_BIN_NONE;
- }
- }
- static int cpr_voltage_uplift_enable_check(struct cpr_regulator *cpr_vreg,
- struct device_node *of_node)
- {
- int rc;
- u32 fuse_sel[5];
- u32 uplift_speed_bin;
- rc = of_property_read_u32_array(of_node,
- "qcom,cpr-fuse-uplift-sel", fuse_sel, 5);
- if (!rc) {
- rc = of_property_read_u32(of_node,
- "qcom,cpr-uplift-speed-bin",
- &uplift_speed_bin);
- if (rc < 0) {
- cpr_err(cpr_vreg,
- "qcom,cpr-uplift-speed-bin missing\n");
- return rc;
- }
- if (cpr_fuse_is_setting_expected(cpr_vreg, fuse_sel)
- && (uplift_speed_bin == cpr_vreg->speed_bin)
- && !(cpr_vreg->flags & FLAGS_SET_MIN_VOLTAGE)) {
- cpr_vreg->flags |= FLAGS_UPLIFT_QUOT_VOLT;
- }
- }
- return 0;
- }
- /*
- * Read in the number of fuse corners and then allocate memory for arrays that
- * are sized based upon the number of fuse corners.
- */
- static int cpr_fuse_corner_array_alloc(struct device *dev,
- struct cpr_regulator *cpr_vreg)
- {
- int rc;
- size_t len;
- rc = of_property_read_u32(dev->of_node, "qcom,cpr-fuse-corners",
- &cpr_vreg->num_fuse_corners);
- if (rc < 0) {
- cpr_err(cpr_vreg, "qcom,cpr-fuse-corners missing: rc=%d\n", rc);
- return rc;
- }
- if (cpr_vreg->num_fuse_corners < CPR_FUSE_CORNER_MIN
- || cpr_vreg->num_fuse_corners > CPR_FUSE_CORNER_LIMIT) {
- cpr_err(cpr_vreg, "corner count=%d is invalid\n",
- cpr_vreg->num_fuse_corners);
- return -EINVAL;
- }
- /*
- * The arrays sized based on the fuse corner count ignore element 0
- * in order to simplify indexing throughout the driver since min_uV = 0
- * cannot be passed into a set_voltage() callback.
- */
- len = cpr_vreg->num_fuse_corners + 1;
- cpr_vreg->pvs_corner_v = devm_kzalloc(dev,
- len * sizeof(*cpr_vreg->pvs_corner_v), GFP_KERNEL);
- cpr_vreg->cpr_fuse_target_quot = devm_kzalloc(dev,
- len * sizeof(*cpr_vreg->cpr_fuse_target_quot), GFP_KERNEL);
- cpr_vreg->cpr_fuse_ro_sel = devm_kzalloc(dev,
- len * sizeof(*cpr_vreg->cpr_fuse_ro_sel), GFP_KERNEL);
- cpr_vreg->fuse_ceiling_volt = devm_kzalloc(dev,
- len * (sizeof(*cpr_vreg->fuse_ceiling_volt)), GFP_KERNEL);
- cpr_vreg->fuse_floor_volt = devm_kzalloc(dev,
- len * (sizeof(*cpr_vreg->fuse_floor_volt)), GFP_KERNEL);
- cpr_vreg->step_quotient = devm_kzalloc(dev,
- len * sizeof(*cpr_vreg->step_quotient), GFP_KERNEL);
- if (cpr_vreg->pvs_corner_v == NULL || cpr_vreg->cpr_fuse_ro_sel == NULL
- || cpr_vreg->fuse_ceiling_volt == NULL
- || cpr_vreg->fuse_floor_volt == NULL
- || cpr_vreg->cpr_fuse_target_quot == NULL
- || cpr_vreg->step_quotient == NULL) {
- cpr_err(cpr_vreg, "Could not allocate memory for CPR arrays\n");
- return -ENOMEM;
- }
- return 0;
- }
- static int cpr_voltage_plan_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- struct device_node *of_node = pdev->dev.of_node;
- int rc, i;
- u32 min_uv = 0;
- rc = of_property_read_u32_array(of_node, "qcom,cpr-voltage-ceiling",
- &cpr_vreg->fuse_ceiling_volt[CPR_FUSE_CORNER_MIN],
- cpr_vreg->num_fuse_corners);
- if (rc < 0) {
- cpr_err(cpr_vreg, "cpr-voltage-ceiling missing: rc=%d\n", rc);
- return rc;
- }
- rc = of_property_read_u32_array(of_node, "qcom,cpr-voltage-floor",
- &cpr_vreg->fuse_floor_volt[CPR_FUSE_CORNER_MIN],
- cpr_vreg->num_fuse_corners);
- if (rc < 0) {
- cpr_err(cpr_vreg, "cpr-voltage-floor missing: rc=%d\n", rc);
- return rc;
- }
- cpr_parse_cond_min_volt_fuse(cpr_vreg, of_node);
- rc = cpr_voltage_uplift_enable_check(cpr_vreg, of_node);
- if (rc < 0) {
- cpr_err(cpr_vreg, "voltage uplift enable check failed, %d\n",
- rc);
- return rc;
- }
- if (cpr_vreg->flags & FLAGS_SET_MIN_VOLTAGE) {
- of_property_read_u32(of_node, "qcom,cpr-cond-min-voltage",
- &min_uv);
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners;
- i++)
- if (cpr_vreg->fuse_ceiling_volt[i] < min_uv) {
- cpr_vreg->fuse_ceiling_volt[i] = min_uv;
- cpr_vreg->fuse_floor_volt[i] = min_uv;
- } else if (cpr_vreg->fuse_floor_volt[i] < min_uv) {
- cpr_vreg->fuse_floor_volt[i] = min_uv;
- }
- }
- return 0;
- }
- static int cpr_mem_acc_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
- {
- int rc, size;
- struct property *prop;
- char *corner_map_str;
- if (of_find_property(pdev->dev.of_node, "mem-acc-supply", NULL)) {
- cpr_vreg->mem_acc_vreg = devm_regulator_get(&pdev->dev,
- "mem-acc");
- if (IS_ERR_OR_NULL(cpr_vreg->mem_acc_vreg)) {
- rc = PTR_RET(cpr_vreg->mem_acc_vreg);
- if (rc != -EPROBE_DEFER)
- cpr_err(cpr_vreg,
- "devm_regulator_get: mem-acc: rc=%d\n",
- rc);
- return rc;
- }
- }
- corner_map_str = "qcom,mem-acc-corner-map";
- prop = of_find_property(pdev->dev.of_node, corner_map_str, NULL);
- if (!prop) {
- corner_map_str = "qcom,cpr-corner-map";
- prop = of_find_property(pdev->dev.of_node, corner_map_str,
- NULL);
- if (!prop) {
- cpr_err(cpr_vreg, "qcom,cpr-corner-map missing\n");
- return -EINVAL;
- }
- }
- size = prop->length / sizeof(u32);
- cpr_vreg->mem_acc_corner_map = devm_kzalloc(&pdev->dev,
- sizeof(int) * (size + 1),
- GFP_KERNEL);
- rc = of_property_read_u32_array(pdev->dev.of_node, corner_map_str,
- &cpr_vreg->mem_acc_corner_map[CPR_FUSE_CORNER_MIN],
- size);
- if (rc) {
- cpr_err(cpr_vreg, "%s missing, rc = %d\n", corner_map_str, rc);
- return rc;
- }
- return 0;
- }
- #if defined(CONFIG_DEBUG_FS)
- static int cpr_enable_set(void *data, u64 val)
- {
- struct cpr_regulator *cpr_vreg = data;
- bool old_cpr_enable;
- mutex_lock(&cpr_vreg->cpr_mutex);
- old_cpr_enable = cpr_vreg->enable;
- cpr_vreg->enable = val;
- if (old_cpr_enable == cpr_vreg->enable)
- goto _exit;
- if (cpr_vreg->enable && cpr_vreg->cpr_fuse_disable) {
- cpr_info(cpr_vreg,
- "CPR permanently disabled due to fuse values\n");
- cpr_vreg->enable = false;
- goto _exit;
- }
- cpr_debug(cpr_vreg, "%s CPR [corner=%d, fuse_corner=%d]\n",
- cpr_vreg->enable ? "enabling" : "disabling",
- cpr_vreg->corner, cpr_vreg->corner_map[cpr_vreg->corner]);
- if (cpr_vreg->corner) {
- if (cpr_vreg->enable) {
- cpr_ctl_disable(cpr_vreg);
- cpr_irq_clr(cpr_vreg);
- cpr_corner_restore(cpr_vreg, cpr_vreg->corner);
- cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
- } else {
- cpr_ctl_disable(cpr_vreg);
- cpr_irq_set(cpr_vreg, 0);
- }
- }
- _exit:
- mutex_unlock(&cpr_vreg->cpr_mutex);
- return 0;
- }
- static int cpr_enable_get(void *data, u64 *val)
- {
- struct cpr_regulator *cpr_vreg = data;
- *val = cpr_vreg->enable;
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(cpr_enable_fops, cpr_enable_get, cpr_enable_set,
- "%llu\n");
- static int cpr_get_cpr_ceiling(void *data, u64 *val)
- {
- struct cpr_regulator *cpr_vreg = data;
- *val = cpr_vreg->ceiling_volt[cpr_vreg->corner];
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(cpr_ceiling_fops, cpr_get_cpr_ceiling, NULL,
- "%llu\n");
- static int cpr_get_cpr_floor(void *data, u64 *val)
- {
- struct cpr_regulator *cpr_vreg = data;
- *val = cpr_vreg->floor_volt[cpr_vreg->corner];
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(cpr_floor_fops, cpr_get_cpr_floor, NULL,
- "%llu\n");
- static int cpr_get_cpr_max_ceiling(void *data, u64 *val)
- {
- struct cpr_regulator *cpr_vreg = data;
- *val = cpr_vreg->cpr_max_ceiling[cpr_vreg->corner];
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(cpr_max_ceiling_fops, cpr_get_cpr_max_ceiling, NULL,
- "%llu\n");
- static int cpr_debug_info_open(struct inode *inode, struct file *file)
- {
- file->private_data = inode->i_private;
- return 0;
- }
- static ssize_t cpr_debug_info_read(struct file *file, char __user *buff,
- size_t count, loff_t *ppos)
- {
- struct cpr_regulator *cpr_vreg = file->private_data;
- char *debugfs_buf;
- ssize_t len, ret = 0;
- u32 gcnt, ro_sel, ctl, irq_status, reg, error_steps;
- u32 step_dn, step_up, error, error_lt0, busy;
- int fuse_corner;
- debugfs_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!debugfs_buf)
- return -ENOMEM;
- mutex_lock(&cpr_vreg->cpr_mutex);
- fuse_corner = cpr_vreg->corner_map[cpr_vreg->corner];
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "corner = %d, current_volt = %d uV\n",
- cpr_vreg->corner, cpr_vreg->last_volt[cpr_vreg->corner]);
- ret += len;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "fuse_corner = %d, current_volt = %d uV\n",
- fuse_corner, cpr_vreg->last_volt[cpr_vreg->corner]);
- ret += len;
- ro_sel = cpr_vreg->cpr_fuse_ro_sel[fuse_corner];
- gcnt = cpr_read(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel));
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "rbcpr_gcnt_target (%u) = 0x%02X\n", ro_sel, gcnt);
- ret += len;
- ctl = cpr_read(cpr_vreg, REG_RBCPR_CTL);
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "rbcpr_ctl = 0x%02X\n", ctl);
- ret += len;
- irq_status = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "rbcpr_irq_status = 0x%02X\n", irq_status);
- ret += len;
- reg = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "rbcpr_result_0 = 0x%02X\n", reg);
- ret += len;
- step_dn = reg & 0x01;
- step_up = (reg >> RBCPR_RESULT0_STEP_UP_SHIFT) & 0x01;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- " [step_dn = %u", step_dn);
- ret += len;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- ", step_up = %u", step_up);
- ret += len;
- error_steps = (reg >> RBCPR_RESULT0_ERROR_STEPS_SHIFT)
- & RBCPR_RESULT0_ERROR_STEPS_MASK;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- ", error_steps = %u", error_steps);
- ret += len;
- error = (reg >> RBCPR_RESULT0_ERROR_SHIFT) & RBCPR_RESULT0_ERROR_MASK;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- ", error = %u", error);
- ret += len;
- error_lt0 = (reg >> RBCPR_RESULT0_ERROR_LT0_SHIFT) & 0x01;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- ", error_lt_0 = %u", error_lt0);
- ret += len;
- busy = (reg >> RBCPR_RESULT0_BUSY_SHIFT) & 0x01;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- ", busy = %u]\n", busy);
- ret += len;
- mutex_unlock(&cpr_vreg->cpr_mutex);
- ret = simple_read_from_buffer(buff, count, ppos, debugfs_buf, ret);
- kfree(debugfs_buf);
- return ret;
- }
- static const struct file_operations cpr_debug_info_fops = {
- .open = cpr_debug_info_open,
- .read = cpr_debug_info_read,
- };
- static int cpr_aging_debug_info_open(struct inode *inode, struct file *file)
- {
- file->private_data = inode->i_private;
- return 0;
- }
- static ssize_t cpr_aging_debug_info_read(struct file *file, char __user *buff,
- size_t count, loff_t *ppos)
- {
- struct cpr_regulator *cpr_vreg = file->private_data;
- struct cpr_aging_info *aging_info = cpr_vreg->aging_info;
- char *debugfs_buf;
- ssize_t len, ret = 0;
- int i;
- debugfs_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!debugfs_buf)
- return -ENOMEM;
- mutex_lock(&cpr_vreg->cpr_mutex);
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "aging_adj_volt = [");
- ret += len;
- for (i = CPR_FUSE_CORNER_MIN; i <= cpr_vreg->num_fuse_corners; i++) {
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- " %d", aging_info->voltage_adjust[i]);
- ret += len;
- }
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- " ]uV\n");
- ret += len;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "aging_measurement_done = %s\n",
- aging_info->cpr_aging_done ? "true" : "false");
- ret += len;
- len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
- "aging_measurement_error = %s\n",
- aging_info->cpr_aging_error ? "true" : "false");
- ret += len;
- mutex_unlock(&cpr_vreg->cpr_mutex);
- ret = simple_read_from_buffer(buff, count, ppos, debugfs_buf, ret);
- kfree(debugfs_buf);
- return ret;
- }
- static const struct file_operations cpr_aging_debug_info_fops = {
- .open = cpr_aging_debug_info_open,
- .read = cpr_aging_debug_info_read,
- };
- static void cpr_debugfs_init(struct cpr_regulator *cpr_vreg)
- {
- struct dentry *temp;
- if (IS_ERR_OR_NULL(cpr_debugfs_base)) {
- cpr_err(cpr_vreg, "Could not create debugfs nodes since base directory is missing\n");
- return;
- }
- cpr_vreg->debugfs = debugfs_create_dir(cpr_vreg->rdesc.name,
- cpr_debugfs_base);
- if (IS_ERR_OR_NULL(cpr_vreg->debugfs)) {
- cpr_err(cpr_vreg, "debugfs directory creation failed\n");
- return;
- }
- temp = debugfs_create_file("debug_info", S_IRUGO, cpr_vreg->debugfs,
- cpr_vreg, &cpr_debug_info_fops);
- if (IS_ERR_OR_NULL(temp)) {
- cpr_err(cpr_vreg, "debug_info node creation failed\n");
- return;
- }
- temp = debugfs_create_file("cpr_enable", S_IRUGO | S_IWUSR,
- cpr_vreg->debugfs, cpr_vreg, &cpr_enable_fops);
- if (IS_ERR_OR_NULL(temp)) {
- cpr_err(cpr_vreg, "cpr_enable node creation failed\n");
- return;
- }
- temp = debugfs_create_file("cpr_ceiling", S_IRUGO,
- cpr_vreg->debugfs, cpr_vreg, &cpr_ceiling_fops);
- if (IS_ERR_OR_NULL(temp)) {
- cpr_err(cpr_vreg, "cpr_ceiling node creation failed\n");
- return;
- }
- temp = debugfs_create_file("cpr_floor", S_IRUGO,
- cpr_vreg->debugfs, cpr_vreg, &cpr_floor_fops);
- if (IS_ERR_OR_NULL(temp)) {
- cpr_err(cpr_vreg, "cpr_floor node creation failed\n");
- return;
- }
- temp = debugfs_create_file("cpr_max_ceiling", S_IRUGO,
- cpr_vreg->debugfs, cpr_vreg, &cpr_max_ceiling_fops);
- if (IS_ERR_OR_NULL(temp)) {
- cpr_err(cpr_vreg, "cpr_max_ceiling node creation failed\n");
- return;
- }
- if (cpr_vreg->aging_info) {
- temp = debugfs_create_file("aging_debug_info", S_IRUGO,
- cpr_vreg->debugfs, cpr_vreg,
- &cpr_aging_debug_info_fops);
- if (IS_ERR_OR_NULL(temp)) {
- cpr_err(cpr_vreg, "aging_debug_info node creation failed\n");
- return;
- }
- }
- }
- static void cpr_debugfs_remove(struct cpr_regulator *cpr_vreg)
- {
- debugfs_remove_recursive(cpr_vreg->debugfs);
- }
- static void cpr_debugfs_base_init(void)
- {
- cpr_debugfs_base = debugfs_create_dir("cpr-regulator", NULL);
- if (IS_ERR_OR_NULL(cpr_debugfs_base))
- pr_err("cpr-regulator debugfs base directory creation failed\n");
- }
- static void cpr_debugfs_base_remove(void)
- {
- debugfs_remove_recursive(cpr_debugfs_base);
- }
- #else
- static void cpr_debugfs_init(struct cpr_regulator *cpr_vreg)
- {}
- static void cpr_debugfs_remove(struct cpr_regulator *cpr_vreg)
- {}
- static void cpr_debugfs_base_init(void)
- {}
- static void cpr_debugfs_base_remove(void)
- {}
- #endif
- /**
- * cpr_panic_callback() - panic notification callback function. This function
- * is invoked when a kernel panic occurs.
- * @nfb: Notifier block pointer of CPR regulator
- * @event: Value passed unmodified to notifier function
- * @data: Pointer passed unmodified to notifier function
- *
- * Return: NOTIFY_OK
- */
- static int cpr_panic_callback(struct notifier_block *nfb,
- unsigned long event, void *data)
- {
- struct cpr_regulator *cpr_vreg = container_of(nfb,
- struct cpr_regulator, panic_notifier);
- int corner, fuse_corner, volt;
- corner = cpr_vreg->corner;
- fuse_corner = cpr_vreg->corner_map[corner];
- if (cpr_is_allowed(cpr_vreg))
- volt = cpr_vreg->last_volt[corner];
- else
- volt = cpr_vreg->open_loop_volt[corner];
- cpr_err(cpr_vreg, "[corner:%d, fuse_corner:%d] = %d uV\n",
- corner, fuse_corner, volt);
- return NOTIFY_OK;
- }
- static int cpr_regulator_probe(struct platform_device *pdev)
- {
- struct regulator_config reg_config = {};
- struct cpr_regulator *cpr_vreg;
- struct regulator_desc *rdesc;
- struct device *dev = &pdev->dev;
- struct regulator_init_data *init_data = pdev->dev.platform_data;
- int rc;
- if (!pdev->dev.of_node) {
- dev_err(dev, "Device tree node is missing\n");
- return -EINVAL;
- }
- cpr_vreg = devm_kzalloc(&pdev->dev, sizeof(struct cpr_regulator),
- GFP_KERNEL);
- if (!cpr_vreg)
- return -ENOMEM;
- init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
- &cpr_vreg->rdesc);
- if (!init_data) {
- dev_err(dev, "regulator init data is missing\n");
- return -EINVAL;
- } else {
- init_data->constraints.input_uV
- = init_data->constraints.max_uV;
- init_data->constraints.valid_ops_mask
- |= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
- }
- cpr_vreg->rdesc.name = init_data->constraints.name;
- if (cpr_vreg->rdesc.name == NULL) {
- dev_err(dev, "regulator-name missing\n");
- return -EINVAL;
- }
- rc = cpr_fuse_corner_array_alloc(&pdev->dev, cpr_vreg);
- if (rc)
- return rc;
- rc = cpr_mem_acc_init(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "mem_acc intialization error rc=%d\n", rc);
- return rc;
- }
- rc = cpr_efuse_init(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Wrong eFuse address specified: rc=%d\n", rc);
- return rc;
- }
- rc = cpr_remap_efuse_data(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Could not remap fuse data: rc=%d\n", rc);
- return rc;
- }
- rc = cpr_check_redundant(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Could not check redundant fuse: rc=%d\n",
- rc);
- goto err_out;
- }
- rc = cpr_read_fuse_revision(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Could not read fuse revision: rc=%d\n", rc);
- goto err_out;
- }
- cpr_parse_speed_bin_fuse(cpr_vreg, dev->of_node);
- cpr_parse_pvs_version_fuse(cpr_vreg, dev->of_node);
- rc = cpr_read_ro_select(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Could not read RO select: rc=%d\n", rc);
- goto err_out;
- }
- rc = cpr_find_fuse_map_match(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Could not determine fuse mapping match: rc=%d\n",
- rc);
- goto err_out;
- }
- rc = cpr_voltage_plan_init(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Wrong DT parameter specified: rc=%d\n", rc);
- goto err_out;
- }
- rc = cpr_pvs_init(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Initialize PVS wrong: rc=%d\n", rc);
- goto err_out;
- }
- rc = cpr_vsens_init(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Initialize vsens configuration failed rc=%d\n",
- rc);
- return rc;
- }
- rc = cpr_apc_init(pdev, cpr_vreg);
- if (rc) {
- if (rc != -EPROBE_DEFER)
- cpr_err(cpr_vreg, "Initialize APC wrong: rc=%d\n", rc);
- goto err_out;
- }
- rc = cpr_init_cpr(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Initialize CPR failed: rc=%d\n", rc);
- goto err_out;
- }
- rc = cpr_rpm_apc_init(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "Initialize RPM APC regulator failed rc=%d\n",
- rc);
- return rc;
- }
- if (of_property_read_bool(pdev->dev.of_node,
- "qcom,disable-closed-loop-in-pc")) {
- rc = cpr_init_pm_notification(cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg,
- "cpr_init_pm_notification failed rc=%d\n", rc);
- return rc;
- }
- }
- /* Load per-online CPU adjustment data */
- rc = cpr_init_per_cpu_adjustments(cpr_vreg, &pdev->dev);
- if (rc) {
- cpr_err(cpr_vreg, "cpr_init_per_cpu_adjustments failed: rc=%d\n",
- rc);
- goto err_out;
- }
- /* Parse dependency parameters */
- if (cpr_vreg->vdd_mx) {
- rc = cpr_parse_vdd_mx_parameters(pdev, cpr_vreg);
- if (rc) {
- cpr_err(cpr_vreg, "parsing vdd_mx parameters failed: rc=%d\n",
- rc);
- goto err_out;
- }
- }
- cpr_efuse_free(cpr_vreg);
- /*
- * Ensure that enable state accurately reflects the case in which CPR
- * is permanently disabled.
- */
- cpr_vreg->enable &= !cpr_vreg->cpr_fuse_disable;
- mutex_init(&cpr_vreg->cpr_mutex);
- rdesc = &cpr_vreg->rdesc;
- rdesc->owner = THIS_MODULE;
- rdesc->type = REGULATOR_VOLTAGE;
- rdesc->ops = &cpr_corner_ops;
- reg_config.dev = &pdev->dev;
- reg_config.init_data = init_data;
- reg_config.driver_data = cpr_vreg;
- reg_config.of_node = pdev->dev.of_node;
- cpr_vreg->rdev = regulator_register(rdesc, ®_config);
- if (IS_ERR(cpr_vreg->rdev)) {
- rc = PTR_ERR(cpr_vreg->rdev);
- cpr_err(cpr_vreg, "regulator_register failed: rc=%d\n", rc);
- cpr_apc_exit(cpr_vreg);
- return rc;
- }
- platform_set_drvdata(pdev, cpr_vreg);
- cpr_debugfs_init(cpr_vreg);
- /* Register panic notification call back */
- cpr_vreg->panic_notifier.notifier_call = cpr_panic_callback;
- atomic_notifier_chain_register(&panic_notifier_list,
- &cpr_vreg->panic_notifier);
- mutex_lock(&cpr_regulator_list_mutex);
- list_add(&cpr_vreg->list, &cpr_regulator_list);
- mutex_unlock(&cpr_regulator_list_mutex);
- return 0;
- err_out:
- cpr_efuse_free(cpr_vreg);
- return rc;
- }
- static int cpr_regulator_remove(struct platform_device *pdev)
- {
- struct cpr_regulator *cpr_vreg;
- cpr_vreg = platform_get_drvdata(pdev);
- if (cpr_vreg) {
- /* Disable CPR */
- if (cpr_is_allowed(cpr_vreg)) {
- cpr_ctl_disable(cpr_vreg);
- cpr_irq_set(cpr_vreg, 0);
- }
- mutex_lock(&cpr_regulator_list_mutex);
- list_del(&cpr_vreg->list);
- mutex_unlock(&cpr_regulator_list_mutex);
- if (cpr_vreg->cpu_notifier.notifier_call)
- unregister_hotcpu_notifier(&cpr_vreg->cpu_notifier);
- atomic_notifier_chain_unregister(&panic_notifier_list,
- &cpr_vreg->panic_notifier);
- cpr_apc_exit(cpr_vreg);
- cpr_debugfs_remove(cpr_vreg);
- regulator_unregister(cpr_vreg->rdev);
- }
- return 0;
- }
- static struct of_device_id cpr_regulator_match_table[] = {
- { .compatible = CPR_REGULATOR_DRIVER_NAME, },
- {}
- };
- static struct platform_driver cpr_regulator_driver = {
- .driver = {
- .name = CPR_REGULATOR_DRIVER_NAME,
- .of_match_table = cpr_regulator_match_table,
- .owner = THIS_MODULE,
- },
- .probe = cpr_regulator_probe,
- .remove = cpr_regulator_remove,
- .suspend = cpr_regulator_suspend,
- .resume = cpr_regulator_resume,
- };
- /**
- * cpr_regulator_init() - register cpr-regulator driver
- *
- * This initialization function should be called in systems in which driver
- * registration ordering must be controlled precisely.
- */
- int __init cpr_regulator_init(void)
- {
- static bool initialized;
- if (initialized)
- return 0;
- else
- initialized = true;
- cpr_debugfs_base_init();
- return platform_driver_register(&cpr_regulator_driver);
- }
- EXPORT_SYMBOL(cpr_regulator_init);
- static void __exit cpr_regulator_exit(void)
- {
- platform_driver_unregister(&cpr_regulator_driver);
- cpr_debugfs_base_remove();
- }
- MODULE_DESCRIPTION("CPR regulator driver");
- MODULE_LICENSE("GPL v2");
- arch_initcall(cpr_regulator_init);
- module_exit(cpr_regulator_exit);
|