123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079/*
 * Copyright 2013 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include <drm/drmP.h>
#include "amdgpu.h"
#include "amdgpu_pm.h"
#include "amdgpu_dpm.h"
#include "amdgpu_atombios.h"
#include "amd_pcie.h"
#include "sid.h"
#include "r600_dpm.h"
#include "si_dpm.h"
#include "atom.h"
#include "../include/pptable.h"
#include <linux/math64.h>
#include <linux/seq_file.h>
#include <linux/firmware.h>

#define MC_CG_ARB_FREQ_F0           0x0a
#define MC_CG_ARB_FREQ_F1           0x0b
#define MC_CG_ARB_FREQ_F2           0x0c
#define MC_CG_ARB_FREQ_F3           0x0d

#define SMC_RAM_END                 0x20000

#define SCLK_MIN_DEEPSLEEP_FREQ     1350


/* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22

#define BIOS_SCRATCH_4                                    0x5cd

MODULE_FIRMWARE("radeon/tahiti_smc.bin");
MODULE_FIRMWARE("radeon/pitcairn_smc.bin");
MODULE_FIRMWARE("radeon/pitcairn_k_smc.bin");
MODULE_FIRMWARE("radeon/verde_smc.bin");
MODULE_FIRMWARE("radeon/verde_k_smc.bin");
MODULE_FIRMWARE("radeon/oland_smc.bin");
MODULE_FIRMWARE("radeon/oland_k_smc.bin");
MODULE_FIRMWARE("radeon/hainan_smc.bin");
MODULE_FIRMWARE("radeon/hainan_k_smc.bin");
MODULE_FIRMWARE("radeon/banks_k_2_smc.bin");

static const struct amd_pm_funcs si_dpm_funcs;

union power_info {
	struct _ATOM_POWERPLAY_INFO info;
	struct _ATOM_POWERPLAY_INFO_V2 info_2;
	struct _ATOM_POWERPLAY_INFO_V3 info_3;
	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
	struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
	struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
};

union fan_info {
	struct _ATOM_PPLIB_FANTABLE fan;
	struct _ATOM_PPLIB_FANTABLE2 fan2;
	struct _ATOM_PPLIB_FANTABLE3 fan3;
};

union pplib_clock_info {
	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
	struct _ATOM_PPLIB_SI_CLOCK_INFO si;
};

static const u32 r600_utc[R600_PM_NUMBER_OF_TC] =
{
	R600_UTC_DFLT_00,
	R600_UTC_DFLT_01,
	R600_UTC_DFLT_02,
	R600_UTC_DFLT_03,
	R600_UTC_DFLT_04,
	R600_UTC_DFLT_05,
	R600_UTC_DFLT_06,
	R600_UTC_DFLT_07,
	R600_UTC_DFLT_08,
	R600_UTC_DFLT_09,
	R600_UTC_DFLT_10,
	R600_UTC_DFLT_11,
	R600_UTC_DFLT_12,
	R600_UTC_DFLT_13,
	R600_UTC_DFLT_14,
};

static const u32 r600_dtc[R600_PM_NUMBER_OF_TC] =
{
	R600_DTC_DFLT_00,
	R600_DTC_DFLT_01,
	R600_DTC_DFLT_02,
	R600_DTC_DFLT_03,
	R600_DTC_DFLT_04,
	R600_DTC_DFLT_05,
	R600_DTC_DFLT_06,
	R600_DTC_DFLT_07,
	R600_DTC_DFLT_08,
	R600_DTC_DFLT_09,
	R600_DTC_DFLT_10,
	R600_DTC_DFLT_11,
	R600_DTC_DFLT_12,
	R600_DTC_DFLT_13,
	R600_DTC_DFLT_14,
};

static const struct si_cac_config_reg cac_weights_tahiti[] =
{
	{ 0x0, 0x0000ffff, 0, 0xc, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x101, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0xc, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x8fc, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x95, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x34e, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x1a1, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0xda, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x46, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x208, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0xe7, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x948, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x167, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x31, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x18e, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg lcac_tahiti[] =
{
	{ 0x143, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x146, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x149, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0x149, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x14c, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0x14c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x9e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x9e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x101, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x101, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x10a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x10d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8f, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x92, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x92, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x95, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x95, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x152, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x155, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x155, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x158, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x158, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x113, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x116, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x116, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x119, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
	{ 0x119, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x122, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x122, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x125, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x125, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x128, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x128, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x12b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x12b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }

};

static const struct si_cac_config_reg cac_override_tahiti[] =
{
	{ 0xFFFFFFFF }
};

static const struct si_powertune_data powertune_data_tahiti =
{
	((1 << 16) | 27027),
	6,
	0,
	4,
	95,
	{
		0UL,
		0UL,
		4521550UL,
		309631529UL,
		-1270850L,
		4513710L,
		40
	},
	595000000UL,
	12,
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	},
	true
};

static const struct si_dte_data dte_data_tahiti =
{
	{ 1159409, 0, 0, 0, 0 },
	{ 777, 0, 0, 0, 0 },
	2,
	54000,
	127000,
	25,
	2,
	10,
	13,
	{ 27, 31, 35, 39, 43, 47, 54, 61, 67, 74, 81, 88, 95, 0, 0, 0 },
	{ 240888759, 221057860, 235370597, 162287531, 158510299, 131423027, 116673180, 103067515, 87941937, 76209048, 68209175, 64090048, 58301890, 0, 0, 0 },
	{ 12024, 11189, 11451, 8411, 7939, 6666, 5681, 4905, 4241, 3720, 3354, 3122, 2890, 0, 0, 0 },
	85,
	false
};

#if 0
static const struct si_dte_data dte_data_tahiti_le =
{
	{ 0x1E8480, 0x7A1200, 0x2160EC0, 0x3938700, 0 },
	{ 0x7D, 0x7D, 0x4E4, 0xB00, 0 },
	0x5,
	0xAFC8,
	0x64,
	0x32,
	1,
	0,
	0x10,
	{ 0x78, 0x7C, 0x82, 0x88, 0x8E, 0x94, 0x9A, 0xA0, 0xA6, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, 0xC0, 0xC4 },
	{ 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700 },
	{ 0x2AF8, 0x2AF8, 0x29BB, 0x27F9, 0x2637, 0x2475, 0x22B3, 0x20F1, 0x1F2F, 0x1D6D, 0x1734, 0x1414, 0x10F4, 0xDD4, 0xAB4, 0x794 },
	85,
	true
};
#endif

static const struct si_dte_data dte_data_tahiti_pro =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0 },
	5,
	45000,
	100,
	0xA,
	1,
	0,
	0x10,
	{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0x7D0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_dte_data dte_data_new_zealand =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0 },
	{ 0x29B, 0x3E9, 0x537, 0x7D2, 0 },
	0x5,
	0xAFC8,
	0x69,
	0x32,
	1,
	0,
	0x10,
	{ 0x82, 0xA0, 0xB4, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0xDAC, 0x1388, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685 },
	85,
	true
};

static const struct si_dte_data dte_data_aruba_pro =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0 },
	5,
	45000,
	100,
	0xA,
	1,
	0,
	0x10,
	{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_dte_data dte_data_malta =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0 },
	5,
	45000,
	100,
	0xA,
	1,
	0,
	0x10,
	{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_cac_config_reg cac_weights_pitcairn[] =
{
	{ 0x0, 0x0000ffff, 0, 0x8a, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x24d, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x19, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0xc11, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0x7f3, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x403, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x367, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x4c9, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x45d, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0x36d, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x534, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x5da, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x880, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0x201, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x9f, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x1f, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x5de, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x7b, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x13, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0xf9, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x66, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x13, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x186, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg lcac_pitcairn[] =
{
	{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x113, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x152, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x146, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x9e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x9e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x10a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x116, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x116, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x155, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x155, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x92, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x92, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x149, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x149, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x101, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x101, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x10d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x119, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x119, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x158, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x158, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x95, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x95, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x14c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x14c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x122, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x122, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x125, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x125, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x128, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x128, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x12b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x12b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_override_pitcairn[] =
{
    { 0xFFFFFFFF }
};

static const struct si_powertune_data powertune_data_pitcairn =
{
	((1 << 16) | 27027),
	5,
	0,
	6,
	100,
	{
		51600000UL,
		1800000UL,
		7194395UL,
		309631529UL,
		-1270850L,
		4513710L,
		100
	},
	117830498UL,
	12,
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	},
	true
};

static const struct si_dte_data dte_data_pitcairn =
{
	{ 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0 },
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	0,
	false
};

static const struct si_dte_data dte_data_curacao_xt =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0 },
	5,
	45000,
	100,
	0xA,
	1,
	0,
	0x10,
	{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0x1D17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_dte_data dte_data_curacao_pro =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0 },
	5,
	45000,
	100,
	0xA,
	1,
	0,
	0x10,
	{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0x1D17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_dte_data dte_data_neptune_xt =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0 },
	5,
	45000,
	100,
	0xA,
	1,
	0,
	0x10,
	{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0x3A2F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_cac_config_reg cac_weights_chelsea_pro[] =
{
	{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x2BD, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_weights_chelsea_xt[] =
{
	{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x30A, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_weights_heathrow[] =
{
	{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x362, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_weights_cape_verde_pro[] =
{
	{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x315, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_weights_cape_verde[] =
{
	{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x3BA, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg lcac_cape_verde[] =
{
	{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x113, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x152, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x146, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_override_cape_verde[] =
{
    { 0xFFFFFFFF }
};

static const struct si_powertune_data powertune_data_cape_verde =
{
	((1 << 16) | 0x6993),
	5,
	0,
	7,
	105,
	{
		0UL,
		0UL,
		7194395UL,
		309631529UL,
		-1270850L,
		4513710L,
		100
	},
	117830498UL,
	12,
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	},
	true
};

static const struct si_dte_data dte_data_cape_verde =
{
	{ 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0 },
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	0,
	false
};

static const struct si_dte_data dte_data_venus_xtx =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x71C, 0xAAB, 0xE39, 0x11C7, 0x0 },
	5,
	55000,
	0x69,
	0xA,
	1,
	0,
	0x3,
	{ 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	{ 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	{ 0xD6D8, 0x88B8, 0x1555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_dte_data dte_data_venus_xt =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0xBDA, 0x11C7, 0x17B4, 0x1DA1, 0x0 },
	5,
	55000,
	0x69,
	0xA,
	1,
	0,
	0x3,
	{ 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	{ 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	{ 0xAFC8, 0x88B8, 0x238E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_dte_data dte_data_venus_pro =
{
	{  0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x11C7, 0x1AAB, 0x238E, 0x2C72, 0x0 },
	5,
	55000,
	0x69,
	0xA,
	1,
	0,
	0x3,
	{ 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	{ 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	{ 0x88B8, 0x88B8, 0x3555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_cac_config_reg cac_weights_oland[] =
{
	{ 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x3BA, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_weights_mars_pro[] =
{
	{ 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_weights_mars_xt[] =
{
	{ 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x60, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_weights_oland_pro[] =
{
	{ 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x90, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_weights_oland_xt[] =
{
	{ 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x120, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg lcac_oland[] =
{
	{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg lcac_mars_pro[] =
{
	{ 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
	{ 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
	{ 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_cac_config_reg cac_override_oland[] =
{
	{ 0xFFFFFFFF }
};

static const struct si_powertune_data powertune_data_oland =
{
	((1 << 16) | 0x6993),
	5,
	0,
	7,
	105,
	{
		0UL,
		0UL,
		7194395UL,
		309631529UL,
		-1270850L,
		4513710L,
		100
	},
	117830498UL,
	12,
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	},
	true
};

static const struct si_powertune_data powertune_data_mars_pro =
{
	((1 << 16) | 0x6993),
	5,
	0,
	7,
	105,
	{
		0UL,
		0UL,
		7194395UL,
		309631529UL,
		-1270850L,
		4513710L,
		100
	},
	117830498UL,
	12,
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	},
	true
};

static const struct si_dte_data dte_data_oland =
{
	{ 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0 },
	0,
	0,
	0,
	0,
	0,
	0,
	0,
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	0,
	false
};

static const struct si_dte_data dte_data_mars_pro =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0 },
	5,
	55000,
	105,
	0xA,
	1,
	0,
	0x10,
	{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0xF627, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};

static const struct si_dte_data dte_data_sun_xt =
{
	{ 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
	{ 0x0, 0x0, 0x0, 0x0, 0x0 },
	5,
	55000,
	105,
	0xA,
	1,
	0,
	0x10,
	{ 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
	{ 0xD555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
	90,
	true
};


static const struct si_cac_config_reg cac_weights_hainan[] =
{
	{ 0x0, 0x0000ffff, 0, 0x2d9, SISLANDS_CACCONFIG_CGIND },
	{ 0x0, 0xffff0000, 16, 0x22b, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0x0000ffff, 0, 0x21c, SISLANDS_CACCONFIG_CGIND },
	{ 0x1, 0xffff0000, 16, 0x1dc, SISLANDS_CACCONFIG_CGIND },
	{ 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0x0000ffff, 0, 0x24e, SISLANDS_CACCONFIG_CGIND },
	{ 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0x0000ffff, 0, 0x35e, SISLANDS_CACCONFIG_CGIND },
	{ 0x5, 0xffff0000, 16, 0x1143, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0x0000ffff, 0, 0xe17, SISLANDS_CACCONFIG_CGIND },
	{ 0x6, 0xffff0000, 16, 0x441, SISLANDS_CACCONFIG_CGIND },
	{ 0x18f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0x0000ffff, 0, 0x28b, SISLANDS_CACCONFIG_CGIND },
	{ 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x8, 0xffff0000, 16, 0xabe, SISLANDS_CACCONFIG_CGIND },
	{ 0x9, 0x0000ffff, 0, 0xf11, SISLANDS_CACCONFIG_CGIND },
	{ 0xa, 0x0000ffff, 0, 0x907, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0x0000ffff, 0, 0xb45, SISLANDS_CACCONFIG_CGIND },
	{ 0xb, 0xffff0000, 16, 0xd1e, SISLANDS_CACCONFIG_CGIND },
	{ 0xc, 0x0000ffff, 0, 0xa2c, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0x0000ffff, 0, 0x62, SISLANDS_CACCONFIG_CGIND },
	{ 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0xe, 0x0000ffff, 0, 0x1f3, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0x0000ffff, 0, 0x42, SISLANDS_CACCONFIG_CGIND },
	{ 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0x0000ffff, 0, 0x709, SISLANDS_CACCONFIG_CGIND },
	{ 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x12, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x13, 0xffff0000, 16, 0x3a, SISLANDS_CACCONFIG_CGIND },
	{ 0x14, 0x0000ffff, 0, 0x357, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0x0000ffff, 0, 0x9f, SISLANDS_CACCONFIG_CGIND },
	{ 0x15, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0x0000ffff, 0, 0x314, SISLANDS_CACCONFIG_CGIND },
	{ 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x17, 0x0000ffff, 0, 0x6d, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
	{ 0x6d, 0x0000ffff, 0, 0x1b9, SISLANDS_CACCONFIG_CGIND },
	{ 0xFFFFFFFF }
};

static const struct si_powertune_data powertune_data_hainan =
{
	((1 << 16) | 0x6993),
	5,
	0,
	9,
	105,
	{
		0UL,
		0UL,
		7194395UL,
		309631529UL,
		-1270850L,
		4513710L,
		100
	},
	117830498UL,
	12,
	{
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	},
	true
};

static struct rv7xx_power_info *rv770_get_pi(struct amdgpu_device *adev);
static struct evergreen_power_info *evergreen_get_pi(struct amdgpu_device *adev);
static struct ni_power_info *ni_get_pi(struct amdgpu_device *adev);
static struct  si_ps *si_get_ps(struct amdgpu_ps *rps);

static int si_populate_voltage_value(struct amdgpu_device *adev,
				     const struct atom_voltage_table *table,
				     u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage);
static int si_get_std_voltage_value(struct amdgpu_device *adev,
				    SISLANDS_SMC_VOLTAGE_VALUE *voltage,
				    u16 *std_voltage);
static int si_write_smc_soft_register(struct amdgpu_device *adev,
				      u16 reg_offset, u32 value);
static int si_convert_power_level_to_smc(struct amdgpu_device *adev,
					 struct rv7xx_pl *pl,
					 SISLANDS_SMC_HW_PERFORMANCE_LEVEL *level);
static int si_calculate_sclk_params(struct amdgpu_device *adev,
				    u32 engine_clock,
				    SISLANDS_SMC_SCLK_VALUE *sclk);

static void si_thermal_start_smc_fan_control(struct amdgpu_device *adev);
static void si_fan_ctrl_set_default_mode(struct amdgpu_device *adev);
static void si_dpm_set_irq_funcs(struct amdgpu_device *adev);

static struct si_power_info *si_get_pi(struct amdgpu_device *adev)
{
	struct si_power_info *pi = adev->pm.dpm.priv;
	return pi;
}

static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coeffients *coeff,
						     u16 v, s32 t, u32 ileakage, u32 *leakage)
{
	s64 kt, kv, leakage_w, i_leakage, vddc;
	s64 temperature, t_slope, t_intercept, av, bv, t_ref;
	s64 tmp;

	i_leakage = div64_s64(drm_int2fixp(ileakage), 100);
	vddc = div64_s64(drm_int2fixp(v), 1000);
	temperature = div64_s64(drm_int2fixp(t), 1000);

	t_slope = div64_s64(drm_int2fixp(coeff->t_slope), 100000000);
	t_intercept = div64_s64(drm_int2fixp(coeff->t_intercept), 100000000);
	av = div64_s64(drm_int2fixp(coeff->av), 100000000);
	bv = div64_s64(drm_int2fixp(coeff->bv), 100000000);
	t_ref = drm_int2fixp(coeff->t_ref);

	tmp = drm_fixp_mul(t_slope, vddc) + t_intercept;
	kt = drm_fixp_exp(drm_fixp_mul(tmp, temperature));
	kt = drm_fixp_div(kt, drm_fixp_exp(drm_fixp_mul(tmp, t_ref)));
	kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc)));

	leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);

	*leakage = drm_fixp2int(leakage_w * 1000);
}

static void si_calculate_leakage_for_v_and_t(struct amdgpu_device *adev,
					     const struct ni_leakage_coeffients *coeff,
					     u16 v,
					     s32 t,
					     u32 i_leakage,
					     u32 *leakage)
{
	si_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage);
}

static void si_calculate_leakage_for_v_formula(const struct ni_leakage_coeffients *coeff,
					       const u32 fixed_kt, u16 v,
					       u32 ileakage, u32 *leakage)
{
	s64 kt, kv, leakage_w, i_leakage, vddc;

	i_leakage = div64_s64(drm_int2fixp(ileakage), 100);
	vddc = div64_s64(drm_int2fixp(v), 1000);

	kt = div64_s64(drm_int2fixp(fixed_kt), 100000000);
	kv = drm_fixp_mul(div64_s64(drm_int2fixp(coeff->av), 100000000),
			  drm_fixp_exp(drm_fixp_mul(div64_s64(drm_int2fixp(coeff->bv), 100000000), vddc)));

	leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);

	*leakage = drm_fixp2int(leakage_w * 1000);
}

static void si_calculate_leakage_for_v(struct amdgpu_device *adev,
				       const struct ni_leakage_coeffients *coeff,
				       const u32 fixed_kt,
				       u16 v,
				       u32 i_leakage,
				       u32 *leakage)
{
	si_calculate_leakage_for_v_formula(coeff, fixed_kt, v, i_leakage, leakage);
}


static void si_update_dte_from_pl2(struct amdgpu_device *adev,
				   struct si_dte_data *dte_data)
{
	u32 p_limit1 = adev->pm.dpm.tdp_limit;
	u32 p_limit2 = adev->pm.dpm.near_tdp_limit;
	u32 k = dte_data->k;
	u32 t_max = dte_data->max_t;
	u32 t_split[5] = { 10, 15, 20, 25, 30 };
	u32 t_0 = dte_data->t0;
	u32 i;

	if (p_limit2 != 0 && p_limit2 <= p_limit1) {
		dte_data->tdep_count = 3;

		for (i = 0; i < k; i++) {
			dte_data->r[i] =
				(t_split[i] * (t_max - t_0/(u32)1000) * (1 << 14)) /
				(p_limit2  * (u32)100);
		}

		dte_data->tdep_r[1] = dte_data->r[4] * 2;

		for (i = 2; i < SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE; i++) {
			dte_data->tdep_r[i] = dte_data->r[4];
		}
	} else {
		DRM_ERROR("Invalid PL2! DTE will not be updated.\n");
	}
}

static struct rv7xx_power_info *rv770_get_pi(struct amdgpu_device *adev)
{
	struct rv7xx_power_info *pi = adev->pm.dpm.priv;

	return pi;
}

static struct ni_power_info *ni_get_pi(struct amdgpu_device *adev)
{
	struct ni_power_info *pi = adev->pm.dpm.priv;

	return pi;
}

static struct si_ps *si_get_ps(struct amdgpu_ps *aps)
{
	struct  si_ps *ps = aps->ps_priv;

	return ps;
}

static void si_initialize_powertune_defaults(struct amdgpu_device *adev)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	bool update_dte_from_pl2 = false;

	if (adev->asic_type == CHIP_TAHITI) {
		si_pi->cac_weights = cac_weights_tahiti;
		si_pi->lcac_config = lcac_tahiti;
		si_pi->cac_override = cac_override_tahiti;
		si_pi->powertune_data = &powertune_data_tahiti;
		si_pi->dte_data = dte_data_tahiti;

		switch (adev->pdev->device) {
		case 0x6798:
			si_pi->dte_data.enable_dte_by_default = true;
			break;
		case 0x6799:
			si_pi->dte_data = dte_data_new_zealand;
			break;
		case 0x6790:
		case 0x6791:
		case 0x6792:
		case 0x679E:
			si_pi->dte_data = dte_data_aruba_pro;
			update_dte_from_pl2 = true;
			break;
		case 0x679B:
			si_pi->dte_data = dte_data_malta;
			update_dte_from_pl2 = true;
			break;
		case 0x679A:
			si_pi->dte_data = dte_data_tahiti_pro;
			update_dte_from_pl2 = true;
			break;
		default:
			if (si_pi->dte_data.enable_dte_by_default == true)
				DRM_ERROR("DTE is not enabled!\n");
			break;
		}
	} else if (adev->asic_type == CHIP_PITCAIRN) {
		si_pi->cac_weights = cac_weights_pitcairn;
		si_pi->lcac_config = lcac_pitcairn;
		si_pi->cac_override = cac_override_pitcairn;
		si_pi->powertune_data = &powertune_data_pitcairn;

		switch (adev->pdev->device) {
		case 0x6810:
		case 0x6818:
			si_pi->dte_data = dte_data_curacao_xt;
			update_dte_from_pl2 = true;
			break;
		case 0x6819:
		case 0x6811:
			si_pi->dte_data = dte_data_curacao_pro;
			update_dte_from_pl2 = true;
			break;
		case 0x6800:
		case 0x6806:
			si_pi->dte_data = dte_data_neptune_xt;
			update_dte_from_pl2 = true;
			break;
		default:
			si_pi->dte_data = dte_data_pitcairn;
			break;
		}
	} else if (adev->asic_type == CHIP_VERDE) {
		si_pi->lcac_config = lcac_cape_verde;
		si_pi->cac_override = cac_override_cape_verde;
		si_pi->powertune_data = &powertune_data_cape_verde;

		switch (adev->pdev->device) {
		case 0x683B:
		case 0x683F:
		case 0x6829:
		case 0x6835:
			si_pi->cac_weights = cac_weights_cape_verde_pro;
			si_pi->dte_data = dte_data_cape_verde;
			break;
		case 0x682C:
			si_pi->cac_weights = cac_weights_cape_verde_pro;
			si_pi->dte_data = dte_data_sun_xt;
			update_dte_from_pl2 = true;
			break;
		case 0x6825:
		case 0x6827:
			si_pi->cac_weights = cac_weights_heathrow;
			si_pi->dte_data = dte_data_cape_verde;
			break;
		case 0x6824:
		case 0x682D:
			si_pi->cac_weights = cac_weights_chelsea_xt;
			si_pi->dte_data = dte_data_cape_verde;
			break;
		case 0x682F:
			si_pi->cac_weights = cac_weights_chelsea_pro;
			si_pi->dte_data = dte_data_cape_verde;
			break;
		case 0x6820:
			si_pi->cac_weights = cac_weights_heathrow;
			si_pi->dte_data = dte_data_venus_xtx;
			break;
		case 0x6821:
			si_pi->cac_weights = cac_weights_heathrow;
			si_pi->dte_data = dte_data_venus_xt;
			break;
		case 0x6823:
		case 0x682B:
		case 0x6822:
		case 0x682A:
			si_pi->cac_weights = cac_weights_chelsea_pro;
			si_pi->dte_data = dte_data_venus_pro;
			break;
		default:
			si_pi->cac_weights = cac_weights_cape_verde;
			si_pi->dte_data = dte_data_cape_verde;
			break;
		}
	} else if (adev->asic_type == CHIP_OLAND) {
		si_pi->lcac_config = lcac_mars_pro;
		si_pi->cac_override = cac_override_oland;
		si_pi->powertune_data = &powertune_data_mars_pro;
		si_pi->dte_data = dte_data_mars_pro;

		switch (adev->pdev->device) {
		case 0x6601:
		case 0x6621:
		case 0x6603:
		case 0x6605:
			si_pi->cac_weights = cac_weights_mars_pro;
			update_dte_from_pl2 = true;
			break;
		case 0x6600:
		case 0x6606:
		case 0x6620:
		case 0x6604:
			si_pi->cac_weights = cac_weights_mars_xt;
			update_dte_from_pl2 = true;
			break;
		case 0x6611:
		case 0x6613:
		case 0x6608:
			si_pi->cac_weights = cac_weights_oland_pro;
			update_dte_from_pl2 = true;
			break;
		case 0x6610:
			si_pi->cac_weights = cac_weights_oland_xt;
			update_dte_from_pl2 = true;
			break;
		default:
			si_pi->cac_weights = cac_weights_oland;
			si_pi->lcac_config = lcac_oland;
			si_pi->cac_override = cac_override_oland;
			si_pi->powertune_data = &powertune_data_oland;
			si_pi->dte_data = dte_data_oland;
			break;
		}
	} else if (adev->asic_type == CHIP_HAINAN) {
		si_pi->cac_weights = cac_weights_hainan;
		si_pi->lcac_config = lcac_oland;
		si_pi->cac_override = cac_override_oland;
		si_pi->powertune_data = &powertune_data_hainan;
		si_pi->dte_data = dte_data_sun_xt;
		update_dte_from_pl2 = true;
	} else {
		DRM_ERROR("Unknown SI asic revision, failed to initialize PowerTune!\n");
		return;
	}

	ni_pi->enable_power_containment = false;
	ni_pi->enable_cac = false;
	ni_pi->enable_sq_ramping = false;
	si_pi->enable_dte = false;

	if (si_pi->powertune_data->enable_powertune_by_default) {
		ni_pi->enable_power_containment = true;
		ni_pi->enable_cac = true;
		if (si_pi->dte_data.enable_dte_by_default) {
			si_pi->enable_dte = true;
			if (update_dte_from_pl2)
				si_update_dte_from_pl2(adev, &si_pi->dte_data);

		}
		ni_pi->enable_sq_ramping = true;
	}

	ni_pi->driver_calculate_cac_leakage = true;
	ni_pi->cac_configuration_required = true;

	if (ni_pi->cac_configuration_required) {
		ni_pi->support_cac_long_term_average = true;
		si_pi->dyn_powertune_data.l2_lta_window_size =
			si_pi->powertune_data->l2_lta_window_size_default;
		si_pi->dyn_powertune_data.lts_truncate =
			si_pi->powertune_data->lts_truncate_default;
	} else {
		ni_pi->support_cac_long_term_average = false;
		si_pi->dyn_powertune_data.l2_lta_window_size = 0;
		si_pi->dyn_powertune_data.lts_truncate = 0;
	}

	si_pi->dyn_powertune_data.disable_uvd_powertune = false;
}

static u32 si_get_smc_power_scaling_factor(struct amdgpu_device *adev)
{
	return 1;
}

static u32 si_calculate_cac_wintime(struct amdgpu_device *adev)
{
	u32 xclk;
	u32 wintime;
	u32 cac_window;
	u32 cac_window_size;

	xclk = amdgpu_asic_get_xclk(adev);

	if (xclk == 0)
		return 0;

	cac_window = RREG32(CG_CAC_CTRL) & CAC_WINDOW_MASK;
	cac_window_size = ((cac_window & 0xFFFF0000) >> 16) * (cac_window & 0x0000FFFF);

	wintime = (cac_window_size * 100) / xclk;

	return wintime;
}

static u32 si_scale_power_for_smc(u32 power_in_watts, u32 scaling_factor)
{
	return power_in_watts;
}

static int si_calculate_adjusted_tdp_limits(struct amdgpu_device *adev,
					    bool adjust_polarity,
					    u32 tdp_adjustment,
					    u32 *tdp_limit,
					    u32 *near_tdp_limit)
{
	u32 adjustment_delta, max_tdp_limit;

	if (tdp_adjustment > (u32)adev->pm.dpm.tdp_od_limit)
		return -EINVAL;

	max_tdp_limit = ((100 + 100) * adev->pm.dpm.tdp_limit) / 100;

	if (adjust_polarity) {
		*tdp_limit = ((100 + tdp_adjustment) * adev->pm.dpm.tdp_limit) / 100;
		*near_tdp_limit = adev->pm.dpm.near_tdp_limit_adjusted + (*tdp_limit - adev->pm.dpm.tdp_limit);
	} else {
		*tdp_limit = ((100 - tdp_adjustment) * adev->pm.dpm.tdp_limit) / 100;
		adjustment_delta  = adev->pm.dpm.tdp_limit - *tdp_limit;
		if (adjustment_delta < adev->pm.dpm.near_tdp_limit_adjusted)
			*near_tdp_limit = adev->pm.dpm.near_tdp_limit_adjusted - adjustment_delta;
		else
			*near_tdp_limit = 0;
	}

	if ((*tdp_limit <= 0) || (*tdp_limit > max_tdp_limit))
		return -EINVAL;
	if ((*near_tdp_limit <= 0) || (*near_tdp_limit > *tdp_limit))
		return -EINVAL;

	return 0;
}

static int si_populate_smc_tdp_limits(struct amdgpu_device *adev,
				      struct amdgpu_ps *amdgpu_state)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);

	if (ni_pi->enable_power_containment) {
		SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable;
		PP_SIslands_PAPMParameters *papm_parm;
		struct amdgpu_ppm_table *ppm = adev->pm.dpm.dyn_state.ppm_table;
		u32 scaling_factor = si_get_smc_power_scaling_factor(adev);
		u32 tdp_limit;
		u32 near_tdp_limit;
		int ret;

		if (scaling_factor == 0)
			return -EINVAL;

		memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE));

		ret = si_calculate_adjusted_tdp_limits(adev,
						       false, /* ??? */
						       adev->pm.dpm.tdp_adjustment,
						       &tdp_limit,
						       &near_tdp_limit);
		if (ret)
			return ret;

		smc_table->dpm2Params.TDPLimit =
			cpu_to_be32(si_scale_power_for_smc(tdp_limit, scaling_factor) * 1000);
		smc_table->dpm2Params.NearTDPLimit =
			cpu_to_be32(si_scale_power_for_smc(near_tdp_limit, scaling_factor) * 1000);
		smc_table->dpm2Params.SafePowerLimit =
			cpu_to_be32(si_scale_power_for_smc((near_tdp_limit * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000);

		ret = amdgpu_si_copy_bytes_to_smc(adev,
						  (si_pi->state_table_start + offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) +
						   offsetof(PP_SIslands_DPM2Parameters, TDPLimit)),
						  (u8 *)(&(smc_table->dpm2Params.TDPLimit)),
						  sizeof(u32) * 3,
						  si_pi->sram_end);
		if (ret)
			return ret;

		if (si_pi->enable_ppm) {
			papm_parm = &si_pi->papm_parm;
			memset(papm_parm, 0, sizeof(PP_SIslands_PAPMParameters));
			papm_parm->NearTDPLimitTherm = cpu_to_be32(ppm->dgpu_tdp);
			papm_parm->dGPU_T_Limit = cpu_to_be32(ppm->tj_max);
			papm_parm->dGPU_T_Warning = cpu_to_be32(95);
			papm_parm->dGPU_T_Hysteresis = cpu_to_be32(5);
			papm_parm->PlatformPowerLimit = 0xffffffff;
			papm_parm->NearTDPLimitPAPM = 0xffffffff;

			ret = amdgpu_si_copy_bytes_to_smc(adev, si_pi->papm_cfg_table_start,
							  (u8 *)papm_parm,
							  sizeof(PP_SIslands_PAPMParameters),
							  si_pi->sram_end);
			if (ret)
				return ret;
		}
	}
	return 0;
}

