Blame view

drivers/uio/uio_pruss.c 7.08 KB
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * Programmable Real-Time Unit Sub System (PRUSS) UIO driver (uio_pruss)
   *
   * This driver exports PRUSS host event out interrupts and PRUSS, L3 RAM,
   * and DDR RAM to user space for applications interacting with PRUSS firmware
   *
   * Copyright (C) 2010-11 Texas Instruments Incorporated - http://www.ti.com/
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation version 2.
   *
   * This program is distributed "as is" WITHOUT ANY WARRANTY of any
   * kind, whether express or implied; without even the implied warranty
   * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   */
  #include <linux/device.h>
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/platform_device.h>
  #include <linux/uio_driver.h>
  #include <linux/platform_data/uio_pruss.h>
  #include <linux/io.h>
  #include <linux/clk.h>
  #include <linux/dma-mapping.h>
876726760   Matwey V. Kornilov   uio: pruss: Inclu...
27
  #include <linux/sizes.h>
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
28
  #include <linux/slab.h>
2eb2478d4   Matt Porter   uio: uio_pruss: r...
29
  #include <linux/genalloc.h>
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
30
31
32
33
34
35
36
37
38
39
40
41
42
  
  #define DRV_NAME "pruss_uio"
  #define DRV_VERSION "1.0"
  
  static int sram_pool_sz = SZ_16K;
  module_param(sram_pool_sz, int, 0);
  MODULE_PARM_DESC(sram_pool_sz, "sram pool size to allocate ");
  
  static int extram_pool_sz = SZ_256K;
  module_param(extram_pool_sz, int, 0);
  MODULE_PARM_DESC(extram_pool_sz, "external ram pool size to allocate");
  
  /*
25985edce   Lucas De Marchi   Fix common misspe...
43
   * Host event IRQ numbers from PRUSS - PRUSS can generate up to 8 interrupt
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
   * events to AINTC of ARM host processor - which can be used for IPC b/w PRUSS
   * firmware and user space application, async notification from PRU firmware
   * to user space application
   * 3	PRU_EVTOUT0
   * 4	PRU_EVTOUT1
   * 5	PRU_EVTOUT2
   * 6	PRU_EVTOUT3
   * 7	PRU_EVTOUT4
   * 8	PRU_EVTOUT5
   * 9	PRU_EVTOUT6
   * 10	PRU_EVTOUT7
  */
  #define MAX_PRUSS_EVT	8
  
  #define PINTC_HIDISR	0x0038
  #define PINTC_HIPIR	0x0900
  #define HIPIR_NOPEND	0x80000000
  #define PINTC_HIER	0x1500
  
  struct uio_pruss_dev {
  	struct uio_info *info;
  	struct clk *pruss_clk;
  	dma_addr_t sram_paddr;
  	dma_addr_t ddr_paddr;
  	void __iomem *prussio_vaddr;
2eb2478d4   Matt Porter   uio: uio_pruss: r...
69
  	unsigned long sram_vaddr;
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
70
71
72
  	void *ddr_vaddr;
  	unsigned int hostirq_start;
  	unsigned int pintc_base;
2eb2478d4   Matt Porter   uio: uio_pruss: r...
73
  	struct gen_pool *sram_pool;
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  };
  
  static irqreturn_t pruss_handler(int irq, struct uio_info *info)
  {
  	struct uio_pruss_dev *gdev = info->priv;
  	int intr_bit = (irq - gdev->hostirq_start + 2);
  	int val, intr_mask = (1 << intr_bit);
  	void __iomem *base = gdev->prussio_vaddr + gdev->pintc_base;
  	void __iomem *intren_reg = base + PINTC_HIER;
  	void __iomem *intrdis_reg = base + PINTC_HIDISR;
  	void __iomem *intrstat_reg = base + PINTC_HIPIR + (intr_bit << 2);
  
  	val = ioread32(intren_reg);
  	/* Is interrupt enabled and active ? */
  	if (!(val & intr_mask) && (ioread32(intrstat_reg) & HIPIR_NOPEND))
  		return IRQ_NONE;
  	/* Disable interrupt */
  	iowrite32(intr_bit, intrdis_reg);
  	return IRQ_HANDLED;
  }
4719ebfd8   Andre Heider   uio: uio_pruss: u...
94
  static void pruss_cleanup(struct device *dev, struct uio_pruss_dev *gdev)
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
95
96
97
98
99
100
101
102
103
104
  {
  	int cnt;
  	struct uio_info *p = gdev->info;
  
  	for (cnt = 0; cnt < MAX_PRUSS_EVT; cnt++, p++) {
  		uio_unregister_device(p);
  		kfree(p->name);
  	}
  	iounmap(gdev->prussio_vaddr);
  	if (gdev->ddr_vaddr) {
4719ebfd8   Andre Heider   uio: uio_pruss: u...
105
  		dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr,
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
106
107
108
  			gdev->ddr_paddr);
  	}
  	if (gdev->sram_vaddr)
