123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616 |
- /*
- * Copyright (C) 2013, Intel Corporation
- * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
- *
- * Ported from Intel released Quark UEFI BIOS
- * QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei
- *
- * SPDX-License-Identifier: Intel
- */
- #include <common.h>
- #include <pci.h>
- #include <asm/arch/device.h>
- #include <asm/arch/mrc.h>
- #include <asm/arch/msg_port.h>
- #include "mrc_util.h"
- #include "hte.h"
- #include "smc.h"
- /* t_ck clock period in picoseconds per speed index 800, 1066, 1333 */
- static const uint32_t t_ck[3] = {
- 2500,
- 1875,
- 1500
- };
- /* Global variables */
- static const uint16_t ddr_wclk[] = {193, 158};
- #ifdef BACKUP_WCTL
- static const uint16_t ddr_wctl[] = {1, 217};
- #endif
- #ifdef BACKUP_WCMD
- static const uint16_t ddr_wcmd[] = {1, 220};
- #endif
- #ifdef BACKUP_RCVN
- static const uint16_t ddr_rcvn[] = {129, 498};
- #endif
- #ifdef BACKUP_WDQS
- static const uint16_t ddr_wdqs[] = {65, 289};
- #endif
- #ifdef BACKUP_RDQS
- static const uint8_t ddr_rdqs[] = {32, 24};
- #endif
- #ifdef BACKUP_WDQ
- static const uint16_t ddr_wdq[] = {32, 257};
- #endif
- /* Stop self refresh driven by MCU */
- void clear_self_refresh(struct mrc_params *mrc_params)
- {
- ENTERFN();
- /* clear the PMSTS Channel Self Refresh bits */
- mrc_write_mask(MEM_CTLR, PMSTS, PMSTS_DISR, PMSTS_DISR);
- LEAVEFN();
- }
- /* It will initialize timing registers in the MCU (DTR0..DTR4) */
- void prog_ddr_timing_control(struct mrc_params *mrc_params)
- {
- uint8_t tcl, wl;
- uint8_t trp, trcd, tras, twr, twtr, trrd, trtp, tfaw;
- uint32_t tck;
- u32 dtr0, dtr1, dtr2, dtr3, dtr4;
- u32 tmp1, tmp2;
- ENTERFN();
- /* mcu_init starts */
- mrc_post_code(0x02, 0x00);
- dtr0 = msg_port_read(MEM_CTLR, DTR0);
- dtr1 = msg_port_read(MEM_CTLR, DTR1);
- dtr2 = msg_port_read(MEM_CTLR, DTR2);
- dtr3 = msg_port_read(MEM_CTLR, DTR3);
- dtr4 = msg_port_read(MEM_CTLR, DTR4);
- tck = t_ck[mrc_params->ddr_speed]; /* Clock in picoseconds */
- tcl = mrc_params->params.cl; /* CAS latency in clocks */
- trp = tcl; /* Per CAT MRC */
- trcd = tcl; /* Per CAT MRC */
- tras = MCEIL(mrc_params->params.ras, tck);
- /* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
- twr = MCEIL(15000, tck);
- twtr = MCEIL(mrc_params->params.wtr, tck);
- trrd = MCEIL(mrc_params->params.rrd, tck);
- trtp = 4; /* Valid for 800 and 1066, use 5 for 1333 */
- tfaw = MCEIL(mrc_params->params.faw, tck);
- wl = 5 + mrc_params->ddr_speed;
- dtr0 &= ~DTR0_DFREQ_MASK;
- dtr0 |= mrc_params->ddr_speed;
- dtr0 &= ~DTR0_TCL_MASK;
- tmp1 = tcl - 5;
- dtr0 |= ((tcl - 5) << 12);
- dtr0 &= ~DTR0_TRP_MASK;
- dtr0 |= ((trp - 5) << 4); /* 5 bit DRAM Clock */
- dtr0 &= ~DTR0_TRCD_MASK;
- dtr0 |= ((trcd - 5) << 8); /* 5 bit DRAM Clock */
- dtr1 &= ~DTR1_TWCL_MASK;
- tmp2 = wl - 3;
- dtr1 |= (wl - 3);
- dtr1 &= ~DTR1_TWTP_MASK;
- dtr1 |= ((wl + 4 + twr - 14) << 8); /* Change to tWTP */
- dtr1 &= ~DTR1_TRTP_MASK;
- dtr1 |= ((MMAX(trtp, 4) - 3) << 28); /* 4 bit DRAM Clock */
- dtr1 &= ~DTR1_TRRD_MASK;
- dtr1 |= ((trrd - 4) << 24); /* 4 bit DRAM Clock */
- dtr1 &= ~DTR1_TCMD_MASK;
- dtr1 |= (1 << 4);
- dtr1 &= ~DTR1_TRAS_MASK;
- dtr1 |= ((tras - 14) << 20); /* 6 bit DRAM Clock */
- dtr1 &= ~DTR1_TFAW_MASK;
- dtr1 |= ((((tfaw + 1) >> 1) - 5) << 16);/* 4 bit DRAM Clock */
- /* Set 4 Clock CAS to CAS delay (multi-burst) */
- dtr1 &= ~DTR1_TCCD_MASK;
- dtr2 &= ~DTR2_TRRDR_MASK;
- dtr2 |= 1;
- dtr2 &= ~DTR2_TWWDR_MASK;
- dtr2 |= (2 << 8);
- dtr2 &= ~DTR2_TRWDR_MASK;
- dtr2 |= (2 << 16);
- dtr3 &= ~DTR3_TWRDR_MASK;
- dtr3 |= 2;
- dtr3 &= ~DTR3_TXXXX_MASK;
- dtr3 |= (2 << 4);
- dtr3 &= ~DTR3_TRWSR_MASK;
- if (mrc_params->ddr_speed == DDRFREQ_800) {
- /* Extended RW delay (+1) */
- dtr3 |= ((tcl - 5 + 1) << 8);
- } else if (mrc_params->ddr_speed == DDRFREQ_1066) {
- /* Extended RW delay (+1) */
- dtr3 |= ((tcl - 5 + 1) << 8);
- }
- dtr3 &= ~DTR3_TWRSR_MASK;
- dtr3 |= ((4 + wl + twtr - 11) << 13);
- dtr3 &= ~DTR3_TXP_MASK;
- if (mrc_params->ddr_speed == DDRFREQ_800)
- dtr3 |= ((MMAX(0, 1 - 1)) << 22);
- else
- dtr3 |= ((MMAX(0, 2 - 1)) << 22);
- dtr4 &= ~DTR4_WRODTSTRT_MASK;
- dtr4 |= 1;
- dtr4 &= ~DTR4_WRODTSTOP_MASK;
- dtr4 |= (1 << 4);
- dtr4 &= ~DTR4_XXXX1_MASK;
- dtr4 |= ((1 + tmp1 - tmp2 + 2) << 8);
- dtr4 &= ~DTR4_XXXX2_MASK;
- dtr4 |= ((1 + tmp1 - tmp2 + 2) << 12);
- dtr4 &= ~(DTR4_ODTDIS | DTR4_TRGSTRDIS);
- msg_port_write(MEM_CTLR, DTR0, dtr0);
- msg_port_write(MEM_CTLR, DTR1, dtr1);
- msg_port_write(MEM_CTLR, DTR2, dtr2);
- msg_port_write(MEM_CTLR, DTR3, dtr3);
- msg_port_write(MEM_CTLR, DTR4, dtr4);
- LEAVEFN();
- }
- /* Configure MCU before jedec init sequence */
- void prog_decode_before_jedec(struct mrc_params *mrc_params)
- {
- u32 drp;
- u32 drfc;
- u32 dcal;
- u32 dsch;
- u32 dpmc0;
- ENTERFN();
- /* Disable power saving features */
- dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
- dpmc0 |= (DPMC0_CLKGTDIS | DPMC0_DISPWRDN);
- dpmc0 &= ~DPMC0_PCLSTO_MASK;
- dpmc0 &= ~DPMC0_DYNSREN;
- msg_port_write(MEM_CTLR, DPMC0, dpmc0);
- /* Disable out of order transactions */
- dsch = msg_port_read(MEM_CTLR, DSCH);
- dsch |= (DSCH_OOODIS | DSCH_NEWBYPDIS);
- msg_port_write(MEM_CTLR, DSCH, dsch);
- /* Disable issuing the REF command */
- drfc = msg_port_read(MEM_CTLR, DRFC);
- drfc &= ~DRFC_TREFI_MASK;
- msg_port_write(MEM_CTLR, DRFC, drfc);
- /* Disable ZQ calibration short */
- dcal = msg_port_read(MEM_CTLR, DCAL);
- dcal &= ~DCAL_ZQCINT_MASK;
- dcal &= ~DCAL_SRXZQCL_MASK;
- msg_port_write(MEM_CTLR, DCAL, dcal);
- /*
- * Training performed in address mode 0, rank population has limited
- * impact, however simulator complains if enabled non-existing rank.
- */
- drp = 0;
- if (mrc_params->rank_enables & 1)
- drp |= DRP_RKEN0;
- if (mrc_params->rank_enables & 2)
- drp |= DRP_RKEN1;
- msg_port_write(MEM_CTLR, DRP, drp);
- LEAVEFN();
- }
- /*
- * After Cold Reset, BIOS should set COLDWAKE bit to 1 before
- * sending the WAKE message to the Dunit.
- *
- * For Standby Exit, or any other mode in which the DRAM is in
- * SR, this bit must be set to 0.
- */
- void perform_ddr_reset(struct mrc_params *mrc_params)
- {
- ENTERFN();
- /* Set COLDWAKE bit before sending the WAKE message */
- mrc_write_mask(MEM_CTLR, DRMC, DRMC_COLDWAKE, DRMC_COLDWAKE);
- /* Send wake command to DUNIT (MUST be done before JEDEC) */
- dram_wake_command();
- /* Set default value */
- msg_port_write(MEM_CTLR, DRMC,
- mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0);
- LEAVEFN();
- }
- /*
- * This function performs some initialization on the DDRIO unit.
- * This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
- */
- void ddrphy_init(struct mrc_params *mrc_params)
- {
- uint32_t temp;
- uint8_t ch; /* channel counter */
- uint8_t rk; /* rank counter */
- uint8_t bl_grp; /* byte lane group counter (2 BLs per module) */
- uint8_t bl_divisor = 1; /* byte lane divisor */
- /* For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333 */
- uint8_t speed = mrc_params->ddr_speed & 3;
- uint8_t cas;
- uint8_t cwl;
- ENTERFN();
- cas = mrc_params->params.cl;
- cwl = 5 + mrc_params->ddr_speed;
- /* ddrphy_init starts */
- mrc_post_code(0x03, 0x00);
- /*
- * HSD#231531
- * Make sure IOBUFACT is deasserted before initializing the DDR PHY
- *
- * HSD#234845
- * Make sure WRPTRENABLE is deasserted before initializing the DDR PHY
- */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- /* Deassert DDRPHY Initialization Complete */
- mrc_alt_write_mask(DDRPHY,
- CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
- ~(1 << 20), 1 << 20); /* SPID_INIT_COMPLETE=0 */
- /* Deassert IOBUFACT */
- mrc_alt_write_mask(DDRPHY,
- CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
- ~(1 << 2), 1 << 2); /* IOBUFACTRST_N=0 */
- /* Disable WRPTR */
- mrc_alt_write_mask(DDRPHY,
- CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
- ~(1 << 0), 1 << 0); /* WRPTRENABLE=0 */
- }
- }
- /* Put PHY in reset */
- mrc_alt_write_mask(DDRPHY, MASTERRSTN, 0, 1);
- /* Initialize DQ01, DQ23, CMD, CLK-CTL, COMP modules */
- /* STEP0 */
- mrc_post_code(0x03, 0x10);
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- /* DQ01-DQ23 */
- for (bl_grp = 0;
- bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
- bl_grp++) {
- /* Analog MUX select - IO2xCLKSEL */
- mrc_alt_write_mask(DDRPHY,
- DQOBSCKEBBCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- bl_grp ? 0 : (1 << 22), 1 << 22);
- /* ODT Strength */
- switch (mrc_params->rd_odt_value) {
- case 1:
- temp = 0x3;
- break; /* 60 ohm */
- case 2:
- temp = 0x3;
- break; /* 120 ohm */
- case 3:
- temp = 0x3;
- break; /* 180 ohm */
- default:
- temp = 0x3;
- break; /* 120 ohm */
- }
- /* ODT strength */
- mrc_alt_write_mask(DDRPHY,
- B0RXIOBUFCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- temp << 5, 0x60);
- /* ODT strength */
- mrc_alt_write_mask(DDRPHY,
- B1RXIOBUFCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- temp << 5, 0x60);
- /* Dynamic ODT/DIFFAMP */
- temp = (cas << 24) | (cas << 16) |
- (cas << 8) | (cas << 0);
- switch (speed) {
- case 0:
- temp -= 0x01010101;
- break; /* 800 */
- case 1:
- temp -= 0x02020202;
- break; /* 1066 */
- case 2:
- temp -= 0x03030303;
- break; /* 1333 */
- case 3:
- temp -= 0x04040404;
- break; /* 1600 */
- }
- /* Launch Time: ODT, DIFFAMP, ODT, DIFFAMP */
- mrc_alt_write_mask(DDRPHY,
- B01LATCTL1 +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- temp, 0x1f1f1f1f);
- switch (speed) {
- /* HSD#234715 */
- case 0:
- temp = (0x06 << 16) | (0x07 << 8);
- break; /* 800 */
- case 1:
- temp = (0x07 << 16) | (0x08 << 8);
- break; /* 1066 */
- case 2:
- temp = (0x09 << 16) | (0x0a << 8);
- break; /* 1333 */
- case 3:
- temp = (0x0a << 16) | (0x0b << 8);
- break; /* 1600 */
- }
- /* On Duration: ODT, DIFFAMP */
- mrc_alt_write_mask(DDRPHY,
- B0ONDURCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- temp, 0x003f3f00);
- /* On Duration: ODT, DIFFAMP */
- mrc_alt_write_mask(DDRPHY,
- B1ONDURCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- temp, 0x003f3f00);
- switch (mrc_params->rd_odt_value) {
- case 0:
- /* override DIFFAMP=on, ODT=off */
- temp = (0x3f << 16) | (0x3f << 10);
- break;
- default:
- /* override DIFFAMP=on, ODT=on */
- temp = (0x3f << 16) | (0x2a << 10);
- break;
- }
- /* Override: DIFFAMP, ODT */
- mrc_alt_write_mask(DDRPHY,
- B0OVRCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- temp, 0x003ffc00);
- /* Override: DIFFAMP, ODT */
- mrc_alt_write_mask(DDRPHY,
- B1OVRCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- temp, 0x003ffc00);
- /* DLL Setup */
- /* 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO) */
- mrc_alt_write_mask(DDRPHY,
- B0LATCTL0 +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- ((cas + 7) << 16) | ((cas - 4) << 8) |
- ((cwl - 2) << 0), 0x003f1f1f);
- mrc_alt_write_mask(DDRPHY,
- B1LATCTL0 +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- ((cas + 7) << 16) | ((cas - 4) << 8) |
- ((cwl - 2) << 0), 0x003f1f1f);
- /* RCVEN Bypass (PO) */
- mrc_alt_write_mask(DDRPHY,
- B0RXIOBUFCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 0, 0x81);
- mrc_alt_write_mask(DDRPHY,
- B1RXIOBUFCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 0, 0x81);
- /* TX */
- mrc_alt_write_mask(DDRPHY,
- DQCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 1 << 16, 1 << 16);
- mrc_alt_write_mask(DDRPHY,
- B01PTRCTL1 +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 1 << 8, 1 << 8);
- /* RX (PO) */
- /* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
- mrc_alt_write_mask(DDRPHY,
- B0VREFCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- (0x03 << 2) | (0x0 << 1) | (0x0 << 0),
- 0xff);
- /* Internal Vref Code, Enable#, Ext_or_Int (1=Ext) */
- mrc_alt_write_mask(DDRPHY,
- B1VREFCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- (0x03 << 2) | (0x0 << 1) | (0x0 << 0),
- 0xff);
- /* Per-Bit De-Skew Enable */
- mrc_alt_write_mask(DDRPHY,
- B0RXIOBUFCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 0, 0x10);
- /* Per-Bit De-Skew Enable */
- mrc_alt_write_mask(DDRPHY,
- B1RXIOBUFCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 0, 0x10);
- }
- /* CLKEBB */
- mrc_alt_write_mask(DDRPHY,
- CMDOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
- 0, 1 << 23);
- /* Enable tristate control of cmd/address bus */
- mrc_alt_write_mask(DDRPHY,
- CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
- 0, 0x03);
- /* ODT RCOMP */
- mrc_alt_write_mask(DDRPHY,
- CMDRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
- (0x03 << 5) | (0x03 << 0), 0x3ff);
- /* CMDPM* registers must be programmed in this order */
- /* Turn On Delays: SFR (regulator), MPLL */
- mrc_alt_write_mask(DDRPHY,
- CMDPMDLYREG4 + ch * DDRIOCCC_CH_OFFSET,
- 0xffffffff, 0xffffffff);
- /*
- * Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3,
- * VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT
- * for_PM_MSG_gt0, MDLL Turn On
- */
- mrc_alt_write_mask(DDRPHY,
- CMDPMDLYREG3 + ch * DDRIOCCC_CH_OFFSET,
- 0xfffff616, 0xffffffff);
- /* MPLL Divider Reset Delays */
- mrc_alt_write_mask(DDRPHY,
- CMDPMDLYREG2 + ch * DDRIOCCC_CH_OFFSET,
- 0xffffffff, 0xffffffff);
- /* Turn Off Delays: VREG, Staggered MDLL, MDLL, PI */
- mrc_alt_write_mask(DDRPHY,
- CMDPMDLYREG1 + ch * DDRIOCCC_CH_OFFSET,
- 0xffffffff, 0xffffffff);
- /* Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT */
- mrc_alt_write_mask(DDRPHY,
- CMDPMDLYREG0 + ch * DDRIOCCC_CH_OFFSET,
- 0xffffffff, 0xffffffff);
- /* Allow PUnit signals */
- mrc_alt_write_mask(DDRPHY,
- CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
- (0x6 << 8) | (0x1 << 6) | (0x4 << 0),
- 0xffe00f4f);
- /* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
- mrc_alt_write_mask(DDRPHY,
- CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
- (0x3 << 4) | (0x7 << 0), 0x7f);
- /* CLK-CTL */
- mrc_alt_write_mask(DDRPHY,
- CCOBSCKEBBCTL + ch * DDRIOCCC_CH_OFFSET,
- 0, 1 << 24); /* CLKEBB */
- /* Buffer Enable: CS,CKE,ODT,CLK */
- mrc_alt_write_mask(DDRPHY,
- CCCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
- 0x1f, 0x000ffff1);
- /* ODT RCOMP */
- mrc_alt_write_mask(DDRPHY,
- CCRCOMPODT + ch * DDRIOCCC_CH_OFFSET,
- (0x03 << 8) | (0x03 << 0), 0x00001f1f);
- /* DLL_VREG Bias Trim, VREF Tuning for DLL_VREG */
- mrc_alt_write_mask(DDRPHY,
- CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
- (0x3 << 4) | (0x7 << 0), 0x7f);
- /*
- * COMP (RON channel specific)
- * - DQ/DQS/DM RON: 32 Ohm
- * - CTRL/CMD RON: 27 Ohm
- * - CLK RON: 26 Ohm
- */
- /* RCOMP Vref PU/PD */
- mrc_alt_write_mask(DDRPHY,
- DQVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x08 << 24) | (0x03 << 16), 0x3f3f0000);
- /* RCOMP Vref PU/PD */
- mrc_alt_write_mask(DDRPHY,
- CMDVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x0C << 24) | (0x03 << 16), 0x3f3f0000);
- /* RCOMP Vref PU/PD */
- mrc_alt_write_mask(DDRPHY,
- CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x0F << 24) | (0x03 << 16), 0x3f3f0000);
- /* RCOMP Vref PU/PD */
- mrc_alt_write_mask(DDRPHY,
- DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x08 << 24) | (0x03 << 16), 0x3f3f0000);
- /* RCOMP Vref PU/PD */
- mrc_alt_write_mask(DDRPHY,
- CTLVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x0C << 24) | (0x03 << 16), 0x3f3f0000);
- /* DQS Swapped Input Enable */
- mrc_alt_write_mask(DDRPHY,
- COMPEN1CH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 19) | (1 << 17), 0xc00ac000);
- /* ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50) */
- /* ODT Vref PU/PD */
- mrc_alt_write_mask(DDRPHY,
- DQVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x32 << 8) | (0x03 << 0), 0x00003f3f);
- /* ODT Vref PU/PD */
- mrc_alt_write_mask(DDRPHY,
- DQSVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x32 << 8) | (0x03 << 0), 0x00003f3f);
- /* ODT Vref PU/PD */
- mrc_alt_write_mask(DDRPHY,
- CLKVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x0E << 8) | (0x05 << 0), 0x00003f3f);
- /*
- * Slew rate settings are frequency specific,
- * numbers below are for 800Mhz (speed == 0)
- * - DQ/DQS/DM/CLK SR: 4V/ns,
- * - CTRL/CMD SR: 1.5V/ns
- */
- temp = (0x0e << 16) | (0x0e << 12) | (0x08 << 8) |
- (0x0b << 4) | (0x0b << 0);
- /* DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ */
- mrc_alt_write_mask(DDRPHY,
- DLYSELCH0 + ch * DDRCOMP_CH_OFFSET,
- temp, 0x000fffff);
- /* TCO Vref CLK,DQS,DQ */
- mrc_alt_write_mask(DDRPHY,
- TCOVREFCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x05 << 16) | (0x05 << 8) | (0x05 << 0),
- 0x003f3f3f);
- /* ODTCOMP CMD/CTL PU/PD */
- mrc_alt_write_mask(DDRPHY,
- CCBUFODTCH0 + ch * DDRCOMP_CH_OFFSET,
- (0x03 << 8) | (0x03 << 0),
- 0x00001f1f);
- /* COMP */
- mrc_alt_write_mask(DDRPHY,
- COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
- 0, 0xc0000100);
- #ifdef BACKUP_COMPS
- /* DQ COMP Overrides */
- /* RCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0a << 16),
- 0x801f0000);
- /* RCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0a << 16),
- 0x801f0000);
- /* DCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x10 << 16),
- 0x801f0000);
- /* DCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x10 << 16),
- 0x801f0000);
- /* ODTCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0b << 16),
- 0x801f0000);
- /* ODTCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0b << 16),
- 0x801f0000);
- /* TCOCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- 1 << 31, 1 << 31);
- /* TCOCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- 1 << 31, 1 << 31);
- /* DQS COMP Overrides */
- /* RCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQSDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0a << 16),
- 0x801f0000);
- /* RCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQSDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0a << 16),
- 0x801f0000);
- /* DCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQSDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x10 << 16),
- 0x801f0000);
- /* DCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQSDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x10 << 16),
- 0x801f0000);
- /* ODTCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQSODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0b << 16),
- 0x801f0000);
- /* ODTCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQSODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0b << 16),
- 0x801f0000);
- /* TCOCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- 1 << 31, 1 << 31);
- /* TCOCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- 1 << 31, 1 << 31);
- /* CLK COMP Overrides */
- /* RCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CLKDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0c << 16),
- 0x801f0000);
- /* RCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CLKDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0c << 16),
- 0x801f0000);
- /* DCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CLKDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x07 << 16),
- 0x801f0000);
- /* DCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CLKDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x07 << 16),
- 0x801f0000);
- /* ODTCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CLKODTPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0b << 16),
- 0x801f0000);
- /* ODTCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CLKODTPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0b << 16),
- 0x801f0000);
- /* TCOCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- 1 << 31, 1 << 31);
- /* TCOCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- 1 << 31, 1 << 31);
- /* CMD COMP Overrides */
- /* RCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CMDDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0d << 16),
- 0x803f0000);
- /* RCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CMDDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0d << 16),
- 0x803f0000);
- /* DCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CMDDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0a << 16),
- 0x801f0000);
- /* DCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CMDDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0a << 16),
- 0x801f0000);
- /* CTL COMP Overrides */
- /* RCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CTLDRVPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0d << 16),
- 0x803f0000);
- /* RCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CTLDRVPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0d << 16),
- 0x803f0000);
- /* DCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CTLDLYPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0a << 16),
- 0x801f0000);
- /* DCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CTLDLYPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x0a << 16),
- 0x801f0000);
- #else
- /* DQ TCOCOMP Overrides */
- /* TCOCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x1f << 16),
- 0x801f0000);
- /* TCOCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x1f << 16),
- 0x801f0000);
- /* DQS TCOCOMP Overrides */
- /* TCOCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- DQSTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x1f << 16),
- 0x801f0000);
- /* TCOCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- DQSTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x1f << 16),
- 0x801f0000);
- /* CLK TCOCOMP Overrides */
- /* TCOCOMP PU */
- mrc_alt_write_mask(DDRPHY,
- CLKTCOPUCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x1f << 16),
- 0x801f0000);
- /* TCOCOMP PD */
- mrc_alt_write_mask(DDRPHY,
- CLKTCOPDCTLCH0 + ch * DDRCOMP_CH_OFFSET,
- (1 << 31) | (0x1f << 16),
- 0x801f0000);
- #endif
- /* program STATIC delays */
- #ifdef BACKUP_WCMD
- set_wcmd(ch, ddr_wcmd[PLATFORM_ID]);
- #else
- set_wcmd(ch, ddr_wclk[PLATFORM_ID] + HALF_CLK);
- #endif
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- set_wclk(ch, rk, ddr_wclk[PLATFORM_ID]);
- #ifdef BACKUP_WCTL
- set_wctl(ch, rk, ddr_wctl[PLATFORM_ID]);
- #else
- set_wctl(ch, rk, ddr_wclk[PLATFORM_ID] + HALF_CLK);
- #endif
- }
- }
- }
- }
- /* COMP (non channel specific) */
- /* RCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, DQANADRVPUCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, DQANADRVPDCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, CMDANADRVPUCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, CMDANADRVPDCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, CLKANADRVPUCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, CLKANADRVPDCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, DQSANADRVPUCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, DQSANADRVPDCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, CTLANADRVPUCTL, 1 << 30, 1 << 30);
- /* RCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, CTLANADRVPDCTL, 1 << 30, 1 << 30);
- /* ODT: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, DQANAODTPUCTL, 1 << 30, 1 << 30);
- /* ODT: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, DQANAODTPDCTL, 1 << 30, 1 << 30);
- /* ODT: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, CLKANAODTPUCTL, 1 << 30, 1 << 30);
- /* ODT: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, CLKANAODTPDCTL, 1 << 30, 1 << 30);
- /* ODT: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, DQSANAODTPUCTL, 1 << 30, 1 << 30);
- /* ODT: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, DQSANAODTPDCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, DQANADLYPUCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, DQANADLYPDCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, CMDANADLYPUCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, CMDANADLYPDCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, CLKANADLYPUCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, CLKANADLYPDCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, DQSANADLYPUCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, DQSANADLYPDCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, CTLANADLYPUCTL, 1 << 30, 1 << 30);
- /* DCOMP: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, CTLANADLYPDCTL, 1 << 30, 1 << 30);
- /* TCO: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, DQANATCOPUCTL, 1 << 30, 1 << 30);
- /* TCO: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, DQANATCOPDCTL, 1 << 30, 1 << 30);
- /* TCO: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, CLKANATCOPUCTL, 1 << 30, 1 << 30);
- /* TCO: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, CLKANATCOPDCTL, 1 << 30, 1 << 30);
- /* TCO: Dither PU Enable */
- mrc_alt_write_mask(DDRPHY, DQSANATCOPUCTL, 1 << 30, 1 << 30);
- /* TCO: Dither PD Enable */
- mrc_alt_write_mask(DDRPHY, DQSANATCOPDCTL, 1 << 30, 1 << 30);
- /* TCOCOMP: Pulse Count */
- mrc_alt_write_mask(DDRPHY, TCOCNTCTRL, 1, 3);
- /* ODT: CMD/CTL PD/PU */
- mrc_alt_write_mask(DDRPHY, CHNLBUFSTATIC,
- (0x03 << 24) | (0x03 << 16), 0x1f1f0000);
- /* Set 1us counter */
- mrc_alt_write_mask(DDRPHY, MSCNTR, 0x64, 0xff);
- mrc_alt_write_mask(DDRPHY, LATCH1CTL, 0x1 << 28, 0x70000000);
- /* Release PHY from reset */
- mrc_alt_write_mask(DDRPHY, MASTERRSTN, 1, 1);
- /* STEP1 */
- mrc_post_code(0x03, 0x11);
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- /* DQ01-DQ23 */
- for (bl_grp = 0;
- bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
- bl_grp++) {
- mrc_alt_write_mask(DDRPHY,
- DQMDLLCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 1 << 13,
- 1 << 13); /* Enable VREG */
- delay_n(3);
- }
- /* ECC */
- mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
- 1 << 13, 1 << 13); /* Enable VREG */
- delay_n(3);
- /* CMD */
- mrc_alt_write_mask(DDRPHY,
- CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
- 1 << 13, 1 << 13); /* Enable VREG */
- delay_n(3);
- /* CLK-CTL */
- mrc_alt_write_mask(DDRPHY,
- CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
- 1 << 13, 1 << 13); /* Enable VREG */
- delay_n(3);
- }
- }
- /* STEP2 */
- mrc_post_code(0x03, 0x12);
- delay_n(200);
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- /* DQ01-DQ23 */
- for (bl_grp = 0;
- bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
- bl_grp++) {
- mrc_alt_write_mask(DDRPHY,
- DQMDLLCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 1 << 17,
- 1 << 17); /* Enable MCDLL */
- delay_n(50);
- }
- /* ECC */
- mrc_alt_write_mask(DDRPHY, ECCMDLLCTL,
- 1 << 17, 1 << 17); /* Enable MCDLL */
- delay_n(50);
- /* CMD */
- mrc_alt_write_mask(DDRPHY,
- CMDMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
- 1 << 18, 1 << 18); /* Enable MCDLL */
- delay_n(50);
- /* CLK-CTL */
- mrc_alt_write_mask(DDRPHY,
- CCMDLLCTL + ch * DDRIOCCC_CH_OFFSET,
- 1 << 18, 1 << 18); /* Enable MCDLL */
- delay_n(50);
- }
- }
- /* STEP3: */
- mrc_post_code(0x03, 0x13);
- delay_n(100);
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- /* DQ01-DQ23 */
- for (bl_grp = 0;
- bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
- bl_grp++) {
- #ifdef FORCE_16BIT_DDRIO
- temp = (bl_grp &&
- (mrc_params->channel_width == X16)) ?
- 0x11ff : 0xffff;
- #else
- temp = 0xffff;
- #endif
- /* Enable TXDLL */
- mrc_alt_write_mask(DDRPHY,
- DQDLLTXCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- temp, 0xffff);
- delay_n(3);
- /* Enable RXDLL */
- mrc_alt_write_mask(DDRPHY,
- DQDLLRXCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 0xf, 0xf);
- delay_n(3);
- /* Enable RXDLL Overrides BL0 */
- mrc_alt_write_mask(DDRPHY,
- B0OVRCTL +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 0xf, 0xf);
- }
- /* ECC */
- temp = 0xffff;
- mrc_alt_write_mask(DDRPHY, ECCDLLTXCTL,
- temp, 0xffff);
- delay_n(3);
- /* CMD (PO) */
- mrc_alt_write_mask(DDRPHY,
- CMDDLLTXCTL + ch * DDRIOCCC_CH_OFFSET,
- temp, 0xffff);
- delay_n(3);
- }
- }
- /* STEP4 */
- mrc_post_code(0x03, 0x14);
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- /* Host To Memory Clock Alignment (HMC) for 800/1066 */
- for (bl_grp = 0;
- bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2;
- bl_grp++) {
- /* CLK_ALIGN_MOD_ID */
- mrc_alt_write_mask(DDRPHY,
- DQCLKALIGNREG2 +
- bl_grp * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- bl_grp ? 3 : 1,
- 0xf);
- }
- mrc_alt_write_mask(DDRPHY,
- ECCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
- 0x2, 0xf);
- mrc_alt_write_mask(DDRPHY,
- CMDCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
- 0x0, 0xf);
- mrc_alt_write_mask(DDRPHY,
- CCCLKALIGNREG2 + ch * DDRIODQ_CH_OFFSET,
- 0x2, 0xf);
- mrc_alt_write_mask(DDRPHY,
- CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
- 0x20, 0x30);
- /*
- * NUM_SAMPLES, MAX_SAMPLES,
- * MACRO_PI_STEP, MICRO_PI_STEP
- */
- mrc_alt_write_mask(DDRPHY,
- CMDCLKALIGNREG1 + ch * DDRIOCCC_CH_OFFSET,
- (0x18 << 16) | (0x10 << 8) |
- (0x8 << 2) | (0x1 << 0),
- 0x007f7fff);
- /* TOTAL_NUM_MODULES, FIRST_U_PARTITION */
- mrc_alt_write_mask(DDRPHY,
- CMDCLKALIGNREG2 + ch * DDRIOCCC_CH_OFFSET,
- (0x10 << 16) | (0x4 << 8) | (0x2 << 4),
- 0x001f0ff0);
- #ifdef HMC_TEST
- /* START_CLK_ALIGN=1 */
- mrc_alt_write_mask(DDRPHY,
- CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET,
- 1 << 24, 1 << 24);
- while (msg_port_alt_read(DDRPHY,
- CMDCLKALIGNREG0 + ch * DDRIOCCC_CH_OFFSET) &
- (1 << 24))
- ; /* wait for START_CLK_ALIGN=0 */
- #endif
- /* Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN */
- mrc_alt_write_mask(DDRPHY,
- CMDPTRREG + ch * DDRIOCCC_CH_OFFSET,
- 1, 1); /* WRPTRENABLE=1 */
- /* COMP initial */
- /* enable bypass for CLK buffer (PO) */
- mrc_alt_write_mask(DDRPHY,
- COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
- 1 << 5, 1 << 5);
- /* Initial COMP Enable */
- mrc_alt_write_mask(DDRPHY, CMPCTRL, 1, 1);
- /* wait for Initial COMP Enable = 0 */
- while (msg_port_alt_read(DDRPHY, CMPCTRL) & 1)
- ;
- /* disable bypass for CLK buffer (PO) */
- mrc_alt_write_mask(DDRPHY,
- COMPEN0CH0 + ch * DDRCOMP_CH_OFFSET,
- ~(1 << 5), 1 << 5);
- /* IOBUFACT */
- /* STEP4a */
- mrc_alt_write_mask(DDRPHY,
- CMDCFGREG0 + ch * DDRIOCCC_CH_OFFSET,
- 1 << 2, 1 << 2); /* IOBUFACTRST_N=1 */
- /* DDRPHY initialization complete */
- mrc_alt_write_mask(DDRPHY,
- CMDPMCONFIG0 + ch * DDRIOCCC_CH_OFFSET,
- 1 << 20, 1 << 20); /* SPID_INIT_COMPLETE=1 */
- }
- }
- LEAVEFN();
- }
- /* This function performs JEDEC initialization on all enabled channels */
- void perform_jedec_init(struct mrc_params *mrc_params)
- {
- uint8_t twr, wl, rank;
- uint32_t tck;
- u32 dtr0;
- u32 drp;
- u32 drmc;
- u32 mrs0_cmd = 0;
- u32 emrs1_cmd = 0;
- u32 emrs2_cmd = 0;
- u32 emrs3_cmd = 0;
- ENTERFN();
- /* jedec_init starts */
- mrc_post_code(0x04, 0x00);
- /* DDR3_RESET_SET=0, DDR3_RESET_RESET=1 */
- mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 2, 0x102);
- /* Assert RESET# for 200us */
- delay_u(200);
- /* DDR3_RESET_SET=1, DDR3_RESET_RESET=0 */
- mrc_alt_write_mask(DDRPHY, CCDDR3RESETCTL, 0x100, 0x102);
- dtr0 = msg_port_read(MEM_CTLR, DTR0);
- /*
- * Set CKEVAL for populated ranks
- * then send NOP to each rank (#4550197)
- */
- drp = msg_port_read(MEM_CTLR, DRP);
- drp &= 0x3;
- drmc = msg_port_read(MEM_CTLR, DRMC);
- drmc &= 0xfffffffc;
- drmc |= (DRMC_CKEMODE | drp);
- msg_port_write(MEM_CTLR, DRMC, drmc);
- for (rank = 0; rank < NUM_RANKS; rank++) {
- /* Skip to next populated rank */
- if ((mrc_params->rank_enables & (1 << rank)) == 0)
- continue;
- dram_init_command(DCMD_NOP(rank));
- }
- msg_port_write(MEM_CTLR, DRMC,
- (mrc_params->rd_odt_value == 0 ? DRMC_ODTMODE : 0));
- /*
- * setup for emrs 2
- * BIT[15:11] --> Always "0"
- * BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)
- * BIT[08] --> Always "0"
- * BIT[07] --> SRT: use sr_temp_range
- * BIT[06] --> ASR: want "Manual SR Reference" (0)
- * BIT[05:03] --> CWL: use oem_tCWL
- * BIT[02:00] --> PASR: want "Full Array" (0)
- */
- emrs2_cmd |= (2 << 3);
- wl = 5 + mrc_params->ddr_speed;
- emrs2_cmd |= ((wl - 5) << 9);
- emrs2_cmd |= (mrc_params->sr_temp_range << 13);
- /*
- * setup for emrs 3
- * BIT[15:03] --> Always "0"
- * BIT[02] --> MPR: want "Normal Operation" (0)
- * BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)
- */
- emrs3_cmd |= (3 << 3);
- /*
- * setup for emrs 1
- * BIT[15:13] --> Always "0"
- * BIT[12:12] --> Qoff: want "Output Buffer Enabled" (0)
- * BIT[11:11] --> TDQS: want "Disabled" (0)
- * BIT[10:10] --> Always "0"
- * BIT[09,06,02] --> Rtt_nom: use rtt_nom_value
- * BIT[08] --> Always "0"
- * BIT[07] --> WR_LVL: want "Disabled" (0)
- * BIT[05,01] --> DIC: use ron_value
- * BIT[04:03] --> AL: additive latency want "0" (0)
- * BIT[00] --> DLL: want "Enable" (0)
- *
- * (BIT5|BIT1) set Ron value
- * 00 --> RZQ/6 (40ohm)
- * 01 --> RZQ/7 (34ohm)
- * 1* --> RESERVED
- *
- * (BIT9|BIT6|BIT2) set Rtt_nom value
- * 000 --> Disabled
- * 001 --> RZQ/4 ( 60ohm)
- * 010 --> RZQ/2 (120ohm)
- * 011 --> RZQ/6 ( 40ohm)
- * 1** --> RESERVED
- */
- emrs1_cmd |= (1 << 3);
- emrs1_cmd &= ~(1 << 6);
- if (mrc_params->ron_value == 0)
- emrs1_cmd |= (1 << 7);
- else
- emrs1_cmd &= ~(1 << 7);
- if (mrc_params->rtt_nom_value == 0)
- emrs1_cmd |= (DDR3_EMRS1_RTTNOM_40 << 6);
- else if (mrc_params->rtt_nom_value == 1)
- emrs1_cmd |= (DDR3_EMRS1_RTTNOM_60 << 6);
- else if (mrc_params->rtt_nom_value == 2)
- emrs1_cmd |= (DDR3_EMRS1_RTTNOM_120 << 6);
- /* save MRS1 value (excluding control fields) */
- mrc_params->mrs1 = emrs1_cmd >> 6;
- /*
- * setup for mrs 0
- * BIT[15:13] --> Always "0"
- * BIT[12] --> PPD: for Quark (1)
- * BIT[11:09] --> WR: use oem_tWR
- * BIT[08] --> DLL: want "Reset" (1, self clearing)
- * BIT[07] --> MODE: want "Normal" (0)
- * BIT[06:04,02] --> CL: use oem_tCAS
- * BIT[03] --> RD_BURST_TYPE: want "Interleave" (1)
- * BIT[01:00] --> BL: want "8 Fixed" (0)
- * WR:
- * 0 --> 16
- * 1 --> 5
- * 2 --> 6
- * 3 --> 7
- * 4 --> 8
- * 5 --> 10
- * 6 --> 12
- * 7 --> 14
- * CL:
- * BIT[02:02] "0" if oem_tCAS <= 11 (1866?)
- * BIT[06:04] use oem_tCAS-4
- */
- mrs0_cmd |= (1 << 14);
- mrs0_cmd |= (1 << 18);
- mrs0_cmd |= ((((dtr0 >> 12) & 7) + 1) << 10);
- tck = t_ck[mrc_params->ddr_speed];
- /* Per JEDEC: tWR=15000ps DDR2/3 from 800-1600 */
- twr = MCEIL(15000, tck);
- mrs0_cmd |= ((twr - 4) << 15);
- for (rank = 0; rank < NUM_RANKS; rank++) {
- /* Skip to next populated rank */
- if ((mrc_params->rank_enables & (1 << rank)) == 0)
- continue;
- emrs2_cmd |= (rank << 22);
- dram_init_command(emrs2_cmd);
- emrs3_cmd |= (rank << 22);
- dram_init_command(emrs3_cmd);
- emrs1_cmd |= (rank << 22);
- dram_init_command(emrs1_cmd);
- mrs0_cmd |= (rank << 22);
- dram_init_command(mrs0_cmd);
- dram_init_command(DCMD_ZQCL(rank));
- }
- LEAVEFN();
- }
- /*
- * Dunit Initialization Complete
- *
- * Indicates that initialization of the Dunit has completed.
- *
- * Memory accesses are permitted and maintenance operation begins.
- * Until this bit is set to a 1, the memory controller will not accept
- * DRAM requests from the MEMORY_MANAGER or HTE.
- */
- void set_ddr_init_complete(struct mrc_params *mrc_params)
- {
- u32 dco;
- ENTERFN();
- dco = msg_port_read(MEM_CTLR, DCO);
- dco &= ~DCO_PMICTL;
- dco |= DCO_IC;
- msg_port_write(MEM_CTLR, DCO, dco);
- LEAVEFN();
- }
- /*
- * This function will retrieve relevant timing data
- *
- * This data will be used on subsequent boots to speed up boot times
- * and is required for Suspend To RAM capabilities.
- */
- void restore_timings(struct mrc_params *mrc_params)
- {
- uint8_t ch, rk, bl;
- const struct mrc_timings *mt = &mrc_params->timings;
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
- set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]);
- set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]);
- set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]);
- set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]);
- if (rk == 0) {
- /* VREF (RANK0 only) */
- set_vref(ch, bl, mt->vref[ch][bl]);
- }
- }
- set_wctl(ch, rk, mt->wctl[ch][rk]);
- }
- set_wcmd(ch, mt->wcmd[ch]);
- }
- }
- /*
- * Configure default settings normally set as part of read training
- *
- * Some defaults have to be set earlier as they may affect earlier
- * training steps.
- */
- void default_timings(struct mrc_params *mrc_params)
- {
- uint8_t ch, rk, bl;
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
- set_rdqs(ch, rk, bl, 24);
- if (rk == 0) {
- /* VREF (RANK0 only) */
- set_vref(ch, bl, 32);
- }
- }
- }
- }
- }
- /*
- * This function will perform our RCVEN Calibration Algorithm.
- * We will only use the 2xCLK domain timings to perform RCVEN Calibration.
- * All byte lanes will be calibrated "simultaneously" per channel per rank.
- */
- void rcvn_cal(struct mrc_params *mrc_params)
- {
- uint8_t ch; /* channel counter */
- uint8_t rk; /* rank counter */
- uint8_t bl; /* byte lane counter */
- uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
- #ifdef R2R_SHARING
- /* used to find placement for rank2rank sharing configs */
- uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
- #ifndef BACKUP_RCVN
- /* used to find placement for rank2rank sharing configs */
- uint32_t num_ranks_enabled = 0;
- #endif
- #endif
- #ifdef BACKUP_RCVN
- #else
- uint32_t temp;
- /* absolute PI value to be programmed on the byte lane */
- uint32_t delay[NUM_BYTE_LANES];
- u32 dtr1, dtr1_save;
- #endif
- ENTERFN();
- /* rcvn_cal starts */
- mrc_post_code(0x05, 0x00);
- #ifndef BACKUP_RCVN
- /* need separate burst to sample DQS preamble */
- dtr1 = msg_port_read(MEM_CTLR, DTR1);
- dtr1_save = dtr1;
- dtr1 |= DTR1_TCCD_12CLK;
- msg_port_write(MEM_CTLR, DTR1, dtr1);
- #endif
- #ifdef R2R_SHARING
- /* need to set "final_delay[][]" elements to "0" */
- memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
- #endif
- /* loop through each enabled channel */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- /* perform RCVEN Calibration on a per rank basis */
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- /*
- * POST_CODE here indicates the current
- * channel and rank being calibrated
- */
- mrc_post_code(0x05, 0x10 + ((ch << 4) | rk));
- #ifdef BACKUP_RCVN
- /* et hard-coded timing values */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++)
- set_rcvn(ch, rk, bl, ddr_rcvn[PLATFORM_ID]);
- #else
- /* enable FIFORST */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
- mrc_alt_write_mask(DDRPHY,
- B01PTRCTL1 +
- (bl >> 1) * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 0, 1 << 8);
- }
- /* initialize the starting delay to 128 PI (cas +1 CLK) */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- /* 1x CLK domain timing is cas-4 */
- delay[bl] = (4 + 1) * FULL_CLK;
- set_rcvn(ch, rk, bl, delay[bl]);
- }
- /* now find the rising edge */
- find_rising_edge(mrc_params, delay, ch, rk, true);
- /* Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- delay[bl] += QRTR_CLK;
- set_rcvn(ch, rk, bl, delay[bl]);
- }
- /* Now decrement delay by 128 PI (1 CLK) until we sample a "0" */
- do {
- temp = sample_dqs(mrc_params, ch, rk, true);
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- if (temp & (1 << bl)) {
- if (delay[bl] >= FULL_CLK) {
- delay[bl] -= FULL_CLK;
- set_rcvn(ch, rk, bl, delay[bl]);
- } else {
- /* not enough delay */
- training_message(ch, rk, bl);
- mrc_post_code(0xee, 0x50);
- }
- }
- }
- } while (temp & 0xff);
- #ifdef R2R_SHARING
- /* increment "num_ranks_enabled" */
- num_ranks_enabled++;
- /* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- delay[bl] += QRTR_CLK;
- /* add "delay[]" values to "final_delay[][]" for rolling average */
- final_delay[ch][bl] += delay[bl];
- /* set timing based on rolling average values */
- set_rcvn(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
- }
- #else
- /* Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- delay[bl] += QRTR_CLK;
- set_rcvn(ch, rk, bl, delay[bl]);
- }
- #endif
- /* disable FIFORST */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl += 2) {
- mrc_alt_write_mask(DDRPHY,
- B01PTRCTL1 +
- (bl >> 1) * DDRIODQ_BL_OFFSET +
- ch * DDRIODQ_CH_OFFSET,
- 1 << 8, 1 << 8);
- }
- #endif
- }
- }
- }
- }
- #ifndef BACKUP_RCVN
- /* restore original */
- msg_port_write(MEM_CTLR, DTR1, dtr1_save);
- #endif
- LEAVEFN();
- }
- /*
- * This function will perform the Write Levelling algorithm
- * (align WCLK and WDQS).
- *
- * This algorithm will act on each rank in each channel separately.
- */
- void wr_level(struct mrc_params *mrc_params)
- {
- uint8_t ch; /* channel counter */
- uint8_t rk; /* rank counter */
- uint8_t bl; /* byte lane counter */
- uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
- #ifdef R2R_SHARING
- /* used to find placement for rank2rank sharing configs */
- uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
- #ifndef BACKUP_WDQS
- /* used to find placement for rank2rank sharing configs */
- uint32_t num_ranks_enabled = 0;
- #endif
- #endif
- #ifdef BACKUP_WDQS
- #else
- /* determines stop condition for CRS_WR_LVL */
- bool all_edges_found;
- /* absolute PI value to be programmed on the byte lane */
- uint32_t delay[NUM_BYTE_LANES];
- /*
- * static makes it so the data is loaded in the heap once by shadow(),
- * where non-static copies the data onto the stack every time this
- * function is called
- */
- uint32_t address; /* address to be checked during COARSE_WR_LVL */
- u32 dtr4, dtr4_save;
- #endif
- ENTERFN();
- /* wr_level starts */
- mrc_post_code(0x06, 0x00);
- #ifdef R2R_SHARING
- /* need to set "final_delay[][]" elements to "0" */
- memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
- #endif
- /* loop through each enabled channel */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- /* perform WRITE LEVELING algorithm on a per rank basis */
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- /*
- * POST_CODE here indicates the current
- * rank and channel being calibrated
- */
- mrc_post_code(0x06, 0x10 + ((ch << 4) | rk));
- #ifdef BACKUP_WDQS
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- set_wdqs(ch, rk, bl, ddr_wdqs[PLATFORM_ID]);
- set_wdq(ch, rk, bl, ddr_wdqs[PLATFORM_ID] - QRTR_CLK);
- }
- #else
- /*
- * perform a single PRECHARGE_ALL command to
- * make DRAM state machine go to IDLE state
- */
- dram_init_command(DCMD_PREA(rk));
- /*
- * enable Write Levelling Mode
- * (EMRS1 w/ Write Levelling Mode Enable)
- */
- dram_init_command(DCMD_MRS1(rk, 0x82));
- /*
- * set ODT DRAM Full Time Termination
- * disable in MCU
- */
- dtr4 = msg_port_read(MEM_CTLR, DTR4);
- dtr4_save = dtr4;
- dtr4 |= DTR4_ODTDIS;
- msg_port_write(MEM_CTLR, DTR4, dtr4);
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
- /*
- * Enable Sandy Bridge Mode (WDQ Tri-State) &
- * Ensure 5 WDQS pulses during Write Leveling
- */
- mrc_alt_write_mask(DDRPHY,
- DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
- 0x10000154,
- 0x100003fc);
- }
- /* Write Leveling Mode enabled in IO */
- mrc_alt_write_mask(DDRPHY,
- CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
- 1 << 16, 1 << 16);
- /* Initialize the starting delay to WCLK */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- /*
- * CLK0 --> RK0
- * CLK1 --> RK1
- */
- delay[bl] = get_wclk(ch, rk);
- set_wdqs(ch, rk, bl, delay[bl]);
- }
- /* now find the rising edge */
- find_rising_edge(mrc_params, delay, ch, rk, false);
- /* disable Write Levelling Mode */
- mrc_alt_write_mask(DDRPHY,
- CCDDR3RESETCTL + DDRIOCCC_CH_OFFSET * ch,
- 0, 1 << 16);
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
- /* Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation */
- mrc_alt_write_mask(DDRPHY,
- DQCTL + DDRIODQ_BL_OFFSET * bl + DDRIODQ_CH_OFFSET * ch,
- 0x00000154,
- 0x100003fc);
- }
- /* restore original DTR4 */
- msg_port_write(MEM_CTLR, DTR4, dtr4_save);
- /*
- * restore original value
- * (Write Levelling Mode Disable)
- */
- dram_init_command(DCMD_MRS1(rk, mrc_params->mrs1));
- /*
- * perform a single PRECHARGE_ALL command to
- * make DRAM state machine go to IDLE state
- */
- dram_init_command(DCMD_PREA(rk));
- mrc_post_code(0x06, 0x30 + ((ch << 4) | rk));
- /*
- * COARSE WRITE LEVEL:
- * check that we're on the correct clock edge
- */
- /* hte reconfiguration request */
- mrc_params->hte_setup = 1;
- /* start CRS_WR_LVL with WDQS = WDQS + 128 PI */
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- delay[bl] = get_wdqs(ch, rk, bl) + FULL_CLK;
- set_wdqs(ch, rk, bl, delay[bl]);
- /*
- * program WDQ timings based on WDQS
- * (WDQ = WDQS - 32 PI)
- */
- set_wdq(ch, rk, bl, (delay[bl] - QRTR_CLK));
- }
- /* get an address in the targeted channel/rank */
- address = get_addr(ch, rk);
- do {
- uint32_t coarse_result = 0x00;
- uint32_t coarse_result_mask = byte_lane_mask(mrc_params);
- /* assume pass */
- all_edges_found = true;
- mrc_params->hte_setup = 1;
- coarse_result = check_rw_coarse(mrc_params, address);
- /* check for failures and margin the byte lane back 128 PI (1 CLK) */
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- if (coarse_result & (coarse_result_mask << bl)) {
- all_edges_found = false;
- delay[bl] -= FULL_CLK;
- set_wdqs(ch, rk, bl, delay[bl]);
- /* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
- set_wdq(ch, rk, bl, delay[bl] - QRTR_CLK);
- }
- }
- } while (!all_edges_found);
- #ifdef R2R_SHARING
- /* increment "num_ranks_enabled" */
- num_ranks_enabled++;
- /* accumulate "final_delay[][]" values from "delay[]" values for rolling average */
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- final_delay[ch][bl] += delay[bl];
- set_wdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
- /* program WDQ timings based on WDQS (WDQ = WDQS - 32 PI) */
- set_wdq(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled - QRTR_CLK);
- }
- #endif
- #endif
- }
- }
- }
- }
- LEAVEFN();
- }
- void prog_page_ctrl(struct mrc_params *mrc_params)
- {
- u32 dpmc0;
- ENTERFN();
- dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
- dpmc0 &= ~DPMC0_PCLSTO_MASK;
- dpmc0 |= (4 << 16);
- dpmc0 |= DPMC0_PREAPWDEN;
- msg_port_write(MEM_CTLR, DPMC0, dpmc0);
- }
- /*
- * This function will perform the READ TRAINING Algorithm on all
- * channels/ranks/byte_lanes simultaneously to minimize execution time.
- *
- * The idea here is to train the VREF and RDQS (and eventually RDQ) values
- * to achieve maximum READ margins. The algorithm will first determine the
- * X coordinate (RDQS setting). This is done by collapsing the VREF eye
- * until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.
- * Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX,
- * then average those; this will be the final X coordinate. The algorithm
- * will then determine the Y coordinate (VREF setting). This is done by
- * collapsing the RDQS eye until we find a minimum required VREF eye for
- * RDQS_MIN and RDQS_MAX. Then we take the averages of the VREF eye at
- * RDQS_MIN and RDQS_MAX, then average those; this will be the final Y
- * coordinate.
- *
- * NOTE: this algorithm assumes the eye curves have a one-to-one relationship,
- * meaning for each X the curve has only one Y and vice-a-versa.
- */
- void rd_train(struct mrc_params *mrc_params)
- {
- uint8_t ch; /* channel counter */
- uint8_t rk; /* rank counter */
- uint8_t bl; /* byte lane counter */
- uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
- #ifdef BACKUP_RDQS
- #else
- uint8_t side_x; /* tracks LEFT/RIGHT approach vectors */
- uint8_t side_y; /* tracks BOTTOM/TOP approach vectors */
- /* X coordinate data (passing RDQS values) for approach vectors */
- uint8_t x_coordinate[2][2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
- /* Y coordinate data (passing VREF values) for approach vectors */
- uint8_t y_coordinate[2][2][NUM_CHANNELS][NUM_BYTE_LANES];
- /* centered X (RDQS) */
- uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
- /* centered Y (VREF) */
- uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES];
- uint32_t address; /* target address for check_bls_ex() */
- uint32_t result; /* result of check_bls_ex() */
- uint32_t bl_mask; /* byte lane mask for result checking */
- #ifdef R2R_SHARING
- /* used to find placement for rank2rank sharing configs */
- uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
- /* used to find placement for rank2rank sharing configs */
- uint32_t num_ranks_enabled = 0;
- #endif
- #endif
- /* rd_train starts */
- mrc_post_code(0x07, 0x00);
- ENTERFN();
- #ifdef BACKUP_RDQS
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- for (bl = 0;
- bl < NUM_BYTE_LANES / bl_divisor;
- bl++) {
- set_rdqs(ch, rk, bl, ddr_rdqs[PLATFORM_ID]);
- }
- }
- }
- }
- }
- #else
- /* initialize x/y_coordinate arrays */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- for (bl = 0;
- bl < NUM_BYTE_LANES / bl_divisor;
- bl++) {
- /* x_coordinate */
- x_coordinate[L][B][ch][rk][bl] = RDQS_MIN;
- x_coordinate[R][B][ch][rk][bl] = RDQS_MAX;
- x_coordinate[L][T][ch][rk][bl] = RDQS_MIN;
- x_coordinate[R][T][ch][rk][bl] = RDQS_MAX;
- /* y_coordinate */
- y_coordinate[L][B][ch][bl] = VREF_MIN;
- y_coordinate[R][B][ch][bl] = VREF_MIN;
- y_coordinate[L][T][ch][bl] = VREF_MAX;
- y_coordinate[R][T][ch][bl] = VREF_MAX;
- }
- }
- }
- }
- }
- /* initialize other variables */
- bl_mask = byte_lane_mask(mrc_params);
- address = get_addr(0, 0);
- #ifdef R2R_SHARING
- /* need to set "final_delay[][]" elements to "0" */
- memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
- #endif
- /* look for passing coordinates */
- for (side_y = B; side_y <= T; side_y++) {
- for (side_x = L; side_x <= R; side_x++) {
- mrc_post_code(0x07, 0x10 + side_y * 2 + side_x);
- /* find passing values */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (0x1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables &
- (0x1 << rk)) {
- /* set x/y_coordinate search starting settings */
- for (bl = 0;
- bl < NUM_BYTE_LANES / bl_divisor;
- bl++) {
- set_rdqs(ch, rk, bl,
- x_coordinate[side_x][side_y][ch][rk][bl]);
- set_vref(ch, bl,
- y_coordinate[side_x][side_y][ch][bl]);
- }
- /* get an address in the target channel/rank */
- address = get_addr(ch, rk);
- /* request HTE reconfiguration */
- mrc_params->hte_setup = 1;
- /* test the settings */
- do {
- /* result[07:00] == failing byte lane (MAX 8) */
- result = check_bls_ex(mrc_params, address);
- /* check for failures */
- if (result & 0xff) {
- /* at least 1 byte lane failed */
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- if (result &
- (bl_mask << bl)) {
- /* adjust the RDQS values accordingly */
- if (side_x == L)
- x_coordinate[L][side_y][ch][rk][bl] += RDQS_STEP;
- else
- x_coordinate[R][side_y][ch][rk][bl] -= RDQS_STEP;
- /* check that we haven't closed the RDQS_EYE too much */
- if ((x_coordinate[L][side_y][ch][rk][bl] > (RDQS_MAX - MIN_RDQS_EYE)) ||
- (x_coordinate[R][side_y][ch][rk][bl] < (RDQS_MIN + MIN_RDQS_EYE)) ||
- (x_coordinate[L][side_y][ch][rk][bl] ==
- x_coordinate[R][side_y][ch][rk][bl])) {
- /*
- * not enough RDQS margin available at this VREF
- * update VREF values accordingly
- */
- if (side_y == B)
- y_coordinate[side_x][B][ch][bl] += VREF_STEP;
- else
- y_coordinate[side_x][T][ch][bl] -= VREF_STEP;
- /* check that we haven't closed the VREF_EYE too much */
- if ((y_coordinate[side_x][B][ch][bl] > (VREF_MAX - MIN_VREF_EYE)) ||
- (y_coordinate[side_x][T][ch][bl] < (VREF_MIN + MIN_VREF_EYE)) ||
- (y_coordinate[side_x][B][ch][bl] == y_coordinate[side_x][T][ch][bl])) {
- /* VREF_EYE collapsed below MIN_VREF_EYE */
- training_message(ch, rk, bl);
- mrc_post_code(0xEE, 0x70 + side_y * 2 + side_x);
- } else {
- /* update the VREF setting */
- set_vref(ch, bl, y_coordinate[side_x][side_y][ch][bl]);
- /* reset the X coordinate to begin the search at the new VREF */
- x_coordinate[side_x][side_y][ch][rk][bl] =
- (side_x == L) ? RDQS_MIN : RDQS_MAX;
- }
- }
- /* update the RDQS setting */
- set_rdqs(ch, rk, bl, x_coordinate[side_x][side_y][ch][rk][bl]);
- }
- }
- }
- } while (result & 0xff);
- }
- }
- }
- }
- }
- }
- mrc_post_code(0x07, 0x20);
- /* find final RDQS (X coordinate) & final VREF (Y coordinate) */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- uint32_t temp1;
- uint32_t temp2;
- /* x_coordinate */
- DPF(D_INFO,
- "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n",
- rk, bl,
- x_coordinate[L][T][ch][rk][bl],
- x_coordinate[R][T][ch][rk][bl],
- x_coordinate[L][B][ch][rk][bl],
- x_coordinate[R][B][ch][rk][bl]);
- /* average the TOP side LEFT & RIGHT values */
- temp1 = (x_coordinate[R][T][ch][rk][bl] + x_coordinate[L][T][ch][rk][bl]) / 2;
- /* average the BOTTOM side LEFT & RIGHT values */
- temp2 = (x_coordinate[R][B][ch][rk][bl] + x_coordinate[L][B][ch][rk][bl]) / 2;
- /* average the above averages */
- x_center[ch][rk][bl] = (uint8_t) ((temp1 + temp2) / 2);
- /* y_coordinate */
- DPF(D_INFO,
- "VREF R/L eye lane%d : %d-%d %d-%d\n",
- bl,
- y_coordinate[R][B][ch][bl],
- y_coordinate[R][T][ch][bl],
- y_coordinate[L][B][ch][bl],
- y_coordinate[L][T][ch][bl]);
- /* average the RIGHT side TOP & BOTTOM values */
- temp1 = (y_coordinate[R][T][ch][bl] + y_coordinate[R][B][ch][bl]) / 2;
- /* average the LEFT side TOP & BOTTOM values */
- temp2 = (y_coordinate[L][T][ch][bl] + y_coordinate[L][B][ch][bl]) / 2;
- /* average the above averages */
- y_center[ch][bl] = (uint8_t) ((temp1 + temp2) / 2);
- }
- }
- }
- }
- }
- #ifdef RX_EYE_CHECK
- /* perform an eye check */
- for (side_y = B; side_y <= T; side_y++) {
- for (side_x = L; side_x <= R; side_x++) {
- mrc_post_code(0x07, 0x30 + side_y * 2 + side_x);
- /* update the settings for the eye check */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- if (side_x == L)
- set_rdqs(ch, rk, bl, x_center[ch][rk][bl] - (MIN_RDQS_EYE / 2));
- else
- set_rdqs(ch, rk, bl, x_center[ch][rk][bl] + (MIN_RDQS_EYE / 2));
- if (side_y == B)
- set_vref(ch, bl, y_center[ch][bl] - (MIN_VREF_EYE / 2));
- else
- set_vref(ch, bl, y_center[ch][bl] + (MIN_VREF_EYE / 2));
- }
- }
- }
- }
- }
- /* request HTE reconfiguration */
- mrc_params->hte_setup = 1;
- /* check the eye */
- if (check_bls_ex(mrc_params, address) & 0xff) {
- /* one or more byte lanes failed */
- mrc_post_code(0xee, 0x74 + side_x * 2 + side_y);
- }
- }
- }
- #endif
- mrc_post_code(0x07, 0x40);
- /* set final placements */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- #ifdef R2R_SHARING
- /* increment "num_ranks_enabled" */
- num_ranks_enabled++;
- #endif
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor); bl++) {
- /* x_coordinate */
- #ifdef R2R_SHARING
- final_delay[ch][bl] += x_center[ch][rk][bl];
- set_rdqs(ch, rk, bl, final_delay[ch][bl] / num_ranks_enabled);
- #else
- set_rdqs(ch, rk, bl, x_center[ch][rk][bl]);
- #endif
- /* y_coordinate */
- set_vref(ch, bl, y_center[ch][bl]);
- }
- }
- }
- }
- }
- #endif
- LEAVEFN();
- }
- /*
- * This function will perform the WRITE TRAINING Algorithm on all
- * channels/ranks/byte_lanes simultaneously to minimize execution time.
- *
- * The idea here is to train the WDQ timings to achieve maximum WRITE margins.
- * The algorithm will start with WDQ at the current WDQ setting (tracks WDQS
- * in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data
- * patterns pass. This is because WDQS will be aligned to WCLK by the
- * Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window
- * of validity.
- */
- void wr_train(struct mrc_params *mrc_params)
- {
- uint8_t ch; /* channel counter */
- uint8_t rk; /* rank counter */
- uint8_t bl; /* byte lane counter */
- uint8_t bl_divisor = (mrc_params->channel_width == X16) ? 2 : 1;
- #ifdef BACKUP_WDQ
- #else
- uint8_t side; /* LEFT/RIGHT side indicator (0=L, 1=R) */
- uint32_t temp; /* temporary DWORD */
- /* 2 arrays, for L & R side passing delays */
- uint32_t delay[2][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
- uint32_t address; /* target address for check_bls_ex() */
- uint32_t result; /* result of check_bls_ex() */
- uint32_t bl_mask; /* byte lane mask for result checking */
- #ifdef R2R_SHARING
- /* used to find placement for rank2rank sharing configs */
- uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES];
- /* used to find placement for rank2rank sharing configs */
- uint32_t num_ranks_enabled = 0;
- #endif
- #endif
- /* wr_train starts */
- mrc_post_code(0x08, 0x00);
- ENTERFN();
- #ifdef BACKUP_WDQ
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- for (bl = 0;
- bl < NUM_BYTE_LANES / bl_divisor;
- bl++) {
- set_wdq(ch, rk, bl, ddr_wdq[PLATFORM_ID]);
- }
- }
- }
- }
- }
- #else
- /* initialize "delay" */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- for (bl = 0;
- bl < NUM_BYTE_LANES / bl_divisor;
- bl++) {
- /*
- * want to start with
- * WDQ = (WDQS - QRTR_CLK)
- * +/- QRTR_CLK
- */
- temp = get_wdqs(ch, rk, bl) - QRTR_CLK;
- delay[L][ch][rk][bl] = temp - QRTR_CLK;
- delay[R][ch][rk][bl] = temp + QRTR_CLK;
- }
- }
- }
- }
- }
- /* initialize other variables */
- bl_mask = byte_lane_mask(mrc_params);
- address = get_addr(0, 0);
- #ifdef R2R_SHARING
- /* need to set "final_delay[][]" elements to "0" */
- memset((void *)(final_delay), 0x00, (size_t)sizeof(final_delay));
- #endif
- /*
- * start algorithm on the LEFT side and train each channel/bl
- * until no failures are observed, then repeat for the RIGHT side.
- */
- for (side = L; side <= R; side++) {
- mrc_post_code(0x08, 0x10 + side);
- /* set starting values */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables &
- (1 << rk)) {
- for (bl = 0;
- bl < NUM_BYTE_LANES / bl_divisor;
- bl++) {
- set_wdq(ch, rk, bl, delay[side][ch][rk][bl]);
- }
- }
- }
- }
- }
- /* find passing values */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables &
- (1 << rk)) {
- /* get an address in the target channel/rank */
- address = get_addr(ch, rk);
- /* request HTE reconfiguration */
- mrc_params->hte_setup = 1;
- /* check the settings */
- do {
- /* result[07:00] == failing byte lane (MAX 8) */
- result = check_bls_ex(mrc_params, address);
- /* check for failures */
- if (result & 0xff) {
- /* at least 1 byte lane failed */
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- if (result &
- (bl_mask << bl)) {
- if (side == L)
- delay[L][ch][rk][bl] += WDQ_STEP;
- else
- delay[R][ch][rk][bl] -= WDQ_STEP;
- /* check for algorithm failure */
- if (delay[L][ch][rk][bl] != delay[R][ch][rk][bl]) {
- /*
- * margin available
- * update delay setting
- */
- set_wdq(ch, rk, bl,
- delay[side][ch][rk][bl]);
- } else {
- /*
- * no margin available
- * notify the user and halt
- */
- training_message(ch, rk, bl);
- mrc_post_code(0xee, 0x80 + side);
- }
- }
- }
- }
- /* stop when all byte lanes pass */
- } while (result & 0xff);
- }
- }
- }
- }
- }
- /* program WDQ to the middle of passing window */
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- if (mrc_params->channel_enables & (1 << ch)) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- if (mrc_params->rank_enables & (1 << rk)) {
- #ifdef R2R_SHARING
- /* increment "num_ranks_enabled" */
- num_ranks_enabled++;
- #endif
- for (bl = 0; bl < NUM_BYTE_LANES / bl_divisor; bl++) {
- DPF(D_INFO,
- "WDQ eye rank%d lane%d : %d-%d\n",
- rk, bl,
- delay[L][ch][rk][bl],
- delay[R][ch][rk][bl]);
- temp = (delay[R][ch][rk][bl] + delay[L][ch][rk][bl]) / 2;
- #ifdef R2R_SHARING
- final_delay[ch][bl] += temp;
- set_wdq(ch, rk, bl,
- final_delay[ch][bl] / num_ranks_enabled);
- #else
- set_wdq(ch, rk, bl, temp);
- #endif
- }
- }
- }
- }
- }
- #endif
- LEAVEFN();
- }
- /*
- * This function will store relevant timing data
- *
- * This data will be used on subsequent boots to speed up boot times
- * and is required for Suspend To RAM capabilities.
- */
- void store_timings(struct mrc_params *mrc_params)
- {
- uint8_t ch, rk, bl;
- struct mrc_timings *mt = &mrc_params->timings;
- for (ch = 0; ch < NUM_CHANNELS; ch++) {
- for (rk = 0; rk < NUM_RANKS; rk++) {
- for (bl = 0; bl < NUM_BYTE_LANES; bl++) {
- mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl);
- mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl);
- mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl);
- mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl);
- if (rk == 0)
- mt->vref[ch][bl] = get_vref(ch, bl);
- }
- mt->wctl[ch][rk] = get_wctl(ch, rk);
- }
- mt->wcmd[ch] = get_wcmd(ch);
- }
- /* need to save for a case of changing frequency after warm reset */
- mt->ddr_speed = mrc_params->ddr_speed;
- }
- /*
- * The purpose of this function is to ensure the SEC comes out of reset
- * and IA initiates the SEC enabling Memory Scrambling.
- */
- void enable_scrambling(struct mrc_params *mrc_params)
- {
- uint32_t lfsr = 0;
- uint8_t i;
- if (mrc_params->scrambling_enables == 0)
- return;
- ENTERFN();
- /* 32 bit seed is always stored in BIOS NVM */
- lfsr = mrc_params->timings.scrambler_seed;
- if (mrc_params->boot_mode == BM_COLD) {
- /*
- * factory value is 0 and in first boot,
- * a clock based seed is loaded.
- */
- if (lfsr == 0) {
- /*
- * get seed from system clock
- * and make sure it is not all 1's
- */
- lfsr = rdtsc() & 0x0fffffff;
- } else {
- /*
- * Need to replace scrambler
- *
- * get next 32bit LFSR 16 times which is the last
- * part of the previous scrambler vector
- */
- for (i = 0; i < 16; i++)
- lfsr32(&lfsr);
- }
- /* save new seed */
- mrc_params->timings.scrambler_seed = lfsr;
- }
- /*
- * In warm boot or S3 exit, we have the previous seed.
- * In cold boot, we have the last 32bit LFSR which is the new seed.
- */
- lfsr32(&lfsr); /* shift to next value */
- msg_port_write(MEM_CTLR, SCRMSEED, (lfsr & 0x0003ffff));
- for (i = 0; i < 2; i++)
- msg_port_write(MEM_CTLR, SCRMLO + i, (lfsr & 0xaaaaaaaa));
- LEAVEFN();
- }
- /*
- * Configure MCU Power Management Control Register
- * and Scheduler Control Register
- */
- void prog_ddr_control(struct mrc_params *mrc_params)
- {
- u32 dsch;
- u32 dpmc0;
- ENTERFN();
- dsch = msg_port_read(MEM_CTLR, DSCH);
- dsch &= ~(DSCH_OOODIS | DSCH_OOOST3DIS | DSCH_NEWBYPDIS);
- msg_port_write(MEM_CTLR, DSCH, dsch);
- dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
- dpmc0 &= ~DPMC0_DISPWRDN;
- dpmc0 |= (mrc_params->power_down_disable << 25);
- dpmc0 &= ~DPMC0_CLKGTDIS;
- dpmc0 &= ~DPMC0_PCLSTO_MASK;
- dpmc0 |= (4 << 16);
- dpmc0 |= DPMC0_PREAPWDEN;
- msg_port_write(MEM_CTLR, DPMC0, dpmc0);
- /* CMDTRIST = 2h - CMD/ADDR are tristated when no valid command */
- mrc_write_mask(MEM_CTLR, DPMC1, 0x20, 0x30);
- LEAVEFN();
- }
- /*
- * After training complete configure MCU Rank Population Register
- * specifying: ranks enabled, device width, density, address mode
- */
- void prog_dra_drb(struct mrc_params *mrc_params)
- {
- u32 drp;
- u32 dco;
- u8 density = mrc_params->params.density;
- ENTERFN();
- dco = msg_port_read(MEM_CTLR, DCO);
- dco &= ~DCO_IC;
- msg_port_write(MEM_CTLR, DCO, dco);
- drp = 0;
- if (mrc_params->rank_enables & 1)
- drp |= DRP_RKEN0;
- if (mrc_params->rank_enables & 2)
- drp |= DRP_RKEN1;
- if (mrc_params->dram_width == X16) {
- drp |= (1 << 4);
- drp |= (1 << 9);
- }
- /*
- * Density encoding in struct dram_params: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
- * has to be mapped RANKDENSx encoding (0=1Gb)
- */
- if (density == 0)
- density = 4;
- drp |= ((density - 1) << 6);
- drp |= ((density - 1) << 11);
- /* Address mode can be overwritten if ECC enabled */
- drp |= (mrc_params->address_mode << 14);
- msg_port_write(MEM_CTLR, DRP, drp);
- dco &= ~DCO_PMICTL;
- dco |= DCO_IC;
- msg_port_write(MEM_CTLR, DCO, dco);
- LEAVEFN();
- }
- /* Send DRAM wake command */
- void perform_wake(struct mrc_params *mrc_params)
- {
- ENTERFN();
- dram_wake_command();
- LEAVEFN();
- }
- /*
- * Configure refresh rate and short ZQ calibration interval
- * Activate dynamic self refresh
- */
- void change_refresh_period(struct mrc_params *mrc_params)
- {
- u32 drfc;
- u32 dcal;
- u32 dpmc0;
- ENTERFN();
- drfc = msg_port_read(MEM_CTLR, DRFC);
- drfc &= ~DRFC_TREFI_MASK;
- drfc |= (mrc_params->refresh_rate << 12);
- drfc |= DRFC_REFDBTCLR;
- msg_port_write(MEM_CTLR, DRFC, drfc);
- dcal = msg_port_read(MEM_CTLR, DCAL);
- dcal &= ~DCAL_ZQCINT_MASK;
- dcal |= (3 << 8); /* 63ms */
- msg_port_write(MEM_CTLR, DCAL, dcal);
- dpmc0 = msg_port_read(MEM_CTLR, DPMC0);
- dpmc0 |= (DPMC0_DYNSREN | DPMC0_ENPHYCLKGATE);
- msg_port_write(MEM_CTLR, DPMC0, dpmc0);
- LEAVEFN();
- }
- /*
- * Configure DDRPHY for Auto-Refresh, Periodic Compensations,
- * Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
- */
- void set_auto_refresh(struct mrc_params *mrc_params)
- {
- uint32_t channel;
- uint32_t rank;
- uint32_t bl;
- uint32_t bl_divisor = 1;
- uint32_t temp;
- ENTERFN();
- /*
- * Enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp,
- * ZQSPERIOD, Auto-Precharge, CKE Power-Down
- */
- for (channel = 0; channel < NUM_CHANNELS; channel++) {
- if (mrc_params->channel_enables & (1 << channel)) {
- /* Enable Periodic RCOMPS */
- mrc_alt_write_mask(DDRPHY, CMPCTRL, 2, 2);
- /* Enable Dynamic DiffAmp & Set Read ODT Value */
- switch (mrc_params->rd_odt_value) {
- case 0:
- temp = 0x3f; /* OFF */
- break;
- default:
- temp = 0x00; /* Auto */
- break;
- }
- for (bl = 0; bl < (NUM_BYTE_LANES / bl_divisor) / 2; bl++) {
- /* Override: DIFFAMP, ODT */
- mrc_alt_write_mask(DDRPHY,
- B0OVRCTL + bl * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET,
- temp << 10,
- 0x003ffc00);
- /* Override: DIFFAMP, ODT */
- mrc_alt_write_mask(DDRPHY,
- B1OVRCTL + bl * DDRIODQ_BL_OFFSET +
- channel * DDRIODQ_CH_OFFSET,
- temp << 10,
- 0x003ffc00);
- }
- /* Issue ZQCS command */
- for (rank = 0; rank < NUM_RANKS; rank++) {
- if (mrc_params->rank_enables & (1 << rank))
- dram_init_command(DCMD_ZQCS(rank));
- }
- }
- }
- clear_pointers();
- LEAVEFN();
- }
- /*
- * Depending on configuration enables ECC support
- *
- * Available memory size is decreased, and updated with 0s
- * in order to clear error status. Address mode 2 forced.
- */
- void ecc_enable(struct mrc_params *mrc_params)
- {
- u32 drp;
- u32 dsch;
- u32 ecc_ctrl;
- if (mrc_params->ecc_enables == 0)
- return;
- ENTERFN();
- /* Configuration required in ECC mode */
- drp = msg_port_read(MEM_CTLR, DRP);
- drp &= ~DRP_ADDRMAP_MASK;
- drp |= DRP_ADDRMAP_MAP1;
- drp |= DRP_PRI64BSPLITEN;
- msg_port_write(MEM_CTLR, DRP, drp);
- /* Disable new request bypass */
- dsch = msg_port_read(MEM_CTLR, DSCH);
- dsch |= DSCH_NEWBYPDIS;
- msg_port_write(MEM_CTLR, DSCH, dsch);
- /* Enable ECC */
- ecc_ctrl = (DECCCTRL_SBEEN | DECCCTRL_DBEEN | DECCCTRL_ENCBGEN);
- msg_port_write(MEM_CTLR, DECCCTRL, ecc_ctrl);
- /* Assume 8 bank memory, one bank is gone for ECC */
- mrc_params->mem_size -= mrc_params->mem_size / 8;
- /* For S3 resume memory content has to be preserved */
- if (mrc_params->boot_mode != BM_S3) {
- select_hte();
- hte_mem_init(mrc_params, MRC_MEM_INIT);
- select_mem_mgr();
- }
- LEAVEFN();
- }
- /*
- * Execute memory test
- * if error detected it is indicated in mrc_params->status
- */
- void memory_test(struct mrc_params *mrc_params)
- {
- uint32_t result = 0;
- ENTERFN();
- select_hte();
- result = hte_mem_init(mrc_params, MRC_MEM_TEST);
- select_mem_mgr();
- DPF(D_INFO, "Memory test result %x\n", result);
- mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);
- LEAVEFN();
- }
- /* Lock MCU registers at the end of initialization sequence */
- void lock_registers(struct mrc_params *mrc_params)
- {
- u32 dco;
- ENTERFN();
- dco = msg_port_read(MEM_CTLR, DCO);
- dco &= ~(DCO_PMICTL | DCO_PMIDIS);
- dco |= (DCO_DRPLOCK | DCO_CPGCLOCK);
- msg_port_write(MEM_CTLR, DCO, dco);
- LEAVEFN();
- }
|