X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?p=linux-2.6-omap-h63xx.git;a=blobdiff_plain;f=drivers%2Fmisc%2Fsti%2Fsdti.c;fp=drivers%2Fmisc%2Fsti%2Fsdti.c;h=31780de3e7f47009e9f6773cb2c7f6c333b27c45;hp=0000000000000000000000000000000000000000;hb=b934c987ee1764eb09b8843a3ee00eabc24bd52c;hpb=14fc69723d3442ef46f8f82b3f481e82f06a346d diff --git a/drivers/misc/sti/sdti.c b/drivers/misc/sti/sdti.c new file mode 100644 index 00000000000..31780de3e7f --- /dev/null +++ b/drivers/misc/sti/sdti.c @@ -0,0 +1,227 @@ +/* + * Support functions for OMAP3 SDTI (Serial Debug Tracing Interface) + * + * Copyright (C) 2008 Nokia Corporation + * Written by: Roman Tereshonkov + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SDTI_REVISION 0x000 +#define SDTI_SYSCONFIG 0x010 +#define SDTI_SYSSTATUS 0x014 +#define SDTI_WINCTRL 0x024 +#define SDTI_SCONFIG 0x028 +#define SDTI_TESTCTRL 0x02C +#define SDTI_LOCK_ACCESS 0xFB0 + +#define CPU1_TRACE_EN 0x01 +#define CPU2_TRACE_EN 0x02 + +#define SDTI_SYSCONFIG_SOFTRESET (1 << 1) +#define SDTI_SYSCONFIG_AUTOIDLE (1 << 0) + +static struct clk *sdti_fck, *sdti_ick; +void __iomem *sti_base, *sti_channel_base; +static DEFINE_SPINLOCK(sdti_lock); +static int sdti_initialized; + +void sti_channel_write_trace(int len, int id, void *data, + unsigned int channel) +{ + const u8 *tpntr = data; + unsigned long flags; + + spin_lock_irqsave(&sdti_lock, flags); + + if (unlikely(!sdti_initialized)) + goto skip; + + sti_channel_writeb(id, channel); + while (len--) + sti_channel_writeb(*tpntr++, channel); + sti_channel_flush(channel); + skip: + spin_unlock_irqrestore(&sdti_lock, flags); +} +EXPORT_SYMBOL(sti_channel_write_trace); + +static void omap_sdti_reset(void) +{ + int i; + + sti_writel(SDTI_SYSCONFIG_SOFTRESET, SDTI_SYSCONFIG); + + for (i = 0; i < 10000; i++) + if (sti_readl(SDTI_SYSSTATUS) & 1) + break; + if (i == 10000) + printk(KERN_WARNING "XTI: no real reset\n"); +} + +static int __init omap_sdti_init(void) +{ + char buf[64]; + int i, ret = 0; + + sdti_fck = clk_get(NULL, "pclk_fck"); + if (IS_ERR(sdti_fck)) { + printk(KERN_ERR "Cannot get clk pclk_fck\n"); + ret = PTR_ERR(sdti_fck); + goto err0; + } + sdti_ick = clk_get(NULL, "pclkx2_fck"); + if (IS_ERR(sdti_ick)) { + printk(KERN_ERR "Cannot get clk pclkx2_fck\n"); + ret = PTR_ERR(sdti_ick); + goto err1; + } + ret = clk_enable(sdti_fck); + if (ret) { + printk(KERN_ERR "Cannot enable sdti_fck\n"); + goto err2; + } + ret = clk_enable(sdti_ick); + if (ret) { + printk(KERN_ERR "Cannot enable sdti_ick\n"); + goto err3; + } + + omap_sdti_reset(); + sti_writel(0xC5ACCE55, SDTI_LOCK_ACCESS); + + /* Autoidle */ + sti_writel(SDTI_SYSCONFIG_AUTOIDLE, SDTI_SYSCONFIG); + + /* Claim SDTI */ + sti_writel(1 << 30, SDTI_WINCTRL); + i = sti_readl(SDTI_WINCTRL); + if (!(i & (1 << 30))) + printk(KERN_WARNING "SDTI: cannot claim SDTI\n"); + + /* 4 bits dual, fclk/3 */ + sti_writel(0x43, SDTI_SCONFIG); + + /* CPU2 trace enable */ + sti_writel(i | CPU2_TRACE_EN, SDTI_WINCTRL); + i = sti_readl(SDTI_WINCTRL); + + /* Enable SDTI */ + sti_writel((1 << 31) | (i & 0x3FFFFFFF), SDTI_WINCTRL); + + spin_lock_irq(&sdti_lock); + sdti_initialized = 1; + spin_unlock_irq(&sdti_lock); + + i = sti_readl(SDTI_REVISION); + snprintf(buf, sizeof(buf), "OMAP SDTI 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 ret; + +err3: + clk_disable(sdti_fck); +err2: + clk_put(sdti_ick); +err1: + clk_put(sdti_fck); +err0: + return ret; +} + +static void omap_sdti_exit(void) +{ + sti_writel(0, SDTI_WINCTRL); + clk_disable(sdti_fck); + clk_disable(sdti_ick); + clk_put(sdti_fck); + clk_put(sdti_ick); +} + +static int __devinit omap_sdti_probe(struct platform_device *pdev) +{ + struct resource *res, *cres; + unsigned int size; + + if (pdev->num_resources != 2) { + dev_err(&pdev->dev, "invalid number of resources: %d\n", + pdev->num_resources); + return -ENODEV; + } + + /* SDTI 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; + } + + size = res->end - res->start; + sti_base = ioremap(res->start, size); + if (unlikely(!sti_base)) + return -ENODEV; + + size = cres->end - cres->start; + sti_channel_base = ioremap(cres->start, size); + if (unlikely(!sti_channel_base)) { + iounmap(sti_base); + return -ENODEV; + } + + return omap_sdti_init(); +} + +static int __devexit omap_sdti_remove(struct platform_device *pdev) +{ + iounmap(sti_channel_base); + iounmap(sti_base); + omap_sdti_exit(); + + return 0; +} + +static struct platform_driver omap_sdti_driver = { + .probe = omap_sdti_probe, + .remove = __devexit_p(omap_sdti_remove), + .driver = { + .name = "sti", + .owner = THIS_MODULE, + }, +}; + +static int __init omap_sdti_module_init(void) +{ + return platform_driver_register(&omap_sdti_driver); +} + +static void __exit omap_sdti_module_exit(void) +{ + platform_driver_unregister(&omap_sdti_driver); +} +subsys_initcall(omap_sdti_module_init); +module_exit(omap_sdti_module_exit); + +MODULE_AUTHOR("Roman Tereshonkov"); +MODULE_LICENSE("GPL");