linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
From: Felix Domke <tmbinc@elitedvb.net>
To: Linuxppc-dev@ozlabs.org
Subject: [patch 6/7] xenon: add SMC support
Date: Wed, 07 Mar 2007 19:01:50 +0100	[thread overview]
Message-ID: <20070307180526.334384000@elitedvb.net> (raw)
In-Reply-To: 20070307180144.812594000@elitedvb.net

This adds lowlevel support for the "System Management Controller"
on the Xenon southbridge, which controls power, the frontpanel leds, 
infrared remote, tilt switch, AVIP detection, RTC and DVD tray control.

It requires a userspace daemon.

Signed-off-by: Felix Domke <tmbinc@elitedvb.net>

---
 drivers/char/Kconfig     |    6 +
 drivers/char/Makefile    |    1 
 drivers/char/xenon_smc.c |  280 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 287 insertions(+)

Index: linux-2.6.20/drivers/char/Kconfig
===================================================================
--- linux-2.6.20.orig/drivers/char/Kconfig	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/char/Kconfig	2007-03-07 19:01:22.000000000 +0100
@@ -350,6 +350,12 @@
 	  this case.  If you have never heard about all this, it's safe to
 	  say N.
 
+config XENON_SMC
+	bool "Xenon SMC"
+	depends on PPC_XENON
+	help
+	  SMC controller in the Xbox 360.
+
 config STALLION
 	tristate "Stallion EasyIO or EC8/32 support"
 	depends on STALDRV && BROKEN_ON_SMP
Index: linux-2.6.20/drivers/char/Makefile
===================================================================
--- linux-2.6.20.orig/drivers/char/Makefile	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/char/Makefile	2007-03-07 19:01:22.000000000 +0100
@@ -55,6 +55,7 @@
 obj-$(CONFIG_HVCS)		+= hvcs.o
 obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
 obj-$(CONFIG_BRIQ_PANEL)	+= briq_panel.o
+obj-$(CONFIG_XENON_SMC)  += xenon_smc.o
 
 obj-$(CONFIG_PRINTER)		+= lp.o
 obj-$(CONFIG_TIPAR)		+= tipar.o