2eb2478d4   Matt Porter   uio: uio_pruss: r...
109
110
111
  		gen_pool_free(gdev->sram_pool,
  			      gdev->sram_vaddr,
  			      sram_pool_sz);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
112
  	kfree(gdev->info);
e663c5dba   Alexey Khoroshilov   uio: pruss: add c...
113
  	clk_disable(gdev->pruss_clk);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
114
115
116
  	clk_put(gdev->pruss_clk);
  	kfree(gdev);
  }
4719ebfd8   Andre Heider   uio: uio_pruss: u...
117
  static int pruss_probe(struct platform_device *pdev)
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
118
119
120
121
  {
  	struct uio_info *p;
  	struct uio_pruss_dev *gdev;
  	struct resource *regs_prussio;
4719ebfd8   Andre Heider   uio: uio_pruss: u...
122
  	struct device *dev = &pdev->dev;
95883676e   Dan Carpenter   uio: pruss: fix e...
123
  	int ret, cnt, i, len;
4719ebfd8   Andre Heider   uio: uio_pruss: u...
124
  	struct uio_pruss_pdata *pdata = dev_get_platdata(dev);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
125
126
127
128
  
  	gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL);
  	if (!gdev)
  		return -ENOMEM;
6396bb221   Kees Cook   treewide: kzalloc...
129
  	gdev->info = kcalloc(MAX_PRUSS_EVT, sizeof(*p), GFP_KERNEL);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
130
  	if (!gdev->info) {
95883676e   Dan Carpenter   uio: pruss: fix e...
131
132
  		ret = -ENOMEM;
  		goto err_free_gdev;
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
133
  	}
4719ebfd8   Andre Heider   uio: uio_pruss: u...
134

f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
135
  	/* Power on PRU in case its not done as part of boot-loader */
