Browse Source

Merge branch 'connectivity-ti-linux-4.19.y' of git://git.ti.com/connectivity-integration-tree/connectivity-ti-linux-kernel into ti-linux-4.19.y

TI-Feature: connectivity
TI-Tree: git://git.ti.com/connectivity-integration-tree/connectivity-ti-linux-kernel.git
TI-Branch: connectivity-ti-linux-4.19.y

* 'connectivity-ti-linux-4.19.y' of git://git.ti.com/connectivity-integration-tree/connectivity-ti-linux-kernel:
  arm64: dts: ti: k3-am654-base-board: Enable ECAP PWM
  arm64: dts: ti: k3-am65-main: Add ECAP PWM node
  pwm: Enable TI ECAP driver for ARCH_K3
  dt-bindings: pwm: tiecap: Add TI AM654 SoC specific compatible
  dt-bindings: i2c: omap: Add new compatible for AM654 SoCs
  mmc: sdhci-omap: Workaround errata regarding SDR104/HS200 tuning failures (i929)
  dt-bindings: sdhci-omap: Add note for cpu_thermal
  mmc: sdhci-omap: Add platform specific reset callback
  mmc: sdhci-omap: Remove redundant structure assignments
  mmc: sdhci-omap: Fix DCRC error handling during tuning

Signed-off-by: LCPD Auto Merger <lcpd_integration@list.ti.com>
LCPD Auto Merger 7 years ago
parent
commit
f6b17ca1f7

+ 6 - 2
Documentation/devicetree/bindings/i2c/i2c-omap.txt

@@ -1,8 +1,12 @@
 I2C for OMAP platforms
 I2C for OMAP platforms
 
 
 Required properties :
 Required properties :
-- compatible : Must be "ti,omap2420-i2c", "ti,omap2430-i2c", "ti,omap3-i2c"
-  or "ti,omap4-i2c"
+- compatible : Must be
+	"ti,omap2420-i2c" for OMAP2420 SoCs
+	"ti,omap2430-i2c" for OMAP2430 SoCs
+	"ti,omap3-i2c" for OMAP3 SoCs
+	"ti,omap4-i2c" for OMAP4+ SoCs
+	"ti,am654-i2c", "ti,omap4-i2c" for AM654 SoCs
 - ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
 - ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
 - #address-cells = <1>;
 - #address-cells = <1>;
 - #size-cells = <0>;
 - #size-cells = <0>;

+ 2 - 0
Documentation/devicetree/bindings/mmc/sdhci-omap.txt

@@ -2,6 +2,8 @@
 
 
 Refer to mmc.txt for standard MMC bindings.
 Refer to mmc.txt for standard MMC bindings.
 
 
+For UHS devices which require tuning, the device tree should have a "cpu_thermal" node which maps to the appropriate thermal zone. This is used to get the temperature of the zone during tuning.
+
 Required properties:
 Required properties:
 - compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
 - compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
 	      Should be "ti,k2g-sdhci" for K2G
 	      Should be "ti,k2g-sdhci" for K2G

+ 1 - 0
Documentation/devicetree/bindings/pwm/pwm-tiecap.txt

@@ -7,6 +7,7 @@ Required properties:
   for da850  - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
   for da850  - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap";
   for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap";
   for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap";
   for 66ak2g - compatible = "ti,k2g-ecap", "ti,am3352-ecap";
   for 66ak2g - compatible = "ti,k2g-ecap", "ti,am3352-ecap";
+  for am654  - compatible = "ti,am654-ecap", "ti,am3352-ecap";
 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
   the cells format. The PWM channel index ranges from 0 to 4. The only third
   the cells format. The PWM channel index ranges from 0 to 4. The only third
   cell flag supported by this binding is PWM_POLARITY_INVERTED.
   cell flag supported by this binding is PWM_POLARITY_INVERTED.

+ 9 - 0
arch/arm64/boot/dts/ti/k3-am65-main.dtsi

@@ -429,4 +429,13 @@
 		reg = <0x00 0x30e00000 0x00 0x1000>;
 		reg = <0x00 0x30e00000 0x00 0x1000>;
 		#hwlock-cells = <1>;
 		#hwlock-cells = <1>;
 	};
 	};
