Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Aug 2009 09:35:50 +0000 (UTC)
From:      Rafal Jaworowski <raj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r196532 - head/sys/arm/mv
Message-ID:  <200908250935.n7P9Zonj022179@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: raj
Date: Tue Aug 25 09:35:50 2009
New Revision: 196532
URL: http://svn.freebsd.org/changeset/base/196532

Log:
  Properly handle initial state of power mgmt.
  
  Modules on Marvell SOC can be selectively PM-disabled, and we must not access
  disabled devices' registers (attempt to initialize them) unconditionally, as
  this leads to the system hang. This patch introduces graceful handling of the
  PM state during devices init.
  
  Submitted by:	Michal Hajduk
  Obtained from:	Semihalf

Modified:
  head/sys/arm/mv/common.c
  head/sys/arm/mv/mvreg.h
  head/sys/arm/mv/mvvar.h

Modified: head/sys/arm/mv/common.c
==============================================================================
--- head/sys/arm/mv/common.c	Tue Aug 25 09:30:03 2009	(r196531)
+++ head/sys/arm/mv/common.c	Tue Aug 25 09:35:50 2009	(r196532)
@@ -32,8 +32,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
+#include <sys/kernel.h>
 
 #include <machine/bus.h>
 
@@ -62,6 +64,76 @@ static void decode_win_usb_dump(void);
 
 static uint32_t used_cpu_wins;
 
+static __inline int
+pm_is_disabled(uint32_t mask)
+{
+
+	return (soc_power_ctrl_get(mask) == mask ? 0 : 1);
+}
+
+static __inline uint32_t
+obio_get_pm_mask(uint32_t base)
+{
+	struct obio_device *od;
+
+	for (od = obio_devices; od->od_name != NULL; od++)
+		if (od->od_base == base)
+			return (od->od_pwr_mask);
+
+	return (CPU_PM_CTRL_NONE);
+}
+
+/*
+ * Disable device using power management register.
+ * 1 - Device Power On
+ * 0 - Device Power Off
+ * Mask can be set in loader.
+ * EXAMPLE:
+ * loader> set hw.pm-disable-mask=0x2
+ *
+ * Common mask:
+ * |-------------------------------|
+ * | Device | Kirkwood | Discovery |
+ * |-------------------------------|
+ * | USB0   | 0x00008  | 0x020000  |
+ * |-------------------------------|
+ * | USB1   |     -    | 0x040000  |
+ * |-------------------------------|
+ * | USB2   |     -    | 0x080000  |
+ * |-------------------------------|
+ * | GE0    | 0x00001  | 0x000002  |
+ * |-------------------------------|
+ * | GE1    |     -    | 0x000004  |
+ * |-------------------------------|
+ * | IDMA   |     -    | 0x100000  |
+ * |-------------------------------|
+ * | XOR    | 0x10000  | 0x200000  |
+ * |-------------------------------|
+ * | CESA   | 0x20000  | 0x400000  |
+ * |-------------------------------|
+ * | SATA   | 0x04000  | 0x004000  |
+ * --------------------------------|
+ * This feature can be used only on Kirkwood and Discovery
+ * machines.
+ */
+static __inline void
+pm_disable_device(int mask)
+{
+#ifdef DIAGNOSTIC
+	uint32_t reg;
+
+	reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL);
+	printf("Power Management Register: 0%x\n", reg);
+
+	reg &= ~mask;
+	soc_power_ctrl_set(reg);
+	printf("Device %x is disabled\n", mask);
+
+	reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL);
+	printf("Power Management Register: 0%x\n", reg);
+#endif
+}
+
 uint32_t
 read_cpu_ctrl(uint32_t reg)
 {
@@ -103,14 +175,36 @@ cpu_extra_feat(void)
 	return (ef);
 }
 
+/*
+ * Get the power status of device. This feature is only supported on
+ * Kirkwood and Discovery SoCs.
+ */
 uint32_t
 soc_power_ctrl_get(uint32_t mask)
 {
 
+#ifndef SOC_MV_ORION
 	if (mask != CPU_PM_CTRL_NONE)
 		mask &= read_cpu_ctrl(CPU_PM_CTRL);
 
 	return (mask);
+#else
+	return (mask);
+#endif
+}
+
+/*
+ * Set the power status of device. This feature is only supported on
+ * Kirkwood and Discovery SoCs.
+ */
+void
+soc_power_ctrl_set(uint32_t mask)
+{
+
+#ifndef SOC_MV_ORION
+	if (mask != CPU_PM_CTRL_NONE)
+		write_cpu_ctrl(CPU_PM_CTRL, mask);
+#endif
 }
 
 void