static int si_populate_smc_tdp_limits_2(struct amdgpu_device *adev,
					struct amdgpu_ps *amdgpu_state)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);

	if (ni_pi->enable_power_containment) {
		SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable;
		u32 scaling_factor = si_get_smc_power_scaling_factor(adev);
		int ret;

		memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE));

		smc_table->dpm2Params.NearTDPLimit =
			cpu_to_be32(si_scale_power_for_smc(adev->pm.dpm.near_tdp_limit_adjusted, scaling_factor) * 1000);
		smc_table->dpm2Params.SafePowerLimit =
			cpu_to_be32(si_scale_power_for_smc((adev->pm.dpm.near_tdp_limit_adjusted * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000);

		ret = amdgpu_si_copy_bytes_to_smc(adev,
						  (si_pi->state_table_start +
						   offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) +
						   offsetof(PP_SIslands_DPM2Parameters, NearTDPLimit)),
						  (u8 *)(&(smc_table->dpm2Params.NearTDPLimit)),
						  sizeof(u32) * 2,
						  si_pi->sram_end);
		if (ret)
			return ret;
	}

	return 0;
}

static u16 si_calculate_power_efficiency_ratio(struct amdgpu_device *adev,
					       const u16 prev_std_vddc,
					       const u16 curr_std_vddc)
{
	u64 margin = (u64)SISLANDS_DPM2_PWREFFICIENCYRATIO_MARGIN;
	u64 prev_vddc = (u64)prev_std_vddc;
	u64 curr_vddc = (u64)curr_std_vddc;
	u64 pwr_efficiency_ratio, n, d;

	if ((prev_vddc == 0) || (curr_vddc == 0))
		return 0;

	n = div64_u64((u64)1024 * curr_vddc * curr_vddc * ((u64)1000 + margin), (u64)1000);
	d = prev_vddc * prev_vddc;
	pwr_efficiency_ratio = div64_u64(n, d);

	if (pwr_efficiency_ratio > (u64)0xFFFF)
		return 0;

	return (u16)pwr_efficiency_ratio;
}

