[PATCH] OLPC Infrastructure

Jordan Crouse jordan.crouse at amd.com
Tue Jan 23 13:33:30 EST 2007


We're getting ready to do a strong push for power management, which
means we're going to be doing a lot more interesting things to
obscure devices like MFGPT timers and GPIO pins.  We're also going to
start to care about the board revision and even the version of the 
EC firmware as new features are added and changed.

So to prepare for this, I am proposing some infrastructure bits that should
help us.

include/asm-i386/geode.h is a dumping ground for the various
MSR and registers that we use, particularly for those blocks that get
used by multiple drivers (such as the GPIO pins).  I also added some macros
to help make it easier to access the GPIO pins.  Those will no doubt change
as our needs do.  

include/asm-i386/olpc.h is the home of the OLPC specific infrastructure - 
in particular machine_is_olpc(), olpc_has_dcon() and olpc_get_rev() functions
to assist drivers in determining whats attached.  These were previous
available through multiple variables, I basically just defined a info
structure, and populated it with a few important fields.  I also started
defining some interesting system wide bits, such as #defines for the GPIO
pins we control.

the rest of the patch is collateral to support the above code.  I use the
brute force method of determining the board revision, just to get something
working.  I know that other more elegant proposals are on the table, but
thats a battle for a different theater of the war.  My only intent here is
to gain some consensus on the API that the rest of the system will use -
what actually happens in the guts of olpc.c is, in the end, irrelevant.

So, comments welcome - if all agree, then we'll push this to the 
experimental tree first, and then it will move to the stable tree in 
due time.

Regards,
Jordan

-- 
Jordan Crouse
Senior Linux Engineer
Advanced Micro Devices, Inc.
<www.amd.com/embeddedprocessors>
-------------- next part --------------
[PATCH] Add header files for Geode & OLPC

From: Jordan Crouse <jordan.crouse at amd.com>

We want to start abstrating some of the Geode and OLPC defines and
access functions so that our upcoming power code flows better.
---

diff --git a/arch/i386/kernel/olpc-pm.c b/arch/i386/kernel/olpc-pm.c
index 01c8adc..930c4e5 100644
--- a/arch/i386/kernel/olpc-pm.c
+++ b/arch/i386/kernel/olpc-pm.c
@@ -10,7 +10,8 @@
 #include <linux/input.h>
 #include <asm/io.h>
 
-extern int machine_is_olpc;
+#include <asm/olpc.h>
+
 #define PM_IRQ 3
 
 
@@ -47,7 +48,7 @@ static int __init olpc_pm_init(void)
 	uint32_t lo, hi;
 	int ret;
 
-	if (!machine_is_olpc)
+	if (machine_is_olpc())
 		return -ENODEV;
 
 	pm_inputdev = input_allocate_device();
diff --git a/arch/i386/kernel/olpc.c b/arch/i386/kernel/olpc.c
index efdd54a..c7e98f4 100644
--- a/arch/i386/kernel/olpc.c
+++ b/arch/i386/kernel/olpc.c
@@ -12,6 +12,15 @@
 #include <linux/init.h>
 #include <linux/mc146818rtc.h>
 
+#include <asm/olpc.h>
+
+/* This is our new multi-purpose structure used to contain the
+ * information about the platform that we detect
+ */
+
+struct olpc_platform_t olpc_platform_info;
+EXPORT_SYMBOL_GPL(olpc_platform_info);
+
 /*********************************************************************
  *		EC locking and access
  *********************************************************************/
@@ -39,7 +48,7 @@ void unlock_ec(void)
 }
 EXPORT_SYMBOL_GPL(unlock_ec);
 
