~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/uio/uio_pruss.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Programmable Real-Time Unit Sub System (PRUSS) UIO driver (uio_pruss)
 
3
 *
 
4
 * This driver exports PRUSS host event out interrupts and PRUSS, L3 RAM,
 
5
 * and DDR RAM to user space for applications interacting with PRUSS firmware
 
6
 *
 
7
 * Copyright (C) 2010-11 Texas Instruments Incorporated - http://www.ti.com/
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU General Public License as
 
11
 * published by the Free Software Foundation version 2.
 
12
 *
 
13
 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
 
14
 * kind, whether express or implied; without even the implied warranty
 
15
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 */
 
18
#include <linux/device.h>
 
19
#include <linux/module.h>
 
20
#include <linux/moduleparam.h>
 
21
#include <linux/platform_device.h>
 
22
#include <linux/uio_driver.h>
 
23
#include <linux/platform_data/uio_pruss.h>
 
24
#include <linux/io.h>
 
25
#include <linux/clk.h>
 
26
#include <linux/dma-mapping.h>
 
27
#include <linux/slab.h>
 
28
#include <mach/sram.h>
 
29
 
 
30
#define DRV_NAME "pruss_uio"
 
31
#define DRV_VERSION "1.0"
 
32
 
 
33
static int sram_pool_sz = SZ_16K;
 
34
module_param(sram_pool_sz, int, 0);
 
35
MODULE_PARM_DESC(sram_pool_sz, "sram pool size to allocate ");
 
36
 
 
37
static int extram_pool_sz = SZ_256K;
 
38
module_param(extram_pool_sz, int, 0);
 
39
MODULE_PARM_DESC(extram_pool_sz, "external ram pool size to allocate");
 
40
 
 
41
/*
 
42
 * Host event IRQ numbers from PRUSS - PRUSS can generate up to 8 interrupt
 
43
 * events to AINTC of ARM host processor - which can be used for IPC b/w PRUSS
 
44
 * firmware and user space application, async notification from PRU firmware
 
45
 * to user space application
 
46
 * 3    PRU_EVTOUT0
 
47
 * 4    PRU_EVTOUT1
 
48
 * 5    PRU_EVTOUT2
 
49
 * 6    PRU_EVTOUT3
 
50
 * 7    PRU_EVTOUT4
 
51
 * 8    PRU_EVTOUT5
 
52
 * 9    PRU_EVTOUT6
 
53
 * 10   PRU_EVTOUT7
 
54
*/
 
55
#define MAX_PRUSS_EVT   8
 
56
 
 
57
#define PINTC_HIDISR    0x0038
 
58
#define PINTC_HIPIR     0x0900
 
59
#define HIPIR_NOPEND    0x80000000
 
60
#define PINTC_HIER      0x1500
 
61
 
 
62
struct uio_pruss_dev {
 
63
        struct uio_info *info;
 
64
        struct clk *pruss_clk;
 
65
        dma_addr_t sram_paddr;
 
66
        dma_addr_t ddr_paddr;
 
67
        void __iomem *prussio_vaddr;
 
68
        void *sram_vaddr;
 
69
        void *ddr_vaddr;
 
70
        unsigned int hostirq_start;
 
71
        unsigned int pintc_base;
 
72
};
 
73
 
 
74
static irqreturn_t pruss_handler(int irq, struct uio_info *info)
 
75
{
 
76
        struct uio_pruss_dev *gdev = info->priv;
 
77
        int intr_bit = (irq - gdev->hostirq_start + 2);
 
78
        int val, intr_mask = (1 << intr_bit);
 
79
        void __iomem *base = gdev->prussio_vaddr + gdev->pintc_base;
 
80
        void __iomem *intren_reg = base + PINTC_HIER;
 
81
        void __iomem *intrdis_reg = base + PINTC_HIDISR;
 
82
        void __iomem *intrstat_reg = base + PINTC_HIPIR + (intr_bit << 2);
 
83
 
 
84
        val = ioread32(intren_reg);
 
85
        /* Is interrupt enabled and active ? */
 
86
        if (!(val & intr_mask) && (ioread32(intrstat_reg) & HIPIR_NOPEND))
 
87
                return IRQ_NONE;
 
88
        /* Disable interrupt */
 
89
        iowrite32(intr_bit, intrdis_reg);
 
90
        return IRQ_HANDLED;
 
91
}
 
92
 
 
93
static void pruss_cleanup(struct platform_device *dev,
 
94
                        struct uio_pruss_dev *gdev)
 
95
{
 
96
        int cnt;
 
97
        struct uio_info *p = gdev->info;
 
98
 
 
99
        for (cnt = 0; cnt < MAX_PRUSS_EVT; cnt++, p++) {
 
100
                uio_unregister_device(p);
 
101
                kfree(p->name);
 
102
        }
 
103
        iounmap(gdev->prussio_vaddr);
 
104
        if (gdev->ddr_vaddr) {
 
105
                dma_free_coherent(&dev->dev, extram_pool_sz, gdev->ddr_vaddr,
 
106
                        gdev->ddr_paddr);
 
107
        }
 
108
        if (gdev->sram_vaddr)
 
109
                sram_free(gdev->sram_vaddr, sram_pool_sz);
 
110
        kfree(gdev->info);
 
111
        clk_put(gdev->pruss_clk);
 
112
        kfree(gdev);
 
113
}
 
114
 
 
115
static int __devinit pruss_probe(struct platform_device *dev)
 
116
{
 
117
        struct uio_info *p;
 
118
        struct uio_pruss_dev *gdev;
 
119
        struct resource *regs_prussio;
 
120
        int ret = -ENODEV, cnt = 0, len;
 
121
        struct uio_pruss_pdata *pdata = dev->dev.platform_data;
 
122
 
 
123
        gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL);
 
