Skip to contentSkip to conversation

arm: omap3: am35x: Convert emac to hwmod & disable hlt when open

PATCH New Mark A. Greer 3 participants 9 messages May 15, 2012 – Jun 27, 2012

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

v2 cover arm: omap3: am35x: Convert emac to hwmod & disable hlt when open

From: "Mark A. Greer" <[email protected]>

These patches convert the davinci emac support for the am35x SoC to use hwmod and add enable_hlt()/disable_hlt() calls to the pm_runtime hooks for that driver.

I have converted the davinci_emac driver to use pm_runtime but I can't formally submit it yet since it requires some changes on the mach-davinci side that haven't happened yet. I will send it as an RFC in a reply to this thread.

The patches are based on:

        git://git.pwsan.com/linux-2.6 am35xx_hwmod_data_fixes_a_3.5

Changes from v1:
- patch 1/2, "arm: omap3: am35x: Add Davinci EMAC/MDIO hwmod support" is unchanged
- patch 2/2, "arm: "omap3: am35x: Disable hlt when using Davinci EMAC" has been reworked to keep the code as simple as possible per
http://www.spinics.net/lists/linux-omap/msg70354.html

Mark
--

Mark A. Greer (2):
arm: omap3: am35x: Add Davinci EMAC/MDIO hwmod support
arm: omap3: am35x: Disable hlt when using Davinci EMAC

 arch/arm/mach-omap2/am35xx-emac.c          |  116 ++++++++++++++++++----------
 arch/arm/mach-omap2/clock3xxx_data.c       |    2 +-
 arch/arm/mach-omap2/include/mach/am35xx.h  |    2 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   85 ++++++++++++++++++++
 4 files changed, 163 insertions(+), 42 deletions(-)
Signature · 1 line
1.7.9.4
#1 lore raw

PATCH v2 1/2 arm: omap3: am35x: Add Davinci EMAC/MDIO hwmod support

From: "Mark A. Greer" <[email protected]>

Add hwmod support for the EMAC (and MDIO)
ethernet controller that's on the am35x
family of SoC's.

---
 arch/arm/mach-omap2/am35xx-emac.c          |   92 ++++++++++++++--------------
 arch/arm/mach-omap2/clock3xxx_data.c       |    2 +-
 arch/arm/mach-omap2/include/mach/am35xx.h  |    2 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   85 +++++++++++++++++++++++++
 4 files changed, 135 insertions(+), 46 deletions(-)
arch/arm/mach-omap2/am35xx-emac.c +47 -45
index 1f97e74..3bb5cb3 100644
@@ -15,27 +15,13 @@
  * General Public License for more details.
  */
 
-#include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/davinci_emac.h>
-#include <linux/platform_device.h>
-#include <plat/irqs.h>
+#include <asm/system.h>
+#include <plat/omap_device.h>
 #include <mach/am35xx.h>
-
 #include "control.h"
-
-static struct mdio_platform_data am35xx_emac_mdio_pdata;
-
-static struct resource am35xx_emac_mdio_resources[] = {
-	DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET, SZ_4K),
-};
-
-static struct platform_device am35xx_emac_mdio_device = {
-	.name		= "davinci_mdio",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(am35xx_emac_mdio_resources),
-	.resource	= am35xx_emac_mdio_resources,
-	.dev.platform_data = &am35xx_emac_mdio_pdata,
-};
+#include "am35xx-emac.h"
 
 static void am35xx_enable_emac_int(void)
 {
@@ -72,41 +58,57 @@ static struct emac_platform_data am35xx_emac_pdata = {
 	.interrupt_disable	= am35xx_disable_emac_int,
 };
 
-static struct resource am35xx_emac_resources[] = {
-	DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE, 0x30000),
-	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RXTHRESH_IRQ),
-	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RX_PULSE_IRQ),
-	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_TX_PULSE_IRQ),
-	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_MISC_PULSE_IRQ),
-};
+static struct mdio_platform_data am35xx_mdio_pdata;
 
