From: Tony Lindgren <tony@atomide.com>
To: linux-omap@vger.kernel.org
Cc: Tony Lindgren <tony@atomide.com>
Subject: [PATCH 10/10] ARM: OMAP: Move STI support to drivers/misc
Date: Wed, 12 Mar 2008 12:45:50 +0200 [thread overview]
Message-ID: <1205318750-9596-11-git-send-email-tony@atomide.com> (raw)
In-Reply-To: <1205318750-9596-10-git-send-email-tony@atomide.com>
This is to allow syncing plat-omap with mainline kernel.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
arch/arm/plat-omap/Makefile | 3 -
arch/arm/plat-omap/sti/Makefile | 4 -
arch/arm/plat-omap/sti/sti-console.c | 189 ---------------
arch/arm/plat-omap/sti/sti-fifo.c | 117 ---------
arch/arm/plat-omap/sti/sti-netlink.c | 152 ------------
arch/arm/plat-omap/sti/sti.c | 432 ----------------------------------
drivers/misc/Makefile | 1 +
drivers/misc/sti/Makefile | 4 +
drivers/misc/sti/sti-console.c | 189 +++++++++++++++
drivers/misc/sti/sti-fifo.c | 117 +++++++++
drivers/misc/sti/sti-netlink.c | 152 ++++++++++++
drivers/misc/sti/sti.c | 432 ++++++++++++++++++++++++++++++++++
12 files changed, 895 insertions(+), 897 deletions(-)
delete mode 100644 arch/arm/plat-omap/sti/Makefile
delete mode 100644 arch/arm/plat-omap/sti/sti-console.c
delete mode 100644 arch/arm/plat-omap/sti/sti-fifo.c
delete mode 100644 arch/arm/plat-omap/sti/sti-netlink.c
delete mode 100644 arch/arm/plat-omap/sti/sti.c
create mode 100644 drivers/misc/sti/Makefile
create mode 100644 drivers/misc/sti/sti-console.c
create mode 100644 drivers/misc/sti/sti-fifo.c
create mode 100644 drivers/misc/sti/sti-netlink.c
create mode 100644 drivers/misc/sti/sti.c
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index c1ada8f..a3f1f5c 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -14,9 +14,6 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
-# STI support
-obj-$(CONFIG_OMAP_STI) += sti/
-
obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o
diff --git a/arch/arm/plat-omap/sti/Makefile b/arch/arm/plat-omap/sti/Makefile
deleted file mode 100644
index 6ad9bb3..0000000
--- a/arch/arm/plat-omap/sti/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-y += sti.o sti-fifo.o
-
-obj-$(CONFIG_OMAP_STI_CONSOLE) += sti-console.o
-obj-$(CONFIG_NET) += sti-netlink.o
diff --git a/arch/arm/plat-omap/sti/sti-console.c b/arch/arm/plat-omap/sti/sti-console.c
deleted file mode 100644
index 451a139..0000000
--- a/arch/arm/plat-omap/sti/sti-console.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Console support for OMAP STI/XTI
- *
- * Copyright (C) 2004, 2005, 2006 Nokia Corporation
- * Written by: Paul Mundt <paul.mundt@nokia.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <asm/arch/sti.h>
-#include <asm/arch/board.h>
-
-#define DRV_NAME "sticon"
-
-static struct tty_driver *tty_driver;
-static DEFINE_SPINLOCK(sti_console_lock);
-static unsigned int sti_console_channel = -1;
-static int sti_line_done = -1;
-
-/*
- * Write a string to any channel (including terminating NULL)
- * Returns number of characters written.
- */
-static int sti_channel_puts(const char *string, unsigned int channel, int len)
-{
- int count = 0;
-
- /*
- * sti_line_done is needed to determine when we have reached the
- * end of the line. write() has a tendency to hand us small
- * strings which otherwise end up creating newlines.. we need to
- * keep the channel open and in append mode until the line has
- * been terminated.
- */
- if (sti_line_done != 0) {
-#ifdef __LITTLE_ENDIAN
- sti_channel_writeb(0xc3, channel);
-#else
- sti_channel_writeb(0xc0, channel);
-#endif
- xchg(&sti_line_done, 0);
- }
-
- while (*string && count != len) {
- char c = *string++;
-
- count++;
-
- if (c == '\n') {
- xchg(&sti_line_done, 1);
- sti_channel_writeb(0, channel);
- break;
- } else
- sti_channel_writeb(c, channel);
- }
-
- if (sti_line_done)
- sti_channel_flush(channel);
-
- return count;
-}
-
-static int sti_tty_open(struct tty_struct *tty, struct file *filp)
-{
- return 0;
-}
-
-static int sti_tty_write(struct tty_struct *tty,
- const unsigned char *buf, int len)
-{
- unsigned long flags;
- int bytes;
-
- spin_lock_irqsave(&sti_console_lock, flags);
- bytes = sti_channel_puts(buf, sti_console_channel, len);
- spin_unlock_irqrestore(&sti_console_lock, flags);
-
- return bytes;
-}
-
-static int sti_tty_write_room(struct tty_struct *tty)
-{
- return 0x100000;
-}
-
-static int sti_tty_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
-static struct tty_operations sti_tty_ops = {
- .open = sti_tty_open,
- .write = sti_tty_write,
- .write_room = sti_tty_write_room,
- .chars_in_buffer = sti_tty_chars_in_buffer,
-};
-
-static void sti_console_write(struct console *c, const char *s, unsigned n)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sti_console_lock, flags);
- sti_channel_puts(s, sti_console_channel, n);
- spin_unlock_irqrestore(&sti_console_lock, flags);
-}
-
-static struct tty_driver *sti_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return tty_driver;
-}
-
-static int sti_console_setup(struct console *c, char *opts)
-{
- return 0;
-}
-
-static struct console sti_console = {
- .name = DRV_NAME,
- .write = sti_console_write,
- .device = sti_console_device,
- .setup = sti_console_setup,
- .flags = CON_PRINTBUFFER | CON_ENABLED,
- .index = -1,
-};
-
-static int __init sti_console_init(void)
-{
- const struct omap_sti_console_config *info;
-
- info = omap_get_config(OMAP_TAG_STI_CONSOLE,
- struct omap_sti_console_config);
- if (info && info->enable) {
- add_preferred_console(DRV_NAME, 0, NULL);
-
- sti_console_channel = info->channel;
- }
-
- if (unlikely(sti_console_channel == -1))
- return -EINVAL;
-
- register_console(&sti_console);
-
- return 0;
-}
-__initcall(sti_console_init);
-
-static int __init sti_tty_init(void)
-{
- struct tty_driver *tty;
- int ret;
-
- tty = alloc_tty_driver(1);
- if (!tty)
- return -ENOMEM;
-
- tty->name = DRV_NAME;
- tty->driver_name = DRV_NAME;
- tty->major = 0; /* dynamic major */
- tty->minor_start = 0;
- tty->type = TTY_DRIVER_TYPE_SYSTEM;
- tty->subtype = SYSTEM_TYPE_SYSCONS;
- tty->init_termios = tty_std_termios;
-
- tty_set_operations(tty, &sti_tty_ops);
-
- ret = tty_register_driver(tty);
- if (ret) {
- put_tty_driver(tty);
- return ret;
- }
-
- tty_driver = tty;
- return 0;
-}
-late_initcall(sti_tty_init);
-
-module_param(sti_console_channel, uint, 0);
-MODULE_PARM_DESC(sti_console_channel, "STI console channel");
-MODULE_AUTHOR("Paul Mundt");
-MODULE_DESCRIPTION("OMAP STI console support");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/sti/sti-fifo.c b/arch/arm/plat-omap/sti/sti-fifo.c
deleted file mode 100644
index 4069d9b..0000000
--- a/arch/arm/plat-omap/sti/sti-fifo.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * STI RX FIFO Support
- *
- * Copyright (C) 2005, 2006 Nokia Corporation
- * Written by: Paul Mundt <paul.mundt@nokia.com> and
- * Roman Tereshonkov <roman.tereshonkov@nokia.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <asm/arch/sti.h>
-
-#define STI_READ_BUFFER_SIZE 1024
-#define sti_buf_pos(pos) ((sti_crb->bufpos + (pos)) % \
- STI_READ_BUFFER_SIZE)
-
-static struct sti_cycle_buffer {
- int bufpos;
- int datalen;
- unsigned char *buf;
-} *sti_crb;
-
-/**
- * sti_read_packet - STI read packet (read an entire STI packet)
- * @buf: Buffer to store the packet.
- * @maxsize: Maximum size requested.
- *
- * This reads in a single completed STI packet from the RX FIFOs and
- * places it in @buf for further processing.
- *
- * The return value is < 0 on error, and >= 0 for the number of bytes
- * actually read. As per the STI specification, we require a 0xC1 to
- * indicate the end of the packet, and we don't return the packet until
- * we've read the entire thing in.
- *
- * Due to the size of the FIFOs, it's unrealistic to constantly drain
- * this for 1 or 2 bytes at a time, so we assemble it here and return
- * the whole thing.
- */
-int sti_read_packet(unsigned char *buf, int maxsize)
-{
- unsigned int pos;
-
- if (unlikely(!buf))
- return -EINVAL;
- if (!sti_crb->datalen)
- return 0;
-
- pos = sti_buf_pos(sti_crb->datalen - 1);
- /* End of packet */
- if (sti_crb->buf[pos] == 0xC1) {
- int i;
-
- for (i = 0; i < sti_crb->datalen && i < maxsize; i++) {
- pos = sti_buf_pos(i);
- buf[i] = sti_crb->buf[pos];
- }
-
- sti_crb->bufpos = sti_buf_pos(i);
- sti_crb->datalen -= i;
-
- return i;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(sti_read_packet);
-
-static void sti_fifo_irq(unsigned long arg)
-{
- /* If there is data read it */
- while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) {
- unsigned int pos = sti_buf_pos(sti_crb->datalen);
-
- sti_crb->buf[pos] = sti_readl(STI_RX_DR);
- sti_crb->datalen++;
- }
-
- sti_ack_irq(STI_RX_INT);
-}
-
-static int __init sti_fifo_init(void)
-{
- unsigned int size;
- int ret;
-
- size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE;
- sti_crb = kmalloc(size, GFP_KERNEL);
- if (!sti_crb)
- return -ENOMEM;
-
- sti_crb->bufpos = sti_crb->datalen = 0;
- sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb));
-
- ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0);
- if (ret != 0)
- kfree(sti_crb);
-
- return ret;
-}
-
-static void __exit sti_fifo_exit(void)
-{
- sti_free_irq(STI_RX_INT);
- kfree(sti_crb);
-}
-
-module_init(sti_fifo_init);
-module_exit(sti_fifo_exit);
-
-MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/sti/sti-netlink.c b/arch/arm/plat-omap/sti/sti-netlink.c
deleted file mode 100644
index ca3533e..0000000
--- a/arch/arm/plat-omap/sti/sti-netlink.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * OMAP STI/XTI communications interface via netlink socket.
- *
- * Copyright (C) 2004, 2005, 2006 Nokia Corporation
- * Written by: Paul Mundt <paul.mundt@nokia.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/netlink.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/mutex.h>
-#include <net/sock.h>
-#include <asm/arch/sti.h>
-
-static struct sock *sti_sock;
-static DEFINE_MUTEX(sti_netlink_mutex);
-
-enum {
- STI_READ,
- STI_WRITE,
-};
-
-static int sti_netlink_read(int pid, int seq, void *payload, int size)
-{
- struct sk_buff *skb;
- struct nlmsghdr *nlh;
- int ret, len = NLMSG_SPACE(size);
- unsigned char *tail;
-
- skb = alloc_skb(len, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- tail = skb->tail;
- nlh = NLMSG_PUT(skb, pid, seq, STI_READ,
- len - (sizeof(struct nlmsghdr)));
- nlh->nlmsg_flags = 0;
- memcpy(NLMSG_DATA(nlh), payload, size);
- nlh->nlmsg_len = skb->tail - tail;
-
- ret = netlink_unicast(sti_sock, skb, pid, MSG_DONTWAIT);
- if (ret > 0)
- ret = 0;
-
- return ret;
-
-nlmsg_failure:
- if (skb)
- kfree_skb(skb);
-
- return -EINVAL;
-}
-
-/*
- * We abuse nlmsg_type and nlmsg_flags for our purposes.
- *
- * The ID is encoded into the upper 8 bits of the nlmsg_type, while the
- * channel number is encoded into the upper 8 bits of the nlmsg_flags.
- */
-static int sti_netlink_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
-{
- void *data;
- u8 chan, id;
- int size, ret = 0, len = 0;
-
- data = NLMSG_DATA(nlh);
- chan = (nlh->nlmsg_flags >> 8) & 0xff;
- id = (nlh->nlmsg_type >> 8) & 0xff;
- size = (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh));
-
- switch (nlh->nlmsg_type & 0xff) {
- case STI_WRITE:
- sti_channel_write_trace(size, id, data, chan);
- break;
- case STI_READ:
- data = kmalloc(size, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- memset(data, 0, size);
-
- len = sti_read_packet(data, size);
- ret = sti_netlink_read(NETLINK_CB(skb).pid, nlh->nlmsg_seq,
- data, len);
- kfree(data);
- break;
- default:
- return -ENOTTY;
- }
-
- return ret;
-}
-
-static int sti_netlink_receive_skb(struct sk_buff *skb)
-{
- while (skb->len >= NLMSG_SPACE(0)) {
- struct nlmsghdr *nlh;
- u32 rlen;
- int ret;
-
- nlh = (struct nlmsghdr *)skb->data;
- if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ||
- skb->len < nlh->nlmsg_len)
- break;
-
- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (rlen > skb->len)
- rlen = skb->len;
-
- ret = sti_netlink_receive_msg(skb, nlh);
- if (ret)
- netlink_ack(skb, nlh, -ret);
- else if (nlh->nlmsg_flags & NLM_F_ACK)
- netlink_ack(skb, nlh, 0);
-
- skb_pull(skb, rlen);
- }
-
- return 0;
-}
-
-static void sti_netlink_receive(struct sk_buff *skb)
-{
- if (!mutex_trylock(&sti_netlink_mutex))
- return;
-
- sti_netlink_receive_skb(skb);
- mutex_unlock(&sti_netlink_mutex);
-}
-
-static int __init sti_netlink_init(void)
-{
- sti_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0,
- sti_netlink_receive, NULL,
- THIS_MODULE);
- if (!sti_sock) {
- printk(KERN_ERR "STI: Failed to create netlink socket\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-module_init(sti_netlink_init);
-
-MODULE_AUTHOR("Paul Mundt");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("STI netlink-driven communications interface");
diff --git a/arch/arm/plat-omap/sti/sti.c b/arch/arm/plat-omap/sti/sti.c
deleted file mode 100644
index e828860..0000000
--- a/arch/arm/plat-omap/sti/sti.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Support functions for OMAP STI/XTI (Serial Tracing Interface)
- *
- * Copyright (C) 2004, 2005, 2006 Nokia Corporation
- * Written by: Paul Mundt <paul.mundt@nokia.com>
- *
- * STI initialization code and channel handling
- * from Juha Yrjölä <juha.yrjola@nokia.com>.
- *
- * XTI initialization
- * from Roman Tereshonkov <roman.tereshonkov@nokia.com>.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <asm/arch/sti.h>
-#include <asm/byteorder.h>
-
-static struct clk *sti_ck;
-unsigned long sti_base, sti_channel_base;
-static unsigned long sti_kern_mask = STIEn;
-static unsigned long sti_irq_mask = STI_IRQSTATUS_MASK;
-static DEFINE_SPINLOCK(sti_lock);
-
-static struct sti_irqdesc {
- irqreturn_t (*func)(unsigned long);
- unsigned long data;
-} ____cacheline_aligned sti_irq_desc[STI_NR_IRQS];
-
-void sti_channel_write_trace(int len, int id, void *data, unsigned int channel)
-{
- const u8 *tpntr = data;
-
- sti_channel_writeb(id, channel);
-
- if (cpu_is_omap16xx())
- /* Check u32 boundary */
- if (!((u32)data & (STI_PERCHANNEL_SIZE - 1)) &&
- (len >= STI_PERCHANNEL_SIZE)) {
- const u32 *asrc = data;
-
- do {
- sti_channel_writel(cpu_to_be32(*asrc++),
- channel);
- len -= STI_PERCHANNEL_SIZE;
- } while (len >= STI_PERCHANNEL_SIZE);
-
- tpntr = (const u8 *)asrc;
- }
-
- while (len--)
- sti_channel_writeb(*tpntr++, channel);
-
- sti_channel_flush(channel);
-}
-EXPORT_SYMBOL(sti_channel_write_trace);
-
-void sti_enable_irq(unsigned int id)
-{
- spin_lock_irq(&sti_lock);
- sti_writel(1 << id, STI_IRQSETEN);
- spin_unlock_irq(&sti_lock);
-}
-EXPORT_SYMBOL(sti_enable_irq);
-
-void sti_disable_irq(unsigned int id)
-{
- spin_lock_irq(&sti_lock);
-
- if (cpu_is_omap16xx())
- sti_writel(1 << id, STI_IRQCLREN);
- else if (cpu_is_omap24xx())
- sti_writel(sti_readl(STI_IRQSETEN) & ~(1 << id), STI_IRQSETEN);
- else
- BUG();
-
- spin_unlock_irq(&sti_lock);
-}
-EXPORT_SYMBOL(sti_disable_irq);
-
-void sti_ack_irq(unsigned int id)
-{
- /* Even though the clear state is 0, we have to write 1 to clear */
- sti_writel(1 << id, STI_IRQSTATUS);
-}
-EXPORT_SYMBOL(sti_ack_irq);
-
-int sti_request_irq(unsigned int irq, void *handler, unsigned long arg)
-{
- struct sti_irqdesc *desc;
-
- if (unlikely(!handler || irq > STI_NR_IRQS))
- return -EINVAL;
-
- desc = sti_irq_desc + irq;
- if (unlikely(desc->func)) {
- printk(KERN_WARNING "STI: Attempting to request in-use IRQ "
- "%d, consider fixing your code..\n", irq);
- return -EBUSY;
- }
-
- desc->func = handler;
- desc->data = arg;
-
- sti_enable_irq(irq);
- return 0;
-}
-EXPORT_SYMBOL(sti_request_irq);
-
-void sti_free_irq(unsigned int irq)
-{
- struct sti_irqdesc *desc = sti_irq_desc + irq;
-
- if (unlikely(irq > STI_NR_IRQS))
- return;
-
- sti_disable_irq(irq);
-
- desc->func = NULL;
- desc->data = 0;
-}
-EXPORT_SYMBOL(sti_free_irq);
-
-/*
- * This is a bit heavy, so normally we would defer this to a tasklet.
- * Unfortunately tasklets are too slow for the RX FIFO interrupt (and
- * possibly some others), so we just do the irqdesc walking here.
- */
-static irqreturn_t sti_interrupt(int irq, void *dev_id)
-{
- int ret = IRQ_NONE;
- u16 status;
- int i;
-
- status = sti_readl(STI_IRQSTATUS) & sti_irq_mask;
-
- for (i = 0; status; i++) {
- struct sti_irqdesc *desc = sti_irq_desc + i;
- u16 id = 1 << i;
-
- if (!(status & id))
- continue;
-
- if (likely(desc && desc->func))
- ret |= desc->func(desc->data);
- if (unlikely(ret == IRQ_NONE)) {
- printk("STI: spurious interrupt (id %d)\n", id);
- sti_disable_irq(i);
- sti_ack_irq(i);
- ret = IRQ_HANDLED;
- }
-
- status &= ~id;
- }
-
- return IRQ_RETVAL(ret);
-}
-
-static void omap_sti_reset(void)
-{
- int i;
-
- /* Reset STI module */
- sti_writel(0x02, STI_SYSCONFIG);
-
- /* Wait a while for the STI module to complete its reset */
- for (i = 0; i < 10000; i++)
- if (sti_readl(STI_SYSSTATUS) & 1)
- break;
-}
-
-static int __init sti_init(void)
-{
- char buf[64];
- int i;
-
- if (cpu_is_omap16xx()) {
- /* Release ARM Rhea buses peripherals enable */
- sti_writel(sti_readl(ARM_RSTCT2) | 0x0001, ARM_RSTCT2);
-
- /* Enable TC1_CK (functional clock) */
- sti_ck = clk_get(NULL, "tc1_ck");
- } else if (cpu_is_omap24xx())
- /* Enable emulation tools clock */
- sti_ck = clk_get(NULL, "emul_ck");
-
- if (IS_ERR(sti_ck))
- return PTR_ERR(sti_ck);
-
- clk_enable(sti_ck);
-
- /* Reset STI module */
- omap_sti_reset();
-
- /* Enable STI */
- sti_trace_enable(MPUCmdEn);
-
- /* Change to custom serial protocol */
- sti_writel(0x01, STI_SERIAL_CFG);
-
- /* Set STI clock control register to normal mode */
- sti_writel(0x00, STI_CLK_CTRL);
-
- i = sti_readl(STI_REVISION);
- snprintf(buf, sizeof(buf), "OMAP STI support loaded (HW v%u.%u)\n",
- (i >> 4) & 0x0f, i & 0x0f);
- printk(KERN_INFO "%s", buf);
-
- sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
-
- return 0;
-}
-
-static void sti_exit(void)
-{
- u32 tmp;
-
- /*
- * This should have already been done by reset, but we switch off
- * STI entirely just for added sanity..
- */
- tmp = sti_readl(STI_ER);
- tmp &= ~STIEn;
- sti_writel(tmp, STI_ER);
-
- clk_disable(sti_ck);
- clk_put(sti_ck);
-}
-
-static void __sti_trace_enable(int event)
-{
- u32 tmp;
-
- tmp = sti_readl(STI_ER);
- tmp |= sti_kern_mask | event;
- sti_writel(tmp, STI_ER);
-}
-
-int sti_trace_enable(int event)
-{
- spin_lock_irq(&sti_lock);
- sti_kern_mask |= event;
- __sti_trace_enable(event);
- spin_unlock_irq(&sti_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(sti_trace_enable);
-
-static void __sti_trace_disable(int event)
-{
- u32 tmp;
-
- tmp = sti_readl(STI_DR);
-
- if (cpu_is_omap16xx()) {
- tmp |= event;
- tmp &= ~sti_kern_mask;
- } else if (cpu_is_omap24xx()) {
- tmp &= ~event;
- tmp |= sti_kern_mask;
- } else
- BUG();
-
- sti_writel(tmp, STI_DR);
-}
-
-void sti_trace_disable(int event)
-{
- spin_lock_irq(&sti_lock);
- sti_kern_mask &= ~event;
- __sti_trace_disable(event);
- spin_unlock_irq(&sti_lock);
-}
-EXPORT_SYMBOL(sti_trace_disable);
-
-static ssize_t
-sti_trace_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "0x%08lx\n", sti_readl(STI_ER));
-}
-
-static ssize_t
-sti_trace_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int evt = simple_strtoul(buf, NULL, 0);
- int mask = ~evt;
-
- spin_lock_irq(&sti_lock);
- __sti_trace_disable(mask);
- __sti_trace_enable(evt);
- spin_unlock_irq(&sti_lock);
-
- return count;
-}
-static DEVICE_ATTR(trace, S_IRUGO | S_IWUSR, sti_trace_show, sti_trace_store);
-
-static ssize_t
-sti_imask_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "0x%04lx\n", sti_irq_mask);
-}
-
-static ssize_t
-sti_imask_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- spin_lock_irq(&sti_lock);
- sti_irq_mask = simple_strtoul(buf, NULL, 0);
- spin_unlock_irq(&sti_lock);
-
- return count;
-}
-static DEVICE_ATTR(imask, S_IRUGO | S_IWUSR, sti_imask_show, sti_imask_store);
-
-static int __devinit sti_probe(struct platform_device *pdev)
-{
- struct resource *res, *cres;
- int ret;
-
- if (pdev->num_resources != 3) {
- dev_err(&pdev->dev, "invalid number of resources: %d\n",
- pdev->num_resources);
- return -ENODEV;
- }
-
- /* STI base */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!res)) {
- dev_err(&pdev->dev, "invalid mem resource\n");
- return -ENODEV;
- }
-
- /* Channel base */
- cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (unlikely(!cres)) {
- dev_err(&pdev->dev, "invalid channel mem resource\n");
- return -ENODEV;
- }
-
- ret = device_create_file(&pdev->dev, &dev_attr_trace);
- if (unlikely(ret != 0))
- return ret;
-
- ret = device_create_file(&pdev->dev, &dev_attr_imask);
- if (unlikely(ret != 0))
- goto err;
-
- sti_base = res->start;
-
- /*
- * OMAP 16xx keeps channels in a relatively sane location,
- * whereas 24xx maps them much further out, and so they must be
- * remapped.
- */
- if (cpu_is_omap16xx())
- sti_channel_base = cres->start;
- else if (cpu_is_omap24xx()) {
- unsigned int size = cres->end - cres->start;
-
- sti_channel_base = (unsigned long)ioremap(cres->start, size);
- if (unlikely(!sti_channel_base)) {
- ret = -ENODEV;
- goto err_badremap;
- }
- }
-
- ret = request_irq(platform_get_irq(pdev, 0), sti_interrupt,
- IRQF_DISABLED, "sti", NULL);
- if (unlikely(ret != 0))
- goto err_badirq;
-
- return sti_init();
-
-err_badirq:
- iounmap((void *)sti_channel_base);
-err_badremap:
- device_remove_file(&pdev->dev, &dev_attr_imask);
-err:
- device_remove_file(&pdev->dev, &dev_attr_trace);
-
- return ret;
-}
-
-static int __devexit sti_remove(struct platform_device *pdev)
-{
- unsigned int irq = platform_get_irq(pdev, 0);
-
- if (cpu_is_omap24xx())
- iounmap((void *)sti_channel_base);
-
- device_remove_file(&pdev->dev, &dev_attr_trace);
- device_remove_file(&pdev->dev, &dev_attr_imask);
- free_irq(irq, NULL);
- sti_exit();
-
- return 0;
-}
-
-static struct platform_driver sti_driver = {
- .probe = sti_probe,
- .remove = __devexit_p(sti_remove),
- .driver = {
- .name = "sti",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sti_module_init(void)
-{
- return platform_driver_register(&sti_driver);
-}
-
-static void __exit sti_module_exit(void)
-{
- platform_driver_unregister(&sti_driver);
-}
-subsys_initcall(sti_module_init);
-module_exit(sti_module_exit);
-
-MODULE_AUTHOR("Paul Mundt, Juha Yrjölä, Roman Tereshonkov");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3b12f5d..d65b43d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -5,6 +5,7 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
+obj-$(CONFIG_OMAP_STI) += sti/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
diff --git a/drivers/misc/sti/Makefile b/drivers/misc/sti/Makefile
new file mode 100644
index 0000000..6ad9bb3
--- /dev/null
+++ b/drivers/misc/sti/Makefile
@@ -0,0 +1,4 @@
+obj-y += sti.o sti-fifo.o
+
+obj-$(CONFIG_OMAP_STI_CONSOLE) += sti-console.o
+obj-$(CONFIG_NET) += sti-netlink.o
diff --git a/drivers/misc/sti/sti-console.c b/drivers/misc/sti/sti-console.c
new file mode 100644
index 0000000..451a139
--- /dev/null
+++ b/drivers/misc/sti/sti-console.c
@@ -0,0 +1,189 @@
+/*
+ * Console support for OMAP STI/XTI
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <asm/arch/sti.h>
+#include <asm/arch/board.h>
+
+#define DRV_NAME "sticon"
+
+static struct tty_driver *tty_driver;
+static DEFINE_SPINLOCK(sti_console_lock);
+static unsigned int sti_console_channel = -1;
+static int sti_line_done = -1;
+
+/*
+ * Write a string to any channel (including terminating NULL)
+ * Returns number of characters written.
+ */
+static int sti_channel_puts(const char *string, unsigned int channel, int len)
+{
+ int count = 0;
+
+ /*
+ * sti_line_done is needed to determine when we have reached the
+ * end of the line. write() has a tendency to hand us small
+ * strings which otherwise end up creating newlines.. we need to
+ * keep the channel open and in append mode until the line has
+ * been terminated.
+ */
+ if (sti_line_done != 0) {
+#ifdef __LITTLE_ENDIAN
+ sti_channel_writeb(0xc3, channel);
+#else
+ sti_channel_writeb(0xc0, channel);
+#endif
+ xchg(&sti_line_done, 0);
+ }
+
+ while (*string && count != len) {
+ char c = *string++;
+
+ count++;
+
+ if (c == '\n') {
+ xchg(&sti_line_done, 1);
+ sti_channel_writeb(0, channel);
+ break;
+ } else
+ sti_channel_writeb(c, channel);
+ }
+
+ if (sti_line_done)
+ sti_channel_flush(channel);
+
+ return count;
+}
+
+static int sti_tty_open(struct tty_struct *tty, struct file *filp)
+{
+ return 0;
+}
+
+static int sti_tty_write(struct tty_struct *tty,
+ const unsigned char *buf, int len)
+{
+ unsigned long flags;
+ int bytes;
+
+ spin_lock_irqsave(&sti_console_lock, flags);
+ bytes = sti_channel_puts(buf, sti_console_channel, len);
+ spin_unlock_irqrestore(&sti_console_lock, flags);
+
+ return bytes;
+}
+
+static int sti_tty_write_room(struct tty_struct *tty)
+{
+ return 0x100000;
+}
+
+static int sti_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ return 0;
+}
+
+static struct tty_operations sti_tty_ops = {
+ .open = sti_tty_open,
+ .write = sti_tty_write,
+ .write_room = sti_tty_write_room,
+ .chars_in_buffer = sti_tty_chars_in_buffer,
+};
+
+static void sti_console_write(struct console *c, const char *s, unsigned n)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sti_console_lock, flags);
+ sti_channel_puts(s, sti_console_channel, n);
+ spin_unlock_irqrestore(&sti_console_lock, flags);
+}
+
+static struct tty_driver *sti_console_device(struct console *c, int *index)
+{
+ *index = c->index;
+ return tty_driver;
+}
+
+static int sti_console_setup(struct console *c, char *opts)
+{
+ return 0;
+}
+
+static struct console sti_console = {
+ .name = DRV_NAME,
+ .write = sti_console_write,
+ .device = sti_console_device,
+ .setup = sti_console_setup,
+ .flags = CON_PRINTBUFFER | CON_ENABLED,
+ .index = -1,
+};
+
+static int __init sti_console_init(void)
+{
+ const struct omap_sti_console_config *info;
+
+ info = omap_get_config(OMAP_TAG_STI_CONSOLE,
+ struct omap_sti_console_config);
+ if (info && info->enable) {
+ add_preferred_console(DRV_NAME, 0, NULL);
+
+ sti_console_channel = info->channel;
+ }
+
+ if (unlikely(sti_console_channel == -1))
+ return -EINVAL;
+
+ register_console(&sti_console);
+
+ return 0;
+}
+__initcall(sti_console_init);
+
+static int __init sti_tty_init(void)
+{
+ struct tty_driver *tty;
+ int ret;
+
+ tty = alloc_tty_driver(1);
+ if (!tty)
+ return -ENOMEM;
+
+ tty->name = DRV_NAME;
+ tty->driver_name = DRV_NAME;
+ tty->major = 0; /* dynamic major */
+ tty->minor_start = 0;
+ tty->type = TTY_DRIVER_TYPE_SYSTEM;
+ tty->subtype = SYSTEM_TYPE_SYSCONS;
+ tty->init_termios = tty_std_termios;
+
+ tty_set_operations(tty, &sti_tty_ops);
+
+ ret = tty_register_driver(tty);
+ if (ret) {
+ put_tty_driver(tty);
+ return ret;
+ }
+
+ tty_driver = tty;
+ return 0;
+}
+late_initcall(sti_tty_init);
+
+module_param(sti_console_channel, uint, 0);
+MODULE_PARM_DESC(sti_console_channel, "STI console channel");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("OMAP STI console support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/sti/sti-fifo.c b/drivers/misc/sti/sti-fifo.c
new file mode 100644
index 0000000..4069d9b
--- /dev/null
+++ b/drivers/misc/sti/sti-fifo.c
@@ -0,0 +1,117 @@
+/*
+ * STI RX FIFO Support
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com> and
+ * Roman Tereshonkov <roman.tereshonkov@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/arch/sti.h>
+
+#define STI_READ_BUFFER_SIZE 1024
+#define sti_buf_pos(pos) ((sti_crb->bufpos + (pos)) % \
+ STI_READ_BUFFER_SIZE)
+
+static struct sti_cycle_buffer {
+ int bufpos;
+ int datalen;
+ unsigned char *buf;
+} *sti_crb;
+
+/**
+ * sti_read_packet - STI read packet (read an entire STI packet)
+ * @buf: Buffer to store the packet.
+ * @maxsize: Maximum size requested.
+ *
+ * This reads in a single completed STI packet from the RX FIFOs and
+ * places it in @buf for further processing.
+ *
+ * The return value is < 0 on error, and >= 0 for the number of bytes
+ * actually read. As per the STI specification, we require a 0xC1 to
+ * indicate the end of the packet, and we don't return the packet until
+ * we've read the entire thing in.
+ *
+ * Due to the size of the FIFOs, it's unrealistic to constantly drain
+ * this for 1 or 2 bytes at a time, so we assemble it here and return
+ * the whole thing.
+ */
+int sti_read_packet(unsigned char *buf, int maxsize)
+{
+ unsigned int pos;
+
+ if (unlikely(!buf))
+ return -EINVAL;
+ if (!sti_crb->datalen)
+ return 0;
+
+ pos = sti_buf_pos(sti_crb->datalen - 1);
+ /* End of packet */
+ if (sti_crb->buf[pos] == 0xC1) {
+ int i;
+
+ for (i = 0; i < sti_crb->datalen && i < maxsize; i++) {
+ pos = sti_buf_pos(i);
+ buf[i] = sti_crb->buf[pos];
+ }
+
+ sti_crb->bufpos = sti_buf_pos(i);
+ sti_crb->datalen -= i;
+
+ return i;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(sti_read_packet);
+
+static void sti_fifo_irq(unsigned long arg)
+{
+ /* If there is data read it */
+ while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) {
+ unsigned int pos = sti_buf_pos(sti_crb->datalen);
+
+ sti_crb->buf[pos] = sti_readl(STI_RX_DR);
+ sti_crb->datalen++;
+ }
+
+ sti_ack_irq(STI_RX_INT);
+}
+
+static int __init sti_fifo_init(void)
+{
+ unsigned int size;
+ int ret;
+
+ size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE;
+ sti_crb = kmalloc(size, GFP_KERNEL);
+ if (!sti_crb)
+ return -ENOMEM;
+
+ sti_crb->bufpos = sti_crb->datalen = 0;
+ sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb));
+
+ ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0);
+ if (ret != 0)
+ kfree(sti_crb);
+
+ return ret;
+}
+
+static void __exit sti_fifo_exit(void)
+{
+ sti_free_irq(STI_RX_INT);
+ kfree(sti_crb);
+}
+
+module_init(sti_fifo_init);
+module_exit(sti_fifo_exit);
+
+MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/sti/sti-netlink.c b/drivers/misc/sti/sti-netlink.c
new file mode 100644
index 0000000..ca3533e
--- /dev/null
+++ b/drivers/misc/sti/sti-netlink.c
@@ -0,0 +1,152 @@
+/*
+ * OMAP STI/XTI communications interface via netlink socket.
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netlink.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/mutex.h>
+#include <net/sock.h>
+#include <asm/arch/sti.h>
+
+static struct sock *sti_sock;
+static DEFINE_MUTEX(sti_netlink_mutex);
+
+enum {
+ STI_READ,
+ STI_WRITE,
+};
+
+static int sti_netlink_read(int pid, int seq, void *payload, int size)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ int ret, len = NLMSG_SPACE(size);
+ unsigned char *tail;
+
+ skb = alloc_skb(len, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ tail = skb->tail;
+ nlh = NLMSG_PUT(skb, pid, seq, STI_READ,
+ len - (sizeof(struct nlmsghdr)));
+ nlh->nlmsg_flags = 0;
+ memcpy(NLMSG_DATA(nlh), payload, size);
+ nlh->nlmsg_len = skb->tail - tail;
+
+ ret = netlink_unicast(sti_sock, skb, pid, MSG_DONTWAIT);
+ if (ret > 0)
+ ret = 0;
+
+ return ret;
+
+nlmsg_failure:
+ if (skb)
+ kfree_skb(skb);
+
+ return -EINVAL;
+}
+
+/*
+ * We abuse nlmsg_type and nlmsg_flags for our purposes.
+ *
+ * The ID is encoded into the upper 8 bits of the nlmsg_type, while the
+ * channel number is encoded into the upper 8 bits of the nlmsg_flags.
+ */
+static int sti_netlink_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+ void *data;
+ u8 chan, id;
+ int size, ret = 0, len = 0;
+
+ data = NLMSG_DATA(nlh);
+ chan = (nlh->nlmsg_flags >> 8) & 0xff;
+ id = (nlh->nlmsg_type >> 8) & 0xff;
+ size = (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh));
+
+ switch (nlh->nlmsg_type & 0xff) {
+ case STI_WRITE:
+ sti_channel_write_trace(size, id, data, chan);
+ break;
+ case STI_READ:
+ data = kmalloc(size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ memset(data, 0, size);
+
+ len = sti_read_packet(data, size);
+ ret = sti_netlink_read(NETLINK_CB(skb).pid, nlh->nlmsg_seq,
+ data, len);
+ kfree(data);
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+static int sti_netlink_receive_skb(struct sk_buff *skb)
+{
+ while (skb->len >= NLMSG_SPACE(0)) {
+ struct nlmsghdr *nlh;
+ u32 rlen;
+ int ret;
+
+ nlh = (struct nlmsghdr *)skb->data;
+ if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ||
+ skb->len < nlh->nlmsg_len)
+ break;
+
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
+
+ ret = sti_netlink_receive_msg(skb, nlh);
+ if (ret)
+ netlink_ack(skb, nlh, -ret);
+ else if (nlh->nlmsg_flags & NLM_F_ACK)
+ netlink_ack(skb, nlh, 0);
+
+ skb_pull(skb, rlen);
+ }
+
+ return 0;
+}
+
+static void sti_netlink_receive(struct sk_buff *skb)
+{
+ if (!mutex_trylock(&sti_netlink_mutex))
+ return;
+
+ sti_netlink_receive_skb(skb);
+ mutex_unlock(&sti_netlink_mutex);
+}
+
+static int __init sti_netlink_init(void)
+{
+ sti_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0,
+ sti_netlink_receive, NULL,
+ THIS_MODULE);
+ if (!sti_sock) {
+ printk(KERN_ERR "STI: Failed to create netlink socket\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+module_init(sti_netlink_init);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("STI netlink-driven communications interface");
diff --git a/drivers/misc/sti/sti.c b/drivers/misc/sti/sti.c
new file mode 100644
index 0000000..e828860
--- /dev/null
+++ b/drivers/misc/sti/sti.c
@@ -0,0 +1,432 @@
+/*
+ * Support functions for OMAP STI/XTI (Serial Tracing Interface)
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * STI initialization code and channel handling
+ * from Juha Yrjölä <juha.yrjola@nokia.com>.
+ *
+ * XTI initialization
+ * from Roman Tereshonkov <roman.tereshonkov@nokia.com>.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/arch/sti.h>
+#include <asm/byteorder.h>
+
+static struct clk *sti_ck;
+unsigned long sti_base, sti_channel_base;
+static unsigned long sti_kern_mask = STIEn;
+static unsigned long sti_irq_mask = STI_IRQSTATUS_MASK;
+static DEFINE_SPINLOCK(sti_lock);
+
+static struct sti_irqdesc {
+ irqreturn_t (*func)(unsigned long);
+ unsigned long data;
+} ____cacheline_aligned sti_irq_desc[STI_NR_IRQS];
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel)
+{
+ const u8 *tpntr = data;
+
+ sti_channel_writeb(id, channel);
+
+ if (cpu_is_omap16xx())
+ /* Check u32 boundary */
+ if (!((u32)data & (STI_PERCHANNEL_SIZE - 1)) &&
+ (len >= STI_PERCHANNEL_SIZE)) {
+ const u32 *asrc = data;
+
+ do {
+ sti_channel_writel(cpu_to_be32(*asrc++),
+ channel);
+ len -= STI_PERCHANNEL_SIZE;
+ } while (len >= STI_PERCHANNEL_SIZE);
+
+ tpntr = (const u8 *)asrc;
+ }
+
+ while (len--)
+ sti_channel_writeb(*tpntr++, channel);
+
+ sti_channel_flush(channel);
+}
+EXPORT_SYMBOL(sti_channel_write_trace);
+
+void sti_enable_irq(unsigned int id)
+{
+ spin_lock_irq(&sti_lock);
+ sti_writel(1 << id, STI_IRQSETEN);
+ spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_enable_irq);
+
+void sti_disable_irq(unsigned int id)
+{
+ spin_lock_irq(&sti_lock);
+
+ if (cpu_is_omap16xx())
+ sti_writel(1 << id, STI_IRQCLREN);
+ else if (cpu_is_omap24xx())
+ sti_writel(sti_readl(STI_IRQSETEN) & ~(1 << id), STI_IRQSETEN);
+ else
+ BUG();
+
+ spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_disable_irq);
+
+void sti_ack_irq(unsigned int id)
+{
+ /* Even though the clear state is 0, we have to write 1 to clear */
+ sti_writel(1 << id, STI_IRQSTATUS);
+}
+EXPORT_SYMBOL(sti_ack_irq);
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg)
+{
+ struct sti_irqdesc *desc;
+
+ if (unlikely(!handler || irq > STI_NR_IRQS))
+ return -EINVAL;
+
+ desc = sti_irq_desc + irq;
+ if (unlikely(desc->func)) {
+ printk(KERN_WARNING "STI: Attempting to request in-use IRQ "
+ "%d, consider fixing your code..\n", irq);
+ return -EBUSY;
+ }
+
+ desc->func = handler;
+ desc->data = arg;
+
+ sti_enable_irq(irq);
+ return 0;
+}
+EXPORT_SYMBOL(sti_request_irq);
+
+void sti_free_irq(unsigned int irq)
+{
+ struct sti_irqdesc *desc = sti_irq_desc + irq;
+
+ if (unlikely(irq > STI_NR_IRQS))
+ return;
+
+ sti_disable_irq(irq);
+
+ desc->func = NULL;
+ desc->data = 0;
+}
+EXPORT_SYMBOL(sti_free_irq);
+
+/*
+ * This is a bit heavy, so normally we would defer this to a tasklet.
+ * Unfortunately tasklets are too slow for the RX FIFO interrupt (and
+ * possibly some others), so we just do the irqdesc walking here.
+ */
+static irqreturn_t sti_interrupt(int irq, void *dev_id)
+{
+ int ret = IRQ_NONE;
+ u16 status;
+ int i;
+
+ status = sti_readl(STI_IRQSTATUS) & sti_irq_mask;
+
+ for (i = 0; status; i++) {
+ struct sti_irqdesc *desc = sti_irq_desc + i;
+ u16 id = 1 << i;
+
+ if (!(status & id))
+ continue;
+
+ if (likely(desc && desc->func))
+ ret |= desc->func(desc->data);
+ if (unlikely(ret == IRQ_NONE)) {
+ printk("STI: spurious interrupt (id %d)\n", id);
+ sti_disable_irq(i);
+ sti_ack_irq(i);
+ ret = IRQ_HANDLED;
+ }
+
+ status &= ~id;
+ }
+
+ return IRQ_RETVAL(ret);
+}
+
+static void omap_sti_reset(void)
+{
+ int i;
+
+ /* Reset STI module */
+ sti_writel(0x02, STI_SYSCONFIG);
+
+ /* Wait a while for the STI module to complete its reset */
+ for (i = 0; i < 10000; i++)
+ if (sti_readl(STI_SYSSTATUS) & 1)
+ break;
+}
+
+static int __init sti_init(void)
+{
+ char buf[64];
+ int i;
+
+ if (cpu_is_omap16xx()) {
+ /* Release ARM Rhea buses peripherals enable */
+ sti_writel(sti_readl(ARM_RSTCT2) | 0x0001, ARM_RSTCT2);
+
+ /* Enable TC1_CK (functional clock) */
+ sti_ck = clk_get(NULL, "tc1_ck");
+ } else if (cpu_is_omap24xx())
+ /* Enable emulation tools clock */
+ sti_ck = clk_get(NULL, "emul_ck");
+
+ if (IS_ERR(sti_ck))
+ return PTR_ERR(sti_ck);
+
+ clk_enable(sti_ck);
+
+ /* Reset STI module */
+ omap_sti_reset();
+
+ /* Enable STI */
+ sti_trace_enable(MPUCmdEn);
+
+ /* Change to custom serial protocol */
+ sti_writel(0x01, STI_SERIAL_CFG);
+
+ /* Set STI clock control register to normal mode */
+ sti_writel(0x00, STI_CLK_CTRL);
+
+ i = sti_readl(STI_REVISION);
+ snprintf(buf, sizeof(buf), "OMAP STI support loaded (HW v%u.%u)\n",
+ (i >> 4) & 0x0f, i & 0x0f);
+ printk(KERN_INFO "%s", buf);
+
+ sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+ return 0;
+}
+
+static void sti_exit(void)
+{
+ u32 tmp;
+
+ /*
+ * This should have already been done by reset, but we switch off
+ * STI entirely just for added sanity..
+ */
+ tmp = sti_readl(STI_ER);
+ tmp &= ~STIEn;
+ sti_writel(tmp, STI_ER);
+
+ clk_disable(sti_ck);
+ clk_put(sti_ck);
+}
+
+static void __sti_trace_enable(int event)
+{
+ u32 tmp;
+
+ tmp = sti_readl(STI_ER);
+ tmp |= sti_kern_mask | event;
+ sti_writel(tmp, STI_ER);
+}
+
+int sti_trace_enable(int event)
+{
+ spin_lock_irq(&sti_lock);
+ sti_kern_mask |= event;
+ __sti_trace_enable(event);
+ spin_unlock_irq(&sti_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(sti_trace_enable);
+
+static void __sti_trace_disable(int event)
+{
+ u32 tmp;
+
+ tmp = sti_readl(STI_DR);
+
+ if (cpu_is_omap16xx()) {
+ tmp |= event;
+ tmp &= ~sti_kern_mask;
+ } else if (cpu_is_omap24xx()) {
+ tmp &= ~event;
+ tmp |= sti_kern_mask;
+ } else
+ BUG();
+
+ sti_writel(tmp, STI_DR);
+}
+
+void sti_trace_disable(int event)
+{
+ spin_lock_irq(&sti_lock);
+ sti_kern_mask &= ~event;
+ __sti_trace_disable(event);
+ spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_trace_disable);
+
+static ssize_t
+sti_trace_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0x%08lx\n", sti_readl(STI_ER));
+}
+
+static ssize_t
+sti_trace_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int evt = simple_strtoul(buf, NULL, 0);
+ int mask = ~evt;
+
+ spin_lock_irq(&sti_lock);
+ __sti_trace_disable(mask);
+ __sti_trace_enable(evt);
+ spin_unlock_irq(&sti_lock);
+
+ return count;
+}
+static DEVICE_ATTR(trace, S_IRUGO | S_IWUSR, sti_trace_show, sti_trace_store);
+
+static ssize_t
+sti_imask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0x%04lx\n", sti_irq_mask);
+}
+
+static ssize_t
+sti_imask_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ spin_lock_irq(&sti_lock);
+ sti_irq_mask = simple_strtoul(buf, NULL, 0);
+ spin_unlock_irq(&sti_lock);
+
+ return count;
+}
+static DEVICE_ATTR(imask, S_IRUGO | S_IWUSR, sti_imask_show, sti_imask_store);
+
+static int __devinit sti_probe(struct platform_device *pdev)
+{
+ struct resource *res, *cres;
+ int ret;
+
+ if (pdev->num_resources != 3) {
+ dev_err(&pdev->dev, "invalid number of resources: %d\n",
+ pdev->num_resources);
+ return -ENODEV;
+ }
+
+ /* STI base */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "invalid mem resource\n");
+ return -ENODEV;
+ }
+
+ /* Channel base */
+ cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (unlikely(!cres)) {
+ dev_err(&pdev->dev, "invalid channel mem resource\n");
+ return -ENODEV;
+ }
+
+ ret = device_create_file(&pdev->dev, &dev_attr_trace);
+ if (unlikely(ret != 0))
+ return ret;
+
+ ret = device_create_file(&pdev->dev, &dev_attr_imask);
+ if (unlikely(ret != 0))
+ goto err;
+
+ sti_base = res->start;
+
+ /*
+ * OMAP 16xx keeps channels in a relatively sane location,
+ * whereas 24xx maps them much further out, and so they must be
+ * remapped.
+ */
+ if (cpu_is_omap16xx())
+ sti_channel_base = cres->start;
+ else if (cpu_is_omap24xx()) {
+ unsigned int size = cres->end - cres->start;
+
+ sti_channel_base = (unsigned long)ioremap(cres->start, size);
+ if (unlikely(!sti_channel_base)) {
+ ret = -ENODEV;
+ goto err_badremap;
+ }
+ }
+
+ ret = request_irq(platform_get_irq(pdev, 0), sti_interrupt,
+ IRQF_DISABLED, "sti", NULL);
+ if (unlikely(ret != 0))
+ goto err_badirq;
+
+ return sti_init();
+
+err_badirq:
+ iounmap((void *)sti_channel_base);
+err_badremap:
+ device_remove_file(&pdev->dev, &dev_attr_imask);
+err:
+ device_remove_file(&pdev->dev, &dev_attr_trace);
+
+ return ret;
+}
+
+static int __devexit sti_remove(struct platform_device *pdev)
+{
+ unsigned int irq = platform_get_irq(pdev, 0);
+
+ if (cpu_is_omap24xx())
+ iounmap((void *)sti_channel_base);
+
+ device_remove_file(&pdev->dev, &dev_attr_trace);
+ device_remove_file(&pdev->dev, &dev_attr_imask);
+ free_irq(irq, NULL);
+ sti_exit();
+
+ return 0;
+}
+
+static struct platform_driver sti_driver = {
+ .probe = sti_probe,
+ .remove = __devexit_p(sti_remove),
+ .driver = {
+ .name = "sti",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sti_module_init(void)
+{
+ return platform_driver_register(&sti_driver);
+}
+
+static void __exit sti_module_exit(void)
+{
+ platform_driver_unregister(&sti_driver);
+}
+subsys_initcall(sti_module_init);
+module_exit(sti_module_exit);
+
+MODULE_AUTHOR("Paul Mundt, Juha Yrjölä, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
--
1.5.3.6
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2008-03-12 10:46 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-03-12 10:45 [PATCH 0/10] Rearranging things before sending patches to mainline Tony Lindgren
2008-03-12 10:45 ` [PATCH 1/10] ARM: OMAP2: Fix _REGADDR macro offset calculations and cm.h for assembly Tony Lindgren
2008-03-12 10:45 ` [PATCH 2/10] ARM: OMAP2: Move sram-fn.S to sram24xx.S Tony Lindgren
2008-03-12 10:45 ` [PATCH 3/10] ARM: OMAP2: Rename 24xx specific SRAM functions Tony Lindgren
2008-03-12 10:45 ` [PATCH 4/10] ARM: OMAP3: Add SRAM support for 3430 Tony Lindgren
2008-03-12 10:45 ` [PATCH 5/10] ARM: OMAP2: Rename cm_regbits_24xx.h to cm-regbits-24xx.h Tony Lindgren
2008-03-12 10:45 ` [PATCH 6/10] ARM: OMAP3: Rename cm_regbits_34xx.h to cm-regbits-34xx.h Tony Lindgren
2008-03-12 10:45 ` [PATCH 7/10] ARM: OMAP2: Rename prcm_common.h to prcm-common.h Tony Lindgren
2008-03-12 10:45 ` [PATCH 8/10] ARM: OMAP2: Rename prm_regbits_24xx.h to prm-regbits-24xx.h Tony Lindgren
2008-03-12 10:45 ` [PATCH 9/10] ARM: OMAP3: Rename prm_regbits_34xx.h to prm-regbits-34xx.h Tony Lindgren
2008-03-12 10:45 ` Tony Lindgren [this message]
2008-03-13 11:28 ` [PATCH 0/10] Rearranging things before sending patches to mainline Tony Lindgren
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=1205318750-9596-11-git-send-email-tony@atomide.com \
--to=tony@atomide.com \
--cc=linux-omap@vger.kernel.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