/* * 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");