static bool si_should_disable_uvd_powertune(struct amdgpu_device *adev,
					    struct amdgpu_ps *amdgpu_state)
{
	struct si_power_info *si_pi = si_get_pi(adev);

	if (si_pi->dyn_powertune_data.disable_uvd_powertune &&
	    amdgpu_state->vclk && amdgpu_state->dclk)
		return true;

	return false;
}

struct evergreen_power_info *evergreen_get_pi(struct amdgpu_device *adev)
{
	struct evergreen_power_info *pi = adev->pm.dpm.priv;

	return pi;
}

static int si_populate_power_containment_values(struct amdgpu_device *adev,
						struct amdgpu_ps *amdgpu_state,
						SISLANDS_SMC_SWSTATE *smc_state)
{
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct  si_ps *state = si_get_ps(amdgpu_state);
	SISLANDS_SMC_VOLTAGE_VALUE vddc;
	u32 prev_sclk;
	u32 max_sclk;
	u32 min_sclk;
	u16 prev_std_vddc;
	u16 curr_std_vddc;
	int i;
	u16 pwr_efficiency_ratio;
	u8 max_ps_percent;
	bool disable_uvd_power_tune;
	int ret;

	if (ni_pi->enable_power_containment == false)
		return 0;

	if (state->performance_level_count == 0)
		return -EINVAL;

	if (smc_state->levelCount != state->performance_level_count)
		return -EINVAL;

	disable_uvd_power_tune = si_should_disable_uvd_powertune(adev, amdgpu_state);

	smc_state->levels[0].dpm2.MaxPS = 0;
	smc_state->levels[0].dpm2.NearTDPDec = 0;
	smc_state->levels[0].dpm2.AboveSafeInc = 0;
	smc_state->levels[0].dpm2.BelowSafeInc = 0;
	smc_state->levels[0].dpm2.PwrEfficiencyRatio = 0;

	for (i = 1; i < state->performance_level_count; i++) {
		prev_sclk = state->performance_levels[i-1].sclk;
		max_sclk  = state->performance_levels[i].sclk;
		if (i == 1)
			max_ps_percent = SISLANDS_DPM2_MAXPS_PERCENT_M;
		else
			max_ps_percent = SISLANDS_DPM2_MAXPS_PERCENT_H;

		if (prev_sclk > max_sclk)
			return -EINVAL;

		if ((max_ps_percent == 0) ||
		    (prev_sclk == max_sclk) ||
		    disable_uvd_power_tune)
			min_sclk = max_sclk;
		else if (i == 1)
			min_sclk = prev_sclk;
		else
			min_sclk = (prev_sclk * (u32)max_ps_percent) / 100;

		if (min_sclk < state->performance_levels[0].sclk)
			min_sclk = state->performance_levels[0].sclk;

		if (min_sclk == 0)
			return -EINVAL;

		ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
						state->performance_levels[i-1].vddc, &vddc);
		if (ret)
			return ret;

		ret = si_get_std_voltage_value(adev, &vddc, &prev_std_vddc);
		if (ret)
			return ret;

		ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
						state->performance_levels[i].vddc, &vddc);
		if (ret)
			return ret;

		ret = si_get_std_voltage_value(adev, &vddc, &curr_std_vddc);
		if (ret)
			return ret;

		pwr_efficiency_ratio = si_calculate_power_efficiency_ratio(adev,
									   prev_std_vddc, curr_std_vddc);

		smc_state->levels[i].dpm2.MaxPS = (u8)((SISLANDS_DPM2_MAX_PULSE_SKIP * (max_sclk - min_sclk)) / max_sclk);
		smc_state->levels[i].dpm2.NearTDPDec = SISLANDS_DPM2_NEAR_TDP_DEC;
		smc_state->levels[i].dpm2.AboveSafeInc = SISLANDS_DPM2_ABOVE_SAFE_INC;
		smc_state->levels[i].dpm2.BelowSafeInc = SISLANDS_DPM2_BELOW_SAFE_INC;
		smc_state->levels[i].dpm2.PwrEfficiencyRatio = cpu_to_be16(pwr_efficiency_ratio);
	}

	return 0;
}

static int si_populate_sq_ramping_values(struct amdgpu_device *adev,
					 struct amdgpu_ps *amdgpu_state,
					 SISLANDS_SMC_SWSTATE *smc_state)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct  si_ps *state = si_get_ps(amdgpu_state);
	u32 sq_power_throttle, sq_power_throttle2;
	bool enable_sq_ramping = ni_pi->enable_sq_ramping;
	int i;

	if (state->performance_level_count == 0)
		return -EINVAL;

	if (smc_state->levelCount != state->performance_level_count)
		return -EINVAL;

	if (adev->pm.dpm.sq_ramping_threshold == 0)
		return -EINVAL;

	if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT))
		enable_sq_ramping = false;

	if (SISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT))
		enable_sq_ramping = false;

	if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT))
		enable_sq_ramping = false;

	if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
		enable_sq_ramping = false;

	if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
		enable_sq_ramping = false;

	for (i = 0; i < state->performance_level_count; i++) {
		sq_power_throttle = 0;
		sq_power_throttle2 = 0;

		if ((state->performance_levels[i].sclk >= adev->pm.dpm.sq_ramping_threshold) &&
		    enable_sq_ramping) {
			sq_power_throttle |= MAX_POWER(SISLANDS_DPM2_SQ_RAMP_MAX_POWER);
			sq_power_throttle |= MIN_POWER(SISLANDS_DPM2_SQ_RAMP_MIN_POWER);
			sq_power_throttle2 |= MAX_POWER_DELTA(SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA);
			sq_power_throttle2 |= STI_SIZE(SISLANDS_DPM2_SQ_RAMP_STI_SIZE);
			sq_power_throttle2 |= LTI_RATIO(SISLANDS_DPM2_SQ_RAMP_LTI_RATIO);
		} else {
			sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK;
			sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
		}

		smc_state->levels[i].SQPowerThrottle = cpu_to_be32(sq_power_throttle);
		smc_state->levels[i].SQPowerThrottle_2 = cpu_to_be32(sq_power_throttle2);
	}

	return 0;
}

static int si_enable_power_containment(struct amdgpu_device *adev,
				       struct amdgpu_ps *amdgpu_new_state,
				       bool enable)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	PPSMC_Result smc_result;
	int ret = 0;

	if (ni_pi->enable_power_containment) {
		if (enable) {
			if (!si_should_disable_uvd_powertune(adev, amdgpu_new_state)) {
				smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_TDPClampingActive);
				if (smc_result != PPSMC_Result_OK) {
					ret = -EINVAL;
					ni_pi->pc_enabled = false;
				} else {
					ni_pi->pc_enabled = true;
				}
			}
		} else {
			smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_TDPClampingInactive);
			if (smc_result != PPSMC_Result_OK)
				ret = -EINVAL;
			ni_pi->pc_enabled = false;
		}
	}

	return ret;
}

static int si_initialize_smc_dte_tables(struct amdgpu_device *adev)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	int ret = 0;
	struct si_dte_data *dte_data = &si_pi->dte_data;
	Smc_SIslands_DTE_Configuration *dte_tables = NULL;
	u32 table_size;
	u8 tdep_count;
	u32 i;

	if (dte_data == NULL)
		si_pi->enable_dte = false;

	if (si_pi->enable_dte == false)
		return 0;

	if (dte_data->k <= 0)
		return -EINVAL;

	dte_tables = kzalloc(sizeof(Smc_SIslands_DTE_Configuration), GFP_KERNEL);
	if (dte_tables == NULL) {
		si_pi->enable_dte = false;
		return -ENOMEM;
	}

	table_size = dte_data->k;

	if (table_size > SMC_SISLANDS_DTE_MAX_FILTER_STAGES)
		table_size = SMC_SISLANDS_DTE_MAX_FILTER_STAGES;

	tdep_count = dte_data->tdep_count;
	if (tdep_count > SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE)
		tdep_count = SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE;

	dte_tables->K = cpu_to_be32(table_size);
	dte_tables->T0 = cpu_to_be32(dte_data->t0);
	dte_tables->MaxT = cpu_to_be32(dte_data->max_t);
	dte_tables->WindowSize = dte_data->window_size;
	dte_tables->temp_select = dte_data->temp_select;
	dte_tables->DTE_mode = dte_data->dte_mode;
	dte_tables->Tthreshold = cpu_to_be32(dte_data->t_threshold);

	if (tdep_count > 0)
		table_size--;

	for (i = 0; i < table_size; i++) {
		dte_tables->tau[i] = cpu_to_be32(dte_data->tau[i]);
		dte_tables->R[i]   = cpu_to_be32(dte_data->r[i]);
	}

	dte_tables->Tdep_count = tdep_count;

	for (i = 0; i < (u32)tdep_count; i++) {
		dte_tables->T_limits[i] = dte_data->t_limits[i];
		dte_tables->Tdep_tau[i] = cpu_to_be32(dte_data->tdep_tau[i]);
		dte_tables->Tdep_R[i] = cpu_to_be32(dte_data->tdep_r[i]);
	}

	ret = amdgpu_si_copy_bytes_to_smc(adev, si_pi->dte_table_start,
					  (u8 *)dte_tables,
					  sizeof(Smc_SIslands_DTE_Configuration),
					  si_pi->sram_end);
	kfree(dte_tables);

	return ret;
}

