]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/misc/sti/sdti.c
92ce57b3491091d1d39151cd3b96913a273c54a9
[linux-2.6-omap-h63xx.git] / drivers / misc / sti / sdti.c
1 /*
2  * Support functions for OMAP3 SDTI (Serial Debug Tracing Interface)
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  * Written by: Roman Tereshonkov <roman.tereshonkov@nokia.com>
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 #include <linux/init.h>
12 #include <linux/err.h>
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/spinlock.h>
16 #include <linux/interrupt.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk.h>
19 #include <mach/sti.h>
20 #include <asm/byteorder.h>
21 #include <asm/io.h>
22
23 #define SDTI_REVISION           0x000
24 #define SDTI_SYSCONFIG          0x010
25 #define SDTI_SYSSTATUS          0x014
26 #define SDTI_WINCTRL            0x024
27 #define SDTI_SCONFIG            0x028
28 #define SDTI_TESTCTRL           0x02C
29 #define SDTI_LOCK_ACCESS        0xFB0
30
31 #define CPU1_TRACE_EN           0x01
32 #define CPU2_TRACE_EN           0x02
33
34 #define SDTI_SYSCONFIG_SOFTRESET        (1 << 1)
35 #define SDTI_SYSCONFIG_AUTOIDLE         (1 << 0)
36
37 static struct clk *sdti_ck;
38 void __iomem *sti_base, *sti_channel_base;
39 static DEFINE_SPINLOCK(sdti_lock);
40
41 void sti_channel_write_trace(int len, int id, void *data,
42                                 unsigned int channel)
43 {
44         const u8 *tpntr = data;
45
46         spin_lock_irq(&sdti_lock);
47
48         sti_channel_writeb(id, channel);
49         while (len--)
50                 sti_channel_writeb(*tpntr++, channel);
51         sti_channel_flush(channel);
52
53         spin_unlock_irq(&sdti_lock);
54 }
55 EXPORT_SYMBOL(sti_channel_write_trace);
56
57 static void omap_sdti_reset(void)
58 {
59         int i;
60
61         sti_writel(SDTI_SYSCONFIG_SOFTRESET, SDTI_SYSCONFIG);
62
63         for (i = 0; i < 10000; i++)
64                 if (sti_readl(SDTI_SYSSTATUS) & 1)
65                         break;
66         if (i == 10000)
67                 printk(KERN_WARNING "XTI: no real reset\n");
68 }
69
70 static int __init omap_sdti_init(void)
71 {
72         char buf[64];
73         int i;
74
75         sdti_ck = clk_get(NULL, "emu_per_alwon_ck");
76         if (IS_ERR(sdti_ck)) {
77                 printk(KERN_ERR "Cannot get clk emu_per_alwon_ck\n");
78                 return PTR_ERR(sdti_ck);
79         }
80         clk_enable(sdti_ck);
81
82         omap_sdti_reset();
83         sti_writel(0xC5ACCE55, SDTI_LOCK_ACCESS);
84
85         /* Autoidle */
86         sti_writel(SDTI_SYSCONFIG_AUTOIDLE, SDTI_SYSCONFIG);
87
88         /* Claim SDTI */
89         sti_writel(1 << 30, SDTI_WINCTRL);
90         i = sti_readl(SDTI_WINCTRL);
91         if (!(i & (1 << 30)))
92                 printk(KERN_WARNING "SDTI: cannot claim SDTI\n");
93
94         /* 4 bits dual, fclk/3 */
95         sti_writel(0x43, SDTI_SCONFIG);
96
97         /* CPU2 trace enable */
98         sti_writel(i | CPU2_TRACE_EN, SDTI_WINCTRL);
99         i = sti_readl(SDTI_WINCTRL);
100
101         /* Enable SDTI */
102         sti_writel((1 << 31) | (i & 0x3FFFFFFF), SDTI_WINCTRL);
103
104         i = sti_readl(SDTI_REVISION);
105         snprintf(buf, sizeof(buf), "OMAP SDTI support loaded (HW v%u.%u)\n",
106                 (i >> 4) & 0x0f, i & 0x0f);
107         printk(KERN_INFO "%s", buf);
108         sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
109
110         return 0;
111 }
112
113 static void omap_sdti_exit(void)
114 {
115         sti_writel(0, SDTI_WINCTRL);
116         clk_disable(sdti_ck);
117         clk_put(sdti_ck);
118 }
119
120 static int __devinit omap_sdti_probe(struct platform_device *pdev)
121 {
122         struct resource *res, *cres;
123         unsigned int size;
124
125         if (pdev->num_resources != 2) {
126                 dev_err(&pdev->dev, "invalid number of resources: %d\n",
127                         pdev->num_resources);
128                 return -ENODEV;
129         }
130
131         /* SDTI base */
132         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
133         if (unlikely(!res)) {
134                 dev_err(&pdev->dev, "invalid mem resource\n");
135                 return -ENODEV;
136         }
137
138         /* Channel base */
139         cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
140         if (unlikely(!cres)) {
141                 dev_err(&pdev->dev, "invalid channel mem resource\n");
142                 return -ENODEV;
143         }
144
145         size = res->end - res->start;
146         sti_base = ioremap(res->start, size);
147         if (unlikely(!sti_base))
148                 return -ENODEV;
149
150         size = cres->end - cres->start;
151         sti_channel_base = ioremap(cres->start, size);
152         if (unlikely(!sti_channel_base)) {
153                 iounmap(sti_base);
154                 return -ENODEV;
155         }
156
157         return omap_sdti_init();
158 }
159
160 static int __devexit omap_sdti_remove(struct platform_device *pdev)
161 {
162         iounmap(sti_channel_base);
163         iounmap(sti_base);
164         omap_sdti_exit();
165
166         return 0;
167 }
168
169 static struct platform_driver omap_sdti_driver = {
170         .probe          = omap_sdti_probe,
171         .remove         = __devexit_p(omap_sdti_remove),
172         .driver         = {
173                 .name   = "sti",
174                 .owner  = THIS_MODULE,
175         },
176 };
177
178 static int __init omap_sdti_module_init(void)
179 {
180         return platform_driver_register(&omap_sdti_driver);
181 }
182
183 static void __exit omap_sdti_module_exit(void)
184 {
185         platform_driver_unregister(&omap_sdti_driver);
186 }
187 subsys_initcall(omap_sdti_module_init);
188 module_exit(omap_sdti_module_exit);
189
190 MODULE_AUTHOR("Roman Tereshonkov");
191 MODULE_LICENSE("GPL");