Index: linux-2.6.20/drivers/char/xenon_smc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/drivers/char/xenon_smc.c	2007-03-07 19:01:22.000000000 +0100
@@ -0,0 +1,280 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+#define DRV_NAME	"xenon_smc"
+#define DRV_VERSION	"0.1"
+
+struct xenon_smc
+{
+	void __iomem *base;
+	unsigned long is_active;
+	wait_queue_head_t wait;
+};
+
+static struct xenon_smc *first_smc;
+
+#define to_smc(pdev) dev_get_drvdata(&pdev->dev)
+
+static int get_smc(struct xenon_smc *ctx, u8 *msg);
+static void send_smc(struct xenon_smc *ctx, void *msg);
+static irqreturn_t xenon_smc_irq(int irq, void *dev_id);
+static ssize_t smc_write(struct file *file, const char __user *data,
+				size_t len, loff_t *ppos);
+static int smc_ioctl(struct inode *inode, struct file *file,
+				unsigned int cmd, unsigned long arg);
+static ssize_t smc_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos);
+static int smc_open(struct inode *inode, struct file *file);
+static int smc_release(struct inode *inode, struct file *file);
+static int xenon_smc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void __devexit xenon_smc_remove(struct pci_dev *pdev);
+
+static const struct pci_device_id xenon_smc_pci_tbl[] = {
+	{ PCI_VDEVICE(MICROSOFT, 0x580d), 0 },
+	{ }	/* terminate list */
+};
+
+static struct pci_driver xenon_smc_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= xenon_smc_pci_tbl,
+	.probe			= xenon_smc_init_one,
+	.remove     = __devexit_p(xenon_smc_remove)
+};
+
+static const struct file_operations smc_fops = {
+	.owner =  THIS_MODULE,
+	.llseek = no_llseek,
+	.write =  smc_write,
+	.ioctl =  smc_ioctl,
+	.open =	  smc_open,
+	.read =   smc_read,
+	.release = smc_release,
+};
+
+static struct miscdevice smc_miscdev = {
+	.minor =  RTC_MINOR,
+	.name =   "smc",
+	.fops =	  &smc_fops,
+};
+
+MODULE_DESCRIPTION("Driver for Xenon Southbridge SMC");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, xenon_smc_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static int get_smc(struct xenon_smc *ctx, u8 *msg)
+{
+	if (readl(ctx->base + 0x94) & 4)
+	{
+		u32 *message = (u32*)msg;
+		int i;
+		writel(4, ctx->base + 0x94);
+		for (i=0; i<4; ++i)
+			message[i] = __raw_readl(ctx->base + 0x90);
+		writel(0, ctx->base + 0x94);
+		return 1;
+	}
+	return 0;
+}
+
+static void send_smc(struct xenon_smc *ctx, void *msg)
+{
+	while (!(readl(ctx->base + 0x84) & 4));
+	writel(4, ctx->base + 0x84);
+	__raw_writel(*(u32*)(msg+0), ctx->base + 0x80);
+	__raw_writel(*(u32*)(msg+4), ctx->base + 0x80);
+	__raw_writel(*(u32*)(msg+8), ctx->base + 0x80);
+	__raw_writel(*(u32*)(msg+12), ctx->base + 0x80);
+	writel(0, ctx->base + 0x84);
+}
+
+static irqreturn_t xenon_smc_irq(int irq, void *dev_id)
+{
+	struct pci_dev *pdev = dev_id;
+	struct xenon_smc *ctx = to_smc(pdev);
+
+	unsigned int irqs = readl(ctx->base + 0x50) & 0x10000000;
+	if (irqs)
+		wake_up(&ctx->wait);
+
+	writel(irqs, ctx->base + 0x58); // ack irq
+
+	return IRQ_HANDLED;
+}
+
+static ssize_t smc_write(struct file *file, const char __user *data,
+			     size_t len, loff_t *ppos)
+{
+	unsigned char msg[16];
+	if (len != 16)
+		return -EINVAL;
+
+	if (copy_from_user(msg, data, 16))
+		return -EFAULT;
+
+	send_smc(first_smc, msg);
+
+	return 16;
+}
+
+static int smc_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	return -ENODEV;
+}
+
+static ssize_t smc_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos)
+{
+	struct xenon_smc *ctx = first_smc;
+	int ret;
+	u8 msg[0x10];
+
+	if (len != 16)
+		return -EINVAL;
+
+	if (!(readl(ctx->base + 0x94) & 4))
+	{
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		ret = wait_event_interruptible(ctx->wait, readl(ctx->base + 0x94) & 4);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (get_smc(ctx, msg) == 0)
+		return -EAGAIN;
+
+	if (copy_to_user(data, msg, 0x10))
+		return -EFAULT;
+
+	return 0x10;
+}
+
+static int smc_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &first_smc->is_active))
+		return -EBUSY;
+
+	return nonseekable_open(inode, file);
+}
+
+static int smc_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &first_smc->is_active);
+	return 0;
+}
+
+static void show_logo(struct xenon_smc *ctx)
+{
+	unsigned char msg[16] = {0x99, 0x01, 0x63, 0};
+	send_smc(ctx, msg);
+}
+
+static int xenon_smc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	int rc;
+	int pci_dev_busy = 0;
+	struct xenon_smc *ctx;
+	unsigned long mmio_start;
+
+	if (!printed_version++)
+		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	ctx = kzalloc(sizeof(struct xenon_smc), GFP_KERNEL);
+	if (!ctx)
+		goto err_out_free;
+
+	dev_set_drvdata(&pdev->dev, ctx);
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	pci_intx(pdev, 1);
+
+	printk(KERN_INFO "attached to xenon SMC\n");
+
+	rc = misc_register(&smc_miscdev);
+	if (rc != 0)
+	{
+		printk(KERN_ERR "xenonsmc: misc_register failed.\n");
+		goto err_out_regions;
+	}
+
+	mmio_start = pci_resource_start (pdev, 0);
+	ctx->base = ioremap(mmio_start, 0x100);
+
+	if (!first_smc)
+		first_smc = ctx;
+
+	init_waitqueue_head(&ctx->wait);
+
+	if (request_irq(pdev->irq, xenon_smc_irq, IRQF_SHARED, "xenonsmc", pdev))
+	{
+		printk(KERN_ERR "xenonsmc: request_irq failed\n");
+		goto err_out_ioremap;
+	}
+
+	show_logo(ctx);
+
+	return 0;
+
+err_out_ioremap:
+	iounmap(ctx->base);
+
+err_out_regions:
+	pci_release_regions(pdev);
+
+err_out_free:
+	kfree(ctx);
+
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+
+}
+
+static void __devexit xenon_smc_remove(struct pci_dev *pdev)
+{
+	struct xenon_smc *ctx = to_smc(pdev);
+
+	if (ctx == first_smc)
+		first_smc = 0;
+
+	misc_deregister(&smc_miscdev);
+	iounmap(ctx->base);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static int __init xenon_smc_init(void)
+{
+	return pci_register_driver(&xenon_smc_pci_driver);
+}
+
+static void __exit xenon_smc_exit(void)
+{
+	pci_unregister_driver(&xenon_smc_pci_driver);
+}
+
+module_init(xenon_smc_init);
+module_exit(xenon_smc_exit);

--

  parent reply	other threads:[~2007-03-07 18:01 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
2007-03-07 18:01 ` [patch 1/7] xenon: add PCI Vendor ID: Microsoft Felix Domke
2007-03-07 18:01 ` [patch 2/7] xenon: add platform support Felix Domke
2007-03-07 23:06   ` Arnd Bergmann
2007-03-07 18:01 ` [patch 3/7] xenon: udbg support (ugly) Felix Domke
2007-03-07 21:00   ` Geert Uytterhoeven
2007-03-07 18:01 ` [patch 4/7] xenon: add southbridge ethernet support Felix Domke
2007-03-07 23:27   ` Arnd Bergmann
2007-03-07 18:01 ` [patch 5/7] xenon: add SATA support Felix Domke
2007-03-07 21:02   ` Sergei Shtylyov
2007-03-07 21:07     ` Felix Domke
2007-03-07 21:14       ` Sergei Shtylyov
2007-03-07 18:01 ` Felix Domke [this message]
2007-03-07 21:54   ` [patch 6/7] xenon: add SMC support Arnd Bergmann
2007-03-08 23:29   ` Linas Vepstas
2007-03-07 18:01 ` [patch 7/7] xenon: add framebuffer support (ugly) Felix Domke
2007-03-07 21:06 ` [patch 0/7] [RFC] Xenon support Josh Boyer
2007-03-07 21:14   ` Felix Domke
2007-03-08  9:48   ` Benjamin Herrenschmidt
2007-03-08  0:35 ` Stephen Rothwell
2007-03-08  0:52   ` Felix Domke
2007-03-08 11:02   ` Christoph Hellwig
2007-03-08 23:50   ` Linas Vepstas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070307180526.334384000@elitedvb.net \
    --to=tmbinc@elitedvb.net \
    --cc=Linuxppc-dev@ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).