124
        if (!gdev)
 
125
                return -ENOMEM;
 
126
 
 
127
        gdev->info = kzalloc(sizeof(*p) * MAX_PRUSS_EVT, GFP_KERNEL);
 
128
        if (!gdev->info) {
 
129
                kfree(gdev);
 
130
                return -ENOMEM;
 
131
        }
 
132
        /* Power on PRU in case its not done as part of boot-loader */
 
133
        gdev->pruss_clk = clk_get(&dev->dev, "pruss");
 
134
        if (IS_ERR(gdev->pruss_clk)) {
 
135
                dev_err(&dev->dev, "Failed to get clock\n");
 
136
                kfree(gdev->info);
 
137
                kfree(gdev);
 
138
                ret = PTR_ERR(gdev->pruss_clk);
 
139
                return ret;
 
140
        } else {
 
141
                clk_enable(gdev->pruss_clk);
 
142
        }
 
143
 
 
144
        regs_prussio = platform_get_resource(dev, IORESOURCE_MEM, 0);
 
145
        if (!regs_prussio) {
 
146
                dev_err(&dev->dev, "No PRUSS I/O resource specified\n");
 
147
                goto out_free;
 
148
        }
 
149
 
 
150
        if (!regs_prussio->start) {
 
151
                dev_err(&dev->dev, "Invalid memory resource\n");
 
152
                goto out_free;
 
153
        }
 
154
 
 
155
        gdev->sram_vaddr = sram_alloc(sram_pool_sz, &(gdev->sram_paddr));
 
156
        if (!gdev->sram_vaddr) {
 
157
                dev_err(&dev->dev, "Could not allocate SRAM pool\n");
 
158
                goto out_free;
 
159
        }
 
160
 
 
161
        gdev->ddr_vaddr = dma_alloc_coherent(&dev->dev, extram_pool_sz,
 
162
                                &(gdev->ddr_paddr), GFP_KERNEL | GFP_DMA);
 
163
        if (!gdev->ddr_vaddr) {
 
164
                dev_err(&dev->dev, "Could not allocate external memory\n");
 
165
                goto out_free;
 
166
        }
 
167
 
 
168
        len = resource_size(regs_prussio);
 
169
        gdev->prussio_vaddr = ioremap(regs_prussio->start, len);
 
170
        if (!gdev->prussio_vaddr) {
 
171
                dev_err(&dev->dev, "Can't remap PRUSS I/O  address range\n");
 
172
                goto out_free;
 
173
        }
 
174
 
 
175
        gdev->pintc_base = pdata->pintc_base;
 
176
        gdev->hostirq_start = platform_get_irq(dev, 0);
 
177
 
 
178
        for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) {
 
179
                p->mem[0].addr = regs_prussio->start;
 
180
                p->mem[0].size = resource_size(regs_prussio);
 
181
                p->mem[0].memtype = UIO_MEM_PHYS;
 
182
 
 
183
                p->mem[1].addr = gdev->sram_paddr;
 
184
                p->mem[1].size = sram_pool_sz;
 
185
                p->mem[1].memtype = UIO_MEM_PHYS;
 
186
 
 
187
                p->mem[2].addr = gdev->ddr_paddr;
 
188
                p->mem[2].size = extram_pool_sz;
 
189
                p->mem[2].memtype = UIO_MEM_PHYS;
 
190
 
 
191
                p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt);
 
192
                p->version = DRV_VERSION;
 
193
 
 
194
                /* Register PRUSS IRQ lines */
 
195
                p->irq = gdev->hostirq_start + cnt;
 
196
                p->handler = pruss_handler;
 
197
                p->priv = gdev;
 
198
 
 
199
                ret = uio_register_device(&dev->dev, p);
 
200
                if (ret < 0)
 
201
                        goto out_free;
 
202
        }
 
203
 
 
204
        platform_set_drvdata(dev, gdev);
 
205
        return 0;
 
206
 
 
207
out_free:
 
208
        pruss_cleanup(dev, gdev);
 
209
        return ret;
 
210
}
 
211
 
 
212
static int __devexit pruss_remove(struct platform_device *dev)
 
213
{
 
214
        struct uio_pruss_dev *gdev = platform_get_drvdata(dev);
 
215
 
 
216
        pruss_cleanup(dev, gdev);
 
217
        platform_set_drvdata(dev, NULL);
 
218
        return 0;
 
219
}
 
220
 
 
221
static struct platform_driver pruss_driver = {
 
222
        .probe = pruss_probe,
 
223
        .remove = __devexit_p(pruss_remove),
 
224
        .driver = {
 
225
                   .name = DRV_NAME,
 
226
                   .owner = THIS_MODULE,
 
227
                   },
 
228
};
 
229
 
 
230
static int __init pruss_init_module(void)
 
231
{
 
232
        return platform_driver_register(&pruss_driver);
 
233
}
 
234
 
 
235
module_init(pruss_init_module);
 
236
 
 
237
static void __exit pruss_exit_module(void)
 
238
{
 
239
        platform_driver_unregister(&pruss_driver);
 
240
}
 
241
 
 
242
module_exit(pruss_exit_module);
 
243
 
 
244
MODULE_LICENSE("GPL v2");
 
245
MODULE_VERSION(DRV_VERSION);
 
246
MODULE_AUTHOR("Amit Chatterjee <amit.chatterjee@ti.com>");
 
247
MODULE_AUTHOR("Pratheesh Gangadhar <pratheesh@ti.com>");