+
+	ecap0: pwm@3100000 {
+		compatible = "ti,am654-ecap", "ti,am3352-ecap";
+		#pwm-cells = <3>;
+		reg = <0x0 0x03100000 0x0 0x60>;
+		power-domains = <&k3_pds 39>;
+		clocks = <&k3_clks 39 0>;
+		clock-names = "fck";
+	};
 };
 };

+ 11 - 0
arch/arm64/boot/dts/ti/k3-am654-base-board.dts

@@ -128,6 +128,12 @@
 			AM65X_IOPAD(0x000c, PIN_INPUT, 0) /* (E21) I2C1_SDA */
 			AM65X_IOPAD(0x000c, PIN_INPUT, 0) /* (E21) I2C1_SDA */
 		>;
 		>;
 	};
 	};
+
+	ecap0_pins_default: ecap0-pins-default {
+		pinctrl-single,pins = <
+			AM65X_IOPAD(0x0010, PIN_INPUT, 0) /* (D21) ECAP0_IN_APWM_OUT */
+		>;
+	};
 };
 };
 
 
 &wkup_uart0 {
 &wkup_uart0 {
@@ -197,3 +203,8 @@
 	phy-mode = "rgmii-id";
 	phy-mode = "rgmii-id";
 	phy-handle = <&phy0>;
 	phy-handle = <&phy0>;
 };
 };
+
+&ecap0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ecap0_pins_default>;
+};

+ 2 - 0
drivers/mmc/host/Kconfig

@@ -935,6 +935,8 @@ config MMC_SDHCI_XENON
 config MMC_SDHCI_OMAP
 config MMC_SDHCI_OMAP
 	tristate "TI SDHCI Controller Support"
 	tristate "TI SDHCI Controller Support"
 	depends on MMC_SDHCI_PLTFM && OF
 	depends on MMC_SDHCI_PLTFM && OF
+	select THERMAL
+	select TI_SOC_THERMAL
 	help
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
 	  support present in TI's DRA7 SOCs. The controller supports
 	  support present in TI's DRA7 SOCs. The controller supports

+ 116 - 10
drivers/mmc/host/sdhci-omap.c

@@ -27,6 +27,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/sys_soc.h>
 #include <linux/sys_soc.h>
+#include <linux/thermal.h>
 
 
 #include "sdhci-pltfm.h"
 #include "sdhci-pltfm.h"
 
 
@@ -115,6 +116,7 @@ struct sdhci_omap_host {
 
 
 	struct pinctrl		*pinctrl;
 	struct pinctrl		*pinctrl;
 	struct pinctrl_state	**pinctrl_state;
 	struct pinctrl_state	**pinctrl_state;
+	bool			is_tuning;
 };
 };
 
 
 static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host);
 static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host);
@@ -285,19 +287,19 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	struct sdhci_host *host = mmc_priv(mmc);
 	struct sdhci_host *host = mmc_priv(mmc);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
 	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+	struct thermal_zone_device *thermal_dev;
 	struct device *dev = omap_host->dev;
 	struct device *dev = omap_host->dev;
 	struct mmc_ios *ios = &mmc->ios;
 	struct mmc_ios *ios = &mmc->ios;
 	u32 start_window = 0, max_window = 0;
 	u32 start_window = 0, max_window = 0;
+	bool single_point_failure = false;
+	bool dcrc_was_enabled = false;
 	u8 cur_match, prev_match = 0;
 	u8 cur_match, prev_match = 0;
 	u32 length = 0, max_len = 0;
 	u32 length = 0, max_len = 0;
-	u32 ier = host->ier;
 	u32 phase_delay = 0;
 	u32 phase_delay = 0;
+	int temperature;
 	int ret = 0;
 	int ret = 0;
 	u32 reg;
 	u32 reg;
-
-	pltfm_host = sdhci_priv(host);
-	omap_host = sdhci_pltfm_priv(pltfm_host);
-	dev = omap_host->dev;
+	int i;
 
 
 	/* clock tuning is not needed for upto 52MHz */
 	/* clock tuning is not needed for upto 52MHz */
 	if (ios->clock <= 52000000)
 	if (ios->clock <= 52000000)