static int si_get_cac_std_voltage_max_min(struct amdgpu_device *adev,
					  u16 *max, u16 *min)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	struct amdgpu_cac_leakage_table *table =
		&adev->pm.dpm.dyn_state.cac_leakage_table;
	u32 i;
	u32 v0_loadline;

	if (table == NULL)
		return -EINVAL;

	*max = 0;
	*min = 0xFFFF;

	for (i = 0; i < table->count; i++) {
		if (table->entries[i].vddc > *max)
			*max = table->entries[i].vddc;
		if (table->entries[i].vddc < *min)
			*min = table->entries[i].vddc;
	}

	if (si_pi->powertune_data->lkge_lut_v0_percent > 100)
		return -EINVAL;

	v0_loadline = (*min) * (100 - si_pi->powertune_data->lkge_lut_v0_percent) / 100;

	if (v0_loadline > 0xFFFFUL)
		return -EINVAL;

	*min = (u16)v0_loadline;

	if ((*min > *max) || (*max == 0) || (*min == 0))
		return -EINVAL;

	return 0;
}

static u16 si_get_cac_std_voltage_step(u16 max, u16 min)
{
	return ((max - min) + (SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES - 1)) /
		SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
}

static int si_init_dte_leakage_table(struct amdgpu_device *adev,
				     PP_SIslands_CacConfig *cac_tables,
				     u16 vddc_max, u16 vddc_min, u16 vddc_step,
				     u16 t0, u16 t_step)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	u32 leakage;
	unsigned int i, j;
	s32 t;
	u32 smc_leakage;
	u32 scaling_factor;
	u16 voltage;

	scaling_factor = si_get_smc_power_scaling_factor(adev);

	for (i = 0; i < SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES ; i++) {
		t = (1000 * (i * t_step + t0));

		for (j = 0; j < SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
			voltage = vddc_max - (vddc_step * j);

			si_calculate_leakage_for_v_and_t(adev,
							 &si_pi->powertune_data->leakage_coefficients,
							 voltage,
							 t,
							 si_pi->dyn_powertune_data.cac_leakage,
							 &leakage);

			smc_leakage = si_scale_power_for_smc(leakage, scaling_factor) / 4;

			if (smc_leakage > 0xFFFF)
				smc_leakage = 0xFFFF;

			cac_tables->cac_lkge_lut[i][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES-1-j] =
				cpu_to_be16((u16)smc_leakage);
		}
	}
	return 0;
}

static int si_init_simplified_leakage_table(struct amdgpu_device *adev,
					    PP_SIslands_CacConfig *cac_tables,
					    u16 vddc_max, u16 vddc_min, u16 vddc_step)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	u32 leakage;
	unsigned int i, j;
	u32 smc_leakage;
	u32 scaling_factor;
	u16 voltage;

	scaling_factor = si_get_smc_power_scaling_factor(adev);

	for (j = 0; j < SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
		voltage = vddc_max - (vddc_step * j);

		si_calculate_leakage_for_v(adev,
					   &si_pi->powertune_data->leakage_coefficients,
					   si_pi->powertune_data->fixed_kt,
					   voltage,
					   si_pi->dyn_powertune_data.cac_leakage,
					   &leakage);

		smc_leakage = si_scale_power_for_smc(leakage, scaling_factor) / 4;

		if (smc_leakage > 0xFFFF)
			smc_leakage = 0xFFFF;

		for (i = 0; i < SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES ; i++)
			cac_tables->cac_lkge_lut[i][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES-1-j] =
				cpu_to_be16((u16)smc_leakage);
	}
	return 0;
}

static int si_initialize_smc_cac_tables(struct amdgpu_device *adev)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	PP_SIslands_CacConfig *cac_tables = NULL;
	u16 vddc_max, vddc_min, vddc_step;
	u16 t0, t_step;
	u32 load_line_slope, reg;
	int ret = 0;
	u32 ticks_per_us = amdgpu_asic_get_xclk(adev) / 100;

	if (ni_pi->enable_cac == false)
		return 0;

	cac_tables = kzalloc(sizeof(PP_SIslands_CacConfig), GFP_KERNEL);
	if (!cac_tables)
		return -ENOMEM;

	reg = RREG32(CG_CAC_CTRL) & ~CAC_WINDOW_MASK;
	reg |= CAC_WINDOW(si_pi->powertune_data->cac_window);
	WREG32(CG_CAC_CTRL, reg);

	si_pi->dyn_powertune_data.cac_leakage = adev->pm.dpm.cac_leakage;
	si_pi->dyn_powertune_data.dc_pwr_value =
		si_pi->powertune_data->dc_cac[NISLANDS_DCCAC_LEVEL_0];
	si_pi->dyn_powertune_data.wintime = si_calculate_cac_wintime(adev);
	si_pi->dyn_powertune_data.shift_n = si_pi->powertune_data->shift_n_default;

	si_pi->dyn_powertune_data.leakage_minimum_temperature = 80 * 1000;

	ret = si_get_cac_std_voltage_max_min(adev, &vddc_max, &vddc_min);
	if (ret)
		goto done_free;

	vddc_step = si_get_cac_std_voltage_step(vddc_max, vddc_min);
	vddc_min = vddc_max - (vddc_step * (SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES - 1));
	t_step = 4;
	t0 = 60;

	if (si_pi->enable_dte || ni_pi->driver_calculate_cac_leakage)
		ret = si_init_dte_leakage_table(adev, cac_tables,
						vddc_max, vddc_min, vddc_step,
						t0, t_step);
	else
		ret = si_init_simplified_leakage_table(adev, cac_tables,
						       vddc_max, vddc_min, vddc_step);
	if (ret)
		goto done_free;

	load_line_slope = ((u32)adev->pm.dpm.load_line_slope << SMC_SISLANDS_SCALE_R) / 100;

	cac_tables->l2numWin_TDP = cpu_to_be32(si_pi->dyn_powertune_data.l2_lta_window_size);
	cac_tables->lts_truncate_n = si_pi->dyn_powertune_data.lts_truncate;
	cac_tables->SHIFT_N = si_pi->dyn_powertune_data.shift_n;
	cac_tables->lkge_lut_V0 = cpu_to_be32((u32)vddc_min);
	cac_tables->lkge_lut_Vstep = cpu_to_be32((u32)vddc_step);
	cac_tables->R_LL = cpu_to_be32(load_line_slope);
	cac_tables->WinTime = cpu_to_be32(si_pi->dyn_powertune_data.wintime);
	cac_tables->calculation_repeats = cpu_to_be32(2);
	cac_tables->dc_cac = cpu_to_be32(0);
	cac_tables->log2_PG_LKG_SCALE = 12;
	cac_tables->cac_temp = si_pi->powertune_data->operating_temp;
	cac_tables->lkge_lut_T0 = cpu_to_be32((u32)t0);
	cac_tables->lkge_lut_Tstep = cpu_to_be32((u32)t_step);

	ret = amdgpu_si_copy_bytes_to_smc(adev, si_pi->cac_table_start,
					  (u8 *)cac_tables,
					  sizeof(PP_SIslands_CacConfig),
					  si_pi->sram_end);

	if (ret)
		goto done_free;

	ret = si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_ticks_per_us, ticks_per_us);

done_free:
	if (ret) {
		ni_pi->enable_cac = false;
		ni_pi->enable_power_containment = false;
	}

	kfree(cac_tables);

	return ret;
}

static int si_program_cac_config_registers(struct amdgpu_device *adev,
					   const struct si_cac_config_reg *cac_config_regs)
{
	const struct si_cac_config_reg *config_regs = cac_config_regs;
	u32 data = 0, offset;

	if (!config_regs)
		return -EINVAL;

	while (config_regs->offset != 0xFFFFFFFF) {
		switch (config_regs->type) {
		case SISLANDS_CACCONFIG_CGIND:
			offset = SMC_CG_IND_START + config_regs->offset;
			if (offset < SMC_CG_IND_END)
				data = RREG32_SMC(offset);
			break;
		default:
			data = RREG32(config_regs->offset);
			break;
		}

		data &= ~config_regs->mask;
		data |= ((config_regs->value << config_regs->shift) & config_regs->mask);

		switch (config_regs->type) {
		case SISLANDS_CACCONFIG_CGIND:
			offset = SMC_CG_IND_START + config_regs->offset;
			if (offset < SMC_CG_IND_END)
				WREG32_SMC(offset, data);
			break;
		default:
			WREG32(config_regs->offset, data);
			break;
		}
		config_regs++;
	}
	return 0;
}

static int si_initialize_hardware_cac_manager(struct amdgpu_device *adev)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	int ret;

	if ((ni_pi->enable_cac == false) ||
	    (ni_pi->cac_configuration_required == false))
		return 0;

	ret = si_program_cac_config_registers(adev, si_pi->lcac_config);
	if (ret)
		return ret;
	ret = si_program_cac_config_registers(adev, si_pi->cac_override);
	if (ret)
		return ret;
	ret = si_program_cac_config_registers(adev, si_pi->cac_weights);
	if (ret)
		return ret;

	return 0;
}

static int si_enable_smc_cac(struct amdgpu_device *adev,
			     struct amdgpu_ps *amdgpu_new_state,
			     bool enable)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	PPSMC_Result smc_result;
	int ret = 0;

	if (ni_pi->enable_cac) {
		if (enable) {
			if (!si_should_disable_uvd_powertune(adev, amdgpu_new_state)) {
				if (ni_pi->support_cac_long_term_average) {
					smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_CACLongTermAvgEnable);
					if (smc_result != PPSMC_Result_OK)
						ni_pi->support_cac_long_term_average = false;
				}

				smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableCac);
				if (smc_result != PPSMC_Result_OK) {
					ret = -EINVAL;
					ni_pi->cac_enabled = false;
				} else {
					ni_pi->cac_enabled = true;
				}

				if (si_pi->enable_dte) {
					smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableDTE);
					if (smc_result != PPSMC_Result_OK)
						ret = -EINVAL;
				}
			}
		} else if (ni_pi->cac_enabled) {
			if (si_pi->enable_dte)
				smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableDTE);

			smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_DisableCac);

			ni_pi->cac_enabled = false;

			if (ni_pi->support_cac_long_term_average)
				smc_result = amdgpu_si_send_msg_to_smc(adev, PPSMC_CACLongTermAvgDisable);
		}
	}
	return ret;
}

