1dce208b5SSvyatoslav Ryhel // SPDX-License-Identifier: GPL-2.0-only 2dce208b5SSvyatoslav Ryhel /* 3dce208b5SSvyatoslav Ryhel * Tegra114 External Memory Controller driver 4dce208b5SSvyatoslav Ryhel * 5dce208b5SSvyatoslav Ryhel * Based on downstream driver from NVIDIA and tegra124-emc.c 6dce208b5SSvyatoslav Ryhel * Copyright (C) 2011-2014 NVIDIA Corporation 7dce208b5SSvyatoslav Ryhel * 8dce208b5SSvyatoslav Ryhel * Copyright (C) 2024 Svyatoslav Ryhel <clamor95@gmail.com> 9dce208b5SSvyatoslav Ryhel */ 10dce208b5SSvyatoslav Ryhel 11dce208b5SSvyatoslav Ryhel #include <linux/clk.h> 12dce208b5SSvyatoslav Ryhel #include <linux/clk/tegra.h> 13dce208b5SSvyatoslav Ryhel #include <linux/debugfs.h> 14dce208b5SSvyatoslav Ryhel #include <linux/delay.h> 15dce208b5SSvyatoslav Ryhel #include <linux/interrupt.h> 16dce208b5SSvyatoslav Ryhel #include <linux/io.h> 17dce208b5SSvyatoslav Ryhel #include <linux/iopoll.h> 18dce208b5SSvyatoslav Ryhel #include <linux/module.h> 19dce208b5SSvyatoslav Ryhel #include <linux/mutex.h> 20dce208b5SSvyatoslav Ryhel #include <linux/of.h> 21dce208b5SSvyatoslav Ryhel #include <linux/platform_device.h> 22dce208b5SSvyatoslav Ryhel #include <linux/pm_opp.h> 23dce208b5SSvyatoslav Ryhel #include <linux/sort.h> 24dce208b5SSvyatoslav Ryhel #include <linux/string.h> 25dce208b5SSvyatoslav Ryhel 26dce208b5SSvyatoslav Ryhel #include <soc/tegra/common.h> 27dce208b5SSvyatoslav Ryhel #include <soc/tegra/fuse.h> 28dce208b5SSvyatoslav Ryhel #include <soc/tegra/mc.h> 29dce208b5SSvyatoslav Ryhel 30dce208b5SSvyatoslav Ryhel #include "mc.h" 31dce208b5SSvyatoslav Ryhel #include "tegra-emc-common.h" 32dce208b5SSvyatoslav Ryhel 33dce208b5SSvyatoslav Ryhel #define EMC_INTSTATUS 0x0 34dce208b5SSvyatoslav Ryhel #define EMC_INTSTATUS_REFRESH_OVERFLOW BIT(3) 35dce208b5SSvyatoslav Ryhel #define EMC_INTSTATUS_CLKCHANGE_COMPLETE BIT(4) 36dce208b5SSvyatoslav Ryhel 37dce208b5SSvyatoslav Ryhel #define EMC_INTMASK 0x4 38dce208b5SSvyatoslav Ryhel 39dce208b5SSvyatoslav Ryhel #define EMC_DBG 0x8 40dce208b5SSvyatoslav Ryhel #define EMC_DBG_READ_MUX_ASSEMBLY BIT(0) 41dce208b5SSvyatoslav Ryhel #define EMC_DBG_WRITE_MUX_ACTIVE BIT(1) 42dce208b5SSvyatoslav Ryhel #define EMC_DBG_FORCE_UPDATE BIT(2) 43dce208b5SSvyatoslav Ryhel #define EMC_DBG_CFG_PRIORITY BIT(24) 44dce208b5SSvyatoslav Ryhel 45dce208b5SSvyatoslav Ryhel #define EMC_CFG 0xc 46dce208b5SSvyatoslav Ryhel #define EMC_CFG_DSR_VTTGEN_DRV_EN BIT(18) 47dce208b5SSvyatoslav Ryhel #define EMC_CFG_PWR_MASK ((0xF << 28) | BIT(18)) 48dce208b5SSvyatoslav Ryhel #define EMC_CFG_DYN_SREF BIT(28) 49dce208b5SSvyatoslav Ryhel #define EMC_CFG_DRAM_ACPD BIT(29) 50dce208b5SSvyatoslav Ryhel #define EMC_CFG_DRAM_CLKSTOP_SR BIT(30) 51dce208b5SSvyatoslav Ryhel #define EMC_CFG_DRAM_CLKSTOP_PD BIT(31) 52dce208b5SSvyatoslav Ryhel 53dce208b5SSvyatoslav Ryhel #define EMC_ADR_CFG 0x10 54dce208b5SSvyatoslav Ryhel #define EMC_ADR_CFG_EMEM_NUMDEV BIT(0) 55dce208b5SSvyatoslav Ryhel 56dce208b5SSvyatoslav Ryhel #define EMC_REFCTRL 0x20 57dce208b5SSvyatoslav Ryhel #define EMC_REFCTRL_DEV_SEL_SHIFT 0 58dce208b5SSvyatoslav Ryhel #define EMC_REFCTRL_ENABLE BIT(31) 59dce208b5SSvyatoslav Ryhel 60dce208b5SSvyatoslav Ryhel #define EMC_TIMING_CONTROL 0x28 61dce208b5SSvyatoslav Ryhel #define EMC_RC 0x2c 62dce208b5SSvyatoslav Ryhel #define EMC_RFC 0x30 63dce208b5SSvyatoslav Ryhel #define EMC_RAS 0x34 64dce208b5SSvyatoslav Ryhel #define EMC_RP 0x38 65dce208b5SSvyatoslav Ryhel #define EMC_R2W 0x3c 66dce208b5SSvyatoslav Ryhel #define EMC_W2R 0x40 67dce208b5SSvyatoslav Ryhel #define EMC_R2P 0x44 68dce208b5SSvyatoslav Ryhel #define EMC_W2P 0x48 69dce208b5SSvyatoslav Ryhel #define EMC_RD_RCD 0x4c 70dce208b5SSvyatoslav Ryhel #define EMC_WR_RCD 0x50 71dce208b5SSvyatoslav Ryhel #define EMC_RRD 0x54 72dce208b5SSvyatoslav Ryhel #define EMC_REXT 0x58 73dce208b5SSvyatoslav Ryhel #define EMC_WDV 0x5c 74dce208b5SSvyatoslav Ryhel #define EMC_QUSE 0x60 75dce208b5SSvyatoslav Ryhel #define EMC_QRST 0x64 76dce208b5SSvyatoslav Ryhel #define EMC_QSAFE 0x68 77dce208b5SSvyatoslav Ryhel #define EMC_RDV 0x6c 78dce208b5SSvyatoslav Ryhel #define EMC_REFRESH 0x70 79dce208b5SSvyatoslav Ryhel #define EMC_BURST_REFRESH_NUM 0x74 80dce208b5SSvyatoslav Ryhel #define EMC_PDEX2WR 0x78 81dce208b5SSvyatoslav Ryhel #define EMC_PDEX2RD 0x7c 82dce208b5SSvyatoslav Ryhel #define EMC_PCHG2PDEN 0x80 83dce208b5SSvyatoslav Ryhel #define EMC_ACT2PDEN 0x84 84dce208b5SSvyatoslav Ryhel #define EMC_AR2PDEN 0x88 85dce208b5SSvyatoslav Ryhel #define EMC_RW2PDEN 0x8c 86dce208b5SSvyatoslav Ryhel #define EMC_TXSR 0x90 87dce208b5SSvyatoslav Ryhel #define EMC_TCKE 0x94 88dce208b5SSvyatoslav Ryhel #define EMC_TFAW 0x98 89dce208b5SSvyatoslav Ryhel #define EMC_TRPAB 0x9c 90dce208b5SSvyatoslav Ryhel #define EMC_TCLKSTABLE 0xa0 91dce208b5SSvyatoslav Ryhel #define EMC_TCLKSTOP 0xa4 92dce208b5SSvyatoslav Ryhel #define EMC_TREFBW 0xa8 93dce208b5SSvyatoslav Ryhel #define EMC_QUSE_EXTRA 0xac 94dce208b5SSvyatoslav Ryhel #define EMC_ODT_WRITE 0xb0 95dce208b5SSvyatoslav Ryhel #define EMC_ODT_READ 0xb4 96dce208b5SSvyatoslav Ryhel #define EMC_WEXT 0xb8 97dce208b5SSvyatoslav Ryhel #define EMC_CTT 0xbc 98dce208b5SSvyatoslav Ryhel #define EMC_RFC_SLR 0xc0 99dce208b5SSvyatoslav Ryhel #define EMC_MRS_WAIT_CNT2 0xc4 100dce208b5SSvyatoslav Ryhel 101dce208b5SSvyatoslav Ryhel #define EMC_MRS_WAIT_CNT 0xc8 102dce208b5SSvyatoslav Ryhel #define EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT 0 103dce208b5SSvyatoslav Ryhel #define EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK \ 104dce208b5SSvyatoslav Ryhel (0x3FF << EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT) 105dce208b5SSvyatoslav Ryhel #define EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT 16 106dce208b5SSvyatoslav Ryhel #define EMC_MRS_WAIT_CNT_LONG_WAIT_MASK \ 107dce208b5SSvyatoslav Ryhel (0x3FF << EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT) 108dce208b5SSvyatoslav Ryhel 109dce208b5SSvyatoslav Ryhel #define EMC_MRS 0xcc 110dce208b5SSvyatoslav Ryhel #define EMC_MODE_SET_DLL_RESET BIT(8) 111dce208b5SSvyatoslav Ryhel #define EMC_MODE_SET_LONG_CNT BIT(26) 112dce208b5SSvyatoslav Ryhel #define EMC_EMRS 0xd0 113dce208b5SSvyatoslav Ryhel #define EMC_REF 0xd4 114dce208b5SSvyatoslav Ryhel #define EMC_PRE 0xd8 115dce208b5SSvyatoslav Ryhel 116dce208b5SSvyatoslav Ryhel #define EMC_SELF_REF 0xe0 117dce208b5SSvyatoslav Ryhel #define EMC_SELF_REF_CMD_ENABLED BIT(0) 118dce208b5SSvyatoslav Ryhel #define EMC_SELF_REF_DEV_SEL_SHIFT 30 119dce208b5SSvyatoslav Ryhel 120dce208b5SSvyatoslav Ryhel #define EMC_MRW 0xe8 121dce208b5SSvyatoslav Ryhel 122dce208b5SSvyatoslav Ryhel #define EMC_MRR 0xec 123dce208b5SSvyatoslav Ryhel #define EMC_MRR_MA_SHIFT 16 124dce208b5SSvyatoslav Ryhel #define LPDDR2_MR4_TEMP_SHIFT 0 125dce208b5SSvyatoslav Ryhel 126dce208b5SSvyatoslav Ryhel #define EMC_XM2DQSPADCTRL3 0xf8 127dce208b5SSvyatoslav Ryhel #define EMC_FBIO_SPARE 0x100 128dce208b5SSvyatoslav Ryhel 129dce208b5SSvyatoslav Ryhel #define EMC_FBIO_CFG5 0x104 130dce208b5SSvyatoslav Ryhel #define EMC_FBIO_CFG5_DRAM_TYPE_MASK 0x3 131dce208b5SSvyatoslav Ryhel #define EMC_FBIO_CFG5_DRAM_TYPE_SHIFT 0 132dce208b5SSvyatoslav Ryhel 133dce208b5SSvyatoslav Ryhel #define EMC_FBIO_CFG6 0x114 134dce208b5SSvyatoslav Ryhel #define EMC_EMRS2 0x12c 135dce208b5SSvyatoslav Ryhel #define EMC_MRW2 0x134 136dce208b5SSvyatoslav Ryhel #define EMC_MRW4 0x13c 137dce208b5SSvyatoslav Ryhel #define EMC_EINPUT 0x14c 138dce208b5SSvyatoslav Ryhel #define EMC_EINPUT_DURATION 0x150 139dce208b5SSvyatoslav Ryhel #define EMC_PUTERM_EXTRA 0x154 140dce208b5SSvyatoslav Ryhel #define EMC_TCKESR 0x158 141dce208b5SSvyatoslav Ryhel #define EMC_TPD 0x15c 142dce208b5SSvyatoslav Ryhel 143dce208b5SSvyatoslav Ryhel #define EMC_AUTO_CAL_CONFIG 0x2a4 144dce208b5SSvyatoslav Ryhel #define EMC_AUTO_CAL_CONFIG_AUTO_CAL_START BIT(31) 145dce208b5SSvyatoslav Ryhel #define EMC_AUTO_CAL_INTERVAL 0x2a8 146dce208b5SSvyatoslav Ryhel #define EMC_AUTO_CAL_STATUS 0x2ac 147dce208b5SSvyatoslav Ryhel #define EMC_AUTO_CAL_STATUS_ACTIVE BIT(31) 148dce208b5SSvyatoslav Ryhel #define EMC_STATUS 0x2b4 149dce208b5SSvyatoslav Ryhel #define EMC_STATUS_TIMING_UPDATE_STALLED BIT(23) 150dce208b5SSvyatoslav Ryhel 151dce208b5SSvyatoslav Ryhel #define EMC_CFG_2 0x2b8 152dce208b5SSvyatoslav Ryhel #define EMC_CFG_2_CLKCHANGE_REQ_ENABLE BIT(0) 153dce208b5SSvyatoslav Ryhel #define EMC_CFG_2_CLKCHANGE_PD_ENABLE BIT(1) 154dce208b5SSvyatoslav Ryhel #define EMC_CFG_2_CLKCHANGE_SR_ENABLE BIT(2) 155dce208b5SSvyatoslav Ryhel 156dce208b5SSvyatoslav Ryhel #define EMC_CFG_DIG_DLL 0x2bc 157dce208b5SSvyatoslav Ryhel #define EMC_CFG_DIG_DLL_PERIOD 0x2c0 158dce208b5SSvyatoslav Ryhel #define EMC_RDV_MASK 0x2cc 159dce208b5SSvyatoslav Ryhel #define EMC_WDV_MASK 0x2d0 160dce208b5SSvyatoslav Ryhel #define EMC_CTT_DURATION 0x2d8 161dce208b5SSvyatoslav Ryhel #define EMC_CTT_TERM_CTRL 0x2dc 162dce208b5SSvyatoslav Ryhel #define EMC_ZCAL_INTERVAL 0x2e0 163dce208b5SSvyatoslav Ryhel #define EMC_ZCAL_WAIT_CNT 0x2e4 164dce208b5SSvyatoslav Ryhel 165dce208b5SSvyatoslav Ryhel #define EMC_ZQ_CAL 0x2ec 166dce208b5SSvyatoslav Ryhel #define EMC_ZQ_CAL_CMD BIT(0) 167dce208b5SSvyatoslav Ryhel #define EMC_ZQ_CAL_LONG BIT(4) 168dce208b5SSvyatoslav Ryhel #define EMC_ZQ_CAL_LONG_CMD_DEV0 \ 169dce208b5SSvyatoslav Ryhel (DRAM_DEV_SEL_0 | EMC_ZQ_CAL_LONG | EMC_ZQ_CAL_CMD) 170dce208b5SSvyatoslav Ryhel #define EMC_ZQ_CAL_LONG_CMD_DEV1 \ 171dce208b5SSvyatoslav Ryhel (DRAM_DEV_SEL_1 | EMC_ZQ_CAL_LONG | EMC_ZQ_CAL_CMD) 172dce208b5SSvyatoslav Ryhel 173dce208b5SSvyatoslav Ryhel #define EMC_XM2CMDPADCTRL 0x2f0 174dce208b5SSvyatoslav Ryhel #define EMC_XM2DQSPADCTRL 0x2f8 175dce208b5SSvyatoslav Ryhel #define EMC_XM2DQSPADCTRL2 0x2fc 176dce208b5SSvyatoslav Ryhel #define EMC_XM2DQSPADCTRL2_RX_FT_REC_ENABLE BIT(0) 177dce208b5SSvyatoslav Ryhel #define EMC_XM2DQSPADCTRL2_VREF_ENABLE BIT(5) 178dce208b5SSvyatoslav Ryhel #define EMC_XM2DQPADCTRL 0x300 179dce208b5SSvyatoslav Ryhel #define EMC_XM2DQPADCTRL2 0x304 180dce208b5SSvyatoslav Ryhel #define EMC_XM2CLKPADCTRL 0x308 181dce208b5SSvyatoslav Ryhel #define EMC_XM2COMPPADCTRL 0x30c 182dce208b5SSvyatoslav Ryhel #define EMC_XM2VTTGENPADCTRL 0x310 183dce208b5SSvyatoslav Ryhel #define EMC_XM2VTTGENPADCTRL2 0x314 184dce208b5SSvyatoslav Ryhel #define EMC_XM2QUSEPADCTRL 0x318 185dce208b5SSvyatoslav Ryhel #define EMC_XM2DQSPADCTRL4 0x320 186dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQS0 0x328 187dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQS1 0x32c 188dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQS2 0x330 189dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQS3 0x334 190dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQS4 0x338 191dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQS5 0x33c 192dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQS6 0x340 193dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQS7 0x344 194dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_QUSE0 0x348 195dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_QUSE1 0x34c 196dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_QUSE2 0x350 197dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_QUSE3 0x354 198dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_QUSE4 0x358 199dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_QUSE5 0x35c 200dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_QUSE6 0x360 201dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_QUSE7 0x364 202dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQ0 0x368 203dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQ1 0x36c 204dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQ2 0x370 205dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_DQ3 0x374 206dce208b5SSvyatoslav Ryhel #define EMC_DLI_TRIM_TXDQS0 0x3a8 207dce208b5SSvyatoslav Ryhel #define EMC_DLI_TRIM_TXDQS1 0x3ac 208dce208b5SSvyatoslav Ryhel #define EMC_DLI_TRIM_TXDQS2 0x3b0 209dce208b5SSvyatoslav Ryhel #define EMC_DLI_TRIM_TXDQS3 0x3b4 210dce208b5SSvyatoslav Ryhel #define EMC_DLI_TRIM_TXDQS4 0x3b8 211dce208b5SSvyatoslav Ryhel #define EMC_DLI_TRIM_TXDQS5 0x3bc 212dce208b5SSvyatoslav Ryhel #define EMC_DLI_TRIM_TXDQS6 0x3c0 213dce208b5SSvyatoslav Ryhel #define EMC_DLI_TRIM_TXDQS7 0x3c4 214dce208b5SSvyatoslav Ryhel #define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3cc 215dce208b5SSvyatoslav Ryhel #define EMC_SEL_DPD_CTRL 0x3d8 216dce208b5SSvyatoslav Ryhel #define EMC_SEL_DPD_CTRL_DATA_SEL_DPD BIT(8) 217dce208b5SSvyatoslav Ryhel #define EMC_SEL_DPD_CTRL_ODT_SEL_DPD BIT(5) 218dce208b5SSvyatoslav Ryhel #define EMC_SEL_DPD_CTRL_RESET_SEL_DPD BIT(4) 219dce208b5SSvyatoslav Ryhel #define EMC_SEL_DPD_CTRL_CA_SEL_DPD BIT(3) 220dce208b5SSvyatoslav Ryhel #define EMC_SEL_DPD_CTRL_CLK_SEL_DPD BIT(2) 221dce208b5SSvyatoslav Ryhel #define EMC_SEL_DPD_CTRL_DDR3_MASK \ 222dce208b5SSvyatoslav Ryhel ((0xf << 2) | BIT(8)) 223dce208b5SSvyatoslav Ryhel #define EMC_SEL_DPD_CTRL_MASK \ 224dce208b5SSvyatoslav Ryhel ((0x3 << 2) | BIT(5) | BIT(8)) 225dce208b5SSvyatoslav Ryhel #define EMC_PRE_REFRESH_REQ_CNT 0x3dc 226dce208b5SSvyatoslav Ryhel #define EMC_DYN_SELF_REF_CONTROL 0x3e0 227dce208b5SSvyatoslav Ryhel #define EMC_TXSRDLL 0x3e4 228dce208b5SSvyatoslav Ryhel #define EMC_CCFIFO_ADDR 0x3e8 229dce208b5SSvyatoslav Ryhel #define EMC_CCFIFO_DATA 0x3ec 230dce208b5SSvyatoslav Ryhel #define EMC_CCFIFO_STATUS 0x3f0 231dce208b5SSvyatoslav Ryhel #define EMC_CDB_CNTL_1 0x3f4 232dce208b5SSvyatoslav Ryhel #define EMC_CDB_CNTL_2 0x3f8 233dce208b5SSvyatoslav Ryhel #define EMC_XM2CLKPADCTRL2 0x3fc 234dce208b5SSvyatoslav Ryhel #define EMC_AUTO_CAL_CONFIG2 0x458 235dce208b5SSvyatoslav Ryhel #define EMC_AUTO_CAL_CONFIG3 0x45c 236dce208b5SSvyatoslav Ryhel #define EMC_IBDLY 0x468 237dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_ADDR0 0x46c 238dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_ADDR1 0x470 239dce208b5SSvyatoslav Ryhel #define EMC_DLL_XFORM_ADDR2 0x474 240dce208b5SSvyatoslav Ryhel #define EMC_DSR_VTTGEN_DRV 0x47c 241dce208b5SSvyatoslav Ryhel #define EMC_TXDSRVTTGEN 0x480 242dce208b5SSvyatoslav Ryhel #define EMC_XM2CMDPADCTRL4 0x484 243dce208b5SSvyatoslav Ryhel 244dce208b5SSvyatoslav Ryhel #define DRAM_DEV_SEL_ALL 0 245dce208b5SSvyatoslav Ryhel #define DRAM_DEV_SEL_0 BIT(31) 246dce208b5SSvyatoslav Ryhel #define DRAM_DEV_SEL_1 BIT(30) 247dce208b5SSvyatoslav Ryhel 248dce208b5SSvyatoslav Ryhel #define EMC_CFG_POWER_FEATURES_MASK \ 249dce208b5SSvyatoslav Ryhel (EMC_CFG_DYN_SREF | EMC_CFG_DRAM_ACPD | EMC_CFG_DRAM_CLKSTOP_SR | \ 250dce208b5SSvyatoslav Ryhel EMC_CFG_DRAM_CLKSTOP_PD | EMC_CFG_DSR_VTTGEN_DRV_EN) 251dce208b5SSvyatoslav Ryhel #define EMC_REFCTRL_DEV_SEL(n) ((((n) > 1) ? 0 : 2) << EMC_REFCTRL_DEV_SEL_SHIFT) 252dce208b5SSvyatoslav Ryhel #define EMC_DRAM_DEV_SEL(n) (((n) > 1) ? DRAM_DEV_SEL_ALL : DRAM_DEV_SEL_0) 253dce208b5SSvyatoslav Ryhel 254dce208b5SSvyatoslav Ryhel /* Maximum amount of time in us. to wait for changes to become effective */ 255dce208b5SSvyatoslav Ryhel #define EMC_STATUS_UPDATE_TIMEOUT 1000 256dce208b5SSvyatoslav Ryhel 257dce208b5SSvyatoslav Ryhel enum emc_dram_type { 258dce208b5SSvyatoslav Ryhel DRAM_TYPE_DDR3, 259dce208b5SSvyatoslav Ryhel DRAM_TYPE_DDR1, 260dce208b5SSvyatoslav Ryhel DRAM_TYPE_LPDDR2, 261dce208b5SSvyatoslav Ryhel DRAM_TYPE_DDR2 262dce208b5SSvyatoslav Ryhel }; 263dce208b5SSvyatoslav Ryhel 264dce208b5SSvyatoslav Ryhel enum emc_dll_change { 265dce208b5SSvyatoslav Ryhel DLL_CHANGE_NONE, 266dce208b5SSvyatoslav Ryhel DLL_CHANGE_ON, 267dce208b5SSvyatoslav Ryhel DLL_CHANGE_OFF 268dce208b5SSvyatoslav Ryhel }; 269dce208b5SSvyatoslav Ryhel 270dce208b5SSvyatoslav Ryhel static const unsigned long emc_burst_regs[] = { 271dce208b5SSvyatoslav Ryhel EMC_RC, 272dce208b5SSvyatoslav Ryhel EMC_RFC, 273dce208b5SSvyatoslav Ryhel EMC_RAS, 274dce208b5SSvyatoslav Ryhel EMC_RP, 275dce208b5SSvyatoslav Ryhel EMC_R2W, 276dce208b5SSvyatoslav Ryhel EMC_W2R, 277dce208b5SSvyatoslav Ryhel EMC_R2P, 278dce208b5SSvyatoslav Ryhel EMC_W2P, 279dce208b5SSvyatoslav Ryhel EMC_RD_RCD, 280dce208b5SSvyatoslav Ryhel EMC_WR_RCD, 281dce208b5SSvyatoslav Ryhel EMC_RRD, 282dce208b5SSvyatoslav Ryhel EMC_REXT, 283dce208b5SSvyatoslav Ryhel EMC_WEXT, 284dce208b5SSvyatoslav Ryhel EMC_WDV, 285dce208b5SSvyatoslav Ryhel EMC_WDV_MASK, 286dce208b5SSvyatoslav Ryhel EMC_QUSE, 287dce208b5SSvyatoslav Ryhel EMC_IBDLY, 288dce208b5SSvyatoslav Ryhel EMC_EINPUT, 289dce208b5SSvyatoslav Ryhel EMC_EINPUT_DURATION, 290dce208b5SSvyatoslav Ryhel EMC_PUTERM_EXTRA, 291dce208b5SSvyatoslav Ryhel EMC_CDB_CNTL_1, 292dce208b5SSvyatoslav Ryhel EMC_CDB_CNTL_2, 293dce208b5SSvyatoslav Ryhel EMC_QRST, 294dce208b5SSvyatoslav Ryhel EMC_QSAFE, 295dce208b5SSvyatoslav Ryhel EMC_RDV, 296dce208b5SSvyatoslav Ryhel EMC_RDV_MASK, 297dce208b5SSvyatoslav Ryhel EMC_REFRESH, 298dce208b5SSvyatoslav Ryhel EMC_BURST_REFRESH_NUM, 299dce208b5SSvyatoslav Ryhel EMC_PRE_REFRESH_REQ_CNT, 300dce208b5SSvyatoslav Ryhel EMC_PDEX2WR, 301dce208b5SSvyatoslav Ryhel EMC_PDEX2RD, 302dce208b5SSvyatoslav Ryhel EMC_PCHG2PDEN, 303dce208b5SSvyatoslav Ryhel EMC_ACT2PDEN, 304dce208b5SSvyatoslav Ryhel EMC_AR2PDEN, 305dce208b5SSvyatoslav Ryhel EMC_RW2PDEN, 306dce208b5SSvyatoslav Ryhel EMC_TXSR, 307dce208b5SSvyatoslav Ryhel EMC_TXSRDLL, 308dce208b5SSvyatoslav Ryhel EMC_TCKE, 309dce208b5SSvyatoslav Ryhel EMC_TCKESR, 310dce208b5SSvyatoslav Ryhel EMC_TPD, 311dce208b5SSvyatoslav Ryhel EMC_TFAW, 312dce208b5SSvyatoslav Ryhel EMC_TRPAB, 313dce208b5SSvyatoslav Ryhel EMC_TCLKSTABLE, 314dce208b5SSvyatoslav Ryhel EMC_TCLKSTOP, 315dce208b5SSvyatoslav Ryhel EMC_TREFBW, 316dce208b5SSvyatoslav Ryhel EMC_QUSE_EXTRA, 317dce208b5SSvyatoslav Ryhel EMC_FBIO_CFG6, 318dce208b5SSvyatoslav Ryhel EMC_ODT_WRITE, 319dce208b5SSvyatoslav Ryhel EMC_ODT_READ, 320dce208b5SSvyatoslav Ryhel EMC_FBIO_CFG5, 321dce208b5SSvyatoslav Ryhel EMC_CFG_DIG_DLL, 322dce208b5SSvyatoslav Ryhel EMC_CFG_DIG_DLL_PERIOD, 323dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQS0, 324dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQS1, 325dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQS2, 326dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQS3, 327dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQS4, 328dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQS5, 329dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQS6, 330dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQS7, 331dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_QUSE0, 332dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_QUSE1, 333dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_QUSE2, 334dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_QUSE3, 335dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_QUSE4, 336dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_QUSE5, 337dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_QUSE6, 338dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_QUSE7, 339dce208b5SSvyatoslav Ryhel EMC_DLI_TRIM_TXDQS0, 340dce208b5SSvyatoslav Ryhel EMC_DLI_TRIM_TXDQS1, 341dce208b5SSvyatoslav Ryhel EMC_DLI_TRIM_TXDQS2, 342dce208b5SSvyatoslav Ryhel EMC_DLI_TRIM_TXDQS3, 343dce208b5SSvyatoslav Ryhel EMC_DLI_TRIM_TXDQS4, 344dce208b5SSvyatoslav Ryhel EMC_DLI_TRIM_TXDQS5, 345dce208b5SSvyatoslav Ryhel EMC_DLI_TRIM_TXDQS6, 346dce208b5SSvyatoslav Ryhel EMC_DLI_TRIM_TXDQS7, 347dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQ0, 348dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQ1, 349dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQ2, 350dce208b5SSvyatoslav Ryhel EMC_DLL_XFORM_DQ3, 351dce208b5SSvyatoslav Ryhel EMC_XM2CMDPADCTRL, 352dce208b5SSvyatoslav Ryhel EMC_XM2CMDPADCTRL4, 353dce208b5SSvyatoslav Ryhel EMC_XM2DQPADCTRL2, 354dce208b5SSvyatoslav Ryhel EMC_XM2CLKPADCTRL, 355dce208b5SSvyatoslav Ryhel EMC_XM2COMPPADCTRL, 356dce208b5SSvyatoslav Ryhel EMC_XM2VTTGENPADCTRL, 357dce208b5SSvyatoslav Ryhel EMC_XM2VTTGENPADCTRL2, 358dce208b5SSvyatoslav Ryhel EMC_XM2DQSPADCTRL3, 359dce208b5SSvyatoslav Ryhel EMC_XM2DQSPADCTRL4, 360dce208b5SSvyatoslav Ryhel EMC_DSR_VTTGEN_DRV, 361dce208b5SSvyatoslav Ryhel EMC_TXDSRVTTGEN, 362dce208b5SSvyatoslav Ryhel EMC_FBIO_SPARE, 363dce208b5SSvyatoslav Ryhel EMC_ZCAL_WAIT_CNT, 364dce208b5SSvyatoslav Ryhel EMC_MRS_WAIT_CNT2, 365dce208b5SSvyatoslav Ryhel EMC_CTT, 366dce208b5SSvyatoslav Ryhel EMC_CTT_DURATION, 367dce208b5SSvyatoslav Ryhel EMC_DYN_SELF_REF_CONTROL, 368dce208b5SSvyatoslav Ryhel }; 369dce208b5SSvyatoslav Ryhel 370dce208b5SSvyatoslav Ryhel struct emc_timing { 371dce208b5SSvyatoslav Ryhel unsigned long rate; 372dce208b5SSvyatoslav Ryhel 373dce208b5SSvyatoslav Ryhel u32 emc_burst_data[ARRAY_SIZE(emc_burst_regs)]; 374dce208b5SSvyatoslav Ryhel 375dce208b5SSvyatoslav Ryhel u32 emc_auto_cal_config; 376dce208b5SSvyatoslav Ryhel u32 emc_auto_cal_config2; 377dce208b5SSvyatoslav Ryhel u32 emc_auto_cal_config3; 378dce208b5SSvyatoslav Ryhel u32 emc_auto_cal_interval; 379dce208b5SSvyatoslav Ryhel u32 emc_cfg; 380dce208b5SSvyatoslav Ryhel u32 emc_ctt_term_ctrl; 381dce208b5SSvyatoslav Ryhel u32 emc_mode_1; 382dce208b5SSvyatoslav Ryhel u32 emc_mode_2; 383dce208b5SSvyatoslav Ryhel u32 emc_mode_4; 384dce208b5SSvyatoslav Ryhel u32 emc_mode_reset; 385dce208b5SSvyatoslav Ryhel u32 emc_mrs_wait_cnt; 386dce208b5SSvyatoslav Ryhel u32 emc_sel_dpd_ctrl; 387dce208b5SSvyatoslav Ryhel u32 emc_xm2dqspadctrl2; 388dce208b5SSvyatoslav Ryhel u32 emc_zcal_cnt_long; 389dce208b5SSvyatoslav Ryhel u32 emc_zcal_interval; 390dce208b5SSvyatoslav Ryhel }; 391dce208b5SSvyatoslav Ryhel 392dce208b5SSvyatoslav Ryhel struct tegra_emc { 393dce208b5SSvyatoslav Ryhel struct device *dev; 394dce208b5SSvyatoslav Ryhel struct tegra_mc *mc; 395dce208b5SSvyatoslav Ryhel void __iomem *regs; 396dce208b5SSvyatoslav Ryhel unsigned int irq; 397dce208b5SSvyatoslav Ryhel struct clk *clk; 398dce208b5SSvyatoslav Ryhel 399dce208b5SSvyatoslav Ryhel enum emc_dram_type dram_type; 400dce208b5SSvyatoslav Ryhel unsigned int dram_num; 401dce208b5SSvyatoslav Ryhel 402dce208b5SSvyatoslav Ryhel struct emc_timing last_timing; 403dce208b5SSvyatoslav Ryhel struct emc_timing *timings; 404dce208b5SSvyatoslav Ryhel unsigned int num_timings; 405dce208b5SSvyatoslav Ryhel 406dce208b5SSvyatoslav Ryhel struct { 407dce208b5SSvyatoslav Ryhel struct dentry *root; 408dce208b5SSvyatoslav Ryhel unsigned long min_rate; 409dce208b5SSvyatoslav Ryhel unsigned long max_rate; 410dce208b5SSvyatoslav Ryhel } debugfs; 411dce208b5SSvyatoslav Ryhel 412dce208b5SSvyatoslav Ryhel struct icc_provider provider; 413dce208b5SSvyatoslav Ryhel struct tegra_emc_rate_requests reqs; 414dce208b5SSvyatoslav Ryhel }; 415dce208b5SSvyatoslav Ryhel 416dce208b5SSvyatoslav Ryhel static irqreturn_t tegra114_emc_isr(int irq, void *data) 417dce208b5SSvyatoslav Ryhel { 418dce208b5SSvyatoslav Ryhel struct tegra_emc *emc = data; 419dce208b5SSvyatoslav Ryhel u32 intmask = EMC_INTSTATUS_REFRESH_OVERFLOW; 420dce208b5SSvyatoslav Ryhel u32 status; 421dce208b5SSvyatoslav Ryhel 422dce208b5SSvyatoslav Ryhel status = readl_relaxed(emc->regs + EMC_INTSTATUS) & intmask; 423dce208b5SSvyatoslav Ryhel if (!status) 424dce208b5SSvyatoslav Ryhel return IRQ_NONE; 425dce208b5SSvyatoslav Ryhel 426dce208b5SSvyatoslav Ryhel /* notify about HW problem */ 427dce208b5SSvyatoslav Ryhel if (status & EMC_INTSTATUS_REFRESH_OVERFLOW) 428dce208b5SSvyatoslav Ryhel dev_err_ratelimited(emc->dev, 429dce208b5SSvyatoslav Ryhel "refresh request overflow timeout\n"); 430dce208b5SSvyatoslav Ryhel 431dce208b5SSvyatoslav Ryhel /* clear interrupts */ 432dce208b5SSvyatoslav Ryhel writel_relaxed(status, emc->regs + EMC_INTSTATUS); 433dce208b5SSvyatoslav Ryhel 434dce208b5SSvyatoslav Ryhel return IRQ_HANDLED; 435dce208b5SSvyatoslav Ryhel } 436dce208b5SSvyatoslav Ryhel 437dce208b5SSvyatoslav Ryhel /* Timing change sequence functions */ 438dce208b5SSvyatoslav Ryhel 439dce208b5SSvyatoslav Ryhel static void emc_ccfifo_writel(struct tegra_emc *emc, u32 value, 440dce208b5SSvyatoslav Ryhel unsigned long offset) 441dce208b5SSvyatoslav Ryhel { 442dce208b5SSvyatoslav Ryhel writel(value, emc->regs + EMC_CCFIFO_DATA); 443dce208b5SSvyatoslav Ryhel writel(offset, emc->regs + EMC_CCFIFO_ADDR); 444dce208b5SSvyatoslav Ryhel } 445dce208b5SSvyatoslav Ryhel 446dce208b5SSvyatoslav Ryhel static void emc_seq_update_timing(struct tegra_emc *emc) 447dce208b5SSvyatoslav Ryhel { 448dce208b5SSvyatoslav Ryhel int ret; 449dce208b5SSvyatoslav Ryhel u32 value; 450dce208b5SSvyatoslav Ryhel 451dce208b5SSvyatoslav Ryhel writel(1, emc->regs + EMC_TIMING_CONTROL); 452dce208b5SSvyatoslav Ryhel 453dce208b5SSvyatoslav Ryhel ret = readl_poll_timeout_atomic(emc->regs + EMC_STATUS, value, 454dce208b5SSvyatoslav Ryhel !(value & EMC_STATUS_TIMING_UPDATE_STALLED), 455dce208b5SSvyatoslav Ryhel 1, EMC_STATUS_UPDATE_TIMEOUT); 456dce208b5SSvyatoslav Ryhel if (ret) 457dce208b5SSvyatoslav Ryhel dev_err(emc->dev, "timing update timed out\n"); 458dce208b5SSvyatoslav Ryhel } 459dce208b5SSvyatoslav Ryhel 460dce208b5SSvyatoslav Ryhel static void emc_seq_disable_auto_cal(struct tegra_emc *emc) 461dce208b5SSvyatoslav Ryhel { 462dce208b5SSvyatoslav Ryhel int ret; 463dce208b5SSvyatoslav Ryhel u32 value; 464dce208b5SSvyatoslav Ryhel 465dce208b5SSvyatoslav Ryhel writel(0, emc->regs + EMC_AUTO_CAL_INTERVAL); 466dce208b5SSvyatoslav Ryhel 467dce208b5SSvyatoslav Ryhel ret = readl_poll_timeout_atomic(emc->regs + EMC_AUTO_CAL_STATUS, value, 468dce208b5SSvyatoslav Ryhel !(value & EMC_AUTO_CAL_STATUS_ACTIVE), 469dce208b5SSvyatoslav Ryhel 1, EMC_STATUS_UPDATE_TIMEOUT); 470dce208b5SSvyatoslav Ryhel if (ret) 471dce208b5SSvyatoslav Ryhel dev_err(emc->dev, "auto cal disable timed out\n"); 472dce208b5SSvyatoslav Ryhel } 473dce208b5SSvyatoslav Ryhel 474dce208b5SSvyatoslav Ryhel static void emc_seq_wait_clkchange(struct tegra_emc *emc) 475dce208b5SSvyatoslav Ryhel { 476dce208b5SSvyatoslav Ryhel int ret; 477dce208b5SSvyatoslav Ryhel u32 value; 478dce208b5SSvyatoslav Ryhel 479dce208b5SSvyatoslav Ryhel ret = readl_poll_timeout_atomic(emc->regs + EMC_INTSTATUS, value, 480dce208b5SSvyatoslav Ryhel value & EMC_INTSTATUS_CLKCHANGE_COMPLETE, 481dce208b5SSvyatoslav Ryhel 1, EMC_STATUS_UPDATE_TIMEOUT); 482dce208b5SSvyatoslav Ryhel if (ret) 483dce208b5SSvyatoslav Ryhel dev_err(emc->dev, "clock change timed out\n"); 484dce208b5SSvyatoslav Ryhel } 485dce208b5SSvyatoslav Ryhel 486dce208b5SSvyatoslav Ryhel static struct emc_timing *tegra114_emc_find_timing(struct tegra_emc *emc, 487dce208b5SSvyatoslav Ryhel unsigned long rate) 488dce208b5SSvyatoslav Ryhel { 489dce208b5SSvyatoslav Ryhel struct emc_timing *timing = NULL; 490dce208b5SSvyatoslav Ryhel unsigned int i; 491dce208b5SSvyatoslav Ryhel 492dce208b5SSvyatoslav Ryhel for (i = 0; i < emc->num_timings; i++) { 493dce208b5SSvyatoslav Ryhel if (emc->timings[i].rate == rate) { 494dce208b5SSvyatoslav Ryhel timing = &emc->timings[i]; 495dce208b5SSvyatoslav Ryhel break; 496dce208b5SSvyatoslav Ryhel } 497dce208b5SSvyatoslav Ryhel } 498dce208b5SSvyatoslav Ryhel 499dce208b5SSvyatoslav Ryhel if (!timing) { 500dce208b5SSvyatoslav Ryhel dev_err(emc->dev, "no timing for rate %lu\n", rate); 501dce208b5SSvyatoslav Ryhel return NULL; 502dce208b5SSvyatoslav Ryhel } 503dce208b5SSvyatoslav Ryhel 504dce208b5SSvyatoslav Ryhel return timing; 505dce208b5SSvyatoslav Ryhel } 506dce208b5SSvyatoslav Ryhel 507dce208b5SSvyatoslav Ryhel static int tegra114_emc_prepare_timing_change(struct tegra_emc *emc, 508dce208b5SSvyatoslav Ryhel unsigned long rate) 509dce208b5SSvyatoslav Ryhel { 510dce208b5SSvyatoslav Ryhel struct emc_timing *timing = tegra114_emc_find_timing(emc, rate); 511dce208b5SSvyatoslav Ryhel struct emc_timing *last = &emc->last_timing; 512dce208b5SSvyatoslav Ryhel enum emc_dll_change dll_change; 513dce208b5SSvyatoslav Ryhel unsigned int pre_wait = 0; 514dce208b5SSvyatoslav Ryhel u32 val, mask; 515dce208b5SSvyatoslav Ryhel bool last_dll_enabled = !(last->emc_mode_1 & 0x1); 516dce208b5SSvyatoslav Ryhel bool update = false; 5174eda0dacSEthan Tidmore bool next_dll_enabled; 518dce208b5SSvyatoslav Ryhel unsigned int i; 519dce208b5SSvyatoslav Ryhel 520dce208b5SSvyatoslav Ryhel if (!timing) 521dce208b5SSvyatoslav Ryhel return -ENOENT; 522dce208b5SSvyatoslav Ryhel 5234eda0dacSEthan Tidmore next_dll_enabled = !(timing->emc_mode_1 & 0x1); 5244eda0dacSEthan Tidmore 525dce208b5SSvyatoslav Ryhel if (next_dll_enabled == last_dll_enabled) 526dce208b5SSvyatoslav Ryhel dll_change = DLL_CHANGE_NONE; 527dce208b5SSvyatoslav Ryhel else if (next_dll_enabled) 528dce208b5SSvyatoslav Ryhel dll_change = DLL_CHANGE_ON; 529dce208b5SSvyatoslav Ryhel else 530dce208b5SSvyatoslav Ryhel dll_change = DLL_CHANGE_OFF; 531dce208b5SSvyatoslav Ryhel 532dce208b5SSvyatoslav Ryhel /* Clear CLKCHANGE_COMPLETE interrupts */ 533dce208b5SSvyatoslav Ryhel writel(EMC_INTSTATUS_CLKCHANGE_COMPLETE, emc->regs + EMC_INTSTATUS); 534dce208b5SSvyatoslav Ryhel 535dce208b5SSvyatoslav Ryhel /* Disable dynamic self-refresh */ 536dce208b5SSvyatoslav Ryhel val = readl(emc->regs + EMC_CFG); 537dce208b5SSvyatoslav Ryhel if (val & EMC_CFG_PWR_MASK) { 538dce208b5SSvyatoslav Ryhel val &= ~EMC_CFG_POWER_FEATURES_MASK; 539dce208b5SSvyatoslav Ryhel writel(val, emc->regs + EMC_CFG); 540dce208b5SSvyatoslav Ryhel 541dce208b5SSvyatoslav Ryhel pre_wait = 5; 542dce208b5SSvyatoslav Ryhel } 543dce208b5SSvyatoslav Ryhel 544dce208b5SSvyatoslav Ryhel /* Disable SEL_DPD_CTRL for clock change */ 545dce208b5SSvyatoslav Ryhel if (emc->dram_type == DRAM_TYPE_DDR3) 546dce208b5SSvyatoslav Ryhel mask = EMC_SEL_DPD_CTRL_DDR3_MASK; 547dce208b5SSvyatoslav Ryhel else 548dce208b5SSvyatoslav Ryhel mask = EMC_SEL_DPD_CTRL_MASK; 549dce208b5SSvyatoslav Ryhel 550dce208b5SSvyatoslav Ryhel val = readl(emc->regs + EMC_SEL_DPD_CTRL); 551dce208b5SSvyatoslav Ryhel if (val & mask) { 552dce208b5SSvyatoslav Ryhel val &= ~mask; 553dce208b5SSvyatoslav Ryhel writel(val, emc->regs + EMC_SEL_DPD_CTRL); 554dce208b5SSvyatoslav Ryhel } 555dce208b5SSvyatoslav Ryhel 556dce208b5SSvyatoslav Ryhel /* Prepare DQ/DQS for clock change */ 557dce208b5SSvyatoslav Ryhel val = readl(emc->regs + EMC_XM2DQSPADCTRL2); 558dce208b5SSvyatoslav Ryhel if (timing->emc_xm2dqspadctrl2 & EMC_XM2DQSPADCTRL2_VREF_ENABLE && 559dce208b5SSvyatoslav Ryhel !(val & EMC_XM2DQSPADCTRL2_VREF_ENABLE)) { 560dce208b5SSvyatoslav Ryhel val |= EMC_XM2DQSPADCTRL2_VREF_ENABLE; 561dce208b5SSvyatoslav Ryhel update = true; 562dce208b5SSvyatoslav Ryhel } 563dce208b5SSvyatoslav Ryhel 564dce208b5SSvyatoslav Ryhel if (timing->emc_xm2dqspadctrl2 & EMC_XM2DQSPADCTRL2_RX_FT_REC_ENABLE && 565dce208b5SSvyatoslav Ryhel !(val & EMC_XM2DQSPADCTRL2_RX_FT_REC_ENABLE)) { 566dce208b5SSvyatoslav Ryhel val |= EMC_XM2DQSPADCTRL2_RX_FT_REC_ENABLE; 567dce208b5SSvyatoslav Ryhel update = true; 568dce208b5SSvyatoslav Ryhel } 569dce208b5SSvyatoslav Ryhel 570dce208b5SSvyatoslav Ryhel if (update) { 571dce208b5SSvyatoslav Ryhel writel(val, emc->regs + EMC_XM2DQSPADCTRL2); 572dce208b5SSvyatoslav Ryhel if (pre_wait < 30) 573dce208b5SSvyatoslav Ryhel pre_wait = 30; 574dce208b5SSvyatoslav Ryhel } 575dce208b5SSvyatoslav Ryhel 576dce208b5SSvyatoslav Ryhel /* Wait to settle */ 577dce208b5SSvyatoslav Ryhel if (pre_wait) { 578dce208b5SSvyatoslav Ryhel emc_seq_update_timing(emc); 579dce208b5SSvyatoslav Ryhel udelay(pre_wait); 580dce208b5SSvyatoslav Ryhel } 581dce208b5SSvyatoslav Ryhel 582dce208b5SSvyatoslav Ryhel /* Program CTT_TERM control */ 583dce208b5SSvyatoslav Ryhel if (last->emc_ctt_term_ctrl != timing->emc_ctt_term_ctrl) { 584dce208b5SSvyatoslav Ryhel emc_seq_disable_auto_cal(emc); 585dce208b5SSvyatoslav Ryhel writel(timing->emc_ctt_term_ctrl, 586dce208b5SSvyatoslav Ryhel emc->regs + EMC_CTT_TERM_CTRL); 587dce208b5SSvyatoslav Ryhel emc_seq_update_timing(emc); 588dce208b5SSvyatoslav Ryhel } 589dce208b5SSvyatoslav Ryhel 590dce208b5SSvyatoslav Ryhel /* Program burst shadow registers */ 591dce208b5SSvyatoslav Ryhel for (i = 0; i < ARRAY_SIZE(timing->emc_burst_data); ++i) 592dce208b5SSvyatoslav Ryhel writel(timing->emc_burst_data[i], 593dce208b5SSvyatoslav Ryhel emc->regs + emc_burst_regs[i]); 594dce208b5SSvyatoslav Ryhel 595dce208b5SSvyatoslav Ryhel writel(timing->emc_xm2dqspadctrl2, emc->regs + EMC_XM2DQSPADCTRL2); 596dce208b5SSvyatoslav Ryhel writel(timing->emc_zcal_interval, emc->regs + EMC_ZCAL_INTERVAL); 597dce208b5SSvyatoslav Ryhel 598dce208b5SSvyatoslav Ryhel tegra_mc_write_emem_configuration(emc->mc, timing->rate); 599dce208b5SSvyatoslav Ryhel 600dce208b5SSvyatoslav Ryhel val = timing->emc_cfg & ~EMC_CFG_POWER_FEATURES_MASK; 601dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, val, EMC_CFG); 602dce208b5SSvyatoslav Ryhel 603dce208b5SSvyatoslav Ryhel /* Program AUTO_CAL_CONFIG */ 604dce208b5SSvyatoslav Ryhel if (timing->emc_auto_cal_config2 != last->emc_auto_cal_config2) 605dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, timing->emc_auto_cal_config2, 606dce208b5SSvyatoslav Ryhel EMC_AUTO_CAL_CONFIG2); 607dce208b5SSvyatoslav Ryhel 608dce208b5SSvyatoslav Ryhel if (timing->emc_auto_cal_config3 != last->emc_auto_cal_config3) 609dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, timing->emc_auto_cal_config3, 610dce208b5SSvyatoslav Ryhel EMC_AUTO_CAL_CONFIG3); 611dce208b5SSvyatoslav Ryhel 612dce208b5SSvyatoslav Ryhel if (timing->emc_auto_cal_config != last->emc_auto_cal_config) { 613dce208b5SSvyatoslav Ryhel val = timing->emc_auto_cal_config; 614dce208b5SSvyatoslav Ryhel val &= EMC_AUTO_CAL_CONFIG_AUTO_CAL_START; 615dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, val, EMC_AUTO_CAL_CONFIG); 616dce208b5SSvyatoslav Ryhel } 617dce208b5SSvyatoslav Ryhel 618dce208b5SSvyatoslav Ryhel /* DDR3: predict MRS long wait count */ 619dce208b5SSvyatoslav Ryhel if (emc->dram_type == DRAM_TYPE_DDR3 && 620dce208b5SSvyatoslav Ryhel dll_change == DLL_CHANGE_ON) { 621dce208b5SSvyatoslav Ryhel u32 cnt = 512; 622dce208b5SSvyatoslav Ryhel 623dce208b5SSvyatoslav Ryhel if (timing->emc_zcal_interval != 0 && 624dce208b5SSvyatoslav Ryhel last->emc_zcal_interval == 0) 625dce208b5SSvyatoslav Ryhel cnt -= emc->dram_num * 256; 626dce208b5SSvyatoslav Ryhel 627dce208b5SSvyatoslav Ryhel val = (timing->emc_mrs_wait_cnt 628dce208b5SSvyatoslav Ryhel & EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK) 629dce208b5SSvyatoslav Ryhel >> EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT; 630dce208b5SSvyatoslav Ryhel if (cnt < val) 631dce208b5SSvyatoslav Ryhel cnt = val; 632dce208b5SSvyatoslav Ryhel 633dce208b5SSvyatoslav Ryhel val = timing->emc_mrs_wait_cnt 634dce208b5SSvyatoslav Ryhel & ~EMC_MRS_WAIT_CNT_LONG_WAIT_MASK; 635dce208b5SSvyatoslav Ryhel val |= (cnt << EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT) 636dce208b5SSvyatoslav Ryhel & EMC_MRS_WAIT_CNT_LONG_WAIT_MASK; 637dce208b5SSvyatoslav Ryhel 638dce208b5SSvyatoslav Ryhel writel(val, emc->regs + EMC_MRS_WAIT_CNT); 639dce208b5SSvyatoslav Ryhel } 640dce208b5SSvyatoslav Ryhel 641dce208b5SSvyatoslav Ryhel /* DDR3: Turn off DLL and enter self-refresh */ 642dce208b5SSvyatoslav Ryhel if (emc->dram_type == DRAM_TYPE_DDR3 && dll_change == DLL_CHANGE_OFF) 643dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, timing->emc_mode_1, EMC_EMRS); 644dce208b5SSvyatoslav Ryhel 645dce208b5SSvyatoslav Ryhel /* Disable refresh controller */ 646dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, EMC_REFCTRL_DEV_SEL(emc->dram_num), 647dce208b5SSvyatoslav Ryhel EMC_REFCTRL); 648dce208b5SSvyatoslav Ryhel if (emc->dram_type == DRAM_TYPE_DDR3) 649dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, EMC_DRAM_DEV_SEL(emc->dram_num) | 650dce208b5SSvyatoslav Ryhel EMC_SELF_REF_CMD_ENABLED, 651dce208b5SSvyatoslav Ryhel EMC_SELF_REF); 652dce208b5SSvyatoslav Ryhel 653dce208b5SSvyatoslav Ryhel /* Flow control marker */ 654dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, 1, EMC_STALL_THEN_EXE_AFTER_CLKCHANGE); 655dce208b5SSvyatoslav Ryhel 656dce208b5SSvyatoslav Ryhel /* DDR3: Exit self-refresh */ 657dce208b5SSvyatoslav Ryhel if (emc->dram_type == DRAM_TYPE_DDR3) 658dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, EMC_DRAM_DEV_SEL(emc->dram_num), 659dce208b5SSvyatoslav Ryhel EMC_SELF_REF); 660dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, EMC_REFCTRL_DEV_SEL(emc->dram_num) | 661dce208b5SSvyatoslav Ryhel EMC_REFCTRL_ENABLE, 662dce208b5SSvyatoslav Ryhel EMC_REFCTRL); 663dce208b5SSvyatoslav Ryhel 664dce208b5SSvyatoslav Ryhel /* Set DRAM mode registers */ 665dce208b5SSvyatoslav Ryhel if (emc->dram_type == DRAM_TYPE_DDR3) { 666dce208b5SSvyatoslav Ryhel if (timing->emc_mode_1 != last->emc_mode_1) 667dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, timing->emc_mode_1, EMC_EMRS); 668dce208b5SSvyatoslav Ryhel if (timing->emc_mode_2 != last->emc_mode_2) 669dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, timing->emc_mode_2, EMC_EMRS2); 670dce208b5SSvyatoslav Ryhel 671dce208b5SSvyatoslav Ryhel if (timing->emc_mode_reset != last->emc_mode_reset || 672dce208b5SSvyatoslav Ryhel dll_change == DLL_CHANGE_ON) { 673dce208b5SSvyatoslav Ryhel val = timing->emc_mode_reset; 674dce208b5SSvyatoslav Ryhel if (dll_change == DLL_CHANGE_ON) { 675dce208b5SSvyatoslav Ryhel val |= EMC_MODE_SET_DLL_RESET; 676dce208b5SSvyatoslav Ryhel val |= EMC_MODE_SET_LONG_CNT; 677dce208b5SSvyatoslav Ryhel } else { 678dce208b5SSvyatoslav Ryhel val &= ~EMC_MODE_SET_DLL_RESET; 679dce208b5SSvyatoslav Ryhel } 680dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, val, EMC_MRS); 681dce208b5SSvyatoslav Ryhel } 682dce208b5SSvyatoslav Ryhel } else { 683dce208b5SSvyatoslav Ryhel if (timing->emc_mode_2 != last->emc_mode_2) 684dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, timing->emc_mode_2, EMC_MRW2); 685dce208b5SSvyatoslav Ryhel if (timing->emc_mode_1 != last->emc_mode_1) 686dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, timing->emc_mode_1, EMC_MRW); 687dce208b5SSvyatoslav Ryhel if (timing->emc_mode_4 != last->emc_mode_4) 688dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, timing->emc_mode_4, EMC_MRW4); 689dce208b5SSvyatoslav Ryhel } 690dce208b5SSvyatoslav Ryhel 691dce208b5SSvyatoslav Ryhel /* Issue ZCAL command if turning ZCAL on */ 692dce208b5SSvyatoslav Ryhel if (timing->emc_zcal_interval != 0 && last->emc_zcal_interval == 0) { 693dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, EMC_ZQ_CAL_LONG_CMD_DEV0, EMC_ZQ_CAL); 694dce208b5SSvyatoslav Ryhel if (emc->dram_num > 1) 695dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, EMC_ZQ_CAL_LONG_CMD_DEV1, 696dce208b5SSvyatoslav Ryhel EMC_ZQ_CAL); 697dce208b5SSvyatoslav Ryhel } 698dce208b5SSvyatoslav Ryhel 699dce208b5SSvyatoslav Ryhel /* Write to RO register to remove stall after change */ 700dce208b5SSvyatoslav Ryhel emc_ccfifo_writel(emc, 0, EMC_CCFIFO_STATUS); 701dce208b5SSvyatoslav Ryhel 702dce208b5SSvyatoslav Ryhel /* Disable AUTO_CAL for clock change */ 703dce208b5SSvyatoslav Ryhel emc_seq_disable_auto_cal(emc); 704dce208b5SSvyatoslav Ryhel 705dce208b5SSvyatoslav Ryhel /* Read register to wait until programming has settled */ 706dce208b5SSvyatoslav Ryhel mc_readl(emc->mc, MC_EMEM_ADR_CFG); 707dce208b5SSvyatoslav Ryhel 708dce208b5SSvyatoslav Ryhel return 0; 709dce208b5SSvyatoslav Ryhel } 710dce208b5SSvyatoslav Ryhel 711dce208b5SSvyatoslav Ryhel static void tegra114_emc_complete_timing_change(struct tegra_emc *emc, 712dce208b5SSvyatoslav Ryhel unsigned long rate) 713dce208b5SSvyatoslav Ryhel { 714dce208b5SSvyatoslav Ryhel struct emc_timing *timing = tegra114_emc_find_timing(emc, rate); 715dce208b5SSvyatoslav Ryhel struct emc_timing *last = &emc->last_timing; 716dce208b5SSvyatoslav Ryhel 717dce208b5SSvyatoslav Ryhel if (!timing) 718dce208b5SSvyatoslav Ryhel return; 719dce208b5SSvyatoslav Ryhel 720dce208b5SSvyatoslav Ryhel /* Wait until the state machine has settled */ 721dce208b5SSvyatoslav Ryhel emc_seq_wait_clkchange(emc); 722dce208b5SSvyatoslav Ryhel 723dce208b5SSvyatoslav Ryhel /* Restore AUTO_CAL */ 724dce208b5SSvyatoslav Ryhel if (timing->emc_ctt_term_ctrl != last->emc_ctt_term_ctrl) 725dce208b5SSvyatoslav Ryhel writel(timing->emc_auto_cal_interval, 726dce208b5SSvyatoslav Ryhel emc->regs + EMC_AUTO_CAL_INTERVAL); 727dce208b5SSvyatoslav Ryhel 728dce208b5SSvyatoslav Ryhel /* Restore dynamic self-refresh */ 729dce208b5SSvyatoslav Ryhel if (timing->emc_cfg & EMC_CFG_PWR_MASK) 730dce208b5SSvyatoslav Ryhel writel(timing->emc_cfg, emc->regs + EMC_CFG); 731dce208b5SSvyatoslav Ryhel 732dce208b5SSvyatoslav Ryhel /* Set ZCAL wait count */ 733dce208b5SSvyatoslav Ryhel writel(timing->emc_zcal_cnt_long, emc->regs + EMC_ZCAL_WAIT_CNT); 734dce208b5SSvyatoslav Ryhel 735dce208b5SSvyatoslav Ryhel /* Wait for timing to settle */ 736dce208b5SSvyatoslav Ryhel udelay(2); 737dce208b5SSvyatoslav Ryhel 738dce208b5SSvyatoslav Ryhel /* Reprogram SEL_DPD_CTRL */ 739dce208b5SSvyatoslav Ryhel writel(timing->emc_sel_dpd_ctrl, emc->regs + EMC_SEL_DPD_CTRL); 740dce208b5SSvyatoslav Ryhel emc_seq_update_timing(emc); 741dce208b5SSvyatoslav Ryhel 742dce208b5SSvyatoslav Ryhel emc->last_timing = *timing; 743dce208b5SSvyatoslav Ryhel } 744dce208b5SSvyatoslav Ryhel 745dce208b5SSvyatoslav Ryhel /* Initialization and deinitialization */ 746dce208b5SSvyatoslav Ryhel 747dce208b5SSvyatoslav Ryhel static void emc_read_current_timing(struct tegra_emc *emc, 748dce208b5SSvyatoslav Ryhel struct emc_timing *timing) 749dce208b5SSvyatoslav Ryhel { 750dce208b5SSvyatoslav Ryhel unsigned int i; 751dce208b5SSvyatoslav Ryhel 752dce208b5SSvyatoslav Ryhel for (i = 0; i < ARRAY_SIZE(emc_burst_regs); ++i) 753dce208b5SSvyatoslav Ryhel timing->emc_burst_data[i] = 754dce208b5SSvyatoslav Ryhel readl(emc->regs + emc_burst_regs[i]); 755dce208b5SSvyatoslav Ryhel 756dce208b5SSvyatoslav Ryhel timing->emc_cfg = readl(emc->regs + EMC_CFG); 757dce208b5SSvyatoslav Ryhel 758dce208b5SSvyatoslav Ryhel timing->emc_auto_cal_interval = 0; 759dce208b5SSvyatoslav Ryhel timing->emc_zcal_cnt_long = 0; 760dce208b5SSvyatoslav Ryhel timing->emc_mode_1 = 0; 761dce208b5SSvyatoslav Ryhel timing->emc_mode_2 = 0; 762dce208b5SSvyatoslav Ryhel timing->emc_mode_4 = 0; 763dce208b5SSvyatoslav Ryhel timing->emc_mode_reset = 0; 764dce208b5SSvyatoslav Ryhel } 765dce208b5SSvyatoslav Ryhel 766dce208b5SSvyatoslav Ryhel static void emc_init(struct tegra_emc *emc) 767dce208b5SSvyatoslav Ryhel { 768dce208b5SSvyatoslav Ryhel u32 emc_cfg, emc_dbg; 769dce208b5SSvyatoslav Ryhel u32 intmask = EMC_INTSTATUS_REFRESH_OVERFLOW; 770dce208b5SSvyatoslav Ryhel const char *dram_type_str; 771dce208b5SSvyatoslav Ryhel 772dce208b5SSvyatoslav Ryhel emc->dram_type = readl(emc->regs + EMC_FBIO_CFG5); 773dce208b5SSvyatoslav Ryhel 774dce208b5SSvyatoslav Ryhel emc->dram_type &= EMC_FBIO_CFG5_DRAM_TYPE_MASK; 775dce208b5SSvyatoslav Ryhel emc->dram_type >>= EMC_FBIO_CFG5_DRAM_TYPE_SHIFT; 776dce208b5SSvyatoslav Ryhel 777dce208b5SSvyatoslav Ryhel emc->dram_num = tegra_mc_get_emem_device_count(emc->mc); 778dce208b5SSvyatoslav Ryhel 779dce208b5SSvyatoslav Ryhel emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2); 780dce208b5SSvyatoslav Ryhel 781dce208b5SSvyatoslav Ryhel /* enable EMC and CAR to handshake on PLL divider/source changes */ 782dce208b5SSvyatoslav Ryhel emc_cfg |= EMC_CFG_2_CLKCHANGE_REQ_ENABLE; 783dce208b5SSvyatoslav Ryhel 784dce208b5SSvyatoslav Ryhel /* configure clock change mode accordingly to DRAM type */ 785dce208b5SSvyatoslav Ryhel if (emc->dram_type == DRAM_TYPE_LPDDR2) 786dce208b5SSvyatoslav Ryhel emc_cfg |= EMC_CFG_2_CLKCHANGE_PD_ENABLE; 787dce208b5SSvyatoslav Ryhel else 788dce208b5SSvyatoslav Ryhel emc_cfg &= ~EMC_CFG_2_CLKCHANGE_PD_ENABLE; 789dce208b5SSvyatoslav Ryhel 790dce208b5SSvyatoslav Ryhel writel_relaxed(emc_cfg, emc->regs + EMC_CFG_2); 791dce208b5SSvyatoslav Ryhel 792dce208b5SSvyatoslav Ryhel /* initialize interrupt */ 793dce208b5SSvyatoslav Ryhel writel_relaxed(intmask, emc->regs + EMC_INTMASK); 794dce208b5SSvyatoslav Ryhel writel_relaxed(0xffffffff, emc->regs + EMC_INTSTATUS); 795dce208b5SSvyatoslav Ryhel 796dce208b5SSvyatoslav Ryhel /* ensure that unwanted debug features are disabled */ 797dce208b5SSvyatoslav Ryhel emc_dbg = readl_relaxed(emc->regs + EMC_DBG); 798dce208b5SSvyatoslav Ryhel emc_dbg |= EMC_DBG_CFG_PRIORITY; 799dce208b5SSvyatoslav Ryhel emc_dbg &= ~EMC_DBG_READ_MUX_ASSEMBLY; 800dce208b5SSvyatoslav Ryhel emc_dbg &= ~EMC_DBG_WRITE_MUX_ACTIVE; 801dce208b5SSvyatoslav Ryhel emc_dbg &= ~EMC_DBG_FORCE_UPDATE; 802dce208b5SSvyatoslav Ryhel writel_relaxed(emc_dbg, emc->regs + EMC_DBG); 803dce208b5SSvyatoslav Ryhel 804dce208b5SSvyatoslav Ryhel switch (emc->dram_type) { 805dce208b5SSvyatoslav Ryhel case DRAM_TYPE_DDR1: 806dce208b5SSvyatoslav Ryhel dram_type_str = "DDR1"; 807dce208b5SSvyatoslav Ryhel break; 808dce208b5SSvyatoslav Ryhel case DRAM_TYPE_LPDDR2: 809dce208b5SSvyatoslav Ryhel dram_type_str = "LPDDR2"; 810dce208b5SSvyatoslav Ryhel break; 811dce208b5SSvyatoslav Ryhel case DRAM_TYPE_DDR2: 812dce208b5SSvyatoslav Ryhel dram_type_str = "DDR2"; 813dce208b5SSvyatoslav Ryhel break; 814dce208b5SSvyatoslav Ryhel case DRAM_TYPE_DDR3: 815dce208b5SSvyatoslav Ryhel dram_type_str = "DDR3"; 816dce208b5SSvyatoslav Ryhel break; 817dce208b5SSvyatoslav Ryhel } 818dce208b5SSvyatoslav Ryhel 819dce208b5SSvyatoslav Ryhel dev_info_once(emc->dev, "%u %s %s attached\n", emc->dram_num, 820dce208b5SSvyatoslav Ryhel dram_type_str, emc->dram_num == 2 ? "devices" : "device"); 821dce208b5SSvyatoslav Ryhel 822dce208b5SSvyatoslav Ryhel emc_read_current_timing(emc, &emc->last_timing); 823dce208b5SSvyatoslav Ryhel } 824dce208b5SSvyatoslav Ryhel 825dce208b5SSvyatoslav Ryhel static int load_one_timing_from_dt(struct tegra_emc *emc, 826dce208b5SSvyatoslav Ryhel struct emc_timing *timing, 827dce208b5SSvyatoslav Ryhel struct device_node *node) 828dce208b5SSvyatoslav Ryhel { 829dce208b5SSvyatoslav Ryhel u32 value; 830dce208b5SSvyatoslav Ryhel int err; 831dce208b5SSvyatoslav Ryhel 832dce208b5SSvyatoslav Ryhel err = of_property_read_u32(node, "clock-frequency", &value); 833dce208b5SSvyatoslav Ryhel if (err) { 834dce208b5SSvyatoslav Ryhel dev_err(emc->dev, "timing %pOFn: failed to read rate: %d\n", 835dce208b5SSvyatoslav Ryhel node, err); 836dce208b5SSvyatoslav Ryhel return err; 837dce208b5SSvyatoslav Ryhel } 838dce208b5SSvyatoslav Ryhel 839dce208b5SSvyatoslav Ryhel timing->rate = value; 840dce208b5SSvyatoslav Ryhel 841dce208b5SSvyatoslav Ryhel err = of_property_read_u32_array(node, "nvidia,emc-configuration", 842dce208b5SSvyatoslav Ryhel timing->emc_burst_data, 843dce208b5SSvyatoslav Ryhel ARRAY_SIZE(timing->emc_burst_data)); 844dce208b5SSvyatoslav Ryhel if (err) { 845dce208b5SSvyatoslav Ryhel dev_err(emc->dev, 846dce208b5SSvyatoslav Ryhel "timing %pOFn: failed to read emc burst data: %d\n", 847dce208b5SSvyatoslav Ryhel node, err); 848dce208b5SSvyatoslav Ryhel return err; 849dce208b5SSvyatoslav Ryhel } 850dce208b5SSvyatoslav Ryhel 851dce208b5SSvyatoslav Ryhel #define EMC_READ_PROP(prop, dtprop) { \ 852dce208b5SSvyatoslav Ryhel err = of_property_read_u32(node, dtprop, &timing->prop); \ 853dce208b5SSvyatoslav Ryhel if (err) { \ 854dce208b5SSvyatoslav Ryhel dev_err(emc->dev, "timing %pOFn: failed to read " #prop ": %d\n", \ 855dce208b5SSvyatoslav Ryhel node, err); \ 856dce208b5SSvyatoslav Ryhel return err; \ 857dce208b5SSvyatoslav Ryhel } \ 858dce208b5SSvyatoslav Ryhel } 859dce208b5SSvyatoslav Ryhel 860dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_auto_cal_config, "nvidia,emc-auto-cal-config") 861dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_auto_cal_config2, "nvidia,emc-auto-cal-config2") 862dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_auto_cal_config3, "nvidia,emc-auto-cal-config3") 863dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_auto_cal_interval, "nvidia,emc-auto-cal-interval") 864dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_cfg, "nvidia,emc-cfg") 865dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_ctt_term_ctrl, "nvidia,emc-ctt-term-ctrl") 866dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_mode_1, "nvidia,emc-mode-1") 867dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_mode_2, "nvidia,emc-mode-2") 868dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_mode_4, "nvidia,emc-mode-4") 869dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_mode_reset, "nvidia,emc-mode-reset") 870dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_mrs_wait_cnt, "nvidia,emc-mrs-wait-cnt") 871dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_sel_dpd_ctrl, "nvidia,emc-sel-dpd-ctrl") 872dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_xm2dqspadctrl2, "nvidia,emc-xm2dqspadctrl2") 873dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_zcal_cnt_long, "nvidia,emc-zcal-cnt-long") 874dce208b5SSvyatoslav Ryhel EMC_READ_PROP(emc_zcal_interval, "nvidia,emc-zcal-interval") 875dce208b5SSvyatoslav Ryhel 876dce208b5SSvyatoslav Ryhel #undef EMC_READ_PROP 877dce208b5SSvyatoslav Ryhel 878dce208b5SSvyatoslav Ryhel return 0; 879dce208b5SSvyatoslav Ryhel } 880dce208b5SSvyatoslav Ryhel 881dce208b5SSvyatoslav Ryhel static int cmp_timings(const void *_a, const void *_b) 882dce208b5SSvyatoslav Ryhel { 883dce208b5SSvyatoslav Ryhel const struct emc_timing *a = _a; 884dce208b5SSvyatoslav Ryhel const struct emc_timing *b = _b; 885dce208b5SSvyatoslav Ryhel 886dce208b5SSvyatoslav Ryhel if (a->rate < b->rate) 887dce208b5SSvyatoslav Ryhel return -1; 888dce208b5SSvyatoslav Ryhel else if (a->rate == b->rate) 889dce208b5SSvyatoslav Ryhel return 0; 890dce208b5SSvyatoslav Ryhel else 891dce208b5SSvyatoslav Ryhel return 1; 892dce208b5SSvyatoslav Ryhel } 893dce208b5SSvyatoslav Ryhel 894dce208b5SSvyatoslav Ryhel static int emc_check_mc_timings(struct tegra_emc *emc) 895dce208b5SSvyatoslav Ryhel { 896dce208b5SSvyatoslav Ryhel struct tegra_mc *mc = emc->mc; 897dce208b5SSvyatoslav Ryhel unsigned int i; 898dce208b5SSvyatoslav Ryhel 899dce208b5SSvyatoslav Ryhel if (emc->num_timings != mc->num_timings) { 900dce208b5SSvyatoslav Ryhel dev_err(emc->dev, "emc/mc timings number mismatch: %u %u\n", 901dce208b5SSvyatoslav Ryhel emc->num_timings, mc->num_timings); 902dce208b5SSvyatoslav Ryhel return -EINVAL; 903dce208b5SSvyatoslav Ryhel } 904dce208b5SSvyatoslav Ryhel 905dce208b5SSvyatoslav Ryhel for (i = 0; i < mc->num_timings; i++) { 906dce208b5SSvyatoslav Ryhel if (emc->timings[i].rate != mc->timings[i].rate) { 907dce208b5SSvyatoslav Ryhel dev_err(emc->dev, 908dce208b5SSvyatoslav Ryhel "emc/mc timing rate mismatch: %lu %lu\n", 909dce208b5SSvyatoslav Ryhel emc->timings[i].rate, mc->timings[i].rate); 910dce208b5SSvyatoslav Ryhel return -EINVAL; 911dce208b5SSvyatoslav Ryhel } 912dce208b5SSvyatoslav Ryhel } 913dce208b5SSvyatoslav Ryhel 914dce208b5SSvyatoslav Ryhel return 0; 915dce208b5SSvyatoslav Ryhel } 916dce208b5SSvyatoslav Ryhel 917dce208b5SSvyatoslav Ryhel static int tegra114_emc_load_timings_from_dt(struct tegra_emc *emc, 918dce208b5SSvyatoslav Ryhel struct device_node *node) 919dce208b5SSvyatoslav Ryhel { 920dce208b5SSvyatoslav Ryhel int child_count = of_get_child_count(node); 921dce208b5SSvyatoslav Ryhel struct emc_timing *timing; 922dce208b5SSvyatoslav Ryhel unsigned int i = 0; 923dce208b5SSvyatoslav Ryhel int err; 924dce208b5SSvyatoslav Ryhel 925dce208b5SSvyatoslav Ryhel emc->timings = devm_kcalloc(emc->dev, child_count, sizeof(*timing), 926dce208b5SSvyatoslav Ryhel GFP_KERNEL); 927dce208b5SSvyatoslav Ryhel if (!emc->timings) 928dce208b5SSvyatoslav Ryhel return -ENOMEM; 929dce208b5SSvyatoslav Ryhel 930dce208b5SSvyatoslav Ryhel emc->num_timings = child_count; 931dce208b5SSvyatoslav Ryhel 932dce208b5SSvyatoslav Ryhel for_each_child_of_node_scoped(node, child) { 933dce208b5SSvyatoslav Ryhel timing = &emc->timings[i++]; 934dce208b5SSvyatoslav Ryhel 935dce208b5SSvyatoslav Ryhel err = load_one_timing_from_dt(emc, timing, child); 936dce208b5SSvyatoslav Ryhel if (err) 937dce208b5SSvyatoslav Ryhel return err; 938dce208b5SSvyatoslav Ryhel } 939dce208b5SSvyatoslav Ryhel 940dce208b5SSvyatoslav Ryhel sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, 941dce208b5SSvyatoslav Ryhel NULL); 942dce208b5SSvyatoslav Ryhel 943dce208b5SSvyatoslav Ryhel err = emc_check_mc_timings(emc); 944dce208b5SSvyatoslav Ryhel if (err) 945dce208b5SSvyatoslav Ryhel return err; 946dce208b5SSvyatoslav Ryhel 947dce208b5SSvyatoslav Ryhel dev_info_once(emc->dev, 948dce208b5SSvyatoslav Ryhel "got %u timings for RAM code %u (min %luMHz max %luMHz)\n", 949dce208b5SSvyatoslav Ryhel emc->num_timings, 950dce208b5SSvyatoslav Ryhel tegra_read_ram_code(), 951dce208b5SSvyatoslav Ryhel emc->timings[0].rate / 1000000, 952dce208b5SSvyatoslav Ryhel emc->timings[emc->num_timings - 1].rate / 1000000); 953dce208b5SSvyatoslav Ryhel 954dce208b5SSvyatoslav Ryhel return 0; 955dce208b5SSvyatoslav Ryhel } 956dce208b5SSvyatoslav Ryhel 957dce208b5SSvyatoslav Ryhel static struct device_node * 958dce208b5SSvyatoslav Ryhel tegra114_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) 959dce208b5SSvyatoslav Ryhel { 960dce208b5SSvyatoslav Ryhel struct device_node *np; 961dce208b5SSvyatoslav Ryhel int err; 962dce208b5SSvyatoslav Ryhel 963dce208b5SSvyatoslav Ryhel for_each_child_of_node(node, np) { 964dce208b5SSvyatoslav Ryhel u32 value; 965dce208b5SSvyatoslav Ryhel 966dce208b5SSvyatoslav Ryhel err = of_property_read_u32(np, "nvidia,ram-code", &value); 967dce208b5SSvyatoslav Ryhel if (err || value != ram_code) 968dce208b5SSvyatoslav Ryhel continue; 969dce208b5SSvyatoslav Ryhel 970dce208b5SSvyatoslav Ryhel return np; 971dce208b5SSvyatoslav Ryhel } 972dce208b5SSvyatoslav Ryhel 973dce208b5SSvyatoslav Ryhel return NULL; 974dce208b5SSvyatoslav Ryhel } 975dce208b5SSvyatoslav Ryhel 976dce208b5SSvyatoslav Ryhel /* 977dce208b5SSvyatoslav Ryhel * debugfs interface 978dce208b5SSvyatoslav Ryhel * 979dce208b5SSvyatoslav Ryhel * The memory controller driver exposes some files in debugfs that can be used 980dce208b5SSvyatoslav Ryhel * to control the EMC frequency. The top-level directory can be found here: 981dce208b5SSvyatoslav Ryhel * 982dce208b5SSvyatoslav Ryhel * /sys/kernel/debug/emc 983dce208b5SSvyatoslav Ryhel * 984dce208b5SSvyatoslav Ryhel * It contains the following files: 985dce208b5SSvyatoslav Ryhel * 986dce208b5SSvyatoslav Ryhel * - available_rates: This file contains a list of valid, space-separated 987dce208b5SSvyatoslav Ryhel * EMC frequencies. 988dce208b5SSvyatoslav Ryhel * 989dce208b5SSvyatoslav Ryhel * - min_rate: Writing a value to this file sets the given frequency as the 990dce208b5SSvyatoslav Ryhel * floor of the permitted range. If this is higher than the currently 991dce208b5SSvyatoslav Ryhel * configured EMC frequency, this will cause the frequency to be 992dce208b5SSvyatoslav Ryhel * increased so that it stays within the valid range. 993dce208b5SSvyatoslav Ryhel * 994dce208b5SSvyatoslav Ryhel * - max_rate: Similarly to the min_rate file, writing a value to this file 995dce208b5SSvyatoslav Ryhel * sets the given frequency as the ceiling of the permitted range. If 996dce208b5SSvyatoslav Ryhel * the value is lower than the currently configured EMC frequency, this 997dce208b5SSvyatoslav Ryhel * will cause the frequency to be decreased so that it stays within the 998dce208b5SSvyatoslav Ryhel * valid range. 999dce208b5SSvyatoslav Ryhel */ 1000dce208b5SSvyatoslav Ryhel 1001dce208b5SSvyatoslav Ryhel static bool tegra114_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) 1002dce208b5SSvyatoslav Ryhel { 1003dce208b5SSvyatoslav Ryhel unsigned int i; 1004dce208b5SSvyatoslav Ryhel 1005dce208b5SSvyatoslav Ryhel for (i = 0; i < emc->num_timings; i++) 1006dce208b5SSvyatoslav Ryhel if (rate == emc->timings[i].rate) 1007dce208b5SSvyatoslav Ryhel return true; 1008dce208b5SSvyatoslav Ryhel 1009dce208b5SSvyatoslav Ryhel return false; 1010dce208b5SSvyatoslav Ryhel } 1011dce208b5SSvyatoslav Ryhel 1012dce208b5SSvyatoslav Ryhel static int tegra114_emc_debug_available_rates_show(struct seq_file *s, 1013dce208b5SSvyatoslav Ryhel void *data) 1014dce208b5SSvyatoslav Ryhel { 1015dce208b5SSvyatoslav Ryhel struct tegra_emc *emc = s->private; 1016dce208b5SSvyatoslav Ryhel const char *prefix = ""; 1017dce208b5SSvyatoslav Ryhel unsigned int i; 1018dce208b5SSvyatoslav Ryhel 1019dce208b5SSvyatoslav Ryhel for (i = 0; i < emc->num_timings; i++) { 1020dce208b5SSvyatoslav Ryhel seq_printf(s, "%s%lu", prefix, emc->timings[i].rate); 1021dce208b5SSvyatoslav Ryhel prefix = " "; 1022dce208b5SSvyatoslav Ryhel } 1023dce208b5SSvyatoslav Ryhel 1024dce208b5SSvyatoslav Ryhel seq_puts(s, "\n"); 1025dce208b5SSvyatoslav Ryhel 1026dce208b5SSvyatoslav Ryhel return 0; 1027dce208b5SSvyatoslav Ryhel } 1028dce208b5SSvyatoslav Ryhel 1029dce208b5SSvyatoslav Ryhel DEFINE_SHOW_ATTRIBUTE(tegra114_emc_debug_available_rates); 1030dce208b5SSvyatoslav Ryhel 1031dce208b5SSvyatoslav Ryhel static int tegra114_emc_debug_min_rate_get(void *data, u64 *rate) 1032dce208b5SSvyatoslav Ryhel { 1033dce208b5SSvyatoslav Ryhel struct tegra_emc *emc = data; 1034dce208b5SSvyatoslav Ryhel 1035dce208b5SSvyatoslav Ryhel *rate = emc->debugfs.min_rate; 1036dce208b5SSvyatoslav Ryhel 1037dce208b5SSvyatoslav Ryhel return 0; 1038dce208b5SSvyatoslav Ryhel } 1039dce208b5SSvyatoslav Ryhel 1040dce208b5SSvyatoslav Ryhel static int tegra114_emc_debug_min_rate_set(void *data, u64 rate) 1041dce208b5SSvyatoslav Ryhel { 1042dce208b5SSvyatoslav Ryhel struct tegra_emc *emc = data; 1043dce208b5SSvyatoslav Ryhel int err; 1044dce208b5SSvyatoslav Ryhel 1045dce208b5SSvyatoslav Ryhel if (!tegra114_emc_validate_rate(emc, rate)) 1046dce208b5SSvyatoslav Ryhel return -EINVAL; 1047dce208b5SSvyatoslav Ryhel 1048dce208b5SSvyatoslav Ryhel err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG); 1049dce208b5SSvyatoslav Ryhel if (err < 0) 1050dce208b5SSvyatoslav Ryhel return err; 1051dce208b5SSvyatoslav Ryhel 1052dce208b5SSvyatoslav Ryhel emc->debugfs.min_rate = rate; 1053dce208b5SSvyatoslav Ryhel 1054dce208b5SSvyatoslav Ryhel return 0; 1055dce208b5SSvyatoslav Ryhel } 1056dce208b5SSvyatoslav Ryhel 1057dce208b5SSvyatoslav Ryhel DEFINE_DEBUGFS_ATTRIBUTE(tegra114_emc_debug_min_rate_fops, 1058dce208b5SSvyatoslav Ryhel tegra114_emc_debug_min_rate_get, 1059dce208b5SSvyatoslav Ryhel tegra114_emc_debug_min_rate_set, "%llu\n"); 1060dce208b5SSvyatoslav Ryhel 1061dce208b5SSvyatoslav Ryhel static int tegra114_emc_debug_max_rate_get(void *data, u64 *rate) 1062dce208b5SSvyatoslav Ryhel { 1063dce208b5SSvyatoslav Ryhel struct tegra_emc *emc = data; 1064dce208b5SSvyatoslav Ryhel 1065dce208b5SSvyatoslav Ryhel *rate = emc->debugfs.max_rate; 1066dce208b5SSvyatoslav Ryhel 1067dce208b5SSvyatoslav Ryhel return 0; 1068dce208b5SSvyatoslav Ryhel } 1069dce208b5SSvyatoslav Ryhel 1070dce208b5SSvyatoslav Ryhel static int tegra114_emc_debug_max_rate_set(void *data, u64 rate) 1071dce208b5SSvyatoslav Ryhel { 1072dce208b5SSvyatoslav Ryhel struct tegra_emc *emc = data; 1073dce208b5SSvyatoslav Ryhel int err; 1074dce208b5SSvyatoslav Ryhel 1075dce208b5SSvyatoslav Ryhel if (!tegra114_emc_validate_rate(emc, rate)) 1076dce208b5SSvyatoslav Ryhel return -EINVAL; 1077dce208b5SSvyatoslav Ryhel 1078dce208b5SSvyatoslav Ryhel err = tegra_emc_set_max_rate(&emc->reqs, rate, TEGRA_EMC_RATE_DEBUG); 1079dce208b5SSvyatoslav Ryhel if (err < 0) 1080dce208b5SSvyatoslav Ryhel return err; 1081dce208b5SSvyatoslav Ryhel 1082dce208b5SSvyatoslav Ryhel emc->debugfs.max_rate = rate; 1083dce208b5SSvyatoslav Ryhel 1084dce208b5SSvyatoslav Ryhel return 0; 1085dce208b5SSvyatoslav Ryhel } 1086dce208b5SSvyatoslav Ryhel 1087dce208b5SSvyatoslav Ryhel DEFINE_DEBUGFS_ATTRIBUTE(tegra114_emc_debug_max_rate_fops, 1088dce208b5SSvyatoslav Ryhel tegra114_emc_debug_max_rate_get, 1089dce208b5SSvyatoslav Ryhel tegra114_emc_debug_max_rate_set, "%llu\n"); 1090dce208b5SSvyatoslav Ryhel 1091dce208b5SSvyatoslav Ryhel static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc) 1092dce208b5SSvyatoslav Ryhel { 1093dce208b5SSvyatoslav Ryhel unsigned int i; 1094dce208b5SSvyatoslav Ryhel int err; 1095dce208b5SSvyatoslav Ryhel 1096dce208b5SSvyatoslav Ryhel emc->debugfs.min_rate = ULONG_MAX; 1097dce208b5SSvyatoslav Ryhel emc->debugfs.max_rate = 0; 1098dce208b5SSvyatoslav Ryhel 1099dce208b5SSvyatoslav Ryhel for (i = 0; i < emc->num_timings; i++) { 1100dce208b5SSvyatoslav Ryhel if (emc->timings[i].rate < emc->debugfs.min_rate) 1101dce208b5SSvyatoslav Ryhel emc->debugfs.min_rate = emc->timings[i].rate; 1102dce208b5SSvyatoslav Ryhel 1103dce208b5SSvyatoslav Ryhel if (emc->timings[i].rate > emc->debugfs.max_rate) 1104dce208b5SSvyatoslav Ryhel emc->debugfs.max_rate = emc->timings[i].rate; 1105dce208b5SSvyatoslav Ryhel } 1106dce208b5SSvyatoslav Ryhel 1107dce208b5SSvyatoslav Ryhel if (!emc->num_timings) { 1108dce208b5SSvyatoslav Ryhel emc->debugfs.min_rate = clk_get_rate(emc->clk); 1109dce208b5SSvyatoslav Ryhel emc->debugfs.max_rate = emc->debugfs.min_rate; 1110dce208b5SSvyatoslav Ryhel } 1111dce208b5SSvyatoslav Ryhel 1112dce208b5SSvyatoslav Ryhel err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, 1113dce208b5SSvyatoslav Ryhel emc->debugfs.max_rate); 1114dce208b5SSvyatoslav Ryhel if (err < 0) { 1115dce208b5SSvyatoslav Ryhel dev_err(dev, "failed to set rate range [%lu-%lu] for %pC\n", 1116dce208b5SSvyatoslav Ryhel emc->debugfs.min_rate, emc->debugfs.max_rate, 1117dce208b5SSvyatoslav Ryhel emc->clk); 1118dce208b5SSvyatoslav Ryhel return; 1119dce208b5SSvyatoslav Ryhel } 1120dce208b5SSvyatoslav Ryhel 1121dce208b5SSvyatoslav Ryhel emc->debugfs.root = debugfs_create_dir("emc", NULL); 1122dce208b5SSvyatoslav Ryhel 1123dce208b5SSvyatoslav Ryhel debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, 1124dce208b5SSvyatoslav Ryhel &tegra114_emc_debug_available_rates_fops); 1125dce208b5SSvyatoslav Ryhel debugfs_create_file("min_rate", 0644, emc->debugfs.root, 1126dce208b5SSvyatoslav Ryhel emc, &tegra114_emc_debug_min_rate_fops); 1127dce208b5SSvyatoslav Ryhel debugfs_create_file("max_rate", 0644, emc->debugfs.root, 1128dce208b5SSvyatoslav Ryhel emc, &tegra114_emc_debug_max_rate_fops); 1129dce208b5SSvyatoslav Ryhel } 1130dce208b5SSvyatoslav Ryhel 1131dce208b5SSvyatoslav Ryhel static inline struct tegra_emc * 1132dce208b5SSvyatoslav Ryhel to_tegra_emc_provider(struct icc_provider *provider) 1133dce208b5SSvyatoslav Ryhel { 1134dce208b5SSvyatoslav Ryhel return container_of(provider, struct tegra_emc, provider); 1135dce208b5SSvyatoslav Ryhel } 1136dce208b5SSvyatoslav Ryhel 1137dce208b5SSvyatoslav Ryhel static struct icc_node_data * 1138dce208b5SSvyatoslav Ryhel emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data) 1139dce208b5SSvyatoslav Ryhel { 1140dce208b5SSvyatoslav Ryhel struct icc_provider *provider = data; 1141dce208b5SSvyatoslav Ryhel struct icc_node_data *ndata; 1142dce208b5SSvyatoslav Ryhel struct icc_node *node; 1143dce208b5SSvyatoslav Ryhel 1144dce208b5SSvyatoslav Ryhel /* External Memory is the only possible ICC route */ 1145dce208b5SSvyatoslav Ryhel list_for_each_entry(node, &provider->nodes, node_list) { 1146dce208b5SSvyatoslav Ryhel if (node->id != TEGRA_ICC_EMEM) 1147dce208b5SSvyatoslav Ryhel continue; 1148dce208b5SSvyatoslav Ryhel 1149dce208b5SSvyatoslav Ryhel ndata = kzalloc_obj(*ndata); 1150dce208b5SSvyatoslav Ryhel if (!ndata) 1151dce208b5SSvyatoslav Ryhel return ERR_PTR(-ENOMEM); 1152dce208b5SSvyatoslav Ryhel 1153dce208b5SSvyatoslav Ryhel /* 1154dce208b5SSvyatoslav Ryhel * SRC and DST nodes should have matching TAG in order to have 1155dce208b5SSvyatoslav Ryhel * it set by default for a requested path. 1156dce208b5SSvyatoslav Ryhel */ 1157dce208b5SSvyatoslav Ryhel ndata->tag = TEGRA_MC_ICC_TAG_ISO; 1158dce208b5SSvyatoslav Ryhel ndata->node = node; 1159dce208b5SSvyatoslav Ryhel 1160dce208b5SSvyatoslav Ryhel return ndata; 1161dce208b5SSvyatoslav Ryhel } 1162dce208b5SSvyatoslav Ryhel 1163dce208b5SSvyatoslav Ryhel return ERR_PTR(-EPROBE_DEFER); 1164dce208b5SSvyatoslav Ryhel } 1165dce208b5SSvyatoslav Ryhel 1166dce208b5SSvyatoslav Ryhel static int emc_icc_set(struct icc_node *src, struct icc_node *dst) 1167dce208b5SSvyatoslav Ryhel { 1168dce208b5SSvyatoslav Ryhel struct tegra_emc *emc = to_tegra_emc_provider(dst->provider); 1169dce208b5SSvyatoslav Ryhel unsigned long long peak_bw = icc_units_to_bps(dst->peak_bw); 1170dce208b5SSvyatoslav Ryhel unsigned long long avg_bw = icc_units_to_bps(dst->avg_bw); 1171dce208b5SSvyatoslav Ryhel unsigned long long rate = max(avg_bw, peak_bw); 1172dce208b5SSvyatoslav Ryhel unsigned int dram_data_bus_width_bytes = 4; 1173dce208b5SSvyatoslav Ryhel const unsigned int ddr = 2; 1174dce208b5SSvyatoslav Ryhel int err; 1175dce208b5SSvyatoslav Ryhel 1176dce208b5SSvyatoslav Ryhel /* 1177dce208b5SSvyatoslav Ryhel * Tegra114 EMC runs on a clock rate of SDRAM bus. This means that 1178dce208b5SSvyatoslav Ryhel * EMC clock rate is twice smaller than the peak data rate because 1179dce208b5SSvyatoslav Ryhel * data is sampled on both EMC clock edges. 1180dce208b5SSvyatoslav Ryhel */ 1181dce208b5SSvyatoslav Ryhel do_div(rate, ddr * dram_data_bus_width_bytes); 1182dce208b5SSvyatoslav Ryhel rate = min_t(u64, rate, U32_MAX); 1183dce208b5SSvyatoslav Ryhel 1184dce208b5SSvyatoslav Ryhel err = tegra_emc_set_min_rate(&emc->reqs, rate, TEGRA_EMC_RATE_ICC); 1185dce208b5SSvyatoslav Ryhel if (err) 1186dce208b5SSvyatoslav Ryhel return err; 1187dce208b5SSvyatoslav Ryhel 1188dce208b5SSvyatoslav Ryhel return 0; 1189dce208b5SSvyatoslav Ryhel } 1190dce208b5SSvyatoslav Ryhel 1191dce208b5SSvyatoslav Ryhel static int tegra114_emc_interconnect_init(struct tegra_emc *emc) 1192dce208b5SSvyatoslav Ryhel { 1193dce208b5SSvyatoslav Ryhel const struct tegra_mc_soc *soc = emc->mc->soc; 1194dce208b5SSvyatoslav Ryhel struct icc_node *node; 1195dce208b5SSvyatoslav Ryhel int err; 1196dce208b5SSvyatoslav Ryhel 1197dce208b5SSvyatoslav Ryhel emc->provider.dev = emc->dev; 1198dce208b5SSvyatoslav Ryhel emc->provider.set = emc_icc_set; 1199dce208b5SSvyatoslav Ryhel emc->provider.data = &emc->provider; 1200dce208b5SSvyatoslav Ryhel emc->provider.aggregate = soc->icc_ops->aggregate; 1201dce208b5SSvyatoslav Ryhel emc->provider.xlate_extended = emc_of_icc_xlate_extended; 1202dce208b5SSvyatoslav Ryhel 1203dce208b5SSvyatoslav Ryhel icc_provider_init(&emc->provider); 1204dce208b5SSvyatoslav Ryhel 1205dce208b5SSvyatoslav Ryhel /* create External Memory Controller node */ 1206dce208b5SSvyatoslav Ryhel node = icc_node_create(TEGRA_ICC_EMC); 120767de69efSKrzysztof Kozlowski if (IS_ERR(node)) 120867de69efSKrzysztof Kozlowski return PTR_ERR(node); 1209dce208b5SSvyatoslav Ryhel 1210dce208b5SSvyatoslav Ryhel node->name = "External Memory Controller"; 1211dce208b5SSvyatoslav Ryhel icc_node_add(node, &emc->provider); 1212dce208b5SSvyatoslav Ryhel 1213dce208b5SSvyatoslav Ryhel /* link External Memory Controller to External Memory (DRAM) */ 1214dce208b5SSvyatoslav Ryhel err = icc_link_create(node, TEGRA_ICC_EMEM); 1215dce208b5SSvyatoslav Ryhel if (err) 1216dce208b5SSvyatoslav Ryhel goto remove_nodes; 1217dce208b5SSvyatoslav Ryhel 1218dce208b5SSvyatoslav Ryhel /* create External Memory node */ 1219dce208b5SSvyatoslav Ryhel node = icc_node_create(TEGRA_ICC_EMEM); 1220dce208b5SSvyatoslav Ryhel if (IS_ERR(node)) { 1221dce208b5SSvyatoslav Ryhel err = PTR_ERR(node); 1222dce208b5SSvyatoslav Ryhel goto remove_nodes; 1223dce208b5SSvyatoslav Ryhel } 1224dce208b5SSvyatoslav Ryhel 1225dce208b5SSvyatoslav Ryhel node->name = "External Memory (DRAM)"; 1226dce208b5SSvyatoslav Ryhel icc_node_add(node, &emc->provider); 1227dce208b5SSvyatoslav Ryhel 1228dce208b5SSvyatoslav Ryhel err = icc_provider_register(&emc->provider); 1229dce208b5SSvyatoslav Ryhel if (err) 1230dce208b5SSvyatoslav Ryhel goto remove_nodes; 1231dce208b5SSvyatoslav Ryhel 1232dce208b5SSvyatoslav Ryhel return 0; 1233dce208b5SSvyatoslav Ryhel 1234dce208b5SSvyatoslav Ryhel remove_nodes: 1235dce208b5SSvyatoslav Ryhel icc_nodes_remove(&emc->provider); 1236dce208b5SSvyatoslav Ryhel 1237*0a783a66SKrzysztof Kozlowski return dev_err_probe(emc->dev, err, "failed to initialize ICC"); 1238dce208b5SSvyatoslav Ryhel } 1239dce208b5SSvyatoslav Ryhel 1240dce208b5SSvyatoslav Ryhel static void devm_tegra114_emc_unset_callback(void *data) 1241dce208b5SSvyatoslav Ryhel { 1242dce208b5SSvyatoslav Ryhel tegra124_clk_set_emc_callbacks(NULL, NULL); 1243dce208b5SSvyatoslav Ryhel } 1244dce208b5SSvyatoslav Ryhel 1245dce208b5SSvyatoslav Ryhel static int tegra114_emc_probe(struct platform_device *pdev) 1246dce208b5SSvyatoslav Ryhel { 1247dce208b5SSvyatoslav Ryhel struct tegra_core_opp_params opp_params = {}; 1248dce208b5SSvyatoslav Ryhel struct device *dev = &pdev->dev; 1249dce208b5SSvyatoslav Ryhel struct device_node *np; 1250dce208b5SSvyatoslav Ryhel struct tegra_emc *emc; 1251dce208b5SSvyatoslav Ryhel u32 ram_code; 1252dce208b5SSvyatoslav Ryhel int err; 1253dce208b5SSvyatoslav Ryhel 1254dce208b5SSvyatoslav Ryhel emc = devm_kzalloc(dev, sizeof(*emc), GFP_KERNEL); 1255dce208b5SSvyatoslav Ryhel if (!emc) 1256dce208b5SSvyatoslav Ryhel return -ENOMEM; 1257dce208b5SSvyatoslav Ryhel 1258dce208b5SSvyatoslav Ryhel emc->dev = dev; 1259dce208b5SSvyatoslav Ryhel 1260dce208b5SSvyatoslav Ryhel emc->regs = devm_platform_ioremap_resource(pdev, 0); 1261dce208b5SSvyatoslav Ryhel if (IS_ERR(emc->regs)) 1262dce208b5SSvyatoslav Ryhel return PTR_ERR(emc->regs); 1263dce208b5SSvyatoslav Ryhel 1264dce208b5SSvyatoslav Ryhel emc->mc = devm_tegra_memory_controller_get(dev); 1265dce208b5SSvyatoslav Ryhel if (IS_ERR(emc->mc)) 1266dce208b5SSvyatoslav Ryhel return PTR_ERR(emc->mc); 1267dce208b5SSvyatoslav Ryhel 1268dce208b5SSvyatoslav Ryhel ram_code = tegra_read_ram_code(); 1269dce208b5SSvyatoslav Ryhel 1270dce208b5SSvyatoslav Ryhel np = tegra114_emc_find_node_by_ram_code(dev->of_node, ram_code); 1271dce208b5SSvyatoslav Ryhel if (np) { 1272dce208b5SSvyatoslav Ryhel err = tegra114_emc_load_timings_from_dt(emc, np); 1273dce208b5SSvyatoslav Ryhel of_node_put(np); 1274dce208b5SSvyatoslav Ryhel if (err) 1275dce208b5SSvyatoslav Ryhel return err; 1276dce208b5SSvyatoslav Ryhel } else { 1277dce208b5SSvyatoslav Ryhel dev_info_once(dev, "no memory timings for RAM code %u found in DT\n", 1278dce208b5SSvyatoslav Ryhel ram_code); 1279dce208b5SSvyatoslav Ryhel } 1280dce208b5SSvyatoslav Ryhel 1281dce208b5SSvyatoslav Ryhel emc_init(emc); 1282dce208b5SSvyatoslav Ryhel 1283dce208b5SSvyatoslav Ryhel platform_set_drvdata(pdev, emc); 1284dce208b5SSvyatoslav Ryhel 1285dce208b5SSvyatoslav Ryhel tegra124_clk_set_emc_callbacks(tegra114_emc_prepare_timing_change, 1286dce208b5SSvyatoslav Ryhel tegra114_emc_complete_timing_change); 1287dce208b5SSvyatoslav Ryhel 1288dce208b5SSvyatoslav Ryhel err = devm_add_action_or_reset(dev, devm_tegra114_emc_unset_callback, 1289dce208b5SSvyatoslav Ryhel NULL); 1290dce208b5SSvyatoslav Ryhel if (err) 1291dce208b5SSvyatoslav Ryhel return err; 1292dce208b5SSvyatoslav Ryhel 1293dce208b5SSvyatoslav Ryhel err = platform_get_irq(pdev, 0); 1294dce208b5SSvyatoslav Ryhel if (err < 0) 1295dce208b5SSvyatoslav Ryhel return err; 1296dce208b5SSvyatoslav Ryhel 1297dce208b5SSvyatoslav Ryhel emc->irq = err; 1298dce208b5SSvyatoslav Ryhel 1299dce208b5SSvyatoslav Ryhel err = devm_request_irq(dev, emc->irq, tegra114_emc_isr, 0, 1300dce208b5SSvyatoslav Ryhel dev_name(dev), emc); 1301dce208b5SSvyatoslav Ryhel if (err) 1302dce208b5SSvyatoslav Ryhel return dev_err_probe(dev, err, "failed to request irq\n"); 1303dce208b5SSvyatoslav Ryhel 1304dce208b5SSvyatoslav Ryhel emc->clk = devm_clk_get(dev, "emc"); 1305dce208b5SSvyatoslav Ryhel if (IS_ERR(emc->clk)) 1306dce208b5SSvyatoslav Ryhel return dev_err_probe(dev, PTR_ERR(emc->clk), 1307dce208b5SSvyatoslav Ryhel "failed to get EMC clock\n"); 1308dce208b5SSvyatoslav Ryhel 1309dce208b5SSvyatoslav Ryhel opp_params.init_state = true; 1310dce208b5SSvyatoslav Ryhel 1311dce208b5SSvyatoslav Ryhel err = devm_tegra_core_dev_init_opp_table(dev, &opp_params); 1312dce208b5SSvyatoslav Ryhel if (err) 1313dce208b5SSvyatoslav Ryhel return err; 1314dce208b5SSvyatoslav Ryhel 1315dce208b5SSvyatoslav Ryhel tegra_emc_rate_requests_init(&emc->reqs, dev); 1316dce208b5SSvyatoslav Ryhel 1317dce208b5SSvyatoslav Ryhel if (IS_ENABLED(CONFIG_DEBUG_FS)) 1318dce208b5SSvyatoslav Ryhel emc_debugfs_init(dev, emc); 1319dce208b5SSvyatoslav Ryhel 1320dce208b5SSvyatoslav Ryhel tegra114_emc_interconnect_init(emc); 1321dce208b5SSvyatoslav Ryhel 1322dce208b5SSvyatoslav Ryhel /* 1323dce208b5SSvyatoslav Ryhel * Don't allow the kernel module to be unloaded. Unloading adds some 1324dce208b5SSvyatoslav Ryhel * extra complexity which doesn't really worth the effort in a case of 1325dce208b5SSvyatoslav Ryhel * this driver. 1326dce208b5SSvyatoslav Ryhel */ 1327dce208b5SSvyatoslav Ryhel try_module_get(THIS_MODULE); 1328dce208b5SSvyatoslav Ryhel 1329dce208b5SSvyatoslav Ryhel return 0; 1330dce208b5SSvyatoslav Ryhel }; 1331dce208b5SSvyatoslav Ryhel 1332dce208b5SSvyatoslav Ryhel static const struct of_device_id tegra114_emc_of_match[] = { 1333dce208b5SSvyatoslav Ryhel { .compatible = "nvidia,tegra114-emc" }, 1334dce208b5SSvyatoslav Ryhel { } 1335dce208b5SSvyatoslav Ryhel }; 1336dce208b5SSvyatoslav Ryhel MODULE_DEVICE_TABLE(of, tegra114_emc_of_match); 1337dce208b5SSvyatoslav Ryhel 1338dce208b5SSvyatoslav Ryhel static struct platform_driver tegra114_emc_driver = { 1339dce208b5SSvyatoslav Ryhel .probe = tegra114_emc_probe, 1340dce208b5SSvyatoslav Ryhel .driver = { 1341dce208b5SSvyatoslav Ryhel .name = "tegra114-emc", 1342dce208b5SSvyatoslav Ryhel .of_match_table = tegra114_emc_of_match, 1343dce208b5SSvyatoslav Ryhel .suppress_bind_attrs = true, 1344dce208b5SSvyatoslav Ryhel .sync_state = icc_sync_state, 1345dce208b5SSvyatoslav Ryhel }, 1346dce208b5SSvyatoslav Ryhel }; 1347dce208b5SSvyatoslav Ryhel module_platform_driver(tegra114_emc_driver); 1348dce208b5SSvyatoslav Ryhel 1349dce208b5SSvyatoslav Ryhel MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); 1350dce208b5SSvyatoslav Ryhel MODULE_DESCRIPTION("NVIDIA Tegra114 EMC driver"); 1351dce208b5SSvyatoslav Ryhel MODULE_LICENSE("GPL"); 1352