@@ -307,6 +309,16 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50))
 	if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50))
 		return 0;
 		return 0;
 
 
+	thermal_dev = thermal_zone_get_zone_by_name("cpu_thermal");
+	if (IS_ERR(thermal_dev)) {
+		dev_err(dev, "Unable to get thermal zone for tuning\n");
+		return PTR_ERR(thermal_dev);
+	}
+
+	ret = thermal_zone_get_temp(thermal_dev, &temperature);
+	if (ret)
+		return ret;
+
 	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
 	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
 	reg |= DLL_SWT;
 	reg |= DLL_SWT;
 	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
 	sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
@@ -317,10 +329,18 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	 * during the tuning procedure. So disable it during the
 	 * during the tuning procedure. So disable it during the
 	 * tuning procedure.
 	 * tuning procedure.
 	 */
 	 */
-	ier &= ~SDHCI_INT_DATA_CRC;
-	sdhci_writel(host, ier, SDHCI_INT_ENABLE);
-	sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+	if (host->ier & SDHCI_INT_DATA_CRC) {
+		host->ier &= ~SDHCI_INT_DATA_CRC;
+		dcrc_was_enabled = true;
+	}
+
+	omap_host->is_tuning = true;
 
 
+	/*
+	 * Stage 1: Search for a maximum pass window ignoring any
+	 * any single point failures. If the tuning value ends up
+	 * near it, move away from it in stage 2 below
+	 */
 	while (phase_delay <= MAX_PHASE_DELAY) {
 	while (phase_delay <= MAX_PHASE_DELAY) {
 		sdhci_omap_set_dll(omap_host, phase_delay);
 		sdhci_omap_set_dll(omap_host, phase_delay);
 
 
@@ -328,10 +348,15 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		if (cur_match) {
 		if (cur_match) {
 			if (prev_match) {
 			if (prev_match) {
 				length++;
 				length++;
+			} else if (single_point_failure) {
+				/* ignore single point failure */
+				length++;
 			} else {
 			} else {
 				start_window = phase_delay;
 				start_window = phase_delay;
 				length = 1;
 				length = 1;
 			}
 			}
+		} else {
+			single_point_failure = prev_match;
 		}
 		}
 
 
 		if (length > max_len) {
 		if (length > max_len) {
@@ -349,23 +374,92 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		goto tuning_error;
 		goto tuning_error;
 	}
 	}
 
 
+	/*
+	 * Assign tuning value as a ratio of maximum pass window based
+	 * on temperature
+	 */
+	if (temperature < -20000)
+		phase_delay = min(max_window + 4 * max_len - 24,
+				  max_window +
+				  DIV_ROUND_UP(13 * max_len, 16) * 4);
+	else if (temperature < 20000)
+		phase_delay = max_window + DIV_ROUND_UP(9 * max_len, 16) * 4;
+	else if (temperature < 40000)
+		phase_delay = max_window + DIV_ROUND_UP(8 * max_len, 16) * 4;
+	else if (temperature < 70000)
+		phase_delay = max_window + DIV_ROUND_UP(7 * max_len, 16) * 4;
+	else if (temperature < 90000)
+		phase_delay = max_window + DIV_ROUND_UP(5 * max_len, 16) * 4;
+	else if (temperature < 120000)
+		phase_delay = max_window + DIV_ROUND_UP(4 * max_len, 16) * 4;
+	else
+		phase_delay = max_window + DIV_ROUND_UP(3 * max_len, 16) * 4;
+
+	/*
+	 * Stage 2: Search for a single point failure near the chosen tuning
+	 * value in two steps. First in the +3 to +10 range and then in the
+	 * +2 to -10 range. If found, move away from it in the appropriate
+	 * direction by the appropriate amount depending on the temperature.
+	 */
+	for (i = 3; i <= 10; i++) {
+		sdhci_omap_set_dll(omap_host, phase_delay + i);
+
+		if (mmc_send_tuning(mmc, opcode, NULL)) {
+			if (temperature < 10000)
+				phase_delay += i + 6;
+			else if (temperature < 20000)
+				phase_delay += i - 12;
+			else if (temperature < 70000)
+				phase_delay += i - 8;
+			else
+				phase_delay += i - 6;
+
+			goto single_failure_found;
+		}
+	}
+
+	for (i = 2; i >= -10; i--) {
+		sdhci_omap_set_dll(omap_host, phase_delay + i);
+
+		if (mmc_send_tuning(mmc, opcode, NULL)) {
+			if (temperature < 10000)
+				phase_delay += i + 12;
+			else if (temperature < 20000)
+				phase_delay += i + 8;
+			else if (temperature < 70000)
+				phase_delay += i + 8;
+			else if (temperature < 90000)
+				phase_delay += i + 10;
+			else
+				phase_delay += i + 12;
+
+			goto single_failure_found;
+		}
+	}
+
+single_failure_found:
 	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
 	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
 	if (!(reg & AC12_SCLK_SEL)) {
 	if (!(reg & AC12_SCLK_SEL)) {
 		ret = -EIO;
 		ret = -EIO;
 		goto tuning_error;
 		goto tuning_error;
 	}
 	}
 
 
-	phase_delay = max_window + 4 * (max_len >> 1);
 	sdhci_omap_set_dll(omap_host, phase_delay);
 	sdhci_omap_set_dll(omap_host, phase_delay);
 
 
+	omap_host->is_tuning = false;
+
 	goto ret;
 	goto ret;
 
 
 tuning_error:
 tuning_error:
+	omap_host->is_tuning = false;
 	dev_err(dev, "Tuning failed\n");
 	dev_err(dev, "Tuning failed\n");
 	sdhci_omap_disable_tuning(omap_host);
 	sdhci_omap_disable_tuning(omap_host);
 
 
 ret:
 ret:
 	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+	/* Reenable forbidden interrupt */
+	if (dcrc_was_enabled)
+		host->ier |= SDHCI_INT_DATA_CRC;
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 	return ret;
 	return ret;
@@ -683,6 +777,18 @@ static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host,
 	sdhci_omap_start_clock(omap_host);
 	sdhci_omap_start_clock(omap_host);
 }
 }
 
 