static int si_init_smc_spll_table(struct amdgpu_device *adev)
{
	struct ni_power_info *ni_pi = ni_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	SMC_SISLANDS_SPLL_DIV_TABLE *spll_table;
	SISLANDS_SMC_SCLK_VALUE sclk_params;
	u32 fb_div, p_div;
	u32 clk_s, clk_v;
	u32 sclk = 0;
	int ret = 0;
	u32 tmp;
	int i;

	if (si_pi->spll_table_start == 0)
		return -EINVAL;

	spll_table = kzalloc(sizeof(SMC_SISLANDS_SPLL_DIV_TABLE), GFP_KERNEL);
	if (spll_table == NULL)
		return -ENOMEM;

	for (i = 0; i < 256; i++) {
		ret = si_calculate_sclk_params(adev, sclk, &sclk_params);
		if (ret)
			break;
		p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT;
		fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
		clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT;
		clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT;

		fb_div &= ~0x00001FFF;
		fb_div >>= 1;
		clk_v >>= 6;

		if (p_div & ~(SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT))
			ret = -EINVAL;
		if (fb_div & ~(SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT))
			ret = -EINVAL;
		if (clk_s & ~(SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
			ret = -EINVAL;
		if (clk_v & ~(SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT))
			ret = -EINVAL;

		if (ret)
			break;

		tmp = ((fb_div << SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK) |
			((p_div << SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK);
		spll_table->freq[i] = cpu_to_be32(tmp);

		tmp = ((clk_v << SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK) |
			((clk_s << SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK);
		spll_table->ss[i] = cpu_to_be32(tmp);

		sclk += 512;
	}


	if (!ret)
		ret = amdgpu_si_copy_bytes_to_smc(adev, si_pi->spll_table_start,
						  (u8 *)spll_table,
						  sizeof(SMC_SISLANDS_SPLL_DIV_TABLE),
						  si_pi->sram_end);

	if (ret)
		ni_pi->enable_power_containment = false;

	kfree(spll_table);

	return ret;
}

static u16 si_get_lower_of_leakage_and_vce_voltage(struct amdgpu_device *adev,
						   u16 vce_voltage)
{
	u16 highest_leakage = 0;
	struct si_power_info *si_pi = si_get_pi(adev);
	int i;

	for (i = 0; i < si_pi->leakage_voltage.count; i++){
		if (highest_leakage < si_pi->leakage_voltage.entries[i].voltage)
			highest_leakage = si_pi->leakage_voltage.entries[i].voltage;
	}

	if (si_pi->leakage_voltage.count && (highest_leakage < vce_voltage))
		return highest_leakage;

	return vce_voltage;
}

static int si_get_vce_clock_voltage(struct amdgpu_device *adev,
				    u32 evclk, u32 ecclk, u16 *voltage)
{
	u32 i;
	int ret = -EINVAL;
	struct amdgpu_vce_clock_voltage_dependency_table *table =
		&adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;

	if (((evclk == 0) && (ecclk == 0)) ||
	    (table && (table->count == 0))) {
		*voltage = 0;
		return 0;
	}

	for (i = 0; i < table->count; i++) {
		if ((evclk <= table->entries[i].evclk) &&
		    (ecclk <= table->entries[i].ecclk)) {
			*voltage = table->entries[i].v;
			ret = 0;
			break;
		}
	}

	/* if no match return the highest voltage */
	if (ret)
		*voltage = table->entries[table->count - 1].v;

	*voltage = si_get_lower_of_leakage_and_vce_voltage(adev, *voltage);

	return ret;
}

static bool si_dpm_vblank_too_short(void *handle)
{
	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
	u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
	/* we never hit the non-gddr5 limit so disable it */
	u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0;

	if (vblank_time < switch_limit)
		return true;
	else
		return false;

}

static int ni_copy_and_switch_arb_sets(struct amdgpu_device *adev,
				u32 arb_freq_src, u32 arb_freq_dest)
{
	u32 mc_arb_dram_timing;
	u32 mc_arb_dram_timing2;
	u32 burst_time;
	u32 mc_cg_config;

	switch (arb_freq_src) {
	case MC_CG_ARB_FREQ_F0:
		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING);
		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE0_MASK) >> STATE0_SHIFT;
		break;
	case MC_CG_ARB_FREQ_F1:
		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_1);
		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_1);
		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE1_MASK) >> STATE1_SHIFT;
		break;
	case MC_CG_ARB_FREQ_F2:
		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_2);
		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_2);
		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE2_MASK) >> STATE2_SHIFT;
		break;
	case MC_CG_ARB_FREQ_F3:
		mc_arb_dram_timing  = RREG32(MC_ARB_DRAM_TIMING_3);
		mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_3);
		burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE3_MASK) >> STATE3_SHIFT;
		break;
	default:
		return -EINVAL;
	}

	switch (arb_freq_dest) {
	case MC_CG_ARB_FREQ_F0:
		WREG32(MC_ARB_DRAM_TIMING, mc_arb_dram_timing);
		WREG32(MC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
		WREG32_P(MC_ARB_BURST_TIME, STATE0(burst_time), ~STATE0_MASK);
		break;
	case MC_CG_ARB_FREQ_F1:
		WREG32(MC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
		WREG32(MC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
		WREG32_P(MC_ARB_BURST_TIME, STATE1(burst_time), ~STATE1_MASK);
		break;
	case MC_CG_ARB_FREQ_F2:
		WREG32(MC_ARB_DRAM_TIMING_2, mc_arb_dram_timing);
		WREG32(MC_ARB_DRAM_TIMING2_2, mc_arb_dram_timing2);
		WREG32_P(MC_ARB_BURST_TIME, STATE2(burst_time), ~STATE2_MASK);
		break;
	case MC_CG_ARB_FREQ_F3:
		WREG32(MC_ARB_DRAM_TIMING_3, mc_arb_dram_timing);
		WREG32(MC_ARB_DRAM_TIMING2_3, mc_arb_dram_timing2);
		WREG32_P(MC_ARB_BURST_TIME, STATE3(burst_time), ~STATE3_MASK);
		break;
	default:
		return -EINVAL;
	}

	mc_cg_config = RREG32(MC_CG_CONFIG) | 0x0000000F;
	WREG32(MC_CG_CONFIG, mc_cg_config);
	WREG32_P(MC_ARB_CG, CG_ARB_REQ(arb_freq_dest), ~CG_ARB_REQ_MASK);

	return 0;
}

static void ni_update_current_ps(struct amdgpu_device *adev,
			  struct amdgpu_ps *rps)
{
	struct si_ps *new_ps = si_get_ps(rps);
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	struct ni_power_info *ni_pi = ni_get_pi(adev);

	eg_pi->current_rps = *rps;
	ni_pi->current_ps = *new_ps;
	eg_pi->current_rps.ps_priv = &ni_pi->current_ps;
	adev->pm.dpm.current_ps = &eg_pi->current_rps;
}

static void ni_update_requested_ps(struct amdgpu_device *adev,
			    struct amdgpu_ps *rps)
{
	struct si_ps *new_ps = si_get_ps(rps);
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	struct ni_power_info *ni_pi = ni_get_pi(adev);

	eg_pi->requested_rps = *rps;
	ni_pi->requested_ps = *new_ps;
	eg_pi->requested_rps.ps_priv = &ni_pi->requested_ps;
	adev->pm.dpm.requested_ps = &eg_pi->requested_rps;
}

static void ni_set_uvd_clock_before_set_eng_clock(struct amdgpu_device *adev,
					   struct amdgpu_ps *new_ps,
					   struct amdgpu_ps *old_ps)
{
	struct si_ps *new_state = si_get_ps(new_ps);
	struct si_ps *current_state = si_get_ps(old_ps);

	if ((new_ps->vclk == old_ps->vclk) &&
	    (new_ps->dclk == old_ps->dclk))
		return;

	if (new_state->performance_levels[new_state->performance_level_count - 1].sclk >=
	    current_state->performance_levels[current_state->performance_level_count - 1].sclk)
		return;

	amdgpu_asic_set_uvd_clocks(adev, new_ps->vclk, new_ps->dclk);
}

static void ni_set_uvd_clock_after_set_eng_clock(struct amdgpu_device *adev,
					  struct amdgpu_ps *new_ps,
					  struct amdgpu_ps *old_ps)
{
	struct si_ps *new_state = si_get_ps(new_ps);
	struct si_ps *current_state = si_get_ps(old_ps);

	if ((new_ps->vclk == old_ps->vclk) &&
	    (new_ps->dclk == old_ps->dclk))
		return;

	if (new_state->performance_levels[new_state->performance_level_count - 1].sclk <
	    current_state->performance_levels[current_state->performance_level_count - 1].sclk)
		return;

	amdgpu_asic_set_uvd_clocks(adev, new_ps->vclk, new_ps->dclk);
}

static u16 btc_find_voltage(struct atom_voltage_table *table, u16 voltage)
{
	unsigned int i;

	for (i = 0; i < table->count; i++)
		if (voltage <= table->entries[i].value)
			return table->entries[i].value;

	return table->entries[table->count - 1].value;
}

static u32 btc_find_valid_clock(struct amdgpu_clock_array *clocks,
		                u32 max_clock, u32 requested_clock)
{
	unsigned int i;

	if ((clocks == NULL) || (clocks->count == 0))
		return (requested_clock < max_clock) ? requested_clock : max_clock;

	for (i = 0; i < clocks->count; i++) {
		if (clocks->values[i] >= requested_clock)
			return (clocks->values[i] < max_clock) ? clocks->values[i] : max_clock;
	}

	return (clocks->values[clocks->count - 1] < max_clock) ?
		clocks->values[clocks->count - 1] : max_clock;
}

static u32 btc_get_valid_mclk(struct amdgpu_device *adev,
			      u32 max_mclk, u32 requested_mclk)
{
	return btc_find_valid_clock(&adev->pm.dpm.dyn_state.valid_mclk_values,
				    max_mclk, requested_mclk);
}

static u32 btc_get_valid_sclk(struct amdgpu_device *adev,
		              u32 max_sclk, u32 requested_sclk)
{
	return btc_find_valid_clock(&adev->pm.dpm.dyn_state.valid_sclk_values,
				    max_sclk, requested_sclk);
}

static void btc_get_max_clock_from_voltage_dependency_table(struct amdgpu_clock_voltage_dependency_table *table,
							    u32 *max_clock)
{
	u32 i, clock = 0;

	if ((table == NULL) || (table->count == 0)) {
		*max_clock = clock;
		return;
	}

	for (i = 0; i < table->count; i++) {
		if (clock < table->entries[i].clk)
			clock = table->entries[i].clk;
	}
	*max_clock = clock;
}

static void btc_apply_voltage_dependency_rules(struct amdgpu_clock_voltage_dependency_table *table,
					       u32 clock, u16 max_voltage, u16 *voltage)
{
	u32 i;

	if ((table == NULL) || (table->count == 0))
		return;

	for (i= 0; i < table->count; i++) {
		if (clock <= table->entries[i].clk) {
			if (*voltage < table->entries[i].v)
				*voltage = (u16)((table->entries[i].v < max_voltage) ?
					   table->entries[i].v : max_voltage);
			return;
		}
	}

	*voltage = (*voltage > max_voltage) ? *voltage : max_voltage;
}

static void btc_adjust_clock_combinations(struct amdgpu_device *adev,
					  const struct amdgpu_clock_and_voltage_limits *max_limits,
					  struct rv7xx_pl *pl)
{

	if ((pl->mclk == 0) || (pl->sclk == 0))
		return;

	if (pl->mclk == pl->sclk)
		return;

	if (pl->mclk > pl->sclk) {
		if (((pl->mclk + (pl->sclk - 1)) / pl->sclk) > adev->pm.dpm.dyn_state.mclk_sclk_ratio)
			pl->sclk = btc_get_valid_sclk(adev,
						      max_limits->sclk,
						      (pl->mclk +
						      (adev->pm.dpm.dyn_state.mclk_sclk_ratio - 1)) /
						      adev->pm.dpm.dyn_state.mclk_sclk_ratio);
	} else {
		if ((pl->sclk - pl->mclk) > adev->pm.dpm.dyn_state.sclk_mclk_delta)
			pl->mclk = btc_get_valid_mclk(adev,
						      max_limits->mclk,
						      pl->sclk -
						      adev->pm.dpm.dyn_state.sclk_mclk_delta);
	}
}

static void btc_apply_voltage_delta_rules(struct amdgpu_device *adev,
					  u16 max_vddc, u16 max_vddci,
					  u16 *vddc, u16 *vddci)
{
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	u16 new_voltage;

	if ((0 == *vddc) || (0 == *vddci))
		return;

	if (*vddc > *vddci) {
		if ((*vddc - *vddci) > adev->pm.dpm.dyn_state.vddc_vddci_delta) {
			new_voltage = btc_find_voltage(&eg_pi->vddci_voltage_table,
						       (*vddc - adev->pm.dpm.dyn_state.vddc_vddci_delta));
			*vddci = (new_voltage < max_vddci) ? new_voltage : max_vddci;
		}
	} else {
		if ((*vddci - *vddc) > adev->pm.dpm.dyn_state.vddc_vddci_delta) {
			new_voltage = btc_find_voltage(&eg_pi->vddc_voltage_table,
						       (*vddci - adev->pm.dpm.dyn_state.vddc_vddci_delta));
			*vddc = (new_voltage < max_vddc) ? new_voltage : max_vddc;
		}
	}
}

static void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
			    u32 *p, u32 *u)
{
	u32 b_c = 0;
	u32 i_c;
	u32 tmp;

	i_c = (i * r_c) / 100;
	tmp = i_c >> p_b;

	while (tmp) {
		b_c++;
		tmp >>= 1;
	}

	*u = (b_c + 1) / 2;
	*p = i_c / (1 << (2 * (*u)));
}

static int r600_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th)
{
	u32 k, a, ah, al;
	u32 t1;

	if ((fl == 0) || (fh == 0) || (fl > fh))
		return -EINVAL;

	k = (100 * fh) / fl;
	t1 = (t * (k - 100));
	a = (1000 * (100 * h + t1)) / (10000 + (t1 / 100));
	a = (a + 5) / 10;
	ah = ((a * t) + 5000) / 10000;
	al = a - ah;

	*th = t - ah;
	*tl = t + al;

	return 0;
}

static bool r600_is_uvd_state(u32 class, u32 class2)
{
	if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
		return true;
	if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
		return true;
	if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
		return true;
	if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
		return true;
	if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
		return true;
	return false;
}

static u8 rv770_get_memory_module_index(struct amdgpu_device *adev)
{
	return (u8) ((RREG32(BIOS_SCRATCH_4) >> 16) & 0xff);
}

static void rv770_get_max_vddc(struct amdgpu_device *adev)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	u16 vddc;

	if (amdgpu_atombios_get_max_vddc(adev, 0, 0, &vddc))
		pi->max_vddc = 0;
	else
		pi->max_vddc = vddc;
}

static void rv770_get_engine_memory_ss(struct amdgpu_device *adev)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	struct amdgpu_atom_ss ss;

	pi->sclk_ss = amdgpu_atombios_get_asic_ss_info(adev, &ss,
						       ASIC_INTERNAL_ENGINE_SS, 0);
	pi->mclk_ss = amdgpu_atombios_get_asic_ss_info(adev, &ss,
						       ASIC_INTERNAL_MEMORY_SS, 0);

	if (pi->sclk_ss || pi->mclk_ss)
		pi->dynamic_ss = true;
	else
		pi->dynamic_ss = false;
}


static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
					struct amdgpu_ps *rps)
{
	struct  si_ps *ps = si_get_ps(rps);
	struct amdgpu_clock_and_voltage_limits *max_limits;
	bool disable_mclk_switching = false;
	bool disable_sclk_switching = false;
	u32 mclk, sclk;
	u16 vddc, vddci, min_vce_voltage = 0;
	u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
	u32 max_sclk = 0, max_mclk = 0;
	int i;

	if (adev->asic_type == CHIP_HAINAN) {
		if ((adev->pdev->revision == 0x81) ||
		    (adev->pdev->revision == 0x83) ||
		    (adev->pdev->revision == 0xC3) ||
		    (adev->pdev->device == 0x6664) ||
		    (adev->pdev->device == 0x6665) ||
		    (adev->pdev->device == 0x6667)) {
			max_sclk = 75000;
		}
		if ((adev->pdev->revision == 0xC3) ||
		    (adev->pdev->device == 0x6665)) {
			max_sclk = 60000;
			max_mclk = 80000;
		}
	} else if (adev->asic_type == CHIP_OLAND) {
		if ((adev->pdev->revision == 0xC7) ||
		    (adev->pdev->revision == 0x80) ||
		    (adev->pdev->revision == 0x81) ||
		    (adev->pdev->revision == 0x83) ||
		    (adev->pdev->revision == 0x87) ||
		    (adev->pdev->device == 0x6604) ||
		    (adev->pdev->device == 0x6605)) {
			max_sclk = 75000;
		}
	}

