blob: 563a013b5e06abe8d51456f475a0394b30b9c615 [file] [log] [blame]
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Joel Nider5556a852011-10-16 10:52:13 +02002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Joel Nider5bd73f82011-12-14 16:53:30 +020013#include <linux/module.h> /* Just for modules */
14#include <linux/kernel.h> /* Only for KERN_INFO */
15#include <linux/err.h> /* Error macros */
16#include <linux/list.h> /* Linked list */
Joel Nider5556a852011-10-16 10:52:13 +020017#include <linux/cdev.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020018#include <linux/init.h> /* Needed for the macros */
19#include <linux/io.h> /* IO macros */
20#include <linux/device.h> /* Device drivers need this */
21#include <linux/sched.h> /* Externally defined globals */
22#include <linux/pm_runtime.h> /* Runtime power management */
Joel Nider5556a852011-10-16 10:52:13 +020023#include <linux/fs.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020024#include <linux/uaccess.h> /* copy_to_user */
Joel Nider5556a852011-10-16 10:52:13 +020025#include <linux/slab.h> /* kfree, kzalloc */
Joel Nider5bd73f82011-12-14 16:53:30 +020026#include <linux/ioport.h> /* XXX_ mem_region */
27#include <linux/dma-mapping.h> /* dma_XXX */
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +020028#include <linux/dmapool.h> /* DMA pools */
Joel Nider5bd73f82011-12-14 16:53:30 +020029#include <linux/delay.h> /* msleep */
30#include <linux/platform_device.h>
Joel Nider5556a852011-10-16 10:52:13 +020031#include <linux/clk.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020032#include <linux/poll.h> /* poll() file op */
33#include <linux/wait.h> /* wait() macros, sleeping */
34#include <linux/tspp.h> /* tspp functions */
Joel Nider5556a852011-10-16 10:52:13 +020035#include <linux/bitops.h> /* BIT() macro */
Joel Nider5bd73f82011-12-14 16:53:30 +020036#include <mach/sps.h> /* BAM stuff */
Joel Nider5556a852011-10-16 10:52:13 +020037#include <mach/gpio.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020038#include <linux/wakelock.h> /* Locking functions */
Hamad Kadmany567bed82012-11-29 14:15:57 +020039#include <linux/timer.h> /* Timer services */
40#include <linux/jiffies.h> /* Jiffies counter */
Joel Nider5556a852011-10-16 10:52:13 +020041#include <mach/dma.h>
42#include <mach/msm_tspp.h>
Joel Nider5556a852011-10-16 10:52:13 +020043#include <linux/debugfs.h>
Joel Nider5556a852011-10-16 10:52:13 +020044
45/*
46 * General defines
47 */
Joel Nider5556a852011-10-16 10:52:13 +020048#define TSPP_TSIF_INSTANCES 2
49#define TSPP_FILTER_TABLES 3
Joel Nider5bd73f82011-12-14 16:53:30 +020050#define TSPP_MAX_DEVICES 1
Joel Nider5556a852011-10-16 10:52:13 +020051#define TSPP_NUM_CHANNELS 16
52#define TSPP_NUM_PRIORITIES 16
53#define TSPP_NUM_KEYS 8
54#define INVALID_CHANNEL 0xFFFFFFFF
Hamad Kadmany567bed82012-11-29 14:15:57 +020055
56/*
57 * BAM descriptor FIFO size (in number of descriptors).
58 * Max number of descriptors allowed by SPS which is 8K-1.
59 * Restrict it to half of this to save DMA memory.
60 */
61#define TSPP_SPS_DESCRIPTOR_COUNT (4 * 1024 - 1)
Joel Nider5556a852011-10-16 10:52:13 +020062#define TSPP_PACKET_LENGTH 188
63#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
Hamad Kadmany567bed82012-11-29 14:15:57 +020064
65/* Max descriptor buffer size allowed by SPS */
66#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
67
68/*
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +020069 * Returns whether to use DMA pool for TSPP output buffers.
70 * For buffers smaller than page size, using DMA pool
71 * provides better memory utilization as dma_alloc_coherent
72 * allocates minimum of page size.
73 */
74#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE)
75
76/*
Hamad Kadmany567bed82012-11-29 14:15:57 +020077 * Max allowed TSPP buffers/descriptors.
78 * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
79 */
80#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
Joel Nider5556a852011-10-16 10:52:13 +020081#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
82#define SPS_DESCRIPTOR_SIZE 8
83#define MIN_ACCEPTABLE_BUFFER_COUNT 2
Joel Nider5bd73f82011-12-14 16:53:30 +020084#define TSPP_DEBUG(msg...)
Joel Nider5556a852011-10-16 10:52:13 +020085
86/*
87 * TSIF register offsets
88 */
89#define TSIF_STS_CTL_OFF (0x0)
90#define TSIF_TIME_LIMIT_OFF (0x4)
91#define TSIF_CLK_REF_OFF (0x8)
92#define TSIF_LPBK_FLAGS_OFF (0xc)
93#define TSIF_LPBK_DATA_OFF (0x10)
94#define TSIF_TEST_CTL_OFF (0x14)
95#define TSIF_TEST_MODE_OFF (0x18)
96#define TSIF_TEST_RESET_OFF (0x1c)
97#define TSIF_TEST_EXPORT_OFF (0x20)
98#define TSIF_TEST_CURRENT_OFF (0x24)
99
100#define TSIF_DATA_PORT_OFF (0x100)
101
102/* bits for TSIF_STS_CTL register */
103#define TSIF_STS_CTL_EN_IRQ BIT(28)
104#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
105#define TSIF_STS_CTL_1ST_PACKET BIT(26)
106#define TSIF_STS_CTL_OVERFLOW BIT(25)
107#define TSIF_STS_CTL_LOST_SYNC BIT(24)
108#define TSIF_STS_CTL_TIMEOUT BIT(23)
109#define TSIF_STS_CTL_INV_SYNC BIT(21)
110#define TSIF_STS_CTL_INV_NULL BIT(20)
111#define TSIF_STS_CTL_INV_ERROR BIT(19)
112#define TSIF_STS_CTL_INV_ENABLE BIT(18)
113#define TSIF_STS_CTL_INV_DATA BIT(17)
114#define TSIF_STS_CTL_INV_CLOCK BIT(16)
115#define TSIF_STS_CTL_SPARE BIT(15)
116#define TSIF_STS_CTL_EN_NULL BIT(11)
117#define TSIF_STS_CTL_EN_ERROR BIT(10)
118#define TSIF_STS_CTL_LAST_BIT BIT(9)
119#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
120#define TSIF_STS_CTL_EN_TCR BIT(7)
121#define TSIF_STS_CTL_TEST_MODE BIT(6)
Joel Nider5bd73f82011-12-14 16:53:30 +0200122#define TSIF_STS_CTL_MODE_2 BIT(5)
Joel Nider5556a852011-10-16 10:52:13 +0200123#define TSIF_STS_CTL_EN_DM BIT(4)
124#define TSIF_STS_CTL_STOP BIT(3)
125#define TSIF_STS_CTL_START BIT(0)
126
127/*
128 * TSPP register offsets
129 */
Liron Kuch229090d2012-10-30 17:47:50 +0200130#define TSPP_RST 0x00
Joel Nider5556a852011-10-16 10:52:13 +0200131#define TSPP_CLK_CONTROL 0x04
Liron Kuch229090d2012-10-30 17:47:50 +0200132#define TSPP_CONFIG 0x08
133#define TSPP_CONTROL 0x0C
Joel Nider5556a852011-10-16 10:52:13 +0200134#define TSPP_PS_DISABLE 0x10
Liron Kuch229090d2012-10-30 17:47:50 +0200135#define TSPP_MSG_IRQ_STATUS 0x14
Joel Nider5556a852011-10-16 10:52:13 +0200136#define TSPP_MSG_IRQ_MASK 0x18
137#define TSPP_IRQ_STATUS 0x1C
138#define TSPP_IRQ_MASK 0x20
139#define TSPP_IRQ_CLEAR 0x24
140#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2))
Liron Kuch229090d2012-10-30 17:47:50 +0200141#define TSPP_STATUS 0x68
142#define TSPP_CURR_TSP_HEADER 0x6C
143#define TSPP_CURR_PID_FILTER 0x70
144#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2))
145#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2))
146#define TSPP_DATA_KEY_RESET 0x9C
Joel Nider5556a852011-10-16 10:52:13 +0200147#define TSPP_KEY_VALID 0xA0
148#define TSPP_KEY_ERROR 0xA4
149#define TSPP_TEST_CTRL 0xA8
Liron Kuch229090d2012-10-30 17:47:50 +0200150#define TSPP_VERSION 0xAC
Joel Nider5556a852011-10-16 10:52:13 +0200151#define TSPP_GENERICS 0xB0
Liron Kuch229090d2012-10-30 17:47:50 +0200152#define TSPP_NOP 0xB4
Joel Nider5556a852011-10-16 10:52:13 +0200153
154/*
155 * Register bit definitions
156 */
157/* TSPP_RST */
158#define TSPP_RST_RESET BIT(0)
159
160/* TSPP_CLK_CONTROL */
161#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9)
162#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8)
163#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7)
164#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6)
165#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5)
166#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
167#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3)
168#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
169#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
170#define TSPP_CLK_CONTROL_SET_CLKON BIT(0)
171
172/* TSPP_CONFIG */
173#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
174((_b & 0xF) << 8))
175#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
176#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7)
177#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6)
178#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5)
179#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
180#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3)
181#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2)
182#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1)
183#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0)
184
185/* TSPP_CONTROL */
186#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5)
187#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4)
188#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3)
189#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2)
190#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1)
191#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0)
192
193/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
194#define TSPP_MSG_TSPP_IRQ BIT(2)
195#define TSPP_MSG_TSIF_1_IRQ BIT(1)
196#define TSPP_MSG_TSIF_0_IRQ BIT(0)
197
198/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
Liron Kuch229090d2012-10-30 17:47:50 +0200199#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19)
200#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18)
Joel Nider5556a852011-10-16 10:52:13 +0200201#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17)
202#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16)
203#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n))
204
205/* TSPP_PIPE_ERROR_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200206#define TSPP_PIPE_PES_SYNC_ERROR BIT(3)
207#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2)
Joel Nider5556a852011-10-16 10:52:13 +0200208#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1)
Liron Kuch229090d2012-10-30 17:47:50 +0200209#define TSPP_PIP_PS_LOST_START BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200210
211/* TSPP_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200212#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10)
213#define TSPP_STATUS_TSIF1_DM_REQ BIT(6)
214#define TSPP_STATUS_TSIF0_DM_REQ BIT(2)
215#define TSPP_CURR_FILTER_TABLE BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200216
217/* TSPP_GENERICS */
Liron Kuch229090d2012-10-30 17:47:50 +0200218#define TSPP_GENERICS_CRYPTO_GEN BIT(12)
Joel Nider5556a852011-10-16 10:52:13 +0200219#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7)
Liron Kuch229090d2012-10-30 17:47:50 +0200220#define TSPP_GENERICS_MAX_PIPES BIT(2)
221#define TSPP_GENERICS_TSIF_1_GEN BIT(1)
222#define TSPP_GENERICS_TSIF_0_GEN BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200223
224/*
225 * TSPP memory regions
226 */
227#define TSPP_PID_FILTER_TABLE0 0x800
228#define TSPP_PID_FILTER_TABLE1 0x880
229#define TSPP_PID_FILTER_TABLE2 0x900
230#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */
231#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */
232#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */
233#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
234#define TSPP_DATA_KEY 0xCD0
235
Joel Nider5556a852011-10-16 10:52:13 +0200236struct debugfs_entry {
237 const char *name;
238 mode_t mode;
239 int offset;
240};
241
242static const struct debugfs_entry debugfs_tsif_regs[] = {
243 {"sts_ctl", S_IRUGO | S_IWUSR, TSIF_STS_CTL_OFF},
244 {"time_limit", S_IRUGO | S_IWUSR, TSIF_TIME_LIMIT_OFF},
245 {"clk_ref", S_IRUGO | S_IWUSR, TSIF_CLK_REF_OFF},
246 {"lpbk_flags", S_IRUGO | S_IWUSR, TSIF_LPBK_FLAGS_OFF},
247 {"lpbk_data", S_IRUGO | S_IWUSR, TSIF_LPBK_DATA_OFF},
248 {"test_ctl", S_IRUGO | S_IWUSR, TSIF_TEST_CTL_OFF},
249 {"test_mode", S_IRUGO | S_IWUSR, TSIF_TEST_MODE_OFF},
250 {"test_reset", S_IWUSR, TSIF_TEST_RESET_OFF},
251 {"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
252 {"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
253 {"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
254};
255
256static const struct debugfs_entry debugfs_tspp_regs[] = {
257 {"rst", S_IRUGO | S_IWUSR, TSPP_RST},
258 {"clk_control", S_IRUGO | S_IWUSR, TSPP_CLK_CONTROL},
259 {"config", S_IRUGO | S_IWUSR, TSPP_CONFIG},
260 {"control", S_IRUGO | S_IWUSR, TSPP_CONTROL},
261 {"ps_disable", S_IRUGO | S_IWUSR, TSPP_PS_DISABLE},
262 {"msg_irq_status", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_STATUS},
263 {"msg_irq_mask", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_MASK},
264 {"irq_status", S_IRUGO | S_IWUSR, TSPP_IRQ_STATUS},
265 {"irq_mask", S_IRUGO | S_IWUSR, TSPP_IRQ_MASK},
266 {"irq_clear", S_IRUGO | S_IWUSR, TSPP_IRQ_CLEAR},
267 /* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
268 {"status", S_IRUGO | S_IWUSR, TSPP_STATUS},
269 {"curr_tsp_header", S_IRUGO | S_IWUSR, TSPP_CURR_TSP_HEADER},
270 {"curr_pid_filter", S_IRUGO | S_IWUSR, TSPP_CURR_PID_FILTER},
271 /* {"system_key", S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
272 /* {"cbc_init_val", S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
273 {"data_key_reset", S_IRUGO | S_IWUSR, TSPP_DATA_KEY_RESET},
274 {"key_valid", S_IRUGO | S_IWUSR, TSPP_KEY_VALID},
275 {"key_error", S_IRUGO | S_IWUSR, TSPP_KEY_ERROR},
276 {"test_ctrl", S_IRUGO | S_IWUSR, TSPP_TEST_CTRL},
277 {"version", S_IRUGO | S_IWUSR, TSPP_VERSION},
278 {"generics", S_IRUGO | S_IWUSR, TSPP_GENERICS},
279 {"pid_filter_table0", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE0},
280 {"pid_filter_table1", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE1},
281 {"pid_filter_table2", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE2},
282 {"global_performance", S_IRUGO | S_IWUSR, TSPP_GLOBAL_PERFORMANCE},
283 {"pipe_context", S_IRUGO | S_IWUSR, TSPP_PIPE_CONTEXT},
284 {"pipe_performance", S_IRUGO | S_IWUSR, TSPP_PIPE_PERFORMANCE},
285 {"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
286};
287
Joel Nider5556a852011-10-16 10:52:13 +0200288struct tspp_pid_filter {
289 u32 filter; /* see FILTER_ macros */
290 u32 config; /* see FILTER_ macros */
291};
292
293/* tsp_info */
294#define FILTER_HEADER_ERROR_MASK BIT(7)
295#define FILTER_TRANS_END_DISABLE BIT(6)
296#define FILTER_DEC_ON_ERROR_EN BIT(5)
297#define FILTER_DECRYPT BIT(4)
298#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT)
299#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF)
300#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \
301 (_p->config & ~0xF) | (_b & 0xF))
302#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3)
303#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \
304 (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
305#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF)
306#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \
307 (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
308#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF)
309#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \
310 (_p->filter & ~0x1FFF) | (_b & 0x1FFF))
311#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3)
312#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \
313 (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
314#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7)
315#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \
316 (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
317
318struct tspp_global_performance_regs {
319 u32 tsp_total;
320 u32 tsp_ignored;
321 u32 tsp_error;
322 u32 tsp_sync;
323};
324
325struct tspp_pipe_context_regs {
326 u16 pes_bytes_left;
327 u16 count;
328 u32 tsif_suffix;
329} __packed;
330#define CONTEXT_GET_STATE(_a) (_a & 0x3)
331#define CONTEXT_UNSPEC_LENGTH BIT(11)
332#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
333
Hamad Kadmany567bed82012-11-29 14:15:57 +0200334#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
335
Joel Nider5556a852011-10-16 10:52:13 +0200336struct tspp_pipe_performance_regs {
337 u32 tsp_total;
338 u32 ps_duplicate_tsp;
339 u32 tsp_no_payload;
340 u32 tsp_broken_ps;
341 u32 ps_total_num;
342 u32 ps_continuity_error;
343 u32 ps_length_error;
344 u32 pes_sync_error;
345};
346
347struct tspp_tsif_device {
348 void __iomem *base;
349 u32 time_limit;
350 u32 ref_count;
Joel Nider5bd73f82011-12-14 16:53:30 +0200351 enum tspp_tsif_mode mode;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200352 int clock_inverse;
353 int data_inverse;
354 int sync_inverse;
355 int enable_inverse;
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200356 u32 tsif_irq;
Joel Nider5556a852011-10-16 10:52:13 +0200357
358 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200359 struct dentry *dent_tsif;
360 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200361 u32 stat_rx;
362 u32 stat_overflow;
363 u32 stat_lost_sync;
364 u32 stat_timeout;
Joel Nider5556a852011-10-16 10:52:13 +0200365};
366
367enum tspp_buf_state {
368 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
369 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider5bd73f82011-12-14 16:53:30 +0200370 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
371 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200372};
373
374struct tspp_mem_buffer {
Joel Nider5bd73f82011-12-14 16:53:30 +0200375 struct tspp_mem_buffer *next;
376 struct sps_mem_buffer sps;
377 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200378 enum tspp_buf_state state;
379 size_t filled; /* how much data this buffer is holding */
380 int read_index; /* where to start reading data from */
381};
382
383/* this represents each char device 'channel' */
384struct tspp_channel {
385 struct cdev cdev;
386 struct device *dd;
Joel Nider5bd73f82011-12-14 16:53:30 +0200387 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200388 struct sps_pipe *pipe;
389 struct sps_connect config;
390 struct sps_register_event event;
Joel Nider5bd73f82011-12-14 16:53:30 +0200391 struct tspp_mem_buffer *data; /* list of buffers */
392 struct tspp_mem_buffer *read; /* first buffer ready to be read */
393 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
394 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200395 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider5bd73f82011-12-14 16:53:30 +0200396 u32 id; /* channel id (0-15) */
397 int used; /* is this channel in use? */
398 int key; /* which encryption key index is used */
399 u32 buffer_size; /* size of the sps transfer buffers */
400 u32 max_buffers; /* how many buffers should be allocated */
401 u32 buffer_count; /* how many buffers are actually allocated */
402 u32 filter_count; /* how many filters have been added to this channel */
403 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200404 enum tspp_source src;
405 enum tspp_mode mode;
Joel Nider5bd73f82011-12-14 16:53:30 +0200406 tspp_notifier *notifier; /* used only with kernel api */
407 void *notify_data; /* data to be passed with the notifier */
Hamad Kadmany567bed82012-11-29 14:15:57 +0200408 u32 expiration_period_ms; /* notification on partially filled buffers */
409 struct timer_list expiration_timer;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200410 struct dma_pool *dma_pool;
Liron Kuch229090d2012-10-30 17:47:50 +0200411 tspp_memfree *memfree; /* user defined memory free function */
412 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200413};
414
415struct tspp_pid_filter_table {
416 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
417};
418
419struct tspp_key_entry {
420 u32 even_lsb;
421 u32 even_msb;
422 u32 odd_lsb;
423 u32 odd_msb;
424};
425
426struct tspp_key_table {
427 struct tspp_key_entry entry[TSPP_NUM_KEYS];
428};
429
Joel Nider5bd73f82011-12-14 16:53:30 +0200430/* this represents the actual hardware device */
431struct tspp_device {
432 struct list_head devlist; /* list of all devices */
433 struct platform_device *pdev;
434 void __iomem *base;
435 unsigned int tspp_irq;
436 unsigned int bam_irq;
437 u32 bam_handle;
438 struct sps_bam_props bam_props;
439 struct wake_lock wake_lock;
440 spinlock_t spinlock;
441 struct tasklet_struct tlet;
442 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
443 /* clocks */
444 struct clk *tsif_pclk;
445 struct clk *tsif_ref_clk;
446 /* data */
447 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
448 struct tspp_channel channels[TSPP_NUM_CHANNELS];
449 struct tspp_key_table *tspp_key_table;
450 struct tspp_global_performance_regs *tspp_global_performance;
451 struct tspp_pipe_context_regs *tspp_pipe_context;
452 struct tspp_pipe_performance_regs *tspp_pipe_performance;
453
454 struct dentry *dent;
455 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
456};
457
458
Joel Nider5556a852011-10-16 10:52:13 +0200459static struct class *tspp_class;
460static int tspp_key_entry;
461static dev_t tspp_minor; /* next minor number to assign */
Joel Nider5bd73f82011-12-14 16:53:30 +0200462
463static LIST_HEAD(tspp_devices);
464
465/* forward declarations */
466static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
467static ssize_t tspp_open(struct inode *inode, struct file *filp);
468static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
469static ssize_t tspp_release(struct inode *inode, struct file *filp);
470static long tspp_ioctl(struct file *, unsigned int, unsigned long);
471
472/* file operations */
473static const struct file_operations tspp_fops = {
474 .owner = THIS_MODULE,
475 .read = tspp_read,
476 .open = tspp_open,
477 .poll = tspp_poll,
478 .release = tspp_release,
479 .unlocked_ioctl = tspp_ioctl,
480};
Joel Nider5556a852011-10-16 10:52:13 +0200481
482/*** IRQ ***/
Joel Nider5bd73f82011-12-14 16:53:30 +0200483static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200484{
Joel Nider5bd73f82011-12-14 16:53:30 +0200485 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200486 u32 status, mask;
487 u32 data;
488
489 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
490 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
491 status &= mask;
492
493 if (!status) {
494 dev_warn(&device->pdev->dev, "Spurious interrupt");
495 return IRQ_NONE;
496 }
497
498 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
499
500 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
501 /* read the key error info */
502 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
503 dev_info(&device->pdev->dev, "key error 0x%x", data);
504 }
505 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
506 data = readl_relaxed(device->base + TSPP_KEY_VALID);
507 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
508 }
509 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
510 dev_info(&device->pdev->dev, "key switched");
511
512 if (status & 0xffff)
Joel Nider5bd73f82011-12-14 16:53:30 +0200513 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200514
515 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200516
517 /*
518 * Before returning IRQ_HANDLED to the generic interrupt handling
519 * framework need to make sure all operations including clearing of
520 * interrupt status registers in the hardware is performed.
521 * Thus a barrier after clearing the interrupt status register
522 * is required to guarantee that the interrupt status register has
523 * really been cleared by the time we return from this handler.
524 */
525 wmb();
526 return IRQ_HANDLED;
527}
528
529static irqreturn_t tsif_isr(int irq, void *dev)
530{
531 struct tspp_tsif_device *tsif_device = dev;
532 u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
533
534 if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
535 TSIF_STS_CTL_OVERFLOW |
536 TSIF_STS_CTL_LOST_SYNC |
537 TSIF_STS_CTL_TIMEOUT)))
538 return IRQ_NONE;
539
540 if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
541 tsif_device->stat_overflow++;
542
543 if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
544 tsif_device->stat_lost_sync++;
545
546 if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
547 tsif_device->stat_timeout++;
548
549 iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
550
551 /*
552 * Before returning IRQ_HANDLED to the generic interrupt handling
553 * framework need to make sure all operations including clearing of
554 * interrupt status registers in the hardware is performed.
555 * Thus a barrier after clearing the interrupt status register
556 * is required to guarantee that the interrupt status register has
557 * really been cleared by the time we return from this handler.
558 */
Joel Nider5556a852011-10-16 10:52:13 +0200559 wmb();
560 return IRQ_HANDLED;
561}
562
563/*** callbacks ***/
564static void tspp_sps_complete_cb(struct sps_event_notify *notify)
565{
Joel Nider5bd73f82011-12-14 16:53:30 +0200566 struct tspp_device *pdev = notify->user;
567 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200568}
569
Hamad Kadmany567bed82012-11-29 14:15:57 +0200570static void tspp_expiration_timer(unsigned long data)
571{
572 struct tspp_device *pdev = (struct tspp_device *)data;
573
574 if (pdev)
575 tasklet_schedule(&pdev->tlet);
576}
577
Joel Nider5556a852011-10-16 10:52:13 +0200578/*** tasklet ***/
579static void tspp_sps_complete_tlet(unsigned long data)
580{
581 int i;
582 int complete;
583 unsigned long flags;
584 struct sps_iovec iovec;
585 struct tspp_channel *channel;
586 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200587 spin_lock_irqsave(&device->spinlock, flags);
588
589 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
590 complete = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +0200591 channel = &device->channels[i];
Hamad Kadmany567bed82012-11-29 14:15:57 +0200592
Joel Nider5bd73f82011-12-14 16:53:30 +0200593 if (!channel->used || !channel->waiting)
594 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200595
Hamad Kadmany567bed82012-11-29 14:15:57 +0200596 /* stop the expiration timer */
597 if (channel->expiration_period_ms)
598 del_timer(&channel->expiration_timer);
599
Joel Nider5556a852011-10-16 10:52:13 +0200600 /* get completions */
Joel Nider5bd73f82011-12-14 16:53:30 +0200601 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200602 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
603 pr_err("tspp: Error in iovec on channel %i",
604 channel->id);
605 break;
606 }
607 if (iovec.size == 0)
608 break;
609
Joel Nider5bd73f82011-12-14 16:53:30 +0200610 if (iovec.addr != channel->waiting->sps.phys_base)
Joel Nider5556a852011-10-16 10:52:13 +0200611 pr_err("tspp: buffer mismatch 0x%08x",
Joel Nider5bd73f82011-12-14 16:53:30 +0200612 channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200613
614 complete = 1;
Joel Nider5bd73f82011-12-14 16:53:30 +0200615 channel->waiting->state = TSPP_BUF_STATE_DATA;
616 channel->waiting->filled = iovec.size;
617 channel->waiting->read_index = 0;
618
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200619 if (channel->src == TSPP_SOURCE_TSIF0)
620 device->tsif[0].stat_rx++;
621 else if (channel->src == TSPP_SOURCE_TSIF1)
622 device->tsif[1].stat_rx++;
623
Joel Nider5bd73f82011-12-14 16:53:30 +0200624 /* update the pointers */
625 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200626 }
627
Joel Nider5bd73f82011-12-14 16:53:30 +0200628 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200629 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200630 wake_up_interruptible(&channel->in_queue);
Joel Nider5bd73f82011-12-14 16:53:30 +0200631
632 /* call notifiers */
633 if (channel->notifier)
634 channel->notifier(channel->id,
635 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200636 }
Hamad Kadmany567bed82012-11-29 14:15:57 +0200637
638 /* restart expiration timer */
639 if (channel->expiration_period_ms)
640 mod_timer(&channel->expiration_timer,
641 jiffies +
642 MSEC_TO_JIFFIES(
643 channel->expiration_period_ms));
Joel Nider5556a852011-10-16 10:52:13 +0200644 }
645
646 spin_unlock_irqrestore(&device->spinlock, flags);
647}
648
649/*** GPIO functions ***/
650static void tspp_gpios_free(const struct msm_gpio *table, int size)
651{
652 int i;
653 const struct msm_gpio *g;
654 for (i = size-1; i >= 0; i--) {
655 g = table + i;
656 gpio_free(GPIO_PIN(g->gpio_cfg));
657 }
658}
659
660static int tspp_gpios_request(const struct msm_gpio *table, int size)
661{
662 int rc;
663 int i;
664 const struct msm_gpio *g;
665 for (i = 0; i < size; i++) {
666 g = table + i;
667 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
668 if (rc) {
669 pr_err("tspp: gpio_request(%d) <%s> failed: %d\n",
670 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
671 goto err;
672 }
673 }
674 return 0;
675err:
676 tspp_gpios_free(table, i);
677 return rc;
678}
679
680static int tspp_gpios_disable(const struct msm_gpio *table, int size)
681{
682 int rc = 0;
683 int i;
684 const struct msm_gpio *g;
685 for (i = size-1; i >= 0; i--) {
686 int tmp;
687 g = table + i;
688 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
689 if (tmp) {
Liron Kuch229090d2012-10-30 17:47:50 +0200690 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200691 g->gpio_cfg, g->label ?: "?", rc);
692 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
693 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
694 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
695 GPIO_DRVSTR(g->gpio_cfg));
696 if (!rc)
697 rc = tmp;
698 }
699 }
700
701 return rc;
702}
703
704static int tspp_gpios_enable(const struct msm_gpio *table, int size)
705{
706 int rc;
707 int i;
708 const struct msm_gpio *g;
709 for (i = 0; i < size; i++) {
710 g = table + i;
711 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
712 if (rc) {
Liron Kuch229090d2012-10-30 17:47:50 +0200713 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200714 g->gpio_cfg, g->label ?: "?", rc);
715 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
716 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
717 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
718 GPIO_DRVSTR(g->gpio_cfg));
719 goto err;
720 }
721 }
722 return 0;
723err:
724 tspp_gpios_disable(table, i);
725 return rc;
726}
727
728static int tspp_gpios_request_enable(const struct msm_gpio *table, int size)
729{
730 int rc = tspp_gpios_request(table, size);
731 if (rc)
732 return rc;
733 rc = tspp_gpios_enable(table, size);
734 if (rc)
735 tspp_gpios_free(table, size);
736 return rc;
737}
738
739static void tspp_gpios_disable_free(const struct msm_gpio *table, int size)
740{
741 tspp_gpios_disable(table, size);
742 tspp_gpios_free(table, size);
743}
744
745static int tspp_start_gpios(struct tspp_device *device)
746{
747 struct msm_tspp_platform_data *pdata =
748 device->pdev->dev.platform_data;
749 return tspp_gpios_request_enable(pdata->gpios, pdata->num_gpios);
750}
751
752static void tspp_stop_gpios(struct tspp_device *device)
753{
754 struct msm_tspp_platform_data *pdata =
755 device->pdev->dev.platform_data;
756 tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios);
757}
758
Joel Nider5bd73f82011-12-14 16:53:30 +0200759/*** Clock functions ***/
760static int tspp_clock_start(struct tspp_device *device)
761{
762 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
763 pr_err("tspp: Can't start pclk");
764 return -EBUSY;
765 }
766
767 if (device->tsif_ref_clk &&
768 clk_prepare_enable(device->tsif_ref_clk) != 0) {
769 pr_err("tspp: Can't start ref clk");
770 clk_disable_unprepare(device->tsif_pclk);
771 return -EBUSY;
772 }
773
774 return 0;
775}
776
777static void tspp_clock_stop(struct tspp_device *device)
778{
779 if (device->tsif_pclk)
780 clk_disable(device->tsif_pclk);
781
782 if (device->tsif_ref_clk)
783 clk_disable(device->tsif_ref_clk);
784}
785
Joel Nider5556a852011-10-16 10:52:13 +0200786/*** TSIF functions ***/
787static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
788{
789 int start_hardware = 0;
790 u32 ctl;
791
792 if (tsif_device->ref_count == 0) {
793 start_hardware = 1;
794 } else if (tsif_device->ref_count > 0) {
795 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
796 if ((ctl & TSIF_STS_CTL_START) != 1) {
797 /* this hardware should already be running */
798 pr_warn("tspp: tsif hw not started but ref count > 0");
799 start_hardware = 1;
800 }
801 }
802
803 if (start_hardware) {
Joel Nider5bd73f82011-12-14 16:53:30 +0200804 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200805 TSIF_STS_CTL_EN_DM;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200806
807 if (tsif_device->clock_inverse)
808 ctl |= TSIF_STS_CTL_INV_CLOCK;
809
810 if (tsif_device->data_inverse)
811 ctl |= TSIF_STS_CTL_INV_DATA;
812
813 if (tsif_device->sync_inverse)
814 ctl |= TSIF_STS_CTL_INV_SYNC;
815
816 if (tsif_device->enable_inverse)
817 ctl |= TSIF_STS_CTL_INV_ENABLE;
818
Joel Nider5bd73f82011-12-14 16:53:30 +0200819 switch (tsif_device->mode) {
820 case TSPP_TSIF_MODE_LOOPBACK:
821 ctl |= TSIF_STS_CTL_EN_NULL |
822 TSIF_STS_CTL_EN_ERROR |
823 TSIF_STS_CTL_TEST_MODE;
824 break;
825 case TSPP_TSIF_MODE_1:
826 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
827 TSIF_STS_CTL_EN_TCR;
828 break;
829 case TSPP_TSIF_MODE_2:
830 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
831 TSIF_STS_CTL_EN_TCR |
832 TSIF_STS_CTL_MODE_2;
833 break;
834 default:
835 pr_warn("tspp: unknown tsif mode 0x%x",
836 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200837 }
838 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
839 writel_relaxed(tsif_device->time_limit,
840 tsif_device->base + TSIF_TIME_LIMIT_OFF);
841 wmb();
842 writel_relaxed(ctl | TSIF_STS_CTL_START,
843 tsif_device->base + TSIF_STS_CTL_OFF);
844 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200845 }
846
Joel Nider5bd73f82011-12-14 16:53:30 +0200847 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Joel Nider5556a852011-10-16 10:52:13 +0200848 tsif_device->ref_count++;
849
Joel Nider5bd73f82011-12-14 16:53:30 +0200850 return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200851}
852
853static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
854{
855 if (tsif_device->ref_count == 0)
856 return;
857
858 tsif_device->ref_count--;
859
860 if (tsif_device->ref_count == 0) {
861 writel_relaxed(TSIF_STS_CTL_STOP,
862 tsif_device->base + TSIF_STS_CTL_OFF);
863 wmb();
864 }
865}
866
Joel Nider5bd73f82011-12-14 16:53:30 +0200867/*** local TSPP functions ***/
868static int tspp_channels_in_use(struct tspp_device *pdev)
869{
870 int i;
871 int count = 0;
872 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
873 count += (pdev->channels[i].used ? 1 : 0);
874
875 return count;
876}
877
878static struct tspp_device *tspp_find_by_id(int id)
879{
880 struct tspp_device *dev;
881 list_for_each_entry(dev, &tspp_devices, devlist) {
882 if (dev->pdev->id == id)
883 return dev;
884 }
885 return NULL;
886}
887
Joel Nider5556a852011-10-16 10:52:13 +0200888static int tspp_get_key_entry(void)
889{
890 int i;
891 for (i = 0; i < TSPP_NUM_KEYS; i++) {
892 if (!(tspp_key_entry & (1 << i))) {
893 tspp_key_entry |= (1 << i);
894 return i;
895 }
896 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200897 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200898}
899
900static void tspp_free_key_entry(int entry)
901{
902 if (entry > TSPP_NUM_KEYS) {
903 pr_err("tspp_free_key_entry: index out of bounds");
904 return;
905 }
906
907 tspp_key_entry &= ~(1 << entry);
908}
909
Joel Nider5bd73f82011-12-14 16:53:30 +0200910static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200911 u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200912{
Joel Nider5bd73f82011-12-14 16:53:30 +0200913 if (size < TSPP_MIN_BUFFER_SIZE ||
914 size > TSPP_MAX_BUFFER_SIZE) {
915 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200916 return -ENOMEM;
917 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200918
919 if (alloc) {
920 TSPP_DEBUG("tspp using alloc function");
921 desc->virt_base = alloc(channel_id, size,
922 &desc->phys_base, user);
923 } else {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200924 if (!dma_pool)
925 desc->virt_base = dma_alloc_coherent(NULL, size,
926 &desc->phys_base, GFP_KERNEL);
927 else
928 desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL,
929 &desc->phys_base);
930
Liron Kuch229090d2012-10-30 17:47:50 +0200931 if (desc->virt_base == 0) {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200932 pr_err("tspp: dma buffer allocation failed %i\n", size);
Liron Kuch229090d2012-10-30 17:47:50 +0200933 return -ENOMEM;
934 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200935 }
936
937 desc->size = size;
938 return 0;
939}
940
941static int tspp_queue_buffer(struct tspp_channel *channel,
942 struct tspp_mem_buffer *buffer)
943{
944 int rc;
945 u32 flags = 0;
946
947 /* make sure the interrupt frequency is valid */
948 if (channel->int_freq < 1)
949 channel->int_freq = 1;
950
951 /* generate interrupt according to requested frequency */
952 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
Hamad Kadmany567bed82012-11-29 14:15:57 +0200953 flags = SPS_IOVEC_FLAG_INT;
Joel Nider5bd73f82011-12-14 16:53:30 +0200954
955 /* start the transfer */
956 rc = sps_transfer_one(channel->pipe,
957 buffer->sps.phys_base,
958 buffer->sps.size,
959 channel->pdev,
960 flags);
961 if (rc < 0)
962 return rc;
963
964 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +0200965
966 return 0;
967}
968
969static int tspp_global_reset(struct tspp_device *pdev)
970{
971 u32 i, val;
972
973 /* stop all TSIFs */
974 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
975 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
976 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
977 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200978 pdev->tsif[i].clock_inverse = 0;
979 pdev->tsif[i].data_inverse = 0;
980 pdev->tsif[i].sync_inverse = 0;
981 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +0200982 }
983 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
984 wmb();
985
986 /* BAM */
987 if (sps_device_reset(pdev->bam_handle) != 0) {
988 pr_err("tspp: error resetting bam");
Joel Nider5bd73f82011-12-14 16:53:30 +0200989 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200990 }
991
992 /* TSPP tables */
993 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider5bd73f82011-12-14 16:53:30 +0200994 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +0200995 0, sizeof(struct tspp_pid_filter_table));
996
997 /* disable all filters */
998 val = (2 << TSPP_NUM_CHANNELS) - 1;
999 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
1000
1001 /* TSPP registers */
1002 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1003 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1004 pdev->base + TSPP_CONTROL);
1005 wmb();
Joel Nider5bd73f82011-12-14 16:53:30 +02001006 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001007 sizeof(struct tspp_global_performance_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +02001008 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001009 sizeof(struct tspp_pipe_context_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +02001010 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001011 sizeof(struct tspp_pipe_performance_regs));
1012 wmb();
1013 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1014 pdev->base + TSPP_CONTROL);
1015 wmb();
1016
1017 val = readl_relaxed(pdev->base + TSPP_CONFIG);
1018 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
1019 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
1020 TSPP_CONFIG_PS_CONT_ERR_MASK);
1021 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
1022 writel_relaxed(val, pdev->base + TSPP_CONFIG);
Hamad Kadmany57f5ac82012-12-20 18:30:40 +02001023 writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK);
Joel Nider5556a852011-10-16 10:52:13 +02001024 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
1025 writel_relaxed(0, pdev->base + TSPP_RST);
1026 wmb();
1027
1028 tspp_key_entry = 0;
1029
1030 return 0;
1031}
1032
Joel Nider5bd73f82011-12-14 16:53:30 +02001033static int tspp_select_source(u32 dev, u32 channel_id,
1034 struct tspp_select_source *src)
1035{
1036 /* make sure the requested src id is in bounds */
1037 if (src->source > TSPP_SOURCE_MEM) {
1038 pr_err("tspp source out of bounds");
1039 return -EINVAL;
1040 }
1041
1042 /* open the stream */
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001043 tspp_open_stream(dev, channel_id, src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001044
1045 return 0;
1046}
1047
1048static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
1049{
1050 struct tspp_device *pdev = channel->pdev;
1051
1052 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
1053 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
1054 return 0;
1055}
1056
1057static int tspp_set_system_keys(struct tspp_channel *channel,
1058 struct tspp_system_keys *keys)
1059{
1060 int i;
1061 struct tspp_device *pdev = channel->pdev;
1062
1063 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
1064 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
1065
1066 return 0;
1067}
1068
1069static int tspp_channel_init(struct tspp_channel *channel,
1070 struct tspp_device *pdev)
1071{
1072 channel->cdev.owner = THIS_MODULE;
1073 cdev_init(&channel->cdev, &tspp_fops);
1074 channel->pdev = pdev;
1075 channel->data = NULL;
1076 channel->read = NULL;
1077 channel->waiting = NULL;
1078 channel->locked = NULL;
1079 channel->id = MINOR(tspp_minor);
1080 channel->used = 0;
1081 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1082 channel->max_buffers = TSPP_NUM_BUFFERS;
1083 channel->buffer_count = 0;
1084 channel->filter_count = 0;
1085 channel->int_freq = 1;
Liron Kuch229090d2012-10-30 17:47:50 +02001086 channel->src = TSPP_SOURCE_NONE;
1087 channel->mode = TSPP_MODE_DISABLED;
Joel Nider5bd73f82011-12-14 16:53:30 +02001088 channel->notifier = NULL;
1089 channel->notify_data = NULL;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001090 channel->expiration_period_ms = 0;
Liron Kuch229090d2012-10-30 17:47:50 +02001091 channel->memfree = NULL;
1092 channel->user_info = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001093 init_waitqueue_head(&channel->in_queue);
1094
1095 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
1096 pr_err("tspp: cdev_add failed");
1097 return -EBUSY;
1098 }
1099
1100 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
1101 channel, "tspp%02d", channel->id);
1102 if (IS_ERR(channel->dd)) {
1103 pr_err("tspp: device_create failed: %i",
1104 (int)PTR_ERR(channel->dd));
1105 cdev_del(&channel->cdev);
1106 return -EBUSY;
1107 }
1108
1109 return 0;
1110}
1111
1112static int tspp_set_buffer_size(struct tspp_channel *channel,
1113 struct tspp_buffer *buf)
1114{
Liron Kuch229090d2012-10-30 17:47:50 +02001115 if (channel->buffer_count > 0) {
1116 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1117 return -EPERM;
1118 }
1119
Joel Nider5bd73f82011-12-14 16:53:30 +02001120 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1121 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1122 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1123 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1124 else
1125 channel->buffer_size = buf->size;
1126
1127 return 0;
1128}
1129
1130static void tspp_set_tsif_mode(struct tspp_channel *channel,
1131 enum tspp_tsif_mode mode)
1132{
1133 int index;
1134
1135 switch (channel->src) {
1136 case TSPP_SOURCE_TSIF0:
1137 index = 0;
1138 break;
1139 case TSPP_SOURCE_TSIF1:
1140 index = 1;
1141 break;
1142 default:
1143 pr_warn("tspp: can't set mode for non-tsif source %d",
1144 channel->src);
1145 return;
1146 }
1147 channel->pdev->tsif[index].mode = mode;
1148}
1149
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001150static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch229090d2012-10-30 17:47:50 +02001151 int clock_inverse, int data_inverse,
1152 int sync_inverse, int enable_inverse)
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001153{
1154 int index;
1155
1156 switch (channel->src) {
1157 case TSPP_SOURCE_TSIF0:
1158 index = 0;
1159 break;
1160 case TSPP_SOURCE_TSIF1:
1161 index = 1;
1162 break;
1163 default:
1164 return;
1165 }
1166 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1167 channel->pdev->tsif[index].data_inverse = data_inverse;
1168 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1169 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1170}
1171
Liron Kuch229090d2012-10-30 17:47:50 +02001172static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1173{
1174 u32 alignment;
1175
1176 switch (mode) {
1177 case TSPP_MODE_RAW:
1178 /* must be a multiple of 192 */
1179 alignment = (TSPP_PACKET_LENGTH + 4);
1180 if (size % alignment)
1181 return 0;
1182 return 1;
1183
1184 case TSPP_MODE_RAW_NO_SUFFIX:
1185 /* must be a multiple of 188 */
1186 alignment = TSPP_PACKET_LENGTH;
1187 if (size % alignment)
1188 return 0;
1189 return 1;
1190
1191 case TSPP_MODE_DISABLED:
1192 case TSPP_MODE_PES:
1193 default:
1194 /* no alignment requirement */
1195 return 1;
1196 }
1197
1198}
1199
1200static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1201{
1202 u32 new_size;
1203 u32 alignment;
1204
1205 switch (mode) {
1206 case TSPP_MODE_RAW:
1207 /* must be a multiple of 192 */
1208 alignment = (TSPP_PACKET_LENGTH + 4);
1209 break;
1210
1211 case TSPP_MODE_RAW_NO_SUFFIX:
1212 /* must be a multiple of 188 */
1213 alignment = TSPP_PACKET_LENGTH;
1214 break;
1215
1216 case TSPP_MODE_DISABLED:
1217 case TSPP_MODE_PES:
1218 default:
1219 /* no alignment requirement - give the user what he asks for */
1220 alignment = 1;
1221 break;
1222 }
1223 /* align up */
1224 new_size = (((size + alignment - 1) / alignment) * alignment);
1225 return new_size;
1226}
1227
1228static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1229{
1230 int i;
1231 struct tspp_mem_buffer *pbuf, *temp;
1232
1233 pbuf = channel->data;
1234 for (i = 0; i < channel->buffer_count; i++) {
1235 if (pbuf->desc.phys_base) {
1236 if (channel->memfree) {
1237 channel->memfree(channel_id,
1238 pbuf->desc.size,
1239 pbuf->desc.virt_base,
1240 pbuf->desc.phys_base,
1241 channel->user_info);
1242 } else {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001243 if (!channel->dma_pool)
1244 dma_free_coherent(NULL,
1245 pbuf->desc.size,
1246 pbuf->desc.virt_base,
1247 pbuf->desc.phys_base);
1248 else
1249 dma_pool_free(channel->dma_pool,
1250 pbuf->desc.virt_base,
1251 pbuf->desc.phys_base);
Liron Kuch229090d2012-10-30 17:47:50 +02001252 }
1253 pbuf->desc.phys_base = 0;
1254 }
1255 pbuf->desc.virt_base = 0;
1256 pbuf->state = TSPP_BUF_STATE_EMPTY;
1257 temp = pbuf;
1258 pbuf = pbuf->next;
1259 kfree(temp);
1260 }
1261}
1262
Joel Nider5bd73f82011-12-14 16:53:30 +02001263/*** TSPP API functions ***/
Liron Kuch229090d2012-10-30 17:47:50 +02001264
1265/**
1266 * tspp_open_stream - open a TSPP stream for use.
1267 *
1268 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1269 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1270 * @source: stream source parameters.
1271 *
1272 * Return error status
1273 *
1274 */
1275int tspp_open_stream(u32 dev, u32 channel_id,
1276 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001277{
1278 u32 val;
1279 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001280 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001281
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001282 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1283 dev, channel_id, source->source, source->mode);
Liron Kuch229090d2012-10-30 17:47:50 +02001284
Joel Nider5bd73f82011-12-14 16:53:30 +02001285 if (dev >= TSPP_MAX_DEVICES) {
1286 pr_err("tspp: device id out of range");
1287 return -ENODEV;
1288 }
Joel Nider5556a852011-10-16 10:52:13 +02001289
Joel Nider5bd73f82011-12-14 16:53:30 +02001290 if (channel_id >= TSPP_NUM_CHANNELS) {
1291 pr_err("tspp: channel id out of range");
1292 return -ECHRNG;
1293 }
1294
1295 pdev = tspp_find_by_id(dev);
1296 if (!pdev) {
1297 pr_err("tspp_str: can't find device %i", dev);
1298 return -ENODEV;
1299 }
1300 channel = &pdev->channels[channel_id];
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001301 channel->src = source->source;
1302 tspp_set_tsif_mode(channel, source->mode);
1303 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch229090d2012-10-30 17:47:50 +02001304 source->data_inverse, source->sync_inverse,
1305 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001306
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001307 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001308 case TSPP_SOURCE_TSIF0:
1309 /* make sure TSIF0 is running & enabled */
1310 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
1311 pr_err("tspp: error starting tsif0");
Joel Nider5bd73f82011-12-14 16:53:30 +02001312 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001313 }
1314 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1315 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1316 pdev->base + TSPP_CONTROL);
1317 wmb();
1318 break;
1319 case TSPP_SOURCE_TSIF1:
1320 /* make sure TSIF1 is running & enabled */
1321 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
1322 pr_err("tspp: error starting tsif1");
Joel Nider5bd73f82011-12-14 16:53:30 +02001323 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001324 }
1325 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1326 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1327 pdev->base + TSPP_CONTROL);
1328 wmb();
1329 break;
1330 case TSPP_SOURCE_MEM:
1331 break;
1332 default:
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001333 pr_err("tspp: channel %i invalid source %i",
1334 channel->id, source->source);
Joel Nider5bd73f82011-12-14 16:53:30 +02001335 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001336 }
1337
Joel Nider5556a852011-10-16 10:52:13 +02001338 return 0;
1339}
1340EXPORT_SYMBOL(tspp_open_stream);
1341
Liron Kuch229090d2012-10-30 17:47:50 +02001342/**
1343 * tspp_close_stream - close a TSPP stream.
1344 *
1345 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1346 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1347 *
1348 * Return error status
1349 *
1350 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001351int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001352{
1353 u32 val;
1354 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001355 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001356
Joel Nider5bd73f82011-12-14 16:53:30 +02001357 if (channel_id >= TSPP_NUM_CHANNELS) {
1358 pr_err("tspp: channel id out of range");
1359 return -ECHRNG;
1360 }
1361 pdev = tspp_find_by_id(dev);
1362 if (!pdev) {
1363 pr_err("tspp_cs: can't find device %i", dev);
1364 return -EBUSY;
1365 }
1366 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001367
1368 switch (channel->src) {
1369 case TSPP_SOURCE_TSIF0:
1370 tspp_stop_tsif(&pdev->tsif[0]);
1371 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1372 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1373 pdev->base + TSPP_CONTROL);
1374 wmb();
1375 break;
1376 case TSPP_SOURCE_TSIF1:
1377 tspp_stop_tsif(&pdev->tsif[1]);
1378 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1379 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1380 pdev->base + TSPP_CONTROL);
1381 break;
1382 case TSPP_SOURCE_MEM:
1383 break;
1384 case TSPP_SOURCE_NONE:
1385 break;
1386 }
1387
Joel Nider5bd73f82011-12-14 16:53:30 +02001388 channel->src = TSPP_SOURCE_NONE;
Joel Nider5556a852011-10-16 10:52:13 +02001389 return 0;
1390}
1391EXPORT_SYMBOL(tspp_close_stream);
1392
Liron Kuch229090d2012-10-30 17:47:50 +02001393/**
1394 * tspp_open_channel - open a TSPP channel.
1395 *
1396 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1397 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1398 *
1399 * Return error status
1400 *
1401 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001402int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001403{
1404 int rc = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001405 struct sps_connect *config;
1406 struct sps_register_event *event;
1407 struct tspp_channel *channel;
1408 struct tspp_device *pdev;
1409
1410 if (channel_id >= TSPP_NUM_CHANNELS) {
1411 pr_err("tspp: channel id out of range");
1412 return -ECHRNG;
1413 }
1414 pdev = tspp_find_by_id(dev);
1415 if (!pdev) {
1416 pr_err("tspp_oc: can't find device %i", dev);
1417 return -ENODEV;
1418 }
1419 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001420
1421 if (channel->used) {
1422 pr_err("tspp channel already in use");
Joel Nider5bd73f82011-12-14 16:53:30 +02001423 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001424 }
1425
Joel Nider5bd73f82011-12-14 16:53:30 +02001426 config = &channel->config;
1427 event = &channel->event;
1428
1429 /* start the clocks if needed */
1430 tspp_clock_start(pdev);
1431 if (tspp_channels_in_use(pdev) == 0)
1432 wake_lock(&pdev->wake_lock);
1433
Joel Nider5556a852011-10-16 10:52:13 +02001434 /* mark it as used */
1435 channel->used = 1;
1436
1437 /* start the bam */
1438 channel->pipe = sps_alloc_endpoint();
1439 if (channel->pipe == 0) {
1440 pr_err("tspp: error allocating endpoint");
1441 rc = -ENOMEM;
1442 goto err_sps_alloc;
1443 }
1444
1445 /* get default configuration */
1446 sps_get_config(channel->pipe, config);
1447
Joel Nider5bd73f82011-12-14 16:53:30 +02001448 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001449 config->destination = SPS_DEV_HANDLE_MEM;
1450 config->mode = SPS_MODE_SRC;
Joel Nider5bd73f82011-12-14 16:53:30 +02001451 config->options =
1452 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1453 SPS_O_STREAMING | /* streaming mode */
1454 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
Hamad Kadmany567bed82012-11-29 14:15:57 +02001455 SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
1456 SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001457 config->src_pipe_index = channel->id;
1458 config->desc.size =
Hamad Kadmany567bed82012-11-29 14:15:57 +02001459 TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
Joel Nider5556a852011-10-16 10:52:13 +02001460 config->desc.base = dma_alloc_coherent(NULL,
1461 config->desc.size,
1462 &config->desc.phys_base,
1463 GFP_KERNEL);
1464 if (config->desc.base == 0) {
1465 pr_err("tspp: error allocating sps descriptors");
1466 rc = -ENOMEM;
1467 goto err_desc_alloc;
1468 }
1469
1470 memset(config->desc.base, 0, config->desc.size);
1471
1472 rc = sps_connect(channel->pipe, config);
1473 if (rc) {
1474 pr_err("tspp: error connecting bam");
1475 goto err_connect;
1476 }
1477
1478 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider5bd73f82011-12-14 16:53:30 +02001479 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001480 event->callback = tspp_sps_complete_cb;
1481 event->xfer_done = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001482 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001483
1484 rc = sps_register_event(channel->pipe, event);
1485 if (rc) {
1486 pr_err("tspp: error registering event");
1487 goto err_event;
1488 }
1489
Hamad Kadmany567bed82012-11-29 14:15:57 +02001490 init_timer(&channel->expiration_timer);
1491 channel->expiration_timer.function = tspp_expiration_timer;
1492 channel->expiration_timer.data = (unsigned long)pdev;
1493 channel->expiration_timer.expires = 0xffffffffL;
1494
Joel Nider5bd73f82011-12-14 16:53:30 +02001495 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001496 if (rc < 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001497 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001498 "Runtime PM: Unable to wake up tspp device, rc = %d",
1499 rc);
1500 }
Joel Nider5556a852011-10-16 10:52:13 +02001501 return 0;
1502
1503err_event:
1504 sps_disconnect(channel->pipe);
1505err_connect:
1506 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1507 config->desc.phys_base);
1508err_desc_alloc:
1509 sps_free_endpoint(channel->pipe);
1510err_sps_alloc:
1511 return rc;
1512}
1513EXPORT_SYMBOL(tspp_open_channel);
1514
Liron Kuch229090d2012-10-30 17:47:50 +02001515/**
1516 * tspp_close_channel - close a TSPP channel.
1517 *
1518 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1519 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1520 *
1521 * Return error status
1522 *
1523 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001524int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001525{
1526 int i;
1527 int id;
1528 u32 val;
Joel Nider5556a852011-10-16 10:52:13 +02001529
Joel Nider5bd73f82011-12-14 16:53:30 +02001530 struct sps_connect *config;
1531 struct tspp_device *pdev;
1532 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02001533
1534 if (channel_id >= TSPP_NUM_CHANNELS) {
1535 pr_err("tspp: channel id out of range");
1536 return -ECHRNG;
1537 }
1538 pdev = tspp_find_by_id(dev);
1539 if (!pdev) {
1540 pr_err("tspp_close: can't find device %i", dev);
1541 return -ENODEV;
1542 }
1543 channel = &pdev->channels[channel_id];
1544
1545 /* if the channel is not used, we are done */
1546 if (!channel->used)
1547 return 0;
1548
Hamad Kadmany567bed82012-11-29 14:15:57 +02001549 if (channel->expiration_period_ms)
1550 del_timer(&channel->expiration_timer);
1551
Joel Nider5bd73f82011-12-14 16:53:30 +02001552 channel->notifier = NULL;
1553 channel->notify_data = NULL;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001554 channel->expiration_period_ms = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001555
1556 config = &channel->config;
1557 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001558
1559 /* disable pipe (channel) */
1560 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1561 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1562 wmb();
1563
1564 /* unregister all filters for this channel */
1565 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1566 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001567 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001568 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1569 if (id == channel->id) {
1570 if (FILTER_HAS_ENCRYPTION(tspp_filter))
1571 tspp_free_key_entry(
1572 FILTER_GET_KEY_NUMBER(tspp_filter));
1573 tspp_filter->config = 0;
1574 tspp_filter->filter = 0;
1575 }
1576 }
1577 channel->filter_count = 0;
1578
1579 /* stop the stream */
Joel Nider5bd73f82011-12-14 16:53:30 +02001580 tspp_close_stream(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02001581
1582 /* disconnect the bam */
1583 if (sps_disconnect(channel->pipe) != 0)
1584 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1585
1586 /* destroy the buffers */
1587 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1588 config->desc.phys_base);
1589
Liron Kuch229090d2012-10-30 17:47:50 +02001590 tspp_destroy_buffers(channel_id, channel);
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001591 if (channel->dma_pool) {
1592 dma_pool_destroy(channel->dma_pool);
1593 channel->dma_pool = NULL;
1594 }
Liron Kuch229090d2012-10-30 17:47:50 +02001595
1596 channel->src = TSPP_SOURCE_NONE;
1597 channel->mode = TSPP_MODE_DISABLED;
1598 channel->memfree = NULL;
1599 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001600 channel->buffer_count = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001601 channel->data = NULL;
1602 channel->read = NULL;
1603 channel->waiting = NULL;
1604 channel->locked = NULL;
1605 channel->used = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001606
Joel Nider5bd73f82011-12-14 16:53:30 +02001607 if (tspp_channels_in_use(pdev) == 0)
1608 wake_unlock(&pdev->wake_lock);
1609 tspp_clock_stop(pdev);
1610
Joel Nider5556a852011-10-16 10:52:13 +02001611 return 0;
1612}
1613EXPORT_SYMBOL(tspp_close_channel);
1614
Liron Kuch229090d2012-10-30 17:47:50 +02001615/**
1616 * tspp_add_filter - add a TSPP filter to a channel.
1617 *
1618 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1619 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1620 * @filter: TSPP filter parameters
1621 *
1622 * Return error status
1623 *
1624 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001625int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001626 struct tspp_filter *filter)
1627{
Liron Kuch229090d2012-10-30 17:47:50 +02001628 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001629 int other_channel;
1630 int entry;
1631 u32 val, pid, enabled;
Joel Nider5bd73f82011-12-14 16:53:30 +02001632 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001633 struct tspp_pid_filter p;
Joel Nider5bd73f82011-12-14 16:53:30 +02001634 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001635
Joel Nider5bd73f82011-12-14 16:53:30 +02001636 TSPP_DEBUG("tspp: add filter");
1637 if (channel_id >= TSPP_NUM_CHANNELS) {
1638 pr_err("tspp: channel id out of range");
1639 return -ECHRNG;
1640 }
1641 pdev = tspp_find_by_id(dev);
1642 if (!pdev) {
1643 pr_err("tspp_add: can't find device %i", dev);
1644 return -ENODEV;
1645 }
1646
1647 channel = &pdev->channels[channel_id];
1648
Joel Nider5556a852011-10-16 10:52:13 +02001649 if (filter->source > TSPP_SOURCE_MEM) {
1650 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001651 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001652 }
1653
1654 if (filter->priority >= TSPP_NUM_PRIORITIES) {
1655 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001656 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001657 }
1658
Liron Kuch229090d2012-10-30 17:47:50 +02001659 channel->mode = filter->mode;
1660 /*
1661 * if buffers are already allocated, verify they fulfil
1662 * the alignment requirements.
1663 */
1664 if ((channel->buffer_count > 0) &&
1665 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1666 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001667
1668 if (filter->mode == TSPP_MODE_PES) {
1669 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1670 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001671 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001672 pid = FILTER_GET_PIPE_PID((tspp_filter));
1673 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1674 if (enabled && (pid == filter->pid)) {
1675 other_channel =
1676 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1677 pr_err("tspp: pid 0x%x already in use by channel %i",
1678 filter->pid, other_channel);
Joel Nider5bd73f82011-12-14 16:53:30 +02001679 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001680 }
1681 }
1682 }
1683
1684 /* make sure this priority is not already in use */
1685 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider5bd73f82011-12-14 16:53:30 +02001686 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001687 if (enabled) {
1688 pr_err("tspp: filter priority %i source %i is already enabled\n",
1689 filter->priority, channel->src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001690 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001691 }
1692
1693 if (channel->mode == TSPP_MODE_PES) {
1694 /* if we are already processing in PES mode, disable pipe
1695 (channel) and filter to be updated */
1696 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1697 writel_relaxed(val | (1 << channel->id),
1698 pdev->base + TSPP_PS_DISABLE);
1699 wmb();
1700 }
1701
1702 /* update entry */
1703 p.filter = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001704 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001705 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1706 FILTER_SET_PIPE_PID((&p), filter->pid);
1707 FILTER_SET_PID_MASK((&p), filter->mask);
1708 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1709 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1710 if (filter->decrypt) {
1711 entry = tspp_get_key_entry();
1712 if (entry == -1) {
1713 pr_err("tspp: no more keys available!");
1714 } else {
1715 p.config |= FILTER_DECRYPT;
1716 FILTER_SET_KEY_NUMBER((&p), entry);
1717 }
1718 }
Joel Nider5556a852011-10-16 10:52:13 +02001719
Joel Nider5bd73f82011-12-14 16:53:30 +02001720 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001721 filter[filter->priority].config = p.config;
Joel Nider5bd73f82011-12-14 16:53:30 +02001722 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001723 filter[filter->priority].filter = p.filter;
1724
Liron Kuch229090d2012-10-30 17:47:50 +02001725 /*
1726 * allocate buffers if needed (i.e. if user did has not already called
1727 * tspp_allocate_buffers() explicitly).
1728 */
1729 if (channel->buffer_count == 0) {
1730 channel->buffer_size =
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001731 tspp_align_buffer_size_by_mode(channel->buffer_size,
Liron Kuch229090d2012-10-30 17:47:50 +02001732 channel->mode);
1733 rc = tspp_allocate_buffers(dev, channel->id,
1734 channel->max_buffers,
1735 channel->buffer_size,
1736 channel->int_freq, NULL, NULL, NULL);
1737 if (rc != 0) {
1738 pr_err("tspp: tspp_allocate_buffers failed\n");
1739 return rc;
1740 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001741 }
1742
Joel Nider5556a852011-10-16 10:52:13 +02001743 /* reenable pipe */
1744 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1745 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1746 wmb();
1747 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1748
Joel Nider5556a852011-10-16 10:52:13 +02001749 channel->filter_count++;
1750
1751 return 0;
1752}
1753EXPORT_SYMBOL(tspp_add_filter);
1754
Liron Kuch229090d2012-10-30 17:47:50 +02001755/**
1756 * tspp_remove_filter - remove a TSPP filter from a channel.
1757 *
1758 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1759 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1760 * @filter: TSPP filter parameters
1761 *
1762 * Return error status
1763 *
1764 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001765int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001766 struct tspp_filter *filter)
1767{
1768 int entry;
1769 u32 val;
Joel Nider5bd73f82011-12-14 16:53:30 +02001770 struct tspp_device *pdev;
1771 int src;
1772 struct tspp_pid_filter *tspp_filter;
1773 struct tspp_channel *channel;
1774
1775 if (channel_id >= TSPP_NUM_CHANNELS) {
1776 pr_err("tspp: channel id out of range");
1777 return -ECHRNG;
1778 }
1779 pdev = tspp_find_by_id(dev);
1780 if (!pdev) {
1781 pr_err("tspp_remove: can't find device %i", dev);
1782 return -ENODEV;
1783 }
1784 channel = &pdev->channels[channel_id];
1785
1786 src = channel->src;
1787 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02001788
1789 /* disable pipe (channel) */
1790 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1791 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1792 wmb();
1793
1794 /* update data keys */
1795 if (tspp_filter->config & FILTER_DECRYPT) {
1796 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
1797 tspp_free_key_entry(entry);
1798 }
1799
1800 /* update pid table */
1801 tspp_filter->config = 0;
1802 tspp_filter->filter = 0;
1803
1804 channel->filter_count--;
1805
1806 /* reenable pipe */
1807 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1808 writel_relaxed(val & ~(1 << channel->id),
1809 pdev->base + TSPP_PS_DISABLE);
1810 wmb();
1811 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1812
1813 return 0;
1814}
1815EXPORT_SYMBOL(tspp_remove_filter);
1816
Liron Kuch229090d2012-10-30 17:47:50 +02001817/**
1818 * tspp_set_key - set TSPP key in key table.
1819 *
1820 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1821 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1822 * @key: TSPP key parameters
1823 *
1824 * Return error status
1825 *
1826 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001827int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02001828{
1829 int i;
1830 int id;
1831 int key_index;
1832 int data;
Joel Nider5bd73f82011-12-14 16:53:30 +02001833 struct tspp_channel *channel;
1834 struct tspp_device *pdev;
1835
1836 if (channel_id >= TSPP_NUM_CHANNELS) {
1837 pr_err("tspp: channel id out of range");
1838 return -ECHRNG;
1839 }
1840 pdev = tspp_find_by_id(dev);
1841 if (!pdev) {
1842 pr_err("tspp_set: can't find device %i", dev);
1843 return -ENODEV;
1844 }
1845 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001846
1847 /* read the key index used by this channel */
1848 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1849 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001850 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02001851 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1852 if (id == channel->id) {
1853 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
1854 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
1855 break;
1856 }
1857 }
1858 }
1859 if (i == TSPP_NUM_PRIORITIES) {
1860 pr_err("tspp: no encryption on this channel");
Joel Nider5bd73f82011-12-14 16:53:30 +02001861 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02001862 }
1863
1864 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001865 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
1866 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001867 } else {
Joel Nider5bd73f82011-12-14 16:53:30 +02001868 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
1869 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001870 }
1871 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
1872
1873 return 0;
1874}
1875EXPORT_SYMBOL(tspp_set_key);
1876
Liron Kuch229090d2012-10-30 17:47:50 +02001877/**
1878 * tspp_register_notification - register TSPP channel notification function.
1879 *
1880 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1881 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1882 * @pNotify: notification function
1883 * @userdata: user data to pass to notification function
1884 * @timer_ms: notification for partially filled buffers
1885 *
1886 * Return error status
1887 *
1888 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001889int tspp_register_notification(u32 dev, u32 channel_id,
1890 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02001891{
Joel Nider5bd73f82011-12-14 16:53:30 +02001892 struct tspp_channel *channel;
1893 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001894
Joel Nider5bd73f82011-12-14 16:53:30 +02001895 if (channel_id >= TSPP_NUM_CHANNELS) {
1896 pr_err("tspp: channel id out of range");
1897 return -ECHRNG;
1898 }
1899 pdev = tspp_find_by_id(dev);
1900 if (!pdev) {
1901 pr_err("tspp_reg: can't find device %i", dev);
1902 return -ENODEV;
1903 }
1904 channel = &pdev->channels[channel_id];
1905 channel->notifier = pNotify;
1906 channel->notify_data = userdata;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001907 channel->expiration_period_ms = timer_ms;
1908
Joel Nider5556a852011-10-16 10:52:13 +02001909 return 0;
1910}
Joel Nider5bd73f82011-12-14 16:53:30 +02001911EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001912
Liron Kuch229090d2012-10-30 17:47:50 +02001913/**
1914 * tspp_unregister_notification - unregister TSPP channel notification function.
1915 *
1916 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1917 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1918 *
1919 * Return error status
1920 *
1921 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001922int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001923{
Joel Nider5bd73f82011-12-14 16:53:30 +02001924 struct tspp_channel *channel;
1925 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001926
Joel Nider5bd73f82011-12-14 16:53:30 +02001927 if (channel_id >= TSPP_NUM_CHANNELS) {
1928 pr_err("tspp: channel id out of range");
1929 return -ECHRNG;
1930 }
1931 pdev = tspp_find_by_id(dev);
1932 if (!pdev) {
1933 pr_err("tspp_unreg: can't find device %i", dev);
1934 return -ENODEV;
1935 }
1936 channel = &pdev->channels[channel_id];
1937 channel->notifier = NULL;
1938 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001939 return 0;
1940}
Joel Nider5bd73f82011-12-14 16:53:30 +02001941EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001942
Liron Kuch229090d2012-10-30 17:47:50 +02001943/**
1944 * tspp_get_buffer - get TSPP data buffer.
1945 *
1946 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1947 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1948 *
1949 * Return error status
1950 *
1951 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001952const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001953{
Joel Nider5bd73f82011-12-14 16:53:30 +02001954 struct tspp_mem_buffer *buffer;
1955 struct tspp_channel *channel;
1956 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001957
Joel Nider5bd73f82011-12-14 16:53:30 +02001958 if (channel_id >= TSPP_NUM_CHANNELS) {
1959 pr_err("tspp: channel id out of range");
1960 return NULL;
1961 }
1962 pdev = tspp_find_by_id(dev);
1963 if (!pdev) {
1964 pr_err("tspp_get: can't find device %i", dev);
1965 return NULL;
1966 }
1967 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001968
Joel Nider5bd73f82011-12-14 16:53:30 +02001969 if (!channel->read) {
1970 pr_warn("tspp: no buffer to get on channel %i!",
1971 channel->id);
1972 return NULL;
1973 }
1974
1975 buffer = channel->read;
1976 /* see if we have any buffers ready to read */
1977 if (buffer->state != TSPP_BUF_STATE_DATA)
1978 return 0;
1979
1980 if (buffer->state == TSPP_BUF_STATE_DATA) {
1981 /* mark the buffer as busy */
1982 buffer->state = TSPP_BUF_STATE_LOCKED;
1983
1984 /* increment the pointer along the list */
1985 channel->read = channel->read->next;
1986 }
1987
1988 return &buffer->desc;
1989}
1990EXPORT_SYMBOL(tspp_get_buffer);
1991
Liron Kuch229090d2012-10-30 17:47:50 +02001992/**
1993 * tspp_release_buffer - release TSPP data buffer back to TSPP.
1994 *
1995 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1996 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1997 * @descriptor_id: buffer descriptor ID
1998 *
1999 * Return error status
2000 *
2001 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002002int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
2003{
2004 int i, found = 0;
2005 struct tspp_mem_buffer *buffer;
2006 struct tspp_channel *channel;
2007 struct tspp_device *pdev;
2008
2009 if (channel_id >= TSPP_NUM_CHANNELS) {
2010 pr_err("tspp: channel id out of range");
2011 return -ECHRNG;
2012 }
2013 pdev = tspp_find_by_id(dev);
2014 if (!pdev) {
2015 pr_err("tspp: can't find device %i", dev);
2016 return -ENODEV;
2017 }
2018 channel = &pdev->channels[channel_id];
2019
2020 if (descriptor_id > channel->buffer_count)
2021 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
2022
2023 /* find the correct descriptor */
2024 buffer = channel->locked;
2025 for (i = 0; i < channel->buffer_count; i++) {
2026 if (buffer->desc.id == descriptor_id) {
2027 found = 1;
2028 break;
2029 }
2030 buffer = buffer->next;
2031 }
2032 channel->locked = channel->locked->next;
2033
2034 if (!found) {
2035 pr_err("tspp: cant find desc %i", descriptor_id);
2036 return -EINVAL;
2037 }
2038
2039 /* make sure the buffer is in the expected state */
2040 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
2041 pr_err("tspp: buffer %i not locked", descriptor_id);
2042 return -EINVAL;
2043 }
2044 /* unlock the buffer and requeue it */
2045 buffer->state = TSPP_BUF_STATE_WAITING;
2046
2047 if (tspp_queue_buffer(channel, buffer))
2048 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02002049 return 0;
2050}
Joel Nider5bd73f82011-12-14 16:53:30 +02002051EXPORT_SYMBOL(tspp_release_buffer);
2052
Liron Kuch229090d2012-10-30 17:47:50 +02002053/**
2054 * tspp_allocate_buffers - allocate TSPP data buffers.
2055 *
2056 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2057 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2058 * @count: number of buffers to allocate
2059 * @size: size of each buffer to allocate
2060 * @int_freq: interrupt frequency
2061 * @alloc: user defined memory allocator function. Pass NULL for default.
2062 * @memfree: user defined memory free function. Pass NULL for default.
2063 * @user: user data to pass to the memory allocator/free function
2064 *
2065 * Return error status
2066 *
2067 * The user can optionally call this function explicitly to allocate the TSPP
2068 * data buffers. Alternatively, if the user did not call this function, it
2069 * is called implicitly by tspp_add_filter().
2070 */
2071int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
2072 u32 int_freq, tspp_allocator *alloc,
2073 tspp_memfree *memfree, void *user)
Joel Nider5bd73f82011-12-14 16:53:30 +02002074{
2075 struct tspp_channel *channel;
2076 struct tspp_device *pdev;
2077 struct tspp_mem_buffer *last = NULL;
2078
2079 TSPP_DEBUG("tspp_allocate_buffers");
2080
2081 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch229090d2012-10-30 17:47:50 +02002082 pr_err("%s: channel id out of range", __func__);
Joel Nider5bd73f82011-12-14 16:53:30 +02002083 return -ECHRNG;
2084 }
Liron Kuch229090d2012-10-30 17:47:50 +02002085
Joel Nider5bd73f82011-12-14 16:53:30 +02002086 pdev = tspp_find_by_id(dev);
2087 if (!pdev) {
Liron Kuch229090d2012-10-30 17:47:50 +02002088 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider5bd73f82011-12-14 16:53:30 +02002089 return -ENODEV;
2090 }
Liron Kuch229090d2012-10-30 17:47:50 +02002091
2092 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
2093 pr_err("%s: tspp requires a minimum of %i buffers\n",
2094 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
2095 return -EINVAL;
2096 }
2097
Joel Nider5bd73f82011-12-14 16:53:30 +02002098 channel = &pdev->channels[channel_id];
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002099
Liron Kuch229090d2012-10-30 17:47:50 +02002100 /* allow buffer allocation only if there was no previous buffer
2101 * allocation for this channel.
2102 */
2103 if (channel->buffer_count > 0) {
2104 pr_err("%s: buffers already allocated for channel %u",
2105 __func__, channel_id);
2106 return -EINVAL;
2107 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002108
2109 channel->max_buffers = count;
2110
2111 /* set up interrupt frequency */
Liron Kuch229090d2012-10-30 17:47:50 +02002112 if (int_freq > channel->max_buffers) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002113 int_freq = channel->max_buffers;
Liron Kuch229090d2012-10-30 17:47:50 +02002114 pr_warn("%s: setting interrupt frequency to %u\n",
2115 __func__, int_freq);
Joel Nider5bd73f82011-12-14 16:53:30 +02002116 }
Liron Kuch229090d2012-10-30 17:47:50 +02002117 channel->int_freq = int_freq;
2118 /*
2119 * it is the responsibility of the caller to tspp_allocate_buffers(),
2120 * whether it's the user or the driver, to make sure the size parameter
2121 * is compatible to the channel mode.
2122 */
2123 channel->buffer_size = size;
Joel Nider5bd73f82011-12-14 16:53:30 +02002124
Liron Kuch229090d2012-10-30 17:47:50 +02002125 /* save user defined memory free function for later use */
2126 channel->memfree = memfree;
2127 channel->user_info = user;
2128
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002129 /*
2130 * For small buffers, create a DMA pool so that memory
2131 * is not wasted through dma_alloc_coherent.
2132 */
2133 if (TSPP_USE_DMA_POOL(channel->buffer_size)) {
2134 channel->dma_pool = dma_pool_create("tspp",
2135 NULL, channel->buffer_size, 0, 0);
2136 if (!channel->dma_pool) {
2137 pr_err("%s: Can't allocate memory pool\n", __func__);
2138 return -ENOMEM;
2139 }
2140 } else {
2141 channel->dma_pool = NULL;
2142 }
2143
2144
Liron Kuch229090d2012-10-30 17:47:50 +02002145 for (channel->buffer_count = 0;
2146 channel->buffer_count < channel->max_buffers;
Joel Nider5bd73f82011-12-14 16:53:30 +02002147 channel->buffer_count++) {
2148
2149 /* allocate the descriptor */
2150 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2151 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2152 if (!desc) {
Liron Kuch229090d2012-10-30 17:47:50 +02002153 pr_warn("%s: Can't allocate desc %i",
2154 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002155 break;
2156 }
2157
2158 desc->desc.id = channel->buffer_count;
2159 /* allocate the buffer */
2160 if (tspp_alloc_buffer(channel_id, &desc->desc,
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002161 channel->buffer_size, channel->dma_pool,
2162 alloc, user) != 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002163 kfree(desc);
Liron Kuch229090d2012-10-30 17:47:50 +02002164 pr_warn("%s: Can't allocate buffer %i",
2165 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002166 break;
2167 }
2168
2169 /* add the descriptor to the list */
2170 desc->filled = 0;
2171 desc->read_index = 0;
2172 if (!channel->data) {
2173 channel->data = desc;
2174 desc->next = channel->data;
2175 } else {
2176 last->next = desc;
2177 }
2178 last = desc;
2179 desc->next = channel->data;
2180
2181 /* prepare the sps descriptor */
2182 desc->sps.phys_base = desc->desc.phys_base;
2183 desc->sps.base = desc->desc.virt_base;
2184 desc->sps.size = desc->desc.size;
2185
2186 /* start the transfer */
2187 if (tspp_queue_buffer(channel, desc))
Liron Kuch229090d2012-10-30 17:47:50 +02002188 pr_err("%s: can't queue buffer %i",
2189 __func__, desc->desc.id);
2190 }
2191
2192 if (channel->buffer_count < channel->max_buffers) {
2193 /*
2194 * we failed to allocate the requested number of buffers.
2195 * we don't allow a partial success, so need to clean up here.
2196 */
2197 tspp_destroy_buffers(channel_id, channel);
2198 channel->buffer_count = 0;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002199
2200 if (channel->dma_pool) {
2201 dma_pool_destroy(channel->dma_pool);
2202 channel->dma_pool = NULL;
2203 }
Liron Kuch229090d2012-10-30 17:47:50 +02002204 return -ENOMEM;
Joel Nider5bd73f82011-12-14 16:53:30 +02002205 }
2206
2207 channel->waiting = channel->data;
2208 channel->read = channel->data;
2209 channel->locked = channel->data;
Liron Kuch229090d2012-10-30 17:47:50 +02002210
Hamad Kadmany567bed82012-11-29 14:15:57 +02002211 /* Now that buffers are scheduled to HW, kick data expiration timer */
2212 if (channel->expiration_period_ms)
2213 mod_timer(&channel->expiration_timer,
2214 jiffies +
2215 MSEC_TO_JIFFIES(
2216 channel->expiration_period_ms));
2217
Joel Nider5bd73f82011-12-14 16:53:30 +02002218 return 0;
2219}
2220EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002221
2222/*** File Operations ***/
2223static ssize_t tspp_open(struct inode *inode, struct file *filp)
2224{
Joel Nider5bd73f82011-12-14 16:53:30 +02002225 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002226 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002227
2228 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002229 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2230 filp->private_data = channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002231 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002232
2233 /* if this channel is already in use, quit */
2234 if (channel->used) {
2235 pr_err("tspp channel %i already in use",
2236 MINOR(channel->cdev.dev));
2237 return -EACCES;
2238 }
2239
Joel Nider5bd73f82011-12-14 16:53:30 +02002240 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002241 pr_err("tspp: error opening channel");
2242 return -EACCES;
2243 }
2244
2245 return 0;
2246}
2247
2248static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2249{
2250 unsigned long flags;
2251 unsigned int mask = 0;
2252 struct tspp_channel *channel;
2253 channel = filp->private_data;
2254
2255 /* register the wait queue for this channel */
2256 poll_wait(filp, &channel->in_queue, p);
2257
2258 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider5bd73f82011-12-14 16:53:30 +02002259 if (channel->read &&
2260 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002261 mask = POLLIN | POLLRDNORM;
2262
2263 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2264
2265 return mask;
2266}
2267
2268static ssize_t tspp_release(struct inode *inode, struct file *filp)
2269{
Joel Nider5bd73f82011-12-14 16:53:30 +02002270 struct tspp_channel *channel = filp->private_data;
2271 u32 dev = channel->pdev->pdev->id;
2272 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002273
Joel Nider5bd73f82011-12-14 16:53:30 +02002274 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002275
2276 return 0;
2277}
2278
2279static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2280 loff_t *f_pos)
2281{
2282 size_t size = 0;
2283 size_t transferred = 0;
2284 struct tspp_channel *channel;
2285 struct tspp_mem_buffer *buffer;
2286 channel = filp->private_data;
2287
2288 TSPP_DEBUG("tspp_read");
Joel Nider5bd73f82011-12-14 16:53:30 +02002289
2290 while (!channel->read) {
2291 if (filp->f_flags & O_NONBLOCK) {
2292 pr_warn("tspp: no buffer on channel %i!",
2293 channel->id);
2294 return -EAGAIN;
2295 }
2296 /* go to sleep if there is nothing to read */
2297 if (wait_event_interruptible(channel->in_queue,
2298 (channel->read != NULL))) {
2299 pr_err("tspp: rude awakening\n");
2300 return -ERESTARTSYS;
2301 }
2302 }
2303
2304 buffer = channel->read;
2305
Joel Nider5556a852011-10-16 10:52:13 +02002306 /* see if we have any buffers ready to read */
2307 while (buffer->state != TSPP_BUF_STATE_DATA) {
2308 if (filp->f_flags & O_NONBLOCK) {
2309 pr_warn("tspp: nothing to read on channel %i!",
2310 channel->id);
2311 return -EAGAIN;
2312 }
2313 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002314 if (wait_event_interruptible(channel->in_queue,
2315 (buffer->state == TSPP_BUF_STATE_DATA))) {
2316 pr_err("tspp: rude awakening\n");
2317 return -ERESTARTSYS;
2318 }
2319 }
2320
2321 while (buffer->state == TSPP_BUF_STATE_DATA) {
2322 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002323 if (size == 0)
2324 break;
2325
Joel Nider5bd73f82011-12-14 16:53:30 +02002326 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002327 buffer->read_index, size)) {
2328 pr_err("tspp: error copying to user buffer");
Joel Nider5bd73f82011-12-14 16:53:30 +02002329 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002330 }
2331 buf += size;
2332 count -= size;
2333 transferred += size;
2334 buffer->read_index += size;
2335
Liron Kuch229090d2012-10-30 17:47:50 +02002336 /*
2337 * after reading the end of the buffer, requeue it,
2338 * and set up for reading the next one
2339 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002340 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002341 buffer->state = TSPP_BUF_STATE_WAITING;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002342
Joel Nider5bd73f82011-12-14 16:53:30 +02002343 if (tspp_queue_buffer(channel, buffer))
2344 pr_err("tspp: can't submit transfer");
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002345
Joel Nider5bd73f82011-12-14 16:53:30 +02002346 channel->locked = channel->read;
2347 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002348 }
2349 }
2350
2351 return transferred;
2352}
2353
2354static long tspp_ioctl(struct file *filp,
2355 unsigned int param0, unsigned long param1)
2356{
Joel Nider5bd73f82011-12-14 16:53:30 +02002357 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002358 int rc = -1;
2359 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002360 struct tspp_select_source ss;
2361 struct tspp_filter f;
2362 struct tspp_key k;
2363 struct tspp_iv iv;
2364 struct tspp_system_keys sk;
2365 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002366 channel = filp->private_data;
Joel Nider5bd73f82011-12-14 16:53:30 +02002367 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002368
2369 if (!param1)
2370 return -EINVAL;
2371
2372 switch (param0) {
2373 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002374 if (!access_ok(VERIFY_READ, param1,
2375 sizeof(struct tspp_select_source))) {
2376 return -EBUSY;
2377 }
2378 if (__copy_from_user(&ss, (void *)param1,
2379 sizeof(struct tspp_select_source)) == 0)
2380 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002381 break;
2382 case TSPP_IOCTL_ADD_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002383 if (!access_ok(VERIFY_READ, param1,
2384 sizeof(struct tspp_filter))) {
2385 return -ENOSR;
2386 }
2387 if (__copy_from_user(&f, (void *)param1,
2388 sizeof(struct tspp_filter)) == 0)
2389 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002390 break;
2391 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002392 if (!access_ok(VERIFY_READ, param1,
2393 sizeof(struct tspp_filter))) {
2394 return -EBUSY;
2395 }
2396 if (__copy_from_user(&f, (void *)param1,
2397 sizeof(struct tspp_filter)) == 0)
2398 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002399 break;
2400 case TSPP_IOCTL_SET_KEY:
Joel Nider5bd73f82011-12-14 16:53:30 +02002401 if (!access_ok(VERIFY_READ, param1,
2402 sizeof(struct tspp_key))) {
2403 return -EBUSY;
2404 }
2405 if (__copy_from_user(&k, (void *)param1,
2406 sizeof(struct tspp_key)) == 0)
2407 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002408 break;
2409 case TSPP_IOCTL_SET_IV:
Joel Nider5bd73f82011-12-14 16:53:30 +02002410 if (!access_ok(VERIFY_READ, param1,
2411 sizeof(struct tspp_iv))) {
2412 return -EBUSY;
2413 }
2414 if (__copy_from_user(&iv, (void *)param1,
2415 sizeof(struct tspp_iv)) == 0)
2416 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002417 break;
2418 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider5bd73f82011-12-14 16:53:30 +02002419 if (!access_ok(VERIFY_READ, param1,
2420 sizeof(struct tspp_system_keys))) {
2421 return -EINVAL;
2422 }
2423 if (__copy_from_user(&sk, (void *)param1,
2424 sizeof(struct tspp_system_keys)) == 0)
2425 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002426 break;
2427 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002428 if (!access_ok(VERIFY_READ, param1,
2429 sizeof(struct tspp_buffer))) {
2430 rc = -EINVAL;
2431 }
2432 if (__copy_from_user(&b, (void *)param1,
2433 sizeof(struct tspp_buffer)) == 0)
2434 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002435 break;
2436 default:
2437 pr_err("tspp: Unknown ioctl %i", param0);
2438 }
2439
Liron Kuch229090d2012-10-30 17:47:50 +02002440 /*
2441 * normalize the return code in case one of the subfunctions does
2442 * something weird
2443 */
Joel Nider5556a852011-10-16 10:52:13 +02002444 if (rc != 0)
Joel Nider5bd73f82011-12-14 16:53:30 +02002445 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002446
2447 return rc;
2448}
2449
2450/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002451static int debugfs_iomem_x32_set(void *data, u64 val)
2452{
2453 writel_relaxed(val, data);
2454 wmb();
2455 return 0;
2456}
2457
2458static int debugfs_iomem_x32_get(void *data, u64 *val)
2459{
2460 *val = readl_relaxed(data);
2461 return 0;
2462}
2463
2464DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2465 debugfs_iomem_x32_set, "0x%08llx");
2466
2467static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2468 int instance)
2469{
2470 char name[10];
2471 snprintf(name, 10, "tsif%i", instance);
2472 tsif_device->dent_tsif = debugfs_create_dir(
2473 name, NULL);
2474 if (tsif_device->dent_tsif) {
2475 int i;
2476 void __iomem *base = tsif_device->base;
2477 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2478 tsif_device->debugfs_tsif_regs[i] =
2479 debugfs_create_file(
2480 debugfs_tsif_regs[i].name,
2481 debugfs_tsif_regs[i].mode,
2482 tsif_device->dent_tsif,
2483 base + debugfs_tsif_regs[i].offset,
2484 &fops_iomem_x32);
2485 }
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002486
2487 debugfs_create_u32(
2488 "stat_rx_chunks",
2489 S_IRUGO|S_IWUGO,
2490 tsif_device->dent_tsif,
2491 &tsif_device->stat_rx);
2492
2493 debugfs_create_u32(
2494 "stat_overflow",
2495 S_IRUGO|S_IWUGO,
2496 tsif_device->dent_tsif,
2497 &tsif_device->stat_overflow);
2498
2499 debugfs_create_u32(
2500 "stat_lost_sync",
2501 S_IRUGO|S_IWUGO,
2502 tsif_device->dent_tsif,
2503 &tsif_device->stat_lost_sync);
2504
2505 debugfs_create_u32(
2506 "stat_timeout",
2507 S_IRUGO|S_IWUGO,
2508 tsif_device->dent_tsif,
2509 &tsif_device->stat_timeout);
2510
Joel Nider5556a852011-10-16 10:52:13 +02002511 }
2512}
2513
2514static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2515{
2516 if (tsif_device->dent_tsif) {
2517 int i;
2518 debugfs_remove_recursive(tsif_device->dent_tsif);
2519 tsif_device->dent_tsif = NULL;
2520 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2521 tsif_device->debugfs_tsif_regs[i] = NULL;
2522 }
2523}
2524
2525static void tspp_debugfs_init(struct tspp_device *device, int instance)
2526{
2527 char name[10];
2528 snprintf(name, 10, "tspp%i", instance);
2529 device->dent = debugfs_create_dir(
2530 name, NULL);
2531 if (device->dent) {
2532 int i;
2533 void __iomem *base = device->base;
2534 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2535 device->debugfs_regs[i] =
2536 debugfs_create_file(
2537 debugfs_tspp_regs[i].name,
2538 debugfs_tspp_regs[i].mode,
2539 device->dent,
2540 base + debugfs_tspp_regs[i].offset,
2541 &fops_iomem_x32);
2542 }
2543 }
2544}
2545
2546static void tspp_debugfs_exit(struct tspp_device *device)
2547{
2548 if (device->dent) {
2549 int i;
2550 debugfs_remove_recursive(device->dent);
2551 device->dent = NULL;
2552 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2553 device->debugfs_regs[i] = NULL;
2554 }
2555}
Joel Nider5556a852011-10-16 10:52:13 +02002556
2557static int __devinit msm_tspp_probe(struct platform_device *pdev)
2558{
2559 int rc = -ENODEV;
2560 u32 version;
Liron Kuch229090d2012-10-30 17:47:50 +02002561 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002562 struct msm_tspp_platform_data *data;
2563 struct tspp_device *device;
2564 struct resource *mem_tsif0;
2565 struct resource *mem_tsif1;
2566 struct resource *mem_tspp;
2567 struct resource *mem_bam;
Liron Kuch229090d2012-10-30 17:47:50 +02002568 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002569
2570 /* must have platform data */
2571 data = pdev->dev.platform_data;
2572 if (!data) {
2573 pr_err("tspp: Platform data not available");
2574 rc = -EINVAL;
2575 goto out;
2576 }
2577
2578 /* check for valid device id */
Joel Nider5bd73f82011-12-14 16:53:30 +02002579 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002580 pr_err("tspp: Invalid device ID %d", pdev->id);
2581 rc = -EINVAL;
2582 goto out;
2583 }
2584
2585 /* OK, we will use this device */
2586 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2587 if (!device) {
2588 pr_err("tspp: Failed to allocate memory for device");
2589 rc = -ENOMEM;
2590 goto out;
2591 }
2592
2593 /* set up references */
2594 device->pdev = pdev;
2595 platform_set_drvdata(pdev, device);
2596
2597 /* map clocks */
2598 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002599 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02002600 if (IS_ERR(device->tsif_pclk)) {
2601 pr_err("tspp: failed to get %s",
2602 data->tsif_pclk);
2603 rc = PTR_ERR(device->tsif_pclk);
2604 device->tsif_pclk = NULL;
2605 goto err_pclock;
2606 }
2607 }
2608 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002609 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02002610 if (IS_ERR(device->tsif_ref_clk)) {
2611 pr_err("tspp: failed to get %s",
2612 data->tsif_ref_clk);
2613 rc = PTR_ERR(device->tsif_ref_clk);
2614 device->tsif_ref_clk = NULL;
2615 goto err_refclock;
2616 }
2617 }
2618
2619 /* map I/O memory */
2620 mem_tsif0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2621 if (!mem_tsif0) {
2622 pr_err("tspp: Missing tsif0 MEM resource");
2623 rc = -ENXIO;
2624 goto err_res_tsif0;
2625 }
2626 device->tsif[0].base = ioremap(mem_tsif0->start,
2627 resource_size(mem_tsif0));
2628 if (!device->tsif[0].base) {
2629 pr_err("tspp: ioremap failed");
2630 goto err_map_tsif0;
2631 }
2632
2633 mem_tsif1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2634 if (!mem_tsif1) {
2635 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
2636 rc = -ENXIO;
2637 goto err_res_tsif1;
2638 }
2639 device->tsif[1].base = ioremap(mem_tsif1->start,
2640 resource_size(mem_tsif1));
2641 if (!device->tsif[1].base) {
2642 dev_err(&pdev->dev, "ioremap failed");
2643 goto err_map_tsif1;
2644 }
2645
2646 mem_tspp = platform_get_resource(pdev, IORESOURCE_MEM, 2);
2647 if (!mem_tspp) {
2648 dev_err(&pdev->dev, "Missing MEM resource");
2649 rc = -ENXIO;
2650 goto err_res_dev;
2651 }
2652 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
2653 if (!device->base) {
2654 dev_err(&pdev->dev, "ioremap failed");
2655 goto err_map_dev;
2656 }
2657
2658 mem_bam = platform_get_resource(pdev, IORESOURCE_MEM, 3);
2659 if (!mem_bam) {
2660 pr_err("tspp: Missing bam MEM resource");
2661 rc = -ENXIO;
2662 goto err_res_bam;
2663 }
2664 memset(&device->bam_props, 0, sizeof(device->bam_props));
2665 device->bam_props.phys_addr = mem_bam->start;
2666 device->bam_props.virt_addr = ioremap(mem_bam->start,
2667 resource_size(mem_bam));
2668 if (!device->bam_props.virt_addr) {
2669 dev_err(&pdev->dev, "ioremap failed");
2670 goto err_map_bam;
2671 }
2672
2673 /* map TSPP IRQ */
2674 rc = platform_get_irq(pdev, 0);
2675 if (rc > 0) {
2676 device->tspp_irq = rc;
2677 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
2678 dev_name(&pdev->dev), device);
2679 if (rc) {
2680 dev_err(&pdev->dev, "failed to request IRQ %d : %d",
2681 device->tspp_irq, rc);
2682 goto err_irq;
2683 }
2684 } else {
2685 dev_err(&pdev->dev, "failed to get tspp IRQ");
2686 goto err_irq;
2687 }
2688
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002689 /* map TSIF IRQs */
2690 device->tsif[0].tsif_irq = TSIF1_IRQ;
2691 device->tsif[1].tsif_irq = TSIF2_IRQ;
2692
2693 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
2694 rc = request_irq(device->tsif[i].tsif_irq,
2695 tsif_isr, IRQF_SHARED,
2696 dev_name(&pdev->dev), &device->tsif[i]);
2697 if (rc) {
2698 dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
2699 i, rc);
2700 device->tsif[i].tsif_irq = 0;
2701 }
2702 }
2703
Joel Nider5556a852011-10-16 10:52:13 +02002704 /* BAM IRQ */
2705 device->bam_irq = TSIF_BAM_IRQ;
2706
2707 /* GPIOs */
2708 rc = tspp_start_gpios(device);
2709 if (rc)
2710 goto err_gpio;
2711
2712 /* power management */
2713 pm_runtime_set_active(&pdev->dev);
2714 pm_runtime_enable(&pdev->dev);
2715
Joel Nider5556a852011-10-16 10:52:13 +02002716 tspp_debugfs_init(device, 0);
2717
2718 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2719 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02002720
2721 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
2722 dev_name(&pdev->dev));
2723
2724 /* set up pointers to ram-based 'registers' */
Joel Nider5bd73f82011-12-14 16:53:30 +02002725 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
2726 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
2727 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
2728 device->tspp_key_table = device->base + TSPP_DATA_KEY;
2729 device->tspp_global_performance =
2730 device->base + TSPP_GLOBAL_PERFORMANCE;
2731 device->tspp_pipe_context =
2732 device->base + TSPP_PIPE_CONTEXT;
2733 device->tspp_pipe_performance =
2734 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02002735
2736 device->bam_props.summing_threshold = 0x10;
2737 device->bam_props.irq = device->bam_irq;
2738 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
2739
2740 if (sps_register_bam_device(&device->bam_props,
2741 &device->bam_handle) != 0) {
2742 pr_err("tspp: failed to register bam");
2743 goto err_bam;
2744 }
2745
Joel Nider5bd73f82011-12-14 16:53:30 +02002746 if (tspp_clock_start(device) != 0) {
2747 dev_err(&pdev->dev, "Can't start clocks");
2748 goto err_clock;
Joel Nider5556a852011-10-16 10:52:13 +02002749 }
2750
2751 spin_lock_init(&device->spinlock);
2752 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
2753 (unsigned long)device);
2754
2755 /* initialize everything to a known state */
2756 tspp_global_reset(device);
2757
2758 version = readl_relaxed(device->base + TSPP_VERSION);
2759 if (version != 1)
2760 pr_warn("tspp: unrecognized hw version=%i", version);
2761
Joel Nider5bd73f82011-12-14 16:53:30 +02002762 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02002763 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002764 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
2765 pr_err("tspp_channel_init failed");
2766 goto err_channel;
2767 }
Joel Nider5556a852011-10-16 10:52:13 +02002768 }
2769
Joel Nider5bd73f82011-12-14 16:53:30 +02002770 /* stop the clocks for power savings */
2771 tspp_clock_stop(device);
2772
2773 /* everything is ok, so add the device to the list */
2774 list_add_tail(&(device->devlist), &tspp_devices);
2775
Joel Nider5556a852011-10-16 10:52:13 +02002776 return 0;
2777
Joel Nider5bd73f82011-12-14 16:53:30 +02002778err_channel:
Liron Kuch229090d2012-10-30 17:47:50 +02002779 /* uninitialize channels */
2780 for (j = 0; j < i; j++) {
2781 channel = &(device->channels[i]);
2782 device_destroy(tspp_class, channel->cdev.dev);
2783 cdev_del(&channel->cdev);
2784 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002785err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02002786 sps_deregister_bam_device(device->bam_handle);
2787err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02002788 tspp_debugfs_exit(device);
2789 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2790 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02002791err_gpio:
2792err_irq:
2793 tspp_stop_gpios(device);
2794 iounmap(device->bam_props.virt_addr);
2795err_map_bam:
2796err_res_bam:
2797 iounmap(device->base);
2798err_map_dev:
2799err_res_dev:
2800 iounmap(device->tsif[1].base);
2801err_map_tsif1:
2802err_res_tsif1:
2803 iounmap(device->tsif[0].base);
2804err_map_tsif0:
2805err_res_tsif0:
2806 if (device->tsif_ref_clk)
2807 clk_put(device->tsif_ref_clk);
2808err_refclock:
2809 if (device->tsif_pclk)
2810 clk_put(device->tsif_pclk);
2811err_pclock:
2812 kfree(device);
2813
2814out:
2815 return rc;
2816}
2817
2818static int __devexit msm_tspp_remove(struct platform_device *pdev)
2819{
Joel Nider5bd73f82011-12-14 16:53:30 +02002820 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002821 u32 i;
Joel Nider5556a852011-10-16 10:52:13 +02002822
2823 struct tspp_device *device = platform_get_drvdata(pdev);
2824
Joel Nider5bd73f82011-12-14 16:53:30 +02002825 /* free the buffers, and delete the channels */
2826 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
2827 channel = &device->channels[i];
2828 tspp_close_channel(device->pdev->id, i);
2829 device_destroy(tspp_class, channel->cdev.dev);
2830 cdev_del(&channel->cdev);
2831 }
2832
Joel Nider5556a852011-10-16 10:52:13 +02002833 sps_deregister_bam_device(device->bam_handle);
2834
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002835 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
Joel Nider5556a852011-10-16 10:52:13 +02002836 tsif_debugfs_exit(&device->tsif[i]);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002837 if (device->tsif[i].tsif_irq)
2838 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
2839 }
Joel Nider5556a852011-10-16 10:52:13 +02002840
2841 wake_lock_destroy(&device->wake_lock);
2842 free_irq(device->tspp_irq, device);
2843 tspp_stop_gpios(device);
2844
2845 iounmap(device->bam_props.virt_addr);
2846 iounmap(device->base);
2847 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2848 iounmap(device->tsif[i].base);
2849
2850 if (device->tsif_ref_clk)
2851 clk_put(device->tsif_ref_clk);
2852
2853 if (device->tsif_pclk)
2854 clk_put(device->tsif_pclk);
2855
2856 pm_runtime_disable(&pdev->dev);
2857 pm_runtime_put(&pdev->dev);
2858 kfree(device);
2859
2860 return 0;
2861}
2862
2863/*** power management ***/
2864
2865static int tspp_runtime_suspend(struct device *dev)
2866{
2867 dev_dbg(dev, "pm_runtime: suspending...");
2868 return 0;
2869}
2870
2871static int tspp_runtime_resume(struct device *dev)
2872{
2873 dev_dbg(dev, "pm_runtime: resuming...");
2874 return 0;
2875}
2876
2877static const struct dev_pm_ops tspp_dev_pm_ops = {
2878 .runtime_suspend = tspp_runtime_suspend,
2879 .runtime_resume = tspp_runtime_resume,
2880};
2881
2882static struct platform_driver msm_tspp_driver = {
2883 .probe = msm_tspp_probe,
2884 .remove = __exit_p(msm_tspp_remove),
2885 .driver = {
2886 .name = "msm_tspp",
2887 .pm = &tspp_dev_pm_ops,
2888 },
2889};
2890
2891
2892static int __init mod_init(void)
2893{
Joel Nider5556a852011-10-16 10:52:13 +02002894 int rc;
2895
Joel Nider5bd73f82011-12-14 16:53:30 +02002896 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02002897 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
2898 if (rc) {
2899 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
2900 goto err_devrgn;
2901 }
2902
2903 tspp_class = class_create(THIS_MODULE, "tspp");
2904 if (IS_ERR(tspp_class)) {
2905 rc = PTR_ERR(tspp_class);
2906 pr_err("tspp: Error creating class: %d", rc);
2907 goto err_class;
2908 }
2909
Joel Nider5bd73f82011-12-14 16:53:30 +02002910 /* register the driver, and check hardware */
2911 rc = platform_driver_register(&msm_tspp_driver);
2912 if (rc) {
2913 pr_err("tspp: platform_driver_register failed: %d", rc);
2914 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02002915 }
2916
2917 return 0;
2918
Joel Nider5bd73f82011-12-14 16:53:30 +02002919err_register:
2920 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02002921err_class:
2922 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
2923err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02002924 return rc;
2925}
2926
2927static void __exit mod_exit(void)
2928{
Joel Nider5bd73f82011-12-14 16:53:30 +02002929 /* delete low level driver */
2930 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02002931
Joel Nider5bd73f82011-12-14 16:53:30 +02002932 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02002933 class_destroy(tspp_class);
2934 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02002935}
2936
2937module_init(mod_init);
2938module_exit(mod_exit);
2939
Joel Nider5bd73f82011-12-14 16:53:30 +02002940MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02002941MODULE_LICENSE("GPL v2");