+void sdhci_omap_reset(struct sdhci_host *host, u8 mask)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+
+	/* Don't reset data lines during tuning operation */
+	if (omap_host->is_tuning)
+		mask &= ~SDHCI_RESET_DATA;
+
+	sdhci_reset(host, mask);
+}
+
 static struct sdhci_ops sdhci_omap_ops = {
 static struct sdhci_ops sdhci_omap_ops = {
 	.set_clock = sdhci_omap_set_clock,
 	.set_clock = sdhci_omap_set_clock,
 	.set_power = sdhci_omap_set_power,
 	.set_power = sdhci_omap_set_power,
@@ -691,7 +797,7 @@ static struct sdhci_ops sdhci_omap_ops = {
 	.get_min_clock = sdhci_omap_get_min_clock,
 	.get_min_clock = sdhci_omap_get_min_clock,
 	.set_bus_width = sdhci_omap_set_bus_width,
 	.set_bus_width = sdhci_omap_set_bus_width,
 	.platform_send_init_74_clocks = sdhci_omap_init_74_clocks,
 	.platform_send_init_74_clocks = sdhci_omap_init_74_clocks,
-	.reset = sdhci_reset,
+	.reset = sdhci_omap_reset,
 	.set_uhs_signaling = sdhci_omap_set_uhs_signaling,
 	.set_uhs_signaling = sdhci_omap_set_uhs_signaling,
 };
 };
 
 

+ 2 - 3
drivers/pwm/Kconfig

@@ -447,10 +447,9 @@ config PWM_TEGRA
 
 
 config  PWM_TIECAP
 config  PWM_TIECAP
 	tristate "ECAP PWM support"
 	tristate "ECAP PWM support"
-	depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE
+	depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3
 	help
 	help
-	  PWM driver support for the ECAP APWM controller found on AM33XX
-	  TI SOC
+	  PWM driver support for the ECAP APWM controller found on TI SOCs
 
 
 	  To compile this driver as a module, choose M here: the module
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-tiecap.
 	  will be called pwm-tiecap.