[PATCH] DCON: Add the DCON platform device
Jordan Crouse
jordan.crouse at amd.unroutablecom
Wed Nov 29 11:14:54 EST 2006
Commit: aca4163a73dc442bfe24ab1e1462513504c162df
Parent: 89ca0c5a674fcf78fd87bb541e75ae3139422ecb
commit aca4163a73dc442bfe24ab1e1462513504c162df
Author: Jordan Crouse <jordan.crouse at amd.com>
AuthorDate: Thu Oct 5 16:51:32 2006 -0600
Commit: Jordan Crouse <jordan.crouse at amd.com>
CommitDate: Fri Oct 6 09:26:07 2006 -0600
[PATCH] DCON: Add the DCON platform device
---
arch/i386/kernel/olpc.c | 4
drivers/video/backlight/dcon_bl.c | 6 -
drivers/video/geode/gxfb_core.c | 17 +
drivers/video/geode/gxfb_dcon.c | 444 +++++++++++++++++++++++--------------
drivers/video/geode/gxfb_dcon.h | 12 +
5 files changed, 297 insertions(+), 186 deletions(-)
diff --git a/arch/i386/kernel/olpc.c b/arch/i386/kernel/olpc.c
index ffa4823..33ac22d 100644
--- a/arch/i386/kernel/olpc.c
+++ b/arch/i386/kernel/olpc.c
@@ -1,4 +1,4 @@
-/* Support for the OLPC Childrens Machine
+/* Support for the OLPC DCON
* Copyright (C) 2006, Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@ static int __init olpc_init(void) {
unsigned char val;
- /* Read the DCON present bit and set the flag accordingly */
+ /* Read the DCON present bit in the CMOS and set the flag accordingly */
val = CMOS_READ(OLPC_CMOS_DCON_OFFSET);
olpc_dcon_present = (val & OLPC_CMOS_DCON_MASK);
diff --git a/drivers/video/backlight/dcon_bl.c b/drivers/video/backlight/dcon_bl.c
index d356c36..78403da 100644
--- a/drivers/video/backlight/dcon_bl.c
+++ b/drivers/video/backlight/dcon_bl.c
@@ -27,12 +27,12 @@ static int dconbl_set(struct backlight_d
if (power != FB_BLANK_UNBLANK)
level = 0;
- gxfb_dcon_setbl(level);
+ dcon_set_backlight(level);
return 0;
}
static int dconbl_get(struct backlight_device *dev) {
- return gxfb_dcon_getbl();
+ return dcon_get_backlight();
}
static struct backlight_properties dcon_data = {
@@ -49,7 +49,7 @@ static int dconbl_probe(struct platform_
if (IS_ERR(dconbl_dev))
return PTR_ERR(dconbl_dev);
- dcon_data.brightness = gxfb_dcon_getbl();
+ dcon_data.brightness = dcon_get_backlight();
return 0;
}
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index ab14dda..7617e3d 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -121,8 +121,6 @@ static const struct fb_videomode gx_dcon
extern int olpc_dcon_present;
#endif
-unsigned long gxfb_dc_regs;
-EXPORT_SYMBOL(gxfb_dc_regs);
static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
@@ -249,8 +247,6 @@ static int __init gxfb_map_video_memory(
if (!par->dc_regs)
return -ENOMEM;
- gxfb_dc_regs = par->dc_regs;
-
ret = pci_request_region(dev, 0, "gxfb (framebuffer)");
if (ret < 0)
return ret;
@@ -281,13 +277,14 @@ static int __init gxfb_map_video_memory(
return 0;
}
-int (*gxfb_ioctl_func)(struct fb_info *info, unsigned int cmd, unsigned long arg);
+int (*gxfb_ioctl_func)(struct fb_info *, unsigned int, unsigned long);
EXPORT_SYMBOL(gxfb_ioctl_func);
-gxfb_ioctl( struct fb_info *info, unsigned int cmd, unsigned long arg) {
-
+static int gxfb_ioctl( struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
int ret = -ENOTTY;
-
+
if (gxfb_ioctl_func != NULL)
ret = gxfb_ioctl_func(info, cmd, arg);
@@ -346,7 +343,8 @@ static struct fb_info * __init gxfb_init
return info;
}
-static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int __init gxfb_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
{
struct geodefb_par *par;
struct fb_info *info;
@@ -359,6 +357,7 @@ static int __init gxfb_probe(struct pci_
info = gxfb_init_fbinfo(&pdev->dev);
if (!info)
return -ENOMEM;
+
par = info->par;
/* GX display controller and GX video device. */
diff --git a/drivers/video/geode/gxfb_dcon.c b/drivers/video/geode/gxfb_dcon.c
index ec1489a..e745e89 100644
--- a/drivers/video/geode/gxfb_dcon.c
+++ b/drivers/video/geode/gxfb_dcon.c
@@ -1,6 +1,6 @@
/*
* Mainly by David Woodhouse, somewhat modified by Jordan Crouse
- *
+ *
* Jordan's work is copyright (C) 2006 Advanced Micro Devices, Inc.
*
* This program is free software. You can redistribute it and/or
@@ -16,9 +16,13 @@ #include "geodefb.h"
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/i2c-id.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
+#include <linux/ctype.h>
#include <asm/tsc.h>
#include "gxfb_dcon.h"
@@ -47,176 +51,167 @@ static struct i2c_driver dcon_driver;
static struct i2c_client *dcon_client;
/* Platform devices */
-static struct platform_device *dcon_bl_dev;
+static struct platform_device *dcon_device;
+static struct platform_device *dconbl_device;
/* Base address of the GPIO registers */
static unsigned long gpio_base;
+/* fbinfo from the GX framebuffer driver */
+static struct fb_info *fbinfo;
+
/* Current source */
static int dcon_source = DCON_SOURCE_CPU;
/* Current output type */
static int dcon_output = DCON_OUTPUT_COLOR;
+/* Current sleep status (not yet implemented) */
+static int dcon_sleep = DCON_ACTIVE;
+
/* Shadow register for the DCON_REG_MODE register */
static unsigned short dcon_disp_mode;
/* Variables used during switches */
-int dcon_waiting;
+static int dcon_switched;
-static DECLARE_WAIT_QUEUE_HEAD(dcon_mode_wq);
-extern unsigned long gxfb_dc_regs;
+static DECLARE_WAIT_QUEUE_HEAD(dcon_wait_queue);
extern int gxfb_powerdown(struct fb_info *info);
extern int gxfb_powerup(struct fb_info *info);
+extern int (*gxfb_ioctl_func)(struct fb_info *, unsigned int, unsigned long);
+
+static unsigned short normal_i2c[] = { 0x0D, I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
#define dcon_write(reg,val) i2c_smbus_write_word_data(dcon_client,reg,val)
#define dcon_read(reg) i2c_smbus_read_word_data(dcon_client,reg)
/* ===== API functions - these are called by a variety of users ==== */
+/* The current backlight value - this saves us some smbus traffic */
static int gxfb_bl_val = -1;
-/* To cut down on SMBUS, we assume that getbl and setbl are the only entities that change the BL,
- so we shadow the variable
-*/
-
-int gxfb_dcon_getbl(void) {
+/* Backlight notes - turning off the backlight enable bit in the DCON
+ * doesn't save us any power over just pushing the BL to zero, so we
+ * don't use that bit in this code.
+ */
- if (dcon_client == NULL)
- return 0;
+int dcon_get_backlight(void)
+{
+ if (dcon_client == NULL)
+ return 0;
- if (gxfb_bl_val == -1)
- gxfb_bl_val = dcon_read(DCON_REG_BRIGHT) & 0x0F;
+ if (gxfb_bl_val == -1)
+ gxfb_bl_val = dcon_read(DCON_REG_BRIGHT) & 0x0F;
- return (dcon_disp_mode & MODE_BL_ENABLE) ? gxfb_bl_val : 0;
+ return gxfb_bl_val;
}
-void gxfb_dcon_setbl(int level) {
+void dcon_set_backlight(int level)
+{
+ if (dcon_client == NULL)
+ return;
- if (dcon_client == NULL)
- return;
+ if (gxfb_bl_val == (level & 0x0F))
+ return;
- if (level == 0) {
- if ((dcon_disp_mode & MODE_BL_ENABLE)) {
- dcon_disp_mode &= ~MODE_BL_ENABLE;
- dcon_write(DCON_REG_MODE, dcon_disp_mode);
- }
+ gxfb_bl_val = level & 0x0F;
+ dcon_write(DCON_REG_BRIGHT, gxfb_bl_val);
+}
+
+/* Set the output type to either color or mono */
+
+static int dcon_set_output(int arg)
+{
+ if (dcon_output == arg)
+ return 0;
- return;
- }
+ dcon_output = arg;
- if (!(dcon_disp_mode & MODE_BL_ENABLE)) {
- dcon_disp_mode |= MODE_BL_ENABLE;
- dcon_write(DCON_REG_MODE, dcon_disp_mode);
- }
+ if (arg == DCON_OUTPUT_MONO) {
+ dcon_disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA);
+ dcon_disp_mode |= MODE_MONO_LUMA;
+ }
+ else {
+ dcon_disp_mode &= ~(MODE_MONO_LUMA);
+ dcon_disp_mode |= (MODE_CSWIZZLE | MODE_COL_AA);
+ }
- gxfb_bl_val = level & 0x0F;
- dcon_write(DCON_REG_BRIGHT, gxfb_bl_val);
+ dcon_write(DCON_REG_MODE, dcon_disp_mode);
+ return 0;
}
-EXPORT_SYMBOL(gxfb_dcon_getbl);
-EXPORT_SYMBOL(gxfb_dcon_setbl);
+EXPORT_SYMBOL(dcon_get_backlight);
+EXPORT_SYMBOL(dcon_set_backlight);
-static int dcon_set_source(struct fb_info *info, int arg)
-{
- struct geodefb_par *par = info->par;
+/* Set the source of the display (CPU or DCON) */
+static int dcon_set_source(int arg)
+{
if (dcon_source == arg)
return 0;
dcon_source = arg;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dcon_switched = 0;
+
if (arg == DCON_SOURCE_CPU) {
- unsigned long timeo = jiffies + (10 * HZ);
- unsigned long scanline1, scanline2;
- /* Power up the graphics engine */
- gxfb_powerup(info);
+ /* FIXME: Set the task uninterruptable for this bit? */
- /* Wait for up to a second for our output to coincide with
- DCON's */
+ /* Enable the scanline interrupt bit */
+ dcon_write(DCON_REG_MODE, dcon_disp_mode | MODE_SCAN_INT);
- while (time_before(jiffies, timeo)) {
- unsigned long dconblnk =
- (inl(gpio_base + GPIOx_READ_BACK) >> 12) & 1;
- scanline1 =
- readl((void __iomem *)(gxfb_dc_regs + 0x6c));
- scanline1 >>= 16;
- scanline1 &= 0x7ff;
+ /* Wait up to one second for the mode to change */
+ wait_event_timeout(dcon_wait_queue, dcon_switched == 1, HZ);
- if (!dconblnk && scanline1 >= resumeline &&
- scanline1 <= (resumeline+2))
- goto ready;
+ /* Turn off the scanline interrupt */
+ dcon_write(DCON_REG_MODE, dcon_disp_mode);
-#if 0
- if (!dconblnk)
- printk("Not ready. blnk %ld, line %ld\n",
- dconblnk, scanline1);
-#endif
+ if (!dcon_switched) {
+ printk(KERN_ERR "dcon: Timeout entering CPU mode\n");
+ return -1;
}
- printk("Wait for VGA ready timed out\n");
-ready:
+ /* Turn on the graphics engine */
+ gxfb_powerup(fbinfo);
outl(1<<11, gpio_base + GPIOx_OUT_VAL);
- scanline2 = readl((void __iomem *)(gxfb_dc_regs + 0x6c));
- scanline2 >>= 16;
- scanline2 &= 0x7ff;
- printk("Re-enabled between %ld and %ld\n",
- scanline1, scanline2);
- } else {
+ printk(KERN_INFO "dcon: The CPU has control\n");
+ }
+ else {
int t;
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(&dcon_mode_wq, &wait);
+ add_wait_queue(&dcon_wait_queue, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
- dcon_waiting = 1;
- /* Clear GPIO11 (DCONLOAD) - this implies that the DCON is in
+ /* Clear GPIO11 (DCONLOAD) - this implies that the DCON is in
control */
outl(1 << (11 + 16), gpio_base + GPIOx_OUT_VAL);
-
+
t = schedule_timeout(HZ/2);
- remove_wait_queue(&dcon_mode_wq, &wait);
+ remove_wait_queue(&dcon_wait_queue, &wait);
set_current_state(TASK_RUNNING);
- if (dcon_waiting) {
- printk("Timeout entering DCON mode\n");
+ if (!dcon_switched) {
+ printk(KERN_ERR "dcon: Timeout entering DCON mode\n");
- /* Re-enable GPIO11 - we never gave up control */
+ /* Set DCONLOAD back to CPU control */
outl(1 << 11, gpio_base + GPIOx_OUT_VAL);
-
return -1;
}
/* Turn off the graphics engine completely */
- gxfb_powerdown(info);
- }
-
- return 0;
-}
-
-static int dcon_set_output(struct fb_info *info, int arg)
-{
- if (dcon_output == arg)
- return 0;
-
- dcon_output = arg;
-
- if (arg == DCON_OUTPUT_MONO) {
- dcon_disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA);
- dcon_disp_mode |= MODE_MONO_LUMA;
- }
- else {
- dcon_disp_mode &= ~(MODE_MONO_LUMA);
- dcon_disp_mode |= (MODE_CSWIZZLE | MODE_COL_AA);
+ gxfb_powerdown(fbinfo);
+ printk(KERN_INFO "dcon: The DCON has control\n");
}
- i2c_smbus_write_word_data(dcon_client, DCON_REG_MODE, dcon_disp_mode);
-
+ dcon_source = arg;
return 0;
}
@@ -236,9 +231,9 @@ static int gxfb_dcon_ioctl(struct fb_inf
return -EINVAL;
if (karg > -1)
- ret = dcon_set_source(info, karg);
+ ret = dcon_set_source(karg);
- if (ret)
+ if (ret)
karg = -1;
else
karg = dcon_source;
@@ -254,9 +249,9 @@ static int gxfb_dcon_ioctl(struct fb_inf
return -EINVAL;
if (karg > -1)
- ret = dcon_set_output(info, karg);
+ ret = dcon_set_output(karg);
- if (ret)
+ if (ret)
return ret;
karg = dcon_output;
@@ -293,11 +288,11 @@ static int gxfb_dcon_ioctl(struct fb_inf
karg = 0;
break;
- case DCONIOC_SETBL:
+ case DCONIOC_SETBL:
if (get_user(karg, (int __user *)arg))
return -EFAULT;
- gxfb_dcon_setbl(karg);
+ dcon_set_backlight(karg);
karg = 0;
break;
@@ -305,7 +300,7 @@ static int gxfb_dcon_ioctl(struct fb_inf
if (get_user(karg, (int __user *)arg))
return -EFAULT;
- karg = gxfb_dcon_getbl();
+ karg = dcon_get_backlight();
break;
default:
@@ -316,22 +311,123 @@ static int gxfb_dcon_ioctl(struct fb_inf
return ret;
}
-static unsigned short normal_i2c[] = { 0x0D, I2C_CLIENT_END };
-I2C_CLIENT_INSMOD;
+static ssize_t dcon_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%4.4X\n", dcon_disp_mode);
+}
+
+static ssize_t dcon_sleep_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", dcon_sleep);
+}
+
+static ssize_t dcon_source_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", dcon_source);
+}
+
+static ssize_t dcon_output_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", dcon_output);
+}
+
+static int _strtoul(const char *buf, int len, unsigned int *val)
+{
+
+ char *endp;
+ unsigned int output = simple_strtoul(buf, &endp, 0);
+ int size = endp - buf;
+
+ if (*endp && isspace(*endp))
+ size++;
+
+ if (size != len)
+ return -EINVAL;
+
+ *val = output;
+ return 0;
+}
+
+static ssize_t dcon_output_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int output;
+ int rc = -EINVAL;
+
+ if (_strtoul(buf, count, &output))
+ return -EINVAL;
+
+ if (output == DCON_OUTPUT_COLOR || output == DCON_OUTPUT_MONO) {
+ dcon_set_output(output);
+ rc = count;
+ }
+
+ return rc;
+}
-extern int (*gxfb_ioctl_func)(struct fb_info *info, unsigned int cmd,
- unsigned long arg);
+static ssize_t dcon_source_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int output;
+ int rc = -EINVAL;
+
+ if (_strtoul(buf, count, &output))
+ return -EINVAL;
+
+ if (output == DCON_SOURCE_CPU || output == DCON_SOURCE_DCON) {
+ dcon_set_source(output);
+ rc = count;
+ }
+
+ return rc;
+}
+
+#if 0
+/* FIXME: I haven't yet implemented sleep support */
+static ssize_t dcon_sleep_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int output;
+ int rc = -EINVAL;
+
+ if (_strtoul(buf, count, &output))
+ return -EINVAL;
+
+ dcon_sleep(output ? DCON_SLEEP : DCON_ACTIVE);
+ return count;
+}
+#endif
+
+static struct device_attribute dcon_device_files[] = {
+ __ATTR(mode, 0444, dcon_mode_show, NULL),
+ __ATTR(sleep, 0644, dcon_sleep_show, NULL),
+ __ATTR(source, 0644, dcon_source_show, dcon_source_store),
+ __ATTR(output, 0644, dcon_output_show, dcon_output_store),
+};
static int dcon_probe(struct i2c_adapter *adap, int addr, int kind)
{
struct i2c_client *client;
+ struct pci_dev *dev;
uint16_t ver;
- int rc;
+ int rc, i;
+
+ dev = pci_find_device(PCI_VENDOR_ID_NS,PCI_DEVICE_ID_NS_GX_VIDEO,
+ NULL);
+
+ if (dev == NULL || (fbinfo = pci_get_drvdata(dev)) == NULL) {
+ printk(KERN_ERR "dcon: Couldn't find the GX GPU device\n");
+ return -ENXIO;
+ }
if (adap->id != I2C_HW_SMBUS_SCX200) {
printk(KERN_ERR "gxfb-dcon: Invalid I2C bus (%d not %d)\n",
- adap->id, I2C_HW_SMBUS_SCX200);
+ adap->id, I2C_HW_SMBUS_SCX200);
return -ENXIO;
}
@@ -346,25 +442,17 @@ static int dcon_probe(struct i2c_adapter
if ((rc = i2c_attach_client(client)) != 0) {
printk(KERN_ERR "gxfb-dcon: Unable to attach the I2C client.\n");
- kfree(client);
- return rc;
+ goto eclient;
}
ver = i2c_smbus_read_word_data(client, DCON_REG_ID);
if ((ver >> 8) != 0xDC) {
- /* Not a DCON chip? */
printk(KERN_ERR "gxfb-dcon: DCON ID not 0xDCxx: 0x%04x instead.\n", ver);
- i2c_detach_client(client);
- kfree(client);
- return -ENXIO;
+ rc = -ENXIO;
+ goto ei2c;
}
- printk(KERN_INFO "gxfb-dcon: Discovered DCON version %x\n", ver & 0xFF);
-
- dcon_client = client;
- gxfb_ioctl_func = gxfb_dcon_ioctl;
-
if (!noinit) {
/* Initialize the DCON registers */
@@ -377,7 +465,7 @@ static int dcon_probe(struct i2c_adapter
MODE_CSWIZZLE | MODE_COL_AA;
i2c_smbus_write_word_data(client, DCON_REG_MODE,
- dcon_disp_mode);
+ dcon_disp_mode);
/* Initialise SDRAM */
@@ -393,22 +481,62 @@ static int dcon_probe(struct i2c_adapter
i2c_smbus_write_word_data(client, 0x43, 0x0101);
}
- /* Now create a backlight device on the platform bus - note that failures here are non fatal */
+ /* Set the scanline to interrupt on during resume */
- dcon_bl_dev = platform_device_alloc("dcon-bl", -1);
+ i2c_smbus_write_word_data(client, DCON_REG_SCAN_INT, resumeline);
- if (dcon_bl_dev == NULL) {
- printk(KERN_INFO "gxfb-dcon: Couldn't allocate the BL device.\n");
- return 0;
+ /* Add the DCON device */
+
+ dcon_device = platform_device_alloc("dcon", -1);
+
+ if (dcon_device == NULL) {
+ printk(KERN_ERR "dcon: Unable to create the DCON device\n");
+ rc = -ENOMEM;
+ goto ei2c;
+ }
+
+ if ((rc = platform_device_add(dcon_device))) {
+ printk(KERN_ERR "dcon: Unable to add the DCON device\n");
+ goto edev;
+ }
+
+ for(i = 0; i < ARRAY_SIZE(dcon_device_files); i++)
+ device_create_file(&dcon_device->dev, &dcon_device_files[i]);
+
+ /* Add the DCON backlight device (for use by the backlight engine) */
+
+ dconbl_device = platform_device_alloc("dcon-bl", -1);
+
+ if (dconbl_device == NULL) {
+ printk(KERN_ERR "dcon: Unable to create the DCON backlight device\n");
+ rc = -ENOMEM;
+ goto edev;
}
- if (platform_device_add(dcon_bl_dev)) {
- printk(KERN_INFO "gxfb-dcon: Couldn't attach the BL device.\n");
- platform_device_put(dcon_bl_dev);
- dcon_bl_dev = NULL;
+ if ((rc = platform_device_add(dconbl_device))) {
+ printk(KERN_ERR "dcon: Unable to add the DCON backlight device\n");
+ goto ebldev;
}
+ dcon_client = client;
+ gxfb_ioctl_func = gxfb_dcon_ioctl;
+
+ printk(KERN_INFO "gxfb-dcon: Discovered DCON version %x\n", ver & 0xFF);
+
return 0;
+
+ ebldev:
+ platform_device_unregister(dconbl_device);
+ dconbl_device = NULL;
+ edev:
+ platform_device_unregister(dcon_device);
+ dcon_device = NULL;
+ ei2c:
+ i2c_detach_client(client);
+ eclient:
+ kfree(client);
+
+ return rc;
}
static int dcon_attach(struct i2c_adapter *adap)
@@ -432,8 +560,11 @@ static int dcon_detach(struct i2c_client
if ((rc = i2c_detach_client(client)) == 0)
kfree(i2c_get_clientdata(client));
- if (dcon_bl_dev != NULL)
- platform_device_unregister(dcon_bl_dev);
+ if (dconbl_device != NULL)
+ platform_device_unregister(dconbl_device);
+
+ if (dcon_device != NULL)
+ platform_device_unregister(dcon_device);
return rc;
}
@@ -448,45 +579,27 @@ static struct i2c_driver dcon_driver = {
};
-
-int dcon_interrupt(int irq, void *id, struct pt_regs *regs)
+static int dcon_interrupt(int irq, void *id, struct pt_regs *regs)
{
- unsigned long gpios = inl(gpio_base + GPIOx_READ_BACK);
- int dconstat = (gpios >> 5) & 3;
- int dconblnk = (gpios >> 12) & 1;
- cycles_t foo = get_cycles();
- static cycles_t foo1;
- static int lastec7;
-
- unsigned long scanline = readl((void __iomem *)(gxfb_dc_regs + 0x6c));
- int ec7 = inl(gpio_base + 0xDC);
- int dconirq = (gpios >> 7) & 1;
-
- scanline >>= 16;
- scanline &= 0x7ff;
- printk("IRQ! TSC %08lx (+%ld), line %ld, STAT %d BLNK %d IRQ %d EC7 %d:+%d\n",
- (long)foo, (long)(foo-foo1), scanline, dconstat, dconblnk, dconirq, ec7, ec7-lastec7);
- foo1 = foo;
- lastec7 = ec7;
+ unsigned long gin = inl(gpio_base + GPIOx_READ_BACK);
+ int dconstat = (gin >> 5) & 3;
/* Clear the negative edge status for GPIO7 */
outl(1 << 7, gpio_base + GPIOx_NEGEDGE_STS);
-#if 0
- printk("GPIOL_NEGEDGE_STS[7] is %d\n", (inl(gpio_base+0x4c)>>7) & 1);
+ if (dconstat == 2 || dconstat == 1) {
+ if (dconstat == 2)
+ printk("IRQ - switch to DCON mode\n");
+ else
+ printk("IRQ - switch to CPU mode\n");
- outl(1<<7, gpio_base+0x4c);
- outl(1<<(16+7), gpio_base + GPIOx_EVNTCNT_EN);
- outl(1<<(7), gpio_base + GPIOx_EVNTCNT_EN);
-#endif
- if (dconstat == 2) {
- dcon_waiting = 0;
- wake_up(&dcon_mode_wq);
+ dcon_switched = 1;
+ wake_up(&dcon_wait_queue);
}
+
return IRQ_HANDLED;
}
-
/* List of GPIOs that we care about:
(in) GPIO12 -- DCONBLNK
(in) GPIO[56] -- DCONSTAT[01]
@@ -505,7 +618,7 @@ int __init gxfb_dcon_init(void)
/* Check the mask and whether GPIO is enabled (sanity check) */
if (hi != 0x0000f001) {
- printk(KERN_WARNING "GPIO not enabled -- cannot use DCON\n");
+ printk(KERN_ERR "GPIO not enabled -- cannot use DCON\n");
return -ENODEV;
}
@@ -521,7 +634,7 @@ int __init gxfb_dcon_init(void)
outl(1 << (16 + 7), gpio_base + GPIOx_EVNT_EN);
/* Set up the interrupt mappings first, so we can collect the
- * first interrupt when it happens
+ * first interrupt when it happens
*/
hi = inl(gpio_base + GPIO_MAP_X);
@@ -533,7 +646,7 @@ int __init gxfb_dcon_init(void)
hi = inl(gpio_base + GPIO_MAP_Y);
hi &= 0xfff0ffff;
- hi |= 0x00000000;
+ hi |= 0x00000000;
outl(hi, gpio_base + GPIO_MAP_Y);
/* Enable GPIO IRQ 7 to trigger the PIC interrupt in the Z sources */
@@ -606,4 +719,3 @@ module_init(gxfb_dcon_init);
module_exit(gxfb_dcon_exit);
MODULE_LICENSE("GPL");
-
diff --git a/drivers/video/geode/gxfb_dcon.h b/drivers/video/geode/gxfb_dcon.h
index 140f2f0..522bd7a 100644
--- a/drivers/video/geode/gxfb_dcon.h
+++ b/drivers/video/geode/gxfb_dcon.h
@@ -65,15 +65,15 @@ #define DCON_SOURCE_CPU 1
#define DCON_OUTPUT_COLOR 0
#define DCON_OUTPUT_MONO 1
+/* Sleep values */
+#define DCON_ACTIVE 0
+#define DCON_SLEEPING 1
+
/* Interrupt */
#define DCON_IRQ 6
-/* Functions available to the world */
-
-/* Set the backlight */
-void gxfb_dcon_setbl(int);
-/* Get the backlight value */
-int gxfb_dcon_getbl(void);
+void dcon_set_backlight(int);
+int dcon_get_backlight(void);
#endif
More information about the Commits-kernel
mailing list