-static struct platform_device am35xx_emac_device = {
-	.name		= "davinci_emac",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(am35xx_emac_resources),
-	.resource	= am35xx_emac_resources,
-	.dev		= {
-		.platform_data	= &am35xx_emac_pdata,
-	},
-};
+static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh,
+		void *pdata, int pdata_len)
+{
+	struct platform_device *pdev;
+
+	pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len,
+			NULL, 0, false);
+	if (IS_ERR(pdev)) {
+		WARN(1, "Can't build omap_device for %s:%s.\n",
+					oh->class->name, oh->name);
+		return PTR_ERR(pdev);
+	}
+
+	return 0;
+}
 
 void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
 {
-	unsigned int regval;
-	int err;
+	struct omap_hwmod *oh;
+	u32 regval;
+	int ret;
 
-	am35xx_emac_pdata.rmii_en = rmii_en;
-	am35xx_emac_mdio_pdata.bus_freq = mdio_bus_freq;
-	err = platform_device_register(&am35xx_emac_device);
-	if (err) {
-		pr_err("AM35x: failed registering EMAC device: %d\n", err);
+	oh = omap_hwmod_lookup("davinci_mdio");
+	if (!oh) {
+		pr_err("Could not find davinci_mdio hwmod\n");
+		return;
+	}
+
+	am35xx_mdio_pdata.bus_freq = mdio_bus_freq;
+
+	ret = omap_davinci_emac_dev_init(oh, &am35xx_mdio_pdata,
+					 sizeof(am35xx_mdio_pdata));
+	if (ret) {
+		pr_err("Could not build davinci_mdio hwmod device\n");
 		return;
 	}
 
-	err = platform_device_register(&am35xx_emac_mdio_device);
-	if (err) {
-		pr_err("AM35x: failed registering EMAC MDIO device: %d\n", err);
-		platform_device_unregister(&am35xx_emac_device);
+	oh = omap_hwmod_lookup("davinci_emac");
+	if (!oh) {
+		pr_err("Could not find davinci_emac hwmod\n");
+		return;
+	}
+
+	am35xx_emac_pdata.rmii_en = rmii_en;
+
+	ret = omap_davinci_emac_dev_init(oh, &am35xx_emac_pdata,
+					 sizeof(am35xx_emac_pdata));
+	if (ret) {
+		pr_err("Could not build davinci_emac hwmod device\n");
 		return;
 	}
 
arch/arm/mach-omap2/clock3xxx_data.c +1 -1
index 12c64db..f2f422e 100644
@@ -3478,7 +3478,7 @@ static struct omap_clk omap3xxx_clks[] = {
 	CLK(NULL,	"ipss_ick",	&ipss_ick,	CK_AM35XX),
 	CLK(NULL,	"rmii_ck",	&rmii_ck,	CK_AM35XX),
 	CLK(NULL,	"pclk_ck",	&pclk_ck,	CK_AM35XX),
-	CLK("davinci_emac",	NULL,	&emac_ick,	CK_AM35XX),
+	CLK("davinci_emac.0",	NULL,	&emac_ick,	CK_AM35XX),
 	CLK("davinci_mdio.0",	NULL,	&emac_fck,	CK_AM35XX),
 	CLK("vpfe-capture",	"master",	&vpfe_ick,	CK_AM35XX),
 	CLK("vpfe-capture",	"slave",	&vpfe_fck,	CK_AM35XX),
arch/arm/mach-omap2/include/mach/am35xx.h +2 -0
index f1e13d1..9559449 100644
@@ -36,6 +36,8 @@
 #define AM35XX_EMAC_CNTRL_MOD_OFFSET	(0x0)
 #define AM35XX_EMAC_CNTRL_RAM_OFFSET	(0x20000)
 #define AM35XX_EMAC_MDIO_OFFSET		(0x30000)
+#define AM35XX_IPSS_MDIO_BASE		(AM35XX_IPSS_EMAC_BASE + \
+						AM35XX_EMAC_MDIO_OFFSET)
 #define AM35XX_EMAC_CNTRL_RAM_SIZE	(0x2000)
 #define AM35XX_EMAC_RAM_ADDR		(AM3517_EMAC_BASE + \
 						AM3517_EMAC_CNTRL_RAM_OFFSET)
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +85 -0

97 lines not on this page · raw message

Signature · 1 line
1.7.9.4
maintainer
#2 lore raw

PATCH v2 1/2 arm: omap3: am35x: Add Davinci EMAC/MDIO hwmod support

Hi

Quoted 7 lines · Mark A. Greer

From: "Mark A. Greer" <[email protected]>

Add hwmod support for the EMAC (and MDIO)
ethernet controller that's on the am35x
family of SoC's.

I had to update this patch to apply on v3.5-rc4; updated patch below.

- Paul

From: "Mark A. Greer" <[email protected]>
Date: Wed, 27 Jun 2012 14:59:57 -0600
Subject: [PATCH 1/2] ARM: OMAP AM35x: EMAC/MDIO integration: Add Davinci
EMAC/MDIO hwmod support

Add hwmod support for the EMAC (and MDIO)
ethernet controller that's on the am35x
family of SoC's.

[paul at pwsan.com: updated subject line; updated to apply on v3.5-rc4]
---
 arch/arm/mach-omap2/am35xx-emac.c          |   90 ++++++++++++++--------------
 arch/arm/mach-omap2/clock3xxx_data.c       |    2 +-
 arch/arm/mach-omap2/include/mach/am35xx.h  |    2 +
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c |   85 ++++++++++++++++++++++++++
 4 files changed, 134 insertions(+), 45 deletions(-)
arch/arm/mach-omap2/am35xx-emac.c +46 -44
index 447682c..2c90ac6 100644
@@ -15,27 +15,13 @@
  * General Public License for more details.
  */
 
-#include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/davinci_emac.h>
-#include <linux/platform_device.h>
-#include <plat/irqs.h>
+#include <asm/system.h>
+#include <plat/omap_device.h>
 #include <mach/am35xx.h>
-
 #include "control.h"
-
-static struct mdio_platform_data am35xx_emac_mdio_pdata;
-
-static struct resource am35xx_emac_mdio_resources[] = {
-	DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET, SZ_4K),
-};
-
-static struct platform_device am35xx_emac_mdio_device = {
-	.name		= "davinci_mdio",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(am35xx_emac_mdio_resources),
-	.resource	= am35xx_emac_mdio_resources,
-	.dev.platform_data = &am35xx_emac_mdio_pdata,
-};
+#include "am35xx-emac.h"
 
 static void am35xx_enable_emac_int(void)
 {
@@ -69,41 +55,57 @@ static struct emac_platform_data am35xx_emac_pdata = {
 	.interrupt_disable	= am35xx_disable_emac_int,
 };
 
-static struct resource am35xx_emac_resources[] = {
-	DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE, 0x30000),
-	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RXTHRESH_IRQ),
-	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RX_PULSE_IRQ),
-	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_TX_PULSE_IRQ),
-	DEFINE_RES_IRQ(INT_35XX_EMAC_C0_MISC_PULSE_IRQ),
-};
+static struct mdio_platform_data am35xx_mdio_pdata;
 
