From 123cc68c33ff537748a244f4932640083b4b6825 Mon Sep 17 00:00:00 2001 From: James Thomas Date: Wed, 30 Jul 2014 11:16:45 +0100 Subject: Upgrade to Tegra R19 --- arch/arm/boot/dts/tegra124-pm375.dts | 9 +- arch/arm/configs/tegra12_defconfig | 3 +- arch/arm/mach-tegra/Kconfig | 7 + arch/arm/mach-tegra/board-ardbeg-memory.c | 410 +++--- arch/arm/mach-tegra/board-ardbeg-sdhci.c | 29 +- arch/arm/mach-tegra/board-ardbeg.c | 26 +- arch/arm/mach-tegra/board-dalmore.c | 9 +- arch/arm/mach-tegra/board-laguna-power.c | 3 +- arch/arm/mach-tegra/board-loki-sdhci.c | 14 +- arch/arm/mach-tegra/board-loki.c | 9 +- arch/arm/mach-tegra/board-macallan.c | 9 +- arch/arm/mach-tegra/board-pismo.c | 9 +- arch/arm/mach-tegra/board-pluto.c | 8 +- arch/arm/mach-tegra/board-roth.c | 9 +- arch/arm/mach-tegra/board-vcm30_t124.c | 6 - arch/arm/mach-tegra/board.h | 9 +- arch/arm/mach-tegra/clock.c | 38 + arch/arm/mach-tegra/common.c | 74 +- arch/arm/mach-tegra/dvfs.c | 73 + arch/arm/mach-tegra/dvfs.h | 1 - arch/arm/mach-tegra/pm.c | 2 +- arch/arm/mach-tegra/powergate-t12x.c | 18 +- arch/arm/mach-tegra/tegra12_clocks.c | 226 ++++ arch/arm/mach-tegra/tegra12_dvfs.c | 83 +- arch/arm/mach-tegra/tegra12_edp.c | 4 + arch/arm/mach-tegra/tegra12_speedo.c | 2 +- drivers/cpufreq/cpufreq_governor.c | 7 + drivers/misc/tegra-fuse/tegra_fuse.c | 1 + drivers/mmc/host/sdhci-tegra.c | 1732 +++++++++++++++++------- drivers/pci/host/pci-tegra.c | 2 + drivers/tty/serial/8250/8250_core.c | 21 + drivers/tty/serial/of_serial.c | 22 - drivers/usb/phy/tegra11x_usb_phy.c | 4 +- drivers/video/tegra/dc/bandwidth.c | 8 +- drivers/video/tegra/dc/dc_reg.h | 12 +- drivers/video/tegra/dc/hdmi_state_machine.c | 2 +- drivers/video/tegra/host/gk20a/channel_gk20a.c | 33 +- drivers/video/tegra/host/gk20a/gr_gk20a.c | 18 +- drivers/video/tegra/host/msenc/msenc.c | 2 +- drivers/video/tegra/host/tsec/tsec.c | 2 +- drivers/video/tegra/host/vic03/vic03.c | 2 +- fs/eventpoll.c | 6 +- include/linux/clk/tegra.h | 2 + include/linux/platform_data/mmc-sdhci-tegra.h | 4 +- include/linux/serial_8250.h | 7 + sound/soc/codecs/max98090.c | 25 +- sound/soc/tegra/tegra30_ahub.c | 16 +- 47 files changed, 2034 insertions(+), 984 deletions(-) diff --git a/arch/arm/boot/dts/tegra124-pm375.dts b/arch/arm/boot/dts/tegra124-pm375.dts index 43dbf9231186..83f314cd3563 100644 --- a/arch/arm/boot/dts/tegra124-pm375.dts +++ b/arch/arm/boot/dts/tegra124-pm375.dts @@ -7,15 +7,13 @@ / { model = "NVIDIA Tegra124 PM375"; - compatible = "nvidia,jetson-tk1", "nvidia,laguna", "nvidia,tegra124"; + compatible = "nvidia,jetson-tk1", "nvidia,tegra124"; nvidia,dtsfilename = __FILE__; #address-cells = <1>; #size-cells = <1>; chosen { bootargs = "tegraid=40.0.0.00.00 vmalloc=256M video=tegrafb console=ttyS0,115200n8 earlyprintk"; - linux,initrd-start = <0x85000000>; - linux,initrd-end = <0x851bc400>; }; pinmux { @@ -107,10 +105,11 @@ status = "okay"; nvidia,invert-interrupt; nvidia,suspend-mode = <0>; - nvidia,cpu-pwr-good-time = <2000>; - nvidia,cpu-pwr-off-time = <2000>; + nvidia,cpu-pwr-good-time = <500>; + nvidia,cpu-pwr-off-time = <300>; nvidia,core-pwr-good-time = <3845 3845>; nvidia,core-pwr-off-time = <2000>; + nvidia,lp0-vec = <0xf46ff000 2064>; nvidia,core-power-req-active-high; nvidia,sys-clock-req-active-high; }; diff --git a/arch/arm/configs/tegra12_defconfig b/arch/arm/configs/tegra12_defconfig index a2bafc4cf2d9..9dfa0c29eeff 100644 --- a/arch/arm/configs/tegra12_defconfig +++ b/arch/arm/configs/tegra12_defconfig @@ -31,6 +31,7 @@ CONFIG_MACH_LOKI=y CONFIG_MACH_LAGUNA=y CONFIG_TEGRA_EMC_SCALING_ENABLE=y CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y +CONFIG_TEGRA_PREINIT_CLOCKS=y CONFIG_TEGRA_EDP_LIMITS=y CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ=1400 CONFIG_TEGRA_DYNAMIC_PWRDET=y @@ -186,7 +187,6 @@ CONFIG_THERM_EST=y CONFIG_FAN_THERM_EST=y CONFIG_EEPROM_AT24=y CONFIG_TEGRA_BB_SUPPORT=y -CONFIG_TEGRA_USB_MODEM_POWER=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y @@ -444,7 +444,6 @@ CONFIG_USB_SERIAL=y CONFIG_USB_SERIAL_PL2303=y CONFIG_USB_SERIAL_OPTION=y CONFIG_USB_SERIAL_BASEBAND=m -CONFIG_USB_RENESAS_MODEM=y CONFIG_USB_TEGRA_OTG=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 53e9b66e45ae..cc9913b6264b 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -753,6 +753,13 @@ config TEGRA_SLOW_CSITE When enabled, csite will be running at 1 Mhz and the performance of jtag, lauterbach and other debugger will be extremely slow. +config TEGRA_PREINIT_CLOCKS + bool "Preinitialize Tegra clocks to known states" + default n + help + Preinitialize Tegra clocks to known states before actual full- + scale clock initialization starts. + config TEGRA_PREPOWER_WIFI bool "Pre-power up WiFi " default n diff --git a/arch/arm/mach-tegra/board-ardbeg-memory.c b/arch/arm/mach-tegra/board-ardbeg-memory.c index eae25e79cebf..99f04e2657ff 100644 --- a/arch/arm/mach-tegra/board-ardbeg-memory.c +++ b/arch/arm/mach-tegra/board-ardbeg-memory.c @@ -11523,8 +11523,8 @@ static struct tegra12_emc_table ardbeg_lpddr3_emc_table_E1781[] = { static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { { - 0x19, /* V5.0.14 */ - "04_12750_03_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_12750_01_V5.0.17_V1.1", /* DVFS table version */ 12750, /* SDRAM frequency */ 800, /* min voltage */ 800, /* gpu min voltage */ @@ -11540,7 +11540,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* EMC_RP */ 0x00000004, /* EMC_R2W */ 0x0000000a, /* EMC_W2R */ - 0x00000003, /* EMC_R2P */ + 0x00000005, /* EMC_R2P */ 0x0000000b, /* EMC_W2P */ 0x00000000, /* EMC_RD_RCD */ 0x00000000, /* EMC_WR_RCD */ @@ -11589,22 +11589,22 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x106aa298, /* EMC_FBIO_CFG5 */ 0x002c00a0, /* EMC_CFG_DIG_DLL */ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ - 0x00064000, /* EMC_DLL_XFORM_DQS0 */ - 0x00064000, /* EMC_DLL_XFORM_DQS1 */ - 0x00064000, /* EMC_DLL_XFORM_DQS2 */ - 0x00064000, /* EMC_DLL_XFORM_DQS3 */ - 0x00064000, /* EMC_DLL_XFORM_DQS4 */ - 0x00064000, /* EMC_DLL_XFORM_DQS5 */ - 0x00064000, /* EMC_DLL_XFORM_DQS6 */ - 0x00064000, /* EMC_DLL_XFORM_DQS7 */ - 0x00064000, /* EMC_DLL_XFORM_DQS8 */ - 0x00064000, /* EMC_DLL_XFORM_DQS9 */ - 0x00064000, /* EMC_DLL_XFORM_DQS10 */ - 0x00064000, /* EMC_DLL_XFORM_DQS11 */ - 0x00064000, /* EMC_DLL_XFORM_DQS12 */ - 0x00064000, /* EMC_DLL_XFORM_DQS13 */ - 0x00064000, /* EMC_DLL_XFORM_DQS14 */ - 0x00064000, /* EMC_DLL_XFORM_DQS15 */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQS8 */ + 0x00080000, /* EMC_DLL_XFORM_DQS9 */ + 0x00080000, /* EMC_DLL_XFORM_DQS10 */ + 0x00080000, /* EMC_DLL_XFORM_DQS11 */ + 0x00080000, /* EMC_DLL_XFORM_DQS12 */ + 0x00080000, /* EMC_DLL_XFORM_DQS13 */ + 0x00080000, /* EMC_DLL_XFORM_DQS14 */ + 0x00080000, /* EMC_DLL_XFORM_DQS15 */ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ @@ -11687,14 +11687,14 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ 0x00000002, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ - 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2R */ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ 0x06030203, /* MC_EMEM_ARB_DA_TURNS */ - 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */ + 0x000a0502, /* MC_EMEM_ARB_DA_COVERS */ 0x77e30303, /* MC_EMEM_ARB_MISC0 */ 0x70000f03, /* MC_EMEM_ARB_MISC1 */ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ @@ -11750,8 +11750,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 57820, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_20400_03_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_20400_01_V5.0.17_V1.1", /* DVFS table version */ 20400, /* SDRAM frequency */ 800, /* min voltage */ 800, /* gpu min voltage */ @@ -11767,7 +11767,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* EMC_RP */ 0x00000004, /* EMC_R2W */ 0x0000000a, /* EMC_W2R */ - 0x00000003, /* EMC_R2P */ + 0x00000005, /* EMC_R2P */ 0x0000000b, /* EMC_W2P */ 0x00000000, /* EMC_RD_RCD */ 0x00000000, /* EMC_WR_RCD */ @@ -11816,22 +11816,22 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x106aa298, /* EMC_FBIO_CFG5 */ 0x002c00a0, /* EMC_CFG_DIG_DLL */ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ - 0x00064000, /* EMC_DLL_XFORM_DQS0 */ - 0x00064000, /* EMC_DLL_XFORM_DQS1 */ - 0x00064000, /* EMC_DLL_XFORM_DQS2 */ - 0x00064000, /* EMC_DLL_XFORM_DQS3 */ - 0x00064000, /* EMC_DLL_XFORM_DQS4 */ - 0x00064000, /* EMC_DLL_XFORM_DQS5 */ - 0x00064000, /* EMC_DLL_XFORM_DQS6 */ - 0x00064000, /* EMC_DLL_XFORM_DQS7 */ - 0x00064000, /* EMC_DLL_XFORM_DQS8 */ - 0x00064000, /* EMC_DLL_XFORM_DQS9 */ - 0x00064000, /* EMC_DLL_XFORM_DQS10 */ - 0x00064000, /* EMC_DLL_XFORM_DQS11 */ - 0x00064000, /* EMC_DLL_XFORM_DQS12 */ - 0x00064000, /* EMC_DLL_XFORM_DQS13 */ - 0x00064000, /* EMC_DLL_XFORM_DQS14 */ - 0x00064000, /* EMC_DLL_XFORM_DQS15 */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQS8 */ + 0x00080000, /* EMC_DLL_XFORM_DQS9 */ + 0x00080000, /* EMC_DLL_XFORM_DQS10 */ + 0x00080000, /* EMC_DLL_XFORM_DQS11 */ + 0x00080000, /* EMC_DLL_XFORM_DQS12 */ + 0x00080000, /* EMC_DLL_XFORM_DQS13 */ + 0x00080000, /* EMC_DLL_XFORM_DQS14 */ + 0x00080000, /* EMC_DLL_XFORM_DQS15 */ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ @@ -11914,14 +11914,14 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ 0x00000002, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ - 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2R */ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ 0x06030203, /* MC_EMEM_ARB_DA_TURNS */ - 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */ + 0x000a0502, /* MC_EMEM_ARB_DA_COVERS */ 0x76230303, /* MC_EMEM_ARB_MISC0 */ 0x70000f03, /* MC_EMEM_ARB_MISC1 */ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ @@ -11977,8 +11977,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 35610, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_40800_03_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_40800_01_V5.0.17_V1.1", /* DVFS table version */ 40800, /* SDRAM frequency */ 800, /* min voltage */ 800, /* gpu min voltage */ @@ -11994,7 +11994,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* EMC_RP */ 0x00000004, /* EMC_R2W */ 0x0000000a, /* EMC_W2R */ - 0x00000003, /* EMC_R2P */ + 0x00000005, /* EMC_R2P */ 0x0000000b, /* EMC_W2P */ 0x00000000, /* EMC_RD_RCD */ 0x00000000, /* EMC_WR_RCD */ @@ -12043,22 +12043,22 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x106aa298, /* EMC_FBIO_CFG5 */ 0x002c00a0, /* EMC_CFG_DIG_DLL */ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ - 0x00064000, /* EMC_DLL_XFORM_DQS0 */ - 0x00064000, /* EMC_DLL_XFORM_DQS1 */ - 0x00064000, /* EMC_DLL_XFORM_DQS2 */ - 0x00064000, /* EMC_DLL_XFORM_DQS3 */ - 0x00064000, /* EMC_DLL_XFORM_DQS4 */ - 0x00064000, /* EMC_DLL_XFORM_DQS5 */ - 0x00064000, /* EMC_DLL_XFORM_DQS6 */ - 0x00064000, /* EMC_DLL_XFORM_DQS7 */ - 0x00064000, /* EMC_DLL_XFORM_DQS8 */ - 0x00064000, /* EMC_DLL_XFORM_DQS9 */ - 0x00064000, /* EMC_DLL_XFORM_DQS10 */ - 0x00064000, /* EMC_DLL_XFORM_DQS11 */ - 0x00064000, /* EMC_DLL_XFORM_DQS12 */ - 0x00064000, /* EMC_DLL_XFORM_DQS13 */ - 0x00064000, /* EMC_DLL_XFORM_DQS14 */ - 0x00064000, /* EMC_DLL_XFORM_DQS15 */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQS8 */ + 0x00080000, /* EMC_DLL_XFORM_DQS9 */ + 0x00080000, /* EMC_DLL_XFORM_DQS10 */ + 0x00080000, /* EMC_DLL_XFORM_DQS11 */ + 0x00080000, /* EMC_DLL_XFORM_DQS12 */ + 0x00080000, /* EMC_DLL_XFORM_DQS13 */ + 0x00080000, /* EMC_DLL_XFORM_DQS14 */ + 0x00080000, /* EMC_DLL_XFORM_DQS15 */ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ @@ -12141,14 +12141,14 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ 0x00000002, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ - 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2R */ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ 0x06030203, /* MC_EMEM_ARB_DA_TURNS */ - 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */ + 0x000a0502, /* MC_EMEM_ARB_DA_COVERS */ 0x74a30303, /* MC_EMEM_ARB_MISC0 */ 0x70000f03, /* MC_EMEM_ARB_MISC1 */ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ @@ -12204,8 +12204,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 20850, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_68000_03_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_68000_01_V5.0.17_V1.1", /* DVFS table version */ 68000, /* SDRAM frequency */ 800, /* min voltage */ 800, /* gpu min voltage */ @@ -12221,7 +12221,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* EMC_RP */ 0x00000004, /* EMC_R2W */ 0x0000000a, /* EMC_W2R */ - 0x00000003, /* EMC_R2P */ + 0x00000005, /* EMC_R2P */ 0x0000000b, /* EMC_W2P */ 0x00000000, /* EMC_RD_RCD */ 0x00000000, /* EMC_WR_RCD */ @@ -12270,22 +12270,22 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x106aa298, /* EMC_FBIO_CFG5 */ 0x002c00a0, /* EMC_CFG_DIG_DLL */ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ - 0x00064000, /* EMC_DLL_XFORM_DQS0 */ - 0x00064000, /* EMC_DLL_XFORM_DQS1 */ - 0x00064000, /* EMC_DLL_XFORM_DQS2 */ - 0x00064000, /* EMC_DLL_XFORM_DQS3 */ - 0x00064000, /* EMC_DLL_XFORM_DQS4 */ - 0x00064000, /* EMC_DLL_XFORM_DQS5 */ - 0x00064000, /* EMC_DLL_XFORM_DQS6 */ - 0x00064000, /* EMC_DLL_XFORM_DQS7 */ - 0x00064000, /* EMC_DLL_XFORM_DQS8 */ - 0x00064000, /* EMC_DLL_XFORM_DQS9 */ - 0x00064000, /* EMC_DLL_XFORM_DQS10 */ - 0x00064000, /* EMC_DLL_XFORM_DQS11 */ - 0x00064000, /* EMC_DLL_XFORM_DQS12 */ - 0x00064000, /* EMC_DLL_XFORM_DQS13 */ - 0x00064000, /* EMC_DLL_XFORM_DQS14 */ - 0x00064000, /* EMC_DLL_XFORM_DQS15 */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQS8 */ + 0x00080000, /* EMC_DLL_XFORM_DQS9 */ + 0x00080000, /* EMC_DLL_XFORM_DQS10 */ + 0x00080000, /* EMC_DLL_XFORM_DQS11 */ + 0x00080000, /* EMC_DLL_XFORM_DQS12 */ + 0x00080000, /* EMC_DLL_XFORM_DQS13 */ + 0x00080000, /* EMC_DLL_XFORM_DQS14 */ + 0x00080000, /* EMC_DLL_XFORM_DQS15 */ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ @@ -12368,14 +12368,14 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ 0x00000002, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ - 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2R */ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ 0x06030203, /* MC_EMEM_ARB_DA_TURNS */ - 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */ + 0x000a0502, /* MC_EMEM_ARB_DA_COVERS */ 0x74230403, /* MC_EMEM_ARB_MISC0 */ 0x70000f03, /* MC_EMEM_ARB_MISC1 */ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ @@ -12431,8 +12431,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 10720, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_102000_03_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_102000_01_V5.0.17_V1.1", /* DVFS table version */ 102000, /* SDRAM frequency */ 800, /* min voltage */ 800, /* gpu min voltage */ @@ -12448,7 +12448,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000001, /* EMC_RP */ 0x00000004, /* EMC_R2W */ 0x0000000a, /* EMC_W2R */ - 0x00000003, /* EMC_R2P */ + 0x00000005, /* EMC_R2P */ 0x0000000b, /* EMC_W2P */ 0x00000001, /* EMC_RD_RCD */ 0x00000001, /* EMC_WR_RCD */ @@ -12486,7 +12486,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000004, /* EMC_TCKE */ 0x00000005, /* EMC_TCKESR */ 0x00000004, /* EMC_TPD */ - 0x00000003, /* EMC_TFAW */ + 0x00000002, /* EMC_TFAW */ 0x00000000, /* EMC_TRPAB */ 0x00000005, /* EMC_TCLKSTABLE */ 0x00000005, /* EMC_TCLKSTOP */ @@ -12497,22 +12497,22 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x106aa298, /* EMC_FBIO_CFG5 */ 0x002c00a0, /* EMC_CFG_DIG_DLL */ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ - 0x00064000, /* EMC_DLL_XFORM_DQS0 */ - 0x00064000, /* EMC_DLL_XFORM_DQS1 */ - 0x00064000, /* EMC_DLL_XFORM_DQS2 */ - 0x00064000, /* EMC_DLL_XFORM_DQS3 */ - 0x00064000, /* EMC_DLL_XFORM_DQS4 */ - 0x00064000, /* EMC_DLL_XFORM_DQS5 */ - 0x00064000, /* EMC_DLL_XFORM_DQS6 */ - 0x00064000, /* EMC_DLL_XFORM_DQS7 */ - 0x00064000, /* EMC_DLL_XFORM_DQS8 */ - 0x00064000, /* EMC_DLL_XFORM_DQS9 */ - 0x00064000, /* EMC_DLL_XFORM_DQS10 */ - 0x00064000, /* EMC_DLL_XFORM_DQS11 */ - 0x00064000, /* EMC_DLL_XFORM_DQS12 */ - 0x00064000, /* EMC_DLL_XFORM_DQS13 */ - 0x00064000, /* EMC_DLL_XFORM_DQS14 */ - 0x00064000, /* EMC_DLL_XFORM_DQS15 */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQS8 */ + 0x00080000, /* EMC_DLL_XFORM_DQS9 */ + 0x00080000, /* EMC_DLL_XFORM_DQS10 */ + 0x00080000, /* EMC_DLL_XFORM_DQS11 */ + 0x00080000, /* EMC_DLL_XFORM_DQS12 */ + 0x00080000, /* EMC_DLL_XFORM_DQS13 */ + 0x00080000, /* EMC_DLL_XFORM_DQS14 */ + 0x00080000, /* EMC_DLL_XFORM_DQS15 */ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ @@ -12595,14 +12595,14 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */ 0x00000002, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ - 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2R */ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ 0x06030203, /* MC_EMEM_ARB_DA_TURNS */ - 0x000a0403, /* MC_EMEM_ARB_DA_COVERS */ + 0x000a0503, /* MC_EMEM_ARB_DA_COVERS */ 0x73c30504, /* MC_EMEM_ARB_MISC0 */ 0x70000f03, /* MC_EMEM_ARB_MISC1 */ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ @@ -12658,8 +12658,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 6890, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_204000_04_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_204000_01_V5.0.17_V1.1", /* DVFS table version */ 204000, /* SDRAM frequency */ 800, /* min voltage */ 800, /* gpu min voltage */ @@ -12675,7 +12675,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000002, /* EMC_RP */ 0x00000005, /* EMC_R2W */ 0x0000000a, /* EMC_W2R */ - 0x00000003, /* EMC_R2P */ + 0x00000005, /* EMC_R2P */ 0x0000000b, /* EMC_W2P */ 0x00000002, /* EMC_RD_RCD */ 0x00000002, /* EMC_WR_RCD */ @@ -12713,7 +12713,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000004, /* EMC_TCKE */ 0x00000005, /* EMC_TCKESR */ 0x00000004, /* EMC_TPD */ - 0x00000007, /* EMC_TFAW */ + 0x00000006, /* EMC_TFAW */ 0x00000000, /* EMC_TRPAB */ 0x00000005, /* EMC_TCLKSTABLE */ 0x00000005, /* EMC_TCLKSTOP */ @@ -12724,22 +12724,22 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x106aa298, /* EMC_FBIO_CFG5 */ 0x002c00a0, /* EMC_CFG_DIG_DLL */ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ - 0x00064000, /* EMC_DLL_XFORM_DQS0 */ - 0x00064000, /* EMC_DLL_XFORM_DQS1 */ - 0x00064000, /* EMC_DLL_XFORM_DQS2 */ - 0x00064000, /* EMC_DLL_XFORM_DQS3 */ - 0x00064000, /* EMC_DLL_XFORM_DQS4 */ - 0x00064000, /* EMC_DLL_XFORM_DQS5 */ - 0x00064000, /* EMC_DLL_XFORM_DQS6 */ - 0x00064000, /* EMC_DLL_XFORM_DQS7 */ - 0x00064000, /* EMC_DLL_XFORM_DQS8 */ - 0x00064000, /* EMC_DLL_XFORM_DQS9 */ - 0x00064000, /* EMC_DLL_XFORM_DQS10 */ - 0x00064000, /* EMC_DLL_XFORM_DQS11 */ - 0x00064000, /* EMC_DLL_XFORM_DQS12 */ - 0x00064000, /* EMC_DLL_XFORM_DQS13 */ - 0x00064000, /* EMC_DLL_XFORM_DQS14 */ - 0x00064000, /* EMC_DLL_XFORM_DQS15 */ + 0x00080000, /* EMC_DLL_XFORM_DQS0 */ + 0x00080000, /* EMC_DLL_XFORM_DQS1 */ + 0x00080000, /* EMC_DLL_XFORM_DQS2 */ + 0x00080000, /* EMC_DLL_XFORM_DQS3 */ + 0x00080000, /* EMC_DLL_XFORM_DQS4 */ + 0x00080000, /* EMC_DLL_XFORM_DQS5 */ + 0x00080000, /* EMC_DLL_XFORM_DQS6 */ + 0x00080000, /* EMC_DLL_XFORM_DQS7 */ + 0x00080000, /* EMC_DLL_XFORM_DQS8 */ + 0x00080000, /* EMC_DLL_XFORM_DQS9 */ + 0x00080000, /* EMC_DLL_XFORM_DQS10 */ + 0x00080000, /* EMC_DLL_XFORM_DQS11 */ + 0x00080000, /* EMC_DLL_XFORM_DQS12 */ + 0x00080000, /* EMC_DLL_XFORM_DQS13 */ + 0x00080000, /* EMC_DLL_XFORM_DQS14 */ + 0x00080000, /* EMC_DLL_XFORM_DQS15 */ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ @@ -12820,16 +12820,16 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000001, /* MC_EMEM_ARB_TIMING_RP */ 0x00000004, /* MC_EMEM_ARB_TIMING_RC */ 0x00000002, /* MC_EMEM_ARB_TIMING_RAS */ - 0x00000004, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ - 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ 0x00000003, /* MC_EMEM_ARB_TIMING_R2R */ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */ 0x06040203, /* MC_EMEM_ARB_DA_TURNS */ - 0x000a0404, /* MC_EMEM_ARB_DA_COVERS */ + 0x000a0504, /* MC_EMEM_ARB_DA_COVERS */ 0x73840a05, /* MC_EMEM_ARB_MISC0 */ 0x70000f03, /* MC_EMEM_ARB_MISC1 */ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */ @@ -12871,8 +12871,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */ 0x00000802, /* EMC_CTT_TERM_CTRL */ 0x73240000, /* EMC_CFG */ - 0x0000088d, /* EMC_CFG_2 */ - 0x00040008, /* EMC_SEL_DPD_CTRL */ + 0x000008cd, /* EMC_CFG_2 */ + 0x00040128, /* EMC_SEL_DPD_CTRL */ 0x002c0068, /* EMC_CFG_DIG_DLL */ 0x00000008, /* EMC_BGBIAS_CTL0 */ 0x00000000, /* EMC_AUTO_CAL_CONFIG2 */ @@ -12885,8 +12885,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 3420, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_300000_04_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_300000_01_V5.0.17_V1.1", /* DVFS table version */ 300000, /* SDRAM frequency */ 820, /* min voltage */ 820, /* gpu min voltage */ @@ -12940,7 +12940,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000004, /* EMC_TCKE */ 0x00000005, /* EMC_TCKESR */ 0x00000004, /* EMC_TPD */ - 0x00000009, /* EMC_TFAW */ + 0x00000008, /* EMC_TFAW */ 0x00000000, /* EMC_TRPAB */ 0x00000005, /* EMC_TCLKSTABLE */ 0x00000005, /* EMC_TCLKSTOP */ @@ -13005,14 +13005,14 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* EMC_DLI_TRIM_TXDQS13 */ 0x00000000, /* EMC_DLI_TRIM_TXDQS14 */ 0x00000000, /* EMC_DLI_TRIM_TXDQS15 */ - 0x00060000, /* EMC_DLL_XFORM_DQ0 */ - 0x00060000, /* EMC_DLL_XFORM_DQ1 */ - 0x00060000, /* EMC_DLL_XFORM_DQ2 */ - 0x00060000, /* EMC_DLL_XFORM_DQ3 */ - 0x00006000, /* EMC_DLL_XFORM_DQ4 */ - 0x00006000, /* EMC_DLL_XFORM_DQ5 */ - 0x00006000, /* EMC_DLL_XFORM_DQ6 */ - 0x00006000, /* EMC_DLL_XFORM_DQ7 */ + 0x00050000, /* EMC_DLL_XFORM_DQ0 */ + 0x00050000, /* EMC_DLL_XFORM_DQ1 */ + 0x00050000, /* EMC_DLL_XFORM_DQ2 */ + 0x00050000, /* EMC_DLL_XFORM_DQ3 */ + 0x00005000, /* EMC_DLL_XFORM_DQ4 */ + 0x00005000, /* EMC_DLL_XFORM_DQ5 */ + 0x00005000, /* EMC_DLL_XFORM_DQ6 */ + 0x00005000, /* EMC_DLL_XFORM_DQ7 */ 0x10000280, /* EMC_XM2CMDPADCTRL */ 0x00000000, /* EMC_XM2CMDPADCTRL4 */ 0x00111111, /* EMC_XM2CMDPADCTRL5 */ @@ -13047,7 +13047,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000002, /* MC_EMEM_ARB_TIMING_RP */ 0x00000007, /* MC_EMEM_ARB_TIMING_RC */ 0x00000004, /* MC_EMEM_ARB_TIMING_RAS */ - 0x00000005, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000004, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000007, /* MC_EMEM_ARB_TIMING_WAP2PRE */ @@ -13112,8 +13112,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 2680, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_396000_05_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_396000_01_V5.0.17_V1.1", /* DVFS table version */ 396000, /* SDRAM frequency */ 850, /* min voltage */ 850, /* gpu min voltage */ @@ -13167,7 +13167,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000004, /* EMC_TCKE */ 0x00000005, /* EMC_TCKESR */ 0x00000004, /* EMC_TPD */ - 0x0000000d, /* EMC_TFAW */ + 0x0000000b, /* EMC_TFAW */ 0x00000000, /* EMC_TRPAB */ 0x00000005, /* EMC_TCLKSTABLE */ 0x00000005, /* EMC_TCLKSTOP */ @@ -13274,7 +13274,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000002, /* MC_EMEM_ARB_TIMING_RP */ 0x00000009, /* MC_EMEM_ARB_TIMING_RC */ 0x00000005, /* MC_EMEM_ARB_TIMING_RAS */ - 0x00000007, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000006, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */ @@ -13339,8 +13339,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 2180, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_528000_05_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_528000_01_V5.0.17_V1.1", /* DVFS table version */ 528000, /* SDRAM frequency */ 880, /* min voltage */ 870, /* gpu min voltage */ @@ -13394,7 +13394,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000004, /* EMC_TCKE */ 0x00000005, /* EMC_TCKESR */ 0x00000004, /* EMC_TPD */ - 0x00000013, /* EMC_TFAW */ + 0x00000010, /* EMC_TFAW */ 0x00000000, /* EMC_TRPAB */ 0x00000006, /* EMC_TCLKSTABLE */ 0x00000006, /* EMC_TCLKSTOP */ @@ -13459,14 +13459,14 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* EMC_DLI_TRIM_TXDQS13 */ 0x00000000, /* EMC_DLI_TRIM_TXDQS14 */ 0x00000000, /* EMC_DLI_TRIM_TXDQS15 */ - 0x0000000e, /* EMC_DLL_XFORM_DQ0 */ - 0x0000000e, /* EMC_DLL_XFORM_DQ1 */ - 0x0000000e, /* EMC_DLL_XFORM_DQ2 */ - 0x0000000e, /* EMC_DLL_XFORM_DQ3 */ - 0x0000000e, /* EMC_DLL_XFORM_DQ4 */ - 0x0000000e, /* EMC_DLL_XFORM_DQ5 */ - 0x0000000e, /* EMC_DLL_XFORM_DQ6 */ - 0x0000000e, /* EMC_DLL_XFORM_DQ7 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ0 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ1 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ2 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ3 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ4 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ5 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ6 */ + 0x0000000c, /* EMC_DLL_XFORM_DQ7 */ 0x100002a0, /* EMC_XM2CMDPADCTRL */ 0x00000000, /* EMC_XM2CMDPADCTRL4 */ 0x00111111, /* EMC_XM2CMDPADCTRL5 */ @@ -13501,7 +13501,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000003, /* MC_EMEM_ARB_TIMING_RP */ 0x0000000c, /* MC_EMEM_ARB_TIMING_RC */ 0x00000007, /* MC_EMEM_ARB_TIMING_RAS */ - 0x0000000a, /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000008, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x00000009, /* MC_EMEM_ARB_TIMING_WAP2PRE */ @@ -13566,8 +13566,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 1440, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_600000_03_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_600000_01_V5.0.17_V1.1", /* DVFS table version */ 600000, /* SDRAM frequency */ 910, /* min voltage */ 910, /* gpu min voltage */ @@ -13621,7 +13621,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000004, /* EMC_TCKE */ 0x00000005, /* EMC_TCKESR */ 0x00000004, /* EMC_TPD */ - 0x00000015, /* EMC_TFAW */ + 0x00000013, /* EMC_TFAW */ 0x00000000, /* EMC_TRPAB */ 0x00000006, /* EMC_TCLKSTABLE */ 0x00000006, /* EMC_TCLKSTOP */ @@ -13720,7 +13720,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* EMC_CTT */ 0x00000003, /* EMC_CTT_DURATION */ 0x000040a0, /* EMC_CFG_PIPE */ - 0x800024a9, /* EMC_DYN_SELF_REF_CONTROL */ + 0x800024aa, /* EMC_DYN_SELF_REF_CONTROL */ 0x0000000e, /* EMC_QPOP */ 0x00000009, /* MC_EMEM_ARB_CFG */ 0x80000040, /* MC_EMEM_ARB_OUTSTANDING_REQ */ @@ -13728,7 +13728,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000004, /* MC_EMEM_ARB_TIMING_RP */ 0x0000000e, /* MC_EMEM_ARB_TIMING_RC */ 0x00000009, /* MC_EMEM_ARB_TIMING_RAS */ - 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */ + 0x0000000a, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x0000000b, /* MC_EMEM_ARB_TIMING_WAP2PRE */ @@ -13793,8 +13793,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 1440, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_792000_06_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_792000_01_V5.0.17_V1.1", /* DVFS table version */ 792000, /* SDRAM frequency */ 980, /* min voltage */ 980, /* gpu min voltage */ @@ -13814,7 +13814,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000013, /* EMC_W2P */ 0x0000000a, /* EMC_RD_RCD */ 0x0000000a, /* EMC_WR_RCD */ - 0x00000003, /* EMC_RRD */ + 0x00000004, /* EMC_RRD */ 0x00000002, /* EMC_REXT */ 0x00000000, /* EMC_WEXT */ 0x00000006, /* EMC_WDV */ @@ -13848,7 +13848,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000005, /* EMC_TCKE */ 0x00000006, /* EMC_TCKESR */ 0x00000005, /* EMC_TPD */ - 0x0000001d, /* EMC_TFAW */ + 0x00000019, /* EMC_TFAW */ 0x00000000, /* EMC_TRPAB */ 0x00000008, /* EMC_TCLKSTABLE */ 0x00000008, /* EMC_TCLKSTOP */ @@ -13859,22 +13859,22 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x104ab098, /* EMC_FBIO_CFG5 */ 0xe00700b1, /* EMC_CFG_DIG_DLL */ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */ - 0x00000008, /* EMC_DLL_XFORM_DQS0 */ - 0x00000008, /* EMC_DLL_XFORM_DQS1 */ - 0x00000008, /* EMC_DLL_XFORM_DQS2 */ - 0x00000008, /* EMC_DLL_XFORM_DQS3 */ - 0x00000008, /* EMC_DLL_XFORM_DQS4 */ - 0x00000008, /* EMC_DLL_XFORM_DQS5 */ - 0x00000008, /* EMC_DLL_XFORM_DQS6 */ - 0x00000008, /* EMC_DLL_XFORM_DQS7 */ - 0x00000008, /* EMC_DLL_XFORM_DQS8 */ - 0x00000008, /* EMC_DLL_XFORM_DQS9 */ - 0x00000008, /* EMC_DLL_XFORM_DQS10 */ - 0x00000008, /* EMC_DLL_XFORM_DQS11 */ - 0x00000008, /* EMC_DLL_XFORM_DQS12 */ - 0x00000008, /* EMC_DLL_XFORM_DQS13 */ - 0x00000008, /* EMC_DLL_XFORM_DQS14 */ - 0x00000008, /* EMC_DLL_XFORM_DQS15 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS0 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS1 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS2 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS3 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS4 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS5 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS6 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS7 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS8 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS9 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS10 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS11 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS12 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS13 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS14 */ + 0x007fc008, /* EMC_DLL_XFORM_DQS15 */ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */ @@ -13955,7 +13955,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000005, /* MC_EMEM_ARB_TIMING_RP */ 0x00000013, /* MC_EMEM_ARB_TIMING_RC */ 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */ - 0x0000000f, /* MC_EMEM_ARB_TIMING_FAW */ + 0x0000000d, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */ @@ -14020,8 +14020,8 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 1200, /* expected dvfs latency (ns) */ }, { - 0x19, /* V5.0.14 */ - "04_924000_06_V5.0.14_V1.1", /* DVFS table version */ + 0x19, /* V5.0.17 */ + "01_924000_01_V5.0.17_V1.1", /* DVFS table version */ 924000, /* SDRAM frequency */ 1010, /* min voltage */ 1010, /* gpu min voltage */ @@ -14075,7 +14075,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000006, /* EMC_TCKE */ 0x00000007, /* EMC_TCKESR */ 0x00000006, /* EMC_TPD */ - 0x00000022, /* EMC_TFAW */ + 0x0000001e, /* EMC_TFAW */ 0x00000000, /* EMC_TRPAB */ 0x0000000a, /* EMC_TCLKSTABLE */ 0x0000000a, /* EMC_TCLKSTOP */ @@ -14124,22 +14124,22 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000000, /* EMC_DLL_XFORM_QUSE13 */ 0x00000000, /* EMC_DLL_XFORM_QUSE14 */ 0x00000000, /* EMC_DLL_XFORM_QUSE15 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS0 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS1 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS2 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS3 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS4 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS5 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS6 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS7 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS8 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS9 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS10 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS11 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS12 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS13 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS14 */ - 0x00000005, /* EMC_DLI_TRIM_TXDQS15 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS7 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS8 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS9 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS10 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS11 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS12 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS13 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS14 */ + 0x00000004, /* EMC_DLI_TRIM_TXDQS15 */ 0x00000008, /* EMC_DLL_XFORM_DQ0 */ 0x00000008, /* EMC_DLL_XFORM_DQ1 */ 0x00000008, /* EMC_DLL_XFORM_DQ2 */ @@ -14182,7 +14182,7 @@ static struct tegra12_emc_table jetson_tk1_ddr3_emc_table[] = { 0x00000006, /* MC_EMEM_ARB_TIMING_RP */ 0x00000016, /* MC_EMEM_ARB_TIMING_RC */ 0x0000000e, /* MC_EMEM_ARB_TIMING_RAS */ - 0x00000011, /* MC_EMEM_ARB_TIMING_FAW */ + 0x0000000f, /* MC_EMEM_ARB_TIMING_FAW */ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */ 0x00000004, /* MC_EMEM_ARB_TIMING_RAP2PRE */ 0x0000000e, /* MC_EMEM_ARB_TIMING_WAP2PRE */ diff --git a/arch/arm/mach-tegra/board-ardbeg-sdhci.c b/arch/arm/mach-tegra/board-ardbeg-sdhci.c index 5d7d2fbde651..80ea1e8b2055 100644 --- a/arch/arm/mach-tegra/board-ardbeg-sdhci.c +++ b/arch/arm/mach-tegra/board-ardbeg-sdhci.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,7 @@ static unsigned int wifi_states[] = {ON, OFF}; #define ARDBEG_SD_CD TEGRA_GPIO_PV2 #define ARDBEG_SD_WP TEGRA_GPIO_PQ4 +#define FUSE_SOC_SPEEDO_0 0x134 static void (*wifi_status_cb)(int card_present, void *dev_id); static void *wifi_status_cb_devid; @@ -206,7 +208,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = { .power_gpio = -1, .is_8bit = 1, .tap_delay = 0x4, - .trim_delay = 0x4, + .trim_delay = 0x3, .ddr_trim_delay = 0x0, .mmc_data = { .built_in = 1, @@ -384,7 +386,8 @@ static int __init ardbeg_wifi_prepower(void) !of_machine_is_compatible("nvidia,laguna") && !of_machine_is_compatible("nvidia,ardbeg_sata") && !of_machine_is_compatible("nvidia,tn8") && - !of_machine_is_compatible("nvidia,norrin")) + !of_machine_is_compatible("nvidia,norrin") && + !of_machine_is_compatible("nvidia,jetson-tk1")) return 0; ardbeg_wifi_power(1); @@ -399,6 +402,7 @@ int __init ardbeg_sdhci_init(void) int nominal_core_mv; int min_vcore_override_mv; int boot_vcore_mv; + u32 speedo; struct board_info board_info; nominal_core_mv = @@ -425,7 +429,8 @@ int __init ardbeg_sdhci_init(void) tegra_sdhci_platform_data3.boot_vcore_mv = boot_vcore_mv; } - if (of_machine_is_compatible("nvidia,laguna")) + if (of_machine_is_compatible("nvidia,laguna") || + of_machine_is_compatible("nvidia,jetson-tk1")) tegra_sdhci_platform_data2.wp_gpio = ARDBEG_SD_WP; tegra_get_board_info(&board_info); @@ -443,6 +448,24 @@ int __init ardbeg_sdhci_init(void) board_info.board_id == BOARD_PM359) tegra_sdhci_platform_data0.disable_clock_gate = 1; + /* + * FIXME: Set max clk limit to 200MHz for SDMMC3 for PM375. + * Requesting 208MHz results in getting 204MHz from PLL_P + * and CRC errors are seen with same. + */ + if (board_info.board_id == BOARD_PM375) + tegra_sdhci_platform_data2.max_clk_limit = 200000000; + + speedo = tegra_fuse_readl(FUSE_SOC_SPEEDO_0); + tegra_sdhci_platform_data0.cpu_speedo = speedo; + tegra_sdhci_platform_data2.cpu_speedo = speedo; + tegra_sdhci_platform_data3.cpu_speedo = speedo; + + speedo = tegra_fuse_readl(FUSE_SOC_SPEEDO_0); + tegra_sdhci_platform_data0.cpu_speedo = speedo; + tegra_sdhci_platform_data2.cpu_speedo = speedo; + tegra_sdhci_platform_data3.cpu_speedo = speedo; + platform_device_register(&tegra_sdhci_device3); platform_device_register(&tegra_sdhci_device2); if (board_info.board_id != BOARD_PM359 && diff --git a/arch/arm/mach-tegra/board-ardbeg.c b/arch/arm/mach-tegra/board-ardbeg.c index 2b7e726bc772..28e7fefa4207 100644 --- a/arch/arm/mach-tegra/board-ardbeg.c +++ b/arch/arm/mach-tegra/board-ardbeg.c @@ -1299,7 +1299,6 @@ static void __init tegra_ardbeg_late_init(void) else platform_device_register(&ardbeg_audio_device_rt5639); - //tegra_ram_console_debug_init(); tegra_io_dpd_init(); ardbeg_sdhci_init(); if (board_info.board_id == BOARD_PM359 || @@ -1373,11 +1372,6 @@ static void __init tegra_ardbeg_late_init(void) ardbeg_sysedp_batmon_init(); } -static void __init ardbeg_ramconsole_reserve(unsigned long size) -{ - tegra_ram_console_debug_reserve(SZ_1M); -} - static void __init tegra_ardbeg_init_early(void) { ardbeg_rail_alignment_init(); @@ -1419,7 +1413,6 @@ static void __init tegra_ardbeg_reserve(void) #endif tegra_reserve(carveout_size, fb1_size, fb2_size); - ardbeg_ramconsole_reserve(SZ_1M); } static const char * const ardbeg_dt_board_compat[] = { @@ -1447,6 +1440,11 @@ static const char * const norrin_dt_board_compat[] = { NULL }; +static const char * const jetson_dt_board_compat[] = { + "nvidia,jetson-tk1", + NULL +}; + DT_MACHINE_START(LAGUNA, "laguna") .atag_offset = 0x100, .smp = smp_ops(tegra_smp_ops), @@ -1517,3 +1515,17 @@ DT_MACHINE_START(ARDBEG_SATA, "ardbeg_sata") .init_late = tegra_init_late MACHINE_END + +DT_MACHINE_START(JETSON_TK1, "jetson-tk1") + .atag_offset = 0x100, + .smp = smp_ops(tegra_smp_ops), + .map_io = tegra_map_common_io, + .reserve = tegra_ardbeg_reserve, + .init_early = tegra_ardbeg_init_early, + .init_irq = irqchip_init, + .init_time = clocksource_of_init, + .init_machine = tegra_ardbeg_dt_init, + .restart = tegra_assert_system_reset, + .dt_compat = jetson_dt_board_compat, + .init_late = tegra_init_late +MACHINE_END diff --git a/arch/arm/mach-tegra/board-dalmore.c b/arch/arm/mach-tegra/board-dalmore.c index 43460f9db428..9cadf4b77b03 100644 --- a/arch/arm/mach-tegra/board-dalmore.c +++ b/arch/arm/mach-tegra/board-dalmore.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-dalmore.c * - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -671,7 +671,6 @@ static void __init tegra_dalmore_late_init(void) dalmore_uart_init(); dalmore_audio_init(); platform_add_devices(dalmore_devices, ARRAY_SIZE(dalmore_devices)); - //tegra_ram_console_debug_init(); tegra_io_dpd_init(); dalmore_regulator_init(); dalmore_sdhci_init(); @@ -702,11 +701,6 @@ static void __init tegra_dalmore_late_init(void) tegra_register_fuse(); } -static void __init dalmore_ramconsole_reserve(unsigned long size) -{ - tegra_ram_console_debug_reserve(SZ_1M); -} - static void __init tegra_dalmore_dt_init(void) { tegra_get_board_info(&board_info); @@ -729,7 +723,6 @@ static void __init tegra_dalmore_reserve(void) #else tegra_reserve(SZ_512M, SZ_16M + SZ_2M, SZ_4M); #endif - dalmore_ramconsole_reserve(SZ_1M); } static const char * const dalmore_dt_board_compat[] = { diff --git a/arch/arm/mach-tegra/board-laguna-power.c b/arch/arm/mach-tegra/board-laguna-power.c index f2e0de9a5ed0..c34f6b42f39a 100644 --- a/arch/arm/mach-tegra/board-laguna-power.c +++ b/arch/arm/mach-tegra/board-laguna-power.c @@ -852,7 +852,8 @@ static int __init laguna_fixed_regulator_init(void) { struct board_info board_info; - if (!of_machine_is_compatible("nvidia,laguna")) + if (!of_machine_is_compatible("nvidia,laguna") && + !of_machine_is_compatible("nvidia,jetson-tk1")) return 0; tegra_get_board_info(&board_info); diff --git a/arch/arm/mach-tegra/board-loki-sdhci.c b/arch/arm/mach-tegra/board-loki-sdhci.c index 86504670dd43..42e2ab6fe188 100644 --- a/arch/arm/mach-tegra/board-loki-sdhci.c +++ b/arch/arm/mach-tegra/board-loki-sdhci.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-loki-sdhci.c * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,8 @@ #define LOKI_SD_CD TEGRA_GPIO_PV2 +#define FUSE_SOC_SPEEDO_0 0x134 + static void (*wifi_status_cb)(int card_present, void *dev_id); static void *wifi_status_cb_devid; static int loki_wifi_status_register(void (*callback)(int , void *), void *); @@ -174,7 +177,7 @@ static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = { .power_gpio = -1, .is_8bit = 1, .tap_delay = 0x4, - .trim_delay = 0x4, + .trim_delay = 0x3, .ddr_trim_delay = 0x0, .mmc_data = { .built_in = 1, @@ -453,6 +456,7 @@ int __init loki_sdhci_init(void) int nominal_core_mv; int min_vcore_override_mv; int boot_vcore_mv; + u32 speedo; struct board_info bi; tegra_get_board_info(&bi); @@ -488,6 +492,12 @@ int __init loki_sdhci_init(void) tegra_sdhci_platform_data0.max_clk_limit = 204000000; + speedo = tegra_fuse_readl(FUSE_SOC_SPEEDO_0); + tegra_sdhci_platform_data0.cpu_speedo = speedo; + tegra_sdhci_platform_data2.cpu_speedo = speedo; + tegra_sdhci_platform_data3.cpu_speedo = speedo; + + platform_device_register(&tegra_sdhci_device3); if (!is_uart_over_sd_enabled()) diff --git a/arch/arm/mach-tegra/board-loki.c b/arch/arm/mach-tegra/board-loki.c index 570e001e7eed..b730466ef577 100644 --- a/arch/arm/mach-tegra/board-loki.c +++ b/arch/arm/mach-tegra/board-loki.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-loki.c * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -799,7 +799,6 @@ static void __init tegra_loki_late_init(void) loki_uart_init(); loki_audio_init(); platform_add_devices(loki_devices, ARRAY_SIZE(loki_devices)); - //tegra_ram_console_debug_init(); tegra_io_dpd_init(); loki_sdhci_init(); loki_regulator_init(); @@ -827,11 +826,6 @@ static void __init tegra_loki_late_init(void) #endif } -static void __init loki_ramconsole_reserve(unsigned long size) -{ - tegra_ram_console_debug_reserve(SZ_1M); -} - static void __init tegra_loki_dt_init(void) { tegra_get_board_info(&board_info); @@ -856,7 +850,6 @@ static void __init tegra_loki_reserve(void) #else tegra_reserve(SZ_1G, SZ_16M + SZ_2M, SZ_4M); #endif - loki_ramconsole_reserve(SZ_1M); } static const char * const loki_dt_board_compat[] = { diff --git a/arch/arm/mach-tegra/board-macallan.c b/arch/arm/mach-tegra/board-macallan.c index 2f0a50256477..47d320bc7076 100644 --- a/arch/arm/mach-tegra/board-macallan.c +++ b/arch/arm/mach-tegra/board-macallan.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-macallan.c * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -546,7 +546,6 @@ static void __init tegra_macallan_late_init(void) macallan_uart_init(); macallan_audio_init(); platform_add_devices(macallan_devices, ARRAY_SIZE(macallan_devices)); - //tegra_ram_console_debug_init(); tegra_io_dpd_init(); macallan_regulator_init(); macallan_sdhci_init(); @@ -572,11 +571,6 @@ static void __init tegra_macallan_late_init(void) tegra_register_fuse(); } -static void __init macallan_ramconsole_reserve(unsigned long size) -{ - tegra_ram_console_debug_reserve(SZ_1M); -} - static void __init tegra_macallan_dt_init(void) { tegra_get_board_info(&board_info); @@ -603,7 +597,6 @@ static void __init tegra_macallan_reserve(void) #else tegra_reserve(SZ_128M, SZ_16M + SZ_2M, SZ_16M + SZ_2M); #endif - macallan_ramconsole_reserve(SZ_1M); } static const char * const macallan_dt_board_compat[] = { diff --git a/arch/arm/mach-tegra/board-pismo.c b/arch/arm/mach-tegra/board-pismo.c index 2577b12e5426..7dd931c4cff5 100644 --- a/arch/arm/mach-tegra/board-pismo.c +++ b/arch/arm/mach-tegra/board-pismo.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-pismo.c * - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -595,7 +595,6 @@ static void __init tegra_pismo_init(void) pismo_uart_init(); pismo_audio_init(); platform_add_devices(pismo_devices, ARRAY_SIZE(pismo_devices)); - //tegra_ram_console_debug_init(); tegra_io_dpd_init(); pismo_regulator_init(); pismo_sdhci_init(); @@ -619,11 +618,6 @@ static void __init tegra_pismo_init(void) pismo_soctherm_init(); } -static void __init pismo_ramconsole_reserve(unsigned long size) -{ - tegra_ram_console_debug_reserve(SZ_1M); -} - #ifdef CONFIG_USE_OF struct of_dev_auxdata pismo_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra114-host1x", TEGRA_HOST1X_BASE, "host1x", @@ -661,7 +655,6 @@ static void __init tegra_pismo_reserve(void) #else tegra_reserve(SZ_128M, SZ_16M + SZ_2M, SZ_4M); #endif - pismo_ramconsole_reserve(SZ_1M); } static const char * const pismo_dt_board_compat[] = { diff --git a/arch/arm/mach-tegra/board-pluto.c b/arch/arm/mach-tegra/board-pluto.c index 68b162873e21..0735f5878281 100644 --- a/arch/arm/mach-tegra/board-pluto.c +++ b/arch/arm/mach-tegra/board-pluto.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-pluto.c * - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -1229,7 +1229,6 @@ static void __init tegra_pluto_late_init(void) pluto_uart_init(); pluto_audio_init(); platform_add_devices(pluto_devices, ARRAY_SIZE(pluto_devices)); - //tegra_ram_console_debug_init(); tegra_io_dpd_init(); pluto_sdhci_init(); pluto_regulator_init(); @@ -1258,10 +1257,6 @@ static void __init tegra_pluto_late_init(void) tegra_register_fuse(); } -static void __init pluto_ramconsole_reserve(unsigned long size) -{ - tegra_ram_console_debug_reserve(SZ_1M); -} static void __init tegra_pluto_dt_init(void) { @@ -1282,7 +1277,6 @@ static void __init tegra_pluto_reserve(void) #else tegra_reserve(SZ_128M, SZ_16M, SZ_4M); #endif - pluto_ramconsole_reserve(SZ_1M); } static const char * const pluto_dt_board_compat[] = { diff --git a/arch/arm/mach-tegra/board-roth.c b/arch/arm/mach-tegra/board-roth.c index b2518795227f..64e45e9fa8a5 100644 --- a/arch/arm/mach-tegra/board-roth.c +++ b/arch/arm/mach-tegra/board-roth.c @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/board-roth.c * - * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -571,7 +571,6 @@ static void __init tegra_roth_init(void) roth_led_init(); roth_audio_init(); platform_add_devices(roth_devices, ARRAY_SIZE(roth_devices)); - //tegra_ram_console_debug_init(); tegra_io_dpd_init(); roth_regulator_init(); roth_sdhci_init(); @@ -601,11 +600,6 @@ static void __init tegra_roth_init(void) roth_issp_init(); } -static void __init roth_ramconsole_reserve(unsigned long size) -{ - tegra_ram_console_debug_reserve(SZ_1M); -} - #ifdef CONFIG_USE_OF struct of_dev_auxdata roth_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra114-host1x", TEGRA_HOST1X_BASE, "host1x", @@ -643,7 +637,6 @@ static void __init tegra_roth_reserve(void) #else tegra_reserve(SZ_128M, SZ_16M + SZ_2M, SZ_4M); #endif - roth_ramconsole_reserve(SZ_1M); } static const char * const roth_dt_board_compat[] = { diff --git a/arch/arm/mach-tegra/board-vcm30_t124.c b/arch/arm/mach-tegra/board-vcm30_t124.c index bf76143776e6..eebf65a56561 100644 --- a/arch/arm/mach-tegra/board-vcm30_t124.c +++ b/arch/arm/mach-tegra/board-vcm30_t124.c @@ -487,11 +487,6 @@ static void __init tegra_vcm30_t124_late_init(void) vcm30_t124_panel_init(); } -static void __init vcm30_t124_ramconsole_reserve(unsigned long size) -{ - tegra_ram_console_debug_reserve(SZ_1M); -} - static void __init tegra_vcm30_t124_dt_init(void) { tegra_get_board_info(&board_info); @@ -515,7 +510,6 @@ static void __init tegra_vcm30_t124_reserve(void) #else tegra_reserve(SZ_128M, SZ_16M + SZ_2M, SZ_4M); #endif - vcm30_t124_ramconsole_reserve(SZ_1M); } static const char * const vcm30_t124_dt_board_compat[] = { diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index 6fd8cfe3f7cf..1db0118b0961 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -2,7 +2,7 @@ * arch/arm/mach-tegra/board.h * * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2011-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross @@ -122,13 +122,6 @@ int get_sd_uart_port_id(void); void set_sd_uart_port_id(int); int __init tegra_register_fuse(void); -#ifdef CONFIG_PSTORE_RAM -void __init tegra_ram_console_debug_reserve(unsigned long ram_console_size); -#else -static inline void __init tegra_ram_console_debug_reserve(unsigned long ram_console_size) -{} -#endif - extern phys_addr_t tegra_bootloader_fb_start; extern phys_addr_t tegra_bootloader_fb_size; extern phys_addr_t tegra_bootloader_fb2_start; diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index c9941f2ebaee..4b21c8aa3974 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -1712,6 +1712,37 @@ static int use_alt_freq_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(use_alt_freq_fops, use_alt_freq_get, use_alt_freq_set, "%llu\n"); +static ssize_t fmax_at_vmin_write(struct file *file, + const char __user *userbuf, size_t count, loff_t *ppos) +{ + struct clk *c = file->f_path.dentry->d_inode->i_private; + unsigned long f_max; + int v_min; + char buf[32]; + + if (sizeof(buf) <= count) + return -EINVAL; + + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + + /* terminate buffer and trim - white spaces may be appended + * at the end when invoked from shell command line */ + buf[count] = '\0'; + strim(buf); + + if (sscanf(buf, "%lu_at_%d", &f_max, &v_min) != 2) + return -EINVAL; + + tegra_dvfs_set_fmax_at_vmin(c, f_max, v_min); + + return count; +} + +static const struct file_operations fmax_at_vmin_fops = { + .write = fmax_at_vmin_write, +}; + static int clk_debugfs_register_one(struct clk *c) { struct dentry *d; @@ -1787,6 +1818,13 @@ static int clk_debugfs_register_one(struct clk *c) goto err_out; } + if (c->dvfs && c->dvfs->can_override) { + d = debugfs_create_file("fmax_at_vmin", S_IWUSR, c->dent, + c, &fmax_at_vmin_fops); + if (!d) + goto err_out; + } + return 0; err_out: diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 1b76f7ecd804..f4961dd48308 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -113,6 +113,11 @@ #define ADDR_BNDRY(x) (((x) & 0xf) << 21) #define INACTIVITY_TIMEOUT(x) (((x) & 0xffff) << 0) +#ifdef CONFIG_PSTORE_RAM +#define RAMOOPS_MEM_SIZE SZ_2M +#define FTRACE_MEM_SIZE SZ_1M +#endif + phys_addr_t tegra_bootloader_fb_start; phys_addr_t tegra_bootloader_fb_size; phys_addr_t tegra_bootloader_fb2_start; @@ -881,7 +886,6 @@ void __init tegra20_init_early(void) tegra_init_power(); tegra_init_ahb_gizmo_settings(); tegra_init_debug_uart_rate(); - tegra_ram_console_debug_reserve(SZ_1M); } #endif #ifdef CONFIG_ARCH_TEGRA_3x_SOC @@ -928,7 +932,6 @@ void __init tegra30_init_early(void) tegra_init_power(); tegra_init_ahb_gizmo_settings(); tegra_init_debug_uart_rate(); - tegra_ram_console_debug_reserve(SZ_1M); init_dma_coherent_pool_size(SZ_1M); } @@ -1024,7 +1027,6 @@ void __init tegra14x_init_early(void) tegra_init_power(); tegra_init_ahb_gizmo_settings(); tegra_init_debug_uart_rate(); - tegra_ram_console_debug_reserve(SZ_1M); } #endif static int __init tegra_lp0_vec_arg(char *options) @@ -1835,6 +1837,38 @@ void __tegra_clear_framebuffer(struct platform_device *pdev, iounmap(to_io); } +#ifdef CONFIG_PSTORE_RAM +static struct ramoops_platform_data ramoops_data; + +static struct platform_device ramoops_dev = { + .name = "ramoops", + .dev = { + .platform_data = &ramoops_data, + }, +}; + +static void __init tegra_reserve_ramoops_memory(unsigned long reserve_size) +{ + ramoops_data.mem_size = reserve_size; + ramoops_data.mem_address = memblock_end_of_4G() - reserve_size; + ramoops_data.console_size = reserve_size - FTRACE_MEM_SIZE; + ramoops_data.ftrace_size = FTRACE_MEM_SIZE; + ramoops_data.dump_oops = 1; + memblock_reserve(ramoops_data.mem_address, ramoops_data.mem_size); +} + +static int __init tegra_register_ramoops_device(void) +{ + int ret = platform_device_register(&ramoops_dev); + if (ret) { + pr_info("Unable to register ramoops platform device\n"); + return ret; + } + return ret; +} +core_initcall(tegra_register_ramoops_device); +#endif + void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size, unsigned long fb2_size) { @@ -2126,6 +2160,9 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size, #endif tegra_fb_linear_set(map); +#ifdef CONFIG_PSTORE_RAM + tegra_reserve_ramoops_memory(RAMOOPS_MEM_SIZE); +#endif } void tegra_get_fb_resource(struct resource *fb_res) @@ -2142,37 +2179,6 @@ void tegra_get_fb2_resource(struct resource *fb2_res) (resource_size_t) tegra_fb2_size - 1; } -#ifdef CONFIG_PSTORE_RAM -static struct persistent_ram_descriptor desc = { - .name = "ramoops", -}; - -static struct persistent_ram ram = { - .descs = &desc, - .num_descs = 1, -}; - -void __init tegra_ram_console_debug_reserve(unsigned long ram_console_size) -{ - int ret; - - ram.start = memblock_end_of_DRAM() - ram_console_size; - ram.size = ram_console_size; - ram.descs->size = ram_console_size; - - INIT_LIST_HEAD(&ram.node); - - ret = persistent_ram_early_init(&ram); - if (ret) - goto fail; - - return; - -fail: - pr_err("Failed to reserve memory block for ram console\n"); -} -#endif - int __init tegra_register_fuse(void) { return platform_device_register(&tegra_fuse_device); diff --git a/arch/arm/mach-tegra/dvfs.c b/arch/arm/mach-tegra/dvfs.c index 47c38be2dfd4..b1414a100350 100644 --- a/arch/arm/mach-tegra/dvfs.c +++ b/arch/arm/mach-tegra/dvfs.c @@ -830,6 +830,7 @@ int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate) tegra_dvfs_get_millivolts_pll(c->dvfs); return predict_millivolts(c, millivolts, rate); } +EXPORT_SYMBOL(tegra_dvfs_predict_millivolts); int tegra_dvfs_predict_peak_millivolts(struct clk *c, unsigned long rate) { @@ -1004,12 +1005,74 @@ int tegra_dvfs_rail_get_override_floor(struct dvfs_rail *rail) } return -ENOENT; } + +static int dvfs_set_fmax_at_vmin(struct clk *c, unsigned long f_max, int v_min) +{ + int i, ret = 0; + struct dvfs *d = c->dvfs; + unsigned long f_min = 1000; /* 1kHz min rate in DVFS tables */ + + mutex_lock(&rail_override_lock); + mutex_lock(&dvfs_lock); + + if (v_min > d->dvfs_rail->override_millivolts) { + pr_err("%s: new %s vmin %dmV is above override voltage %dmV\n", + __func__, c->name, v_min, + d->dvfs_rail->override_millivolts); + ret = -EPERM; + goto out; + } + + if (v_min >= d->max_millivolts) { + pr_err("%s: new %s vmin %dmV is at/above max voltage %dmV\n", + __func__, c->name, v_min, d->max_millivolts); + ret = -EINVAL; + goto out; + } + + /* + * dvfs table update: + * - for voltages below new v_min the respective frequencies are shifted + * below new f_max to the levels already present in the table; if the + * 1st table entry has frequency above new fmax, all entries below v_min + * are filled in with 1kHz (min rate used in DVFS tables). + * - for voltages above new v_min, the respective frequencies are + * increased to at least new f_max + * - if new v_min is already in the table set the respective frequency + * to new f_max + */ + for (i = 0; i < d->num_freqs; i++) { + int mv = d->millivolts[i]; + unsigned long f = d->freqs[i]; + + if (mv < v_min) { + if (d->freqs[i] >= f_max) + d->freqs[i] = i ? d->freqs[i-1] : f_min; + } else if (mv > v_min) { + d->freqs[i] = max(f, f_max); + } else { + d->freqs[i] = f_max; + } + ret = __tegra_dvfs_set_rate(d, d->cur_rate); + } +out: + mutex_unlock(&dvfs_lock); + mutex_unlock(&rail_override_lock); + + return ret; +} #else static int dvfs_override_core_voltage(int override_mv) { pr_err("%s: vdd core override is not supported\n", __func__); return -ENOSYS; } + +static int dvfs_set_fmax_at_vmin(struct clk *c, unsigned long f_max, int v_min) +{ + pr_err("%s: vdd core override is not supported\n", __func__); + return -ENOSYS; +} #endif int tegra_dvfs_override_core_voltage(struct clk *c, int override_mv) @@ -1022,6 +1085,16 @@ int tegra_dvfs_override_core_voltage(struct clk *c, int override_mv) } EXPORT_SYMBOL(tegra_dvfs_override_core_voltage); +int tegra_dvfs_set_fmax_at_vmin(struct clk *c, unsigned long f_max, int v_min) +{ + if (!c->dvfs || !c->dvfs->can_override) { + pr_err("%s: %s cannot set fmax_at_vmin)\n", __func__, c->name); + return -EPERM; + } + return dvfs_set_fmax_at_vmin(c, f_max, v_min); +} +EXPORT_SYMBOL(tegra_dvfs_set_fmax_at_vmin); + /* May only be called during clock init, does not take any locks on clock c. */ int __init tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d) { diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h index 4565529b01bc..cc9ef7a315a1 100644 --- a/arch/arm/mach-tegra/dvfs.h +++ b/arch/arm/mach-tegra/dvfs.h @@ -250,7 +250,6 @@ void tegra_dvfs_rail_pause(struct dvfs_rail *rail, ktime_t delta, bool on); int tegra_dvfs_rail_set_mode(struct dvfs_rail *rail, unsigned int mode); struct dvfs_rail *tegra_dvfs_get_rail_by_name(const char *reg_id); -int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate); int tegra_dvfs_predict_peak_millivolts(struct clk *c, unsigned long rate); const int *tegra_dvfs_get_millivolts_pll(struct dvfs *d); diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 51cc64fcfaaa..525f575d4e6c 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -1660,7 +1660,7 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat) /* create the pdata from DT information */ pm_dat = tegra_get_pm_data(); if (pm_dat) { - pr_err("PMC dt information non-NULL %s\n", __func__); + pr_debug("PMC dt information non-NULL %s\n", __func__); is_board_pdata = false; pdata = kzalloc(sizeof(struct tegra_suspend_platform_data), GFP_KERNEL); diff --git a/arch/arm/mach-tegra/powergate-t12x.c b/arch/arm/mach-tegra/powergate-t12x.c index 05933a731a91..14bd096be15e 100644 --- a/arch/arm/mach-tegra/powergate-t12x.c +++ b/arch/arm/mach-tegra/powergate-t12x.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -286,6 +286,7 @@ static struct powergate_partition_info tegra12x_powergate_partition_info[] = { #define MC_CLIENT_HOTRESET_STAT 0x204 #define MC_CLIENT_HOTRESET_CTRL_1 0x970 #define MC_CLIENT_HOTRESET_STAT_1 0x974 +#define MC_VIDEO_PROTECT_REG_CTRL 0x650 #define PMC_GPU_RG_CNTRL_0 0x2d4 @@ -444,12 +445,27 @@ err_power_off: return ret; } +static int mc_check_vpr(void) +{ + int ret = 0; + u32 val = mc_read(MC_VIDEO_PROTECT_REG_CTRL); + if ((val & 1) == 0) { + pr_err("VPR configuration not locked down\n"); + ret = -EINVAL; + } + return ret; +} + static int tegra12x_gpu_unpowergate(int id, struct powergate_partition_info *pg_info) { int ret = 0; bool first = false; + ret = mc_check_vpr(); + if (ret) + return ret; + if (!gpu_rail) { gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu"); if (IS_ERR_OR_NULL(gpu_rail)) { diff --git a/arch/arm/mach-tegra/tegra12_clocks.c b/arch/arm/mach-tegra/tegra12_clocks.c index c686b43d5bc5..c9a085bf70a2 100644 --- a/arch/arm/mach-tegra/tegra12_clocks.c +++ b/arch/arm/mach-tegra/tegra12_clocks.c @@ -8355,6 +8355,16 @@ struct clk_duplicate tegra_clk_duplicates[] = { CLK_DUPLICATE("dam2", NULL, "dam2"), CLK_DUPLICATE("spdif_in", NULL, "spdif_in"), CLK_DUPLICATE("mclk", NULL, "default_mclk"), + CLK_DUPLICATE("amx", NULL, "amx"), + CLK_DUPLICATE("amx1", NULL, "amx1"), + CLK_DUPLICATE("adx", NULL, "adx"), + CLK_DUPLICATE("adx1", NULL, "adx1"), + CLK_DUPLICATE("afc0", NULL, "afc0"), + CLK_DUPLICATE("afc1", NULL, "afc1"), + CLK_DUPLICATE("afc2", NULL, "afc2"), + CLK_DUPLICATE("afc3", NULL, "afc3"), + CLK_DUPLICATE("afc4", NULL, "afc4"), + CLK_DUPLICATE("afc5", NULL, "afc5"), CLK_DUPLICATE("amx", "tegra124-amx.0", NULL), CLK_DUPLICATE("amx1", "tegra124-amx.1", NULL), CLK_DUPLICATE("adx", "tegra124-adx.0", NULL), @@ -9219,11 +9229,227 @@ static void tegra12_init_xusb_clocks(void) tegra12_init_one_clock(&tegra_xusb_coupled_clks[i]); } +#ifdef CONFIG_TEGRA_PREINIT_CLOCKS + +#define CLK_RSTENB_DEV_V_0_AUDIO_BIT (1 << 10) +#define CLK_RSTENB_DEV_V_0_3D2_BIT (1 << 2) + +#define CLK_RSTENB_DEV_L_0_HOST1X_BIT (1 << 28) +#define CLK_RSTENB_DEV_L_0_DISP1_BIT (1 << 27) +#define CLK_RSTENB_DEV_L_0_3D_BIT (1 << 24) +#define CLK_RSTENB_DEV_L_0_ISP_BIT (1 << 23) +#define CLK_RSTENB_DEV_L_0_2D_BIT (1 << 21) +#define CLK_RSTENB_DEV_L_0_VI_BIT (1 << 20) +#define CLK_RSTENB_DEV_L_0_EPP_BIT (1 << 19) + +#define CLK_RSTENB_DEV_H_0_VDE_BIT (1 << 29) +#define CLK_RSTENB_DEV_H_0_MPE_BIT (1 << 28) + +#define CLK_RSTENB_DEV_U_0_CSITE_BIT (1 << 9) + +#define CLK_RSTENB_DEV_X_0_HDMI_AUDIO_BIT (1 << 16) + +#define HOST1X_CLK_REG_OFFSET 0x180 +#define HOST1X_CLK_SRC_SHIFT 30 +#define HOST1X_CLK_SRC_MASK (0x3 << HOST1X_CLK_SRC_SHIFT) +#define HOST1X_CLK_SRC_PLLM_OUT0 0 +#define HOST1X_CLK_SRC_PLLC_OUT0 1 +#define HOST1X_CLK_SRC_PLLP_OUT0 2 +#define HOST1X_CLK_SRC_PLLA_OUT0 3 +#define HOST1X_CLK_SRC_DEFAULT (\ + HOST1X_CLK_SRC_PLLP_OUT0 << HOST1X_CLK_SRC_SHIFT) +#define HOST1X_CLK_IDLE_DIV_SHIFT 8 +#define HOST1X_CLK_IDLE_DIV_MASK (0xff << HOST1X_CLK_IDLE_DIV_SHIFT) +#define HOST1X_CLK_IDLE_DIV_DEFAULT (0 << HOST1X_CLK_IDLE_DIV_SHIFT) +#define HOST1X_CLK_DIV_SHIFT 0 +#define HOST1X_CLK_DIV_MASK (0xff << HOST1X_CLK_DIV_SHIFT) +#define HOST1X_CLK_DIV_DEFAULT (3 << HOST1X_CLK_DIV_SHIFT) + +#define VCLK_SRC_SHIFT 30 +#define VCLK_SRC_MASK (0x3 << VCLK_SRC_SHIFT) +#define VCLK_SRC_PLLM_OUT0 0 +#define VCLK_SRC_PLLC_OUT0 1 +#define VCLK_SRC_PLLP_OUT0 2 +#define VCLK_SRC_PLLA_OUT0 3 +#define VCLK_SRC_DEFAULT (VCLK_SRC_PLLM_OUT0 << VCLK_SRC_SHIFT) +#define VCLK_IDLE_DIV_SHIFT 8 +#define VCLK_IDLE_DIV_MASK (0xff << VCLK_IDLE_DIV_SHIFT) +#define VCLK_IDLE_DIV_DEFAULT (0 << VCLK_IDLE_DIV_SHIFT) +#define VCLK_DIV_SHIFT 0 +#define VCLK_DIV_MASK (0xff << VCLK_DIV_SHIFT) +#define VCLK_DIV_DEFAULT (0xa << VCLK_DIV_SHIFT) + +#define ISP_CLK_REG_OFFSET 0x144 +#define VI_CLK_REG_OFFSET 0x148 +#define VI_SENSOR_CLK_REG_OFFSET 0x1a8 +#define VI_SENSOR2_CLK_REG_OFFSET 0x658 +#define VI_CLK_DIV_DEFAULT (0x12 << VCLK_DIV_SHIFT) +#define G3D_CLK_REG_OFFSET 0x158 +#define G2D_CLK_REG_OFFSET 0x15c +#define EPP_CLK_REG_OFFSET 0x16c +#define MPE_CLK_REG_OFFSET 0x170 +#define VDE_CLK_REG_OFFSET 0x170 +#define G3D2_CLK_REG_OFFSET 0x3b0 +#define HDMI_AUDIO_CLK_REG_OFFSET 0x668 +#define HDMI_AUDIO_CLK_DIV_DEFAULT (0x12 << VCLK_DIV_SHIFT) +#define CSITE_CLK_REG_OFFSET 0x1d4 +#define CSITE_CLK_DIV_DEFAULT (0x4 << VCLK_DIV_SHIFT) + +static void __init clk_setbit(u32 reg, u32 bit) +{ + u32 val = clk_readl(reg); + + if ((val & bit) == bit) + return; + val |= bit; + clk_writel(val, reg); + udelay(2); +} + +static void __init clk_clrbit(u32 reg, u32 bit) +{ + u32 val = clk_readl(reg); + + if ((val & bit) == 0) + return; + val &= ~bit; + clk_writel(val, reg); + udelay(2); +} + +static void __init clk_setbits(u32 reg, u32 bits, u32 mask) +{ + u32 val = clk_readl(reg); + + if ((val & mask) == bits) + return; + val &= ~mask; + val |= bits; + clk_writel(val, reg); + udelay(2); +} + +static void __init vclk_init(int tag, u32 src, u32 rebit) +{ + u32 rst, enb; + + switch (tag) { + case 'L': + rst = RST_DEVICES_L; + enb = CLK_OUT_ENB_L; + break; + case 'H': + rst = RST_DEVICES_H; + enb = CLK_OUT_ENB_H; + break; + case 'U': + rst = RST_DEVICES_U; + enb = CLK_OUT_ENB_U; + break; + case 'V': + rst = RST_DEVICES_V; + enb = CLK_OUT_ENB_V; + break; + case 'W': + rst = RST_DEVICES_W; + enb = CLK_OUT_ENB_W; + break; + case 'X': + rst = RST_DEVICES_X; + enb = CLK_OUT_ENB_X; + break; + default: + /* Quietly ignore. */ + return; + } + + clk_setbit(rst, rebit); + clk_clrbit(enb, rebit); + + clk_setbits(src, VCLK_SRC_DEFAULT, VCLK_SRC_MASK); + clk_setbits(src, VCLK_DIV_DEFAULT, VCLK_DIV_MASK); + + clk_clrbit(rst, rebit); +} + +static int __init tegra_soc_preinit_clocks(void) +{ + /* + * Make sure host1x clock configuration has: + * HOST1X_CLK_SRC : PLLP_OUT0. + * HOST1X_CLK_DIVISOR: >2 to start from safe enough frequency. + */ + clk_setbit(RST_DEVICES_L, CLK_RSTENB_DEV_L_0_HOST1X_BIT); + clk_setbit(CLK_OUT_ENB_L, CLK_RSTENB_DEV_L_0_HOST1X_BIT); + clk_setbits(HOST1X_CLK_REG_OFFSET, + HOST1X_CLK_DIV_DEFAULT, HOST1X_CLK_DIV_MASK); + clk_setbits(HOST1X_CLK_REG_OFFSET, + HOST1X_CLK_IDLE_DIV_DEFAULT, HOST1X_CLK_IDLE_DIV_MASK); + clk_setbits(HOST1X_CLK_REG_OFFSET, + HOST1X_CLK_SRC_DEFAULT, HOST1X_CLK_SRC_MASK); + clk_clrbit(RST_DEVICES_L, CLK_RSTENB_DEV_L_0_HOST1X_BIT); + + /* + * Make sure vi clock configuration has: + * VI_CLK_DIVISOR: 0x12 + * VI_SENSOR_CLK_DIVISOR: 0x12 + * VI_SENSOR2_CLK_DIVISOR: 0x12 + */ + clk_setbit(RST_DEVICES_L, CLK_RSTENB_DEV_L_0_VI_BIT); + clk_setbit(CLK_OUT_ENB_L, CLK_RSTENB_DEV_L_0_VI_BIT); + clk_setbits(VI_CLK_REG_OFFSET, + VCLK_SRC_DEFAULT, VCLK_SRC_MASK); + clk_setbits(VI_CLK_REG_OFFSET, VI_CLK_DIV_DEFAULT, VCLK_DIV_MASK); + clk_setbits(VI_SENSOR_CLK_REG_OFFSET, VCLK_SRC_DEFAULT, VCLK_SRC_MASK); + clk_setbits(VI_SENSOR_CLK_REG_OFFSET, + VI_CLK_DIV_DEFAULT, VCLK_DIV_MASK); + clk_setbits(VI_SENSOR2_CLK_REG_OFFSET, VCLK_SRC_DEFAULT, VCLK_SRC_MASK); + clk_setbits(VI_SENSOR2_CLK_REG_OFFSET, + VI_CLK_DIV_DEFAULT, VCLK_DIV_MASK); + clk_clrbit(RST_DEVICES_L, CLK_RSTENB_DEV_L_0_VI_BIT); + + /* + * Make sure hdmi_audio clock configuration has: + * HDMI_AUDIO_CLK_DIVISOR: 0x12 + */ + clk_setbit(RST_DEVICES_X, CLK_RSTENB_DEV_X_0_HDMI_AUDIO_BIT); + clk_setbit(CLK_OUT_ENB_X, CLK_RSTENB_DEV_X_0_HDMI_AUDIO_BIT); + clk_setbits(HDMI_AUDIO_CLK_REG_OFFSET, + HDMI_AUDIO_CLK_DIV_DEFAULT, VCLK_DIV_MASK); + clk_clrbit(RST_DEVICES_X, CLK_RSTENB_DEV_X_0_HDMI_AUDIO_BIT); + + /* + * Make sure csite clock configuration has: + * CSITE_CLK_DIVISOR: 0x4 + */ + clk_setbit(RST_DEVICES_U, CLK_RSTENB_DEV_U_0_CSITE_BIT); + clk_setbit(CLK_OUT_ENB_U, CLK_RSTENB_DEV_U_0_CSITE_BIT); + clk_setbits(CSITE_CLK_REG_OFFSET, CSITE_CLK_DIV_DEFAULT, VCLK_DIV_MASK); + clk_clrbit(RST_DEVICES_U, CLK_RSTENB_DEV_U_0_CSITE_BIT); + + /* Pre-initialize Video clocks. */ + vclk_init('L', G3D_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_3D_BIT); + vclk_init('L', G2D_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_2D_BIT); + vclk_init('L', ISP_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_ISP_BIT); + vclk_init('L', EPP_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_EPP_BIT); + vclk_init('H', VDE_CLK_REG_OFFSET, CLK_RSTENB_DEV_H_0_VDE_BIT); + vclk_init('H', MPE_CLK_REG_OFFSET, CLK_RSTENB_DEV_H_0_MPE_BIT); + vclk_init('V', G3D2_CLK_REG_OFFSET, CLK_RSTENB_DEV_V_0_3D2_BIT); + + return 0; +} +#endif /* CONFIG_TEGRA_PREINIT_CLOCKS */ + void __init tegra12x_init_clocks(void) { int i; struct clk *c; + +#ifdef CONFIG_TEGRA_PREINIT_CLOCKS + tegra_soc_preinit_clocks(); +#endif /* CONFIG_TEGRA_PREINIT_CLOCKS */ + for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++) tegra12_init_one_clock(tegra_ptr_clks[i]); diff --git a/arch/arm/mach-tegra/tegra12_dvfs.c b/arch/arm/mach-tegra/tegra12_dvfs.c index 2a03b7165bc5..d2fbb8de3c52 100644 --- a/arch/arm/mach-tegra/tegra12_dvfs.c +++ b/arch/arm/mach-tegra/tegra12_dvfs.c @@ -141,8 +141,8 @@ void __init tegra12x_vdd_cpu_align(int step_uv, int offset_uv) /* CPU DVFS tables */ static unsigned long cpu_max_freq[] = { -/* speedo_id 0 1 2 3 */ - 2014500, 2320500, 2116500, 2524500, +/* speedo_id 0 1 2 3 4 5 */ + 2014500, 2320500, 2116500, 2524500, 1500000, 2218500, }; static struct cpu_cvb_dvfs cpu_cvb_dvfs_table[] = { @@ -221,6 +221,19 @@ static const int core_millivolts[MAX_DVFS_FREQS] = { .dvfs_rail = &tegra12_dvfs_rail_vdd_core, \ } +#define OVRRD_DVFS(_clk_name, _speedo_id, _process_id, _auto, _mult, _freqs...) \ + { \ + .clk_name = _clk_name, \ + .speedo_id = _speedo_id, \ + .process_id = _process_id, \ + .freqs = {_freqs}, \ + .freqs_mult = _mult, \ + .millivolts = core_millivolts, \ + .auto_dvfs = _auto, \ + .can_override = true, \ + .dvfs_rail = &tegra12_dvfs_rail_vdd_core, \ + } + static struct dvfs core_dvfs_table[] = { /* Core voltages (mV): 800, 850, 900, 950, 1000, 1050, 1100, 1150 */ /* Clock limits for internal blocks, PLLs */ @@ -315,41 +328,19 @@ static struct dvfs core_dvfs_table[] = { CORE_DVFS("hda", -1, -1, 1, KHZ, 1, 108000, 108000, 108000, 108000, 108000 , 108000, 108000), CORE_DVFS("hda2codec_2x", -1, -1, 1, KHZ, 1, 48000, 48000, 48000, 48000, 48000 , 48000, 48000), + + OVRRD_DVFS("sdmmc1", -1, -1, 1, KHZ, 1, 1, 82000, 82000, 136000, 136000, 136000, 204000), + OVRRD_DVFS("sdmmc3", -1, -1, 1, KHZ, 1, 1, 82000, 82000, 136000, 136000, 136000, 204000), + OVRRD_DVFS("sdmmc4", -1, -1, 1, KHZ, 1, 1, 82000, 82000, 136000, 136000, 136000, 200000), }; /* - * Separate sdmmc and display dvfs table to handle dependency of sdmmc tuning - * on display maximum rate. - * * Display peak voltage aggregation into override range floor is deferred until * actual pixel clock for the particular platform is known. This would allow to - * extend sdmmc tuning range on the platforms that do not excercise maximum - * display clock capabilities specified in DVFS table. + * extend override range on the platforms that do not excercise maximum display + * clock capabilities specified in DVFS table. * - * Two SDMMC tables: - * - "1-point tuning" table is applicable when override floor is equal to - * nominal voltage (override range is zero). It is installed by default, while - * display peak voltage is unknown. It is overwritten when display peak voltage - * is aggregated, provided final override floor is below nominal. - * - * - "2-point tuning" table is applicable when override floor is below nominal - * voltage (i.e., at least 2 tuning points in override range). It is installed - * when display peak voltage is aggregated, provided final override floor is - * below nominal. */ -#define OVRRD_DVFS(_clk_name, _speedo_id, _process_id, _auto, _mult, _freqs...) \ - { \ - .clk_name = _clk_name, \ - .speedo_id = _speedo_id, \ - .process_id = _process_id, \ - .freqs = {_freqs}, \ - .freqs_mult = _mult, \ - .millivolts = core_millivolts, \ - .auto_dvfs = _auto, \ - .can_override = true, \ - .dvfs_rail = &tegra12_dvfs_rail_vdd_core, \ - } - #define DEFER_DVFS(_clk_name, _speedo_id, _process_id, _auto, _mult, _freqs...) \ { \ .clk_name = _clk_name, \ @@ -363,19 +354,6 @@ static struct dvfs core_dvfs_table[] = { .dvfs_rail = &tegra12_dvfs_rail_vdd_core, \ } - /* Core voltages (mV): 800, 850, 900, 950, 1000, 1050, 1100, 1150 */ -static struct dvfs sdmmc_dvfs_table[] = { - OVRRD_DVFS("sdmmc1", -1, -1, 1, KHZ, 1, 1, 50000, 50000, 50000, 50000, 50000, 204000), - OVRRD_DVFS("sdmmc3", -1, -1, 1, KHZ, 1, 1, 50000, 50000, 50000, 50000, 50000, 204000), - OVRRD_DVFS("sdmmc4", -1, -1, 1, KHZ, 1, 1, 50000, 50000, 50000, 50000, 50000, 200000), -}; - -static struct dvfs sdmmc_tune2_dvfs_table[] = { - OVRRD_DVFS("sdmmc1", -1, -1, 1, KHZ, 1, 1, 82000, 82000, 136000, 136000, 136000, 204000), - OVRRD_DVFS("sdmmc3", -1, -1, 1, KHZ, 1, 1, 82000, 82000, 136000, 136000, 136000, 204000), - OVRRD_DVFS("sdmmc4", -1, -1, 1, KHZ, 1, 1, 82000, 82000, 136000, 136000, 136000, 200000), -}; - static struct dvfs disp_dvfs_table[] = { /* * The clock rate for the display controllers that determines the @@ -407,22 +385,7 @@ static struct dvfs disp_alt_dvfs_table[] = { static int resolve_core_override(int min_override_mv) { - int i, j; - struct dvfs *d = sdmmc_dvfs_table; - struct dvfs *d_tune = sdmmc_tune2_dvfs_table; - - BUILD_BUG_ON(ARRAY_SIZE(sdmmc_dvfs_table) != - ARRAY_SIZE(sdmmc_tune2_dvfs_table)); - - if (min_override_mv >= - tegra12_dvfs_rail_vdd_core.nominal_millivolts) - return 0; - - /* Override range is not 0: 2+ points for SDMMC tuning are available */ - for (i = 0; i < ARRAY_SIZE(sdmmc_dvfs_table); i++, d++, d_tune++) { - for (j = 0; j < d->num_freqs; j++) - d->freqs[j] = d_tune->freqs[j] * d_tune->freqs_mult; - } + /* nothing to do -- always resolved */ return 0; } @@ -1173,8 +1136,6 @@ void __init tegra12x_init_dvfs(void) if (!tegra_platform_is_linsim()) { INIT_CORE_DVFS_TABLE(core_dvfs_table, ARRAY_SIZE(core_dvfs_table)); - INIT_CORE_DVFS_TABLE(sdmmc_dvfs_table, - ARRAY_SIZE(sdmmc_dvfs_table)); INIT_CORE_DVFS_TABLE(disp_dvfs_table, ARRAY_SIZE(disp_dvfs_table)); diff --git a/arch/arm/mach-tegra/tegra12_edp.c b/arch/arm/mach-tegra/tegra12_edp.c index 91570e0102ed..10d6ec9e6484 100644 --- a/arch/arm/mach-tegra/tegra12_edp.c +++ b/arch/arm/mach-tegra/tegra12_edp.c @@ -272,6 +272,10 @@ static struct tegra_edp_cpu_leakage_params t12x_leakage_params[] = { .cpu_speedo_id = 3, /* Prod SKU */ EDP_PARAMS_COMMON_PART, }, + { + .cpu_speedo_id = 5, /* Prod SKU */ + EDP_PARAMS_COMMON_PART, + }, }; #ifdef CONFIG_TEGRA_GPU_EDP diff --git a/arch/arm/mach-tegra/tegra12_speedo.c b/arch/arm/mach-tegra/tegra12_speedo.c index 92244be7cf20..9ce142e5354a 100644 --- a/arch/arm/mach-tegra/tegra12_speedo.c +++ b/arch/arm/mach-tegra/tegra12_speedo.c @@ -106,7 +106,7 @@ static void rev_sku_to_speedo_ids(int rev, int sku) case 0x1F: case 0x87: case 0x27: - cpu_speedo_id = 2; + cpu_speedo_id = 5; soc_speedo_id = 0; gpu_speedo_id = 1; threshold_index = 0; diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index a7272676b230..3a87379674d5 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -8,6 +8,7 @@ * (C) 2003 Jun Nakajima * (C) 2009 Alexander Clouter * (c) 2012 Viresh Kumar + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -364,6 +365,11 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, break; case CPUFREQ_GOV_LIMITS: + mutex_lock(&dbs_data->mutex); + if (!cpu_cdbs->cur_policy) { + mutex_unlock(&dbs_data->mutex); + break; + } mutex_lock(&cpu_cdbs->timer_mutex); if (policy->max < cpu_cdbs->cur_policy->cur) __cpufreq_driver_target(cpu_cdbs->cur_policy, @@ -373,6 +379,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); mutex_unlock(&cpu_cdbs->timer_mutex); + mutex_unlock(&dbs_data->mutex); break; } return 0; diff --git a/drivers/misc/tegra-fuse/tegra_fuse.c b/drivers/misc/tegra-fuse/tegra_fuse.c index 5ad209ecd5f6..e8c65f520ffa 100644 --- a/drivers/misc/tegra-fuse/tegra_fuse.c +++ b/drivers/misc/tegra-fuse/tegra_fuse.c @@ -322,6 +322,7 @@ static struct chip_revision tegra_chip_revisions[] = { CHIP_REVISION(TEGRA11, 1, 2, 0, A02), CHIP_REVISION(TEGRA14, 1, 1, 0, A01), CHIP_REVISION(TEGRA14, 1, 2, 0, A02), + CHIP_REVISION(TEGRA12, 1, 1, 0, A01), }; static enum tegra_revision tegra_decode_revision(const struct tegra_id *id) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index fdda83afe1f6..abcc0e5f5020 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -146,6 +146,7 @@ #define NVQUIRK_HIGH_FREQ_TAP_PROCEDURE BIT(22) /* Disable SDMMC3 external loopback */ #define NVQUIRK_DISABLE_EXTERNAL_LOOPBACK BIT(23) +#define NVQUIRK_TMP_VAR_1_5_TAP_MARGIN BIT(24) /* Common subset of quirks for Tegra3 and later sdmmc controllers */ #define TEGRA_SDHCI_NVQUIRKS (NVQUIRK_ENABLE_PADPIPE_CLKEN | \ @@ -196,7 +197,7 @@ #define TUNING_VOLTAGES_COUNT 3 #define TUNING_RETRIES 1 #define DFS_FREQ_COUNT 2 - +#define NEG_MAR_CHK_WIN_COUNT 2 /* Tuning core voltage requirements */ #define NOMINAL_VCORE_TUN BIT(0) #define BOOT_VCORE_TUN BIT(1) @@ -221,7 +222,10 @@ struct sdhci_tegra_soc_data { u32 nvquirks; const char *parent_clk_list[2]; unsigned int tuning_freq_list[TUNING_FREQ_COUNT]; - unsigned int tuning_min_volt_list[TUNING_FREQ_COUNT]; + u8 t2t_coeffs_count; + u8 tap_hole_coeffs_count; + struct tuning_t2t_coeffs *t2t_coeffs; + struct tap_hole_coeffs *tap_hole_coeffs; }; @@ -231,18 +235,137 @@ enum tegra_regulator_config_ops { CONFIG_REG_SET_VOLT, }; -static unsigned int uhs_max_freq_MHz[] = { - [MMC_TIMING_UHS_SDR50] = 100, - [MMC_TIMING_UHS_SDR104] = 208, - [MMC_TIMING_MMC_HS200] = 200, -}; - enum tegra_tuning_freq { TUNING_LOW_FREQ, TUNING_HIGH_FREQ, TUNING_MAX_FREQ, }; +struct tuning_t2t_coeffs { + const char *dev_id; + int vmax; + int vmin; + unsigned int t2t_vnom_slope; + unsigned int t2t_vnom_int; + unsigned int t2t_vmax_slope; + unsigned int t2t_vmax_int; + unsigned int t2t_vmin_slope; + unsigned int t2t_vmin_int; +}; + +#define SET_TUNING_COEFFS(_device_id, _vmax, _vmin, _t2t_vnom_slope, \ + _t2t_vnom_int, _t2t_vmax_slope, _t2t_vmax_int, _t2t_vmin_slope, \ + _t2t_vmin_int) \ + { \ + .dev_id = _device_id, \ + .vmax = _vmax, \ + .vmin = _vmin, \ + .t2t_vnom_slope = _t2t_vnom_slope, \ + .t2t_vnom_int = _t2t_vnom_int, \ + .t2t_vmax_slope = _t2t_vmax_slope, \ + .t2t_vmax_int = _t2t_vmax_int, \ + .t2t_vmin_slope = _t2t_vmin_slope, \ + .t2t_vmin_int = _t2t_vmin_int, \ + } + +struct tuning_t2t_coeffs t11x_tuning_coeffs[] = { + SET_TUNING_COEFFS("sdhci-tegra.3", 1250, 950, 55, 135434, + 73, 170493, 243, 455948), + SET_TUNING_COEFFS("sdhci-tegra.2", 1250, 950, 50, 129738, + 73, 168898, 241, 453050), + SET_TUNING_COEFFS("sdhci-tegra.0", 1250, 950, 62, 143469, + 82, 180096, 238, 444285), +}; + +struct tuning_t2t_coeffs t12x_tuning_coeffs[] = { + SET_TUNING_COEFFS("sdhci-tegra.3", 1150, 950, 27, 118295, + 27, 118295, 48, 188148), + SET_TUNING_COEFFS("sdhci-tegra.2", 1150, 950, 29, 124427, + 29, 124427, 54, 203707), + SET_TUNING_COEFFS("sdhci-tegra.0", 1150, 950, 25, 115933, + 25, 115933, 47, 187224), +}; + +struct tap_hole_coeffs { + const char *dev_id; + unsigned int freq_khz; + unsigned int thole_vnom_slope; + unsigned int thole_vnom_int; + unsigned int thole_vmax_slope; + unsigned int thole_vmax_int; + unsigned int thole_vmin_slope; + unsigned int thole_vmin_int; +}; + +#define SET_TAP_HOLE_COEFFS(_device_id, _freq_khz, _thole_vnom_slope, \ + _thole_vnom_int, _thole_vmax_slope, _thole_vmax_int, \ + _thole_vmin_slope, _thole_vmin_int) \ + { \ + .dev_id = _device_id, \ + .freq_khz = _freq_khz, \ + .thole_vnom_slope = _thole_vnom_slope, \ + .thole_vnom_int = _thole_vnom_int, \ + .thole_vmax_slope = _thole_vmax_slope, \ + .thole_vmax_int = _thole_vmax_int, \ + .thole_vmin_slope = _thole_vmin_slope, \ + .thole_vmin_int = _thole_vmin_int, \ + } + +struct tap_hole_coeffs t11x_tap_hole_coeffs[] = { + SET_TAP_HOLE_COEFFS("sdhci-tegra.3", 200000, 765, 102357, 507, + 81144, 131, 36346), + SET_TAP_HOLE_COEFFS("sdhci-tegra.3", 156000, 1042, 142044, 776, + 121659, 152, 48728), + SET_TAP_HOLE_COEFFS("sdhci-tegra.3", 136000, 1215, 167702, 905, + 143825, 207, 63477), + SET_TAP_HOLE_COEFFS("sdhci-tegra.3", 81600, 1925, 284516, 1528, + 253188, 366, 120001), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 204000, 472, 53312, 318, + 41756, 84, 15496), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 156000, 765, 95512, 526, + 77404, 134, 33032), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 136000, 949, 121887, 656, + 99684, 165, 43992), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 81600, 1901, 259035, 1334, + 215539, 326, 100986), + SET_TAP_HOLE_COEFFS("sdhci-tegra.0", 204000, 411, 54495, 305, + 46415, 91, 20366), + SET_TAP_HOLE_COEFFS("sdhci-tegra.0", 156000, 715, 97623, 516, + 82375, 145, 38278), + SET_TAP_HOLE_COEFFS("sdhci-tegra.0", 136000, 905, 124579, 648, + 104850, 179, 50204), + SET_TAP_HOLE_COEFFS("sdhci-tegra.0", 81600, 1893, 264746, 1333, + 221722, 354, 109880), +}; + +struct tap_hole_coeffs t12x_tap_hole_coeffs[] = { + SET_TAP_HOLE_COEFFS("sdhci-tegra.3", 200000, 1037, 106934, 1037, + 106934, 558, 74315), + SET_TAP_HOLE_COEFFS("sdhci-tegra.3", 136000, 1703, 186307, 1703, + 186307, 890, 130617), + SET_TAP_HOLE_COEFFS("sdhci-tegra.3", 100000, 2452, 275601, 2452, + 275601, 1264, 193957), + SET_TAP_HOLE_COEFFS("sdhci-tegra.3", 81600, 3090, 351666, 3090, + 351666, 1583, 247913), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 204000, 468, 36031, 468, + 36031, 253, 21264), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 200000, 468, 36031, 468, + 36031, 253, 21264), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 136000, 1146, 117841, 1146, + 117841, 589, 78993), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 100000, 1879, 206195, 1879, + 206195, 953, 141341), + SET_TAP_HOLE_COEFFS("sdhci-tegra.2", 81600, 2504, 281460, 2504, + 281460, 1262, 194452), + SET_TAP_HOLE_COEFFS("sdhci-tegra.0", 204000, 874, 85243, 874, + 85243, 449, 57321), + SET_TAP_HOLE_COEFFS("sdhci-tegra.0", 136000, 1554, 167210, 1554, + 167210, 793, 115672), + SET_TAP_HOLE_COEFFS("sdhci-tegra.0", 100000, 2290, 255734, 2290, + 255734, 1164, 178691), + SET_TAP_HOLE_COEFFS("sdhci-tegra.0", 81600, 2916, 331143, 2916, + 331143, 1480, 232373), +}; struct freq_tuning_constraints { unsigned int vcore_mask; @@ -253,35 +376,57 @@ static struct freq_tuning_constraints tuning_vcore_constraints[3] = { .vcore_mask = BOOT_VCORE_TUN, }, [1] = { - .vcore_mask = BOOT_VCORE_TUN | MIN_OVERRIDE_VCORE_TUN | - NOMINAL_VCORE_TUN, + .vcore_mask = BOOT_VCORE_TUN, }, [2] = { - .vcore_mask = BOOT_VCORE_TUN | NOMINAL_VCORE_TUN, + .vcore_mask = BOOT_VCORE_TUN, }, }; +struct tuning_ui { + int ui; + bool is_valid_ui; +}; + +enum tap_win_edge_attr { + WIN_EDGE_BOUN_START, + WIN_EDGE_BOUN_END, + WIN_EDGE_HOLE, +}; + struct tap_window_data { - bool abandon_partial_win; - bool abandon_full_win; - unsigned int voltage; - u8 partial_win; - u8 full_win_begin; - u8 full_win_end; - u8 vcore_set_status; - u8 found_tuning_window; - u8 tuning_done; + int win_start; + int win_end; + enum tap_win_edge_attr win_start_attr; + enum tap_win_edge_attr win_end_attr; + u8 win_size; + u8 hole_pos; }; +struct tuning_values { + int t2t_vmax; + int t2t_vmin; + int ui; + int ui_vmin; + int vmax_thole; + int vmin_thole; +}; struct tegra_tuning_data { unsigned int freq_hz; - unsigned int best_tap_value; - unsigned int nom_best_tap_value; + int best_tap_value; + int nom_best_tap_value; struct freq_tuning_constraints constraints; - struct tap_window_data *tap_data[TUNING_VOLTAGES_COUNT]; + struct tap_hole_coeffs *thole_coeffs; + struct tuning_t2t_coeffs *t2t_coeffs; + struct tuning_values est_values; + struct tuning_values calc_values; + struct tap_window_data *tap_data; + struct tap_window_data *final_tap_data; + u8 num_of_valid_tap_wins; u8 nr_voltages; u8 freq_band; bool tuning_done; + bool is_partial_win_valid; }; #ifdef CONFIG_MMC_FREQ_SCALING @@ -372,7 +517,7 @@ struct sdhci_tegra { /* Tuning packet size */ unsigned int tuning_bsize; /* Num of tuning freqs selected */ - unsigned int tuning_freq_count; + int tuning_freq_count; unsigned int tap_cmd; /* Tuning status */ unsigned int tuning_status; @@ -382,6 +527,7 @@ struct sdhci_tegra { /* Freq tuning information for each sampling clock freq */ struct tegra_tuning_data tuning_data[DFS_FREQ_COUNT]; struct tegra_freq_gov_data *gov_data; + u32 speedo; }; static struct clk *pll_c; @@ -802,9 +948,11 @@ static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - /* Select Bus Speed Mode for host */ - /* For HS200 we need to set UHS_MODE_SEL to SDR104. + /* Select Bus Speed Mode for host + * For HS200 we need to set UHS_MODE_SEL to SDR104. * It works as SDR 104 in SD 4-bit mode and HS200 in eMMC 8-bit mode. + * SDR50 mode timing seems to have issues. Programming SDR104 + * mode for SDR50 mode for reliable transfers over interface. */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; switch (uhs) { @@ -815,7 +963,7 @@ static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, ctrl_2 |= SDHCI_CTRL_UHS_SDR25; break; case MMC_TIMING_UHS_SDR50: - ctrl_2 |= SDHCI_CTRL_UHS_SDR50; + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; break; case MMC_TIMING_UHS_SDR104: case MMC_TIMING_MMC_HS200: @@ -1016,8 +1164,17 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) /* External loopback is valid for sdmmc3 only */ if ((soc_data->nvquirks & NVQUIRK_DISABLE_EXTERNAL_LOOPBACK) && - (tegra_host->instance == 2)) - misc_ctrl &= ~(1 << SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT); + (tegra_host->instance == 2)) { + if ((tegra_host->tuning_status == TUNING_STATUS_DONE) + && (host->mmc->pm_flags & + MMC_PM_KEEP_POWER)) { + misc_ctrl &= ~(1 << + SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT); + } else { + misc_ctrl |= (1 << + SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT); + } + } sdhci_writel(host, misc_ctrl, SDHCI_VNDR_MISC_CTRL); if (soc_data->nvquirks & NVQUIRK_DISABLE_AUTO_CMD23) @@ -1144,13 +1301,12 @@ static void tegra_sdhci_clock_set_parent(struct sdhci_host *host, if ((pll_c_freq > desired_rate) && (pll_p_freq > desired_rate)) { if (pll_p_freq <= pll_c_freq) { desired_rate = pll_p_freq; - parent_clk = pll_p; + pll_c_freq = 0; } else { desired_rate = pll_c_freq; - parent_clk = pll_c; + pll_p_freq = 0; } rc = clk_set_rate(pltfm_host->clk, desired_rate); - goto set_clk_parent; } if (pll_c_freq > pll_p_freq) { @@ -1166,7 +1322,6 @@ static void tegra_sdhci_clock_set_parent(struct sdhci_host *host, } else return; -set_clk_parent: rc = clk_set_parent(pltfm_host->clk, parent_clk); if (rc) pr_err("%s: failed to set pll parent clock %d\n", @@ -1512,7 +1667,13 @@ static void sdhci_tegra_set_tap_delay(struct sdhci_host *sdhci, u32 vendor_ctrl; /* Max tap delay value is 255 */ - BUG_ON(tap_delay > MAX_TAP_VALUES); + if (tap_delay > MAX_TAP_VALUES) { + dev_err(mmc_dev(sdhci->mmc), + "Valid tap range (0-255). Setting tap value %d\n", + tap_delay); + dump_stack(); + return; + } vendor_ctrl = sdhci_readl(sdhci, SDHCI_VNDR_CLK_CTRL); vendor_ctrl &= ~(0xFF << SDHCI_VNDR_CLK_CTRL_TAP_VALUE_SHIFT); @@ -1567,266 +1728,296 @@ out: return tuning_data; } -static void sdhci_tegra_dump_tuning_data(struct sdhci_host *sdhci) +static void calculate_vmin_values(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data, int vmin, int boot_mv) { - struct tegra_tuning_data *tuning_data; - struct tap_window_data *tap_data; - u8 i; + struct tuning_values *est_values = &tuning_data->est_values; + struct tuning_values *calc_values = &tuning_data->calc_values; + struct tuning_t2t_coeffs *t2t_coeffs = tuning_data->t2t_coeffs; + struct tap_hole_coeffs *thole_coeffs = tuning_data->thole_coeffs; + int vmin_slope, vmin_int, temp_calc_vmin; + int t2t_vmax, t2t_vmin; + int vmax_thole, vmin_thole; - pr_info("********%s: Tuning window data********\n", - mmc_hostname(sdhci->mmc)); - tuning_data = sdhci_tegra_get_tuning_data(sdhci, sdhci->max_clk); - for (i = 0; i < tuning_data->nr_voltages; i++) { - tap_data = tuning_data->tap_data[i]; - pr_info("%dHz: voltage %dmv:\n", sdhci->max_clk, - tap_data->voltage); - pr_info("Partial Win %d, Full win start %d, full win end %d\n", - tap_data->partial_win, - tap_data->full_win_begin, - tap_data->full_win_end); + /* + * If current vmin is equal to vmin or vmax of tuning data, use the + * previously calculated estimated T2T values directly. Note that the + * estimated T2T_vmax is not at Vmax specified in tuning data. It is + * the T2T at the boot or max voltage for the current SKU. Hence, + * boot_mv is used in place of t2t_coeffs->vmax. + */ + if (vmin == t2t_coeffs->vmin) { + t2t_vmin = est_values->t2t_vmin; + } else if (vmin == boot_mv) { + t2t_vmin = est_values->t2t_vmax; + } else { + /* + * For any intermediate voltage between boot voltage and vmin + * of tuning data, calculate the slope and intercept from the + * t2t at boot_mv and vmin and calculate the actual values. + */ + t2t_vmax = 1000 / est_values->t2t_vmax; + t2t_vmin = 1000 / est_values->t2t_vmin; + vmin_slope = ((t2t_vmax - t2t_vmin) * 1000) / + (boot_mv - t2t_coeffs->vmin); + vmin_int = (t2t_vmax * 1000 - (vmin_slope * boot_mv)) / 1000; + t2t_vmin = (vmin_slope * vmin) / 1000 + vmin_int; + t2t_vmin = (1000 / t2t_vmin); } - pr_info("Best tap value %d, best nom voltage tap value %d\n", - tuning_data->best_tap_value, - tuning_data->nom_best_tap_value); - pr_info("*****************************\n"); + + calc_values->t2t_vmin = (t2t_vmin * calc_values->t2t_vmax) / + est_values->t2t_vmax; + + calc_values->ui_vmin = (1000000 / (tuning_data->freq_hz / 1000000)) / + calc_values->t2t_vmin; + + /* Calculate the vmin tap hole at vmin of tuning data */ + temp_calc_vmin = (est_values->t2t_vmin * calc_values->t2t_vmax) / + est_values->t2t_vmax; + vmin_thole = (thole_coeffs->thole_vmin_int - + (thole_coeffs->thole_vmin_slope * temp_calc_vmin)) / + 1000; + vmax_thole = calc_values->vmax_thole; + + if (vmin == t2t_coeffs->vmin) { + calc_values->vmin_thole = vmin_thole; + } else if (vmin == boot_mv) { + calc_values->vmin_thole = vmax_thole; + } else { + /* + * Interpolate the tap hole for any intermediate voltage. + * Calculate the slope and intercept from the available data + * and use them to calculate the actual values. + */ + vmin_slope = ((vmax_thole - vmin_thole) * 1000) / + (boot_mv - t2t_coeffs->vmin); + vmin_int = (vmax_thole * 1000 - (vmin_slope * boot_mv)) / 1000; + calc_values->vmin_thole = (vmin_slope * vmin) / 1000 + vmin_int; + } + + /* Adjust the partial win start for Vmin boundary */ + if (tuning_data->is_partial_win_valid) + tuning_data->final_tap_data[0].win_start = + (tuning_data->final_tap_data[0].win_start * + tuning_data->calc_values.t2t_vmax) / + tuning_data->calc_values.t2t_vmin; + + pr_info("**********Tuning values*********\n"); + pr_info("**estimated values**\n"); + pr_info("T2T_Vmax %d, T2T_Vmin %d, 1'st_hole_Vmax %d, UI_Vmax %d\n", + est_values->t2t_vmax, est_values->t2t_vmin, + est_values->vmax_thole, est_values->ui); + pr_info("**Calculated values**\n"); + pr_info("T2T_Vmax %d, 1'st_hole_Vmax %d, UI_Vmax %d\n", + calc_values->t2t_vmax, calc_values->vmax_thole, + calc_values->ui); + pr_info("T2T_Vmin %d, 1'st_hole_Vmin %d, UI_Vmin %d\n", + calc_values->t2t_vmin, calc_values->vmin_thole, + calc_values->ui_vmin); + pr_info("***********************************\n"); } -/* - * Calculation of best tap value for low frequencies(82MHz). - * X = Partial win, Y = Full win start, Z = Full win end. - * UI = Z - X. - * Full Window = Z - Y. - * Taps margin = mid-point of 1/2*(curr_freq/max_frequency)*UI - * = (1/2)*(1/2)*(82/200)*UI - * = (0.1025)*UI - * if Partial win<(0.22)*UI - * best tap = Y+(0.1025*UI) - * else - * best tap = (X-(Z-Y))+(0.1025*UI) - * If best tap<0, best tap = 0 - */ -static unsigned int calculate_low_freq_tap_value(struct sdhci_host *sdhci, - struct tap_window_data *tap_data) +static int slide_window_start(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data, + int tap_value, enum tap_win_edge_attr edge_attr, int tap_hole) { - unsigned int curr_clock; - unsigned int max_clock; - int best_tap_value; - unsigned int tuning_ui; - unsigned int sampling_point = 0; - bool select_partial_win = false; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; - tuning_ui = tap_data->full_win_end - tap_data->partial_win; + if (edge_attr == WIN_EDGE_BOUN_START) { + if (tap_value < 0) + tap_value += (1000 / tuning_data->calc_values.t2t_vmin); + else + tap_value += (1000 / tuning_data->calc_values.t2t_vmax); + } else if (edge_attr == WIN_EDGE_HOLE) { + if (soc_data->nvquirks & NVQUIRK_TMP_VAR_1_5_TAP_MARGIN) + tap_value += ((7 * tap_hole) / 100) + 2; + else + tap_value += ((7 * tap_hole) / 100) + + (((2 * (450 / tuning_data->calc_values.t2t_vmax)) + + 1) / 2); + } - /* Calculate the sampling point */ - curr_clock = sdhci->max_clk / 1000000; - max_clock = uhs_max_freq_MHz[sdhci->mmc->ios.timing]; - sampling_point = ((tuning_ui * curr_clock) / (max_clock << 2)); + if (tap_value > MAX_TAP_VALUES) + tap_value = MAX_TAP_VALUES; - /* - * Check whether partial window should be used. Use partial window - * if partial window > 0.22(UI). - */ - if ((!tap_data->abandon_partial_win) && - (tap_data->partial_win > ((22 * tuning_ui) / 100))) - select_partial_win = true; - - if (select_partial_win) - best_tap_value = (tap_data->partial_win - - (tap_data->full_win_end - tap_data->full_win_begin)) + - sampling_point; - else - best_tap_value = tap_data->full_win_begin + - sampling_point; + return tap_value; +} + +static int slide_window_end(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data, + int tap_value, enum tap_win_edge_attr edge_attr, int tap_hole) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; - if (best_tap_value < 0) - best_tap_value = 0; + if (edge_attr == WIN_EDGE_BOUN_END) { + tap_value = (tap_value * tuning_data->calc_values.t2t_vmax) / + tuning_data->calc_values.t2t_vmin; + tap_value -= (1000 / tuning_data->calc_values.t2t_vmin); + } else if (edge_attr == WIN_EDGE_HOLE) { + if (tap_hole > 0) + tap_value = tap_hole; + if (soc_data->nvquirks & NVQUIRK_TMP_VAR_1_5_TAP_MARGIN) + tap_value -= ((7 * tap_hole) / 100) + 2; + else + tap_value -= ((7 * tap_hole) / 100) + + (((2 * (450 / tuning_data->calc_values.t2t_vmin)) + + 1) / 2); + } - return best_tap_value; + return tap_value; } -/* - * Calculation of best tap value for high frequencies(156MHz). - * Tap window data at 1.25V core voltage - * X = Partial win, Y = Full win start, Z = Full win end. - * Full Window = Z-Y. - * UI = Z-X. - * Tap_margin = (0.20375)UI - * - * Tap window data at 1.1V core voltage - * X' = Partial win, Y' = Full win start, Z' = Full win end. - * UI' = Z'-X'. - * Full Window' = Z'-Y'. - * Tap_margin' = (0.20375)UI' - * - * Full_window_tap=[(Z'-0.20375UI')+(Y+0.20375UI)]/2 - * Partial_window_tap=[(X'-0.20375UI')+(X-(Z-Y)+0x20375UI)]/2 - * if(Partial_window_tap < 0), Partial_window_tap=0 - * - * Full_window_quality=[(Z'-0.20375UI')-(Y+0.20375UI)]/2 - * Partial_window_quality=(X'-0.20375UI')-Partial_window_tap - * if(Full_window_quality>Partial_window_quality) choose full window, - * else choose partial window. - * If there is no margin window for both cases, - * best tap=(Y+Z')/2. - */ -static unsigned int calculate_high_freq_tap_value(struct sdhci_host *sdhci, - struct tap_window_data *vmax_tap_data, - struct tap_window_data *vmid_tap_data) -{ - unsigned int curr_clock; - unsigned int max_clock; - unsigned int vmax_tuning_ui; - unsigned int vmax_sampling_point; - unsigned int vmid_tuning_ui; - unsigned int vmid_sampling_point; - unsigned int full_win_tap; - int partial_win_start; - int partial_win_tap; - int full_win_quality; - int partial_win_quality; - int best_tap_value; +static int adjust_window_boundaries(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data, + struct tap_window_data *temp_tap_data) +{ + struct tap_window_data *tap_data; + int vmin_tap_hole; + int vmax_tap_hole; + u8 i = 0; - curr_clock = sdhci->max_clk / 1000000; - max_clock = uhs_max_freq_MHz[sdhci->mmc->ios.timing]; + for (i = 0; i < tuning_data->num_of_valid_tap_wins; i++) { + tap_data = &temp_tap_data[i]; + /* Update with next hole if first hole is taken care of */ + if (tap_data->win_start_attr == WIN_EDGE_HOLE) + vmax_tap_hole = tuning_data->calc_values.vmax_thole + + (tap_data->hole_pos - 1) * + tuning_data->calc_values.ui; + tap_data->win_start = slide_window_start(sdhci, tuning_data, + tap_data->win_start, tap_data->win_start_attr, + vmax_tap_hole); + + /* Update with next hole if first hole is taken care of */ + if (tap_data->win_end_attr == WIN_EDGE_HOLE) + vmin_tap_hole = tuning_data->calc_values.vmin_thole + + (tap_data->hole_pos - 1) * + tuning_data->calc_values.ui_vmin; + tap_data->win_end = slide_window_end(sdhci, tuning_data, + tap_data->win_end, tap_data->win_end_attr, + vmin_tap_hole); + } - /* - * Calculate the tuning_ui and sampling points for tap windows found - * at all core voltages. - */ - vmax_tuning_ui = vmax_tap_data->full_win_end - - vmax_tap_data->partial_win; - vmax_sampling_point = (vmax_tuning_ui * curr_clock) / (max_clock << 2); - - vmid_tuning_ui = vmid_tap_data->full_win_end - - vmid_tap_data->partial_win; - vmid_sampling_point = (vmid_tuning_ui * curr_clock) / (max_clock << 2); - - full_win_tap = ((vmid_tap_data->full_win_end - vmid_sampling_point) + - (vmax_tap_data->full_win_begin + vmax_sampling_point)); - full_win_tap >>= 1; - full_win_quality = (vmid_tap_data->full_win_end - - vmid_sampling_point) - (vmax_tap_data->full_win_begin + - vmax_sampling_point); - full_win_quality >>= 1; - - partial_win_start = (vmax_tap_data->partial_win - - (vmax_tap_data->full_win_end - - vmax_tap_data->full_win_begin)); - partial_win_tap = ((vmid_tap_data->partial_win - vmid_sampling_point) + - (partial_win_start + vmax_sampling_point)); - partial_win_tap >>= 1; - - if (partial_win_tap < 0) - partial_win_tap = 0; - partial_win_quality = (vmid_tap_data->partial_win - - vmid_sampling_point) - partial_win_tap; - - if ((full_win_quality <= 0) && (partial_win_quality <= 0)) { - dev_warn(mmc_dev(sdhci->mmc), - "No margin window for both windows\n"); - best_tap_value = vmax_tap_data->full_win_begin + - vmid_tap_data->full_win_end; - best_tap_value >>= 1; + pr_info("***********final tuning windows**********\n"); + for (i = 0; i < tuning_data->num_of_valid_tap_wins; i++) { + tap_data = &temp_tap_data[i]; + pr_info("win[%d]: %d - %d\n", i, tap_data->win_start, + tap_data->win_end); + } + pr_info("********************************\n"); + return 0; +} + +static int find_best_tap_value(struct tegra_tuning_data *tuning_data, + struct tap_window_data *temp_tap_data, int vmin) +{ + struct tap_window_data *tap_data; + u8 i = 0, sel_win = 0; + int pref_win = 0, curr_win_size = 0; + int best_tap_value = 0; + + for (i = 0; i < tuning_data->num_of_valid_tap_wins; i++) { + tap_data = &temp_tap_data[i]; + if (!i && tuning_data->is_partial_win_valid) { + pref_win = tap_data->win_end - tap_data->win_start; + if ((tap_data->win_end * 2) < pref_win) + pref_win = tap_data->win_end * 2; + sel_win = 0; + } else { + curr_win_size = tap_data->win_end - tap_data->win_start; + if ((curr_win_size > 0) && (curr_win_size > pref_win)) { + pref_win = curr_win_size; + sel_win = i; + } + } + } + + if (pref_win <= 0) { + pr_err("No window opening for %d vmin\n", vmin); + return -1; + } + + tap_data = &temp_tap_data[sel_win]; + if (!sel_win && tuning_data->is_partial_win_valid) { + i = sel_win; + best_tap_value = tap_data->win_end - (pref_win / 2); + if (best_tap_value < 0) + best_tap_value = 0; } else { - if (full_win_quality > partial_win_quality) - best_tap_value = full_win_tap; - else - best_tap_value = partial_win_tap; + best_tap_value = tap_data->win_start + + ((tap_data->win_end - tap_data->win_start) * + tuning_data->calc_values.t2t_vmin) / + (tuning_data->calc_values.t2t_vmin + + tuning_data->calc_values.t2t_vmax); } - if (best_tap_value < 0) - best_tap_value = 0; + pr_info("best tap win - (%d-%d), best tap value %d\n", + tap_data->win_start, tap_data->win_end, best_tap_value); return best_tap_value; } -static void sdhci_tegra_calculate_best_tap(struct sdhci_host *sdhci, - u8 freq_band) +static int sdhci_tegra_calculate_best_tap(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); struct sdhci_tegra *tegra_host = pltfm_host->priv; - struct tegra_tuning_data *tuning_data; - unsigned int vdd_core; - int delta_vdd; - unsigned int voltage = 0; + struct tap_window_data *temp_tap_data = NULL; + int vmin, curr_vmin, best_tap_value = 0; + int err = 0; - SDHCI_TEGRA_DBG("%s: calculating best tap for freq band %d\n", - mmc_hostname(sdhci->mmc), freq_band); - SDHCI_TEGRA_DBG("%s: Best tap %s nom best tap\n", - mmc_hostname(sdhci->mmc), - (tegra_host->plat->en_nominal_vcore_tuning) ? "different from" : - "same as"); + curr_vmin = tegra_dvfs_predict_millivolts(pltfm_host->clk, + tuning_data->freq_hz); + vmin = curr_vmin; - tuning_data = sdhci_tegra_get_tuning_data(sdhci, sdhci->max_clk); + do { + SDHCI_TEGRA_DBG("%s: checking for win opening with vmin %d\n", + mmc_hostname(sdhci->mmc), vmin); + if ((best_tap_value < 0) && + (vmin > tegra_host->boot_vcore_mv)) { + dev_err(mmc_dev(sdhci->mmc), + "No best tap for any vcore range\n"); + return -EINVAL; + } - if (tuning_data->tap_data[0] && tuning_data->tap_data[1] && - (tegra_host->soc_data->nvquirks & - NVQUIRK_HIGH_FREQ_TAP_PROCEDURE)) { - voltage = tuning_data->tap_data[0]->voltage - - tuning_data->tap_data[1]->voltage; - - if (voltage > 0 && (freq_band == TUNING_LOW_FREQ || - freq_band == TUNING_HIGH_FREQ)) { - vdd_core = - tegra_host->soc_data->tuning_min_volt_list[freq_band]; - delta_vdd = tuning_data->tap_data[1]->voltage - - vdd_core; - tuning_data->tap_data[1]->partial_win = - ((tuning_data->tap_data[0]->partial_win - - tuning_data->tap_data[1]->partial_win) * - delta_vdd) / voltage + - tuning_data->tap_data[1]->partial_win; - tuning_data->tap_data[1]->full_win_begin = - ((tuning_data->tap_data[0]->full_win_begin - - tuning_data->tap_data[1]->full_win_begin) * - delta_vdd) / voltage + - tuning_data->tap_data[1]->full_win_begin; - tuning_data->tap_data[1]->full_win_end = - -((tuning_data->tap_data[0]->full_win_end - - tuning_data->tap_data[1]->full_win_end) * - (delta_vdd / voltage)) + - tuning_data->tap_data[1]->full_win_end; - } - } - - if (freq_band == TUNING_LOW_FREQ) { - if (tegra_host->soc_data->nvquirks & - NVQUIRK_HIGH_FREQ_TAP_PROCEDURE) - tuning_data->nom_best_tap_value = - calculate_high_freq_tap_value(sdhci, - tuning_data->tap_data[0], - tuning_data->tap_data[1]); - else - tuning_data->nom_best_tap_value = - calculate_low_freq_tap_value(sdhci, - tuning_data->tap_data[0]); - tuning_data->best_tap_value = tuning_data->nom_best_tap_value; - } else if (freq_band == TUNING_HIGH_FREQ) { - tuning_data->nom_best_tap_value = - calculate_high_freq_tap_value(sdhci, - tuning_data->tap_data[0], tuning_data->tap_data[1]); - if (!tegra_host->plat->en_nominal_vcore_tuning) { - tuning_data->best_tap_value = - tuning_data->nom_best_tap_value; - } else { - tuning_data->best_tap_value = - calculate_high_freq_tap_value(sdhci, - tuning_data->tap_data[1], - tuning_data->tap_data[2]); - } - } else if (freq_band == TUNING_MAX_FREQ) { - tuning_data->nom_best_tap_value = calculate_high_freq_tap_value( - sdhci, tuning_data->tap_data[0], - tuning_data->tap_data[0]); - if (!tegra_host->plat->en_nominal_vcore_tuning) { - tuning_data->best_tap_value = - tuning_data->nom_best_tap_value; - } else { - tuning_data->best_tap_value = - calculate_high_freq_tap_value(sdhci, - tuning_data->tap_data[1], - tuning_data->tap_data[1]); + calculate_vmin_values(sdhci, tuning_data, vmin, + tegra_host->boot_vcore_mv); + + if (temp_tap_data == NULL) { + temp_tap_data = kzalloc(sizeof(struct tap_window_data) * + tuning_data->num_of_valid_tap_wins, GFP_KERNEL); + if (IS_ERR_OR_NULL(temp_tap_data)) { + dev_err(mmc_dev(sdhci->mmc), + "No memory for final tap value calculation\n"); + return -ENOMEM; + } } - } + + memcpy(temp_tap_data, tuning_data->final_tap_data, + sizeof(struct tap_window_data) * + tuning_data->num_of_valid_tap_wins); + + adjust_window_boundaries(sdhci, tuning_data, temp_tap_data); + + best_tap_value = find_best_tap_value(tuning_data, + temp_tap_data, vmin); + + if (best_tap_value < 0) + vmin += 50; + } while (best_tap_value < 0); + + tuning_data->best_tap_value = best_tap_value; + tuning_data->nom_best_tap_value = best_tap_value; + + /* Set the new vmin if there is any change. */ + if ((tuning_data->best_tap_value >= 0) && (curr_vmin != vmin)) + err = tegra_dvfs_set_fmax_at_vmin(pltfm_host->clk, + tuning_data->freq_hz, vmin); + + kfree(temp_tap_data); + return err; } static int sdhci_tegra_issue_tuning_cmd(struct sdhci_host *sdhci) @@ -1946,89 +2137,545 @@ static int sdhci_tegra_scan_tap_values(struct sdhci_host *sdhci, return tap_value; } -/* - * While scanning for tap values, first get the partial window followed by the - * full window. Note that, when scanning for full win start, tuning has to be - * run until a passing tap value is found. Hence, failure is expected during - * this process and ignored. - */ -static int sdhci_tegra_get_tap_window_data(struct sdhci_host *sdhci, - struct tap_window_data *tap_data) +static int calculate_actual_tuning_values(int speedo, + struct tegra_tuning_data *tuning_data, int voltage_mv) { - unsigned int tap_value; - unsigned int full_win_percentage = 0; - int err = 0; + struct tuning_t2t_coeffs *t2t_coeffs = tuning_data->t2t_coeffs; + struct tap_hole_coeffs *thole_coeffs = tuning_data->thole_coeffs; + struct tuning_values *calc_values = &tuning_data->calc_values; + int slope, inpt; + int vmax_thole, vmin_thole; + + /* T2T_Vmax = (1000000/freq_MHz)/Calc_UI */ + calc_values->t2t_vmax = (1000000 / (tuning_data->freq_hz / 1000000)) / + calc_values->ui; - if (!tap_data) { - dev_err(mmc_dev(sdhci->mmc), "Invalid tap data\n"); - return -ENODATA; + /* + * Interpolate the tap hole. + * Vmax_1'st_hole = (Calc_T2T_Vmax*(-thole_slope)+thole_tint. + */ + vmax_thole = (thole_coeffs->thole_vmax_int - + (thole_coeffs->thole_vmax_slope * calc_values->t2t_vmax)) / + 1000; + vmin_thole = (thole_coeffs->thole_vmin_int - + (thole_coeffs->thole_vmin_slope * calc_values->t2t_vmax)) / + 1000; + if (voltage_mv == t2t_coeffs->vmin) { + calc_values->vmax_thole = vmin_thole; + } else if (voltage_mv == t2t_coeffs->vmax) { + calc_values->vmax_thole = vmax_thole; + } else { + slope = (vmax_thole - vmin_thole) / + (t2t_coeffs->vmax - t2t_coeffs->vmin); + inpt = ((vmax_thole * 1000) - (slope * 1250)) / 1000; + calc_values->vmax_thole = slope * voltage_mv + inpt; } - /* Get the partial window data */ - tap_value = 0; - tap_value = sdhci_tegra_scan_tap_values(sdhci, tap_value, false); - if (!tap_value) { - tap_data->abandon_partial_win = true; - tap_data->partial_win = 0; - } else if (tap_value > MAX_TAP_VALUES) { + return 0; +} + +/* + * All coeffs are filled up in the table after multiplying by 1000. So, all + * calculations should have a divide by 1000 at the end. + */ +static int calculate_estimated_tuning_values(int speedo, + struct tegra_tuning_data *tuning_data, int voltage_mv) +{ + struct tuning_t2t_coeffs *t2t_coeffs = tuning_data->t2t_coeffs; + struct tap_hole_coeffs *thole_coeffs = tuning_data->thole_coeffs; + struct tuning_values *est_values = &tuning_data->est_values; + int slope, inpt; + int vmax_t2t, vmin_t2t; + int vmax_thole, vmin_thole; + + /* Est_T2T_Vmax = (speedo*(-t2t_slope)+t2t_int */ + vmax_t2t = (t2t_coeffs->t2t_vmax_int - (speedo * + t2t_coeffs->t2t_vmax_slope)) / 1000; + vmin_t2t = (t2t_coeffs->t2t_vmin_int - (speedo * + t2t_coeffs->t2t_vmin_slope)) / 1000; + est_values->t2t_vmin = vmin_t2t; + + if (voltage_mv == t2t_coeffs->vmin) { + est_values->t2t_vmax = vmin_t2t; + } else if (voltage_mv == t2t_coeffs->vmax) { + est_values->t2t_vmax = vmax_t2t; + } else { + vmax_t2t = 1000 / vmax_t2t; + vmin_t2t = 1000 / vmin_t2t; /* - * If tap value is more than 0xFF, we have hit the miracle case - * of all tap values passing. Discard full window as passing - * window has covered all taps. + * For any intermediate voltage between 0.95V and 1.25V, + * calculate the slope and intercept from the T2T and tap hole + * values of 0.95V and 1.25V and use them to calculate the + * actual values. 1/T2T is a linear function of voltage. */ - tap_data->partial_win = MAX_TAP_VALUES; - tap_data->abandon_full_win = true; - goto out; + slope = ((vmax_t2t - vmin_t2t) * 1000) / + (t2t_coeffs->vmax - t2t_coeffs->vmin); + inpt = (vmax_t2t * 1000 - (slope * t2t_coeffs->vmax)) / 1000; + est_values->t2t_vmax = (slope * voltage_mv) / 1000 + inpt; + est_values->t2t_vmax = (1000 / est_values->t2t_vmax); + } + + /* Est_UI = (1000000/freq_MHz)/Est_T2T_Vmax */ + est_values->ui = (1000000 / (thole_coeffs->freq_khz / 1000)) / + est_values->t2t_vmax; + + /* + * Est_1'st_hole = (Est_T2T_Vmax*(-thole_slope)) + thole_int. + */ + vmax_thole = (thole_coeffs->thole_vmax_int - + (thole_coeffs->thole_vmax_slope * est_values->t2t_vmax)) / 1000; + vmin_thole = (thole_coeffs->thole_vmin_int - + (thole_coeffs->thole_vmin_slope * est_values->t2t_vmax)) / 1000; + + if (voltage_mv == t2t_coeffs->vmin) { + est_values->vmax_thole = vmin_thole; + } else if (voltage_mv == t2t_coeffs->vmax) { + est_values->vmax_thole = vmax_thole; } else { - tap_data->partial_win = tap_value - 1; - if (tap_value == MAX_TAP_VALUES) { - /* All tap values exhausted. No full window */ - tap_data->abandon_full_win = true; - goto out; + /* + * For any intermediate voltage between 0.95V and 1.25V, + * calculate the slope and intercept from the t2t and tap hole + * values of 0.95V and 1.25V and use them to calculate the + * actual values. Tap hole is a linear function of voltage. + */ + slope = ((vmax_thole - vmin_thole) * 1000) / + (t2t_coeffs->vmax - t2t_coeffs->vmin); + inpt = (vmax_thole * 1000 - (slope * t2t_coeffs->vmax)) / 1000; + est_values->vmax_thole = (slope * voltage_mv) / 1000 + inpt; + } + est_values->vmin_thole = vmin_thole; + + return 0; +} + +/* + * Insert the calculated holes and get the final tap windows + * with the boundaries and holes set. + */ +static int adjust_holes_in_tap_windows(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data) +{ + struct tap_window_data *tap_data; + struct tap_window_data *final_tap_data; + struct tuning_values *calc_values = &tuning_data->calc_values; + int tap_hole, size = 0; + u8 i = 0, j = 0, num_of_wins, hole_pos = 0; + + tuning_data->final_tap_data = + devm_kzalloc(mmc_dev(sdhci->mmc), + sizeof(struct tap_window_data) * 42, GFP_KERNEL); + if (IS_ERR_OR_NULL(tuning_data->final_tap_data)) { + dev_err(mmc_dev(sdhci->mmc), "No mem for final tap wins\n"); + return -ENOMEM; + } + + num_of_wins = tuning_data->num_of_valid_tap_wins; + tap_hole = calc_values->vmax_thole; + hole_pos++; + do { + tap_data = &tuning_data->tap_data[i]; + final_tap_data = &tuning_data->final_tap_data[j]; + if (tap_hole < tap_data->win_start) { + tap_hole += calc_values->ui; + hole_pos++; + continue; + } else if (tap_hole > tap_data->win_end) { + memcpy(final_tap_data, tap_data, + sizeof(struct tap_window_data)); + i++; + j++; + num_of_wins--; + continue; + } else if ((tap_hole >= tap_data->win_start) && + (tap_hole <= tap_data->win_end)) { + size = tap_data->win_end - tap_data->win_start; + do { + final_tap_data = + &tuning_data->final_tap_data[j]; + if (tap_hole == tap_data->win_start) { + final_tap_data->win_start = + tap_hole + 1; + final_tap_data->win_start_attr = + WIN_EDGE_HOLE; + final_tap_data->hole_pos = hole_pos; + tap_hole += calc_values->ui; + hole_pos++; + } else { + final_tap_data->win_start = + tap_data->win_start; + final_tap_data->win_start_attr = + WIN_EDGE_BOUN_START; + } + if (tap_hole <= tap_data->win_end) { + final_tap_data->win_end = tap_hole - 1; + final_tap_data->win_end_attr = + WIN_EDGE_HOLE; + final_tap_data->hole_pos = hole_pos; + tap_data->win_start = tap_hole; + } else if (tap_hole > tap_data->win_end) { + final_tap_data->win_end = + tap_data->win_end; + final_tap_data->win_end_attr = + WIN_EDGE_BOUN_END; + tap_data->win_start = + tap_data->win_end; + } + size = tap_data->win_end - tap_data->win_start; + j++; + } while (size > 0); + i++; + num_of_wins--; } + } while (num_of_wins > 0); + + /* Update the num of valid wins count after tap holes insertion */ + tuning_data->num_of_valid_tap_wins = j; + + pr_info("********tuning windows after inserting holes*****\n"); + pr_info("WIN_ATTR legend: 0-BOUN_ST, 1-BOUN_END, 2-HOLE\n"); + for (i = 0; i < tuning_data->num_of_valid_tap_wins; i++) { + final_tap_data = &tuning_data->final_tap_data[i]; + pr_info("win[%d]:%d(%d) - %d(%d)\n", i, + final_tap_data->win_start, + final_tap_data->win_start_attr, + final_tap_data->win_end, final_tap_data->win_end_attr); } + pr_info("***********************************************\n"); + return 0; +} + +/* + * Insert the boundaries from negative margin calculations into the windows + * from auto tuning. + */ +static int insert_boundaries_in_tap_windows(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data, u8 boun_end) +{ + struct tap_window_data *tap_data; + struct tap_window_data *new_tap_data; + struct tap_window_data *temp_tap_data; + struct tuning_values *calc_values = &tuning_data->calc_values; + int curr_boun; + u8 i = 0, j = 0, num_of_wins; + bool get_next_boun = false; + + temp_tap_data = devm_kzalloc(mmc_dev(sdhci->mmc), + sizeof(struct tap_window_data) * 42, GFP_KERNEL); + if (IS_ERR_OR_NULL(temp_tap_data)) { + dev_err(mmc_dev(sdhci->mmc), "No mem for final tap wins\n"); + return -ENOMEM; + } + + num_of_wins = tuning_data->num_of_valid_tap_wins; + curr_boun = boun_end % calc_values->ui; do { - /* Get the full window start */ - tap_value++; - tap_value = sdhci_tegra_scan_tap_values(sdhci, tap_value, true); - if (tap_value > MAX_TAP_VALUES) { - /* All tap values exhausted. No full window */ - tap_data->abandon_full_win = true; - goto out; - } else { - tap_data->full_win_begin = tap_value; + if (get_next_boun) { + curr_boun += calc_values->ui; /* - * If full win start is 0xFF, then set that as - * full win end and exit. + * If the boun_end exceeds the intial boundary end, + * just copy remaining windows and return. */ - if (tap_value == MAX_TAP_VALUES) { - tap_data->full_win_end = tap_value; - goto out; - } + if (curr_boun >= boun_end) + curr_boun += MAX_TAP_VALUES; + } + + tap_data = &tuning_data->tap_data[i]; + new_tap_data = &temp_tap_data[j]; + if (curr_boun <= tap_data->win_start) { + get_next_boun = true; + continue; + } else if (curr_boun >= tap_data->win_end) { + memcpy(new_tap_data, tap_data, + sizeof(struct tap_window_data)); + i++; + j++; + num_of_wins--; + get_next_boun = false; + continue; + } else if ((curr_boun >= tap_data->win_start) && + (curr_boun <= tap_data->win_end)) { + new_tap_data->win_start = tap_data->win_start; + new_tap_data->win_start_attr = + tap_data->win_start_attr; + new_tap_data->win_end = curr_boun - 1; + new_tap_data->win_end_attr = + tap_data->win_end_attr; + j++; + new_tap_data = &temp_tap_data[j]; + new_tap_data->win_start = curr_boun; + new_tap_data->win_end = curr_boun; + new_tap_data->win_start_attr = + WIN_EDGE_BOUN_START; + new_tap_data->win_end_attr = + WIN_EDGE_BOUN_END; + j++; + new_tap_data = &temp_tap_data[j]; + new_tap_data->win_start = curr_boun + 1; + new_tap_data->win_start_attr = WIN_EDGE_BOUN_START; + new_tap_data->win_end = tap_data->win_end; + new_tap_data->win_end_attr = + tap_data->win_end_attr; + i++; + j++; + num_of_wins--; + get_next_boun = true; } + } while (num_of_wins > 0); + + /* Update the num of valid wins count after tap holes insertion */ + tuning_data->num_of_valid_tap_wins = j; + + memcpy(tuning_data->tap_data, temp_tap_data, + j * sizeof(struct tap_window_data)); + SDHCI_TEGRA_DBG("***tuning windows after inserting boundaries***\n"); + SDHCI_TEGRA_DBG("WIN_ATTR legend: 0-BOUN_ST, 1-BOUN_END, 2-HOLE\n"); + for (i = 0; i < tuning_data->num_of_valid_tap_wins; i++) { + new_tap_data = &tuning_data->tap_data[i]; + SDHCI_TEGRA_DBG("win[%d]:%d(%d) - %d(%d)\n", i, + new_tap_data->win_start, + new_tap_data->win_start_attr, + new_tap_data->win_end, new_tap_data->win_end_attr); + } + SDHCI_TEGRA_DBG("***********************************************\n"); + + return 0; +} - /* Get the full window end */ +/* + * Scan for all tap values and get all passing tap windows. + */ +static int sdhci_tegra_get_tap_window_data(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + struct tap_window_data *tap_data; + struct tuning_ui tuning_ui[10]; + int err = 0, partial_win_start = 0, temp_margin = 0; + unsigned int tap_value, calc_ui = 0; + u8 prev_boundary_end = 0, num_of_wins = 0; + u8 num_of_uis = 0, valid_num_uis = 0; + u8 ref_ui, first_valid_full_win = 0; + u8 boun_end = 0, next_boun_end = 0; + u8 j = 0; + bool valid_ui_found = false; + + /* + * Assume there are a max of 10 windows and allocate tap window + * structures for the same. If there are more windows, the array + * size can be adjusted later using realloc. + */ + tuning_data->tap_data = devm_kzalloc(mmc_dev(sdhci->mmc), + sizeof(struct tap_window_data) * 42, GFP_KERNEL); + if (IS_ERR_OR_NULL(tuning_data->tap_data)) { + dev_err(mmc_dev(sdhci->mmc), "No memory for tap data\n"); + return -ENOMEM; + } + + spin_lock(&sdhci->lock); + tap_value = 0; + do { + tap_data = &tuning_data->tap_data[num_of_wins]; + /* Get the window start */ + tap_value = sdhci_tegra_scan_tap_values(sdhci, tap_value, true); + tap_data->win_start = min_t(u8, tap_value, MAX_TAP_VALUES); tap_value++; + if (tap_value >= MAX_TAP_VALUES) { + /* If it's first iteration, then all taps failed */ + if (!num_of_wins) { + dev_err(mmc_dev(sdhci->mmc), + "All tap values(0-255) failed\n"); + spin_unlock(&sdhci->lock); + return -EINVAL; + } else { + /* All windows obtained */ + break; + } + } + + /* Get the window end */ tap_value = sdhci_tegra_scan_tap_values(sdhci, tap_value, false); - tap_data->full_win_end = tap_value - 1; - if (tap_value > MAX_TAP_VALUES) - tap_data->full_win_end = MAX_TAP_VALUES; - full_win_percentage = ((tap_data->full_win_end - - tap_data->full_win_begin) * 100) / - (tap_data->partial_win + 1); - } while (full_win_percentage < 50 && tap_value < MAX_TAP_VALUES); - - if (full_win_percentage < 50) - tap_data->abandon_full_win = true; -out: + tap_data->win_end = min_t(u8, (tap_value - 1), MAX_TAP_VALUES); + tap_data->win_size = tap_data->win_end - tap_data->win_start; + tap_value++; + + /* + * If the size of window is more than 4 taps wide, then it is a + * valid window. If tap value 0 has passed, then a partial + * window exists. Mark all the window edges as boundary edges. + */ + if (tap_data->win_size > 4) { + if (tap_data->win_start == 0) + tuning_data->is_partial_win_valid = true; + tap_data->win_start_attr = WIN_EDGE_BOUN_START; + tap_data->win_end_attr = WIN_EDGE_BOUN_END; + } else { + /* Invalid window as size is less than 5 taps */ + SDHCI_TEGRA_DBG("Invalid tuning win (%d-%d) ignored\n", + tap_data->win_start, tap_data->win_end); + continue; + } + + /* Ignore first and last partial UIs */ + if (tap_data->win_end_attr == WIN_EDGE_BOUN_END) { + tuning_ui[num_of_uis].ui = tap_data->win_end - + prev_boundary_end; + tuning_ui[num_of_uis].is_valid_ui = true; + num_of_uis++; + prev_boundary_end = tap_data->win_end; + } + num_of_wins++; + } while (tap_value < MAX_TAP_VALUES); + spin_unlock(&sdhci->lock); + + tuning_data->num_of_valid_tap_wins = num_of_wins; + valid_num_uis = num_of_uis; + + /* Print info of all tap windows */ + pr_info("**********Auto tuning windows*************\n"); + pr_info("WIN_ATTR legend: 0-BOUN_ST, 1-BOUN_END, 2-HOLE\n"); + for (j = 0; j < tuning_data->num_of_valid_tap_wins; j++) { + tap_data = &tuning_data->tap_data[j]; + pr_info("win[%d]: %d(%d) - %d(%d)\n", + j, tap_data->win_start, tap_data->win_start_attr, + tap_data->win_end, tap_data->win_end_attr); + } + pr_info("***************************************\n"); + + /* Mark the first last partial UIs as invalid */ + tuning_ui[0].is_valid_ui = false; + tuning_ui[num_of_uis - 1].is_valid_ui = false; + valid_num_uis -= 2; + + /* Discredit all uis at either end with size less than 30% of est ui */ + ref_ui = (30 * tuning_data->est_values.ui) / 100; + for (j = 0; j < num_of_uis; j++) { + if (tuning_ui[j].is_valid_ui) { + tuning_ui[j].is_valid_ui = false; + valid_num_uis--; + } + if (tuning_ui[j].ui > ref_ui) + break; + } + + for (j = num_of_uis; j > 0; j--) { + if (tuning_ui[j - 1].ui < ref_ui) { + if (tuning_ui[j - 1].is_valid_ui) { + tuning_ui[j - 1].is_valid_ui = false; + valid_num_uis--; + } + } else + break; + } + + /* Calculate 0.75*est_UI */ + ref_ui = (75 * tuning_data->est_values.ui) / 100; + /* - * Mark tuning as failed if both partial and full windows are - * abandoned. + * Check for valid UIs and discredit invalid UIs. A UI is considered + * valid if it's greater than (0.75*est_UI). If an invalid UI is found, + * also discredit the smaller of the two adjacent windows. */ - if (tap_data->abandon_partial_win && tap_data->abandon_full_win) - err = -EIO; + for (j = 1; j < (num_of_uis - 1); j++) { + if (tuning_ui[j].ui > ref_ui && tuning_ui[j].is_valid_ui) { + tuning_ui[j].is_valid_ui = true; + } else { + if (tuning_ui[j].is_valid_ui) { + tuning_ui[j].is_valid_ui = false; + valid_num_uis--; + } + if (!tuning_ui[j + 1].is_valid_ui || + !tuning_ui[j - 1].is_valid_ui) { + if (tuning_ui[j - 1].is_valid_ui) { + tuning_ui[j - 1].is_valid_ui = false; + valid_num_uis--; + } else if (tuning_ui[j + 1].is_valid_ui) { + tuning_ui[j + 1].is_valid_ui = false; + valid_num_uis--; + } + } else { + + if (tuning_ui[j - 1].ui > tuning_ui[j + 1].ui) + tuning_ui[j + 1].is_valid_ui = false; + else + tuning_ui[j - 1].is_valid_ui = false; + valid_num_uis--; + } + } + } + + /* Calculate the cumulative UI if there are valid UIs left */ + if (valid_num_uis) { + for (j = 0; j < num_of_uis; j++) + if (tuning_ui[j].is_valid_ui) { + calc_ui += tuning_ui[j].ui; + if (!first_valid_full_win) + first_valid_full_win = j; + } + } + + if (calc_ui) { + tuning_data->calc_values.ui = (calc_ui / valid_num_uis); + valid_ui_found = true; + } else { + tuning_data->calc_values.ui = tuning_data->est_values.ui; + valid_ui_found = false; + } + + SDHCI_TEGRA_DBG("****Tuning UIs***********\n"); + for (j = 0; j < num_of_uis; j++) + SDHCI_TEGRA_DBG("Tuning UI[%d] : %d, Is valid[%d]\n", + j, tuning_ui[j].ui, tuning_ui[j].is_valid_ui); + SDHCI_TEGRA_DBG("*************************\n"); + + /* Get the calculated tuning values */ + err = calculate_actual_tuning_values(tegra_host->speedo, tuning_data, + tegra_host->boot_vcore_mv); + + /* + * Calculate negative margin if partial win is valid. There are two + * cases here. + * Case 1: If Avg_UI is found, then keep subtracting avg_ui from start + * of first valid full window until a value <=0 is obtained. + * Case 2: If Avg_UI is not found, subtract avg_ui from all boundary + * starts until a value <=0 is found. + */ + if (tuning_data->is_partial_win_valid && (num_of_wins > 1)) { + if (valid_ui_found) { + partial_win_start = + tuning_data->tap_data[first_valid_full_win].win_start; + boun_end = partial_win_start; + partial_win_start %= tuning_data->calc_values.ui; + partial_win_start -= tuning_data->calc_values.ui; + } else { + for (j = 0; j < NEG_MAR_CHK_WIN_COUNT; j++) { + temp_margin = + tuning_data->tap_data[j + 1].win_start; + if (!boun_end) + boun_end = temp_margin; + else if (!next_boun_end) + next_boun_end = temp_margin; + temp_margin %= tuning_data->calc_values.ui; + temp_margin -= tuning_data->calc_values.ui; + if (!partial_win_start || + (temp_margin > partial_win_start)) + partial_win_start = temp_margin; + } + } + if (partial_win_start <= 0) + tuning_data->tap_data[0].win_start = partial_win_start; + } + + if (boun_end) + insert_boundaries_in_tap_windows(sdhci, tuning_data, boun_end); + if (next_boun_end) + insert_boundaries_in_tap_windows(sdhci, tuning_data, next_boun_end); + + /* Insert calculated holes into the windows */ + err = adjust_holes_in_tap_windows(sdhci, tuning_data); + return err; } @@ -2037,8 +2684,7 @@ static void sdhci_tegra_dump_tuning_constraints(struct sdhci_host *sdhci) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); struct sdhci_tegra *tegra_host = pltfm_host->priv; struct tegra_tuning_data *tuning_data; - struct tap_window_data *tap_data; - u8 i, j; + u8 i; SDHCI_TEGRA_DBG("%s: Num of tuning frequencies%d\n", mmc_hostname(sdhci->mmc), tegra_host->tuning_freq_count); @@ -2047,12 +2693,6 @@ static void sdhci_tegra_dump_tuning_constraints(struct sdhci_host *sdhci) SDHCI_TEGRA_DBG("%s: Tuning freq[%d]: %d, freq band %d\n", mmc_hostname(sdhci->mmc), i, tuning_data->freq_hz, tuning_data->freq_band); - SDHCI_TEGRA_DBG("%s: Supported voltages:", - mmc_hostname(sdhci->mmc)); - for (j = 0; j < tuning_data->nr_voltages; ++j) { - tap_data = tuning_data->tap_data[j]; - SDHCI_TEGRA_DBG("%d,", tap_data->voltage); - } } } @@ -2074,40 +2714,6 @@ static unsigned int get_tuning_voltage(struct sdhci_tegra *tegra_host, u8 *mask) return tegra_host->boot_vcore_mv; } -static int sdhci_tegra_setup_vcore_constraints(struct sdhci_host *sdhci) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - struct freq_tuning_constraints *constraints; - struct tegra_tuning_data *tuning_data; - struct tap_window_data *tap_data; - u8 freq_count = tegra_host->tuning_freq_count; - u8 nr_voltages, i, j, vcore_mask; - - for (i = 0; i < freq_count; i++) { - tuning_data = &tegra_host->tuning_data[i]; - constraints = &tuning_data->constraints; - nr_voltages = hweight32(constraints->vcore_mask); - SDHCI_TEGRA_DBG("%s: %dHz: vcore mask %#x, nr voltages %d\n", - mmc_hostname(sdhci->mmc), tuning_data->freq_hz, - constraints->vcore_mask, nr_voltages); - vcore_mask = constraints->vcore_mask; - for (j = 0; j < nr_voltages; j++) { - tap_data = devm_kzalloc( - mmc_dev(sdhci->mmc), - sizeof(struct tap_window_data), - GFP_KERNEL); - if (!tap_data) - return -ENOMEM; - tap_data->voltage = get_tuning_voltage(tegra_host, - &vcore_mask); - tuning_data->tap_data[j] = tap_data; - } - tuning_data->nr_voltages = nr_voltages; - } - return 0; -} - static u8 sdhci_tegra_get_freq_point(struct sdhci_host *sdhci) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); @@ -2126,20 +2732,97 @@ static u8 sdhci_tegra_get_freq_point(struct sdhci_host *sdhci) return TUNING_MAX_FREQ; } +/* + * The frequency tuning algorithm tries to calculate the tap-to-tap delay + * UI and estimate holes using equations and predetermined coefficients from + * the characterization data. The algorithm will not work without this data. + */ +static int find_tuning_coeffs_data(struct sdhci_host *sdhci, + bool force_retuning) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + struct tegra_tuning_data *tuning_data; + struct tuning_t2t_coeffs *t2t_coeffs; + struct tap_hole_coeffs *thole_coeffs; + const char *dev_id; + unsigned int freq_khz; + u8 i, j; + bool coeffs_set = false; + + dev_id = dev_name(mmc_dev(sdhci->mmc)); + /* Find the coeffs data for all supported frequencies */ + for (i = 0; i < tegra_host->tuning_freq_count; i++) { + tuning_data = &tegra_host->tuning_data[i]; + + /* Skip if T2T coeffs are already found */ + if (tuning_data->t2t_coeffs == NULL || force_retuning) { + t2t_coeffs = soc_data->t2t_coeffs; + for (j = 0; j < soc_data->t2t_coeffs_count; j++) { + if (!strcmp(dev_id, t2t_coeffs->dev_id)) { + tuning_data->t2t_coeffs = t2t_coeffs; + coeffs_set = true; + dev_info(mmc_dev(sdhci->mmc), + "Found T2T coeffs data\n"); + break; + } + t2t_coeffs++; + } + if (!coeffs_set) { + dev_err(mmc_dev(sdhci->mmc), + "T2T coeffs data missing\n"); + tuning_data->t2t_coeffs = NULL; + return -ENODATA; + } + } + + coeffs_set = false; + /* Skip if tap hole coeffs are already found */ + if (tuning_data->thole_coeffs == NULL || force_retuning) { + thole_coeffs = soc_data->tap_hole_coeffs; + freq_khz = tuning_data->freq_hz / 1000; + for (j = 0; j < soc_data->tap_hole_coeffs_count; j++) { + if (!strcmp(dev_id, thole_coeffs->dev_id) && + (freq_khz == thole_coeffs->freq_khz)) { + tuning_data->thole_coeffs = + thole_coeffs; + coeffs_set = true; + dev_info(mmc_dev(sdhci->mmc), + "%dMHz tap hole coeffs found\n", + (freq_khz / 1000)); + break; + } + thole_coeffs++; + } + + if (!coeffs_set) { + dev_err(mmc_dev(sdhci->mmc), + "%dMHz Tap hole coeffs data missing\n", + (freq_khz / 1000)); + tuning_data->thole_coeffs = NULL; + return -ENODATA; + } + } + } + + return 0; +} + /* * Determines the numbers of frequencies required and then fills up the tuning * constraints for each of the frequencies. The data of lower frequency is - * filled first and then the higher frequency data. Currently fills constraints - * for number of frequencies 1 and 2. + * filled first and then the higher frequency data. Max supported frequencies + * is currently two. */ -static u8 sdhci_tegra_setup_freq_constraints(struct sdhci_host *sdhci, +static int setup_freq_constraints(struct sdhci_host *sdhci, const unsigned int *freq_list) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); struct sdhci_tegra *tegra_host = pltfm_host->priv; struct tegra_tuning_data *tuning_data; - int i; - u8 freq_count, freq_band; + int i, freq_count; + u8 freq_band; if ((sdhci->mmc->ios.timing != MMC_TIMING_UHS_SDR50) && (sdhci->mmc->caps2 & MMC_CAP2_FREQ_SCALING)) @@ -2154,27 +2837,19 @@ static u8 sdhci_tegra_setup_freq_constraints(struct sdhci_host *sdhci, tuning_data = &tegra_host->tuning_data[0]; tuning_data->freq_hz = sdhci->max_clk; tuning_data->freq_band = freq_band; - tuning_data->constraints = - tuning_vcore_constraints[freq_band]; - if (tegra_host->soc_data->nvquirks & - NVQUIRK_HIGH_FREQ_TAP_PROCEDURE) { - if (tuning_data->freq_band == TUNING_LOW_FREQ) - tuning_data->constraints.vcore_mask |= - MIN_OVERRIDE_VCORE_TUN; - } - if (!tegra_host->plat->en_nominal_vcore_tuning) - tuning_data->constraints.vcore_mask &= - ~NOMINAL_VCORE_TUN; + tuning_data->constraints.vcore_mask = + tuning_vcore_constraints[freq_band].vcore_mask; + tuning_data->nr_voltages = + hweight32(tuning_data->constraints.vcore_mask); break; case 2: tuning_data = &tegra_host->tuning_data[1]; tuning_data->freq_hz = sdhci->max_clk; tuning_data->freq_band = freq_band; - tuning_data->constraints = - tuning_vcore_constraints[freq_band]; - if (!tegra_host->plat->en_nominal_vcore_tuning) - tuning_data->constraints.vcore_mask &= - ~NOMINAL_VCORE_TUN; + tuning_data->constraints.vcore_mask = + tuning_vcore_constraints[freq_band].vcore_mask; + tuning_data->nr_voltages = + hweight32(tuning_data->constraints.vcore_mask); tuning_data = &tegra_host->tuning_data[0]; for (i = (freq_band - 1); i >= 0; i--) { @@ -2182,51 +2857,51 @@ static u8 sdhci_tegra_setup_freq_constraints(struct sdhci_host *sdhci, continue; tuning_data->freq_hz = freq_list[i]; tuning_data->freq_band = i; - tuning_data->constraints = - tuning_vcore_constraints[i]; - if (tegra_host->soc_data->nvquirks & - NVQUIRK_HIGH_FREQ_TAP_PROCEDURE) { - if (i == TUNING_LOW_FREQ) - tuning_data->constraints.vcore_mask |= - MIN_OVERRIDE_VCORE_TUN; - } - if (!tegra_host->plat->en_nominal_vcore_tuning) - tuning_data->constraints.vcore_mask &= - ~NOMINAL_VCORE_TUN; + tuning_data->nr_voltages = 1; + tuning_data->constraints.vcore_mask = + tuning_vcore_constraints[i].vcore_mask; + tuning_data->nr_voltages = + hweight32(tuning_data->constraints.vcore_mask); } break; default: dev_err(mmc_dev(sdhci->mmc), "Unsupported freq count\n"); + freq_count = -1; } + return freq_count; } /* - * Get the supported frequencies, core voltage levels for each frequency and - * other tuning related constraints. - * The supported frequencies should be determined from the list of frequencies - * in the soc data and also consider the platform clock limits as well as any - * DFS related restrictions. - * Check if tuning at nominal core voltage is required. + * Get the supported frequencies and other tuning related constraints for each + * frequency. The supported frequencies should be determined from the list of + * frequencies in the soc data and also consider the platform clock limits as + * well as any DFS related restrictions. */ -static int sdhci_tegra_get_tuning_constraints(struct sdhci_host *sdhci) +static int sdhci_tegra_get_tuning_constraints(struct sdhci_host *sdhci, + bool force_retuning) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); struct sdhci_tegra *tegra_host = pltfm_host->priv; const unsigned int *freq_list; int err = 0; + /* A valid freq count means freq constraints are already set up */ + if (!tegra_host->tuning_freq_count || force_retuning) { + freq_list = tegra_host->soc_data->tuning_freq_list; + tegra_host->tuning_freq_count = + setup_freq_constraints(sdhci, freq_list); + if (tegra_host->tuning_freq_count < 0) { + dev_err(mmc_dev(sdhci->mmc), + "Invalid tuning freq count\n"); + return -EINVAL; + } + } - /* Check if the constraints are already filled up */ - if (tegra_host->tuning_freq_count) + err = find_tuning_coeffs_data(sdhci, force_retuning); + if (err) return err; - freq_list = tegra_host->soc_data->tuning_freq_list; - tegra_host->tuning_freq_count = - sdhci_tegra_setup_freq_constraints(sdhci, freq_list); - - err = sdhci_tegra_setup_vcore_constraints(sdhci); - sdhci_tegra_dump_tuning_constraints(sdhci); return err; @@ -2288,63 +2963,59 @@ static int sdhci_tegra_set_tuning_voltage(struct sdhci_host *sdhci, return err; } -static u8 get_curr_voltage_tuning_status(struct tap_window_data *tap_data) -{ - if (!tap_data->vcore_set_status) - maintain_boot_voltage = true; - - if (!tap_data->vcore_set_status || !tap_data->found_tuning_window) - return 1; - - return 0; -} - -static u8 sdhci_tegra_run_tuning(struct sdhci_host *sdhci, - struct tegra_tuning_data *tuning_data, bool force_retuning) +static int sdhci_tegra_run_tuning(struct sdhci_host *sdhci, + struct tegra_tuning_data *tuning_data) { - struct tap_window_data *tap_data; - int err; - u8 i, retuning_req = 0; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + int err = 0; + int voltage = 0; + u8 i, vcore_mask = 0; + vcore_mask = tuning_data->constraints.vcore_mask; for (i = 0; i < tuning_data->nr_voltages; i++) { - tap_data = tuning_data->tap_data[i]; - /* Skip if tuning is already completed successfully */ - if (tap_data->vcore_set_status && - tap_data->found_tuning_window && !force_retuning) - continue; - err = sdhci_tegra_set_tuning_voltage(sdhci, - tap_data->voltage); - tap_data->vcore_set_status = !err; + voltage = get_tuning_voltage(tegra_host, &vcore_mask); + err = sdhci_tegra_set_tuning_voltage(sdhci, voltage); + if (err) { + dev_err(mmc_dev(sdhci->mmc), + "Unable to set override voltage.\n"); + return err; + } + /* Get the tuning window info */ - spin_lock(&sdhci->lock); - err = sdhci_tegra_get_tap_window_data(sdhci, tap_data); - spin_unlock(&sdhci->lock); - SDHCI_TEGRA_DBG("%s: Tap data[%d] obtained\n", - mmc_hostname(sdhci->mmc), i); - tap_data->found_tuning_window = !err; - if (err) + SDHCI_TEGRA_DBG("Getting tuning windows...\n"); + err = sdhci_tegra_get_tap_window_data(sdhci, tuning_data); + if (err) { dev_err(mmc_dev(sdhci->mmc), - "Invalid tap win. Retuning req\n"); - retuning_req |= get_curr_voltage_tuning_status(tap_data); - SDHCI_TEGRA_DBG("%s: Retuning req %s\n", - mmc_hostname(sdhci->mmc), retuning_req ? "set" : - "not set"); + "Failed to get tap win %d\n", err); + return err; + } + SDHCI_TEGRA_DBG("%s: %d tuning window data obtained\n", + mmc_hostname(sdhci->mmc), tuning_data->freq_hz); } - return retuning_req; + return err; } -static int sdhci_tegra_verify_best_tap(struct sdhci_host *sdhci, - u8 freq_band) +static int sdhci_tegra_verify_best_tap(struct sdhci_host *sdhci) { struct tegra_tuning_data *tuning_data; - unsigned int best_tap_value = 0; - int err; + int err = 0; tuning_data = sdhci_tegra_get_tuning_data(sdhci, sdhci->max_clk); - best_tap_value = tuning_data->best_tap_value; + if ((tuning_data->best_tap_value < 0) || + (tuning_data->best_tap_value > MAX_TAP_VALUES)) { + dev_err(mmc_dev(sdhci->mmc), + "Trying to verify invalid best tap value\n"); + return -EINVAL; + } else { + dev_info(mmc_dev(sdhci->mmc), + "%s: tuning freq %dhz, best tap %d\n", + __func__, tuning_data->freq_hz, + tuning_data->best_tap_value); + } /* Set the best tap value */ - sdhci_tegra_set_tap_delay(sdhci, best_tap_value); + sdhci_tegra_set_tap_delay(sdhci, tuning_data->best_tap_value); /* Run tuning after setting the best tap value */ err = sdhci_tegra_issue_tuning_cmd(sdhci); @@ -2360,13 +3031,14 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); struct sdhci_tegra *tegra_host = pltfm_host->priv; struct tegra_tuning_data *tuning_data; - unsigned int freq_band; + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; int err; u16 ctrl_2; + u32 misc_ctrl; u32 ier; u8 i, set_retuning = 0; - bool is_retuning_req = false; bool force_retuning = false; + bool enable_lb_clk; /* Tuning is valid only in SDR104 and SDR50 modes */ ctrl_2 = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2); @@ -2384,10 +3056,16 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode) return -EINVAL; SDHCI_TEGRA_DBG("%s: Starting freq tuning\n", mmc_hostname(sdhci->mmc)); + enable_lb_clk = (soc_data->nvquirks & + NVQUIRK_DISABLE_EXTERNAL_LOOPBACK) && + (tegra_host->instance == 2); + if (enable_lb_clk) { + misc_ctrl = sdhci_readl(sdhci, SDHCI_VNDR_MISC_CTRL); + misc_ctrl &= ~(1 << + SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT); + sdhci_writel(sdhci, misc_ctrl, SDHCI_VNDR_MISC_CTRL); + } mutex_lock(&tuning_mutex); - if (sdhci->flags & SDHCI_NEEDS_RETUNING) - is_retuning_req = true; - sdhci->flags &= ~SDHCI_NEEDS_RETUNING; /* Set the tuning command to be used */ tegra_host->tuning_opcode = opcode; @@ -2408,15 +3086,14 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode) * previous best tap value verification failed, force retuning. */ if (tegra_host->tuning_status == TUNING_STATUS_DONE) { - freq_band = sdhci_tegra_get_freq_point(sdhci); - dev_info(mmc_dev(sdhci->mmc), - "Tuning already done. Setting tuned tap value %d\n", - tegra_host->tuning_data[freq_band].best_tap_value); - err = sdhci_tegra_verify_best_tap(sdhci, freq_band); - if (err) + err = sdhci_tegra_verify_best_tap(sdhci); + if (err) { + dev_err(mmc_dev(sdhci->mmc), + "Prev best tap failed. Re-running tuning\n"); force_retuning = true; - else + } else { goto out; + } } if (tegra_host->force_retune == true) { @@ -2425,9 +3102,10 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode) } tegra_host->tuning_status = 0; - err = sdhci_tegra_get_tuning_constraints(sdhci); + err = sdhci_tegra_get_tuning_constraints(sdhci, force_retuning); if (err) { - dev_err(mmc_dev(sdhci->mmc), "Failed to get tuning constraints\n"); + dev_err(mmc_dev(sdhci->mmc), + "Failed to get tuning constraints\n"); goto out; } @@ -2440,16 +3118,24 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode) mmc_hostname(sdhci->mmc), tuning_data->freq_hz); tegra_sdhci_set_clock(sdhci, tuning_data->freq_hz); - set_retuning = sdhci_tegra_run_tuning(sdhci, tuning_data, - force_retuning); + SDHCI_TEGRA_DBG("%s: Calculating estimated tuning values\n", + mmc_hostname(sdhci->mmc)); + err = calculate_estimated_tuning_values(tegra_host->speedo, + tuning_data, tegra_host->boot_vcore_mv); + if (err) + goto out; - sdhci_tegra_calculate_best_tap(sdhci, tuning_data->freq_band); + SDHCI_TEGRA_DBG("Running tuning...\n"); + err = sdhci_tegra_run_tuning(sdhci, tuning_data); + if (err) + goto out; - /* Dump the tuning data */ - sdhci_tegra_dump_tuning_data(sdhci); + SDHCI_TEGRA_DBG("calculating best tap value\n"); + err = sdhci_tegra_calculate_best_tap(sdhci, tuning_data); + if (err) + goto out; - err = sdhci_tegra_verify_best_tap(sdhci, - tuning_data->freq_band); + err = sdhci_tegra_verify_best_tap(sdhci); if (!err && !set_retuning) { tuning_data->tuning_done = true; tegra_host->tuning_status |= TUNING_STATUS_DONE; @@ -2457,29 +3143,9 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode) tegra_host->tuning_status |= TUNING_STATUS_RETUNE; } } - if (tegra_host->tuning_status & TUNING_STATUS_RETUNE) - mod_timer(&sdhci->tuning_timer, jiffies + 10 * HZ); out: - if (maintain_boot_voltage) { - ++boot_volt_req_refcount; - maintain_boot_voltage = false; - SDHCI_TEGRA_DBG("%s: Need fixed core volt %d, refcount %d\n", - mmc_hostname(sdhci->mmc), tegra_host->boot_vcore_mv, - boot_volt_req_refcount); - - } else { - if (boot_volt_req_refcount && is_retuning_req) - --boot_volt_req_refcount; - SDHCI_TEGRA_DBG("%s: Relax core volt constraint. refcount %d\n", - mmc_hostname(sdhci->mmc), boot_volt_req_refcount); - } - - if (boot_volt_req_refcount) - sdhci_tegra_set_tuning_voltage(sdhci, - tegra_host->boot_vcore_mv); - else - sdhci_tegra_set_tuning_voltage(sdhci, 0); - + /* Release any override core voltages set */ + sdhci_tegra_set_tuning_voltage(sdhci, 0); /* Enable interrupts. Enable full range for core voltage */ sdhci_writel(sdhci, ier, SDHCI_INT_ENABLE); @@ -2487,6 +3153,21 @@ out: mutex_unlock(&tuning_mutex); SDHCI_TEGRA_DBG("%s: Freq tuning done\n", mmc_hostname(sdhci->mmc)); + if (enable_lb_clk) { + misc_ctrl = sdhci_readl(sdhci, SDHCI_VNDR_MISC_CTRL); + if (err) { + /* Tuning is failed and card will try to enumerate in + * Legacy High Speed mode. So, Enable External Loopback + * for SDMMC3. + */ + misc_ctrl |= (1 << + SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT); + } else { + misc_ctrl &= ~(1 << + SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT); + } + sdhci_writel(sdhci, misc_ctrl, SDHCI_VNDR_MISC_CTRL); + } return err; } @@ -2580,22 +3261,26 @@ static void tegra_sdhci_post_resume(struct sdhci_host *sdhci) /* * For tegra specific tuning, core voltage has to be fixed at different * voltages to get the tap values. Fixing the core voltage during tuning for one - * device might affect transfers of other SDMMC devices. To handle this, lock - * tuning_mutex to prevent any transfers during tuning execution. This is not - * required once tuning is done. + * device might affect transfers of other SDMMC devices. Check if tuning mutex + * is locked before starting a data transfer. The new tuning procedure might + * take at max 1.5s for completion for a single run. Taking DFS into count, + * setting the max timeout for tuning mutex check a 3 secs. Since tuning is + * run only during boot or the first time device is inserted, there wouldn't + * be any delays in cmd/xfer execution once devices enumeration is done. */ static void tegra_sdhci_get_bus(struct sdhci_host *sdhci) { - int timeout = 100; - while (mutex_is_locked(&tuning_mutex)) { - if (!timeout) { - dev_err(mmc_dev(sdhci->mmc), - "Tuning timer not released\n"); - return; - } - msleep(10); - timeout--; - }; + unsigned int timeout = 300; + + while (mutex_is_locked(&tuning_mutex)) { + msleep(10); + --timeout; + if (!timeout) { + dev_err(mmc_dev(sdhci->mmc), + "Tuning mutex locked for long time\n"); + return; + } + }; } /* @@ -2953,9 +3638,14 @@ static struct sdhci_tegra_soc_data soc_data_tegra11 = { NVQUIRK_ENABLE_DDR50 | NVQUIRK_ENABLE_HS200 | NVQUIRK_INFINITE_ERASE_TIMEOUT | + NVQUIRK_DISABLE_EXTERNAL_LOOPBACK | NVQUIRK_DISABLE_SDMMC4_CALIB, .parent_clk_list = {"pll_p", "pll_c"}, .tuning_freq_list = {81600000, 156000000, 200000000}, + .t2t_coeffs = t11x_tuning_coeffs, + .t2t_coeffs_count = 3, + .tap_hole_coeffs = t11x_tap_hole_coeffs, + .tap_hole_coeffs_count = 12, }; static struct sdhci_pltfm_data sdhci_tegra12_pdata = { @@ -2978,7 +3668,10 @@ static struct sdhci_tegra_soc_data soc_data_tegra12 = { NVQUIRK_DISABLE_EXTERNAL_LOOPBACK, .parent_clk_list = {"pll_p", "pll_c"}, .tuning_freq_list = {81600000, 136000000, 200000000}, - .tuning_min_volt_list = {950, 1000, 0}, + .t2t_coeffs = t12x_tuning_coeffs, + .t2t_coeffs_count = 3, + .tap_hole_coeffs = t12x_tap_hole_coeffs, + .tap_hole_coeffs_count = 13, }; static const struct of_device_id sdhci_tegra_dt_match[] = { @@ -3308,7 +4001,8 @@ static int sdhci_tegra_probe(struct platform_device *pdev) tegra_host->ddr_clk_limit = plat->ddr_clk_limit; tegra_host->instance = pdev->id; tegra_host->tap_cmd = TAP_CMD_TRIM_DEFAULT_VOLTAGE; - + tegra_host->speedo = plat->cpu_speedo; + dev_info(mmc_dev(host->mmc), "Speedo value %d\n", tegra_host->speedo); host->mmc->pm_caps |= plat->pm_caps; host->mmc->pm_flags |= plat->pm_flags; diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 9e003f2957a4..fe7329ec0150 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -1888,6 +1888,8 @@ static int tegra_pcie_resume_noirq(struct device *dev) return ret; } } + /* give 100ms for 1.05v to come up */ + msleep(100); ret = tegra_pcie_power_on(); if (ret) { pr_err("PCIE: Failed to power on: %d\n", ret); diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 264054fe8a66..5914e7a9ed5a 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1601,6 +1601,24 @@ static int serial8250_tegra_handle_irq(struct uart_port *port) return 1; } +#ifdef CONFIG_ARCH_TEGRA +void tegra_serial_handle_break(struct uart_port *p) +{ + unsigned int status, tmout = 10000; + + do { + status = p->serial_in(p, UART_LSR); + if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) + status = p->serial_in(p, UART_RX); + else + break; + if (--tmout == 0) + break; + udelay(1); + } while (1); +} +#endif + /* * These Exar UARTs have an extra interrupt indicator that could * fire for a few unimplemented interrupts. One of which is a @@ -2761,6 +2779,9 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type == PORT_TEGRA) { up->bugs |= UART_BUG_NOMSR; port->handle_irq = serial8250_tegra_handle_irq; +#if defined CONFIG_ARCH_TEGRA + port->handle_break = tegra_serial_handle_break; +#endif } if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 39c7ea4cb14f..261c0ad164ec 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -29,28 +29,6 @@ struct of_serial_info { int line; }; -#ifdef CONFIG_ARCH_TEGRA -void tegra_serial_handle_break(struct uart_port *p) -{ - unsigned int status, tmout = 10000; - - do { - status = p->serial_in(p, UART_LSR); - if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) - status = p->serial_in(p, UART_RX); - else - break; - if (--tmout == 0) - break; - udelay(1); - } while (1); -} -#else -static inline void tegra_serial_handle_break(struct uart_port *port) -{ -} -#endif - /* * Fill a struct uart_port for a given device node */ diff --git a/drivers/usb/phy/tegra11x_usb_phy.c b/drivers/usb/phy/tegra11x_usb_phy.c index 426a2e69682b..f690691e3fa1 100644 --- a/drivers/usb/phy/tegra11x_usb_phy.c +++ b/drivers/usb/phy/tegra11x_usb_phy.c @@ -1,7 +1,7 @@ /* * drivers/usb/phy/tegra11x_usb_phy.c * - * Copyright (c) 2012-2013 NVIDIA Corporation. All rights reserved. + * Copyright (c) 2012-2014 NVIDIA Corporation. All rights reserved. * * * This software is licensed under the terms of the GNU General Public @@ -1023,7 +1023,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) utmi_phy_iddq_override(false); if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, - USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500)) + USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2600)) pr_warn("%s: timeout waiting for phy to stabilize\n", __func__); val = readl(base + HOSTPC1_DEVLC); diff --git a/drivers/video/tegra/dc/bandwidth.c b/drivers/video/tegra/dc/bandwidth.c index b98ced801f7c..45558450403d 100644 --- a/drivers/video/tegra/dc/bandwidth.c +++ b/drivers/video/tegra/dc/bandwidth.c @@ -617,12 +617,12 @@ static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc, * is of the luma plane's size only. */ bpp = tegra_dc_is_yuv_planar(w->fmt) ? 2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt); - ret = dc->mode.pclk / 1000UL * bpp / 8 * + ret = dc->mode.pclk / 1000UL * bpp / 8 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) - (win_use_v_filter(dc, w) ? 2 : 1) * + * (win_use_v_filter(dc, w) ? 2 : 1) #endif - in_w / w->out_w * (WIN_IS_TILED(w) ? - tiled_windows_bw_multiplier : 1); + / w->out_w * in_w + / (WIN_IS_TILED(w) ? tiled_windows_bw_multiplier : 1); #ifdef CONFIG_ARCH_TEGRA_2x_SOC /* * Assuming 60% efficiency: i.e. if we calculate we need 70MBps, we diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h index 8586d32a37ec..3580153ef5d2 100644 --- a/drivers/video/tegra/dc/dc_reg.h +++ b/drivers/video/tegra/dc/dc_reg.h @@ -503,16 +503,16 @@ #define DC_WIN_COLOR_DEPTH 0x703 #define DC_WIN_POSITION 0x704 -#define H_POSITION(x) (((x) & 0xfff) << 0) -#define V_POSITION(x) (((x) & 0xfff) << 16) +#define H_POSITION(x) (((x) & 0x1fff) << 0) +#define V_POSITION(x) (((x) & 0x1fff) << 16) #define DC_WIN_SIZE 0x705 -#define H_SIZE(x) (((x) & 0xfff) << 0) -#define V_SIZE(x) (((x) & 0xfff) << 16) +#define H_SIZE(x) (((x) & 0x1fff) << 0) +#define V_SIZE(x) (((x) & 0x1fff) << 16) #define DC_WIN_PRESCALED_SIZE 0x706 -#define H_PRESCALED_SIZE(x) (((x) & 0x3fff) << 0) -#define V_PRESCALED_SIZE(x) (((x) & 0xfff) << 16) +#define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) +#define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) #define DC_WIN_H_INITIAL_DDA 0x707 #define DC_WIN_V_INITIAL_DDA 0x708 diff --git a/drivers/video/tegra/dc/hdmi_state_machine.c b/drivers/video/tegra/dc/hdmi_state_machine.c index 3707a0a00a40..2312a98b3fff 100644 --- a/drivers/video/tegra/dc/hdmi_state_machine.c +++ b/drivers/video/tegra/dc/hdmi_state_machine.c @@ -151,7 +151,7 @@ static int emulate_hotplug = 1; static void handle_enable_l(struct tegra_dc_hdmi_data *hdmi) { tegra_dc_enable(hdmi->dc); - if (emulate_hotplug) { + if (emulate_hotplug && hdmi->dvi) { emulate_hotplug = 0; hdmi_reread_edid(hdmi->dc); } diff --git a/drivers/video/tegra/host/gk20a/channel_gk20a.c b/drivers/video/tegra/host/gk20a/channel_gk20a.c index efb1c698faa0..bf15be94af9b 100644 --- a/drivers/video/tegra/host/gk20a/channel_gk20a.c +++ b/drivers/video/tegra/host/gk20a/channel_gk20a.c @@ -1528,8 +1528,7 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, * sure the fence represents work completion. In that case * issue a wait-for-idle before the syncpoint increment. */ - wfi_cmd = !!(flags & NVHOST_SUBMIT_GPFIFO_FLAGS_FENCE_GET) - && c->obj_class != KEPLER_C; + wfi_cmd = !!(flags & NVHOST_SUBMIT_GPFIFO_FLAGS_FENCE_GET); /* Invalidate tlb if it's dirty... */ /* TBD: this should be done in the cmd stream, not with PRIs. */ @@ -1671,26 +1670,16 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, c->last_submit_fence.wfi = wfi_cmd; trace_nvhost_ioctl_ctrl_syncpt_incr(fence->syncpt_id); - if (c->obj_class == KEPLER_C) { - /* setobject KEPLER_C */ - incr_cmd->ptr[j++] = 0x20010000; - incr_cmd->ptr[j++] = KEPLER_C; - /* syncpt incr */ - incr_cmd->ptr[j++] = 0x200100B2; - incr_cmd->ptr[j++] = fence->syncpt_id | (0x1 << 20) - | (0x1 << 16); - } else { - if (wfi_cmd) - add_wfi_cmd(incr_cmd, &j); - /* syncpoint_a */ - incr_cmd->ptr[j++] = 0x2001001C; - /* payload, ignored */ - incr_cmd->ptr[j++] = 0; - /* syncpoint_b */ - incr_cmd->ptr[j++] = 0x2001001D; - /* syncpt_id, incr */ - incr_cmd->ptr[j++] = (fence->syncpt_id << 8) | 0x1; - } + if (wfi_cmd) + add_wfi_cmd(incr_cmd, &j); + /* syncpoint_a */ + incr_cmd->ptr[j++] = 0x2001001C; + /* payload, ignored */ + incr_cmd->ptr[j++] = 0; + /* syncpoint_b */ + incr_cmd->ptr[j++] = 0x2001001D; + /* syncpt_id, incr */ + incr_cmd->ptr[j++] = (fence->syncpt_id << 8) | 0x1; c->gpfifo.cpu_va[c->gpfifo.put].entry0 = u64_lo32(incr_cmd->gva); diff --git a/drivers/video/tegra/host/gk20a/gr_gk20a.c b/drivers/video/tegra/host/gk20a/gr_gk20a.c index 4caaa51ab1aa..b4da945ee2a3 100644 --- a/drivers/video/tegra/host/gk20a/gr_gk20a.c +++ b/drivers/video/tegra/host/gk20a/gr_gk20a.c @@ -1887,10 +1887,9 @@ static int gr_gk20a_init_ctxsw_ucode(struct gk20a *g) p_buf = (u8 *)p_ucode_info->surface_desc.cpuva; if (!p_buf) { - release_firmware(fecs_fw); - release_firmware(gpccs_fw); nvhost_err(d, "failed to map surface desc buffer"); - return -ENOMEM; + err = -ENOMEM; + goto clean_up; } gr_gk20a_copy_ctxsw_ucode_inst(p_buf, &p_ucode_info->fecs, @@ -1898,11 +1897,17 @@ static int gr_gk20a_init_ctxsw_ucode(struct gk20a *g) g->gr.ctx_vars.ucode.fecs.inst.l, g->gr.ctx_vars.ucode.fecs.data.l); + release_firmware(fecs_fw); + fecs_fw = NULL; + gr_gk20a_copy_ctxsw_ucode_inst(p_buf, &p_ucode_info->gpcs, p_gpcs_boot_desc, p_gpcs_boot_image, g->gr.ctx_vars.ucode.gpccs.inst.l, g->gr.ctx_vars.ucode.gpccs.data.l); + release_firmware(gpccs_fw); + gpccs_fw = NULL; + err = gr_gk20a_init_ctxsw_ucode_vaspace(g); if (err) goto clean_up; @@ -1925,6 +1930,11 @@ static int gr_gk20a_init_ctxsw_ucode(struct gk20a *g) p_ucode_info->surface_desc.cpuva = NULL; p_ucode_info->surface_desc.iova = 0; + release_firmware(gpccs_fw); + gpccs_fw = NULL; + release_firmware(fecs_fw); + fecs_fw = NULL; + return err; } @@ -5422,7 +5432,7 @@ int gk20a_gr_isr(struct gk20a *g) } if (need_reset) - gk20a_set_error_notifier(ch, + gk20a_set_error_notifier(ch->hwctx, NVHOST_CHANNEL_GR_ERROR_SW_NOTIFY); } diff --git a/drivers/video/tegra/host/msenc/msenc.c b/drivers/video/tegra/host/msenc/msenc.c index 4a71de312978..c260ec1740d3 100644 --- a/drivers/video/tegra/host/msenc/msenc.c +++ b/drivers/video/tegra/host/msenc/msenc.c @@ -76,7 +76,7 @@ static char *msenc_get_fw_name(struct platform_device *dev) return NULL; } - dev_info(&dev->dev, "fw name:%s\n", fw_name); + dev_dbg(&dev->dev, "fw name:%s\n", fw_name); return fw_name; } diff --git a/drivers/video/tegra/host/tsec/tsec.c b/drivers/video/tegra/host/tsec/tsec.c index 9316ab5bc9cc..eba08a1aec4e 100644 --- a/drivers/video/tegra/host/tsec/tsec.c +++ b/drivers/video/tegra/host/tsec/tsec.c @@ -80,7 +80,7 @@ static char *tsec_get_fw_name(struct platform_device *dev) return NULL; } - dev_info(&dev->dev, "fw name:%s\n", fw_name); + dev_dbg(&dev->dev, "fw name:%s\n", fw_name); return fw_name; } diff --git a/drivers/video/tegra/host/vic03/vic03.c b/drivers/video/tegra/host/vic03/vic03.c index 35816243e0b5..b58f938eae09 100644 --- a/drivers/video/tegra/host/vic03/vic03.c +++ b/drivers/video/tegra/host/vic03/vic03.c @@ -73,7 +73,7 @@ static char *vic_get_fw_name(struct platform_device *dev) decode_vic_ver(pdata->version, &maj, &min); sprintf(fw_name, "vic%02d_ucode.bin", maj); - dev_info(&dev->dev, "fw name:%s\n", fw_name); + dev_dbg(&dev->dev, "fw name:%s\n", fw_name); return fw_name; } diff --git a/fs/eventpoll.c b/fs/eventpoll.c index ab2157896d1d..047accde593d 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -9,7 +9,7 @@ * * Davide Libenzi * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. * */ @@ -1290,7 +1290,9 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, spin_lock(&tfile->f_lock); list_add_tail(&epi->fllink, &tfile->f_ep_links); spin_unlock(&tfile->f_lock); - tfile->f_path.dentry->d_inode->i_private = get_thread_process(current); + if (tfile->f_path.dentry->d_inode->i_private == NULL) + tfile->f_path.dentry->d_inode->i_private = + get_thread_process(current); /* * Add the current item to the RB tree. All RB tree operations are diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 59ea8e6a9587..2a374c56297d 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -159,6 +159,8 @@ struct notifier_block; int tegra_dvfs_get_freqs(struct clk *c, unsigned long **freqs, int *num_freqs); int tegra_dvfs_set_rate(struct clk *c, unsigned long rate); int tegra_dvfs_override_core_voltage(struct clk *c, int override_mv); +int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate); +int tegra_dvfs_set_fmax_at_vmin(struct clk *c, unsigned long f_max, int v_min); unsigned long clk_get_rate_all_locked(struct clk *c); int tegra_dvfs_rail_disable_by_name(const char *reg_id); int tegra_register_clk_rate_notifier(struct clk *c, struct notifier_block *nb); diff --git a/include/linux/platform_data/mmc-sdhci-tegra.h b/include/linux/platform_data/mmc-sdhci-tegra.h index 32de3cc5f1b6..0d5f862f66aa 100644 --- a/include/linux/platform_data/mmc-sdhci-tegra.h +++ b/include/linux/platform_data/mmc-sdhci-tegra.h @@ -1,9 +1,8 @@ /* * Copyright (C) 2009 Palm, Inc. - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * Author: Yvonne Yip * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -64,6 +63,7 @@ struct tegra_sdhci_platform_data { unsigned int calib_3v3_offsets; /* Format to be filled: 0xXXXXPDPU */ unsigned int calib_1v8_offsets; /* Format to be filled: 0xXXXXPDPU */ bool disable_clock_gate; /* no clock gate when true */ + u32 cpu_speedo; }; #endif diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index af47a8af6024..b4ddb420405c 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -125,5 +125,12 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up); extern void serial8250_set_isa_configurator(void (*v) (int port, struct uart_port *up, unsigned short *capabilities)); +#ifdef CONFIG_ARCH_TEGRA +extern void tegra_serial_handle_break(struct uart_port *p); +#else +static inline void tegra_serial_handle_break(struct uart_port *port) +{ +} +#endif #endif diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 611fed829ff6..2b79879684c8 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -3715,17 +3715,6 @@ static int max98090_probe(struct snd_soc_codec *codec) INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); - /* Enable jack detection */ - snd_soc_write(codec, M98090_REG_3D_CFG_JACK, - M98090_JDETEN_MASK | M98090_JDEB_25MS); - - /* Register for interrupts */ - if ((request_threaded_irq(pdata->irq, NULL, - max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "max98090_interrupt", codec)) < 0) { - dev_info(codec->dev, "request_irq failed\n"); - } - #ifdef MAX98090_HIGH_PERFORMANCE /* High Performance */ snd_soc_update_bits(codec, M98090_REG_43_DAC_CFG, @@ -3758,6 +3747,20 @@ static int max98090_probe(struct snd_soc_codec *codec) max98090_add_widgets(codec); + /* Clear existing interrupts */ + snd_soc_read(codec, M98090_REG_01_IRQ_STATUS); + + /* Register for interrupts */ + if ((request_threaded_irq(pdata->irq, NULL, + max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "max98090_interrupt", codec)) < 0) { + dev_info(codec->dev, "request_irq failed\n"); + } + + /* Enable jack detection */ + snd_soc_write(codec, M98090_REG_3D_CFG_JACK, + M98090_JDETEN_MASK | M98090_JDEB_25MS); + err_access: return ret; } diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index d57280e23318..c6e1d653f8e8 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -1,7 +1,7 @@ /* * tegra30_ahub.c - Tegra30 AHUB driver * - * Copyright (c) 2011-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -618,6 +618,20 @@ static const char * const configlink_clocks[] = { #ifndef CONFIG_ARCH_TEGRA_14x_SOC "spdif_in", #endif +#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_12x_SOC) + "amx", + "adx", +#endif +#ifdef CONFIG_ARCH_TEGRA_12x_SOC + "amx1", + "adx1", + "afc0", + "afc1", + "afc2", + "afc3", + "afc4", + "afc5", +#endif }; struct of_dev_auxdata ahub_auxdata[] = { -- cgit v1.2.1