@@ -191,6 +285,13 @@ int
 soc_decode_win(void)
 {
 	uint32_t dev, rev;
+	int mask;
+
+	mask = 0;
+	TUNABLE_INT_FETCH("hw.pm-disable-mask", &mask);
+
+	if (mask != 0)
+		pm_disable_device(mask);
 
 	/* Retrieve our ID: some windows facilities vary between SoC models */
 	soc_id(&dev, &rev);
@@ -623,8 +724,12 @@ decode_win_usb_setup(void)
 
 	/* Disable and clear all USB windows for all ports */
 	m = usb_max_ports();
+
 	for (p = 0; p < m; p++) {
 
+		if (pm_is_disabled(CPU_PM_CTRL_USB(p)))
+			continue;
+
 		for (i = 0; i < MV_WIN_USB_MAX; i++) {
 			win_usb_cr_write(i, p, 0);
 			win_usb_br_write(i, p, 0);
@@ -710,6 +815,9 @@ decode_win_eth_setup(uint32_t base)
 	uint32_t br, sz;
 	int i, j;
 
+	if (pm_is_disabled(obio_get_pm_mask(base)))
+		return;
+
 	/* Disable, clear and revoke protection for all ETH windows */
 	for (i = 0; i < MV_WIN_ETH_MAX; i++) {
 
@@ -880,6 +988,8 @@ decode_win_idma_setup(void)
 	uint32_t br, sz;
 	int i, j;
 
+	if (pm_is_disabled(CPU_PM_CTRL_IDMA))
+		return;
 	/*
 	 * Disable and clear all IDMA windows, revoke protection for all channels
 	 */
@@ -1172,6 +1282,9 @@ decode_win_xor_setup(void)
 	uint32_t br, sz;
 	int i, j, z, e = 1, m, window;
 
+	if (pm_is_disabled(CPU_PM_CTRL_XOR))
+		return;
+
 	/*
 	 * Disable and clear all XOR windows, revoke protection for all
 	 * channels
@@ -1364,6 +1477,9 @@ decode_win_cesa_setup(void)
 	uint32_t br, cr;
 	int i, j;
 
+	if (pm_is_disabled(CPU_PM_CTRL_CRYPTO))
+		return;
+
 	/* Disable and clear all CESA windows */
 	for (i = 0; i < MV_WIN_CESA_MAX; i++) {
 		win_cesa_cr_write(i, 0);
@@ -1432,6 +1548,9 @@ decode_win_sata_setup(void)
 	uint32_t cr, br;
 	int i, j;
 
+	if (pm_is_disabled(CPU_PM_CTRL_SATA))
+		return;
+
 	for (i = 0; i < MV_WIN_SATA_MAX; i++) {
 		win_sata_cr_write(i, 0);
 		win_sata_br_write(i, 0);

Modified: head/sys/arm/mv/mvreg.h
==============================================================================
--- head/sys/arm/mv/mvreg.h	Tue Aug 25 09:30:03 2009	(r196531)
+++ head/sys/arm/mv/mvreg.h	Tue Aug 25 09:35:50 2009	(r196532)
@@ -218,6 +218,7 @@
  */
 #define CPU_PM_CTRL		0x1C
 #define CPU_PM_CTRL_NONE	0
+#define CPU_PM_CTRL_ALL		~0x0
 
 #if defined(SOC_MV_KIRKWOOD)
 #define CPU_PM_CTRL_GE0		(1 << 0)
@@ -234,8 +235,11 @@
 #define CPU_PM_CTRL_SATA1	(1 << 15)
 #define CPU_PM_CTRL_XOR1	(1 << 16)
 #define CPU_PM_CTRL_CRYPTO	(1 << 17)
-#define CPU_PM_CTRL_GE1		(1 << 18)
-#define CPU_PM_CTRL_TDM		(1 << 19)
+#define CPU_PM_CTRL_GE1		(1 << 19)
+#define CPU_PM_CTRL_TDM		(1 << 20)
+#define CPU_PM_CTRL_XOR		(CPU_PM_CTRL_XOR0 | CPU_PM_CTRL_XOR1)
+#define CPU_PM_CTRL_USB(u)	(CPU_PM_CTRL_USB0)
+#define CPU_PM_CTRL_SATA	(CPU_PM_CTRL_SATA0 | CPU_PM_CTRL_SATA1)
 #elif defined(SOC_MV_DISCOVERY)
 #define CPU_PM_CTRL_GE0		(1 << 1)
 #define CPU_PM_CTRL_GE1		(1 << 2)
@@ -258,6 +262,14 @@
 #define CPU_PM_CTRL_XOR		(1 << 21)
 #define CPU_PM_CTRL_CRYPTO	(1 << 22)
 #define CPU_PM_CTRL_DEVICE	(1 << 23)
+#define CPU_PM_CTRL_USB(u)	(1 << (17 + (u)))
+#define CPU_PM_CTRL_SATA	(CPU_PM_CTRL_SATA0 | CPU_PM_CTRL_SATA1)
+#else
+#define CPU_PM_CTRL_CRYPTO	(CPU_PM_CTRL_NONE)
+#define CPU_PM_CTRL_IDMA	(CPU_PM_CTRL_NONE)
+#define CPU_PM_CTRL_XOR		(CPU_PM_CTRL_NONE)
+#define CPU_PM_CTRL_SATA	(CPU_PM_CTRL_NONE)
+#define CPU_PM_CTRL_USB(u)	(CPU_PM_CTRL_NONE)
 #endif
 
 /*

Modified: head/sys/arm/mv/mvvar.h
==============================================================================
--- head/sys/arm/mv/mvvar.h	Tue Aug 25 09:30:03 2009	(r196531)
+++ head/sys/arm/mv/mvvar.h	Tue Aug 25 09:35:50 2009	(r196532)
@@ -135,6 +135,7 @@ void soc_id(uint32_t *dev, uint32_t *rev
 void soc_identify(void);
 void soc_dump_decode_win(void);
 uint32_t soc_power_ctrl_get(uint32_t mask);
+void soc_power_ctrl_set(uint32_t mask);
 
 int decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size,
     int remap);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200908250935.n7P9Zonj022179>