	if (rps->vce_active) {
		rps->evclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].evclk;
		rps->ecclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].ecclk;
		si_get_vce_clock_voltage(adev, rps->evclk, rps->ecclk,
					 &min_vce_voltage);
	} else {
		rps->evclk = 0;
		rps->ecclk = 0;
	}

	if ((adev->pm.dpm.new_active_crtc_count > 1) ||
	    si_dpm_vblank_too_short(adev))
		disable_mclk_switching = true;

	if (rps->vclk || rps->dclk) {
		disable_mclk_switching = true;
		disable_sclk_switching = true;
	}

	if (adev->pm.dpm.ac_power)
		max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
	else
		max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc;

	for (i = ps->performance_level_count - 2; i >= 0; i--) {
		if (ps->performance_levels[i].vddc > ps->performance_levels[i+1].vddc)
			ps->performance_levels[i].vddc = ps->performance_levels[i+1].vddc;
	}
	if (adev->pm.dpm.ac_power == false) {
		for (i = 0; i < ps->performance_level_count; i++) {
			if (ps->performance_levels[i].mclk > max_limits->mclk)
				ps->performance_levels[i].mclk = max_limits->mclk;
			if (ps->performance_levels[i].sclk > max_limits->sclk)
				ps->performance_levels[i].sclk = max_limits->sclk;
			if (ps->performance_levels[i].vddc > max_limits->vddc)
				ps->performance_levels[i].vddc = max_limits->vddc;
			if (ps->performance_levels[i].vddci > max_limits->vddci)
				ps->performance_levels[i].vddci = max_limits->vddci;
		}
	}

	/* limit clocks to max supported clocks based on voltage dependency tables */
	btc_get_max_clock_from_voltage_dependency_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
							&max_sclk_vddc);
	btc_get_max_clock_from_voltage_dependency_table(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
							&max_mclk_vddci);
	btc_get_max_clock_from_voltage_dependency_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
							&max_mclk_vddc);

	for (i = 0; i < ps->performance_level_count; i++) {
		if (max_sclk_vddc) {
			if (ps->performance_levels[i].sclk > max_sclk_vddc)
				ps->performance_levels[i].sclk = max_sclk_vddc;
		}
		if (max_mclk_vddci) {
			if (ps->performance_levels[i].mclk > max_mclk_vddci)
				ps->performance_levels[i].mclk = max_mclk_vddci;
		}
		if (max_mclk_vddc) {
			if (ps->performance_levels[i].mclk > max_mclk_vddc)
				ps->performance_levels[i].mclk = max_mclk_vddc;
		}
		if (max_mclk) {
			if (ps->performance_levels[i].mclk > max_mclk)
				ps->performance_levels[i].mclk = max_mclk;
		}
		if (max_sclk) {
			if (ps->performance_levels[i].sclk > max_sclk)
				ps->performance_levels[i].sclk = max_sclk;
		}
	}

	/* XXX validate the min clocks required for display */

	if (disable_mclk_switching) {
		mclk  = ps->performance_levels[ps->performance_level_count - 1].mclk;
		vddci = ps->performance_levels[ps->performance_level_count - 1].vddci;
	} else {
		mclk = ps->performance_levels[0].mclk;
		vddci = ps->performance_levels[0].vddci;
	}

	if (disable_sclk_switching) {
		sclk = ps->performance_levels[ps->performance_level_count - 1].sclk;
		vddc = ps->performance_levels[ps->performance_level_count - 1].vddc;
	} else {
		sclk = ps->performance_levels[0].sclk;
		vddc = ps->performance_levels[0].vddc;
	}

	if (rps->vce_active) {
		if (sclk < adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].sclk)
			sclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].sclk;
		if (mclk < adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].mclk)
			mclk = adev->pm.dpm.vce_states[adev->pm.dpm.vce_level].mclk;
	}

	/* adjusted low state */
	ps->performance_levels[0].sclk = sclk;
	ps->performance_levels[0].mclk = mclk;
	ps->performance_levels[0].vddc = vddc;
	ps->performance_levels[0].vddci = vddci;

	if (disable_sclk_switching) {
		sclk = ps->performance_levels[0].sclk;
		for (i = 1; i < ps->performance_level_count; i++) {
			if (sclk < ps->performance_levels[i].sclk)
				sclk = ps->performance_levels[i].sclk;
		}
		for (i = 0; i < ps->performance_level_count; i++) {
			ps->performance_levels[i].sclk = sclk;
			ps->performance_levels[i].vddc = vddc;
		}
	} else {
		for (i = 1; i < ps->performance_level_count; i++) {
			if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
				ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
			if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
				ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
		}
	}

	if (disable_mclk_switching) {
		mclk = ps->performance_levels[0].mclk;
		for (i = 1; i < ps->performance_level_count; i++) {
			if (mclk < ps->performance_levels[i].mclk)
				mclk = ps->performance_levels[i].mclk;
		}
		for (i = 0; i < ps->performance_level_count; i++) {
			ps->performance_levels[i].mclk = mclk;
			ps->performance_levels[i].vddci = vddci;
		}
	} else {
		for (i = 1; i < ps->performance_level_count; i++) {
			if (ps->performance_levels[i].mclk < ps->performance_levels[i - 1].mclk)
				ps->performance_levels[i].mclk = ps->performance_levels[i - 1].mclk;
			if (ps->performance_levels[i].vddci < ps->performance_levels[i - 1].vddci)
				ps->performance_levels[i].vddci = ps->performance_levels[i - 1].vddci;
		}
	}

	for (i = 0; i < ps->performance_level_count; i++)
		btc_adjust_clock_combinations(adev, max_limits,
					      &ps->performance_levels[i]);

	for (i = 0; i < ps->performance_level_count; i++) {
		if (ps->performance_levels[i].vddc < min_vce_voltage)
			ps->performance_levels[i].vddc = min_vce_voltage;
		btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
						   ps->performance_levels[i].sclk,
						   max_limits->vddc,  &ps->performance_levels[i].vddc);
		btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
						   ps->performance_levels[i].mclk,
						   max_limits->vddci, &ps->performance_levels[i].vddci);
		btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
						   ps->performance_levels[i].mclk,
						   max_limits->vddc,  &ps->performance_levels[i].vddc);
		btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
						   adev->clock.current_dispclk,
						   max_limits->vddc,  &ps->performance_levels[i].vddc);
	}

	for (i = 0; i < ps->performance_level_count; i++) {
		btc_apply_voltage_delta_rules(adev,
					      max_limits->vddc, max_limits->vddci,
					      &ps->performance_levels[i].vddc,
					      &ps->performance_levels[i].vddci);
	}

	ps->dc_compatible = true;
	for (i = 0; i < ps->performance_level_count; i++) {
		if (ps->performance_levels[i].vddc > adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc)
			ps->dc_compatible = false;
	}
}

#if 0
static int si_read_smc_soft_register(struct amdgpu_device *adev,
				     u16 reg_offset, u32 *value)
{
	struct si_power_info *si_pi = si_get_pi(adev);

	return amdgpu_si_read_smc_sram_dword(adev,
					     si_pi->soft_regs_start + reg_offset, value,
					     si_pi->sram_end);
}
#endif

static int si_write_smc_soft_register(struct amdgpu_device *adev,
				      u16 reg_offset, u32 value)
{
	struct si_power_info *si_pi = si_get_pi(adev);

	return amdgpu_si_write_smc_sram_dword(adev,
					      si_pi->soft_regs_start + reg_offset,
					      value, si_pi->sram_end);
}

static bool si_is_special_1gb_platform(struct amdgpu_device *adev)
{
	bool ret = false;
	u32 tmp, width, row, column, bank, density;
	bool is_memory_gddr5, is_special;

	tmp = RREG32(MC_SEQ_MISC0);
	is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE == ((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT));
	is_special = (MC_SEQ_MISC0_REV_ID_VALUE == ((tmp & MC_SEQ_MISC0_REV_ID_MASK) >> MC_SEQ_MISC0_REV_ID_SHIFT))
		& (MC_SEQ_MISC0_VEN_ID_VALUE == ((tmp & MC_SEQ_MISC0_VEN_ID_MASK) >> MC_SEQ_MISC0_VEN_ID_SHIFT));

	WREG32(MC_SEQ_IO_DEBUG_INDEX, 0xb);
	width = ((RREG32(MC_SEQ_IO_DEBUG_DATA) >> 1) & 1) ? 16 : 32;

	tmp = RREG32(MC_ARB_RAMCFG);
	row = ((tmp & NOOFROWS_MASK) >> NOOFROWS_SHIFT) + 10;
	column = ((tmp & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) + 8;
	bank = ((tmp & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + 2;

	density = (1 << (row + column - 20 + bank)) * width;

	if ((adev->pdev->device == 0x6819) &&
	    is_memory_gddr5 && is_special && (density == 0x400))
		ret = true;

	return ret;
}

static void si_get_leakage_vddc(struct amdgpu_device *adev)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	u16 vddc, count = 0;
	int i, ret;

	for (i = 0; i < SISLANDS_MAX_LEAKAGE_COUNT; i++) {
		ret = amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(adev, &vddc, SISLANDS_LEAKAGE_INDEX0 + i);

		if (!ret && (vddc > 0) && (vddc != (SISLANDS_LEAKAGE_INDEX0 + i))) {
			si_pi->leakage_voltage.entries[count].voltage = vddc;
			si_pi->leakage_voltage.entries[count].leakage_index =
				SISLANDS_LEAKAGE_INDEX0 + i;
			count++;
		}
	}
	si_pi->leakage_voltage.count = count;
}

static int si_get_leakage_voltage_from_leakage_index(struct amdgpu_device *adev,
						     u32 index, u16 *leakage_voltage)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	int i;

	if (leakage_voltage == NULL)
		return -EINVAL;

	if ((index & 0xff00) != 0xff00)
		return -EINVAL;

	if ((index & 0xff) > SISLANDS_MAX_LEAKAGE_COUNT + 1)
		return -EINVAL;

	if (index < SISLANDS_LEAKAGE_INDEX0)
		return -EINVAL;

	for (i = 0; i < si_pi->leakage_voltage.count; i++) {
		if (si_pi->leakage_voltage.entries[i].leakage_index == index) {
			*leakage_voltage = si_pi->leakage_voltage.entries[i].voltage;
			return 0;
		}
	}
	return -EAGAIN;
}

static void si_set_dpm_event_sources(struct amdgpu_device *adev, u32 sources)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	bool want_thermal_protection;
	enum amdgpu_dpm_event_src dpm_event_src;

	switch (sources) {
	case 0:
	default:
		want_thermal_protection = false;
		break;
	case (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL):
		want_thermal_protection = true;
		dpm_event_src = AMDGPU_DPM_EVENT_SRC_DIGITAL;
		break;
	case (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
		want_thermal_protection = true;
		dpm_event_src = AMDGPU_DPM_EVENT_SRC_EXTERNAL;
		break;
	case ((1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
	      (1 << AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL)):
		want_thermal_protection = true;
		dpm_event_src = AMDGPU_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
		break;
	}

	if (want_thermal_protection) {
		WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
		if (pi->thermal_protection)
			WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
	} else {
		WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
	}
}

static void si_enable_auto_throttle_source(struct amdgpu_device *adev,
					   enum amdgpu_dpm_auto_throttle_src source,
					   bool enable)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);

	if (enable) {
		if (!(pi->active_auto_throttle_sources & (1 << source))) {
			pi->active_auto_throttle_sources |= 1 << source;
			si_set_dpm_event_sources(adev, pi->active_auto_throttle_sources);
		}
	} else {
		if (pi->active_auto_throttle_sources & (1 << source)) {
			pi->active_auto_throttle_sources &= ~(1 << source);
			si_set_dpm_event_sources(adev, pi->active_auto_throttle_sources);
		}
	}
}

static void si_start_dpm(struct amdgpu_device *adev)
{
	WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
}

static void si_stop_dpm(struct amdgpu_device *adev)
{
	WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
}

static void si_enable_sclk_control(struct amdgpu_device *adev, bool enable)
{
	if (enable)
		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
	else
		WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);

}

#if 0
static int si_notify_hardware_of_thermal_state(struct amdgpu_device *adev,
					       u32 thermal_level)
{
	PPSMC_Result ret;

	if (thermal_level == 0) {
		ret = amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_EnableThermalInterrupt);
		if (ret == PPSMC_Result_OK)
			return 0;
		else
			return -EINVAL;
	}
	return 0;
}

static void si_notify_hardware_vpu_recovery_event(struct amdgpu_device *adev)
{
	si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen, true);
}
#endif

#if 0
static int si_notify_hw_of_powersource(struct amdgpu_device *adev, bool ac_power)
{
	if (ac_power)
		return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ?
			0 : -EINVAL;

	return 0;
}
#endif

static PPSMC_Result si_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
						      PPSMC_Msg msg, u32 parameter)
{
	WREG32(SMC_SCRATCH0, parameter);
	return amdgpu_si_send_msg_to_smc(adev, msg);
}

static int si_restrict_performance_levels_before_switch(struct amdgpu_device *adev)
{
	if (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
		return -EINVAL;

	return (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetEnabledLevels, 1) == PPSMC_Result_OK) ?
		0 : -EINVAL;
}

static int si_dpm_force_performance_level(void *handle,
				   enum amd_dpm_forced_level level)
{
	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
	struct amdgpu_ps *rps = adev->pm.dpm.current_ps;
	struct  si_ps *ps = si_get_ps(rps);
	u32 levels = ps->performance_level_count;

	if (level == AMD_DPM_FORCED_LEVEL_HIGH) {
		if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
			return -EINVAL;

		if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
			return -EINVAL;
	} else if (level == AMD_DPM_FORCED_LEVEL_LOW) {
		if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
			return -EINVAL;

		if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
			return -EINVAL;
	} else if (level == AMD_DPM_FORCED_LEVEL_AUTO) {
		if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
			return -EINVAL;

		if (si_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
			return -EINVAL;
	}

	adev->pm.dpm.forced_level = level;

	return 0;
}

#if 0
static int si_set_boot_state(struct amdgpu_device *adev)
{
	return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ?
		0 : -EINVAL;
}
#endif

static int si_set_sw_state(struct amdgpu_device *adev)
{
	return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_SwitchToSwState) == PPSMC_Result_OK) ?
		0 : -EINVAL;
}

static int si_halt_smc(struct amdgpu_device *adev)
{
	if (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_Halt) != PPSMC_Result_OK)
		return -EINVAL;

	return (amdgpu_si_wait_for_smc_inactive(adev) == PPSMC_Result_OK) ?
		0 : -EINVAL;
}

static int si_resume_smc(struct amdgpu_device *adev)
{
	if (amdgpu_si_send_msg_to_smc(adev, PPSMC_FlushDataCache) != PPSMC_Result_OK)
		return -EINVAL;

	return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_Resume) == PPSMC_Result_OK) ?
		0 : -EINVAL;
}

static void si_dpm_start_smc(struct amdgpu_device *adev)
{
	amdgpu_si_program_jump_on_start(adev);
	amdgpu_si_start_smc(adev);
	amdgpu_si_smc_clock(adev, true);
}

static void si_dpm_stop_smc(struct amdgpu_device *adev)
{
	amdgpu_si_reset_smc(adev);
	amdgpu_si_smc_clock(adev, false);
}

