1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved.
- */
- #include <linux/kernel.h>
- #include <linux/io.h>
- #include <linux/clk.h>
- #include <linux/delay.h>
- #include <linux/of.h>
- #include <soc/tegra/mc.h>
- #include "tegra210-emc.h"
- #include "tegra210-mc.h"
- /*
- * Enable flags for specifying verbosity.
- */
- #define INFO (1 << 0)
- #define STEPS (1 << 1)
- #define SUB_STEPS (1 << 2)
- #define PRELOCK (1 << 3)
- #define PRELOCK_STEPS (1 << 4)
- #define ACTIVE_EN (1 << 5)
- #define PRAMP_UP (1 << 6)
- #define PRAMP_DN (1 << 7)
- #define EMA_WRITES (1 << 10)
- #define EMA_UPDATES (1 << 11)
- #define PER_TRAIN (1 << 16)
- #define CC_PRINT (1 << 17)
- #define CCFIFO (1 << 29)
- #define REGS (1 << 30)
- #define REG_LISTS (1 << 31)
- #define emc_dbg(emc, flags, ...) dev_dbg(emc->dev, __VA_ARGS__)
- #define DVFS_CLOCK_CHANGE_VERSION 21021
- #define EMC_PRELOCK_VERSION 2101
- enum {
- DVFS_SEQUENCE = 1,
- WRITE_TRAINING_SEQUENCE = 2,
- PERIODIC_TRAINING_SEQUENCE = 3,
- DVFS_PT1 = 10,
- DVFS_UPDATE = 11,
- TRAINING_PT1 = 12,
- TRAINING_UPDATE = 13,
- PERIODIC_TRAINING_UPDATE = 14
- };
- /*
- * PTFV defines - basically just indexes into the per table PTFV array.
- */
- #define PTFV_DQSOSC_MOVAVG_C0D0U0_INDEX 0
- #define PTFV_DQSOSC_MOVAVG_C0D0U1_INDEX 1
- #define PTFV_DQSOSC_MOVAVG_C0D1U0_INDEX 2
- #define PTFV_DQSOSC_MOVAVG_C0D1U1_INDEX 3
- #define PTFV_DQSOSC_MOVAVG_C1D0U0_INDEX 4
- #define PTFV_DQSOSC_MOVAVG_C1D0U1_INDEX 5
- #define PTFV_DQSOSC_MOVAVG_C1D1U0_INDEX 6
- #define PTFV_DQSOSC_MOVAVG_C1D1U1_INDEX 7
- #define PTFV_DVFS_SAMPLES_INDEX 9
- #define PTFV_MOVAVG_WEIGHT_INDEX 10
- #define PTFV_CONFIG_CTRL_INDEX 11
- #define PTFV_CONFIG_CTRL_USE_PREVIOUS_EMA (1 << 0)
- /*
- * Do arithmetic in fixed point.
- */
- #define MOVAVG_PRECISION_FACTOR 100
- /*
- * The division portion of the average operation.
- */
- #define __AVERAGE_PTFV(dev) \
- ({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] = \
- next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \
- next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; })
- /*
- * Convert val to fixed point and add it to the temporary average.
- */
- #define __INCREMENT_PTFV(dev, val) \
- ({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] += \
- ((val) * MOVAVG_PRECISION_FACTOR); })
- /*
- * Convert a moving average back to integral form and return the value.
- */
- #define __MOVAVG_AC(timing, dev) \
- ((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \
- MOVAVG_PRECISION_FACTOR)
- /* Weighted update. */
- #define __WEIGHTED_UPDATE_PTFV(dev, nval) \
- do { \
- int w = PTFV_MOVAVG_WEIGHT_INDEX; \
- int dqs = PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX; \
- \
- next->ptfv_list[dqs] = \
- ((nval * MOVAVG_PRECISION_FACTOR) + \
- (next->ptfv_list[dqs] * \
- next->ptfv_list[w])) / \
- (next->ptfv_list[w] + 1); \
- \
- emc_dbg(emc, EMA_UPDATES, "%s: (s=%lu) EMA: %u\n", \
- __stringify(dev), nval, next->ptfv_list[dqs]); \
- } while (0)
- /* Access a particular average. */
- #define __MOVAVG(timing, dev) \
- ((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX])
- static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type)
- {
- bool periodic_training_update = type == PERIODIC_TRAINING_UPDATE;
- struct tegra210_emc_timing *last = emc->last;
- struct tegra210_emc_timing *next = emc->next;
- u32 last_timing_rate_mhz = last->rate / 1000;
- u32 next_timing_rate_mhz = next->rate / 1000;
- bool dvfs_update = type == DVFS_UPDATE;
- s32 tdel = 0, tmdel = 0, adel = 0;
- bool dvfs_pt1 = type == DVFS_PT1;
- unsigned long cval = 0;
- u32 temp[2][2], value;
- unsigned int i;
- /*
- * Dev0 MSB.
- */
- if (dvfs_pt1 || periodic_training_update) {
- value = tegra210_emc_mrr_read(emc, 2, 19);
- for (i = 0; i < emc->num_channels; i++) {
- temp[i][0] = (value & 0x00ff) << 8;
- temp[i][1] = (value & 0xff00) << 0;
- value >>= 16;
- }
- /*
- * Dev0 LSB.
- */
- value = tegra210_emc_mrr_read(emc, 2, 18);
- for (i = 0; i < emc->num_channels; i++) {
- temp[i][0] |= (value & 0x00ff) >> 0;
- temp[i][1] |= (value & 0xff00) >> 8;
- value >>= 16;
- }
- }
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[0][0];
- }
- if (dvfs_pt1)
- __INCREMENT_PTFV(C0D0U0, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C0D0U0);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C0D0U0, cval);
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C0D0U0] -
- __MOVAVG_AC(next, C0D0U0);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- adel = tmdel;
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C0D0U0] =
- __MOVAVG_AC(next, C0D0U0);
- }
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[0][1];
- }
- if (dvfs_pt1)
- __INCREMENT_PTFV(C0D0U1, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C0D0U1);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C0D0U1, cval);
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C0D0U1] -
- __MOVAVG_AC(next, C0D0U1);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- if (tmdel > adel)
- adel = tmdel;
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C0D0U1] =
- __MOVAVG_AC(next, C0D0U1);
- }
- if (emc->num_channels > 1) {
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[1][0];
- }
- if (dvfs_pt1)
- __INCREMENT_PTFV(C1D0U0, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C1D0U0);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C1D0U0, cval);
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C1D0U0] -
- __MOVAVG_AC(next, C1D0U0);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- if (tmdel > adel)
- adel = tmdel;
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C1D0U0] =
- __MOVAVG_AC(next, C1D0U0);
- }
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[1][1];
- }
- if (dvfs_pt1)
- __INCREMENT_PTFV(C1D0U1, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C1D0U1);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C1D0U1, cval);
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C1D0U1] -
- __MOVAVG_AC(next, C1D0U1);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- if (tmdel > adel)
- adel = tmdel;
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C1D0U1] =
- __MOVAVG_AC(next, C1D0U1);
- }
- }
- if (emc->num_devices < 2)
- goto done;
- /*
- * Dev1 MSB.
- */
- if (dvfs_pt1 || periodic_training_update) {
- value = tegra210_emc_mrr_read(emc, 1, 19);
- for (i = 0; i < emc->num_channels; i++) {
- temp[i][0] = (value & 0x00ff) << 8;
- temp[i][1] = (value & 0xff00) << 0;
- value >>= 16;
- }
- /*
- * Dev1 LSB.
- */
- value = tegra210_emc_mrr_read(emc, 2, 18);
- for (i = 0; i < emc->num_channels; i++) {
- temp[i][0] |= (value & 0x00ff) >> 0;
- temp[i][1] |= (value & 0xff00) >> 8;
- value >>= 16;
- }
- }
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[0][0];
- }
- if (dvfs_pt1)
- __INCREMENT_PTFV(C0D1U0, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C0D1U0);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C0D1U0, cval);
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C0D1U0] -
- __MOVAVG_AC(next, C0D1U0);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- if (tmdel > adel)
- adel = tmdel;
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C0D1U0] =
- __MOVAVG_AC(next, C0D1U0);
- }
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[0][1];
- }
- if (dvfs_pt1)
- __INCREMENT_PTFV(C0D1U1, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C0D1U1);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C0D1U1, cval);
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C0D1U1] -
- __MOVAVG_AC(next, C0D1U1);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- if (tmdel > adel)
- adel = tmdel;
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C0D1U1] =
- __MOVAVG_AC(next, C0D1U1);
- }
- if (emc->num_channels > 1) {
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[1][0];
- }
- if (dvfs_pt1)
- __INCREMENT_PTFV(C1D1U0, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C1D1U0);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C1D1U0, cval);
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C1D1U0] -
- __MOVAVG_AC(next, C1D1U0);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- if (tmdel > adel)
- adel = tmdel;
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C1D1U0] =
- __MOVAVG_AC(next, C1D1U0);
- }
- if (dvfs_pt1 || periodic_training_update) {
- cval = tegra210_emc_actual_osc_clocks(last->run_clocks);
- cval *= 1000000;
- cval /= last_timing_rate_mhz * 2 * temp[1][1];
- }
- if (dvfs_pt1)
- __INCREMENT_PTFV(C1D1U1, cval);
- else if (dvfs_update)
- __AVERAGE_PTFV(C1D1U1);
- else if (periodic_training_update)
- __WEIGHTED_UPDATE_PTFV(C1D1U1, cval);
- if (dvfs_update || periodic_training_update) {
- tdel = next->current_dram_clktree[C1D1U1] -
- __MOVAVG_AC(next, C1D1U1);
- tmdel = (tdel < 0) ? -1 * tdel : tdel;
- if (tmdel > adel)
- adel = tmdel;
- if (tmdel * 128 * next_timing_rate_mhz / 1000000 >
- next->tree_margin)
- next->current_dram_clktree[C1D1U1] =
- __MOVAVG_AC(next, C1D1U1);
- }
- }
- done:
- return adel;
- }
- static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type,
- struct tegra210_emc_timing *last,
- struct tegra210_emc_timing *next)
- {
- #define __COPY_EMA(nt, lt, dev) \
- ({ __MOVAVG(nt, dev) = __MOVAVG(lt, dev) * \
- (nt)->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; })
- u32 i, adel = 0, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX];
- u32 delay;
- delay = tegra210_emc_actual_osc_clocks(last->run_clocks);
- delay *= 1000;
- delay = 2 + (delay / last->rate);
- if (!next->periodic_training)
- return 0;
- if (type == DVFS_SEQUENCE) {
- if (last->periodic_training &&
- (next->ptfv_list[PTFV_CONFIG_CTRL_INDEX] &
- PTFV_CONFIG_CTRL_USE_PREVIOUS_EMA)) {
- /*
- * If the previous frequency was using periodic
- * calibration then we can reuse the previous
- * frequencies EMA data.
- */
- __COPY_EMA(next, last, C0D0U0);
- __COPY_EMA(next, last, C0D0U1);
- __COPY_EMA(next, last, C1D0U0);
- __COPY_EMA(next, last, C1D0U1);
- __COPY_EMA(next, last, C0D1U0);
- __COPY_EMA(next, last, C0D1U1);
- __COPY_EMA(next, last, C1D1U0);
- __COPY_EMA(next, last, C1D1U1);
- } else {
- /* Reset the EMA.*/
- __MOVAVG(next, C0D0U0) = 0;
- __MOVAVG(next, C0D0U1) = 0;
- __MOVAVG(next, C1D0U0) = 0;
- __MOVAVG(next, C1D0U1) = 0;
- __MOVAVG(next, C0D1U0) = 0;
- __MOVAVG(next, C0D1U1) = 0;
- __MOVAVG(next, C1D1U0) = 0;
- __MOVAVG(next, C1D1U1) = 0;
- for (i = 0; i < samples; i++) {
- tegra210_emc_start_periodic_compensation(emc);
- udelay(delay);
- /*
- * Generate next sample of data.
- */
- adel = update_clock_tree_delay(emc, DVFS_PT1);
- }
- }
- /*
- * Seems like it should be part of the
- * 'if (last_timing->periodic_training)' conditional
- * since is already done for the else clause.
- */
- adel = update_clock_tree_delay(emc, DVFS_UPDATE);
- }
- if (type == PERIODIC_TRAINING_SEQUENCE) {
- tegra210_emc_start_periodic_compensation(emc);
- udelay(delay);
- adel = update_clock_tree_delay(emc, PERIODIC_TRAINING_UPDATE);
- }
- return adel;
- }
- static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc)
- {
- u32 emc_cfg, emc_cfg_o, emc_cfg_update, del, value;
- static const u32 list[] = {
- EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0,
- EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1,
- EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2,
- EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3,
- EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0,
- EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1,
- EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2,
- EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3,
- EMC_DATA_BRLSHFT_0,
- EMC_DATA_BRLSHFT_1
- };
- struct tegra210_emc_timing *last = emc->last;
- unsigned int items = ARRAY_SIZE(list), i;
- unsigned long delay;
- if (last->periodic_training) {
- emc_dbg(emc, PER_TRAIN, "Periodic training starting\n");
- value = emc_readl(emc, EMC_DBG);
- emc_cfg_o = emc_readl(emc, EMC_CFG);
- emc_cfg = emc_cfg_o & ~(EMC_CFG_DYN_SELF_REF |
- EMC_CFG_DRAM_ACPD |
- EMC_CFG_DRAM_CLKSTOP_PD);
- /*
- * 1. Power optimizations should be off.
- */
- emc_writel(emc, emc_cfg, EMC_CFG);
- /* Does emc_timing_update() for above changes. */
- tegra210_emc_dll_disable(emc);
- for (i = 0; i < emc->num_channels; i++)
- tegra210_emc_wait_for_update(emc, i, EMC_EMC_STATUS,
- EMC_EMC_STATUS_DRAM_IN_POWERDOWN_MASK,
- 0);
- for (i = 0; i < emc->num_channels; i++)
- tegra210_emc_wait_for_update(emc, i, EMC_EMC_STATUS,
- EMC_EMC_STATUS_DRAM_IN_SELF_REFRESH_MASK,
- 0);
- emc_cfg_update = value = emc_readl(emc, EMC_CFG_UPDATE);
- value &= ~EMC_CFG_UPDATE_UPDATE_DLL_IN_UPDATE_MASK;
- value |= (2 << EMC_CFG_UPDATE_UPDATE_DLL_IN_UPDATE_SHIFT);
- emc_writel(emc, value, EMC_CFG_UPDATE);
- /*
- * 2. osc kick off - this assumes training and dvfs have set
- * correct MR23.
- */
- tegra210_emc_start_periodic_compensation(emc);
- /*
- * 3. Let dram capture its clock tree delays.
- */
- delay = tegra210_emc_actual_osc_clocks(last->run_clocks);
- delay *= 1000;
- delay /= last->rate + 1;
- udelay(delay);
- /*
- * 4. Check delta wrt previous values (save value if margin
- * exceeds what is set in table).
- */
- del = periodic_compensation_handler(emc,
- PERIODIC_TRAINING_SEQUENCE,
- last, last);
- /*
- * 5. Apply compensation w.r.t. trained values (if clock tree
- * has drifted more than the set margin).
- */
- if (last->tree_margin < ((del * 128 * (last->rate / 1000)) / 1000000)) {
- for (i = 0; i < items; i++) {
- value = tegra210_emc_compensate(last, list[i]);
- emc_dbg(emc, EMA_WRITES, "0x%08x <= 0x%08x\n",
- list[i], value);
- emc_writel(emc, value, list[i]);
- }
- }
- emc_writel(emc, emc_cfg_o, EMC_CFG);
- /*
- * 6. Timing update actally applies the new trimmers.
- */
- tegra210_emc_timing_update(emc);
- /* 6.1. Restore the UPDATE_DLL_IN_UPDATE field. */
- emc_writel(emc, emc_cfg_update, EMC_CFG_UPDATE);
- /* 6.2. Restore the DLL. */
- tegra210_emc_dll_enable(emc);
- }
- return 0;
- }
- /*
- * Do the clock change sequence.
- */
- static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc)
- {
- /* state variables */
- static bool fsp_for_next_freq;
- /* constant configuration parameters */
- const bool save_restore_clkstop_pd = true;
- const u32 zqcal_before_cc_cutoff = 2400;
- const bool cya_allow_ref_cc = false;
- const bool cya_issue_pc_ref = false;
- const bool opt_cc_short_zcal = true;
- const bool ref_b4_sref_en = false;
- const u32 tZQCAL_lpddr4 = 1000000;
- const bool opt_short_zcal = true;
- const bool opt_do_sw_qrst = true;
- const u32 opt_dvfs_mode = MAN_SR;
- /*
- * This is the timing table for the source frequency. It does _not_
- * necessarily correspond to the actual timing values in the EMC at the
- * moment. If the boot BCT differs from the table then this can happen.
- * However, we need it for accessing the dram_timings (which are not
- * really registers) array for the current frequency.
- */
- struct tegra210_emc_timing *fake, *last = emc->last, *next = emc->next;
- u32 tRTM, RP_war, R2P_war, TRPab_war, deltaTWATM, W2P_war, tRPST;
- u32 mr13_flip_fspwr, mr13_flip_fspop, ramp_up_wait, ramp_down_wait;
- u32 zq_wait_long, zq_latch_dvfs_wait_time, tZQCAL_lpddr4_fc_adj;
- u32 emc_auto_cal_config, auto_cal_en, emc_cfg, emc_sel_dpd_ctrl;
- u32 tFC_lpddr4 = 1000 * next->dram_timings[T_FC_LPDDR4];
- u32 bg_reg_mode_change, enable_bglp_reg, enable_bg_reg;
- bool opt_zcal_en_cc = false, is_lpddr3 = false;
- bool compensate_trimmer_applicable = false;
- u32 emc_dbg, emc_cfg_pipe_clk, emc_pin;
- u32 src_clk_period, dst_clk_period; /* in picoseconds */
- bool shared_zq_resistor = false;
- u32 value, dram_type;
- u32 opt_dll_mode = 0;
- unsigned long delay;
- unsigned int i;
- emc_dbg(emc, INFO, "Running clock change.\n");
- /* XXX fake == last */
- fake = tegra210_emc_find_timing(emc, last->rate * 1000UL);
- fsp_for_next_freq = !fsp_for_next_freq;
- value = emc_readl(emc, EMC_FBIO_CFG5) & EMC_FBIO_CFG5_DRAM_TYPE_MASK;
- dram_type = value >> EMC_FBIO_CFG5_DRAM_TYPE_SHIFT;
- if (last->burst_regs[EMC_ZCAL_WAIT_CNT_INDEX] & BIT(31))
- shared_zq_resistor = true;
- if ((next->burst_regs[EMC_ZCAL_INTERVAL_INDEX] != 0 &&
- last->burst_regs[EMC_ZCAL_INTERVAL_INDEX] == 0) ||
- dram_type == DRAM_TYPE_LPDDR4)
- opt_zcal_en_cc = true;
- if (dram_type == DRAM_TYPE_DDR3)
- opt_dll_mode = tegra210_emc_get_dll_state(next);
- if ((next->burst_regs[EMC_FBIO_CFG5_INDEX] & BIT(25)) &&
- (dram_type == DRAM_TYPE_LPDDR2))
- is_lpddr3 = true;
- emc_readl(emc, EMC_CFG);
- emc_readl(emc, EMC_AUTO_CAL_CONFIG);
- src_clk_period = 1000000000 / last->rate;
- dst_clk_period = 1000000000 / next->rate;
- if (dst_clk_period <= zqcal_before_cc_cutoff)
- tZQCAL_lpddr4_fc_adj = tZQCAL_lpddr4 - tFC_lpddr4;
- else
- tZQCAL_lpddr4_fc_adj = tZQCAL_lpddr4;
- tZQCAL_lpddr4_fc_adj /= dst_clk_period;
- emc_dbg = emc_readl(emc, EMC_DBG);
- emc_pin = emc_readl(emc, EMC_PIN);
- emc_cfg_pipe_clk = emc_readl(emc, EMC_CFG_PIPE_CLK);
- emc_cfg = next->burst_regs[EMC_CFG_INDEX];
- emc_cfg &= ~(EMC_CFG_DYN_SELF_REF | EMC_CFG_DRAM_ACPD |
- EMC_CFG_DRAM_CLKSTOP_SR | EMC_CFG_DRAM_CLKSTOP_PD);
- emc_sel_dpd_ctrl = next->emc_sel_dpd_ctrl;
- emc_sel_dpd_ctrl &= ~(EMC_SEL_DPD_CTRL_CLK_SEL_DPD_EN |
- EMC_SEL_DPD_CTRL_CA_SEL_DPD_EN |
- EMC_SEL_DPD_CTRL_RESET_SEL_DPD_EN |
- EMC_SEL_DPD_CTRL_ODT_SEL_DPD_EN |
- EMC_SEL_DPD_CTRL_DATA_SEL_DPD_EN);
- emc_dbg(emc, INFO, "Clock change version: %d\n",
- DVFS_CLOCK_CHANGE_VERSION);
- emc_dbg(emc, INFO, "DRAM type = %d\n", dram_type);
- emc_dbg(emc, INFO, "DRAM dev #: %u\n", emc->num_devices);
- emc_dbg(emc, INFO, "Next EMC clksrc: 0x%08x\n", clksrc);
- emc_dbg(emc, INFO, "DLL clksrc: 0x%08x\n", next->dll_clk_src);
- emc_dbg(emc, INFO, "last rate: %u, next rate %u\n", last->rate,
- next->rate);
- emc_dbg(emc, INFO, "last period: %u, next period: %u\n",
- src_clk_period, dst_clk_period);
- emc_dbg(emc, INFO, " shared_zq_resistor: %d\n", !!shared_zq_resistor);
- emc_dbg(emc, INFO, " num_channels: %u\n", emc->num_channels);
- emc_dbg(emc, INFO, " opt_dll_mode: %d\n", opt_dll_mode);
- /*
- * Step 1:
- * Pre DVFS SW sequence.
- */
- emc_dbg(emc, STEPS, "Step 1\n");
- emc_dbg(emc, STEPS, "Step 1.1: Disable DLL temporarily.\n");
- value = emc_readl(emc, EMC_CFG_DIG_DLL);
- value &= ~EMC_CFG_DIG_DLL_CFG_DLL_EN;
- emc_writel(emc, value, EMC_CFG_DIG_DLL);
- tegra210_emc_timing_update(emc);
- for (i = 0; i < emc->num_channels; i++)
- tegra210_emc_wait_for_update(emc, i, EMC_CFG_DIG_DLL,
- EMC_CFG_DIG_DLL_CFG_DLL_EN, 0);
- emc_dbg(emc, STEPS, "Step 1.2: Disable AUTOCAL temporarily.\n");
- emc_auto_cal_config = next->emc_auto_cal_config;
- auto_cal_en = emc_auto_cal_config & EMC_AUTO_CAL_CONFIG_AUTO_CAL_ENABLE;
- emc_auto_cal_config &= ~EMC_AUTO_CAL_CONFIG_AUTO_CAL_START;
- emc_auto_cal_config |= EMC_AUTO_CAL_CONFIG_AUTO_CAL_MEASURE_STALL;
- emc_auto_cal_config |= EMC_AUTO_CAL_CONFIG_AUTO_CAL_UPDATE_STALL;
- emc_auto_cal_config |= auto_cal_en;
- emc_writel(emc, emc_auto_cal_config, EMC_AUTO_CAL_CONFIG);
- emc_readl(emc, EMC_AUTO_CAL_CONFIG); /* Flush write. */
- emc_dbg(emc, STEPS, "Step 1.3: Disable other power features.\n");
- tegra210_emc_set_shadow_bypass(emc, ACTIVE);
- emc_writel(emc, emc_cfg, EMC_CFG);
- emc_writel(emc, emc_sel_dpd_ctrl, EMC_SEL_DPD_CTRL);
- tegra210_emc_set_shadow_bypass(emc, ASSEMBLY);
- if (next->periodic_training) {
- tegra210_emc_reset_dram_clktree_values(next);
- for (i = 0; i < emc->num_channels; i++)
- tegra210_emc_wait_for_update(emc, i, EMC_EMC_STATUS,
- EMC_EMC_STATUS_DRAM_IN_POWERDOWN_MASK,
- 0);
- for (i = 0; i < emc->num_channels; i++)
- tegra210_emc_wait_for_update(emc, i, EMC_EMC_STATUS,
- EMC_EMC_STATUS_DRAM_IN_SELF_REFRESH_MASK,
- 0);
- tegra210_emc_start_periodic_compensation(emc);
- delay = 1000 * tegra210_emc_actual_osc_clocks(last->run_clocks);
- udelay((delay / last->rate) + 2);
- value = periodic_compensation_handler(emc, DVFS_SEQUENCE, fake,
- next);
- value = (value * 128 * next->rate / 1000) / 1000000;
- if (next->periodic_training && value > next->tree_margin)
- compensate_trimmer_applicable = true;
- }
- emc_writel(emc, EMC_INTSTATUS_CLKCHANGE_COMPLETE, EMC_INTSTATUS);
- tegra210_emc_set_shadow_bypass(emc, ACTIVE);
- emc_writel(emc, emc_cfg, EMC_CFG);
- emc_writel(emc, emc_sel_dpd_ctrl, EMC_SEL_DPD_CTRL);
- emc_writel(emc, emc_cfg_pipe_clk | EMC_CFG_PIPE_CLK_CLK_ALWAYS_ON,
- EMC_CFG_PIPE_CLK);
- emc_writel(emc, next->emc_fdpd_ctrl_cmd_no_ramp &
- ~EMC_FDPD_CTRL_CMD_NO_RAMP_CMD_DPD_NO_RAMP_ENABLE,
- EMC_FDPD_CTRL_CMD_NO_RAMP);
- bg_reg_mode_change =
- ((next->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- EMC_PMACRO_BG_BIAS_CTRL_0_BGLP_E_PWRD) ^
- (last->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- EMC_PMACRO_BG_BIAS_CTRL_0_BGLP_E_PWRD)) ||
- ((next->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- EMC_PMACRO_BG_BIAS_CTRL_0_BG_E_PWRD) ^
- (last->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- EMC_PMACRO_BG_BIAS_CTRL_0_BG_E_PWRD));
- enable_bglp_reg =
- (next->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- EMC_PMACRO_BG_BIAS_CTRL_0_BGLP_E_PWRD) == 0;
- enable_bg_reg =
- (next->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- EMC_PMACRO_BG_BIAS_CTRL_0_BG_E_PWRD) == 0;
- if (bg_reg_mode_change) {
- if (enable_bg_reg)
- emc_writel(emc, last->burst_regs
- [EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- ~EMC_PMACRO_BG_BIAS_CTRL_0_BG_E_PWRD,
- EMC_PMACRO_BG_BIAS_CTRL_0);
- if (enable_bglp_reg)
- emc_writel(emc, last->burst_regs
- [EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- ~EMC_PMACRO_BG_BIAS_CTRL_0_BGLP_E_PWRD,
- EMC_PMACRO_BG_BIAS_CTRL_0);
- }
- /* Check if we need to turn on VREF generator. */
- if ((((last->burst_regs[EMC_PMACRO_DATA_PAD_TX_CTRL_INDEX] &
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQ_E_IVREF) == 0) &&
- ((next->burst_regs[EMC_PMACRO_DATA_PAD_TX_CTRL_INDEX] &
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQ_E_IVREF) == 1)) ||
- (((last->burst_regs[EMC_PMACRO_DATA_PAD_TX_CTRL_INDEX] &
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQS_E_IVREF) == 0) &&
- ((next->burst_regs[EMC_PMACRO_DATA_PAD_TX_CTRL_INDEX] &
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQS_E_IVREF) != 0))) {
- u32 pad_tx_ctrl =
- next->burst_regs[EMC_PMACRO_DATA_PAD_TX_CTRL_INDEX];
- u32 last_pad_tx_ctrl =
- last->burst_regs[EMC_PMACRO_DATA_PAD_TX_CTRL_INDEX];
- u32 next_dq_e_ivref, next_dqs_e_ivref;
- next_dqs_e_ivref = pad_tx_ctrl &
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQS_E_IVREF;
- next_dq_e_ivref = pad_tx_ctrl &
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQ_E_IVREF;
- value = (last_pad_tx_ctrl &
- ~EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQ_E_IVREF &
- ~EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQS_E_IVREF) |
- next_dq_e_ivref | next_dqs_e_ivref;
- emc_writel(emc, value, EMC_PMACRO_DATA_PAD_TX_CTRL);
- udelay(1);
- } else if (bg_reg_mode_change) {
- udelay(1);
- }
- tegra210_emc_set_shadow_bypass(emc, ASSEMBLY);
- /*
- * Step 2:
- * Prelock the DLL.
- */
- emc_dbg(emc, STEPS, "Step 2\n");
- if (next->burst_regs[EMC_CFG_DIG_DLL_INDEX] &
- EMC_CFG_DIG_DLL_CFG_DLL_EN) {
- emc_dbg(emc, INFO, "Prelock enabled for target frequency.\n");
- value = tegra210_emc_dll_prelock(emc, clksrc);
- emc_dbg(emc, INFO, "DLL out: 0x%03x\n", value);
- } else {
- emc_dbg(emc, INFO, "Disabling DLL for target frequency.\n");
- tegra210_emc_dll_disable(emc);
- }
- /*
- * Step 3:
- * Prepare autocal for the clock change.
- */
- emc_dbg(emc, STEPS, "Step 3\n");
- tegra210_emc_set_shadow_bypass(emc, ACTIVE);
- emc_writel(emc, next->emc_auto_cal_config2, EMC_AUTO_CAL_CONFIG2);
- emc_writel(emc, next->emc_auto_cal_config3, EMC_AUTO_CAL_CONFIG3);
- emc_writel(emc, next->emc_auto_cal_config4, EMC_AUTO_CAL_CONFIG4);
- emc_writel(emc, next->emc_auto_cal_config5, EMC_AUTO_CAL_CONFIG5);
- emc_writel(emc, next->emc_auto_cal_config6, EMC_AUTO_CAL_CONFIG6);
- emc_writel(emc, next->emc_auto_cal_config7, EMC_AUTO_CAL_CONFIG7);
- emc_writel(emc, next->emc_auto_cal_config8, EMC_AUTO_CAL_CONFIG8);
- tegra210_emc_set_shadow_bypass(emc, ASSEMBLY);
- emc_auto_cal_config |= (EMC_AUTO_CAL_CONFIG_AUTO_CAL_COMPUTE_START |
- auto_cal_en);
- emc_writel(emc, emc_auto_cal_config, EMC_AUTO_CAL_CONFIG);
- /*
- * Step 4:
- * Update EMC_CFG. (??)
- */
- emc_dbg(emc, STEPS, "Step 4\n");
- if (src_clk_period > 50000 && dram_type == DRAM_TYPE_LPDDR4)
- ccfifo_writel(emc, 1, EMC_SELF_REF, 0);
- else
- emc_writel(emc, next->emc_cfg_2, EMC_CFG_2);
- /*
- * Step 5:
- * Prepare reference variables for ZQCAL regs.
- */
- emc_dbg(emc, STEPS, "Step 5\n");
- if (dram_type == DRAM_TYPE_LPDDR4)
- zq_wait_long = max((u32)1, div_o3(1000000, dst_clk_period));
- else if (dram_type == DRAM_TYPE_LPDDR2 || is_lpddr3)
- zq_wait_long = max(next->min_mrs_wait,
- div_o3(360000, dst_clk_period)) + 4;
- else if (dram_type == DRAM_TYPE_DDR3)
- zq_wait_long = max((u32)256,
- div_o3(320000, dst_clk_period) + 2);
- else
- zq_wait_long = 0;
- /*
- * Step 6:
- * Training code - removed.
- */
- emc_dbg(emc, STEPS, "Step 6\n");
- /*
- * Step 7:
- * Program FSP reference registers and send MRWs to new FSPWR.
- */
- emc_dbg(emc, STEPS, "Step 7\n");
- emc_dbg(emc, SUB_STEPS, "Step 7.1: Bug 200024907 - Patch RP R2P");
- /* WAR 200024907 */
- if (dram_type == DRAM_TYPE_LPDDR4) {
- u32 nRTP = 16;
- if (src_clk_period >= 1000000 / 1866) /* 535.91 ps */
- nRTP = 14;
- if (src_clk_period >= 1000000 / 1600) /* 625.00 ps */
- nRTP = 12;
- if (src_clk_period >= 1000000 / 1333) /* 750.19 ps */
- nRTP = 10;
- if (src_clk_period >= 1000000 / 1066) /* 938.09 ps */
- nRTP = 8;
- deltaTWATM = max_t(u32, div_o3(7500, src_clk_period), 8);
- /*
- * Originally there was a + .5 in the tRPST calculation.
- * However since we can't do FP in the kernel and the tRTM
- * computation was in a floating point ceiling function, adding
- * one to tRTP should be ok. There is no other source of non
- * integer values, so the result was always going to be
- * something for the form: f_ceil(N + .5) = N + 1;
- */
- tRPST = (last->emc_mrw & 0x80) >> 7;
- tRTM = fake->dram_timings[RL] + div_o3(3600, src_clk_period) +
- max_t(u32, div_o3(7500, src_clk_period), 8) + tRPST +
- 1 + nRTP;
- emc_dbg(emc, INFO, "tRTM = %u, EMC_RP = %u\n", tRTM,
- next->burst_regs[EMC_RP_INDEX]);
- if (last->burst_regs[EMC_RP_INDEX] < tRTM) {
- if (tRTM > (last->burst_regs[EMC_R2P_INDEX] +
- last->burst_regs[EMC_RP_INDEX])) {
- R2P_war = tRTM - last->burst_regs[EMC_RP_INDEX];
- RP_war = last->burst_regs[EMC_RP_INDEX];
- TRPab_war = last->burst_regs[EMC_TRPAB_INDEX];
- if (R2P_war > 63) {
- RP_war = R2P_war +
- last->burst_regs[EMC_RP_INDEX] - 63;
- if (TRPab_war < RP_war)
- TRPab_war = RP_war;
- R2P_war = 63;
- }
- } else {
- R2P_war = last->burst_regs[EMC_R2P_INDEX];
- RP_war = last->burst_regs[EMC_RP_INDEX];
- TRPab_war = last->burst_regs[EMC_TRPAB_INDEX];
- }
- if (RP_war < deltaTWATM) {
- W2P_war = last->burst_regs[EMC_W2P_INDEX]
- + deltaTWATM - RP_war;
- if (W2P_war > 63) {
- RP_war = RP_war + W2P_war - 63;
- if (TRPab_war < RP_war)
- TRPab_war = RP_war;
- W2P_war = 63;
- }
- } else {
- W2P_war = last->burst_regs[
- EMC_W2P_INDEX];
- }
- if ((last->burst_regs[EMC_W2P_INDEX] ^ W2P_war) ||
- (last->burst_regs[EMC_R2P_INDEX] ^ R2P_war) ||
- (last->burst_regs[EMC_RP_INDEX] ^ RP_war) ||
- (last->burst_regs[EMC_TRPAB_INDEX] ^ TRPab_war)) {
- emc_writel(emc, RP_war, EMC_RP);
- emc_writel(emc, R2P_war, EMC_R2P);
- emc_writel(emc, W2P_war, EMC_W2P);
- emc_writel(emc, TRPab_war, EMC_TRPAB);
- }
- tegra210_emc_timing_update(emc);
- } else {
- emc_dbg(emc, INFO, "Skipped WAR\n");
- }
- }
- if (!fsp_for_next_freq) {
- mr13_flip_fspwr = (next->emc_mrw3 & 0xffffff3f) | 0x80;
- mr13_flip_fspop = (next->emc_mrw3 & 0xffffff3f) | 0x00;
- } else {
- mr13_flip_fspwr = (next->emc_mrw3 & 0xffffff3f) | 0x40;
- mr13_flip_fspop = (next->emc_mrw3 & 0xffffff3f) | 0xc0;
- }
- if (dram_type == DRAM_TYPE_LPDDR4) {
- emc_writel(emc, mr13_flip_fspwr, EMC_MRW3);
- emc_writel(emc, next->emc_mrw, EMC_MRW);
- emc_writel(emc, next->emc_mrw2, EMC_MRW2);
- }
- /*
- * Step 8:
- * Program the shadow registers.
- */
- emc_dbg(emc, STEPS, "Step 8\n");
- emc_dbg(emc, SUB_STEPS, "Writing burst_regs\n");
- for (i = 0; i < next->num_burst; i++) {
- const u16 *offsets = emc->offsets->burst;
- u16 offset;
- if (!offsets[i])
- continue;
- value = next->burst_regs[i];
- offset = offsets[i];
- if (dram_type != DRAM_TYPE_LPDDR4 &&
- (offset == EMC_MRW6 || offset == EMC_MRW7 ||
- offset == EMC_MRW8 || offset == EMC_MRW9 ||
- offset == EMC_MRW10 || offset == EMC_MRW11 ||
- offset == EMC_MRW12 || offset == EMC_MRW13 ||
- offset == EMC_MRW14 || offset == EMC_MRW15 ||
- offset == EMC_TRAINING_CTRL))
- continue;
- /* Pain... And suffering. */
- if (offset == EMC_CFG) {
- value &= ~EMC_CFG_DRAM_ACPD;
- value &= ~EMC_CFG_DYN_SELF_REF;
- if (dram_type == DRAM_TYPE_LPDDR4) {
- value &= ~EMC_CFG_DRAM_CLKSTOP_SR;
- value &= ~EMC_CFG_DRAM_CLKSTOP_PD;
- }
- } else if (offset == EMC_MRS_WAIT_CNT &&
- dram_type == DRAM_TYPE_LPDDR2 &&
- opt_zcal_en_cc && !opt_cc_short_zcal &&
- opt_short_zcal) {
- value = (value & ~(EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK <<
- EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT)) |
- ((zq_wait_long & EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK) <<
- EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT);
- } else if (offset == EMC_ZCAL_WAIT_CNT &&
- dram_type == DRAM_TYPE_DDR3 && opt_zcal_en_cc &&
- !opt_cc_short_zcal && opt_short_zcal) {
- value = (value & ~(EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK <<
- EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_SHIFT)) |
- ((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) <<
- EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT);
- } else if (offset == EMC_ZCAL_INTERVAL && opt_zcal_en_cc) {
- value = 0; /* EMC_ZCAL_INTERVAL reset value. */
- } else if (offset == EMC_PMACRO_AUTOCAL_CFG_COMMON) {
- value |= EMC_PMACRO_AUTOCAL_CFG_COMMON_E_CAL_BYPASS_DVFS;
- } else if (offset == EMC_PMACRO_DATA_PAD_TX_CTRL) {
- value &= ~(EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQSP_TX_E_DCC |
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQSN_TX_E_DCC |
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_DQ_TX_E_DCC |
- EMC_PMACRO_DATA_PAD_TX_CTRL_DATA_CMD_TX_E_DCC);
- } else if (offset == EMC_PMACRO_CMD_PAD_TX_CTRL) {
- value |= EMC_PMACRO_CMD_PAD_TX_CTRL_CMD_DQ_TX_DRVFORCEON;
- value &= ~(EMC_PMACRO_CMD_PAD_TX_CTRL_CMD_DQSP_TX_E_DCC |
- EMC_PMACRO_CMD_PAD_TX_CTRL_CMD_DQSN_TX_E_DCC |
- EMC_PMACRO_CMD_PAD_TX_CTRL_CMD_DQ_TX_E_DCC |
- EMC_PMACRO_CMD_PAD_TX_CTRL_CMD_CMD_TX_E_DCC);
- } else if (offset == EMC_PMACRO_BRICK_CTRL_RFU1) {
- value &= 0xf800f800;
- } else if (offset == EMC_PMACRO_COMMON_PAD_TX_CTRL) {
- value &= 0xfffffff0;
- }
- emc_writel(emc, value, offset);
- }
- /* SW addition: do EMC refresh adjustment here. */
- tegra210_emc_adjust_timing(emc, next);
- if (dram_type == DRAM_TYPE_LPDDR4) {
- value = (23 << EMC_MRW_MRW_MA_SHIFT) |
- (next->run_clocks & EMC_MRW_MRW_OP_MASK);
- emc_writel(emc, value, EMC_MRW);
- }
- /* Per channel burst registers. */
- emc_dbg(emc, SUB_STEPS, "Writing burst_regs_per_ch\n");
- for (i = 0; i < next->num_burst_per_ch; i++) {
- const struct tegra210_emc_per_channel_regs *burst =
- emc->offsets->burst_per_channel;
- if (!burst[i].offset)
- continue;
- if (dram_type != DRAM_TYPE_LPDDR4 &&
- (burst[i].offset == EMC_MRW6 ||
- burst[i].offset == EMC_MRW7 ||
- burst[i].offset == EMC_MRW8 ||
- burst[i].offset == EMC_MRW9 ||
- burst[i].offset == EMC_MRW10 ||
- burst[i].offset == EMC_MRW11 ||
- burst[i].offset == EMC_MRW12 ||
- burst[i].offset == EMC_MRW13 ||
- burst[i].offset == EMC_MRW14 ||
- burst[i].offset == EMC_MRW15))
- continue;
- /* Filter out second channel if not in DUAL_CHANNEL mode. */
- if (emc->num_channels < 2 && burst[i].bank >= 1)
- continue;
- emc_dbg(emc, REG_LISTS, "(%u) 0x%08x => 0x%08x\n", i,
- next->burst_reg_per_ch[i], burst[i].offset);
- emc_channel_writel(emc, burst[i].bank,
- next->burst_reg_per_ch[i],
- burst[i].offset);
- }
- /* Vref regs. */
- emc_dbg(emc, SUB_STEPS, "Writing vref_regs\n");
- for (i = 0; i < next->vref_num; i++) {
- const struct tegra210_emc_per_channel_regs *vref =
- emc->offsets->vref_per_channel;
- if (!vref[i].offset)
- continue;
- if (emc->num_channels < 2 && vref[i].bank >= 1)
- continue;
- emc_dbg(emc, REG_LISTS, "(%u) 0x%08x => 0x%08x\n", i,
- next->vref_perch_regs[i], vref[i].offset);
- emc_channel_writel(emc, vref[i].bank, next->vref_perch_regs[i],
- vref[i].offset);
- }
- /* Trimmers. */
- emc_dbg(emc, SUB_STEPS, "Writing trim_regs\n");
- for (i = 0; i < next->num_trim; i++) {
- const u16 *offsets = emc->offsets->trim;
- if (!offsets[i])
- continue;
- if (compensate_trimmer_applicable &&
- (offsets[i] == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 ||
- offsets[i] == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 ||
- offsets[i] == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 ||
- offsets[i] == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 ||
- offsets[i] == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 ||
- offsets[i] == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 ||
- offsets[i] == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 ||
- offsets[i] == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 ||
- offsets[i] == EMC_DATA_BRLSHFT_0 ||
- offsets[i] == EMC_DATA_BRLSHFT_1)) {
- value = tegra210_emc_compensate(next, offsets[i]);
- emc_dbg(emc, REG_LISTS, "(%u) 0x%08x => 0x%08x\n", i,
- value, offsets[i]);
- emc_dbg(emc, EMA_WRITES, "0x%08x <= 0x%08x\n",
- (u32)(u64)offsets[i], value);
- emc_writel(emc, value, offsets[i]);
- } else {
- emc_dbg(emc, REG_LISTS, "(%u) 0x%08x => 0x%08x\n", i,
- next->trim_regs[i], offsets[i]);
- emc_writel(emc, next->trim_regs[i], offsets[i]);
- }
- }
- /* Per channel trimmers. */
- emc_dbg(emc, SUB_STEPS, "Writing trim_regs_per_ch\n");
- for (i = 0; i < next->num_trim_per_ch; i++) {
- const struct tegra210_emc_per_channel_regs *trim =
- &emc->offsets->trim_per_channel[0];
- unsigned int offset;
- if (!trim[i].offset)
- continue;
- if (emc->num_channels < 2 && trim[i].bank >= 1)
- continue;
- offset = trim[i].offset;
- if (compensate_trimmer_applicable &&
- (offset == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 ||
- offset == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 ||
- offset == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 ||
- offset == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 ||
- offset == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 ||
- offset == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 ||
- offset == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 ||
- offset == EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 ||
- offset == EMC_DATA_BRLSHFT_0 ||
- offset == EMC_DATA_BRLSHFT_1)) {
- value = tegra210_emc_compensate(next, offset);
- emc_dbg(emc, REG_LISTS, "(%u) 0x%08x => 0x%08x\n", i,
- value, offset);
- emc_dbg(emc, EMA_WRITES, "0x%08x <= 0x%08x\n", offset,
- value);
- emc_channel_writel(emc, trim[i].bank, value, offset);
- } else {
- emc_dbg(emc, REG_LISTS, "(%u) 0x%08x => 0x%08x\n", i,
- next->trim_perch_regs[i], offset);
- emc_channel_writel(emc, trim[i].bank,
- next->trim_perch_regs[i], offset);
- }
- }
- emc_dbg(emc, SUB_STEPS, "Writing burst_mc_regs\n");
- for (i = 0; i < next->num_mc_regs; i++) {
- const u16 *offsets = emc->offsets->burst_mc;
- u32 *values = next->burst_mc_regs;
- emc_dbg(emc, REG_LISTS, "(%u) 0x%08x => 0x%08x\n", i,
- values[i], offsets[i]);
- mc_writel(emc->mc, values[i], offsets[i]);
- }
- /* Registers to be programmed on the faster clock. */
- if (next->rate < last->rate) {
- const u16 *la = emc->offsets->la_scale;
- emc_dbg(emc, SUB_STEPS, "Writing la_scale_regs\n");
- for (i = 0; i < next->num_up_down; i++) {
- emc_dbg(emc, REG_LISTS, "(%u) 0x%08x => 0x%08x\n", i,
- next->la_scale_regs[i], la[i]);
- mc_writel(emc->mc, next->la_scale_regs[i], la[i]);
- }
- }
- /* Flush all the burst register writes. */
- mc_readl(emc->mc, MC_EMEM_ADR_CFG);
- /*
- * Step 9:
- * LPDDR4 section A.
- */
- emc_dbg(emc, STEPS, "Step 9\n");
- value = next->burst_regs[EMC_ZCAL_WAIT_CNT_INDEX];
- value &= ~EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK;
- if (dram_type == DRAM_TYPE_LPDDR4) {
- emc_writel(emc, 0, EMC_ZCAL_INTERVAL);
- emc_writel(emc, value, EMC_ZCAL_WAIT_CNT);
- value = emc_dbg | (EMC_DBG_WRITE_MUX_ACTIVE |
- EMC_DBG_WRITE_ACTIVE_ONLY);
- emc_writel(emc, value, EMC_DBG);
- emc_writel(emc, 0, EMC_ZCAL_INTERVAL);
- emc_writel(emc, emc_dbg, EMC_DBG);
- }
- /*
- * Step 10:
- * LPDDR4 and DDR3 common section.
- */
- emc_dbg(emc, STEPS, "Step 10\n");
- if (opt_dvfs_mode == MAN_SR || dram_type == DRAM_TYPE_LPDDR4) {
- if (dram_type == DRAM_TYPE_LPDDR4)
- ccfifo_writel(emc, 0x101, EMC_SELF_REF, 0);
- else
- ccfifo_writel(emc, 0x1, EMC_SELF_REF, 0);
- if (dram_type == DRAM_TYPE_LPDDR4 &&
- dst_clk_period <= zqcal_before_cc_cutoff) {
- ccfifo_writel(emc, mr13_flip_fspwr ^ 0x40, EMC_MRW3, 0);
- ccfifo_writel(emc, (next->burst_regs[EMC_MRW6_INDEX] &
- 0xFFFF3F3F) |
- (last->burst_regs[EMC_MRW6_INDEX] &
- 0x0000C0C0), EMC_MRW6, 0);
- ccfifo_writel(emc, (next->burst_regs[EMC_MRW14_INDEX] &
- 0xFFFF0707) |
- (last->burst_regs[EMC_MRW14_INDEX] &
- 0x00003838), EMC_MRW14, 0);
- if (emc->num_devices > 1) {
- ccfifo_writel(emc,
- (next->burst_regs[EMC_MRW7_INDEX] &
- 0xFFFF3F3F) |
- (last->burst_regs[EMC_MRW7_INDEX] &
- 0x0000C0C0), EMC_MRW7, 0);
- ccfifo_writel(emc,
- (next->burst_regs[EMC_MRW15_INDEX] &
- 0xFFFF0707) |
- (last->burst_regs[EMC_MRW15_INDEX] &
- 0x00003838), EMC_MRW15, 0);
- }
- if (opt_zcal_en_cc) {
- if (emc->num_devices < 2)
- ccfifo_writel(emc,
- 2UL << EMC_ZQ_CAL_DEV_SEL_SHIFT
- | EMC_ZQ_CAL_ZQ_CAL_CMD,
- EMC_ZQ_CAL, 0);
- else if (shared_zq_resistor)
- ccfifo_writel(emc,
- 2UL << EMC_ZQ_CAL_DEV_SEL_SHIFT
- | EMC_ZQ_CAL_ZQ_CAL_CMD,
- EMC_ZQ_CAL, 0);
- else
- ccfifo_writel(emc,
- EMC_ZQ_CAL_ZQ_CAL_CMD,
- EMC_ZQ_CAL, 0);
- }
- }
- }
- if (dram_type == DRAM_TYPE_LPDDR4) {
- value = (1000 * fake->dram_timings[T_RP]) / src_clk_period;
- ccfifo_writel(emc, mr13_flip_fspop | 0x8, EMC_MRW3, value);
- ccfifo_writel(emc, 0, 0, tFC_lpddr4 / src_clk_period);
- }
- if (dram_type == DRAM_TYPE_LPDDR4 || opt_dvfs_mode != MAN_SR) {
- delay = 30;
- if (cya_allow_ref_cc) {
- delay += (1000 * fake->dram_timings[T_RP]) /
- src_clk_period;
- delay += 4000 * fake->dram_timings[T_RFC];
- }
- ccfifo_writel(emc, emc_pin & ~(EMC_PIN_PIN_CKE_PER_DEV |
- EMC_PIN_PIN_CKEB |
- EMC_PIN_PIN_CKE),
- EMC_PIN, delay);
- }
- /* calculate reference delay multiplier */
- value = 1;
- if (ref_b4_sref_en)
- value++;
- if (cya_allow_ref_cc)
- value++;
- if (cya_issue_pc_ref)
- value++;
- if (dram_type != DRAM_TYPE_LPDDR4) {
- delay = ((1000 * fake->dram_timings[T_RP] / src_clk_period) +
- (1000 * fake->dram_timings[T_RFC] / src_clk_period));
- delay = value * delay + 20;
- } else {
- delay = 0;
- }
- /*
- * Step 11:
- * Ramp down.
- */
- emc_dbg(emc, STEPS, "Step 11\n");
- ccfifo_writel(emc, 0x0, EMC_CFG_SYNC, delay);
- value = emc_dbg | EMC_DBG_WRITE_MUX_ACTIVE | EMC_DBG_WRITE_ACTIVE_ONLY;
- ccfifo_writel(emc, value, EMC_DBG, 0);
- ramp_down_wait = tegra210_emc_dvfs_power_ramp_down(emc, src_clk_period,
- 0);
- /*
- * Step 12:
- * And finally - trigger the clock change.
- */
- emc_dbg(emc, STEPS, "Step 12\n");
- ccfifo_writel(emc, 1, EMC_STALL_THEN_EXE_AFTER_CLKCHANGE, 0);
- value &= ~EMC_DBG_WRITE_ACTIVE_ONLY;
- ccfifo_writel(emc, value, EMC_DBG, 0);
- /*
- * Step 13:
- * Ramp up.
- */
- emc_dbg(emc, STEPS, "Step 13\n");
- ramp_up_wait = tegra210_emc_dvfs_power_ramp_up(emc, dst_clk_period, 0);
- ccfifo_writel(emc, emc_dbg, EMC_DBG, 0);
- /*
- * Step 14:
- * Bringup CKE pins.
- */
- emc_dbg(emc, STEPS, "Step 14\n");
- if (dram_type == DRAM_TYPE_LPDDR4) {
- value = emc_pin | EMC_PIN_PIN_CKE;
- if (emc->num_devices <= 1)
- value &= ~(EMC_PIN_PIN_CKEB | EMC_PIN_PIN_CKE_PER_DEV);
- else
- value |= EMC_PIN_PIN_CKEB | EMC_PIN_PIN_CKE_PER_DEV;
- ccfifo_writel(emc, value, EMC_PIN, 0);
- }
- /*
- * Step 15: (two step 15s ??)
- * Calculate zqlatch wait time; has dependency on ramping times.
- */
- emc_dbg(emc, STEPS, "Step 15\n");
- if (dst_clk_period <= zqcal_before_cc_cutoff) {
- s32 t = (s32)(ramp_up_wait + ramp_down_wait) /
- (s32)dst_clk_period;
- zq_latch_dvfs_wait_time = (s32)tZQCAL_lpddr4_fc_adj - t;
- } else {
- zq_latch_dvfs_wait_time = tZQCAL_lpddr4_fc_adj -
- div_o3(1000 * next->dram_timings[T_PDEX],
- dst_clk_period);
- }
- emc_dbg(emc, INFO, "tZQCAL_lpddr4_fc_adj = %u\n", tZQCAL_lpddr4_fc_adj);
- emc_dbg(emc, INFO, "dst_clk_period = %u\n",
- dst_clk_period);
- emc_dbg(emc, INFO, "next->dram_timings[T_PDEX] = %u\n",
- next->dram_timings[T_PDEX]);
- emc_dbg(emc, INFO, "zq_latch_dvfs_wait_time = %d\n",
- max_t(s32, 0, zq_latch_dvfs_wait_time));
- if (dram_type == DRAM_TYPE_LPDDR4 && opt_zcal_en_cc) {
- delay = div_o3(1000 * next->dram_timings[T_PDEX],
- dst_clk_period);
- if (emc->num_devices < 2) {
- if (dst_clk_period > zqcal_before_cc_cutoff)
- ccfifo_writel(emc,
- 2UL << EMC_ZQ_CAL_DEV_SEL_SHIFT |
- EMC_ZQ_CAL_ZQ_CAL_CMD, EMC_ZQ_CAL,
- delay);
- value = (mr13_flip_fspop & 0xfffffff7) | 0x0c000000;
- ccfifo_writel(emc, value, EMC_MRW3, delay);
- ccfifo_writel(emc, 0, EMC_SELF_REF, 0);
- ccfifo_writel(emc, 0, EMC_REF, 0);
- ccfifo_writel(emc, 2UL << EMC_ZQ_CAL_DEV_SEL_SHIFT |
- EMC_ZQ_CAL_ZQ_LATCH_CMD,
- EMC_ZQ_CAL,
- max_t(s32, 0, zq_latch_dvfs_wait_time));
- } else if (shared_zq_resistor) {
- if (dst_clk_period > zqcal_before_cc_cutoff)
- ccfifo_writel(emc,
- 2UL << EMC_ZQ_CAL_DEV_SEL_SHIFT |
- EMC_ZQ_CAL_ZQ_CAL_CMD, EMC_ZQ_CAL,
- delay);
- ccfifo_writel(emc, 2UL << EMC_ZQ_CAL_DEV_SEL_SHIFT |
- EMC_ZQ_CAL_ZQ_LATCH_CMD, EMC_ZQ_CAL,
- max_t(s32, 0, zq_latch_dvfs_wait_time) +
- delay);
- ccfifo_writel(emc, 1UL << EMC_ZQ_CAL_DEV_SEL_SHIFT |
- EMC_ZQ_CAL_ZQ_LATCH_CMD,
- EMC_ZQ_CAL, 0);
- value = (mr13_flip_fspop & 0xfffffff7) | 0x0c000000;
- ccfifo_writel(emc, value, EMC_MRW3, 0);
- ccfifo_writel(emc, 0, EMC_SELF_REF, 0);
- ccfifo_writel(emc, 0, EMC_REF, 0);
- ccfifo_writel(emc, 1UL << EMC_ZQ_CAL_DEV_SEL_SHIFT |
- EMC_ZQ_CAL_ZQ_LATCH_CMD, EMC_ZQ_CAL,
- tZQCAL_lpddr4 / dst_clk_period);
- } else {
- if (dst_clk_period > zqcal_before_cc_cutoff)
- ccfifo_writel(emc, EMC_ZQ_CAL_ZQ_CAL_CMD,
- EMC_ZQ_CAL, delay);
- value = (mr13_flip_fspop & 0xfffffff7) | 0x0c000000;
- ccfifo_writel(emc, value, EMC_MRW3, delay);
- ccfifo_writel(emc, 0, EMC_SELF_REF, 0);
- ccfifo_writel(emc, 0, EMC_REF, 0);
- ccfifo_writel(emc, EMC_ZQ_CAL_ZQ_LATCH_CMD, EMC_ZQ_CAL,
- max_t(s32, 0, zq_latch_dvfs_wait_time));
- }
- }
- /* WAR: delay for zqlatch */
- ccfifo_writel(emc, 0, 0, 10);
- /*
- * Step 16:
- * LPDDR4 Conditional Training Kickoff. Removed.
- */
- /*
- * Step 17:
- * MANSR exit self refresh.
- */
- emc_dbg(emc, STEPS, "Step 17\n");
- if (opt_dvfs_mode == MAN_SR && dram_type != DRAM_TYPE_LPDDR4)
- ccfifo_writel(emc, 0, EMC_SELF_REF, 0);
- /*
- * Step 18:
- * Send MRWs to LPDDR3/DDR3.
- */
- emc_dbg(emc, STEPS, "Step 18\n");
- if (dram_type == DRAM_TYPE_LPDDR2) {
- ccfifo_writel(emc, next->emc_mrw2, EMC_MRW2, 0);
- ccfifo_writel(emc, next->emc_mrw, EMC_MRW, 0);
- if (is_lpddr3)
- ccfifo_writel(emc, next->emc_mrw4, EMC_MRW4, 0);
- } else if (dram_type == DRAM_TYPE_DDR3) {
- if (opt_dll_mode)
- ccfifo_writel(emc, next->emc_emrs &
- ~EMC_EMRS_USE_EMRS_LONG_CNT, EMC_EMRS, 0);
- ccfifo_writel(emc, next->emc_emrs2 &
- ~EMC_EMRS2_USE_EMRS2_LONG_CNT, EMC_EMRS2, 0);
- ccfifo_writel(emc, next->emc_mrs |
- EMC_EMRS_USE_EMRS_LONG_CNT, EMC_MRS, 0);
- }
- /*
- * Step 19:
- * ZQCAL for LPDDR3/DDR3
- */
- emc_dbg(emc, STEPS, "Step 19\n");
- if (opt_zcal_en_cc) {
- if (dram_type == DRAM_TYPE_LPDDR2) {
- value = opt_cc_short_zcal ? 90000 : 360000;
- value = div_o3(value, dst_clk_period);
- value = value <<
- EMC_MRS_WAIT_CNT2_MRS_EXT2_WAIT_CNT_SHIFT |
- value <<
- EMC_MRS_WAIT_CNT2_MRS_EXT1_WAIT_CNT_SHIFT;
- ccfifo_writel(emc, value, EMC_MRS_WAIT_CNT2, 0);
- value = opt_cc_short_zcal ? 0x56 : 0xab;
- ccfifo_writel(emc, 2 << EMC_MRW_MRW_DEV_SELECTN_SHIFT |
- EMC_MRW_USE_MRW_EXT_CNT |
- 10 << EMC_MRW_MRW_MA_SHIFT |
- value << EMC_MRW_MRW_OP_SHIFT,
- EMC_MRW, 0);
- if (emc->num_devices > 1) {
- value = 1 << EMC_MRW_MRW_DEV_SELECTN_SHIFT |
- EMC_MRW_USE_MRW_EXT_CNT |
- 10 << EMC_MRW_MRW_MA_SHIFT |
- value << EMC_MRW_MRW_OP_SHIFT;
- ccfifo_writel(emc, value, EMC_MRW, 0);
- }
- } else if (dram_type == DRAM_TYPE_DDR3) {
- value = opt_cc_short_zcal ? 0 : EMC_ZQ_CAL_LONG;
- ccfifo_writel(emc, value |
- 2 << EMC_ZQ_CAL_DEV_SEL_SHIFT |
- EMC_ZQ_CAL_ZQ_CAL_CMD, EMC_ZQ_CAL,
- 0);
- if (emc->num_devices > 1) {
- value = value | 1 << EMC_ZQ_CAL_DEV_SEL_SHIFT |
- EMC_ZQ_CAL_ZQ_CAL_CMD;
- ccfifo_writel(emc, value, EMC_ZQ_CAL, 0);
- }
- }
- }
- if (bg_reg_mode_change) {
- tegra210_emc_set_shadow_bypass(emc, ACTIVE);
- if (ramp_up_wait <= 1250000)
- delay = (1250000 - ramp_up_wait) / dst_clk_period;
- else
- delay = 0;
- ccfifo_writel(emc,
- next->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX],
- EMC_PMACRO_BG_BIAS_CTRL_0, delay);
- tegra210_emc_set_shadow_bypass(emc, ASSEMBLY);
- }
- /*
- * Step 20:
- * Issue ref and optional QRST.
- */
- emc_dbg(emc, STEPS, "Step 20\n");
- if (dram_type != DRAM_TYPE_LPDDR4)
- ccfifo_writel(emc, 0, EMC_REF, 0);
- if (opt_do_sw_qrst) {
- ccfifo_writel(emc, 1, EMC_ISSUE_QRST, 0);
- ccfifo_writel(emc, 0, EMC_ISSUE_QRST, 2);
- }
- /*
- * Step 21:
- * Restore ZCAL and ZCAL interval.
- */
- emc_dbg(emc, STEPS, "Step 21\n");
- if (save_restore_clkstop_pd || opt_zcal_en_cc) {
- ccfifo_writel(emc, emc_dbg | EMC_DBG_WRITE_MUX_ACTIVE,
- EMC_DBG, 0);
- if (opt_zcal_en_cc && dram_type != DRAM_TYPE_LPDDR4)
- ccfifo_writel(emc, next->burst_regs[EMC_ZCAL_INTERVAL_INDEX],
- EMC_ZCAL_INTERVAL, 0);
- if (save_restore_clkstop_pd)
- ccfifo_writel(emc, next->burst_regs[EMC_CFG_INDEX] &
- ~EMC_CFG_DYN_SELF_REF,
- EMC_CFG, 0);
- ccfifo_writel(emc, emc_dbg, EMC_DBG, 0);
- }
- /*
- * Step 22:
- * Restore EMC_CFG_PIPE_CLK.
- */
- emc_dbg(emc, STEPS, "Step 22\n");
- ccfifo_writel(emc, emc_cfg_pipe_clk, EMC_CFG_PIPE_CLK, 0);
- if (bg_reg_mode_change) {
- if (enable_bg_reg)
- emc_writel(emc,
- next->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- ~EMC_PMACRO_BG_BIAS_CTRL_0_BGLP_E_PWRD,
- EMC_PMACRO_BG_BIAS_CTRL_0);
- else
- emc_writel(emc,
- next->burst_regs[EMC_PMACRO_BG_BIAS_CTRL_0_INDEX] &
- ~EMC_PMACRO_BG_BIAS_CTRL_0_BG_E_PWRD,
- EMC_PMACRO_BG_BIAS_CTRL_0);
- }
- /*
- * Step 23:
- */
- emc_dbg(emc, STEPS, "Step 23\n");
- value = emc_readl(emc, EMC_CFG_DIG_DLL);
- value |= EMC_CFG_DIG_DLL_CFG_DLL_STALL_ALL_TRAFFIC;
- value &= ~EMC_CFG_DIG_DLL_CFG_DLL_STALL_RW_UNTIL_LOCK;
- value &= ~EMC_CFG_DIG_DLL_CFG_DLL_STALL_ALL_UNTIL_LOCK;
- value &= ~EMC_CFG_DIG_DLL_CFG_DLL_EN;
- value = (value & ~EMC_CFG_DIG_DLL_CFG_DLL_MODE_MASK) |
- (2 << EMC_CFG_DIG_DLL_CFG_DLL_MODE_SHIFT);
- emc_writel(emc, value, EMC_CFG_DIG_DLL);
- tegra210_emc_do_clock_change(emc, clksrc);
- /*
- * Step 24:
- * Save training results. Removed.
- */
- /*
- * Step 25:
- * Program MC updown registers.
- */
- emc_dbg(emc, STEPS, "Step 25\n");
- if (next->rate > last->rate) {
- for (i = 0; i < next->num_up_down; i++)
- mc_writel(emc->mc, next->la_scale_regs[i],
- emc->offsets->la_scale[i]);
- tegra210_emc_timing_update(emc);
- }
- /*
- * Step 26:
- * Restore ZCAL registers.
- */
- emc_dbg(emc, STEPS, "Step 26\n");
- if (dram_type == DRAM_TYPE_LPDDR4) {
- tegra210_emc_set_shadow_bypass(emc, ACTIVE);
- emc_writel(emc, next->burst_regs[EMC_ZCAL_WAIT_CNT_INDEX],
- EMC_ZCAL_WAIT_CNT);
- emc_writel(emc, next->burst_regs[EMC_ZCAL_INTERVAL_INDEX],
- EMC_ZCAL_INTERVAL);
- tegra210_emc_set_shadow_bypass(emc, ASSEMBLY);
- }
- if (dram_type != DRAM_TYPE_LPDDR4 && opt_zcal_en_cc &&
- !opt_short_zcal && opt_cc_short_zcal) {
- udelay(2);
- tegra210_emc_set_shadow_bypass(emc, ACTIVE);
- if (dram_type == DRAM_TYPE_LPDDR2)
- emc_writel(emc, next->burst_regs[EMC_MRS_WAIT_CNT_INDEX],
- EMC_MRS_WAIT_CNT);
- else if (dram_type == DRAM_TYPE_DDR3)
- emc_writel(emc, next->burst_regs[EMC_ZCAL_WAIT_CNT_INDEX],
- EMC_ZCAL_WAIT_CNT);
- tegra210_emc_set_shadow_bypass(emc, ASSEMBLY);
- }
- /*
- * Step 27:
- * Restore EMC_CFG, FDPD registers.
- */
- emc_dbg(emc, STEPS, "Step 27\n");
- tegra210_emc_set_shadow_bypass(emc, ACTIVE);
- emc_writel(emc, next->burst_regs[EMC_CFG_INDEX], EMC_CFG);
- tegra210_emc_set_shadow_bypass(emc, ASSEMBLY);
- emc_writel(emc, next->emc_fdpd_ctrl_cmd_no_ramp,
- EMC_FDPD_CTRL_CMD_NO_RAMP);
- emc_writel(emc, next->emc_sel_dpd_ctrl, EMC_SEL_DPD_CTRL);
- /*
- * Step 28:
- * Training recover. Removed.
- */
- emc_dbg(emc, STEPS, "Step 28\n");
- tegra210_emc_set_shadow_bypass(emc, ACTIVE);
- emc_writel(emc,
- next->burst_regs[EMC_PMACRO_AUTOCAL_CFG_COMMON_INDEX],
- EMC_PMACRO_AUTOCAL_CFG_COMMON);
- tegra210_emc_set_shadow_bypass(emc, ASSEMBLY);
- /*
- * Step 29:
- * Power fix WAR.
- */
- emc_dbg(emc, STEPS, "Step 29\n");
- emc_writel(emc, EMC_PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE0 |
- EMC_PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE1 |
- EMC_PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE2 |
- EMC_PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE3 |
- EMC_PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE4 |
- EMC_PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE5 |
- EMC_PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE6 |
- EMC_PMACRO_CFG_PM_GLOBAL_0_DISABLE_CFG_BYTE7,
- EMC_PMACRO_CFG_PM_GLOBAL_0);
- emc_writel(emc, EMC_PMACRO_TRAINING_CTRL_0_CH0_TRAINING_E_WRPTR,
- EMC_PMACRO_TRAINING_CTRL_0);
- emc_writel(emc, EMC_PMACRO_TRAINING_CTRL_1_CH1_TRAINING_E_WRPTR,
- EMC_PMACRO_TRAINING_CTRL_1);
- emc_writel(emc, 0, EMC_PMACRO_CFG_PM_GLOBAL_0);
- /*
- * Step 30:
- * Re-enable autocal.
- */
- emc_dbg(emc, STEPS, "Step 30: Re-enable DLL and AUTOCAL\n");
- if (next->burst_regs[EMC_CFG_DIG_DLL_INDEX] & EMC_CFG_DIG_DLL_CFG_DLL_EN) {
- value = emc_readl(emc, EMC_CFG_DIG_DLL);
- value |= EMC_CFG_DIG_DLL_CFG_DLL_STALL_ALL_TRAFFIC;
- value |= EMC_CFG_DIG_DLL_CFG_DLL_EN;
- value &= ~EMC_CFG_DIG_DLL_CFG_DLL_STALL_RW_UNTIL_LOCK;
- value &= ~EMC_CFG_DIG_DLL_CFG_DLL_STALL_ALL_UNTIL_LOCK;
- value = (value & ~EMC_CFG_DIG_DLL_CFG_DLL_MODE_MASK) |
- (2 << EMC_CFG_DIG_DLL_CFG_DLL_MODE_SHIFT);
- emc_writel(emc, value, EMC_CFG_DIG_DLL);
- tegra210_emc_timing_update(emc);
- }
- emc_writel(emc, next->emc_auto_cal_config, EMC_AUTO_CAL_CONFIG);
- /* Done! Yay. */
- }
- const struct tegra210_emc_sequence tegra210_emc_r21021 = {
- .revision = 0x7,
- .set_clock = tegra210_emc_r21021_set_clock,
- .periodic_compensation = tegra210_emc_r21021_periodic_compensation,
- };
|