This is to allow syncing plat-omap with mainline kernel. Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx> --- 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@xxxxxxxxx> - * - * 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@xxxxxxxxx> and - * Roman Tereshonkov <roman.tereshonkov@xxxxxxxxx> - * - * 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@xxxxxxxxx> - * - * 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@xxxxxxxxx> - * - * STI initialization code and channel handling - * from Juha Yrjölä <juha.yrjola@xxxxxxxxx>. - * - * XTI initialization - * from Roman Tereshonkov <roman.tereshonkov@xxxxxxxxx>. - * - * 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@xxxxxxxxx> + * + * 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@xxxxxxxxx> and + * Roman Tereshonkov <roman.tereshonkov@xxxxxxxxx> + * + * 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@xxxxxxxxx> + * + * 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@xxxxxxxxx> + * + * STI initialization code and channel handling + * from Juha Yrjölä <juha.yrjola@xxxxxxxxx>. + * + * XTI initialization + * from Roman Tereshonkov <roman.tereshonkov@xxxxxxxxx>. + * + * 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html