-static struct platform_device am35xx_emac_device = {
-	.name		= "davinci_emac",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(am35xx_emac_resources),
-	.resource	= am35xx_emac_resources,
-	.dev		= {
-		.platform_data	= &am35xx_emac_pdata,
-	},
-};
+static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh,
+		void *pdata, int pdata_len)
+{
+	struct platform_device *pdev;
+
+	pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len,
+				 NULL, 0, false);
+	if (IS_ERR(pdev)) {
+		WARN(1, "Can't build omap_device for %s:%s.\n",
+		     oh->class->name, oh->name);
+		return PTR_ERR(pdev);
+	}
+
+	return 0;
+}
 
 void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
 {
+	struct omap_hwmod *oh;
 	u32 v;
-	int err;
+	int ret;
 
-	am35xx_emac_pdata.rmii_en = rmii_en;
-	am35xx_emac_mdio_pdata.bus_freq = mdio_bus_freq;
-	err = platform_device_register(&am35xx_emac_device);
-	if (err) {
-		pr_err("AM35x: failed registering EMAC device: %d\n", err);
+	oh = omap_hwmod_lookup("davinci_mdio");
+	if (!oh) {
+		pr_err("Could not find davinci_mdio hwmod\n");
+		return;
+	}
+
+	am35xx_mdio_pdata.bus_freq = mdio_bus_freq;
+
+	ret = omap_davinci_emac_dev_init(oh, &am35xx_mdio_pdata,
+					 sizeof(am35xx_mdio_pdata));
+	if (ret) {
+		pr_err("Could not build davinci_mdio hwmod device\n");
 		return;
 	}
 
-	err = platform_device_register(&am35xx_emac_mdio_device);
-	if (err) {
-		pr_err("AM35x: failed registering EMAC MDIO device: %d\n", err);
-		platform_device_unregister(&am35xx_emac_device);
+	oh = omap_hwmod_lookup("davinci_emac");
+	if (!oh) {
+		pr_err("Could not find davinci_emac hwmod\n");
+		return;
+	}
+
+	am35xx_emac_pdata.rmii_en = rmii_en;
+
+	ret = omap_davinci_emac_dev_init(oh, &am35xx_emac_pdata,
+					 sizeof(am35xx_emac_pdata));
+	if (ret) {
+		pr_err("Could not build davinci_emac hwmod device\n");
 		return;
 	}
 
arch/arm/mach-omap2/clock3xxx_data.c +1 -1
index 1efdec2..10c1395 100644
@@ -3474,7 +3474,7 @@ static struct omap_clk omap3xxx_clks[] = {
 	CLK(NULL,	"ipss_ick",	&ipss_ick,	CK_AM35XX),
 	CLK(NULL,	"rmii_ck",	&rmii_ck,	CK_AM35XX),
 	CLK(NULL,	"pclk_ck",	&pclk_ck,	CK_AM35XX),
-	CLK("davinci_emac",	NULL,	&emac_ick,	CK_AM35XX),
+	CLK("davinci_emac.0",	NULL,	&emac_ick,	CK_AM35XX),
 	CLK("davinci_mdio.0",	NULL,	&emac_fck,	CK_AM35XX),
 	CLK("vpfe-capture",	"master",	&vpfe_ick,	CK_AM35XX),
 	CLK("vpfe-capture",	"slave",	&vpfe_fck,	CK_AM35XX),
arch/arm/mach-omap2/include/mach/am35xx.h +2 -0
index f1e13d1..9559449 100644
@@ -36,6 +36,8 @@
 #define AM35XX_EMAC_CNTRL_MOD_OFFSET	(0x0)
 #define AM35XX_EMAC_CNTRL_RAM_OFFSET	(0x20000)
 #define AM35XX_EMAC_MDIO_OFFSET		(0x30000)
+#define AM35XX_IPSS_MDIO_BASE		(AM35XX_IPSS_EMAC_BASE + \
+						AM35XX_EMAC_MDIO_OFFSET)
 #define AM35XX_EMAC_CNTRL_RAM_SIZE	(0x2000)
 #define AM35XX_EMAC_RAM_ADDR		(AM3517_EMAC_BASE + \
 						AM3517_EMAC_CNTRL_RAM_OFFSET)
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +85 -0

97 lines not on this page · raw message

Signature · 1 line
1.7.10
maintainer
#3 lore raw

PATCH v2 1/2 arm: omap3: am35x: Add Davinci EMAC/MDIO hwmod support

In reply to Mark A. Greer

Hi

one comment on this one

Quoted 14 lines · Mark A. Greer

From: "Mark A. Greer" <[email protected]>

Add hwmod support for the EMAC (and MDIO)
ethernet controller that's on the am35x
family of SoC's.

arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +6 -0
+static struct omap_hwmod_ocp_if am35xx_mdio__l3 = {
+	.master		= &am35xx_mdio_hwmod,
+	.slave		= &omap3xxx_l3_main_hwmod,
+	.clk		= "emac_fck",
+	.user		= OCP_USER_MPU,
+};

...

Quoted 8 lines
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +8 -0
+/* l4_core -> davinci mdio  */
+static struct omap_hwmod_ocp_if am35xx_l4_core__mdio = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &am35xx_mdio_hwmod,
+	.clk		= "emac_fck",
+	.addr		= am35xx_mdio_addrs,
+	.user		= OCP_USER_MPU,
+};

...

arch/arm/mach-omap2/omap_hwmod_3xxx_data.c static struct omap_hwmod_ocp_if omap3xxx_l4_core__usb_tll_hs = { · line 3157

Quoted 8 lines
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +8 -0
+/* l4_core -> davinci emac  */
+static struct omap_hwmod_ocp_if am35xx_l4_core__emac = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &am35xx_emac_hwmod,
+	.clk		= "emac_ick",
+	.addr		= am35xx_emac_addrs,
+	.user		= OCP_USER_MPU,
+};

As I understand it, these devices are actually directly connected to the IPSS. However, for such a topology to work correctly, we'll probably need some changes in the hwmod core. I had hoped to have this done for 3.6, but that's looking pretty unlikely. So instead, will drop some comments in the data to note that this will need to be fixed.

- Paul

#4 lore raw

PATCH v2 2/2 arm: omap3: am35x: Disable hlt when using Davinci EMAC

In reply to Mark A. Greer

From: "Mark A. Greer" <[email protected]>

The am35x family of SoCs has a Davinci EMAC ethernet controller on-chip. Unfortunately, the EMAC is unable to wake the PRCM when there is network activity which leads to a hung or extremely slow system when the MPU has executed a 'wfi' instruction (because of pm_idle or CPUidle). To prevent this, add hooks to the EMAC pm_runtime suspend/resume calls so that hlt is disabled whenever the EMAC is in use.

---
 arch/arm/mach-omap2/am35xx-emac.c |   40 +++++++++++++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/am35xx-emac.c +36 -4
index 3bb5cb3..887a057 100644
@@ -23,6 +23,35 @@
 #include "control.h"
 #include "am35xx-emac.h"
 
+/*
+ * Default pm_lats for the am35x.
+ * The net effect of using am35xx_emac_pm_lats[] is that
+ * pm_idle or CPUidle won't be called while the emac
+ * interface is open.  This is required because the
+ * EMAC can't wake up PRCM so if the MPU is executing
+ * a 'wfi' instruction (e.g., from pm_idle or CPUidle),
+ * it won't break out of it due to emac activity.
+ */
+static int am35xx_emac_deactivate_func(struct omap_device *od)
+{
+	enable_hlt();
+	return omap_device_idle_hwmods(od);
+}
+
+static int am35xx_emac_activate_func(struct omap_device *od)
+{
+	disable_hlt();
+	return omap_device_enable_hwmods(od);
+}
+
+static struct omap_device_pm_latency am35xx_emac_pm_lats[] = {
+	{
+		.deactivate_func	= am35xx_emac_deactivate_func,
+		.activate_func		= am35xx_emac_activate_func,
+		.flags			= OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
 static void am35xx_enable_emac_int(void)
 {
 	u32 regval;
@@ -61,12 +90,13 @@ static struct emac_platform_data am35xx_emac_pdata = {
 static struct mdio_platform_data am35xx_mdio_pdata;
 
 static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh,
-		void *pdata, int pdata_len)
+		void *pdata, int pdata_len,
+		struct omap_device_pm_latency *pm_lats, int pm_lats_size)
 {
 	struct platform_device *pdev;
 
 	pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len,
-			NULL, 0, false);
+			pm_lats, pm_lats_size, false);
 	if (IS_ERR(pdev)) {
 		WARN(1, "Can't build omap_device for %s:%s.\n",
 					oh->class->name, oh->name);
@@ -91,7 +121,7 @@ void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
 	am35xx_mdio_pdata.bus_freq = mdio_bus_freq;
 
 	ret = omap_davinci_emac_dev_init(oh, &am35xx_mdio_pdata,
-					 sizeof(am35xx_mdio_pdata));
+					 sizeof(am35xx_mdio_pdata), NULL, 0);
 	if (ret) {
 		pr_err("Could not build davinci_mdio hwmod device\n");
 		return;
@@ -106,7 +136,9 @@ void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
 	am35xx_emac_pdata.rmii_en = rmii_en;
 
 	ret = omap_davinci_emac_dev_init(oh, &am35xx_emac_pdata,
-					 sizeof(am35xx_emac_pdata));
+					 sizeof(am35xx_emac_pdata),
+					 am35xx_emac_pm_lats,
+					 ARRAY_SIZE(am35xx_emac_pm_lats));
 	if (ret) {
 		pr_err("Could not build davinci_emac hwmod device\n");
 		return;
Signature · 1 line
1.7.9.4
#5 lore raw

PATCH v2 2/2 arm: omap3: am35x: Disable hlt when using Davinci EMAC

Quoted 11 lines · Mark A. Greer

From: "Mark A. Greer" <[email protected]>

The am35x family of SoCs has a Davinci EMAC ethernet controller on-chip. Unfortunately, the EMAC is unable to wake the PRCM when there is network activity which leads to a hung or extremely slow system when the MPU has executed a 'wfi' instruction (because of pm_idle or CPUidle). To prevent this, add hooks to the EMAC pm_runtime suspend/resume calls so that hlt is disabled whenever the EMAC is in use.

Quoted 1 line

Looks good,

maintainer
#6 lore raw

PATCH v2 2/2 arm: omap3: am35x: Disable hlt when using Davinci EMAC

In reply to Mark A. Greer

Hi

Quoted 11 lines · Mark A. Greer

From: "Mark A. Greer" <[email protected]>

The am35x family of SoCs has a Davinci EMAC ethernet controller on-chip. Unfortunately, the EMAC is unable to wake the PRCM when there is network activity which leads to a hung or extremely slow system when the MPU has executed a 'wfi' instruction (because of pm_idle or CPUidle). To prevent this, add hooks to the EMAC pm_runtime suspend/resume calls so that hlt is disabled whenever the EMAC is in use.

Quoted 1 line

This patch has been updated to apply on v3.5-rc4; updated patch below.

- Paul

From: "Mark A. Greer" <[email protected]>
Date: Wed, 27 Jun 2012 15:03:20 -0600
Subject: [PATCH 2/2] ARM: OMAP AM35x: EMAC integration: Disable hlt when
using Davinci EMAC

The am35x family of SoCs has a Davinci EMAC ethernet controller on-chip. Unfortunately, the EMAC is unable to wake the PRCM when there is network activity which leads to a hung or extremely slow system when the MPU has executed a 'wfi' instruction (because of pm_idle or CPUidle). To prevent this, add hooks to the EMAC pm_runtime suspend/resume calls so that hlt is disabled whenever the EMAC is in use.

[paul at pwsan.com: updated subject line; updated to apply on v3.5-rc4]
---
 arch/arm/mach-omap2/am35xx-emac.c |   41 +++++++++++++++++++++++++++++++++----
 1 file changed, 37 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/am35xx-emac.c +37 -4
index 2c90ac6..37639ee 100644
@@ -23,6 +23,35 @@
 #include "control.h"
 #include "am35xx-emac.h"
 
+/*
+ * Default pm_lats for the am35x.
+ * The net effect of using am35xx_emac_pm_lats[] is that
+ * pm_idle or CPUidle won't be called while the emac
+ * interface is open.  This is required because the
+ * EMAC can't wake up PRCM so if the MPU is executing
+ * a 'wfi' instruction (e.g., from pm_idle or CPUidle),
+ * it won't break out of it due to emac activity.
+ */
+static int am35xx_emac_deactivate_func(struct omap_device *od)
+{
+	enable_hlt();
+	return omap_device_idle_hwmods(od);
+}
+
+static int am35xx_emac_activate_func(struct omap_device *od)
+{
+	disable_hlt();
+	return omap_device_enable_hwmods(od);
+}
+
+static struct omap_device_pm_latency am35xx_emac_pm_lats[] = {
+	{
+		.deactivate_func	= am35xx_emac_deactivate_func,
+		.activate_func		= am35xx_emac_activate_func,
+		.flags			= OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
 static void am35xx_enable_emac_int(void)
 {
 	u32 v;
@@ -58,12 +87,14 @@ static struct emac_platform_data am35xx_emac_pdata = {
 static struct mdio_platform_data am35xx_mdio_pdata;
 
 static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh,
-		void *pdata, int pdata_len)
+					     void *pdata, int pdata_len,
+					     struct omap_device_pm_latency *pm_lats,
+					     int pm_lats_size)
 {
 	struct platform_device *pdev;
 
 	pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len,
-				 NULL, 0, false);
+				 pm_lats, pm_lats_size, false);
 	if (IS_ERR(pdev)) {
 		WARN(1, "Can't build omap_device for %s:%s.\n",
 		     oh->class->name, oh->name);
@@ -88,7 +119,7 @@ void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
 	am35xx_mdio_pdata.bus_freq = mdio_bus_freq;
 
 	ret = omap_davinci_emac_dev_init(oh, &am35xx_mdio_pdata,
-					 sizeof(am35xx_mdio_pdata));
+					 sizeof(am35xx_mdio_pdata), NULL, 0);
 	if (ret) {
 		pr_err("Could not build davinci_mdio hwmod device\n");
 		return;
@@ -103,7 +134,9 @@ void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
 	am35xx_emac_pdata.rmii_en = rmii_en;
 
 	ret = omap_davinci_emac_dev_init(oh, &am35xx_emac_pdata,
-					 sizeof(am35xx_emac_pdata));
+					 sizeof(am35xx_emac_pdata),
+					 am35xx_emac_pm_lats,
+					 ARRAY_SIZE(am35xx_emac_pm_lats));
 	if (ret) {
 		pr_err("Could not build davinci_emac hwmod device\n");
 		return;
Signature · 1 line
1.7.10
#7 lore raw

v2 cover arm: omap3: am35x: Convert emac to hwmod & disable hlt when open

In reply to Mark A. Greer
Quoted 10 lines · Mark A. Greer

From: "Mark A. Greer" <[email protected]>

These patches convert the davinci emac support for the am35x SoC to use hwmod and add enable_hlt()/disable_hlt() calls to the pm_runtime hooks for that driver.

I have converted the davinci_emac driver to use pm_runtime but I can't formally submit it yet since it requires some changes on the mach-davinci side that haven't happened yet. I will send it as an RFC in a reply to this thread.

I haven't seen any patches for the davinci runtime PM support, so I thought I would do a quick patch to show how easy it is to use some generic PM core code to manage clocks in runtime PM.

The patch below implments this on davinci but has only been boot tested on my ancient dm6446 EVM. Combined with Mark's RFC patch to convert davinci_emac to runtime PM, it was working fine on dm6446 to enable the emac clocks.

Kevin

Quoted 1 line

From 7a90e650ad8542b7f85076b58703e94bdc058562 Mon Sep 17 00:00:00 2001

From: Kevin Hilman <[email protected]>
Date: Thu, 31 May 2012 09:59:53 -0700
Subject: [PATCH] ARM: davinci: add runtime PM support for clock management

Add runtime PM core support to davinci by using the pm_clk infrastructure of the PM core.

When runtime PM is enabled, the davinci runtime PM implementation will use the pm_clk layer to enable/disable clocks on demand. When runtime PM is disabled, the pm_clk core will automatically enable clocks when the driver is bound and disable clocks when the driver is unbound.

Cc Mark A. Greer <[email protected]>
Cc Sekhar Nori <nsekhar at ti.com

---
Applies on v3.4

 arch/arm/mach-davinci/Makefile    |    1 +
 arch/arm/mach-davinci/pm_domain.c |   70 +++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+)
 create mode 100644 arch/arm/mach-davinci/pm_domain.c
arch/arm/mach-davinci/Makefile +1 -0
index 2db78bd..2227eff 100644
@@ -39,3 +39,4 @@ obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD)	+= board-omapl138-hawk.o
 obj-$(CONFIG_CPU_FREQ)			+= cpufreq.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_SUSPEND)			+= pm.o sleep.o
+obj-$(CONFIG_HAVE_CLK)			+= pm_domain.o
arch/arm/mach-davinci/pm_domain.c new file +70 -0

70 lines not on this page · raw message

Signature · 1 line
1.7.9.2
maintainer
#8 lore raw

v2 cover arm: omap3: am35x: Convert emac to hwmod & disable hlt when open

In reply to Mark A. Greer

Hi

Quoted 12 lines · Mark A. Greer

From: "Mark A. Greer" <[email protected]>

These patches convert the davinci emac support for the am35x SoC to use hwmod and add enable_hlt()/disable_hlt() calls to the pm_runtime hooks for that driver.

I have converted the davinci_emac driver to use pm_runtime but I can't formally submit it yet since it requires some changes on the mach-davinci side that haven't happened yet. I will send it as an RFC in a reply to this thread.

The patches are based on:

Quoted 8 lines
        git://git.pwsan.com/linux-2.6 am35xx_hwmod_data_fixes_a_3.5

Changes from v1:
- patch 1/2, "arm: omap3: am35x: Add Davinci EMAC/MDIO hwmod support" is unchanged
- patch 2/2, "arm: "omap3: am35x: Disable hlt when using Davinci EMAC" has been reworked to keep the code as simple as possible per
http://www.spinics.net/lists/linux-omap/msg70354.html

The updated patches that were just reposted today have been queued for 3.6, along with a few comments about the IPSS issue, mentioned earlier. They can be found in the branch am35xx_emac_mdio_devel_3.6 in
git://git.pwsan.com/linux-2.6. Please let me know if you have any comments.

- Paul