-/* wait for either input or output buffer full, io is 1 for input, 
+/* wait for either input or output buffer full, io is 1 for input,
 0 for output */
 static int wait_bf(int io)
 {
@@ -82,9 +91,12 @@ unsigned short read_ec_word(unsigned sho
 }
 EXPORT_SYMBOL_GPL(read_ec_word);
 
-int write_ec_command(unsigned char command)
+/* This code actually issues the command - and returns what the EC returns */
+
+static
+int do_ec_command(unsigned char command)
 {
-	unsigned char ec_resp;
+	unsigned char resp = -EIO;
 
 	if (lock_ec())
 		return -EIO;
@@ -92,28 +104,34 @@ int write_ec_command(unsigned char comma
 	outb(command, 0x6c);
 
 	/* wait for IBF */
-	if (wait_bf(1)) {
-		unlock_ec();
-		return -EIO;
-	}
-	
+	if (wait_bf(1))
+		goto err;
+
 	/* wait for OBF */
-	if (wait_bf(0)) {
-		unlock_ec();
-		return -EIO;
-	}
-	
-	ec_resp = inb(0x68);
-	if (ec_resp) {
-		printk(KERN_ERR "EC failure: %x\n", ec_resp);
-		unlock_ec();
-		return -EIO;
-	}
+	if (wait_bf(0))
+		goto err;
+
+	resp = inb(0x68);
 
+err:
 	unlock_ec();
+	return resp;
+}
 
-	return 0;
+/* This function writes a command, but expects a zero response on success */
+
+int write_ec_command(unsigned char command)
+{
+	int resp = do_ec_command(command);
+
+	if (resp > 0) {
+		printk(KERN_ERR "EC failure %x\n", resp);
+		return -EIO;
+	}
+
+	return resp;
 }
+
 EXPORT_SYMBOL_GPL(write_ec_command);
 
 /*********************************************************************
@@ -131,11 +149,7 @@ static void olpc_power_off(void)
 	outb(0x00, 0x383);
 }
 
-
-int machine_is_olpc;
-EXPORT_SYMBOL_GPL(machine_is_olpc);
-
-int olpc_dcon_present = -1;
+static int olpc_dcon_present = -1;
 module_param(olpc_dcon_present, int, 0444);
 
 /* REV_A CMOS map:
@@ -145,12 +159,17 @@ module_param(olpc_dcon_present, int, 044
 #define OLPC_CMOS_DCON_OFFSET (440 / 8)
 #define OLPC_CMOS_DCON_MASK   0x01
 
+static char *olpc_boardrev_str[] = { "Unknown", "A", "B1", "B2" };
+
 static int __init olpc_init(void)
 {
 	unsigned char val;
 	unsigned char *romsig;
+	unsigned int rev;
+	u64 pllval;
 
 	romsig = ioremap(0xffffffc0, 16);
+
 	if (!romsig)
 		return 0;
 
@@ -162,15 +181,52 @@ static int __init olpc_init(void)
 	}
 	printk(KERN_INFO "OLPC board with OpenFirmware: %.16s\n", romsig);
 
-	machine_is_olpc = 1;
+	olpc_platform_info.flags |= OLPC_F_PRESENT;
+
 	pm_power_off = olpc_power_off;
 
 	/* Read the DCON present bit in the CMOS and set the flag accordingly */
 	val = CMOS_READ(OLPC_CMOS_DCON_OFFSET);
+
 	if (olpc_dcon_present == -1)
 		olpc_dcon_present = (val & OLPC_CMOS_DCON_MASK);
 
-	printk(KERN_INFO "CMOS DCON_PRESENT: %d\n", olpc_dcon_present);
+	if (olpc_dcon_present)
+		olpc_platform_info.flags |= OLPC_F_DCON;
+
+	/* Try to determine the platform information */
+
+	/* Check the bootstraps */
+	rdmsrl(GX_GLCP_SYS_RSTPLL, pllval);
+
+	/* We think that 0x05 is the "default" value for B1 and earlier
+	 * boards.  Presumably that value won't be reused again
+	 */
+
+	rev = ((pllval >> 4) & 0x07);
+
+	olpc_platform_info.boardrev = OLPC_REV_UNKNOWN;
+
+	if (rev != 5) {
+		/* This could probably qualify for a table lookup */
+
+		switch(rev) {
+			case 0:
+				olpc_platform_info.boardrev = OLPC_REV_B2;
+				break;
+		}
+	}
+	else {
+		int ret = do_ec_command(0x09);
+		/* If the return value is 0x09, then this is a Aboard */
+		if (ret == 0x09)
+			olpc_platform_info.boardrev = OLPC_REV_A;
+		else
+			olpc_platform_info.boardrev = OLPC_REV_B1;
+	}
+
+	printk(KERN_INFO "OLPC board revision: %s\n",
+		olpc_boardrev_str[olpc_platform_info.boardrev]);
 
  unmap:
 	iounmap(romsig);
@@ -179,4 +235,3 @@ static int __init olpc_init(void)
 }
 
 subsys_initcall(olpc_init);
-EXPORT_SYMBOL_GPL(olpc_dcon_present);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 6513dc3..48da313 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -39,6 +39,7 @@ Change log:
 #include <linux/netdevice.h>
 #include <linux/usb.h>
 #include <asm/io.h>
+#include <asm/olpc.h>
 
 #include "host.h"
 #include "sbi.h"
@@ -728,8 +729,6 @@ int libertas_sbi_read_event_cause(wlan_p
 	return WLAN_STATUS_SUCCESS;
 }
 
-extern int machine_is_olpc;
-
 int reset_device(wlan_private *priv)
 {
 	int ret;
@@ -737,7 +736,7 @@ int reset_device(wlan_private *priv)
 	ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RESET,
 			   	    HostCmd_ACT_HALT, 0, 0, NULL);
 #ifdef CONFIG_OLPC
-	if (machine_is_olpc) {
+	if (machine_is_olpc()) {
 		/* Frob the GPIO ED pin on the EC to reset the poxy thing too */
 
 		/* Set DATA low */
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index 144780c..f2715c8 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -32,6 +32,10 @@
 #include <linux/pci.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_OLPC
+#include <asm/olpc.h>
+#endif
+
 #include "geodefb.h"
 #include "display_gx.h"
 #include "video_gx.h"
@@ -119,8 +123,6 @@ static const struct fb_videomode gx_dcon
 	{ NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
 	  0, FB_VMODE_NONINTERLACED, 0 }
 };
-
-extern int olpc_dcon_present;
 #endif
 
 
@@ -437,7 +439,7 @@ static int __init gxfb_probe(struct pci_
 	modedb_size = ARRAY_SIZE(gx_modedb);
 
 #ifdef CONFIG_OLPC
-	if (olpc_dcon_present) {
+	if (olpc_has_dcon()) {
 		modedb_ptr = (struct fb_videomode *) gx_dcon_modedb;
 		modedb_size = ARRAY_SIZE(gx_dcon_modedb);
 	}
diff --git a/include/asm-i386/geode.h b/include/asm-i386/geode.h
new file mode 100644
index 0000000..f17ebe5
--- /dev/null
+++ b/include/asm-i386/geode.h
@@ -0,0 +1,97 @@
+/* AMD Geode definitions
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_GEODE_H_
+#define _ASM_GEODE_H_
+
+/* MSRS */
+
+#define GX_GLCP_SYS_RSTPLL      0x4C000014
+#define MSR_LBAR_GPIO           0x5140000C
+#define MSR_LBAR_ACPI		0x5140000E
+#define MSR_LBAR_PMS		0x5140000F
+
+/* ACPI registers (PMS block) */
+
+/* PM1_EN is only valid when VSA is enabled for 16 bit reads
+ * When VSA is not enabled, *always* read both PM1_STS and PM1_EN
+ * with a 32 bit read at offset 0x0
+ */
+
+#define PM1_STS                0x00
+#define PM1_EN                 0x02
+#define PM1_CNT                0x08
+#define PM2_CNT                0x0C
+#define PM_TMR                 0x10
+#define PM_GPEO_STS            0x18
+#define PM_GPE0_EN             0x1C
+
+/* PMC registers (PMS block) */
+
+#define PM_SSD                 0x00
+#define PM_SCXA                0x04
+#define PM_SCYA                0x08
+#define PM_OUT_SLPCTL          0x0C
+#define PM_SCLK                0x10
+#define PM_SED                 0x1
+#define PM_SCXD                0x18
+#define PM_SCYD                0x1C
+#define PM_IN_SLPCTL           0x20
+#define PM_WKD                 0x30
+#define PM_WKXD                0x34
+#define PM_RD                  0x38
+#define PM_WKXA                0x3C
+#define PM_FSD                 0x40
+#define PM_TSD                 0x44
+#define PM_PSD                 0x48
+#define PM_NWKD                0x4C
+#define PM_AWKD                0x50
+#define PM_SSC                 0x54
+
+/* GPIO */
+
+#define GPIO_OUTPUT_VAL        0x00
+#define GPIO_OUTPUT_ENABLE     0x04
+#define GPIO_OUTPUT_OPEN_DRAIN 0x08
+#define GPIO_OUTPUT_INVERT     0x0C
+#define GPIO_OUTPUT_AUX1       0x10
+#define GPIO_OUTPUT_AUX2       0x14
+#define GPIO_PULL_UP           0x18
+#define GPIO_PULL_DOWN         0x1C
+#define GPIO_INPUT_ENABLE      0x20
+#define GPIO_INPUT_INVERT      0x24
+#define GPIO_INPUT_FILTER      0x28
+#define GPIO_INPUT_EVENT_COUNT 0x2C
+#define GPIO_READ_BACK         0x30
+#define GPIO_INPUT_AUX1        0x34
+#define GPIO_EVENTS_ENABLE     0x38
+#define GPIO_LOCK_ENABLE       0x3C
+#define GPIO_POSITIVE_EDGE_EN  0x40
+#define GPIO_NEGATIVE_EDGE_EN  0x44
+#define GPIO_POSITIVE_EDGE_STS 0x48
+#define GPIO_NEGATIVE_EDGE_STS 0x4C
+
+#define GPIO_MAP_X 0xE0
+#define GPIO_MAP_Y 0xE4
+#define GPIO_MAP_Z 0xE8
+#define GPIO_MAP_W 0xEC
+
+/* The low GPIO pins are 0 - 15 */
+#define GPIO_LO(o) (o)
+
+/* The high gpio pins are 16 - 28 */
+#define GPIO_HI(o) (o + 0x80)
+
+/* Useful macros */
+
+#define GPIO_REG(p, r) (p < 16 ? GPIO_LO(r) : GPIO_HI(r))
+#define GPIO_SET_MASK(p) ( p < 16 ? (1 << p) : (1 << (p - 16)))
+#define GPIO_CLEAR_MASK(p) ( p < 16 ? (1 << (p + 16)) : (1 << p))
+
+#endif
diff --git a/include/asm-i386/olpc.h b/include/asm-i386/olpc.h
new file mode 100644
index 0000000..c578e4a
--- /dev/null
+++ b/include/asm-i386/olpc.h
@@ -0,0 +1,51 @@
+/* OLPC machine specific definitions */
+
+#ifndef ASM_OLPC_H_
+#define ASM_OLPC_H_
+
+#include <asm/geode.h>
+
+struct olpc_platform_t {
+	int flags;
+	int boardrev;
+	int ecver;
+};
+
+extern struct olpc_platform_t olpc_platform_info;
+
+#define OLPC_F_PRESENT 0x01
+#define OLPC_F_DCON    0x02
+
+#define OLPC_REV_UNKNOWN     0x00
+#define OLPC_REV_A           0x01
+#define OLPC_REV_B1          0x02
+#define OLPC_REV_B2          0x03
+
+static inline int
+machine_is_olpc(void)
+{
+	return (olpc_platform_info.flags & OLPC_F_PRESENT) ? 1 : 0;
+}
+
+static inline int
+olpc_has_dcon(void)
+{
+	return (olpc_platform_info.flags & OLPC_F_DCON) ? 1 : 0;
+}
+
+static inline int
+olpc_get_rev(void)
+{
+	return olpc_platform_info.boardrev;
+}
+
+/* GPIO assignments */
+
+#define OLPC_GPIO_MIC_AC      1
+#define OLPC_GPIO_THRM_ALRM  10
+#define OLPC_GPIO_WORKAUX    24
+#define OLPC_GPIO_LID        26
+#define OLPC_GPIO_ECSCI      27
+
+#endif
+


More information about the Devel mailing list