blob: eebaab9271ffc22ded7f946c41dfd6af1e953624 [file] [log] [blame]
Joel Niderb9662ca2012-06-10 14:21:11 +03001/* Copyright (c) 2011-2012, Code Aurora Forum. 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 */
28#include <linux/delay.h> /* msleep */
29#include <linux/platform_device.h>
Joel Nider5556a852011-10-16 10:52:13 +020030#include <linux/clk.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020031#include <linux/poll.h> /* poll() file op */
32#include <linux/wait.h> /* wait() macros, sleeping */
33#include <linux/tspp.h> /* tspp functions */
Joel Nider5556a852011-10-16 10:52:13 +020034#include <linux/bitops.h> /* BIT() macro */
Joel Nider5bd73f82011-12-14 16:53:30 +020035#include <mach/sps.h> /* BAM stuff */
Joel Nider5556a852011-10-16 10:52:13 +020036#include <mach/gpio.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020037#include <linux/wakelock.h> /* Locking functions */
Hamad Kadmany567bed82012-11-29 14:15:57 +020038#include <linux/timer.h> /* Timer services */
39#include <linux/jiffies.h> /* Jiffies counter */
Joel Nider5556a852011-10-16 10:52:13 +020040#include <mach/dma.h>
41#include <mach/msm_tspp.h>
Joel Nider5556a852011-10-16 10:52:13 +020042#include <linux/debugfs.h>
Joel Nider5556a852011-10-16 10:52:13 +020043
44/*
45 * General defines
46 */
Joel Nider5556a852011-10-16 10:52:13 +020047#define TSPP_TSIF_INSTANCES 2
48#define TSPP_FILTER_TABLES 3
Joel Nider5bd73f82011-12-14 16:53:30 +020049#define TSPP_MAX_DEVICES 1
Joel Nider5556a852011-10-16 10:52:13 +020050#define TSPP_NUM_CHANNELS 16
51#define TSPP_NUM_PRIORITIES 16
52#define TSPP_NUM_KEYS 8
53#define INVALID_CHANNEL 0xFFFFFFFF
Hamad Kadmany567bed82012-11-29 14:15:57 +020054
55/*
56 * BAM descriptor FIFO size (in number of descriptors).
57 * Max number of descriptors allowed by SPS which is 8K-1.
58 * Restrict it to half of this to save DMA memory.
59 */
60#define TSPP_SPS_DESCRIPTOR_COUNT (4 * 1024 - 1)
Joel Nider5556a852011-10-16 10:52:13 +020061#define TSPP_PACKET_LENGTH 188
62#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
Hamad Kadmany567bed82012-11-29 14:15:57 +020063
64/* Max descriptor buffer size allowed by SPS */
65#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
66
67/*
68 * Max allowed TSPP buffers/descriptors.
69 * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
70 */
71#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
Joel Nider5556a852011-10-16 10:52:13 +020072#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
73#define SPS_DESCRIPTOR_SIZE 8
74#define MIN_ACCEPTABLE_BUFFER_COUNT 2
Joel Nider5bd73f82011-12-14 16:53:30 +020075#define TSPP_DEBUG(msg...)
Joel Nider5556a852011-10-16 10:52:13 +020076
77/*
78 * TSIF register offsets
79 */
80#define TSIF_STS_CTL_OFF (0x0)
81#define TSIF_TIME_LIMIT_OFF (0x4)
82#define TSIF_CLK_REF_OFF (0x8)
83#define TSIF_LPBK_FLAGS_OFF (0xc)
84#define TSIF_LPBK_DATA_OFF (0x10)
85#define TSIF_TEST_CTL_OFF (0x14)
86#define TSIF_TEST_MODE_OFF (0x18)
87#define TSIF_TEST_RESET_OFF (0x1c)
88#define TSIF_TEST_EXPORT_OFF (0x20)
89#define TSIF_TEST_CURRENT_OFF (0x24)
90
91#define TSIF_DATA_PORT_OFF (0x100)
92
93/* bits for TSIF_STS_CTL register */
94#define TSIF_STS_CTL_EN_IRQ BIT(28)
95#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
96#define TSIF_STS_CTL_1ST_PACKET BIT(26)
97#define TSIF_STS_CTL_OVERFLOW BIT(25)
98#define TSIF_STS_CTL_LOST_SYNC BIT(24)
99#define TSIF_STS_CTL_TIMEOUT BIT(23)
100#define TSIF_STS_CTL_INV_SYNC BIT(21)
101#define TSIF_STS_CTL_INV_NULL BIT(20)
102#define TSIF_STS_CTL_INV_ERROR BIT(19)
103#define TSIF_STS_CTL_INV_ENABLE BIT(18)
104#define TSIF_STS_CTL_INV_DATA BIT(17)
105#define TSIF_STS_CTL_INV_CLOCK BIT(16)
106#define TSIF_STS_CTL_SPARE BIT(15)
107#define TSIF_STS_CTL_EN_NULL BIT(11)
108#define TSIF_STS_CTL_EN_ERROR BIT(10)
109#define TSIF_STS_CTL_LAST_BIT BIT(9)
110#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
111#define TSIF_STS_CTL_EN_TCR BIT(7)
112#define TSIF_STS_CTL_TEST_MODE BIT(6)
Joel Nider5bd73f82011-12-14 16:53:30 +0200113#define TSIF_STS_CTL_MODE_2 BIT(5)
Joel Nider5556a852011-10-16 10:52:13 +0200114#define TSIF_STS_CTL_EN_DM BIT(4)
115#define TSIF_STS_CTL_STOP BIT(3)
116#define TSIF_STS_CTL_START BIT(0)
117
118/*
119 * TSPP register offsets
120 */
Liron Kuch229090d2012-10-30 17:47:50 +0200121#define TSPP_RST 0x00
Joel Nider5556a852011-10-16 10:52:13 +0200122#define TSPP_CLK_CONTROL 0x04
Liron Kuch229090d2012-10-30 17:47:50 +0200123#define TSPP_CONFIG 0x08
124#define TSPP_CONTROL 0x0C
Joel Nider5556a852011-10-16 10:52:13 +0200125#define TSPP_PS_DISABLE 0x10
Liron Kuch229090d2012-10-30 17:47:50 +0200126#define TSPP_MSG_IRQ_STATUS 0x14
Joel Nider5556a852011-10-16 10:52:13 +0200127#define TSPP_MSG_IRQ_MASK 0x18
128#define TSPP_IRQ_STATUS 0x1C
129#define TSPP_IRQ_MASK 0x20
130#define TSPP_IRQ_CLEAR 0x24
131#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2))
Liron Kuch229090d2012-10-30 17:47:50 +0200132#define TSPP_STATUS 0x68
133#define TSPP_CURR_TSP_HEADER 0x6C
134#define TSPP_CURR_PID_FILTER 0x70
135#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2))
136#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2))
137#define TSPP_DATA_KEY_RESET 0x9C
Joel Nider5556a852011-10-16 10:52:13 +0200138#define TSPP_KEY_VALID 0xA0
139#define TSPP_KEY_ERROR 0xA4
140#define TSPP_TEST_CTRL 0xA8
Liron Kuch229090d2012-10-30 17:47:50 +0200141#define TSPP_VERSION 0xAC
Joel Nider5556a852011-10-16 10:52:13 +0200142#define TSPP_GENERICS 0xB0
Liron Kuch229090d2012-10-30 17:47:50 +0200143#define TSPP_NOP 0xB4
Joel Nider5556a852011-10-16 10:52:13 +0200144
145/*
146 * Register bit definitions
147 */
148/* TSPP_RST */
149#define TSPP_RST_RESET BIT(0)
150
151/* TSPP_CLK_CONTROL */
152#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9)
153#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8)
154#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7)
155#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6)
156#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5)
157#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
158#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3)
159#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
160#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
161#define TSPP_CLK_CONTROL_SET_CLKON BIT(0)
162
163/* TSPP_CONFIG */
164#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
165((_b & 0xF) << 8))
166#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
167#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7)
168#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6)
169#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5)
170#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
171#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3)
172#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2)
173#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1)
174#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0)
175
176/* TSPP_CONTROL */
177#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5)
178#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4)
179#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3)
180#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2)
181#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1)
182#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0)
183
184/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
185#define TSPP_MSG_TSPP_IRQ BIT(2)
186#define TSPP_MSG_TSIF_1_IRQ BIT(1)
187#define TSPP_MSG_TSIF_0_IRQ BIT(0)
188
189/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
Liron Kuch229090d2012-10-30 17:47:50 +0200190#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19)
191#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18)
Joel Nider5556a852011-10-16 10:52:13 +0200192#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17)
193#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16)
194#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n))
195
196/* TSPP_PIPE_ERROR_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200197#define TSPP_PIPE_PES_SYNC_ERROR BIT(3)
198#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2)
Joel Nider5556a852011-10-16 10:52:13 +0200199#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1)
Liron Kuch229090d2012-10-30 17:47:50 +0200200#define TSPP_PIP_PS_LOST_START BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200201
202/* TSPP_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200203#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10)
204#define TSPP_STATUS_TSIF1_DM_REQ BIT(6)
205#define TSPP_STATUS_TSIF0_DM_REQ BIT(2)
206#define TSPP_CURR_FILTER_TABLE BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200207
208/* TSPP_GENERICS */
Liron Kuch229090d2012-10-30 17:47:50 +0200209#define TSPP_GENERICS_CRYPTO_GEN BIT(12)
Joel Nider5556a852011-10-16 10:52:13 +0200210#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7)
Liron Kuch229090d2012-10-30 17:47:50 +0200211#define TSPP_GENERICS_MAX_PIPES BIT(2)
212#define TSPP_GENERICS_TSIF_1_GEN BIT(1)
213#define TSPP_GENERICS_TSIF_0_GEN BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200214
215/*
216 * TSPP memory regions
217 */
218#define TSPP_PID_FILTER_TABLE0 0x800
219#define TSPP_PID_FILTER_TABLE1 0x880
220#define TSPP_PID_FILTER_TABLE2 0x900
221#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */
222#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */
223#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */
224#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
225#define TSPP_DATA_KEY 0xCD0
226
Joel Nider5556a852011-10-16 10:52:13 +0200227struct debugfs_entry {
228 const char *name;
229 mode_t mode;
230 int offset;
231};
232
233static const struct debugfs_entry debugfs_tsif_regs[] = {
234 {"sts_ctl", S_IRUGO | S_IWUSR, TSIF_STS_CTL_OFF},
235 {"time_limit", S_IRUGO | S_IWUSR, TSIF_TIME_LIMIT_OFF},
236 {"clk_ref", S_IRUGO | S_IWUSR, TSIF_CLK_REF_OFF},
237 {"lpbk_flags", S_IRUGO | S_IWUSR, TSIF_LPBK_FLAGS_OFF},
238 {"lpbk_data", S_IRUGO | S_IWUSR, TSIF_LPBK_DATA_OFF},
239 {"test_ctl", S_IRUGO | S_IWUSR, TSIF_TEST_CTL_OFF},
240 {"test_mode", S_IRUGO | S_IWUSR, TSIF_TEST_MODE_OFF},
241 {"test_reset", S_IWUSR, TSIF_TEST_RESET_OFF},
242 {"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
243 {"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
244 {"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
245};
246
247static const struct debugfs_entry debugfs_tspp_regs[] = {
248 {"rst", S_IRUGO | S_IWUSR, TSPP_RST},
249 {"clk_control", S_IRUGO | S_IWUSR, TSPP_CLK_CONTROL},
250 {"config", S_IRUGO | S_IWUSR, TSPP_CONFIG},
251 {"control", S_IRUGO | S_IWUSR, TSPP_CONTROL},
252 {"ps_disable", S_IRUGO | S_IWUSR, TSPP_PS_DISABLE},
253 {"msg_irq_status", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_STATUS},
254 {"msg_irq_mask", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_MASK},
255 {"irq_status", S_IRUGO | S_IWUSR, TSPP_IRQ_STATUS},
256 {"irq_mask", S_IRUGO | S_IWUSR, TSPP_IRQ_MASK},
257 {"irq_clear", S_IRUGO | S_IWUSR, TSPP_IRQ_CLEAR},
258 /* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
259 {"status", S_IRUGO | S_IWUSR, TSPP_STATUS},
260 {"curr_tsp_header", S_IRUGO | S_IWUSR, TSPP_CURR_TSP_HEADER},
261 {"curr_pid_filter", S_IRUGO | S_IWUSR, TSPP_CURR_PID_FILTER},
262 /* {"system_key", S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
263 /* {"cbc_init_val", S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
264 {"data_key_reset", S_IRUGO | S_IWUSR, TSPP_DATA_KEY_RESET},
265 {"key_valid", S_IRUGO | S_IWUSR, TSPP_KEY_VALID},
266 {"key_error", S_IRUGO | S_IWUSR, TSPP_KEY_ERROR},
267 {"test_ctrl", S_IRUGO | S_IWUSR, TSPP_TEST_CTRL},
268 {"version", S_IRUGO | S_IWUSR, TSPP_VERSION},
269 {"generics", S_IRUGO | S_IWUSR, TSPP_GENERICS},
270 {"pid_filter_table0", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE0},
271 {"pid_filter_table1", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE1},
272 {"pid_filter_table2", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE2},
273 {"global_performance", S_IRUGO | S_IWUSR, TSPP_GLOBAL_PERFORMANCE},
274 {"pipe_context", S_IRUGO | S_IWUSR, TSPP_PIPE_CONTEXT},
275 {"pipe_performance", S_IRUGO | S_IWUSR, TSPP_PIPE_PERFORMANCE},
276 {"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
277};
278
Joel Nider5556a852011-10-16 10:52:13 +0200279struct tspp_pid_filter {
280 u32 filter; /* see FILTER_ macros */
281 u32 config; /* see FILTER_ macros */
282};
283
284/* tsp_info */
285#define FILTER_HEADER_ERROR_MASK BIT(7)
286#define FILTER_TRANS_END_DISABLE BIT(6)
287#define FILTER_DEC_ON_ERROR_EN BIT(5)
288#define FILTER_DECRYPT BIT(4)
289#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT)
290#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF)
291#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \
292 (_p->config & ~0xF) | (_b & 0xF))
293#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3)
294#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \
295 (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
296#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF)
297#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \
298 (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
299#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF)
300#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \
301 (_p->filter & ~0x1FFF) | (_b & 0x1FFF))
302#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3)
303#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \
304 (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
305#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7)
306#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \
307 (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
308
309struct tspp_global_performance_regs {
310 u32 tsp_total;
311 u32 tsp_ignored;
312 u32 tsp_error;
313 u32 tsp_sync;
314};
315
316struct tspp_pipe_context_regs {
317 u16 pes_bytes_left;
318 u16 count;
319 u32 tsif_suffix;
320} __packed;
321#define CONTEXT_GET_STATE(_a) (_a & 0x3)
322#define CONTEXT_UNSPEC_LENGTH BIT(11)
323#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
324
Hamad Kadmany567bed82012-11-29 14:15:57 +0200325#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
326
Joel Nider5556a852011-10-16 10:52:13 +0200327struct tspp_pipe_performance_regs {
328 u32 tsp_total;
329 u32 ps_duplicate_tsp;
330 u32 tsp_no_payload;
331 u32 tsp_broken_ps;
332 u32 ps_total_num;
333 u32 ps_continuity_error;
334 u32 ps_length_error;
335 u32 pes_sync_error;
336};
337
338struct tspp_tsif_device {
339 void __iomem *base;
340 u32 time_limit;
341 u32 ref_count;
Joel Nider5bd73f82011-12-14 16:53:30 +0200342 enum tspp_tsif_mode mode;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200343 int clock_inverse;
344 int data_inverse;
345 int sync_inverse;
346 int enable_inverse;
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200347 u32 tsif_irq;
Joel Nider5556a852011-10-16 10:52:13 +0200348
349 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200350 struct dentry *dent_tsif;
351 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200352 u32 stat_rx;
353 u32 stat_overflow;
354 u32 stat_lost_sync;
355 u32 stat_timeout;
Joel Nider5556a852011-10-16 10:52:13 +0200356};
357
358enum tspp_buf_state {
359 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
360 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider5bd73f82011-12-14 16:53:30 +0200361 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
362 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200363};
364
365struct tspp_mem_buffer {
Joel Nider5bd73f82011-12-14 16:53:30 +0200366 struct tspp_mem_buffer *next;
367 struct sps_mem_buffer sps;
368 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200369 enum tspp_buf_state state;
370 size_t filled; /* how much data this buffer is holding */
371 int read_index; /* where to start reading data from */
372};
373
374/* this represents each char device 'channel' */
375struct tspp_channel {
376 struct cdev cdev;
377 struct device *dd;
Joel Nider5bd73f82011-12-14 16:53:30 +0200378 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200379 struct sps_pipe *pipe;
380 struct sps_connect config;
381 struct sps_register_event event;
Joel Nider5bd73f82011-12-14 16:53:30 +0200382 struct tspp_mem_buffer *data; /* list of buffers */
383 struct tspp_mem_buffer *read; /* first buffer ready to be read */
384 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
385 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200386 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider5bd73f82011-12-14 16:53:30 +0200387 u32 id; /* channel id (0-15) */
388 int used; /* is this channel in use? */
389 int key; /* which encryption key index is used */
390 u32 buffer_size; /* size of the sps transfer buffers */
391 u32 max_buffers; /* how many buffers should be allocated */
392 u32 buffer_count; /* how many buffers are actually allocated */
393 u32 filter_count; /* how many filters have been added to this channel */
394 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200395 enum tspp_source src;
396 enum tspp_mode mode;
Joel Nider5bd73f82011-12-14 16:53:30 +0200397 tspp_notifier *notifier; /* used only with kernel api */
398 void *notify_data; /* data to be passed with the notifier */
Hamad Kadmany567bed82012-11-29 14:15:57 +0200399 u32 expiration_period_ms; /* notification on partially filled buffers */
400 struct timer_list expiration_timer;
Liron Kuch229090d2012-10-30 17:47:50 +0200401 tspp_memfree *memfree; /* user defined memory free function */
402 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200403};
404
405struct tspp_pid_filter_table {
406 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
407};
408
409struct tspp_key_entry {
410 u32 even_lsb;
411 u32 even_msb;
412 u32 odd_lsb;
413 u32 odd_msb;
414};
415
416struct tspp_key_table {
417 struct tspp_key_entry entry[TSPP_NUM_KEYS];
418};
419
Joel Nider5bd73f82011-12-14 16:53:30 +0200420/* this represents the actual hardware device */
421struct tspp_device {
422 struct list_head devlist; /* list of all devices */
423 struct platform_device *pdev;
424 void __iomem *base;
425 unsigned int tspp_irq;
426 unsigned int bam_irq;
427 u32 bam_handle;
428 struct sps_bam_props bam_props;
429 struct wake_lock wake_lock;
430 spinlock_t spinlock;
431 struct tasklet_struct tlet;
432 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
433 /* clocks */
434 struct clk *tsif_pclk;
435 struct clk *tsif_ref_clk;
436 /* data */
437 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
438 struct tspp_channel channels[TSPP_NUM_CHANNELS];
439 struct tspp_key_table *tspp_key_table;
440 struct tspp_global_performance_regs *tspp_global_performance;
441 struct tspp_pipe_context_regs *tspp_pipe_context;
442 struct tspp_pipe_performance_regs *tspp_pipe_performance;
443
444 struct dentry *dent;
445 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
446};
447
448
Joel Nider5556a852011-10-16 10:52:13 +0200449static struct class *tspp_class;
450static int tspp_key_entry;
451static dev_t tspp_minor; /* next minor number to assign */
Joel Nider5bd73f82011-12-14 16:53:30 +0200452
453static LIST_HEAD(tspp_devices);
454
455/* forward declarations */
456static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
457static ssize_t tspp_open(struct inode *inode, struct file *filp);
458static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
459static ssize_t tspp_release(struct inode *inode, struct file *filp);
460static long tspp_ioctl(struct file *, unsigned int, unsigned long);
461
462/* file operations */
463static const struct file_operations tspp_fops = {
464 .owner = THIS_MODULE,
465 .read = tspp_read,
466 .open = tspp_open,
467 .poll = tspp_poll,
468 .release = tspp_release,
469 .unlocked_ioctl = tspp_ioctl,
470};
Joel Nider5556a852011-10-16 10:52:13 +0200471
472/*** IRQ ***/
Joel Nider5bd73f82011-12-14 16:53:30 +0200473static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200474{
Joel Nider5bd73f82011-12-14 16:53:30 +0200475 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200476 u32 status, mask;
477 u32 data;
478
479 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
480 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
481 status &= mask;
482
483 if (!status) {
484 dev_warn(&device->pdev->dev, "Spurious interrupt");
485 return IRQ_NONE;
486 }
487
488 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
489
490 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
491 /* read the key error info */
492 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
493 dev_info(&device->pdev->dev, "key error 0x%x", data);
494 }
495 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
496 data = readl_relaxed(device->base + TSPP_KEY_VALID);
497 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
498 }
499 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
500 dev_info(&device->pdev->dev, "key switched");
501
502 if (status & 0xffff)
Joel Nider5bd73f82011-12-14 16:53:30 +0200503 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200504
505 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200506
507 /*
508 * Before returning IRQ_HANDLED to the generic interrupt handling
509 * framework need to make sure all operations including clearing of
510 * interrupt status registers in the hardware is performed.
511 * Thus a barrier after clearing the interrupt status register
512 * is required to guarantee that the interrupt status register has
513 * really been cleared by the time we return from this handler.
514 */
515 wmb();
516 return IRQ_HANDLED;
517}
518
519static irqreturn_t tsif_isr(int irq, void *dev)
520{
521 struct tspp_tsif_device *tsif_device = dev;
522 u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
523
524 if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
525 TSIF_STS_CTL_OVERFLOW |
526 TSIF_STS_CTL_LOST_SYNC |
527 TSIF_STS_CTL_TIMEOUT)))
528 return IRQ_NONE;
529
530 if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
531 tsif_device->stat_overflow++;
532
533 if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
534 tsif_device->stat_lost_sync++;
535
536 if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
537 tsif_device->stat_timeout++;
538
539 iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
540
541 /*
542 * Before returning IRQ_HANDLED to the generic interrupt handling
543 * framework need to make sure all operations including clearing of
544 * interrupt status registers in the hardware is performed.
545 * Thus a barrier after clearing the interrupt status register
546 * is required to guarantee that the interrupt status register has
547 * really been cleared by the time we return from this handler.
548 */
Joel Nider5556a852011-10-16 10:52:13 +0200549 wmb();
550 return IRQ_HANDLED;
551}
552
553/*** callbacks ***/
554static void tspp_sps_complete_cb(struct sps_event_notify *notify)
555{
Joel Nider5bd73f82011-12-14 16:53:30 +0200556 struct tspp_device *pdev = notify->user;
557 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200558}
559
Hamad Kadmany567bed82012-11-29 14:15:57 +0200560static void tspp_expiration_timer(unsigned long data)
561{
562 struct tspp_device *pdev = (struct tspp_device *)data;
563
564 if (pdev)
565 tasklet_schedule(&pdev->tlet);
566}
567
Joel Nider5556a852011-10-16 10:52:13 +0200568/*** tasklet ***/
569static void tspp_sps_complete_tlet(unsigned long data)
570{
571 int i;
572 int complete;
573 unsigned long flags;
574 struct sps_iovec iovec;
575 struct tspp_channel *channel;
576 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200577 spin_lock_irqsave(&device->spinlock, flags);
578
579 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
580 complete = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +0200581 channel = &device->channels[i];
Hamad Kadmany567bed82012-11-29 14:15:57 +0200582
Joel Nider5bd73f82011-12-14 16:53:30 +0200583 if (!channel->used || !channel->waiting)
584 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200585
Hamad Kadmany567bed82012-11-29 14:15:57 +0200586 /* stop the expiration timer */
587 if (channel->expiration_period_ms)
588 del_timer(&channel->expiration_timer);
589
Joel Nider5556a852011-10-16 10:52:13 +0200590 /* get completions */
Joel Nider5bd73f82011-12-14 16:53:30 +0200591 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200592 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
593 pr_err("tspp: Error in iovec on channel %i",
594 channel->id);
595 break;
596 }
597 if (iovec.size == 0)
598 break;
599
Joel Nider5bd73f82011-12-14 16:53:30 +0200600 if (iovec.addr != channel->waiting->sps.phys_base)
Joel Nider5556a852011-10-16 10:52:13 +0200601 pr_err("tspp: buffer mismatch 0x%08x",
Joel Nider5bd73f82011-12-14 16:53:30 +0200602 channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200603
604 complete = 1;
Joel Nider5bd73f82011-12-14 16:53:30 +0200605 channel->waiting->state = TSPP_BUF_STATE_DATA;
606 channel->waiting->filled = iovec.size;
607 channel->waiting->read_index = 0;
608
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200609 if (channel->src == TSPP_SOURCE_TSIF0)
610 device->tsif[0].stat_rx++;
611 else if (channel->src == TSPP_SOURCE_TSIF1)
612 device->tsif[1].stat_rx++;
613
Joel Nider5bd73f82011-12-14 16:53:30 +0200614 /* update the pointers */
615 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200616 }
617
Joel Nider5bd73f82011-12-14 16:53:30 +0200618 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200619 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200620 wake_up_interruptible(&channel->in_queue);
Joel Nider5bd73f82011-12-14 16:53:30 +0200621
622 /* call notifiers */
623 if (channel->notifier)
624 channel->notifier(channel->id,
625 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200626 }
Hamad Kadmany567bed82012-11-29 14:15:57 +0200627
628 /* restart expiration timer */
629 if (channel->expiration_period_ms)
630 mod_timer(&channel->expiration_timer,
631 jiffies +
632 MSEC_TO_JIFFIES(
633 channel->expiration_period_ms));
Joel Nider5556a852011-10-16 10:52:13 +0200634 }
635
636 spin_unlock_irqrestore(&device->spinlock, flags);
637}
638
639/*** GPIO functions ***/
640static void tspp_gpios_free(const struct msm_gpio *table, int size)
641{
642 int i;
643 const struct msm_gpio *g;
644 for (i = size-1; i >= 0; i--) {
645 g = table + i;
646 gpio_free(GPIO_PIN(g->gpio_cfg));
647 }
648}
649
650static int tspp_gpios_request(const struct msm_gpio *table, int size)
651{
652 int rc;
653 int i;
654 const struct msm_gpio *g;
655 for (i = 0; i < size; i++) {
656 g = table + i;
657 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
658 if (rc) {
659 pr_err("tspp: gpio_request(%d) <%s> failed: %d\n",
660 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
661 goto err;
662 }
663 }
664 return 0;
665err:
666 tspp_gpios_free(table, i);
667 return rc;
668}
669
670static int tspp_gpios_disable(const struct msm_gpio *table, int size)
671{
672 int rc = 0;
673 int i;
674 const struct msm_gpio *g;
675 for (i = size-1; i >= 0; i--) {
676 int tmp;
677 g = table + i;
678 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
679 if (tmp) {
Liron Kuch229090d2012-10-30 17:47:50 +0200680 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200681 g->gpio_cfg, g->label ?: "?", rc);
682 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
683 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
684 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
685 GPIO_DRVSTR(g->gpio_cfg));
686 if (!rc)
687 rc = tmp;
688 }
689 }
690
691 return rc;
692}
693
694static int tspp_gpios_enable(const struct msm_gpio *table, int size)
695{
696 int rc;
697 int i;
698 const struct msm_gpio *g;
699 for (i = 0; i < size; i++) {
700 g = table + i;
701 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
702 if (rc) {
Liron Kuch229090d2012-10-30 17:47:50 +0200703 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200704 g->gpio_cfg, g->label ?: "?", rc);
705 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
706 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
707 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
708 GPIO_DRVSTR(g->gpio_cfg));
709 goto err;
710 }
711 }
712 return 0;
713err:
714 tspp_gpios_disable(table, i);
715 return rc;
716}
717
718static int tspp_gpios_request_enable(const struct msm_gpio *table, int size)
719{
720 int rc = tspp_gpios_request(table, size);
721 if (rc)
722 return rc;
723 rc = tspp_gpios_enable(table, size);
724 if (rc)
725 tspp_gpios_free(table, size);
726 return rc;
727}
728
729static void tspp_gpios_disable_free(const struct msm_gpio *table, int size)
730{
731 tspp_gpios_disable(table, size);
732 tspp_gpios_free(table, size);
733}
734
735static int tspp_start_gpios(struct tspp_device *device)
736{
737 struct msm_tspp_platform_data *pdata =
738 device->pdev->dev.platform_data;
739 return tspp_gpios_request_enable(pdata->gpios, pdata->num_gpios);
740}
741
742static void tspp_stop_gpios(struct tspp_device *device)
743{
744 struct msm_tspp_platform_data *pdata =
745 device->pdev->dev.platform_data;
746 tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios);
747}
748
Joel Nider5bd73f82011-12-14 16:53:30 +0200749/*** Clock functions ***/
750static int tspp_clock_start(struct tspp_device *device)
751{
752 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
753 pr_err("tspp: Can't start pclk");
754 return -EBUSY;
755 }
756
757 if (device->tsif_ref_clk &&
758 clk_prepare_enable(device->tsif_ref_clk) != 0) {
759 pr_err("tspp: Can't start ref clk");
760 clk_disable_unprepare(device->tsif_pclk);
761 return -EBUSY;
762 }
763
764 return 0;
765}
766
767static void tspp_clock_stop(struct tspp_device *device)
768{
769 if (device->tsif_pclk)
770 clk_disable(device->tsif_pclk);
771
772 if (device->tsif_ref_clk)
773 clk_disable(device->tsif_ref_clk);
774}
775
Joel Nider5556a852011-10-16 10:52:13 +0200776/*** TSIF functions ***/
777static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
778{
779 int start_hardware = 0;
780 u32 ctl;
781
782 if (tsif_device->ref_count == 0) {
783 start_hardware = 1;
784 } else if (tsif_device->ref_count > 0) {
785 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
786 if ((ctl & TSIF_STS_CTL_START) != 1) {
787 /* this hardware should already be running */
788 pr_warn("tspp: tsif hw not started but ref count > 0");
789 start_hardware = 1;
790 }
791 }
792
793 if (start_hardware) {
Joel Nider5bd73f82011-12-14 16:53:30 +0200794 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200795 TSIF_STS_CTL_EN_DM;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200796
797 if (tsif_device->clock_inverse)
798 ctl |= TSIF_STS_CTL_INV_CLOCK;
799
800 if (tsif_device->data_inverse)
801 ctl |= TSIF_STS_CTL_INV_DATA;
802
803 if (tsif_device->sync_inverse)
804 ctl |= TSIF_STS_CTL_INV_SYNC;
805
806 if (tsif_device->enable_inverse)
807 ctl |= TSIF_STS_CTL_INV_ENABLE;
808
Joel Nider5bd73f82011-12-14 16:53:30 +0200809 switch (tsif_device->mode) {
810 case TSPP_TSIF_MODE_LOOPBACK:
811 ctl |= TSIF_STS_CTL_EN_NULL |
812 TSIF_STS_CTL_EN_ERROR |
813 TSIF_STS_CTL_TEST_MODE;
814 break;
815 case TSPP_TSIF_MODE_1:
816 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
817 TSIF_STS_CTL_EN_TCR;
818 break;
819 case TSPP_TSIF_MODE_2:
820 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
821 TSIF_STS_CTL_EN_TCR |
822 TSIF_STS_CTL_MODE_2;
823 break;
824 default:
825 pr_warn("tspp: unknown tsif mode 0x%x",
826 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200827 }
828 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
829 writel_relaxed(tsif_device->time_limit,
830 tsif_device->base + TSIF_TIME_LIMIT_OFF);
831 wmb();
832 writel_relaxed(ctl | TSIF_STS_CTL_START,
833 tsif_device->base + TSIF_STS_CTL_OFF);
834 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200835 }
836
Joel Nider5bd73f82011-12-14 16:53:30 +0200837 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Joel Nider5556a852011-10-16 10:52:13 +0200838 tsif_device->ref_count++;
839
Joel Nider5bd73f82011-12-14 16:53:30 +0200840 return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200841}
842
843static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
844{
845 if (tsif_device->ref_count == 0)
846 return;
847
848 tsif_device->ref_count--;
849
850 if (tsif_device->ref_count == 0) {
851 writel_relaxed(TSIF_STS_CTL_STOP,
852 tsif_device->base + TSIF_STS_CTL_OFF);
853 wmb();
854 }
855}
856
Joel Nider5bd73f82011-12-14 16:53:30 +0200857/*** local TSPP functions ***/
858static int tspp_channels_in_use(struct tspp_device *pdev)
859{
860 int i;
861 int count = 0;
862 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
863 count += (pdev->channels[i].used ? 1 : 0);
864
865 return count;
866}
867
868static struct tspp_device *tspp_find_by_id(int id)
869{
870 struct tspp_device *dev;
871 list_for_each_entry(dev, &tspp_devices, devlist) {
872 if (dev->pdev->id == id)
873 return dev;
874 }
875 return NULL;
876}
877
Joel Nider5556a852011-10-16 10:52:13 +0200878static int tspp_get_key_entry(void)
879{
880 int i;
881 for (i = 0; i < TSPP_NUM_KEYS; i++) {
882 if (!(tspp_key_entry & (1 << i))) {
883 tspp_key_entry |= (1 << i);
884 return i;
885 }
886 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200887 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200888}
889
890static void tspp_free_key_entry(int entry)
891{
892 if (entry > TSPP_NUM_KEYS) {
893 pr_err("tspp_free_key_entry: index out of bounds");
894 return;
895 }
896
897 tspp_key_entry &= ~(1 << entry);
898}
899
Joel Nider5bd73f82011-12-14 16:53:30 +0200900static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
901 u32 size, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200902{
Joel Nider5bd73f82011-12-14 16:53:30 +0200903 if (size < TSPP_MIN_BUFFER_SIZE ||
904 size > TSPP_MAX_BUFFER_SIZE) {
905 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200906 return -ENOMEM;
907 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200908
909 if (alloc) {
910 TSPP_DEBUG("tspp using alloc function");
911 desc->virt_base = alloc(channel_id, size,
912 &desc->phys_base, user);
913 } else {
Liron Kuch229090d2012-10-30 17:47:50 +0200914 desc->virt_base = dma_alloc_coherent(NULL, size,
915 &desc->phys_base, GFP_KERNEL);
916 if (desc->virt_base == 0) {
917 pr_err("tspp dma alloc coherent failed %i", size);
918 return -ENOMEM;
919 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200920 }
921
922 desc->size = size;
923 return 0;
924}
925
926static int tspp_queue_buffer(struct tspp_channel *channel,
927 struct tspp_mem_buffer *buffer)
928{
929 int rc;
930 u32 flags = 0;
931
932 /* make sure the interrupt frequency is valid */
933 if (channel->int_freq < 1)
934 channel->int_freq = 1;
935
936 /* generate interrupt according to requested frequency */
937 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
Hamad Kadmany567bed82012-11-29 14:15:57 +0200938 flags = SPS_IOVEC_FLAG_INT;
Joel Nider5bd73f82011-12-14 16:53:30 +0200939
940 /* start the transfer */
941 rc = sps_transfer_one(channel->pipe,
942 buffer->sps.phys_base,
943 buffer->sps.size,
944 channel->pdev,
945 flags);
946 if (rc < 0)
947 return rc;
948
949 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +0200950
951 return 0;
952}
953
954static int tspp_global_reset(struct tspp_device *pdev)
955{
956 u32 i, val;
957
958 /* stop all TSIFs */
959 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
960 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
961 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
962 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200963 pdev->tsif[i].clock_inverse = 0;
964 pdev->tsif[i].data_inverse = 0;
965 pdev->tsif[i].sync_inverse = 0;
966 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +0200967 }
968 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
969 wmb();
970
971 /* BAM */
972 if (sps_device_reset(pdev->bam_handle) != 0) {
973 pr_err("tspp: error resetting bam");
Joel Nider5bd73f82011-12-14 16:53:30 +0200974 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200975 }
976
977 /* TSPP tables */
978 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider5bd73f82011-12-14 16:53:30 +0200979 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +0200980 0, sizeof(struct tspp_pid_filter_table));
981
982 /* disable all filters */
983 val = (2 << TSPP_NUM_CHANNELS) - 1;
984 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
985
986 /* TSPP registers */
987 val = readl_relaxed(pdev->base + TSPP_CONTROL);
988 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
989 pdev->base + TSPP_CONTROL);
990 wmb();
Joel Nider5bd73f82011-12-14 16:53:30 +0200991 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200992 sizeof(struct tspp_global_performance_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +0200993 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200994 sizeof(struct tspp_pipe_context_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +0200995 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200996 sizeof(struct tspp_pipe_performance_regs));
997 wmb();
998 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
999 pdev->base + TSPP_CONTROL);
1000 wmb();
1001
1002 val = readl_relaxed(pdev->base + TSPP_CONFIG);
1003 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
1004 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
1005 TSPP_CONFIG_PS_CONT_ERR_MASK);
1006 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
1007 writel_relaxed(val, pdev->base + TSPP_CONFIG);
1008 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_MASK);
1009 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
1010 writel_relaxed(0, pdev->base + TSPP_RST);
1011 wmb();
1012
1013 tspp_key_entry = 0;
1014
1015 return 0;
1016}
1017
Joel Nider5bd73f82011-12-14 16:53:30 +02001018static int tspp_select_source(u32 dev, u32 channel_id,
1019 struct tspp_select_source *src)
1020{
1021 /* make sure the requested src id is in bounds */
1022 if (src->source > TSPP_SOURCE_MEM) {
1023 pr_err("tspp source out of bounds");
1024 return -EINVAL;
1025 }
1026
1027 /* open the stream */
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001028 tspp_open_stream(dev, channel_id, src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001029
1030 return 0;
1031}
1032
1033static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
1034{
1035 struct tspp_device *pdev = channel->pdev;
1036
1037 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
1038 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
1039 return 0;
1040}
1041
1042static int tspp_set_system_keys(struct tspp_channel *channel,
1043 struct tspp_system_keys *keys)
1044{
1045 int i;
1046 struct tspp_device *pdev = channel->pdev;
1047
1048 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
1049 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
1050
1051 return 0;
1052}
1053
1054static int tspp_channel_init(struct tspp_channel *channel,
1055 struct tspp_device *pdev)
1056{
1057 channel->cdev.owner = THIS_MODULE;
1058 cdev_init(&channel->cdev, &tspp_fops);
1059 channel->pdev = pdev;
1060 channel->data = NULL;
1061 channel->read = NULL;
1062 channel->waiting = NULL;
1063 channel->locked = NULL;
1064 channel->id = MINOR(tspp_minor);
1065 channel->used = 0;
1066 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1067 channel->max_buffers = TSPP_NUM_BUFFERS;
1068 channel->buffer_count = 0;
1069 channel->filter_count = 0;
1070 channel->int_freq = 1;
Liron Kuch229090d2012-10-30 17:47:50 +02001071 channel->src = TSPP_SOURCE_NONE;
1072 channel->mode = TSPP_MODE_DISABLED;
Joel Nider5bd73f82011-12-14 16:53:30 +02001073 channel->notifier = NULL;
1074 channel->notify_data = NULL;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001075 channel->expiration_period_ms = 0;
Liron Kuch229090d2012-10-30 17:47:50 +02001076 channel->memfree = NULL;
1077 channel->user_info = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001078 init_waitqueue_head(&channel->in_queue);
1079
1080 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
1081 pr_err("tspp: cdev_add failed");
1082 return -EBUSY;
1083 }
1084
1085 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
1086 channel, "tspp%02d", channel->id);
1087 if (IS_ERR(channel->dd)) {
1088 pr_err("tspp: device_create failed: %i",
1089 (int)PTR_ERR(channel->dd));
1090 cdev_del(&channel->cdev);
1091 return -EBUSY;
1092 }
1093
1094 return 0;
1095}
1096
1097static int tspp_set_buffer_size(struct tspp_channel *channel,
1098 struct tspp_buffer *buf)
1099{
Liron Kuch229090d2012-10-30 17:47:50 +02001100 if (channel->buffer_count > 0) {
1101 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1102 return -EPERM;
1103 }
1104
Joel Nider5bd73f82011-12-14 16:53:30 +02001105 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1106 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1107 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1108 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1109 else
1110 channel->buffer_size = buf->size;
1111
1112 return 0;
1113}
1114
1115static void tspp_set_tsif_mode(struct tspp_channel *channel,
1116 enum tspp_tsif_mode mode)
1117{
1118 int index;
1119
1120 switch (channel->src) {
1121 case TSPP_SOURCE_TSIF0:
1122 index = 0;
1123 break;
1124 case TSPP_SOURCE_TSIF1:
1125 index = 1;
1126 break;
1127 default:
1128 pr_warn("tspp: can't set mode for non-tsif source %d",
1129 channel->src);
1130 return;
1131 }
1132 channel->pdev->tsif[index].mode = mode;
1133}
1134
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001135static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch229090d2012-10-30 17:47:50 +02001136 int clock_inverse, int data_inverse,
1137 int sync_inverse, int enable_inverse)
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001138{
1139 int index;
1140
1141 switch (channel->src) {
1142 case TSPP_SOURCE_TSIF0:
1143 index = 0;
1144 break;
1145 case TSPP_SOURCE_TSIF1:
1146 index = 1;
1147 break;
1148 default:
1149 return;
1150 }
1151 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1152 channel->pdev->tsif[index].data_inverse = data_inverse;
1153 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1154 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1155}
1156
Liron Kuch229090d2012-10-30 17:47:50 +02001157static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1158{
1159 u32 alignment;
1160
1161 switch (mode) {
1162 case TSPP_MODE_RAW:
1163 /* must be a multiple of 192 */
1164 alignment = (TSPP_PACKET_LENGTH + 4);
1165 if (size % alignment)
1166 return 0;
1167 return 1;
1168
1169 case TSPP_MODE_RAW_NO_SUFFIX:
1170 /* must be a multiple of 188 */
1171 alignment = TSPP_PACKET_LENGTH;
1172 if (size % alignment)
1173 return 0;
1174 return 1;
1175
1176 case TSPP_MODE_DISABLED:
1177 case TSPP_MODE_PES:
1178 default:
1179 /* no alignment requirement */
1180 return 1;
1181 }
1182
1183}
1184
1185static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1186{
1187 u32 new_size;
1188 u32 alignment;
1189
1190 switch (mode) {
1191 case TSPP_MODE_RAW:
1192 /* must be a multiple of 192 */
1193 alignment = (TSPP_PACKET_LENGTH + 4);
1194 break;
1195
1196 case TSPP_MODE_RAW_NO_SUFFIX:
1197 /* must be a multiple of 188 */
1198 alignment = TSPP_PACKET_LENGTH;
1199 break;
1200
1201 case TSPP_MODE_DISABLED:
1202 case TSPP_MODE_PES:
1203 default:
1204 /* no alignment requirement - give the user what he asks for */
1205 alignment = 1;
1206 break;
1207 }
1208 /* align up */
1209 new_size = (((size + alignment - 1) / alignment) * alignment);
1210 return new_size;
1211}
1212
1213static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1214{
1215 int i;
1216 struct tspp_mem_buffer *pbuf, *temp;
1217
1218 pbuf = channel->data;
1219 for (i = 0; i < channel->buffer_count; i++) {
1220 if (pbuf->desc.phys_base) {
1221 if (channel->memfree) {
1222 channel->memfree(channel_id,
1223 pbuf->desc.size,
1224 pbuf->desc.virt_base,
1225 pbuf->desc.phys_base,
1226 channel->user_info);
1227 } else {
1228 dma_free_coherent(NULL,
1229 pbuf->desc.size,
1230 pbuf->desc.virt_base,
1231 pbuf->desc.phys_base);
1232 }
1233 pbuf->desc.phys_base = 0;
1234 }
1235 pbuf->desc.virt_base = 0;
1236 pbuf->state = TSPP_BUF_STATE_EMPTY;
1237 temp = pbuf;
1238 pbuf = pbuf->next;
1239 kfree(temp);
1240 }
1241}
1242
Joel Nider5bd73f82011-12-14 16:53:30 +02001243/*** TSPP API functions ***/
Liron Kuch229090d2012-10-30 17:47:50 +02001244
1245/**
1246 * tspp_open_stream - open a TSPP stream for use.
1247 *
1248 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1249 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1250 * @source: stream source parameters.
1251 *
1252 * Return error status
1253 *
1254 */
1255int tspp_open_stream(u32 dev, u32 channel_id,
1256 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001257{
1258 u32 val;
1259 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001260 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001261
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001262 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1263 dev, channel_id, source->source, source->mode);
Liron Kuch229090d2012-10-30 17:47:50 +02001264
Joel Nider5bd73f82011-12-14 16:53:30 +02001265 if (dev >= TSPP_MAX_DEVICES) {
1266 pr_err("tspp: device id out of range");
1267 return -ENODEV;
1268 }
Joel Nider5556a852011-10-16 10:52:13 +02001269
Joel Nider5bd73f82011-12-14 16:53:30 +02001270 if (channel_id >= TSPP_NUM_CHANNELS) {
1271 pr_err("tspp: channel id out of range");
1272 return -ECHRNG;
1273 }
1274
1275 pdev = tspp_find_by_id(dev);
1276 if (!pdev) {
1277 pr_err("tspp_str: can't find device %i", dev);
1278 return -ENODEV;
1279 }
1280 channel = &pdev->channels[channel_id];
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001281 channel->src = source->source;
1282 tspp_set_tsif_mode(channel, source->mode);
1283 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch229090d2012-10-30 17:47:50 +02001284 source->data_inverse, source->sync_inverse,
1285 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001286
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001287 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001288 case TSPP_SOURCE_TSIF0:
1289 /* make sure TSIF0 is running & enabled */
1290 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
1291 pr_err("tspp: error starting tsif0");
Joel Nider5bd73f82011-12-14 16:53:30 +02001292 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001293 }
1294 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1295 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1296 pdev->base + TSPP_CONTROL);
1297 wmb();
1298 break;
1299 case TSPP_SOURCE_TSIF1:
1300 /* make sure TSIF1 is running & enabled */
1301 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
1302 pr_err("tspp: error starting tsif1");
Joel Nider5bd73f82011-12-14 16:53:30 +02001303 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001304 }
1305 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1306 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1307 pdev->base + TSPP_CONTROL);
1308 wmb();
1309 break;
1310 case TSPP_SOURCE_MEM:
1311 break;
1312 default:
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001313 pr_err("tspp: channel %i invalid source %i",
1314 channel->id, source->source);
Joel Nider5bd73f82011-12-14 16:53:30 +02001315 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001316 }
1317
Joel Nider5556a852011-10-16 10:52:13 +02001318 return 0;
1319}
1320EXPORT_SYMBOL(tspp_open_stream);
1321
Liron Kuch229090d2012-10-30 17:47:50 +02001322/**
1323 * tspp_close_stream - close a TSPP stream.
1324 *
1325 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1326 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1327 *
1328 * Return error status
1329 *
1330 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001331int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001332{
1333 u32 val;
1334 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001335 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001336
Joel Nider5bd73f82011-12-14 16:53:30 +02001337 if (channel_id >= TSPP_NUM_CHANNELS) {
1338 pr_err("tspp: channel id out of range");
1339 return -ECHRNG;
1340 }
1341 pdev = tspp_find_by_id(dev);
1342 if (!pdev) {
1343 pr_err("tspp_cs: can't find device %i", dev);
1344 return -EBUSY;
1345 }
1346 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001347
1348 switch (channel->src) {
1349 case TSPP_SOURCE_TSIF0:
1350 tspp_stop_tsif(&pdev->tsif[0]);
1351 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1352 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1353 pdev->base + TSPP_CONTROL);
1354 wmb();
1355 break;
1356 case TSPP_SOURCE_TSIF1:
1357 tspp_stop_tsif(&pdev->tsif[1]);
1358 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1359 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1360 pdev->base + TSPP_CONTROL);
1361 break;
1362 case TSPP_SOURCE_MEM:
1363 break;
1364 case TSPP_SOURCE_NONE:
1365 break;
1366 }
1367
Joel Nider5bd73f82011-12-14 16:53:30 +02001368 channel->src = TSPP_SOURCE_NONE;
Joel Nider5556a852011-10-16 10:52:13 +02001369 return 0;
1370}
1371EXPORT_SYMBOL(tspp_close_stream);
1372
Liron Kuch229090d2012-10-30 17:47:50 +02001373/**
1374 * tspp_open_channel - open a TSPP channel.
1375 *
1376 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1377 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1378 *
1379 * Return error status
1380 *
1381 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001382int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001383{
1384 int rc = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001385 struct sps_connect *config;
1386 struct sps_register_event *event;
1387 struct tspp_channel *channel;
1388 struct tspp_device *pdev;
1389
1390 if (channel_id >= TSPP_NUM_CHANNELS) {
1391 pr_err("tspp: channel id out of range");
1392 return -ECHRNG;
1393 }
1394 pdev = tspp_find_by_id(dev);
1395 if (!pdev) {
1396 pr_err("tspp_oc: can't find device %i", dev);
1397 return -ENODEV;
1398 }
1399 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001400
1401 if (channel->used) {
1402 pr_err("tspp channel already in use");
Joel Nider5bd73f82011-12-14 16:53:30 +02001403 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001404 }
1405
Joel Nider5bd73f82011-12-14 16:53:30 +02001406 config = &channel->config;
1407 event = &channel->event;
1408
1409 /* start the clocks if needed */
1410 tspp_clock_start(pdev);
1411 if (tspp_channels_in_use(pdev) == 0)
1412 wake_lock(&pdev->wake_lock);
1413
Joel Nider5556a852011-10-16 10:52:13 +02001414 /* mark it as used */
1415 channel->used = 1;
1416
1417 /* start the bam */
1418 channel->pipe = sps_alloc_endpoint();
1419 if (channel->pipe == 0) {
1420 pr_err("tspp: error allocating endpoint");
1421 rc = -ENOMEM;
1422 goto err_sps_alloc;
1423 }
1424
1425 /* get default configuration */
1426 sps_get_config(channel->pipe, config);
1427
Joel Nider5bd73f82011-12-14 16:53:30 +02001428 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001429 config->destination = SPS_DEV_HANDLE_MEM;
1430 config->mode = SPS_MODE_SRC;
Joel Nider5bd73f82011-12-14 16:53:30 +02001431 config->options =
1432 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1433 SPS_O_STREAMING | /* streaming mode */
1434 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
Hamad Kadmany567bed82012-11-29 14:15:57 +02001435 SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
1436 SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001437 config->src_pipe_index = channel->id;
1438 config->desc.size =
Hamad Kadmany567bed82012-11-29 14:15:57 +02001439 TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
Joel Nider5556a852011-10-16 10:52:13 +02001440 config->desc.base = dma_alloc_coherent(NULL,
1441 config->desc.size,
1442 &config->desc.phys_base,
1443 GFP_KERNEL);
1444 if (config->desc.base == 0) {
1445 pr_err("tspp: error allocating sps descriptors");
1446 rc = -ENOMEM;
1447 goto err_desc_alloc;
1448 }
1449
1450 memset(config->desc.base, 0, config->desc.size);
1451
1452 rc = sps_connect(channel->pipe, config);
1453 if (rc) {
1454 pr_err("tspp: error connecting bam");
1455 goto err_connect;
1456 }
1457
1458 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider5bd73f82011-12-14 16:53:30 +02001459 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001460 event->callback = tspp_sps_complete_cb;
1461 event->xfer_done = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001462 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001463
1464 rc = sps_register_event(channel->pipe, event);
1465 if (rc) {
1466 pr_err("tspp: error registering event");
1467 goto err_event;
1468 }
1469
Hamad Kadmany567bed82012-11-29 14:15:57 +02001470 init_timer(&channel->expiration_timer);
1471 channel->expiration_timer.function = tspp_expiration_timer;
1472 channel->expiration_timer.data = (unsigned long)pdev;
1473 channel->expiration_timer.expires = 0xffffffffL;
1474
Joel Nider5bd73f82011-12-14 16:53:30 +02001475 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001476 if (rc < 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001477 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001478 "Runtime PM: Unable to wake up tspp device, rc = %d",
1479 rc);
1480 }
Joel Nider5556a852011-10-16 10:52:13 +02001481 return 0;
1482
1483err_event:
1484 sps_disconnect(channel->pipe);
1485err_connect:
1486 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1487 config->desc.phys_base);
1488err_desc_alloc:
1489 sps_free_endpoint(channel->pipe);
1490err_sps_alloc:
1491 return rc;
1492}
1493EXPORT_SYMBOL(tspp_open_channel);
1494
Liron Kuch229090d2012-10-30 17:47:50 +02001495/**
1496 * tspp_close_channel - close a TSPP channel.
1497 *
1498 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1499 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1500 *
1501 * Return error status
1502 *
1503 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001504int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001505{
1506 int i;
1507 int id;
1508 u32 val;
Joel Nider5556a852011-10-16 10:52:13 +02001509
Joel Nider5bd73f82011-12-14 16:53:30 +02001510 struct sps_connect *config;
1511 struct tspp_device *pdev;
1512 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02001513
1514 if (channel_id >= TSPP_NUM_CHANNELS) {
1515 pr_err("tspp: channel id out of range");
1516 return -ECHRNG;
1517 }
1518 pdev = tspp_find_by_id(dev);
1519 if (!pdev) {
1520 pr_err("tspp_close: can't find device %i", dev);
1521 return -ENODEV;
1522 }
1523 channel = &pdev->channels[channel_id];
1524
1525 /* if the channel is not used, we are done */
1526 if (!channel->used)
1527 return 0;
1528
Hamad Kadmany567bed82012-11-29 14:15:57 +02001529 if (channel->expiration_period_ms)
1530 del_timer(&channel->expiration_timer);
1531
Joel Nider5bd73f82011-12-14 16:53:30 +02001532 channel->notifier = NULL;
1533 channel->notify_data = NULL;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001534 channel->expiration_period_ms = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001535
1536 config = &channel->config;
1537 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001538
1539 /* disable pipe (channel) */
1540 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1541 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1542 wmb();
1543
1544 /* unregister all filters for this channel */
1545 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1546 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001547 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001548 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1549 if (id == channel->id) {
1550 if (FILTER_HAS_ENCRYPTION(tspp_filter))
1551 tspp_free_key_entry(
1552 FILTER_GET_KEY_NUMBER(tspp_filter));
1553 tspp_filter->config = 0;
1554 tspp_filter->filter = 0;
1555 }
1556 }
1557 channel->filter_count = 0;
1558
1559 /* stop the stream */
Joel Nider5bd73f82011-12-14 16:53:30 +02001560 tspp_close_stream(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02001561
1562 /* disconnect the bam */
1563 if (sps_disconnect(channel->pipe) != 0)
1564 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1565
1566 /* destroy the buffers */
1567 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1568 config->desc.phys_base);
1569
Liron Kuch229090d2012-10-30 17:47:50 +02001570 tspp_destroy_buffers(channel_id, channel);
1571
1572 channel->src = TSPP_SOURCE_NONE;
1573 channel->mode = TSPP_MODE_DISABLED;
1574 channel->memfree = NULL;
1575 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001576 channel->buffer_count = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001577 channel->data = NULL;
1578 channel->read = NULL;
1579 channel->waiting = NULL;
1580 channel->locked = NULL;
1581 channel->used = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001582
Joel Nider5bd73f82011-12-14 16:53:30 +02001583 if (tspp_channels_in_use(pdev) == 0)
1584 wake_unlock(&pdev->wake_lock);
1585 tspp_clock_stop(pdev);
1586
Joel Nider5556a852011-10-16 10:52:13 +02001587 return 0;
1588}
1589EXPORT_SYMBOL(tspp_close_channel);
1590
Liron Kuch229090d2012-10-30 17:47:50 +02001591/**
1592 * tspp_add_filter - add a TSPP filter to a channel.
1593 *
1594 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1595 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1596 * @filter: TSPP filter parameters
1597 *
1598 * Return error status
1599 *
1600 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001601int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001602 struct tspp_filter *filter)
1603{
Liron Kuch229090d2012-10-30 17:47:50 +02001604 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001605 int other_channel;
1606 int entry;
1607 u32 val, pid, enabled;
Joel Nider5bd73f82011-12-14 16:53:30 +02001608 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001609 struct tspp_pid_filter p;
Joel Nider5bd73f82011-12-14 16:53:30 +02001610 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001611
Joel Nider5bd73f82011-12-14 16:53:30 +02001612 TSPP_DEBUG("tspp: add filter");
1613 if (channel_id >= TSPP_NUM_CHANNELS) {
1614 pr_err("tspp: channel id out of range");
1615 return -ECHRNG;
1616 }
1617 pdev = tspp_find_by_id(dev);
1618 if (!pdev) {
1619 pr_err("tspp_add: can't find device %i", dev);
1620 return -ENODEV;
1621 }
1622
1623 channel = &pdev->channels[channel_id];
1624
Joel Nider5556a852011-10-16 10:52:13 +02001625 if (filter->source > TSPP_SOURCE_MEM) {
1626 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001627 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001628 }
1629
1630 if (filter->priority >= TSPP_NUM_PRIORITIES) {
1631 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001632 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001633 }
1634
Liron Kuch229090d2012-10-30 17:47:50 +02001635 channel->mode = filter->mode;
1636 /*
1637 * if buffers are already allocated, verify they fulfil
1638 * the alignment requirements.
1639 */
1640 if ((channel->buffer_count > 0) &&
1641 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1642 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001643
1644 if (filter->mode == TSPP_MODE_PES) {
1645 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1646 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001647 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001648 pid = FILTER_GET_PIPE_PID((tspp_filter));
1649 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1650 if (enabled && (pid == filter->pid)) {
1651 other_channel =
1652 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1653 pr_err("tspp: pid 0x%x already in use by channel %i",
1654 filter->pid, other_channel);
Joel Nider5bd73f82011-12-14 16:53:30 +02001655 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001656 }
1657 }
1658 }
1659
1660 /* make sure this priority is not already in use */
1661 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider5bd73f82011-12-14 16:53:30 +02001662 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001663 if (enabled) {
1664 pr_err("tspp: filter priority %i source %i is already enabled\n",
1665 filter->priority, channel->src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001666 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001667 }
1668
1669 if (channel->mode == TSPP_MODE_PES) {
1670 /* if we are already processing in PES mode, disable pipe
1671 (channel) and filter to be updated */
1672 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1673 writel_relaxed(val | (1 << channel->id),
1674 pdev->base + TSPP_PS_DISABLE);
1675 wmb();
1676 }
1677
1678 /* update entry */
1679 p.filter = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001680 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001681 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1682 FILTER_SET_PIPE_PID((&p), filter->pid);
1683 FILTER_SET_PID_MASK((&p), filter->mask);
1684 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1685 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1686 if (filter->decrypt) {
1687 entry = tspp_get_key_entry();
1688 if (entry == -1) {
1689 pr_err("tspp: no more keys available!");
1690 } else {
1691 p.config |= FILTER_DECRYPT;
1692 FILTER_SET_KEY_NUMBER((&p), entry);
1693 }
1694 }
Joel Nider5556a852011-10-16 10:52:13 +02001695
Joel Nider5bd73f82011-12-14 16:53:30 +02001696 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001697 filter[filter->priority].config = p.config;
Joel Nider5bd73f82011-12-14 16:53:30 +02001698 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001699 filter[filter->priority].filter = p.filter;
1700
Liron Kuch229090d2012-10-30 17:47:50 +02001701 /*
1702 * allocate buffers if needed (i.e. if user did has not already called
1703 * tspp_allocate_buffers() explicitly).
1704 */
1705 if (channel->buffer_count == 0) {
1706 channel->buffer_size =
1707 tspp_align_buffer_size_by_mode(channel->buffer_size,
1708 channel->mode);
1709 rc = tspp_allocate_buffers(dev, channel->id,
1710 channel->max_buffers,
1711 channel->buffer_size,
1712 channel->int_freq, NULL, NULL, NULL);
1713 if (rc != 0) {
1714 pr_err("tspp: tspp_allocate_buffers failed\n");
1715 return rc;
1716 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001717 }
1718
Joel Nider5556a852011-10-16 10:52:13 +02001719 /* reenable pipe */
1720 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1721 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1722 wmb();
1723 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1724
Joel Nider5556a852011-10-16 10:52:13 +02001725 channel->filter_count++;
1726
1727 return 0;
1728}
1729EXPORT_SYMBOL(tspp_add_filter);
1730
Liron Kuch229090d2012-10-30 17:47:50 +02001731/**
1732 * tspp_remove_filter - remove a TSPP filter from a channel.
1733 *
1734 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1735 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1736 * @filter: TSPP filter parameters
1737 *
1738 * Return error status
1739 *
1740 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001741int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001742 struct tspp_filter *filter)
1743{
1744 int entry;
1745 u32 val;
Joel Nider5bd73f82011-12-14 16:53:30 +02001746 struct tspp_device *pdev;
1747 int src;
1748 struct tspp_pid_filter *tspp_filter;
1749 struct tspp_channel *channel;
1750
1751 if (channel_id >= TSPP_NUM_CHANNELS) {
1752 pr_err("tspp: channel id out of range");
1753 return -ECHRNG;
1754 }
1755 pdev = tspp_find_by_id(dev);
1756 if (!pdev) {
1757 pr_err("tspp_remove: can't find device %i", dev);
1758 return -ENODEV;
1759 }
1760 channel = &pdev->channels[channel_id];
1761
1762 src = channel->src;
1763 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02001764
1765 /* disable pipe (channel) */
1766 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1767 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1768 wmb();
1769
1770 /* update data keys */
1771 if (tspp_filter->config & FILTER_DECRYPT) {
1772 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
1773 tspp_free_key_entry(entry);
1774 }
1775
1776 /* update pid table */
1777 tspp_filter->config = 0;
1778 tspp_filter->filter = 0;
1779
1780 channel->filter_count--;
1781
1782 /* reenable pipe */
1783 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1784 writel_relaxed(val & ~(1 << channel->id),
1785 pdev->base + TSPP_PS_DISABLE);
1786 wmb();
1787 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1788
1789 return 0;
1790}
1791EXPORT_SYMBOL(tspp_remove_filter);
1792
Liron Kuch229090d2012-10-30 17:47:50 +02001793/**
1794 * tspp_set_key - set TSPP key in key table.
1795 *
1796 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1797 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1798 * @key: TSPP key parameters
1799 *
1800 * Return error status
1801 *
1802 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001803int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02001804{
1805 int i;
1806 int id;
1807 int key_index;
1808 int data;
Joel Nider5bd73f82011-12-14 16:53:30 +02001809 struct tspp_channel *channel;
1810 struct tspp_device *pdev;
1811
1812 if (channel_id >= TSPP_NUM_CHANNELS) {
1813 pr_err("tspp: channel id out of range");
1814 return -ECHRNG;
1815 }
1816 pdev = tspp_find_by_id(dev);
1817 if (!pdev) {
1818 pr_err("tspp_set: can't find device %i", dev);
1819 return -ENODEV;
1820 }
1821 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001822
1823 /* read the key index used by this channel */
1824 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1825 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001826 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02001827 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1828 if (id == channel->id) {
1829 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
1830 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
1831 break;
1832 }
1833 }
1834 }
1835 if (i == TSPP_NUM_PRIORITIES) {
1836 pr_err("tspp: no encryption on this channel");
Joel Nider5bd73f82011-12-14 16:53:30 +02001837 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02001838 }
1839
1840 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001841 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
1842 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001843 } else {
Joel Nider5bd73f82011-12-14 16:53:30 +02001844 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
1845 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001846 }
1847 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
1848
1849 return 0;
1850}
1851EXPORT_SYMBOL(tspp_set_key);
1852
Liron Kuch229090d2012-10-30 17:47:50 +02001853/**
1854 * tspp_register_notification - register TSPP channel notification function.
1855 *
1856 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1857 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1858 * @pNotify: notification function
1859 * @userdata: user data to pass to notification function
1860 * @timer_ms: notification for partially filled buffers
1861 *
1862 * Return error status
1863 *
1864 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001865int tspp_register_notification(u32 dev, u32 channel_id,
1866 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02001867{
Joel Nider5bd73f82011-12-14 16:53:30 +02001868 struct tspp_channel *channel;
1869 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001870
Joel Nider5bd73f82011-12-14 16:53:30 +02001871 if (channel_id >= TSPP_NUM_CHANNELS) {
1872 pr_err("tspp: channel id out of range");
1873 return -ECHRNG;
1874 }
1875 pdev = tspp_find_by_id(dev);
1876 if (!pdev) {
1877 pr_err("tspp_reg: can't find device %i", dev);
1878 return -ENODEV;
1879 }
1880 channel = &pdev->channels[channel_id];
1881 channel->notifier = pNotify;
1882 channel->notify_data = userdata;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001883 channel->expiration_period_ms = timer_ms;
1884
Joel Nider5556a852011-10-16 10:52:13 +02001885 return 0;
1886}
Joel Nider5bd73f82011-12-14 16:53:30 +02001887EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001888
Liron Kuch229090d2012-10-30 17:47:50 +02001889/**
1890 * tspp_unregister_notification - unregister TSPP channel notification function.
1891 *
1892 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1893 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1894 *
1895 * Return error status
1896 *
1897 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001898int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001899{
Joel Nider5bd73f82011-12-14 16:53:30 +02001900 struct tspp_channel *channel;
1901 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001902
Joel Nider5bd73f82011-12-14 16:53:30 +02001903 if (channel_id >= TSPP_NUM_CHANNELS) {
1904 pr_err("tspp: channel id out of range");
1905 return -ECHRNG;
1906 }
1907 pdev = tspp_find_by_id(dev);
1908 if (!pdev) {
1909 pr_err("tspp_unreg: can't find device %i", dev);
1910 return -ENODEV;
1911 }
1912 channel = &pdev->channels[channel_id];
1913 channel->notifier = NULL;
1914 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001915 return 0;
1916}
Joel Nider5bd73f82011-12-14 16:53:30 +02001917EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001918
Liron Kuch229090d2012-10-30 17:47:50 +02001919/**
1920 * tspp_get_buffer - get TSPP data buffer.
1921 *
1922 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1923 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1924 *
1925 * Return error status
1926 *
1927 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001928const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001929{
Joel Nider5bd73f82011-12-14 16:53:30 +02001930 struct tspp_mem_buffer *buffer;
1931 struct tspp_channel *channel;
1932 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001933
Joel Nider5bd73f82011-12-14 16:53:30 +02001934 if (channel_id >= TSPP_NUM_CHANNELS) {
1935 pr_err("tspp: channel id out of range");
1936 return NULL;
1937 }
1938 pdev = tspp_find_by_id(dev);
1939 if (!pdev) {
1940 pr_err("tspp_get: can't find device %i", dev);
1941 return NULL;
1942 }
1943 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001944
Joel Nider5bd73f82011-12-14 16:53:30 +02001945 if (!channel->read) {
1946 pr_warn("tspp: no buffer to get on channel %i!",
1947 channel->id);
1948 return NULL;
1949 }
1950
1951 buffer = channel->read;
1952 /* see if we have any buffers ready to read */
1953 if (buffer->state != TSPP_BUF_STATE_DATA)
1954 return 0;
1955
1956 if (buffer->state == TSPP_BUF_STATE_DATA) {
1957 /* mark the buffer as busy */
1958 buffer->state = TSPP_BUF_STATE_LOCKED;
1959
1960 /* increment the pointer along the list */
1961 channel->read = channel->read->next;
1962 }
1963
1964 return &buffer->desc;
1965}
1966EXPORT_SYMBOL(tspp_get_buffer);
1967
Liron Kuch229090d2012-10-30 17:47:50 +02001968/**
1969 * tspp_release_buffer - release TSPP data buffer back to TSPP.
1970 *
1971 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1972 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1973 * @descriptor_id: buffer descriptor ID
1974 *
1975 * Return error status
1976 *
1977 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001978int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
1979{
1980 int i, found = 0;
1981 struct tspp_mem_buffer *buffer;
1982 struct tspp_channel *channel;
1983 struct tspp_device *pdev;
1984
1985 if (channel_id >= TSPP_NUM_CHANNELS) {
1986 pr_err("tspp: channel id out of range");
1987 return -ECHRNG;
1988 }
1989 pdev = tspp_find_by_id(dev);
1990 if (!pdev) {
1991 pr_err("tspp: can't find device %i", dev);
1992 return -ENODEV;
1993 }
1994 channel = &pdev->channels[channel_id];
1995
1996 if (descriptor_id > channel->buffer_count)
1997 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
1998
1999 /* find the correct descriptor */
2000 buffer = channel->locked;
2001 for (i = 0; i < channel->buffer_count; i++) {
2002 if (buffer->desc.id == descriptor_id) {
2003 found = 1;
2004 break;
2005 }
2006 buffer = buffer->next;
2007 }
2008 channel->locked = channel->locked->next;
2009
2010 if (!found) {
2011 pr_err("tspp: cant find desc %i", descriptor_id);
2012 return -EINVAL;
2013 }
2014
2015 /* make sure the buffer is in the expected state */
2016 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
2017 pr_err("tspp: buffer %i not locked", descriptor_id);
2018 return -EINVAL;
2019 }
2020 /* unlock the buffer and requeue it */
2021 buffer->state = TSPP_BUF_STATE_WAITING;
2022
2023 if (tspp_queue_buffer(channel, buffer))
2024 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02002025 return 0;
2026}
Joel Nider5bd73f82011-12-14 16:53:30 +02002027EXPORT_SYMBOL(tspp_release_buffer);
2028
Liron Kuch229090d2012-10-30 17:47:50 +02002029/**
2030 * tspp_allocate_buffers - allocate TSPP data buffers.
2031 *
2032 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2033 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2034 * @count: number of buffers to allocate
2035 * @size: size of each buffer to allocate
2036 * @int_freq: interrupt frequency
2037 * @alloc: user defined memory allocator function. Pass NULL for default.
2038 * @memfree: user defined memory free function. Pass NULL for default.
2039 * @user: user data to pass to the memory allocator/free function
2040 *
2041 * Return error status
2042 *
2043 * The user can optionally call this function explicitly to allocate the TSPP
2044 * data buffers. Alternatively, if the user did not call this function, it
2045 * is called implicitly by tspp_add_filter().
2046 */
2047int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
2048 u32 int_freq, tspp_allocator *alloc,
2049 tspp_memfree *memfree, void *user)
Joel Nider5bd73f82011-12-14 16:53:30 +02002050{
2051 struct tspp_channel *channel;
2052 struct tspp_device *pdev;
2053 struct tspp_mem_buffer *last = NULL;
2054
2055 TSPP_DEBUG("tspp_allocate_buffers");
2056
2057 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch229090d2012-10-30 17:47:50 +02002058 pr_err("%s: channel id out of range", __func__);
Joel Nider5bd73f82011-12-14 16:53:30 +02002059 return -ECHRNG;
2060 }
Liron Kuch229090d2012-10-30 17:47:50 +02002061
Joel Nider5bd73f82011-12-14 16:53:30 +02002062 pdev = tspp_find_by_id(dev);
2063 if (!pdev) {
Liron Kuch229090d2012-10-30 17:47:50 +02002064 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider5bd73f82011-12-14 16:53:30 +02002065 return -ENODEV;
2066 }
Liron Kuch229090d2012-10-30 17:47:50 +02002067
2068 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
2069 pr_err("%s: tspp requires a minimum of %i buffers\n",
2070 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
2071 return -EINVAL;
2072 }
2073
Joel Nider5bd73f82011-12-14 16:53:30 +02002074 channel = &pdev->channels[channel_id];
Liron Kuch229090d2012-10-30 17:47:50 +02002075 /* allow buffer allocation only if there was no previous buffer
2076 * allocation for this channel.
2077 */
2078 if (channel->buffer_count > 0) {
2079 pr_err("%s: buffers already allocated for channel %u",
2080 __func__, channel_id);
2081 return -EINVAL;
2082 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002083
2084 channel->max_buffers = count;
2085
2086 /* set up interrupt frequency */
Liron Kuch229090d2012-10-30 17:47:50 +02002087 if (int_freq > channel->max_buffers) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002088 int_freq = channel->max_buffers;
Liron Kuch229090d2012-10-30 17:47:50 +02002089 pr_warn("%s: setting interrupt frequency to %u\n",
2090 __func__, int_freq);
Joel Nider5bd73f82011-12-14 16:53:30 +02002091 }
Liron Kuch229090d2012-10-30 17:47:50 +02002092 channel->int_freq = int_freq;
2093 /*
2094 * it is the responsibility of the caller to tspp_allocate_buffers(),
2095 * whether it's the user or the driver, to make sure the size parameter
2096 * is compatible to the channel mode.
2097 */
2098 channel->buffer_size = size;
Joel Nider5bd73f82011-12-14 16:53:30 +02002099
Liron Kuch229090d2012-10-30 17:47:50 +02002100 /* save user defined memory free function for later use */
2101 channel->memfree = memfree;
2102 channel->user_info = user;
2103
2104 for (channel->buffer_count = 0;
2105 channel->buffer_count < channel->max_buffers;
Joel Nider5bd73f82011-12-14 16:53:30 +02002106 channel->buffer_count++) {
2107
2108 /* allocate the descriptor */
2109 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2110 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2111 if (!desc) {
Liron Kuch229090d2012-10-30 17:47:50 +02002112 pr_warn("%s: Can't allocate desc %i",
2113 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002114 break;
2115 }
2116
2117 desc->desc.id = channel->buffer_count;
2118 /* allocate the buffer */
2119 if (tspp_alloc_buffer(channel_id, &desc->desc,
2120 channel->buffer_size, alloc, user) != 0) {
2121 kfree(desc);
Liron Kuch229090d2012-10-30 17:47:50 +02002122 pr_warn("%s: Can't allocate buffer %i",
2123 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002124 break;
2125 }
2126
2127 /* add the descriptor to the list */
2128 desc->filled = 0;
2129 desc->read_index = 0;
2130 if (!channel->data) {
2131 channel->data = desc;
2132 desc->next = channel->data;
2133 } else {
2134 last->next = desc;
2135 }
2136 last = desc;
2137 desc->next = channel->data;
2138
2139 /* prepare the sps descriptor */
2140 desc->sps.phys_base = desc->desc.phys_base;
2141 desc->sps.base = desc->desc.virt_base;
2142 desc->sps.size = desc->desc.size;
2143
2144 /* start the transfer */
2145 if (tspp_queue_buffer(channel, desc))
Liron Kuch229090d2012-10-30 17:47:50 +02002146 pr_err("%s: can't queue buffer %i",
2147 __func__, desc->desc.id);
2148 }
2149
2150 if (channel->buffer_count < channel->max_buffers) {
2151 /*
2152 * we failed to allocate the requested number of buffers.
2153 * we don't allow a partial success, so need to clean up here.
2154 */
2155 tspp_destroy_buffers(channel_id, channel);
2156 channel->buffer_count = 0;
2157 return -ENOMEM;
Joel Nider5bd73f82011-12-14 16:53:30 +02002158 }
2159
2160 channel->waiting = channel->data;
2161 channel->read = channel->data;
2162 channel->locked = channel->data;
Liron Kuch229090d2012-10-30 17:47:50 +02002163
Hamad Kadmany567bed82012-11-29 14:15:57 +02002164 /* Now that buffers are scheduled to HW, kick data expiration timer */
2165 if (channel->expiration_period_ms)
2166 mod_timer(&channel->expiration_timer,
2167 jiffies +
2168 MSEC_TO_JIFFIES(
2169 channel->expiration_period_ms));
2170
Joel Nider5bd73f82011-12-14 16:53:30 +02002171 return 0;
2172}
2173EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002174
2175/*** File Operations ***/
2176static ssize_t tspp_open(struct inode *inode, struct file *filp)
2177{
Joel Nider5bd73f82011-12-14 16:53:30 +02002178 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002179 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002180
2181 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002182 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2183 filp->private_data = channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002184 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002185
2186 /* if this channel is already in use, quit */
2187 if (channel->used) {
2188 pr_err("tspp channel %i already in use",
2189 MINOR(channel->cdev.dev));
2190 return -EACCES;
2191 }
2192
Joel Nider5bd73f82011-12-14 16:53:30 +02002193 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002194 pr_err("tspp: error opening channel");
2195 return -EACCES;
2196 }
2197
2198 return 0;
2199}
2200
2201static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2202{
2203 unsigned long flags;
2204 unsigned int mask = 0;
2205 struct tspp_channel *channel;
2206 channel = filp->private_data;
2207
2208 /* register the wait queue for this channel */
2209 poll_wait(filp, &channel->in_queue, p);
2210
2211 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider5bd73f82011-12-14 16:53:30 +02002212 if (channel->read &&
2213 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002214 mask = POLLIN | POLLRDNORM;
2215
2216 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2217
2218 return mask;
2219}
2220
2221static ssize_t tspp_release(struct inode *inode, struct file *filp)
2222{
Joel Nider5bd73f82011-12-14 16:53:30 +02002223 struct tspp_channel *channel = filp->private_data;
2224 u32 dev = channel->pdev->pdev->id;
2225 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002226
Joel Nider5bd73f82011-12-14 16:53:30 +02002227 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002228
2229 return 0;
2230}
2231
2232static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2233 loff_t *f_pos)
2234{
2235 size_t size = 0;
2236 size_t transferred = 0;
2237 struct tspp_channel *channel;
2238 struct tspp_mem_buffer *buffer;
2239 channel = filp->private_data;
2240
2241 TSPP_DEBUG("tspp_read");
Joel Nider5bd73f82011-12-14 16:53:30 +02002242
2243 while (!channel->read) {
2244 if (filp->f_flags & O_NONBLOCK) {
2245 pr_warn("tspp: no buffer on channel %i!",
2246 channel->id);
2247 return -EAGAIN;
2248 }
2249 /* go to sleep if there is nothing to read */
2250 if (wait_event_interruptible(channel->in_queue,
2251 (channel->read != NULL))) {
2252 pr_err("tspp: rude awakening\n");
2253 return -ERESTARTSYS;
2254 }
2255 }
2256
2257 buffer = channel->read;
2258
Joel Nider5556a852011-10-16 10:52:13 +02002259 /* see if we have any buffers ready to read */
2260 while (buffer->state != TSPP_BUF_STATE_DATA) {
2261 if (filp->f_flags & O_NONBLOCK) {
2262 pr_warn("tspp: nothing to read on channel %i!",
2263 channel->id);
2264 return -EAGAIN;
2265 }
2266 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002267 if (wait_event_interruptible(channel->in_queue,
2268 (buffer->state == TSPP_BUF_STATE_DATA))) {
2269 pr_err("tspp: rude awakening\n");
2270 return -ERESTARTSYS;
2271 }
2272 }
2273
2274 while (buffer->state == TSPP_BUF_STATE_DATA) {
2275 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002276 if (size == 0)
2277 break;
2278
Joel Nider5bd73f82011-12-14 16:53:30 +02002279 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002280 buffer->read_index, size)) {
2281 pr_err("tspp: error copying to user buffer");
Joel Nider5bd73f82011-12-14 16:53:30 +02002282 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002283 }
2284 buf += size;
2285 count -= size;
2286 transferred += size;
2287 buffer->read_index += size;
2288
Liron Kuch229090d2012-10-30 17:47:50 +02002289 /*
2290 * after reading the end of the buffer, requeue it,
2291 * and set up for reading the next one
2292 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002293 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002294 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5bd73f82011-12-14 16:53:30 +02002295 if (tspp_queue_buffer(channel, buffer))
2296 pr_err("tspp: can't submit transfer");
2297 channel->locked = channel->read;
2298 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002299 }
2300 }
2301
2302 return transferred;
2303}
2304
2305static long tspp_ioctl(struct file *filp,
2306 unsigned int param0, unsigned long param1)
2307{
Joel Nider5bd73f82011-12-14 16:53:30 +02002308 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002309 int rc = -1;
2310 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002311 struct tspp_select_source ss;
2312 struct tspp_filter f;
2313 struct tspp_key k;
2314 struct tspp_iv iv;
2315 struct tspp_system_keys sk;
2316 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002317 channel = filp->private_data;
Joel Nider5bd73f82011-12-14 16:53:30 +02002318 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002319
2320 if (!param1)
2321 return -EINVAL;
2322
2323 switch (param0) {
2324 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002325 if (!access_ok(VERIFY_READ, param1,
2326 sizeof(struct tspp_select_source))) {
2327 return -EBUSY;
2328 }
2329 if (__copy_from_user(&ss, (void *)param1,
2330 sizeof(struct tspp_select_source)) == 0)
2331 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002332 break;
2333 case TSPP_IOCTL_ADD_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002334 if (!access_ok(VERIFY_READ, param1,
2335 sizeof(struct tspp_filter))) {
2336 return -ENOSR;
2337 }
2338 if (__copy_from_user(&f, (void *)param1,
2339 sizeof(struct tspp_filter)) == 0)
2340 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002341 break;
2342 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002343 if (!access_ok(VERIFY_READ, param1,
2344 sizeof(struct tspp_filter))) {
2345 return -EBUSY;
2346 }
2347 if (__copy_from_user(&f, (void *)param1,
2348 sizeof(struct tspp_filter)) == 0)
2349 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002350 break;
2351 case TSPP_IOCTL_SET_KEY:
Joel Nider5bd73f82011-12-14 16:53:30 +02002352 if (!access_ok(VERIFY_READ, param1,
2353 sizeof(struct tspp_key))) {
2354 return -EBUSY;
2355 }
2356 if (__copy_from_user(&k, (void *)param1,
2357 sizeof(struct tspp_key)) == 0)
2358 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002359 break;
2360 case TSPP_IOCTL_SET_IV:
Joel Nider5bd73f82011-12-14 16:53:30 +02002361 if (!access_ok(VERIFY_READ, param1,
2362 sizeof(struct tspp_iv))) {
2363 return -EBUSY;
2364 }
2365 if (__copy_from_user(&iv, (void *)param1,
2366 sizeof(struct tspp_iv)) == 0)
2367 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002368 break;
2369 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider5bd73f82011-12-14 16:53:30 +02002370 if (!access_ok(VERIFY_READ, param1,
2371 sizeof(struct tspp_system_keys))) {
2372 return -EINVAL;
2373 }
2374 if (__copy_from_user(&sk, (void *)param1,
2375 sizeof(struct tspp_system_keys)) == 0)
2376 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002377 break;
2378 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002379 if (!access_ok(VERIFY_READ, param1,
2380 sizeof(struct tspp_buffer))) {
2381 rc = -EINVAL;
2382 }
2383 if (__copy_from_user(&b, (void *)param1,
2384 sizeof(struct tspp_buffer)) == 0)
2385 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002386 break;
2387 default:
2388 pr_err("tspp: Unknown ioctl %i", param0);
2389 }
2390
Liron Kuch229090d2012-10-30 17:47:50 +02002391 /*
2392 * normalize the return code in case one of the subfunctions does
2393 * something weird
2394 */
Joel Nider5556a852011-10-16 10:52:13 +02002395 if (rc != 0)
Joel Nider5bd73f82011-12-14 16:53:30 +02002396 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002397
2398 return rc;
2399}
2400
2401/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002402static int debugfs_iomem_x32_set(void *data, u64 val)
2403{
2404 writel_relaxed(val, data);
2405 wmb();
2406 return 0;
2407}
2408
2409static int debugfs_iomem_x32_get(void *data, u64 *val)
2410{
2411 *val = readl_relaxed(data);
2412 return 0;
2413}
2414
2415DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2416 debugfs_iomem_x32_set, "0x%08llx");
2417
2418static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2419 int instance)
2420{
2421 char name[10];
2422 snprintf(name, 10, "tsif%i", instance);
2423 tsif_device->dent_tsif = debugfs_create_dir(
2424 name, NULL);
2425 if (tsif_device->dent_tsif) {
2426 int i;
2427 void __iomem *base = tsif_device->base;
2428 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2429 tsif_device->debugfs_tsif_regs[i] =
2430 debugfs_create_file(
2431 debugfs_tsif_regs[i].name,
2432 debugfs_tsif_regs[i].mode,
2433 tsif_device->dent_tsif,
2434 base + debugfs_tsif_regs[i].offset,
2435 &fops_iomem_x32);
2436 }
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002437
2438 debugfs_create_u32(
2439 "stat_rx_chunks",
2440 S_IRUGO|S_IWUGO,
2441 tsif_device->dent_tsif,
2442 &tsif_device->stat_rx);
2443
2444 debugfs_create_u32(
2445 "stat_overflow",
2446 S_IRUGO|S_IWUGO,
2447 tsif_device->dent_tsif,
2448 &tsif_device->stat_overflow);
2449
2450 debugfs_create_u32(
2451 "stat_lost_sync",
2452 S_IRUGO|S_IWUGO,
2453 tsif_device->dent_tsif,
2454 &tsif_device->stat_lost_sync);
2455
2456 debugfs_create_u32(
2457 "stat_timeout",
2458 S_IRUGO|S_IWUGO,
2459 tsif_device->dent_tsif,
2460 &tsif_device->stat_timeout);
2461
Joel Nider5556a852011-10-16 10:52:13 +02002462 }
2463}
2464
2465static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2466{
2467 if (tsif_device->dent_tsif) {
2468 int i;
2469 debugfs_remove_recursive(tsif_device->dent_tsif);
2470 tsif_device->dent_tsif = NULL;
2471 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2472 tsif_device->debugfs_tsif_regs[i] = NULL;
2473 }
2474}
2475
2476static void tspp_debugfs_init(struct tspp_device *device, int instance)
2477{
2478 char name[10];
2479 snprintf(name, 10, "tspp%i", instance);
2480 device->dent = debugfs_create_dir(
2481 name, NULL);
2482 if (device->dent) {
2483 int i;
2484 void __iomem *base = device->base;
2485 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2486 device->debugfs_regs[i] =
2487 debugfs_create_file(
2488 debugfs_tspp_regs[i].name,
2489 debugfs_tspp_regs[i].mode,
2490 device->dent,
2491 base + debugfs_tspp_regs[i].offset,
2492 &fops_iomem_x32);
2493 }
2494 }
2495}
2496
2497static void tspp_debugfs_exit(struct tspp_device *device)
2498{
2499 if (device->dent) {
2500 int i;
2501 debugfs_remove_recursive(device->dent);
2502 device->dent = NULL;
2503 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2504 device->debugfs_regs[i] = NULL;
2505 }
2506}
Joel Nider5556a852011-10-16 10:52:13 +02002507
2508static int __devinit msm_tspp_probe(struct platform_device *pdev)
2509{
2510 int rc = -ENODEV;
2511 u32 version;
Liron Kuch229090d2012-10-30 17:47:50 +02002512 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002513 struct msm_tspp_platform_data *data;
2514 struct tspp_device *device;
2515 struct resource *mem_tsif0;
2516 struct resource *mem_tsif1;
2517 struct resource *mem_tspp;
2518 struct resource *mem_bam;
Liron Kuch229090d2012-10-30 17:47:50 +02002519 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002520
2521 /* must have platform data */
2522 data = pdev->dev.platform_data;
2523 if (!data) {
2524 pr_err("tspp: Platform data not available");
2525 rc = -EINVAL;
2526 goto out;
2527 }
2528
2529 /* check for valid device id */
Joel Nider5bd73f82011-12-14 16:53:30 +02002530 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002531 pr_err("tspp: Invalid device ID %d", pdev->id);
2532 rc = -EINVAL;
2533 goto out;
2534 }
2535
2536 /* OK, we will use this device */
2537 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2538 if (!device) {
2539 pr_err("tspp: Failed to allocate memory for device");
2540 rc = -ENOMEM;
2541 goto out;
2542 }
2543
2544 /* set up references */
2545 device->pdev = pdev;
2546 platform_set_drvdata(pdev, device);
2547
2548 /* map clocks */
2549 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002550 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02002551 if (IS_ERR(device->tsif_pclk)) {
2552 pr_err("tspp: failed to get %s",
2553 data->tsif_pclk);
2554 rc = PTR_ERR(device->tsif_pclk);
2555 device->tsif_pclk = NULL;
2556 goto err_pclock;
2557 }
2558 }
2559 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002560 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02002561 if (IS_ERR(device->tsif_ref_clk)) {
2562 pr_err("tspp: failed to get %s",
2563 data->tsif_ref_clk);
2564 rc = PTR_ERR(device->tsif_ref_clk);
2565 device->tsif_ref_clk = NULL;
2566 goto err_refclock;
2567 }
2568 }
2569
2570 /* map I/O memory */
2571 mem_tsif0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2572 if (!mem_tsif0) {
2573 pr_err("tspp: Missing tsif0 MEM resource");
2574 rc = -ENXIO;
2575 goto err_res_tsif0;
2576 }
2577 device->tsif[0].base = ioremap(mem_tsif0->start,
2578 resource_size(mem_tsif0));
2579 if (!device->tsif[0].base) {
2580 pr_err("tspp: ioremap failed");
2581 goto err_map_tsif0;
2582 }
2583
2584 mem_tsif1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2585 if (!mem_tsif1) {
2586 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
2587 rc = -ENXIO;
2588 goto err_res_tsif1;
2589 }
2590 device->tsif[1].base = ioremap(mem_tsif1->start,
2591 resource_size(mem_tsif1));
2592 if (!device->tsif[1].base) {
2593 dev_err(&pdev->dev, "ioremap failed");
2594 goto err_map_tsif1;
2595 }
2596
2597 mem_tspp = platform_get_resource(pdev, IORESOURCE_MEM, 2);
2598 if (!mem_tspp) {
2599 dev_err(&pdev->dev, "Missing MEM resource");
2600 rc = -ENXIO;
2601 goto err_res_dev;
2602 }
2603 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
2604 if (!device->base) {
2605 dev_err(&pdev->dev, "ioremap failed");
2606 goto err_map_dev;
2607 }
2608
2609 mem_bam = platform_get_resource(pdev, IORESOURCE_MEM, 3);
2610 if (!mem_bam) {
2611 pr_err("tspp: Missing bam MEM resource");
2612 rc = -ENXIO;
2613 goto err_res_bam;
2614 }
2615 memset(&device->bam_props, 0, sizeof(device->bam_props));
2616 device->bam_props.phys_addr = mem_bam->start;
2617 device->bam_props.virt_addr = ioremap(mem_bam->start,
2618 resource_size(mem_bam));
2619 if (!device->bam_props.virt_addr) {
2620 dev_err(&pdev->dev, "ioremap failed");
2621 goto err_map_bam;
2622 }
2623
2624 /* map TSPP IRQ */
2625 rc = platform_get_irq(pdev, 0);
2626 if (rc > 0) {
2627 device->tspp_irq = rc;
2628 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
2629 dev_name(&pdev->dev), device);
2630 if (rc) {
2631 dev_err(&pdev->dev, "failed to request IRQ %d : %d",
2632 device->tspp_irq, rc);
2633 goto err_irq;
2634 }
2635 } else {
2636 dev_err(&pdev->dev, "failed to get tspp IRQ");
2637 goto err_irq;
2638 }
2639
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002640 /* map TSIF IRQs */
2641 device->tsif[0].tsif_irq = TSIF1_IRQ;
2642 device->tsif[1].tsif_irq = TSIF2_IRQ;
2643
2644 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
2645 rc = request_irq(device->tsif[i].tsif_irq,
2646 tsif_isr, IRQF_SHARED,
2647 dev_name(&pdev->dev), &device->tsif[i]);
2648 if (rc) {
2649 dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
2650 i, rc);
2651 device->tsif[i].tsif_irq = 0;
2652 }
2653 }
2654
Joel Nider5556a852011-10-16 10:52:13 +02002655 /* BAM IRQ */
2656 device->bam_irq = TSIF_BAM_IRQ;
2657
2658 /* GPIOs */
2659 rc = tspp_start_gpios(device);
2660 if (rc)
2661 goto err_gpio;
2662
2663 /* power management */
2664 pm_runtime_set_active(&pdev->dev);
2665 pm_runtime_enable(&pdev->dev);
2666
Joel Nider5556a852011-10-16 10:52:13 +02002667 tspp_debugfs_init(device, 0);
2668
2669 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2670 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02002671
2672 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
2673 dev_name(&pdev->dev));
2674
2675 /* set up pointers to ram-based 'registers' */
Joel Nider5bd73f82011-12-14 16:53:30 +02002676 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
2677 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
2678 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
2679 device->tspp_key_table = device->base + TSPP_DATA_KEY;
2680 device->tspp_global_performance =
2681 device->base + TSPP_GLOBAL_PERFORMANCE;
2682 device->tspp_pipe_context =
2683 device->base + TSPP_PIPE_CONTEXT;
2684 device->tspp_pipe_performance =
2685 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02002686
2687 device->bam_props.summing_threshold = 0x10;
2688 device->bam_props.irq = device->bam_irq;
2689 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
2690
2691 if (sps_register_bam_device(&device->bam_props,
2692 &device->bam_handle) != 0) {
2693 pr_err("tspp: failed to register bam");
2694 goto err_bam;
2695 }
2696
Joel Nider5bd73f82011-12-14 16:53:30 +02002697 if (tspp_clock_start(device) != 0) {
2698 dev_err(&pdev->dev, "Can't start clocks");
2699 goto err_clock;
Joel Nider5556a852011-10-16 10:52:13 +02002700 }
2701
2702 spin_lock_init(&device->spinlock);
2703 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
2704 (unsigned long)device);
2705
2706 /* initialize everything to a known state */
2707 tspp_global_reset(device);
2708
2709 version = readl_relaxed(device->base + TSPP_VERSION);
2710 if (version != 1)
2711 pr_warn("tspp: unrecognized hw version=%i", version);
2712
Joel Nider5bd73f82011-12-14 16:53:30 +02002713 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02002714 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002715 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
2716 pr_err("tspp_channel_init failed");
2717 goto err_channel;
2718 }
Joel Nider5556a852011-10-16 10:52:13 +02002719 }
2720
Joel Nider5bd73f82011-12-14 16:53:30 +02002721 /* stop the clocks for power savings */
2722 tspp_clock_stop(device);
2723
2724 /* everything is ok, so add the device to the list */
2725 list_add_tail(&(device->devlist), &tspp_devices);
2726
Joel Nider5556a852011-10-16 10:52:13 +02002727 return 0;
2728
Joel Nider5bd73f82011-12-14 16:53:30 +02002729err_channel:
Liron Kuch229090d2012-10-30 17:47:50 +02002730 /* uninitialize channels */
2731 for (j = 0; j < i; j++) {
2732 channel = &(device->channels[i]);
2733 device_destroy(tspp_class, channel->cdev.dev);
2734 cdev_del(&channel->cdev);
2735 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002736err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02002737 sps_deregister_bam_device(device->bam_handle);
2738err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02002739 tspp_debugfs_exit(device);
2740 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2741 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02002742err_gpio:
2743err_irq:
2744 tspp_stop_gpios(device);
2745 iounmap(device->bam_props.virt_addr);
2746err_map_bam:
2747err_res_bam:
2748 iounmap(device->base);
2749err_map_dev:
2750err_res_dev:
2751 iounmap(device->tsif[1].base);
2752err_map_tsif1:
2753err_res_tsif1:
2754 iounmap(device->tsif[0].base);
2755err_map_tsif0:
2756err_res_tsif0:
2757 if (device->tsif_ref_clk)
2758 clk_put(device->tsif_ref_clk);
2759err_refclock:
2760 if (device->tsif_pclk)
2761 clk_put(device->tsif_pclk);
2762err_pclock:
2763 kfree(device);
2764
2765out:
2766 return rc;
2767}
2768
2769static int __devexit msm_tspp_remove(struct platform_device *pdev)
2770{
Joel Nider5bd73f82011-12-14 16:53:30 +02002771 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002772 u32 i;
Joel Nider5556a852011-10-16 10:52:13 +02002773
2774 struct tspp_device *device = platform_get_drvdata(pdev);
2775
Joel Nider5bd73f82011-12-14 16:53:30 +02002776 /* free the buffers, and delete the channels */
2777 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
2778 channel = &device->channels[i];
2779 tspp_close_channel(device->pdev->id, i);
2780 device_destroy(tspp_class, channel->cdev.dev);
2781 cdev_del(&channel->cdev);
2782 }
2783
Joel Nider5556a852011-10-16 10:52:13 +02002784 sps_deregister_bam_device(device->bam_handle);
2785
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002786 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
Joel Nider5556a852011-10-16 10:52:13 +02002787 tsif_debugfs_exit(&device->tsif[i]);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002788 if (device->tsif[i].tsif_irq)
2789 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
2790 }
Joel Nider5556a852011-10-16 10:52:13 +02002791
2792 wake_lock_destroy(&device->wake_lock);
2793 free_irq(device->tspp_irq, device);
2794 tspp_stop_gpios(device);
2795
2796 iounmap(device->bam_props.virt_addr);
2797 iounmap(device->base);
2798 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2799 iounmap(device->tsif[i].base);
2800
2801 if (device->tsif_ref_clk)
2802 clk_put(device->tsif_ref_clk);
2803
2804 if (device->tsif_pclk)
2805 clk_put(device->tsif_pclk);
2806
2807 pm_runtime_disable(&pdev->dev);
2808 pm_runtime_put(&pdev->dev);
2809 kfree(device);
2810
2811 return 0;
2812}
2813
2814/*** power management ***/
2815
2816static int tspp_runtime_suspend(struct device *dev)
2817{
2818 dev_dbg(dev, "pm_runtime: suspending...");
2819 return 0;
2820}
2821
2822static int tspp_runtime_resume(struct device *dev)
2823{
2824 dev_dbg(dev, "pm_runtime: resuming...");
2825 return 0;
2826}
2827
2828static const struct dev_pm_ops tspp_dev_pm_ops = {
2829 .runtime_suspend = tspp_runtime_suspend,
2830 .runtime_resume = tspp_runtime_resume,
2831};
2832
2833static struct platform_driver msm_tspp_driver = {
2834 .probe = msm_tspp_probe,
2835 .remove = __exit_p(msm_tspp_remove),
2836 .driver = {
2837 .name = "msm_tspp",
2838 .pm = &tspp_dev_pm_ops,
2839 },
2840};
2841
2842
2843static int __init mod_init(void)
2844{
Joel Nider5556a852011-10-16 10:52:13 +02002845 int rc;
2846
Joel Nider5bd73f82011-12-14 16:53:30 +02002847 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02002848 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
2849 if (rc) {
2850 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
2851 goto err_devrgn;
2852 }
2853
2854 tspp_class = class_create(THIS_MODULE, "tspp");
2855 if (IS_ERR(tspp_class)) {
2856 rc = PTR_ERR(tspp_class);
2857 pr_err("tspp: Error creating class: %d", rc);
2858 goto err_class;
2859 }
2860
Joel Nider5bd73f82011-12-14 16:53:30 +02002861 /* register the driver, and check hardware */
2862 rc = platform_driver_register(&msm_tspp_driver);
2863 if (rc) {
2864 pr_err("tspp: platform_driver_register failed: %d", rc);
2865 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02002866 }
2867
2868 return 0;
2869
Joel Nider5bd73f82011-12-14 16:53:30 +02002870err_register:
2871 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02002872err_class:
2873 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
2874err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02002875 return rc;
2876}
2877
2878static void __exit mod_exit(void)
2879{
Joel Nider5bd73f82011-12-14 16:53:30 +02002880 /* delete low level driver */
2881 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02002882
Joel Nider5bd73f82011-12-14 16:53:30 +02002883 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02002884 class_destroy(tspp_class);
2885 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02002886}
2887
2888module_init(mod_init);
2889module_exit(mod_exit);
2890
Joel Nider5bd73f82011-12-14 16:53:30 +02002891MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02002892MODULE_LICENSE("GPL v2");