static int si_process_firmware_header(struct amdgpu_device *adev)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	u32 tmp;
	int ret;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_stateTable,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->state_table_start = tmp;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_softRegisters,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->soft_regs_start = tmp;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->mc_reg_table_start = tmp;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_fanTable,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->fan_table_start = tmp;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->arb_table_start = tmp;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_CacConfigTable,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->cac_table_start = tmp;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_DteConfiguration,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->dte_table_start = tmp;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_spllTable,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->spll_table_start = tmp;

	ret = amdgpu_si_read_smc_sram_dword(adev,
					    SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
					    SISLANDS_SMC_FIRMWARE_HEADER_PAPMParameters,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	si_pi->papm_cfg_table_start = tmp;

	return ret;
}

static void si_read_clock_registers(struct amdgpu_device *adev)
{
	struct si_power_info *si_pi = si_get_pi(adev);

	si_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
	si_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2);
	si_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3);
	si_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4);
	si_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM);
	si_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
	si_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
	si_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
	si_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
	si_pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL);
	si_pi->clock_registers.mpll_func_cntl = RREG32(MPLL_FUNC_CNTL);
	si_pi->clock_registers.mpll_func_cntl_1 = RREG32(MPLL_FUNC_CNTL_1);
	si_pi->clock_registers.mpll_func_cntl_2 = RREG32(MPLL_FUNC_CNTL_2);
	si_pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1);
	si_pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2);
}

static void si_enable_thermal_protection(struct amdgpu_device *adev,
					  bool enable)
{
	if (enable)
		WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
	else
		WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
}

static void si_enable_acpi_power_management(struct amdgpu_device *adev)
{
	WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
}

#if 0
static int si_enter_ulp_state(struct amdgpu_device *adev)
{
	WREG32(SMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower);

	udelay(25000);

	return 0;
}

static int si_exit_ulp_state(struct amdgpu_device *adev)
{
	int i;

	WREG32(SMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower);

	udelay(7000);

	for (i = 0; i < adev->usec_timeout; i++) {
		if (RREG32(SMC_RESP_0) == 1)
			break;
		udelay(1000);
	}

	return 0;
}
#endif

static int si_notify_smc_display_change(struct amdgpu_device *adev,
				     bool has_display)
{
	PPSMC_Msg msg = has_display ?
		PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay;

	return (amdgpu_si_send_msg_to_smc(adev, msg) == PPSMC_Result_OK) ?
		0 : -EINVAL;
}

static void si_program_response_times(struct amdgpu_device *adev)
{
	u32 voltage_response_time, backbias_response_time, acpi_delay_time, vbi_time_out;
	u32 vddc_dly, acpi_dly, vbi_dly;
	u32 reference_clock;

	si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_mvdd_chg_time, 1);

	voltage_response_time = (u32)adev->pm.dpm.voltage_response_time;
	backbias_response_time = (u32)adev->pm.dpm.backbias_response_time;

	if (voltage_response_time == 0)
		voltage_response_time = 1000;

	acpi_delay_time = 15000;
	vbi_time_out = 100000;

	reference_clock = amdgpu_asic_get_xclk(adev);

	vddc_dly = (voltage_response_time  * reference_clock) / 100;
	acpi_dly = (acpi_delay_time * reference_clock) / 100;
	vbi_dly  = (vbi_time_out * reference_clock) / 100;

	si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_delay_vreg,  vddc_dly);
	si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_delay_acpi,  acpi_dly);
	si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
	si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_mc_block_delay, 0xAA);
}

static void si_program_ds_registers(struct amdgpu_device *adev)
{
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	u32 tmp;

	/* DEEP_SLEEP_CLK_SEL field should be 0x10 on tahiti A0 */
	if (adev->asic_type == CHIP_TAHITI && adev->rev_id == 0x0)
		tmp = 0x10;
	else
		tmp = 0x1;

	if (eg_pi->sclk_deep_sleep) {
		WREG32_P(MISC_CLK_CNTL, DEEP_SLEEP_CLK_SEL(tmp), ~DEEP_SLEEP_CLK_SEL_MASK);
		WREG32_P(CG_SPLL_AUTOSCALE_CNTL, AUTOSCALE_ON_SS_CLEAR,
			 ~AUTOSCALE_ON_SS_CLEAR);
	}
}

static void si_program_display_gap(struct amdgpu_device *adev)
{
	u32 tmp, pipe;
	int i;

	tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
	if (adev->pm.dpm.new_active_crtc_count > 0)
		tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
	else
		tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE);

	if (adev->pm.dpm.new_active_crtc_count > 1)
		tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
	else
		tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE);

	WREG32(CG_DISPLAY_GAP_CNTL, tmp);

	tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG);
	pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT;

	if ((adev->pm.dpm.new_active_crtc_count > 0) &&
	    (!(adev->pm.dpm.new_active_crtcs & (1 << pipe)))) {
		/* find the first active crtc */
		for (i = 0; i < adev->mode_info.num_crtc; i++) {
			if (adev->pm.dpm.new_active_crtcs & (1 << i))
				break;
		}
		if (i == adev->mode_info.num_crtc)
			pipe = 0;
		else
			pipe = i;

		tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK;
		tmp |= DCCG_DISP1_SLOW_SELECT(pipe);
		WREG32(DCCG_DISP_SLOW_SELECT_REG, tmp);
	}

	/* Setting this to false forces the performance state to low if the crtcs are disabled.
	 * This can be a problem on PowerXpress systems or if you want to use the card
	 * for offscreen rendering or compute if there are no crtcs enabled.
	 */
	si_notify_smc_display_change(adev, adev->pm.dpm.new_active_crtc_count > 0);
}

static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);

	if (enable) {
		if (pi->sclk_ss)
			WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
	} else {
		WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
		WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
	}
}

static void si_setup_bsp(struct amdgpu_device *adev)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	u32 xclk = amdgpu_asic_get_xclk(adev);

	r600_calculate_u_and_p(pi->asi,
			       xclk,
			       16,
			       &pi->bsp,
			       &pi->bsu);

	r600_calculate_u_and_p(pi->pasi,
			       xclk,
			       16,
			       &pi->pbsp,
			       &pi->pbsu);


        pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
	pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);

	WREG32(CG_BSP, pi->dsp);
}

static void si_program_git(struct amdgpu_device *adev)
{
	WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK);
}

static void si_program_tp(struct amdgpu_device *adev)
{
	int i;
	enum r600_td td = R600_TD_DFLT;

	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
		WREG32(CG_FFCT_0 + i, (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i])));

	if (td == R600_TD_AUTO)
		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
	else
		WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);

	if (td == R600_TD_UP)
		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);

	if (td == R600_TD_DOWN)
		WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
}

static void si_program_tpp(struct amdgpu_device *adev)
{
	WREG32(CG_TPC, R600_TPC_DFLT);
}

static void si_program_sstp(struct amdgpu_device *adev)
{
	WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
}

static void si_enable_display_gap(struct amdgpu_device *adev)
{
	u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);

	tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
	tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
		DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));

	tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
	tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
		DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
	WREG32(CG_DISPLAY_GAP_CNTL, tmp);
}

static void si_program_vc(struct amdgpu_device *adev)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);

	WREG32(CG_FTV, pi->vrc);
}

static void si_clear_vc(struct amdgpu_device *adev)
{
	WREG32(CG_FTV, 0);
}

static u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock)
{
	u8 mc_para_index;

	if (memory_clock < 10000)
		mc_para_index = 0;
	else if (memory_clock >= 80000)
		mc_para_index = 0x0f;
	else
		mc_para_index = (u8)((memory_clock - 10000) / 5000 + 1);
	return mc_para_index;
}

static u8 si_get_mclk_frequency_ratio(u32 memory_clock, bool strobe_mode)
{
	u8 mc_para_index;

	if (strobe_mode) {
		if (memory_clock < 12500)
			mc_para_index = 0x00;
		else if (memory_clock > 47500)
			mc_para_index = 0x0f;
		else
			mc_para_index = (u8)((memory_clock - 10000) / 2500);
	} else {
		if (memory_clock < 65000)
			mc_para_index = 0x00;
		else if (memory_clock > 135000)
			mc_para_index = 0x0f;
		else
			mc_para_index = (u8)((memory_clock - 60000) / 5000);
	}
	return mc_para_index;
}

static u8 si_get_strobe_mode_settings(struct amdgpu_device *adev, u32 mclk)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	bool strobe_mode = false;
	u8 result = 0;

	if (mclk <= pi->mclk_strobe_mode_threshold)
		strobe_mode = true;

	if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5)
		result = si_get_mclk_frequency_ratio(mclk, strobe_mode);
	else
		result = si_get_ddr3_mclk_frequency_ratio(mclk);

	if (strobe_mode)
		result |= SISLANDS_SMC_STROBE_ENABLE;

	return result;
}

static int si_upload_firmware(struct amdgpu_device *adev)
{
	struct si_power_info *si_pi = si_get_pi(adev);

	amdgpu_si_reset_smc(adev);
	amdgpu_si_smc_clock(adev, false);

	return amdgpu_si_load_smc_ucode(adev, si_pi->sram_end);
}

static bool si_validate_phase_shedding_tables(struct amdgpu_device *adev,
					      const struct atom_voltage_table *table,
					      const struct amdgpu_phase_shedding_limits_table *limits)
{
	u32 data, num_bits, num_levels;

	if ((table == NULL) || (limits == NULL))
		return false;

	data = table->mask_low;

	num_bits = hweight32(data);

	if (num_bits == 0)
		return false;

	num_levels = (1 << num_bits);

	if (table->count != num_levels)
		return false;

	if (limits->count != (num_levels - 1))
		return false;

	return true;
}

static void si_trim_voltage_table_to_fit_state_table(struct amdgpu_device *adev,
					      u32 max_voltage_steps,
					      struct atom_voltage_table *voltage_table)
{
	unsigned int i, diff;

	if (voltage_table->count <= max_voltage_steps)
		return;

	diff = voltage_table->count - max_voltage_steps;

	for (i= 0; i < max_voltage_steps; i++)
		voltage_table->entries[i] = voltage_table->entries[i + diff];

	voltage_table->count = max_voltage_steps;
}

static int si_get_svi2_voltage_table(struct amdgpu_device *adev,
				     struct amdgpu_clock_voltage_dependency_table *voltage_dependency_table,
				     struct atom_voltage_table *voltage_table)
{
	u32 i;

	if (voltage_dependency_table == NULL)
		return -EINVAL;

	voltage_table->mask_low = 0;
	voltage_table->phase_delay = 0;

	voltage_table->count = voltage_dependency_table->count;
	for (i = 0; i < voltage_table->count; i++) {
		voltage_table->entries[i].value = voltage_dependency_table->entries[i].v;
		voltage_table->entries[i].smio_low = 0;
	}

	return 0;
}

static int si_construct_voltage_tables(struct amdgpu_device *adev)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	int ret;

	if (pi->voltage_control) {
		ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDC,
						    VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table);
		if (ret)
			return ret;

		if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
			si_trim_voltage_table_to_fit_state_table(adev,
								 SISLANDS_MAX_NO_VREG_STEPS,
								 &eg_pi->vddc_voltage_table);
	} else if (si_pi->voltage_control_svi2) {
		ret = si_get_svi2_voltage_table(adev,
						&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
						&eg_pi->vddc_voltage_table);
		if (ret)
			return ret;
	} else {
		return -EINVAL;
	}

	if (eg_pi->vddci_control) {
		ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDCI,
						    VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddci_voltage_table);
		if (ret)
			return ret;

		if (eg_pi->vddci_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
			si_trim_voltage_table_to_fit_state_table(adev,
								 SISLANDS_MAX_NO_VREG_STEPS,
								 &eg_pi->vddci_voltage_table);
	}
	if (si_pi->vddci_control_svi2) {
		ret = si_get_svi2_voltage_table(adev,
						&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
						&eg_pi->vddci_voltage_table);
		if (ret)
			return ret;
	}

	if (pi->mvdd_control) {
		ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_MVDDC,
						    VOLTAGE_OBJ_GPIO_LUT, &si_pi->mvdd_voltage_table);

		if (ret) {
			pi->mvdd_control = false;
			return ret;
		}

		if (si_pi->mvdd_voltage_table.count == 0) {
			pi->mvdd_control = false;
			return -EINVAL;
		}

		if (si_pi->mvdd_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
			si_trim_voltage_table_to_fit_state_table(adev,
								 SISLANDS_MAX_NO_VREG_STEPS,
								 &si_pi->mvdd_voltage_table);
	}

	if (si_pi->vddc_phase_shed_control) {
		ret = amdgpu_atombios_get_voltage_table(adev, VOLTAGE_TYPE_VDDC,
						    VOLTAGE_OBJ_PHASE_LUT, &si_pi->vddc_phase_shed_table);
		if (ret)
			si_pi->vddc_phase_shed_control = false;

		if ((si_pi->vddc_phase_shed_table.count == 0) ||
		    (si_pi->vddc_phase_shed_table.count > SISLANDS_MAX_NO_VREG_STEPS))
			si_pi->vddc_phase_shed_control = false;
	}

	return 0;
}

static void si_populate_smc_voltage_table(struct amdgpu_device *adev,
					  const struct atom_voltage_table *voltage_table,
					  SISLANDS_SMC_STATETABLE *table)
{
	unsigned int i;

	for (i = 0; i < voltage_table->count; i++)
		table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low);
}

static int si_populate_smc_voltage_tables(struct amdgpu_device *adev,
					  SISLANDS_SMC_STATETABLE *table)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	u8 i;

	if (si_pi->voltage_control_svi2) {
		si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svc,
			si_pi->svc_gpio_id);
		si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_svi_rework_gpio_id_svd,
			si_pi->svd_gpio_id);
		si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_svi_rework_plat_type,
					   2);
	} else {
		if (eg_pi->vddc_voltage_table.count) {
			si_populate_smc_voltage_table(adev, &eg_pi->vddc_voltage_table, table);
			table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
				cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);

			for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
				if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
					table->maxVDDCIndexInPPTable = i;
					break;
				}
			}
		}

		if (eg_pi->vddci_voltage_table.count) {
			si_populate_smc_voltage_table(adev, &eg_pi->vddci_voltage_table, table);

			table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] =
				cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);
		}


		if (si_pi->mvdd_voltage_table.count) {
			si_populate_smc_voltage_table(adev, &si_pi->mvdd_voltage_table, table);

			table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] =
				cpu_to_be32(si_pi->mvdd_voltage_table.mask_low);
		}

		if (si_pi->vddc_phase_shed_control) {
			if (si_validate_phase_shedding_tables(adev, &si_pi->vddc_phase_shed_table,
							      &adev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
				si_populate_smc_voltage_table(adev, &si_pi->vddc_phase_shed_table, table);

				table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING] =
					cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);

				si_write_smc_soft_register(adev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
							   (u32)si_pi->vddc_phase_shed_table.phase_delay);
			} else {
				si_pi->vddc_phase_shed_control = false;
			}
		}
	}

	return 0;
}