4719ebfd8   Andre Heider   uio: uio_pruss: u...
136
  	gdev->pruss_clk = clk_get(dev, "pruss");
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
137
  	if (IS_ERR(gdev->pruss_clk)) {
4719ebfd8   Andre Heider   uio: uio_pruss: u...
138
139
  		dev_err(dev, "Failed to get clock
  ");
cb3771b04   Emil Goode   uio: uio_pruss: F...
140
  		ret = PTR_ERR(gdev->pruss_clk);
95883676e   Dan Carpenter   uio: pruss: fix e...
141
142
143
144
145
146
147
148
  		goto err_free_info;
  	}
  
  	ret = clk_enable(gdev->pruss_clk);
  	if (ret) {
  		dev_err(dev, "Failed to enable clock
  ");
  		goto err_clk_put;
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
149
  	}
4719ebfd8   Andre Heider   uio: uio_pruss: u...
150
  	regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
151
  	if (!regs_prussio) {
4719ebfd8   Andre Heider   uio: uio_pruss: u...
152
153
  		dev_err(dev, "No PRUSS I/O resource specified
  ");
95883676e   Dan Carpenter   uio: pruss: fix e...
154
155
  		ret = -EIO;
  		goto err_clk_disable;
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
156
157
158
  	}
  
  	if (!regs_prussio->start) {
4719ebfd8   Andre Heider   uio: uio_pruss: u...
159
160
  		dev_err(dev, "Invalid memory resource
  ");
95883676e   Dan Carpenter   uio: pruss: fix e...
161
162
  		ret = -EIO;
  		goto err_clk_disable;
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
163
  	}
2eb2478d4   Matt Porter   uio: uio_pruss: r...
164
165
166
  	if (pdata->sram_pool) {
  		gdev->sram_pool = pdata->sram_pool;
  		gdev->sram_vaddr =
288342e9c   Nicolin Chen   drivers/uio/uio_p...
167
168
  			(unsigned long)gen_pool_dma_alloc(gdev->sram_pool,
  					sram_pool_sz, &gdev->sram_paddr);
2eb2478d4   Matt Porter   uio: uio_pruss: r...
169
  		if (!gdev->sram_vaddr) {
4719ebfd8   Andre Heider   uio: uio_pruss: u...
170
171
  			dev_err(dev, "Could not allocate SRAM pool
  ");
95883676e   Dan Carpenter   uio: pruss: fix e...
172
173
  			ret = -ENOMEM;
  			goto err_clk_disable;
2eb2478d4   Matt Porter   uio: uio_pruss: r...
174
  		}
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
175
  	}
4719ebfd8   Andre Heider   uio: uio_pruss: u...
176
  	gdev->ddr_vaddr = dma_alloc_coherent(dev, extram_pool_sz,
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
177
178
  				&(gdev->ddr_paddr), GFP_KERNEL | GFP_DMA);
  	if (!gdev->ddr_vaddr) {
4719ebfd8   Andre Heider   uio: uio_pruss: u...
179
180
  		dev_err(dev, "Could not allocate external memory
  ");
95883676e   Dan Carpenter   uio: pruss: fix e...
181
182
  		ret = -ENOMEM;
  		goto err_free_sram;
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
183
184
185
186
187
  	}
  
  	len = resource_size(regs_prussio);
  	gdev->prussio_vaddr = ioremap(regs_prussio->start, len);
  	if (!gdev->prussio_vaddr) {
4719ebfd8   Andre Heider   uio: uio_pruss: u...
188
189
  		dev_err(dev, "Can't remap PRUSS I/O  address range
  ");
95883676e   Dan Carpenter   uio: pruss: fix e...
190
191
  		ret = -ENOMEM;
  		goto err_free_ddr_vaddr;
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
192
193
194
  	}
  
  	gdev->pintc_base = pdata->pintc_base;
4719ebfd8   Andre Heider   uio: uio_pruss: u...
195
  	gdev->hostirq_start = platform_get_irq(pdev, 0);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  
  	for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) {
  		p->mem[0].addr = regs_prussio->start;
  		p->mem[0].size = resource_size(regs_prussio);
  		p->mem[0].memtype = UIO_MEM_PHYS;
  
  		p->mem[1].addr = gdev->sram_paddr;
  		p->mem[1].size = sram_pool_sz;
  		p->mem[1].memtype = UIO_MEM_PHYS;
  
  		p->mem[2].addr = gdev->ddr_paddr;
  		p->mem[2].size = extram_pool_sz;
  		p->mem[2].memtype = UIO_MEM_PHYS;
  
  		p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt);
  		p->version = DRV_VERSION;
  
  		/* Register PRUSS IRQ lines */
  		p->irq = gdev->hostirq_start + cnt;
  		p->handler = pruss_handler;
  		p->priv = gdev;
4719ebfd8   Andre Heider   uio: uio_pruss: u...
217
  		ret = uio_register_device(dev, p);
95883676e   Dan Carpenter   uio: pruss: fix e...
218
219
220
221
  		if (ret < 0) {
  			kfree(p->name);
  			goto err_unloop;
  		}
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
222
  	}
4719ebfd8   Andre Heider   uio: uio_pruss: u...
223
  	platform_set_drvdata(pdev, gdev);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
224
  	return 0;
95883676e   Dan Carpenter   uio: pruss: fix e...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  err_unloop:
  	for (i = 0, p = gdev->info; i < cnt; i++, p++) {
  		uio_unregister_device(p);
  		kfree(p->name);
  	}
  	iounmap(gdev->prussio_vaddr);
  err_free_ddr_vaddr:
  	dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr,
  			  gdev->ddr_paddr);
  err_free_sram:
  	if (pdata->sram_pool)
  		gen_pool_free(gdev->sram_pool, gdev->sram_vaddr, sram_pool_sz);
  err_clk_disable:
  	clk_disable(gdev->pruss_clk);
  err_clk_put:
  	clk_put(gdev->pruss_clk);
  err_free_info:
  	kfree(gdev->info);
  err_free_gdev:
  	kfree(gdev);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
245
246
  	return ret;
  }
9b96c3124   Bill Pemberton   uio: remove use o...
247
  static int pruss_remove(struct platform_device *dev)
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
248
249
  {
  	struct uio_pruss_dev *gdev = platform_get_drvdata(dev);
4719ebfd8   Andre Heider   uio: uio_pruss: u...
250
  	pruss_cleanup(&dev->dev, gdev);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
251
252
253
254
255
  	return 0;
  }
  
  static struct platform_driver pruss_driver = {
  	.probe = pruss_probe,
5a59509b4   Bill Pemberton   uio: remove use o...
256
  	.remove = pruss_remove,
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
257
258
  	.driver = {
  		   .name = DRV_NAME,
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
259
260
  		   },
  };
11e3123d9   Axel Lin   uio: convert driv...
261
  module_platform_driver(pruss_driver);
f1a304e79   Pratheesh Gangadhar   UIO: add PRUSS UI...
262
263
264
265
266
  
  MODULE_LICENSE("GPL v2");
  MODULE_VERSION(DRV_VERSION);
  MODULE_AUTHOR("Amit Chatterjee <amit.chatterjee@ti.com>");
  MODULE_AUTHOR("Pratheesh Gangadhar <pratheesh@ti.com>");