static int si_populate_voltage_value(struct amdgpu_device *adev,
				     const struct atom_voltage_table *table,
				     u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage)
{
	unsigned int i;

	for (i = 0; i < table->count; i++) {
		if (value <= table->entries[i].value) {
			voltage->index = (u8)i;
			voltage->value = cpu_to_be16(table->entries[i].value);
			break;
		}
	}

	if (i >= table->count)
		return -EINVAL;

	return 0;
}

static int si_populate_mvdd_value(struct amdgpu_device *adev, u32 mclk,
				  SISLANDS_SMC_VOLTAGE_VALUE *voltage)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);

	if (pi->mvdd_control) {
		if (mclk <= pi->mvdd_split_frequency)
			voltage->index = 0;
		else
			voltage->index = (u8)(si_pi->mvdd_voltage_table.count) - 1;

		voltage->value = cpu_to_be16(si_pi->mvdd_voltage_table.entries[voltage->index].value);
	}
	return 0;
}

static int si_get_std_voltage_value(struct amdgpu_device *adev,
				    SISLANDS_SMC_VOLTAGE_VALUE *voltage,
				    u16 *std_voltage)
{
	u16 v_index;
	bool voltage_found = false;
	*std_voltage = be16_to_cpu(voltage->value);

	if (adev->pm.dpm.dyn_state.cac_leakage_table.entries) {
		if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE) {
			if (adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL)
				return -EINVAL;

			for (v_index = 0; (u32)v_index < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
				if (be16_to_cpu(voltage->value) ==
				    (u16)adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
					voltage_found = true;
					if ((u32)v_index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
						*std_voltage =
							adev->pm.dpm.dyn_state.cac_leakage_table.entries[v_index].vddc;
					else
						*std_voltage =
							adev->pm.dpm.dyn_state.cac_leakage_table.entries[adev->pm.dpm.dyn_state.cac_leakage_table.count-1].vddc;
					break;
				}
			}

			if (!voltage_found) {
				for (v_index = 0; (u32)v_index < adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
					if (be16_to_cpu(voltage->value) <=
					    (u16)adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
						voltage_found = true;
						if ((u32)v_index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
							*std_voltage =
								adev->pm.dpm.dyn_state.cac_leakage_table.entries[v_index].vddc;
						else
							*std_voltage =
								adev->pm.dpm.dyn_state.cac_leakage_table.entries[adev->pm.dpm.dyn_state.cac_leakage_table.count-1].vddc;
						break;
					}
				}
			}
		} else {
			if ((u32)voltage->index < adev->pm.dpm.dyn_state.cac_leakage_table.count)
				*std_voltage = adev->pm.dpm.dyn_state.cac_leakage_table.entries[voltage->index].vddc;
		}
	}

	return 0;
}

static int si_populate_std_voltage_value(struct amdgpu_device *adev,
					 u16 value, u8 index,
					 SISLANDS_SMC_VOLTAGE_VALUE *voltage)
{
	voltage->index = index;
	voltage->value = cpu_to_be16(value);

	return 0;
}

static int si_populate_phase_shedding_value(struct amdgpu_device *adev,
					    const struct amdgpu_phase_shedding_limits_table *limits,
					    u16 voltage, u32 sclk, u32 mclk,
					    SISLANDS_SMC_VOLTAGE_VALUE *smc_voltage)
{
	unsigned int i;

	for (i = 0; i < limits->count; i++) {
		if ((voltage <= limits->entries[i].voltage) &&
		    (sclk <= limits->entries[i].sclk) &&
		    (mclk <= limits->entries[i].mclk))
			break;
	}

	smc_voltage->phase_settings = (u8)i;

	return 0;
}

static int si_init_arb_table_index(struct amdgpu_device *adev)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	u32 tmp;
	int ret;

	ret = amdgpu_si_read_smc_sram_dword(adev, si_pi->arb_table_start,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	tmp &= 0x00FFFFFF;
	tmp |= MC_CG_ARB_FREQ_F1 << 24;

	return amdgpu_si_write_smc_sram_dword(adev, si_pi->arb_table_start,
					      tmp, si_pi->sram_end);
}

static int si_initial_switch_from_arb_f0_to_f1(struct amdgpu_device *adev)
{
	return ni_copy_and_switch_arb_sets(adev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
}

static int si_reset_to_default(struct amdgpu_device *adev)
{
	return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ?
		0 : -EINVAL;
}

static int si_force_switch_to_arb_f0(struct amdgpu_device *adev)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	u32 tmp;
	int ret;

	ret = amdgpu_si_read_smc_sram_dword(adev, si_pi->arb_table_start,
					    &tmp, si_pi->sram_end);
	if (ret)
		return ret;

	tmp = (tmp >> 24) & 0xff;

	if (tmp == MC_CG_ARB_FREQ_F0)
		return 0;

	return ni_copy_and_switch_arb_sets(adev, tmp, MC_CG_ARB_FREQ_F0);
}

static u32 si_calculate_memory_refresh_rate(struct amdgpu_device *adev,
					    u32 engine_clock)
{
	u32 dram_rows;
	u32 dram_refresh_rate;
	u32 mc_arb_rfsh_rate;
	u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;

	if (tmp >= 4)
		dram_rows = 16384;
	else
		dram_rows = 1 << (tmp + 10);

	dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3);
	mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;

	return mc_arb_rfsh_rate;
}

static int si_populate_memory_timing_parameters(struct amdgpu_device *adev,
						struct rv7xx_pl *pl,
						SMC_SIslands_MCArbDramTimingRegisterSet *arb_regs)
{
	u32 dram_timing;
	u32 dram_timing2;
	u32 burst_time;

	arb_regs->mc_arb_rfsh_rate =
		(u8)si_calculate_memory_refresh_rate(adev, pl->sclk);

	amdgpu_atombios_set_engine_dram_timings(adev,
					    pl->sclk,
		                            pl->mclk);

	dram_timing  = RREG32(MC_ARB_DRAM_TIMING);
	dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
	burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK;

	arb_regs->mc_arb_dram_timing  = cpu_to_be32(dram_timing);
	arb_regs->mc_arb_dram_timing2 = cpu_to_be32(dram_timing2);
	arb_regs->mc_arb_burst_time = (u8)burst_time;

	return 0;
}

static int si_do_program_memory_timing_parameters(struct amdgpu_device *adev,
						  struct amdgpu_ps *amdgpu_state,
						  unsigned int first_arb_set)
{
	struct si_power_info *si_pi = si_get_pi(adev);
	struct  si_ps *state = si_get_ps(amdgpu_state);
	SMC_SIslands_MCArbDramTimingRegisterSet arb_regs = { 0 };
	int i, ret = 0;

	for (i = 0; i < state->performance_level_count; i++) {
		ret = si_populate_memory_timing_parameters(adev, &state->performance_levels[i], &arb_regs);
		if (ret)
			break;
		ret = amdgpu_si_copy_bytes_to_smc(adev,
						  si_pi->arb_table_start +
						  offsetof(SMC_SIslands_MCArbDramTimingRegisters, data) +
						  sizeof(SMC_SIslands_MCArbDramTimingRegisterSet) * (first_arb_set + i),
						  (u8 *)&arb_regs,
						  sizeof(SMC_SIslands_MCArbDramTimingRegisterSet),
						  si_pi->sram_end);
		if (ret)
			break;
	}

	return ret;
}

static int si_program_memory_timing_parameters(struct amdgpu_device *adev,
					       struct amdgpu_ps *amdgpu_new_state)
{
	return si_do_program_memory_timing_parameters(adev, amdgpu_new_state,
						      SISLANDS_DRIVER_STATE_ARB_INDEX);
}

static int si_populate_initial_mvdd_value(struct amdgpu_device *adev,
					  struct SISLANDS_SMC_VOLTAGE_VALUE *voltage)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);

	if (pi->mvdd_control)
		return si_populate_voltage_value(adev, &si_pi->mvdd_voltage_table,
						 si_pi->mvdd_bootup_value, voltage);

	return 0;
}

static int si_populate_smc_initial_state(struct amdgpu_device *adev,
					 struct amdgpu_ps *amdgpu_initial_state,
					 SISLANDS_SMC_STATETABLE *table)
{
	struct  si_ps *initial_state = si_get_ps(amdgpu_initial_state);
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	u32 reg;
	int ret;

	table->initialState.levels[0].mclk.vDLL_CNTL =
		cpu_to_be32(si_pi->clock_registers.dll_cntl);
	table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
		cpu_to_be32(si_pi->clock_registers.mclk_pwrmgt_cntl);
	table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
		cpu_to_be32(si_pi->clock_registers.mpll_ad_func_cntl);
	table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
		cpu_to_be32(si_pi->clock_registers.mpll_dq_func_cntl);
	table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL =
		cpu_to_be32(si_pi->clock_registers.mpll_func_cntl);
	table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
		cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_1);
	table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
		cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_2);
	table->initialState.levels[0].mclk.vMPLL_SS =
		cpu_to_be32(si_pi->clock_registers.mpll_ss1);
	table->initialState.levels[0].mclk.vMPLL_SS2 =
		cpu_to_be32(si_pi->clock_registers.mpll_ss2);

	table->initialState.levels[0].mclk.mclk_value =
		cpu_to_be32(initial_state->performance_levels[0].mclk);

	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
		cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl);
	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
		cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_2);
	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
		cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_3);
	table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
		cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_4);
	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
		cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum);
	table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2  =
		cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum_2);

	table->initialState.levels[0].sclk.sclk_value =
		cpu_to_be32(initial_state->performance_levels[0].sclk);

	table->initialState.levels[0].arbRefreshState =
		SISLANDS_INITIAL_STATE_ARB_INDEX;

	table->initialState.levels[0].ACIndex = 0;

	ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
					initial_state->performance_levels[0].vddc,
					&table->initialState.levels[0].vddc);

	if (!ret) {
		u16 std_vddc;

		ret = si_get_std_voltage_value(adev,
					       &table->initialState.levels[0].vddc,
					       &std_vddc);
		if (!ret)
			si_populate_std_voltage_value(adev, std_vddc,
						      table->initialState.levels[0].vddc.index,
						      &table->initialState.levels[0].std_vddc);
	}

	if (eg_pi->vddci_control)
		si_populate_voltage_value(adev,
					  &eg_pi->vddci_voltage_table,
					  initial_state->performance_levels[0].vddci,
					  &table->initialState.levels[0].vddci);

	if (si_pi->vddc_phase_shed_control)
		si_populate_phase_shedding_value(adev,
						 &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
						 initial_state->performance_levels[0].vddc,
						 initial_state->performance_levels[0].sclk,
						 initial_state->performance_levels[0].mclk,
						 &table->initialState.levels[0].vddc);

	si_populate_initial_mvdd_value(adev, &table->initialState.levels[0].mvdd);

	reg = CG_R(0xffff) | CG_L(0);
	table->initialState.levels[0].aT = cpu_to_be32(reg);
	table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
	table->initialState.levels[0].gen2PCIE = (u8)si_pi->boot_pcie_gen;

	if (adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5) {
		table->initialState.levels[0].strobeMode =
			si_get_strobe_mode_settings(adev,
						    initial_state->performance_levels[0].mclk);

		if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
			table->initialState.levels[0].mcFlags = SISLANDS_SMC_MC_EDC_RD_FLAG | SISLANDS_SMC_MC_EDC_WR_FLAG;
		else
			table->initialState.levels[0].mcFlags =  0;
	}

	table->initialState.levelCount = 1;

	table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;

	table->initialState.levels[0].dpm2.MaxPS = 0;
	table->initialState.levels[0].dpm2.NearTDPDec = 0;
	table->initialState.levels[0].dpm2.AboveSafeInc = 0;
	table->initialState.levels[0].dpm2.BelowSafeInc = 0;
	table->initialState.levels[0].dpm2.PwrEfficiencyRatio = 0;

	reg = MIN_POWER_MASK | MAX_POWER_MASK;
	table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);

	reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
	table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);

	return 0;
}

static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
				      SISLANDS_SMC_STATETABLE *table)
{
	struct rv7xx_power_info *pi = rv770_get_pi(adev);
	struct evergreen_power_info *eg_pi = evergreen_get_pi(adev);
	struct si_power_info *si_pi = si_get_pi(adev);
	u32 spll_func_cntl = si_pi->clock_registers.cg_spll_func_cntl;
	u32 spll_func_cntl_2 = si_pi->clock_registers.cg_spll_func_cntl_2;
	u32 spll_func_cntl_3 = si_pi->clock_registers.cg_spll_func_cntl_3;
	u32 spll_func_cntl_4 = si_pi->clock_registers.cg_spll_func_cntl_4;
	u32 dll_cntl = si_pi->clock_registers.dll_cntl;
	u32 mclk_pwrmgt_cntl = si_pi->clock_registers.mclk_pwrmgt_cntl;
	u32 mpll_ad_func_cntl = si_pi->clock_registers.mpll_ad_func_cntl;
	u32 mpll_dq_func_cntl = si_pi->clock_registers.mpll_dq_func_cntl;
	u32 mpll_func_cntl = si_pi->clock_registers.mpll_func_cntl;
	u32 mpll_func_cntl_1 = si_pi->clock_registers.mpll_func_cntl_1;
	u32 mpll_func_cntl_2 = si_pi->clock_registers.mpll_func_cntl_2;
	u32 reg;
	int ret;

	table->ACPIState = table->initialState;

	table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;

	if (pi->acpi_vddc) {
		ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
						pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
		if (!ret) {
			u16 std_vddc;

			ret = si_get_std_voltage_value(adev,
						       &table->ACPIState.levels[0].vddc, &std_vddc);
			if (!ret)
				si_populate_std_voltage_value(adev, std_vddc,
							      table->ACPIState.levels[0].vddc.index,
							      &table->ACPIState.levels[0].std_vddc);
		}
		table->ACPIState.levels[0].gen2PCIE = si_pi->acpi_pcie_gen;

		if (si_pi->vddc_phase_shed_control) {
			si_populate_phase_shedding_value(adev,
							 &adev->pm.dpm.dyn_state.phase_shedding_limits_table,
							 pi->acpi_vddc,
							 0,
							 0,
							 &table->ACPIState.levels[0].vddc);
		}
	} else {
		ret = si_populate_voltage_value(adev, &eg_pi->vddc_voltage_table,
						pi->min_vddc_in_table, &table->ACPIState.levels[0].vddc);
		if (!ret) {
			u16 std_vddc;

			ret = si_get_std_voltage_value(adev,
						       &