blob: f6aa9cc29f4fe9ed84c2cf13d3ef4709508487fd [file] [log] [blame]
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Joel Nider5556a852011-10-16 10:52:13 +02002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Joel Nider5bd73f82011-12-14 16:53:30 +020013#include <linux/module.h> /* Just for modules */
14#include <linux/kernel.h> /* Only for KERN_INFO */
15#include <linux/err.h> /* Error macros */
16#include <linux/list.h> /* Linked list */
Joel Nider5556a852011-10-16 10:52:13 +020017#include <linux/cdev.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020018#include <linux/init.h> /* Needed for the macros */
19#include <linux/io.h> /* IO macros */
20#include <linux/device.h> /* Device drivers need this */
21#include <linux/sched.h> /* Externally defined globals */
22#include <linux/pm_runtime.h> /* Runtime power management */
Joel Nider5556a852011-10-16 10:52:13 +020023#include <linux/fs.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020024#include <linux/uaccess.h> /* copy_to_user */
Joel Nider5556a852011-10-16 10:52:13 +020025#include <linux/slab.h> /* kfree, kzalloc */
Joel Nider5bd73f82011-12-14 16:53:30 +020026#include <linux/ioport.h> /* XXX_ mem_region */
27#include <linux/dma-mapping.h> /* dma_XXX */
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +020028#include <linux/dmapool.h> /* DMA pools */
Joel Nider5bd73f82011-12-14 16:53:30 +020029#include <linux/delay.h> /* msleep */
30#include <linux/platform_device.h>
Joel Nider5556a852011-10-16 10:52:13 +020031#include <linux/clk.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020032#include <linux/poll.h> /* poll() file op */
33#include <linux/wait.h> /* wait() macros, sleeping */
34#include <linux/tspp.h> /* tspp functions */
Joel Nider5556a852011-10-16 10:52:13 +020035#include <linux/bitops.h> /* BIT() macro */
Joel Nider5bd73f82011-12-14 16:53:30 +020036#include <mach/sps.h> /* BAM stuff */
Joel Nider5556a852011-10-16 10:52:13 +020037#include <mach/gpio.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020038#include <linux/wakelock.h> /* Locking functions */
Hamad Kadmany567bed82012-11-29 14:15:57 +020039#include <linux/timer.h> /* Timer services */
40#include <linux/jiffies.h> /* Jiffies counter */
Joel Nider5556a852011-10-16 10:52:13 +020041#include <mach/dma.h>
42#include <mach/msm_tspp.h>
Joel Nider5556a852011-10-16 10:52:13 +020043#include <linux/debugfs.h>
Liron Kuch8fa85b02013-01-01 18:29:47 +020044#include <linux/of.h>
45#include <linux/of_gpio.h>
Liron Kuch65067fa2013-02-10 15:19:32 +020046#include <linux/string.h>
Joel Nider5556a852011-10-16 10:52:13 +020047
48/*
49 * General defines
50 */
Joel Nider5556a852011-10-16 10:52:13 +020051#define TSPP_TSIF_INSTANCES 2
Liron Kuch65067fa2013-02-10 15:19:32 +020052#define TSPP_GPIOS_PER_TSIF 4
Joel Nider5556a852011-10-16 10:52:13 +020053#define TSPP_FILTER_TABLES 3
Joel Nider5bd73f82011-12-14 16:53:30 +020054#define TSPP_MAX_DEVICES 1
Joel Nider5556a852011-10-16 10:52:13 +020055#define TSPP_NUM_CHANNELS 16
56#define TSPP_NUM_PRIORITIES 16
57#define TSPP_NUM_KEYS 8
58#define INVALID_CHANNEL 0xFFFFFFFF
Hamad Kadmany567bed82012-11-29 14:15:57 +020059
60/*
61 * BAM descriptor FIFO size (in number of descriptors).
62 * Max number of descriptors allowed by SPS which is 8K-1.
Hamad Kadmany567bed82012-11-29 14:15:57 +020063 */
Hamad Kadmany45f3f062013-05-22 15:40:38 +030064#define TSPP_SPS_DESCRIPTOR_COUNT (8 * 1024 - 1)
Joel Nider5556a852011-10-16 10:52:13 +020065#define TSPP_PACKET_LENGTH 188
66#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
Hamad Kadmany567bed82012-11-29 14:15:57 +020067
68/* Max descriptor buffer size allowed by SPS */
69#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
70
71/*
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +020072 * Returns whether to use DMA pool for TSPP output buffers.
73 * For buffers smaller than page size, using DMA pool
74 * provides better memory utilization as dma_alloc_coherent
75 * allocates minimum of page size.
76 */
77#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE)
78
79/*
Hamad Kadmany567bed82012-11-29 14:15:57 +020080 * Max allowed TSPP buffers/descriptors.
81 * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
82 */
83#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
Joel Nider5556a852011-10-16 10:52:13 +020084#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
85#define SPS_DESCRIPTOR_SIZE 8
86#define MIN_ACCEPTABLE_BUFFER_COUNT 2
Joel Nider5bd73f82011-12-14 16:53:30 +020087#define TSPP_DEBUG(msg...)
Joel Nider5556a852011-10-16 10:52:13 +020088
89/*
90 * TSIF register offsets
91 */
92#define TSIF_STS_CTL_OFF (0x0)
93#define TSIF_TIME_LIMIT_OFF (0x4)
94#define TSIF_CLK_REF_OFF (0x8)
95#define TSIF_LPBK_FLAGS_OFF (0xc)
96#define TSIF_LPBK_DATA_OFF (0x10)
97#define TSIF_TEST_CTL_OFF (0x14)
98#define TSIF_TEST_MODE_OFF (0x18)
99#define TSIF_TEST_RESET_OFF (0x1c)
100#define TSIF_TEST_EXPORT_OFF (0x20)
101#define TSIF_TEST_CURRENT_OFF (0x24)
102
103#define TSIF_DATA_PORT_OFF (0x100)
104
105/* bits for TSIF_STS_CTL register */
106#define TSIF_STS_CTL_EN_IRQ BIT(28)
107#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
108#define TSIF_STS_CTL_1ST_PACKET BIT(26)
109#define TSIF_STS_CTL_OVERFLOW BIT(25)
110#define TSIF_STS_CTL_LOST_SYNC BIT(24)
111#define TSIF_STS_CTL_TIMEOUT BIT(23)
112#define TSIF_STS_CTL_INV_SYNC BIT(21)
113#define TSIF_STS_CTL_INV_NULL BIT(20)
114#define TSIF_STS_CTL_INV_ERROR BIT(19)
115#define TSIF_STS_CTL_INV_ENABLE BIT(18)
116#define TSIF_STS_CTL_INV_DATA BIT(17)
117#define TSIF_STS_CTL_INV_CLOCK BIT(16)
118#define TSIF_STS_CTL_SPARE BIT(15)
119#define TSIF_STS_CTL_EN_NULL BIT(11)
120#define TSIF_STS_CTL_EN_ERROR BIT(10)
121#define TSIF_STS_CTL_LAST_BIT BIT(9)
122#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
123#define TSIF_STS_CTL_EN_TCR BIT(7)
124#define TSIF_STS_CTL_TEST_MODE BIT(6)
Joel Nider5bd73f82011-12-14 16:53:30 +0200125#define TSIF_STS_CTL_MODE_2 BIT(5)
Joel Nider5556a852011-10-16 10:52:13 +0200126#define TSIF_STS_CTL_EN_DM BIT(4)
127#define TSIF_STS_CTL_STOP BIT(3)
128#define TSIF_STS_CTL_START BIT(0)
129
130/*
131 * TSPP register offsets
132 */
Liron Kuch229090d2012-10-30 17:47:50 +0200133#define TSPP_RST 0x00
Joel Nider5556a852011-10-16 10:52:13 +0200134#define TSPP_CLK_CONTROL 0x04
Liron Kuch229090d2012-10-30 17:47:50 +0200135#define TSPP_CONFIG 0x08
136#define TSPP_CONTROL 0x0C
Joel Nider5556a852011-10-16 10:52:13 +0200137#define TSPP_PS_DISABLE 0x10
Liron Kuch229090d2012-10-30 17:47:50 +0200138#define TSPP_MSG_IRQ_STATUS 0x14
Joel Nider5556a852011-10-16 10:52:13 +0200139#define TSPP_MSG_IRQ_MASK 0x18
140#define TSPP_IRQ_STATUS 0x1C
141#define TSPP_IRQ_MASK 0x20
142#define TSPP_IRQ_CLEAR 0x24
143#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2))
Liron Kuch229090d2012-10-30 17:47:50 +0200144#define TSPP_STATUS 0x68
145#define TSPP_CURR_TSP_HEADER 0x6C
146#define TSPP_CURR_PID_FILTER 0x70
147#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2))
148#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2))
149#define TSPP_DATA_KEY_RESET 0x9C
Joel Nider5556a852011-10-16 10:52:13 +0200150#define TSPP_KEY_VALID 0xA0
151#define TSPP_KEY_ERROR 0xA4
152#define TSPP_TEST_CTRL 0xA8
Liron Kuch229090d2012-10-30 17:47:50 +0200153#define TSPP_VERSION 0xAC
Joel Nider5556a852011-10-16 10:52:13 +0200154#define TSPP_GENERICS 0xB0
Liron Kuch229090d2012-10-30 17:47:50 +0200155#define TSPP_NOP 0xB4
Joel Nider5556a852011-10-16 10:52:13 +0200156
157/*
158 * Register bit definitions
159 */
160/* TSPP_RST */
161#define TSPP_RST_RESET BIT(0)
162
163/* TSPP_CLK_CONTROL */
164#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9)
165#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8)
166#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7)
167#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6)
168#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5)
169#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
170#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3)
171#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
172#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
173#define TSPP_CLK_CONTROL_SET_CLKON BIT(0)
174
175/* TSPP_CONFIG */
176#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
177((_b & 0xF) << 8))
178#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
179#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7)
180#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6)
181#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5)
182#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
183#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3)
184#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2)
185#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1)
186#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0)
187
188/* TSPP_CONTROL */
189#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5)
190#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4)
191#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3)
192#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2)
193#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1)
194#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0)
195
196/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
197#define TSPP_MSG_TSPP_IRQ BIT(2)
198#define TSPP_MSG_TSIF_1_IRQ BIT(1)
199#define TSPP_MSG_TSIF_0_IRQ BIT(0)
200
201/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
Liron Kuch229090d2012-10-30 17:47:50 +0200202#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19)
203#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18)
Joel Nider5556a852011-10-16 10:52:13 +0200204#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17)
205#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16)
206#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n))
207
208/* TSPP_PIPE_ERROR_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200209#define TSPP_PIPE_PES_SYNC_ERROR BIT(3)
210#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2)
Joel Nider5556a852011-10-16 10:52:13 +0200211#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1)
Liron Kuch229090d2012-10-30 17:47:50 +0200212#define TSPP_PIP_PS_LOST_START BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200213
214/* TSPP_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200215#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10)
216#define TSPP_STATUS_TSIF1_DM_REQ BIT(6)
217#define TSPP_STATUS_TSIF0_DM_REQ BIT(2)
218#define TSPP_CURR_FILTER_TABLE BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200219
220/* TSPP_GENERICS */
Liron Kuch229090d2012-10-30 17:47:50 +0200221#define TSPP_GENERICS_CRYPTO_GEN BIT(12)
Joel Nider5556a852011-10-16 10:52:13 +0200222#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7)
Liron Kuch229090d2012-10-30 17:47:50 +0200223#define TSPP_GENERICS_MAX_PIPES BIT(2)
224#define TSPP_GENERICS_TSIF_1_GEN BIT(1)
225#define TSPP_GENERICS_TSIF_0_GEN BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200226
227/*
228 * TSPP memory regions
229 */
230#define TSPP_PID_FILTER_TABLE0 0x800
231#define TSPP_PID_FILTER_TABLE1 0x880
232#define TSPP_PID_FILTER_TABLE2 0x900
233#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */
234#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */
235#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */
236#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
237#define TSPP_DATA_KEY 0xCD0
238
Joel Nider5556a852011-10-16 10:52:13 +0200239struct debugfs_entry {
240 const char *name;
241 mode_t mode;
242 int offset;
243};
244
245static const struct debugfs_entry debugfs_tsif_regs[] = {
246 {"sts_ctl", S_IRUGO | S_IWUSR, TSIF_STS_CTL_OFF},
247 {"time_limit", S_IRUGO | S_IWUSR, TSIF_TIME_LIMIT_OFF},
248 {"clk_ref", S_IRUGO | S_IWUSR, TSIF_CLK_REF_OFF},
249 {"lpbk_flags", S_IRUGO | S_IWUSR, TSIF_LPBK_FLAGS_OFF},
250 {"lpbk_data", S_IRUGO | S_IWUSR, TSIF_LPBK_DATA_OFF},
251 {"test_ctl", S_IRUGO | S_IWUSR, TSIF_TEST_CTL_OFF},
252 {"test_mode", S_IRUGO | S_IWUSR, TSIF_TEST_MODE_OFF},
253 {"test_reset", S_IWUSR, TSIF_TEST_RESET_OFF},
254 {"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
255 {"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
256 {"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
257};
258
259static const struct debugfs_entry debugfs_tspp_regs[] = {
260 {"rst", S_IRUGO | S_IWUSR, TSPP_RST},
261 {"clk_control", S_IRUGO | S_IWUSR, TSPP_CLK_CONTROL},
262 {"config", S_IRUGO | S_IWUSR, TSPP_CONFIG},
263 {"control", S_IRUGO | S_IWUSR, TSPP_CONTROL},
264 {"ps_disable", S_IRUGO | S_IWUSR, TSPP_PS_DISABLE},
265 {"msg_irq_status", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_STATUS},
266 {"msg_irq_mask", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_MASK},
267 {"irq_status", S_IRUGO | S_IWUSR, TSPP_IRQ_STATUS},
268 {"irq_mask", S_IRUGO | S_IWUSR, TSPP_IRQ_MASK},
269 {"irq_clear", S_IRUGO | S_IWUSR, TSPP_IRQ_CLEAR},
270 /* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
271 {"status", S_IRUGO | S_IWUSR, TSPP_STATUS},
272 {"curr_tsp_header", S_IRUGO | S_IWUSR, TSPP_CURR_TSP_HEADER},
273 {"curr_pid_filter", S_IRUGO | S_IWUSR, TSPP_CURR_PID_FILTER},
274 /* {"system_key", S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
275 /* {"cbc_init_val", S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
276 {"data_key_reset", S_IRUGO | S_IWUSR, TSPP_DATA_KEY_RESET},
277 {"key_valid", S_IRUGO | S_IWUSR, TSPP_KEY_VALID},
278 {"key_error", S_IRUGO | S_IWUSR, TSPP_KEY_ERROR},
279 {"test_ctrl", S_IRUGO | S_IWUSR, TSPP_TEST_CTRL},
280 {"version", S_IRUGO | S_IWUSR, TSPP_VERSION},
281 {"generics", S_IRUGO | S_IWUSR, TSPP_GENERICS},
282 {"pid_filter_table0", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE0},
283 {"pid_filter_table1", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE1},
284 {"pid_filter_table2", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE2},
285 {"global_performance", S_IRUGO | S_IWUSR, TSPP_GLOBAL_PERFORMANCE},
286 {"pipe_context", S_IRUGO | S_IWUSR, TSPP_PIPE_CONTEXT},
287 {"pipe_performance", S_IRUGO | S_IWUSR, TSPP_PIPE_PERFORMANCE},
288 {"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
289};
290
Joel Nider5556a852011-10-16 10:52:13 +0200291struct tspp_pid_filter {
292 u32 filter; /* see FILTER_ macros */
293 u32 config; /* see FILTER_ macros */
294};
295
296/* tsp_info */
297#define FILTER_HEADER_ERROR_MASK BIT(7)
298#define FILTER_TRANS_END_DISABLE BIT(6)
299#define FILTER_DEC_ON_ERROR_EN BIT(5)
300#define FILTER_DECRYPT BIT(4)
301#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT)
302#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF)
303#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \
304 (_p->config & ~0xF) | (_b & 0xF))
305#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3)
306#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \
307 (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
308#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF)
309#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \
310 (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
311#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF)
312#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \
313 (_p->filter & ~0x1FFF) | (_b & 0x1FFF))
314#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3)
315#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \
316 (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
317#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7)
318#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \
319 (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
320
321struct tspp_global_performance_regs {
322 u32 tsp_total;
323 u32 tsp_ignored;
324 u32 tsp_error;
325 u32 tsp_sync;
326};
327
328struct tspp_pipe_context_regs {
329 u16 pes_bytes_left;
330 u16 count;
331 u32 tsif_suffix;
332} __packed;
333#define CONTEXT_GET_STATE(_a) (_a & 0x3)
334#define CONTEXT_UNSPEC_LENGTH BIT(11)
335#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
336
Hamad Kadmany567bed82012-11-29 14:15:57 +0200337#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
338
Joel Nider5556a852011-10-16 10:52:13 +0200339struct tspp_pipe_performance_regs {
340 u32 tsp_total;
341 u32 ps_duplicate_tsp;
342 u32 tsp_no_payload;
343 u32 tsp_broken_ps;
344 u32 ps_total_num;
345 u32 ps_continuity_error;
346 u32 ps_length_error;
347 u32 pes_sync_error;
348};
349
350struct tspp_tsif_device {
351 void __iomem *base;
352 u32 time_limit;
353 u32 ref_count;
Joel Nider5bd73f82011-12-14 16:53:30 +0200354 enum tspp_tsif_mode mode;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200355 int clock_inverse;
356 int data_inverse;
357 int sync_inverse;
358 int enable_inverse;
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200359 u32 tsif_irq;
Joel Nider5556a852011-10-16 10:52:13 +0200360
361 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200362 struct dentry *dent_tsif;
363 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200364 u32 stat_rx;
365 u32 stat_overflow;
366 u32 stat_lost_sync;
367 u32 stat_timeout;
Joel Nider5556a852011-10-16 10:52:13 +0200368};
369
370enum tspp_buf_state {
371 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
372 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider5bd73f82011-12-14 16:53:30 +0200373 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
374 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200375};
376
377struct tspp_mem_buffer {
Joel Nider5bd73f82011-12-14 16:53:30 +0200378 struct tspp_mem_buffer *next;
379 struct sps_mem_buffer sps;
380 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200381 enum tspp_buf_state state;
382 size_t filled; /* how much data this buffer is holding */
383 int read_index; /* where to start reading data from */
384};
385
386/* this represents each char device 'channel' */
387struct tspp_channel {
388 struct cdev cdev;
389 struct device *dd;
Joel Nider5bd73f82011-12-14 16:53:30 +0200390 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200391 struct sps_pipe *pipe;
392 struct sps_connect config;
393 struct sps_register_event event;
Joel Nider5bd73f82011-12-14 16:53:30 +0200394 struct tspp_mem_buffer *data; /* list of buffers */
395 struct tspp_mem_buffer *read; /* first buffer ready to be read */
396 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
397 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200398 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider5bd73f82011-12-14 16:53:30 +0200399 u32 id; /* channel id (0-15) */
400 int used; /* is this channel in use? */
401 int key; /* which encryption key index is used */
402 u32 buffer_size; /* size of the sps transfer buffers */
403 u32 max_buffers; /* how many buffers should be allocated */
404 u32 buffer_count; /* how many buffers are actually allocated */
405 u32 filter_count; /* how many filters have been added to this channel */
406 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200407 enum tspp_source src;
408 enum tspp_mode mode;
Joel Nider5bd73f82011-12-14 16:53:30 +0200409 tspp_notifier *notifier; /* used only with kernel api */
410 void *notify_data; /* data to be passed with the notifier */
Hamad Kadmany567bed82012-11-29 14:15:57 +0200411 u32 expiration_period_ms; /* notification on partially filled buffers */
412 struct timer_list expiration_timer;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200413 struct dma_pool *dma_pool;
Liron Kuch229090d2012-10-30 17:47:50 +0200414 tspp_memfree *memfree; /* user defined memory free function */
415 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200416};
417
418struct tspp_pid_filter_table {
419 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
420};
421
422struct tspp_key_entry {
423 u32 even_lsb;
424 u32 even_msb;
425 u32 odd_lsb;
426 u32 odd_msb;
427};
428
429struct tspp_key_table {
430 struct tspp_key_entry entry[TSPP_NUM_KEYS];
431};
432
Joel Nider5bd73f82011-12-14 16:53:30 +0200433/* this represents the actual hardware device */
434struct tspp_device {
435 struct list_head devlist; /* list of all devices */
436 struct platform_device *pdev;
437 void __iomem *base;
438 unsigned int tspp_irq;
439 unsigned int bam_irq;
440 u32 bam_handle;
441 struct sps_bam_props bam_props;
442 struct wake_lock wake_lock;
443 spinlock_t spinlock;
444 struct tasklet_struct tlet;
445 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
446 /* clocks */
447 struct clk *tsif_pclk;
448 struct clk *tsif_ref_clk;
449 /* data */
450 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
451 struct tspp_channel channels[TSPP_NUM_CHANNELS];
452 struct tspp_key_table *tspp_key_table;
453 struct tspp_global_performance_regs *tspp_global_performance;
454 struct tspp_pipe_context_regs *tspp_pipe_context;
455 struct tspp_pipe_performance_regs *tspp_pipe_performance;
456
457 struct dentry *dent;
458 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
459};
460
461
Joel Nider5556a852011-10-16 10:52:13 +0200462static struct class *tspp_class;
463static int tspp_key_entry;
464static dev_t tspp_minor; /* next minor number to assign */
Joel Nider5bd73f82011-12-14 16:53:30 +0200465
466static LIST_HEAD(tspp_devices);
467
468/* forward declarations */
469static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
470static ssize_t tspp_open(struct inode *inode, struct file *filp);
471static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
472static ssize_t tspp_release(struct inode *inode, struct file *filp);
473static long tspp_ioctl(struct file *, unsigned int, unsigned long);
474
475/* file operations */
476static const struct file_operations tspp_fops = {
477 .owner = THIS_MODULE,
478 .read = tspp_read,
479 .open = tspp_open,
480 .poll = tspp_poll,
481 .release = tspp_release,
482 .unlocked_ioctl = tspp_ioctl,
483};
Joel Nider5556a852011-10-16 10:52:13 +0200484
485/*** IRQ ***/
Joel Nider5bd73f82011-12-14 16:53:30 +0200486static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200487{
Joel Nider5bd73f82011-12-14 16:53:30 +0200488 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200489 u32 status, mask;
490 u32 data;
491
492 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
493 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
494 status &= mask;
495
496 if (!status) {
497 dev_warn(&device->pdev->dev, "Spurious interrupt");
498 return IRQ_NONE;
499 }
500
501 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
502
503 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
504 /* read the key error info */
505 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
506 dev_info(&device->pdev->dev, "key error 0x%x", data);
507 }
508 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
509 data = readl_relaxed(device->base + TSPP_KEY_VALID);
510 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
511 }
512 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
513 dev_info(&device->pdev->dev, "key switched");
514
515 if (status & 0xffff)
Joel Nider5bd73f82011-12-14 16:53:30 +0200516 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200517
518 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200519
520 /*
521 * Before returning IRQ_HANDLED to the generic interrupt handling
522 * framework need to make sure all operations including clearing of
523 * interrupt status registers in the hardware is performed.
524 * Thus a barrier after clearing the interrupt status register
525 * is required to guarantee that the interrupt status register has
526 * really been cleared by the time we return from this handler.
527 */
528 wmb();
529 return IRQ_HANDLED;
530}
531
532static irqreturn_t tsif_isr(int irq, void *dev)
533{
534 struct tspp_tsif_device *tsif_device = dev;
535 u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
536
537 if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
538 TSIF_STS_CTL_OVERFLOW |
539 TSIF_STS_CTL_LOST_SYNC |
540 TSIF_STS_CTL_TIMEOUT)))
541 return IRQ_NONE;
542
543 if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
544 tsif_device->stat_overflow++;
545
546 if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
547 tsif_device->stat_lost_sync++;
548
549 if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
550 tsif_device->stat_timeout++;
551
552 iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
553
554 /*
555 * Before returning IRQ_HANDLED to the generic interrupt handling
556 * framework need to make sure all operations including clearing of
557 * interrupt status registers in the hardware is performed.
558 * Thus a barrier after clearing the interrupt status register
559 * is required to guarantee that the interrupt status register has
560 * really been cleared by the time we return from this handler.
561 */
Joel Nider5556a852011-10-16 10:52:13 +0200562 wmb();
563 return IRQ_HANDLED;
564}
565
566/*** callbacks ***/
567static void tspp_sps_complete_cb(struct sps_event_notify *notify)
568{
Joel Nider5bd73f82011-12-14 16:53:30 +0200569 struct tspp_device *pdev = notify->user;
570 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200571}
572
Hamad Kadmany567bed82012-11-29 14:15:57 +0200573static void tspp_expiration_timer(unsigned long data)
574{
575 struct tspp_device *pdev = (struct tspp_device *)data;
576
577 if (pdev)
578 tasklet_schedule(&pdev->tlet);
579}
580
Joel Nider5556a852011-10-16 10:52:13 +0200581/*** tasklet ***/
582static void tspp_sps_complete_tlet(unsigned long data)
583{
584 int i;
585 int complete;
586 unsigned long flags;
587 struct sps_iovec iovec;
588 struct tspp_channel *channel;
589 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200590 spin_lock_irqsave(&device->spinlock, flags);
591
592 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
593 complete = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +0200594 channel = &device->channels[i];
Hamad Kadmany567bed82012-11-29 14:15:57 +0200595
Joel Nider5bd73f82011-12-14 16:53:30 +0200596 if (!channel->used || !channel->waiting)
597 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200598
Hamad Kadmany567bed82012-11-29 14:15:57 +0200599 /* stop the expiration timer */
600 if (channel->expiration_period_ms)
601 del_timer(&channel->expiration_timer);
602
Joel Nider5556a852011-10-16 10:52:13 +0200603 /* get completions */
Joel Nider5bd73f82011-12-14 16:53:30 +0200604 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200605 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
606 pr_err("tspp: Error in iovec on channel %i",
607 channel->id);
608 break;
609 }
610 if (iovec.size == 0)
611 break;
612
Joel Nider5bd73f82011-12-14 16:53:30 +0200613 if (iovec.addr != channel->waiting->sps.phys_base)
Joel Nider5556a852011-10-16 10:52:13 +0200614 pr_err("tspp: buffer mismatch 0x%08x",
Joel Nider5bd73f82011-12-14 16:53:30 +0200615 channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200616
617 complete = 1;
Joel Nider5bd73f82011-12-14 16:53:30 +0200618 channel->waiting->state = TSPP_BUF_STATE_DATA;
619 channel->waiting->filled = iovec.size;
620 channel->waiting->read_index = 0;
621
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200622 if (channel->src == TSPP_SOURCE_TSIF0)
623 device->tsif[0].stat_rx++;
624 else if (channel->src == TSPP_SOURCE_TSIF1)
625 device->tsif[1].stat_rx++;
626
Joel Nider5bd73f82011-12-14 16:53:30 +0200627 /* update the pointers */
628 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200629 }
630
Joel Nider5bd73f82011-12-14 16:53:30 +0200631 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200632 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200633 wake_up_interruptible(&channel->in_queue);
Joel Nider5bd73f82011-12-14 16:53:30 +0200634
635 /* call notifiers */
636 if (channel->notifier)
637 channel->notifier(channel->id,
638 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200639 }
Hamad Kadmany567bed82012-11-29 14:15:57 +0200640
641 /* restart expiration timer */
642 if (channel->expiration_period_ms)
643 mod_timer(&channel->expiration_timer,
644 jiffies +
645 MSEC_TO_JIFFIES(
646 channel->expiration_period_ms));
Joel Nider5556a852011-10-16 10:52:13 +0200647 }
648
649 spin_unlock_irqrestore(&device->spinlock, flags);
650}
651
652/*** GPIO functions ***/
Liron Kuch65067fa2013-02-10 15:19:32 +0200653static int tspp_gpios_disable(const struct tspp_tsif_device *tsif_device,
654 const struct msm_gpio *table,
655 int size)
Joel Nider5556a852011-10-16 10:52:13 +0200656{
657 int rc = 0;
658 int i;
659 const struct msm_gpio *g;
Liron Kuch8fa85b02013-01-01 18:29:47 +0200660
Joel Nider5556a852011-10-16 10:52:13 +0200661 for (i = size-1; i >= 0; i--) {
662 int tmp;
663 g = table + i;
Liron Kuch8fa85b02013-01-01 18:29:47 +0200664
Liron Kuch65067fa2013-02-10 15:19:32 +0200665 /* don't use sync GPIO when not working in mode 2 */
666 if ((tsif_device->mode != TSPP_TSIF_MODE_2) &&
667 (strnstr(g->label, "sync", strlen(g->label)) != NULL))
668 continue;
669
Liron Kuch8fa85b02013-01-01 18:29:47 +0200670 tmp = gpio_tlmm_config(GPIO_CFG(GPIO_PIN(g->gpio_cfg),
671 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
672 GPIO_CFG_DISABLE);
Joel Nider5556a852011-10-16 10:52:13 +0200673 if (tmp) {
Liron Kuch229090d2012-10-30 17:47:50 +0200674 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200675 g->gpio_cfg, g->label ?: "?", rc);
676 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
677 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
678 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
679 GPIO_DRVSTR(g->gpio_cfg));
680 if (!rc)
681 rc = tmp;
682 }
683 }
684
685 return rc;
686}
687
Liron Kuch65067fa2013-02-10 15:19:32 +0200688static int tspp_gpios_enable(const struct tspp_tsif_device *tsif_device,
689 const struct msm_gpio *table,
690 int size)
Joel Nider5556a852011-10-16 10:52:13 +0200691{
692 int rc;
Liron Kuch65067fa2013-02-10 15:19:32 +0200693 int i;
Joel Nider5556a852011-10-16 10:52:13 +0200694 const struct msm_gpio *g;
Liron Kuch8fa85b02013-01-01 18:29:47 +0200695
Joel Nider5556a852011-10-16 10:52:13 +0200696 for (i = 0; i < size; i++) {
697 g = table + i;
Liron Kuch65067fa2013-02-10 15:19:32 +0200698
699 /* don't use sync GPIO when not working in mode 2 */
700 if ((tsif_device->mode != TSPP_TSIF_MODE_2) &&
701 (strnstr(g->label, "sync", strlen(g->label)) != NULL))
702 continue;
703
Joel Nider5556a852011-10-16 10:52:13 +0200704 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
705 if (rc) {
Liron Kuch229090d2012-10-30 17:47:50 +0200706 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200707 g->gpio_cfg, g->label ?: "?", rc);
708 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
709 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
710 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
711 GPIO_DRVSTR(g->gpio_cfg));
712 goto err;
713 }
714 }
715 return 0;
716err:
Liron Kuch65067fa2013-02-10 15:19:32 +0200717 tspp_gpios_disable(tsif_device, table, i);
Joel Nider5556a852011-10-16 10:52:13 +0200718
Joel Nider5556a852011-10-16 10:52:13 +0200719 return rc;
720}
721
Liron Kuch65067fa2013-02-10 15:19:32 +0200722
723static int tspp_config_gpios(struct tspp_device *device,
724 enum tspp_source source,
725 int enable)
Joel Nider5556a852011-10-16 10:52:13 +0200726{
Liron Kuch65067fa2013-02-10 15:19:32 +0200727 const struct msm_gpio *table;
728 struct msm_tspp_platform_data *pdata = device->pdev->dev.platform_data;
729 int num_gpios = (pdata->num_gpios / TSPP_TSIF_INSTANCES);
730 int i = 0;
Liron Kuch8fa85b02013-01-01 18:29:47 +0200731
Liron Kuch65067fa2013-02-10 15:19:32 +0200732 if (num_gpios != TSPP_GPIOS_PER_TSIF) {
733 pr_err("tspp %s: unexpected number of GPIOs %d, expected %d\n",
734 __func__, num_gpios, TSPP_GPIOS_PER_TSIF);
735 return -EINVAL;
736 }
Joel Nider5556a852011-10-16 10:52:13 +0200737
Liron Kuch65067fa2013-02-10 15:19:32 +0200738 /*
739 * Note: this code assumes that the GPIO definitions in the
740 * pdata->gpios table are according to the TSIF instance number,
741 * i.e., that TSIF0 GPIOs are defined first, then TSIF1 GPIOs etc.
742 */
743 switch (source) {
744 case TSPP_SOURCE_TSIF0:
745 i = 0;
746 break;
747 case TSPP_SOURCE_TSIF1:
748 i = 1;
749 break;
750 default:
751 pr_err("tspp %s: invalid source\n", __func__);
752 return -EINVAL;
753 }
Liron Kuch8fa85b02013-01-01 18:29:47 +0200754
Liron Kuch65067fa2013-02-10 15:19:32 +0200755 table = pdata->gpios + (i * num_gpios);
756 if (enable)
757 return tspp_gpios_enable(&device->tsif[i], table, num_gpios);
758 else
759 return tspp_gpios_disable(&device->tsif[i], table, num_gpios);
Joel Nider5556a852011-10-16 10:52:13 +0200760}
761
Joel Nider5bd73f82011-12-14 16:53:30 +0200762/*** Clock functions ***/
763static int tspp_clock_start(struct tspp_device *device)
764{
Liron Kuchde8cbf92013-02-21 14:25:57 +0200765 if (device == NULL) {
766 pr_err("tspp: Can't start clocks, invalid device\n");
767 return -EINVAL;
768 }
769
Joel Nider5bd73f82011-12-14 16:53:30 +0200770 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
771 pr_err("tspp: Can't start pclk");
772 return -EBUSY;
773 }
774
775 if (device->tsif_ref_clk &&
776 clk_prepare_enable(device->tsif_ref_clk) != 0) {
777 pr_err("tspp: Can't start ref clk");
778 clk_disable_unprepare(device->tsif_pclk);
779 return -EBUSY;
780 }
781
782 return 0;
783}
784
785static void tspp_clock_stop(struct tspp_device *device)
786{
Liron Kuchde8cbf92013-02-21 14:25:57 +0200787 if (device == NULL) {
788 pr_err("tspp: Can't stop clocks, invalid device\n");
789 return;
790 }
791
Joel Nider5bd73f82011-12-14 16:53:30 +0200792 if (device->tsif_pclk)
Liron Kuchde8cbf92013-02-21 14:25:57 +0200793 clk_disable_unprepare(device->tsif_pclk);
Joel Nider5bd73f82011-12-14 16:53:30 +0200794
795 if (device->tsif_ref_clk)
Liron Kuchde8cbf92013-02-21 14:25:57 +0200796 clk_disable_unprepare(device->tsif_ref_clk);
Joel Nider5bd73f82011-12-14 16:53:30 +0200797}
798
Joel Nider5556a852011-10-16 10:52:13 +0200799/*** TSIF functions ***/
800static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
801{
802 int start_hardware = 0;
803 u32 ctl;
804
805 if (tsif_device->ref_count == 0) {
806 start_hardware = 1;
807 } else if (tsif_device->ref_count > 0) {
808 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
809 if ((ctl & TSIF_STS_CTL_START) != 1) {
810 /* this hardware should already be running */
811 pr_warn("tspp: tsif hw not started but ref count > 0");
812 start_hardware = 1;
813 }
814 }
815
816 if (start_hardware) {
Joel Nider5bd73f82011-12-14 16:53:30 +0200817 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200818 TSIF_STS_CTL_EN_DM;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200819
820 if (tsif_device->clock_inverse)
821 ctl |= TSIF_STS_CTL_INV_CLOCK;
822
823 if (tsif_device->data_inverse)
824 ctl |= TSIF_STS_CTL_INV_DATA;
825
826 if (tsif_device->sync_inverse)
827 ctl |= TSIF_STS_CTL_INV_SYNC;
828
829 if (tsif_device->enable_inverse)
830 ctl |= TSIF_STS_CTL_INV_ENABLE;
831
Joel Nider5bd73f82011-12-14 16:53:30 +0200832 switch (tsif_device->mode) {
833 case TSPP_TSIF_MODE_LOOPBACK:
834 ctl |= TSIF_STS_CTL_EN_NULL |
835 TSIF_STS_CTL_EN_ERROR |
836 TSIF_STS_CTL_TEST_MODE;
837 break;
838 case TSPP_TSIF_MODE_1:
839 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
840 TSIF_STS_CTL_EN_TCR;
841 break;
842 case TSPP_TSIF_MODE_2:
843 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
844 TSIF_STS_CTL_EN_TCR |
845 TSIF_STS_CTL_MODE_2;
846 break;
847 default:
848 pr_warn("tspp: unknown tsif mode 0x%x",
849 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200850 }
851 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
852 writel_relaxed(tsif_device->time_limit,
853 tsif_device->base + TSIF_TIME_LIMIT_OFF);
854 wmb();
855 writel_relaxed(ctl | TSIF_STS_CTL_START,
856 tsif_device->base + TSIF_STS_CTL_OFF);
857 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200858 }
859
Joel Nider5bd73f82011-12-14 16:53:30 +0200860 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Joel Nider5556a852011-10-16 10:52:13 +0200861 tsif_device->ref_count++;
862
Joel Nider5bd73f82011-12-14 16:53:30 +0200863 return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200864}
865
866static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
867{
868 if (tsif_device->ref_count == 0)
869 return;
870
871 tsif_device->ref_count--;
872
873 if (tsif_device->ref_count == 0) {
874 writel_relaxed(TSIF_STS_CTL_STOP,
875 tsif_device->base + TSIF_STS_CTL_OFF);
876 wmb();
877 }
878}
879
Joel Nider5bd73f82011-12-14 16:53:30 +0200880/*** local TSPP functions ***/
881static int tspp_channels_in_use(struct tspp_device *pdev)
882{
883 int i;
884 int count = 0;
885 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
886 count += (pdev->channels[i].used ? 1 : 0);
887
888 return count;
889}
890
891static struct tspp_device *tspp_find_by_id(int id)
892{
893 struct tspp_device *dev;
894 list_for_each_entry(dev, &tspp_devices, devlist) {
895 if (dev->pdev->id == id)
896 return dev;
897 }
898 return NULL;
899}
900
Joel Nider5556a852011-10-16 10:52:13 +0200901static int tspp_get_key_entry(void)
902{
903 int i;
904 for (i = 0; i < TSPP_NUM_KEYS; i++) {
905 if (!(tspp_key_entry & (1 << i))) {
906 tspp_key_entry |= (1 << i);
907 return i;
908 }
909 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200910 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200911}
912
913static void tspp_free_key_entry(int entry)
914{
915 if (entry > TSPP_NUM_KEYS) {
916 pr_err("tspp_free_key_entry: index out of bounds");
917 return;
918 }
919
920 tspp_key_entry &= ~(1 << entry);
921}
922
Joel Nider5bd73f82011-12-14 16:53:30 +0200923static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200924 u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200925{
Joel Nider5bd73f82011-12-14 16:53:30 +0200926 if (size < TSPP_MIN_BUFFER_SIZE ||
927 size > TSPP_MAX_BUFFER_SIZE) {
928 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200929 return -ENOMEM;
930 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200931
932 if (alloc) {
933 TSPP_DEBUG("tspp using alloc function");
934 desc->virt_base = alloc(channel_id, size,
935 &desc->phys_base, user);
936 } else {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200937 if (!dma_pool)
938 desc->virt_base = dma_alloc_coherent(NULL, size,
939 &desc->phys_base, GFP_KERNEL);
940 else
941 desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL,
942 &desc->phys_base);
943
Liron Kuch229090d2012-10-30 17:47:50 +0200944 if (desc->virt_base == 0) {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200945 pr_err("tspp: dma buffer allocation failed %i\n", size);
Liron Kuch229090d2012-10-30 17:47:50 +0200946 return -ENOMEM;
947 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200948 }
949
950 desc->size = size;
951 return 0;
952}
953
954static int tspp_queue_buffer(struct tspp_channel *channel,
955 struct tspp_mem_buffer *buffer)
956{
957 int rc;
958 u32 flags = 0;
959
960 /* make sure the interrupt frequency is valid */
961 if (channel->int_freq < 1)
962 channel->int_freq = 1;
963
964 /* generate interrupt according to requested frequency */
965 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
Hamad Kadmany567bed82012-11-29 14:15:57 +0200966 flags = SPS_IOVEC_FLAG_INT;
Joel Nider5bd73f82011-12-14 16:53:30 +0200967
968 /* start the transfer */
969 rc = sps_transfer_one(channel->pipe,
970 buffer->sps.phys_base,
971 buffer->sps.size,
972 channel->pdev,
973 flags);
974 if (rc < 0)
975 return rc;
976
977 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +0200978
979 return 0;
980}
981
982static int tspp_global_reset(struct tspp_device *pdev)
983{
984 u32 i, val;
985
986 /* stop all TSIFs */
987 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
988 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
989 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
990 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200991 pdev->tsif[i].clock_inverse = 0;
992 pdev->tsif[i].data_inverse = 0;
993 pdev->tsif[i].sync_inverse = 0;
994 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +0200995 }
996 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
997 wmb();
998
999 /* BAM */
1000 if (sps_device_reset(pdev->bam_handle) != 0) {
1001 pr_err("tspp: error resetting bam");
Joel Nider5bd73f82011-12-14 16:53:30 +02001002 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001003 }
1004
1005 /* TSPP tables */
1006 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider5bd73f82011-12-14 16:53:30 +02001007 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +02001008 0, sizeof(struct tspp_pid_filter_table));
1009
1010 /* disable all filters */
1011 val = (2 << TSPP_NUM_CHANNELS) - 1;
1012 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
1013
1014 /* TSPP registers */
1015 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1016 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1017 pdev->base + TSPP_CONTROL);
1018 wmb();
Joel Nider5bd73f82011-12-14 16:53:30 +02001019 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001020 sizeof(struct tspp_global_performance_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +02001021 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001022 sizeof(struct tspp_pipe_context_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +02001023 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001024 sizeof(struct tspp_pipe_performance_regs));
1025 wmb();
1026 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1027 pdev->base + TSPP_CONTROL);
1028 wmb();
1029
1030 val = readl_relaxed(pdev->base + TSPP_CONFIG);
1031 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
1032 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
1033 TSPP_CONFIG_PS_CONT_ERR_MASK);
1034 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
1035 writel_relaxed(val, pdev->base + TSPP_CONFIG);
Hamad Kadmany57f5ac82012-12-20 18:30:40 +02001036 writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK);
Joel Nider5556a852011-10-16 10:52:13 +02001037 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
1038 writel_relaxed(0, pdev->base + TSPP_RST);
1039 wmb();
1040
1041 tspp_key_entry = 0;
1042
1043 return 0;
1044}
1045
Joel Nider5bd73f82011-12-14 16:53:30 +02001046static int tspp_select_source(u32 dev, u32 channel_id,
1047 struct tspp_select_source *src)
1048{
1049 /* make sure the requested src id is in bounds */
1050 if (src->source > TSPP_SOURCE_MEM) {
1051 pr_err("tspp source out of bounds");
1052 return -EINVAL;
1053 }
1054
1055 /* open the stream */
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001056 tspp_open_stream(dev, channel_id, src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001057
1058 return 0;
1059}
1060
1061static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
1062{
1063 struct tspp_device *pdev = channel->pdev;
1064
1065 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
1066 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
1067 return 0;
1068}
1069
1070static int tspp_set_system_keys(struct tspp_channel *channel,
1071 struct tspp_system_keys *keys)
1072{
1073 int i;
1074 struct tspp_device *pdev = channel->pdev;
1075
1076 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
1077 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
1078
1079 return 0;
1080}
1081
1082static int tspp_channel_init(struct tspp_channel *channel,
1083 struct tspp_device *pdev)
1084{
1085 channel->cdev.owner = THIS_MODULE;
1086 cdev_init(&channel->cdev, &tspp_fops);
1087 channel->pdev = pdev;
1088 channel->data = NULL;
1089 channel->read = NULL;
1090 channel->waiting = NULL;
1091 channel->locked = NULL;
1092 channel->id = MINOR(tspp_minor);
1093 channel->used = 0;
1094 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1095 channel->max_buffers = TSPP_NUM_BUFFERS;
1096 channel->buffer_count = 0;
1097 channel->filter_count = 0;
1098 channel->int_freq = 1;
Liron Kuch229090d2012-10-30 17:47:50 +02001099 channel->src = TSPP_SOURCE_NONE;
1100 channel->mode = TSPP_MODE_DISABLED;
Joel Nider5bd73f82011-12-14 16:53:30 +02001101 channel->notifier = NULL;
1102 channel->notify_data = NULL;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001103 channel->expiration_period_ms = 0;
Liron Kuch229090d2012-10-30 17:47:50 +02001104 channel->memfree = NULL;
1105 channel->user_info = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001106 init_waitqueue_head(&channel->in_queue);
1107
1108 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
1109 pr_err("tspp: cdev_add failed");
1110 return -EBUSY;
1111 }
1112
1113 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
1114 channel, "tspp%02d", channel->id);
1115 if (IS_ERR(channel->dd)) {
1116 pr_err("tspp: device_create failed: %i",
1117 (int)PTR_ERR(channel->dd));
1118 cdev_del(&channel->cdev);
1119 return -EBUSY;
1120 }
1121
1122 return 0;
1123}
1124
1125static int tspp_set_buffer_size(struct tspp_channel *channel,
1126 struct tspp_buffer *buf)
1127{
Liron Kuch229090d2012-10-30 17:47:50 +02001128 if (channel->buffer_count > 0) {
1129 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1130 return -EPERM;
1131 }
1132
Joel Nider5bd73f82011-12-14 16:53:30 +02001133 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1134 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1135 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1136 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1137 else
1138 channel->buffer_size = buf->size;
1139
1140 return 0;
1141}
1142
1143static void tspp_set_tsif_mode(struct tspp_channel *channel,
1144 enum tspp_tsif_mode mode)
1145{
1146 int index;
1147
1148 switch (channel->src) {
1149 case TSPP_SOURCE_TSIF0:
1150 index = 0;
1151 break;
1152 case TSPP_SOURCE_TSIF1:
1153 index = 1;
1154 break;
1155 default:
1156 pr_warn("tspp: can't set mode for non-tsif source %d",
1157 channel->src);
1158 return;
1159 }
1160 channel->pdev->tsif[index].mode = mode;
1161}
1162
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001163static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch229090d2012-10-30 17:47:50 +02001164 int clock_inverse, int data_inverse,
1165 int sync_inverse, int enable_inverse)
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001166{
1167 int index;
1168
1169 switch (channel->src) {
1170 case TSPP_SOURCE_TSIF0:
1171 index = 0;
1172 break;
1173 case TSPP_SOURCE_TSIF1:
1174 index = 1;
1175 break;
1176 default:
1177 return;
1178 }
1179 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1180 channel->pdev->tsif[index].data_inverse = data_inverse;
1181 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1182 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1183}
1184
Liron Kuch229090d2012-10-30 17:47:50 +02001185static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1186{
1187 u32 alignment;
1188
1189 switch (mode) {
1190 case TSPP_MODE_RAW:
1191 /* must be a multiple of 192 */
1192 alignment = (TSPP_PACKET_LENGTH + 4);
1193 if (size % alignment)
1194 return 0;
1195 return 1;
1196
1197 case TSPP_MODE_RAW_NO_SUFFIX:
1198 /* must be a multiple of 188 */
1199 alignment = TSPP_PACKET_LENGTH;
1200 if (size % alignment)
1201 return 0;
1202 return 1;
1203
1204 case TSPP_MODE_DISABLED:
1205 case TSPP_MODE_PES:
1206 default:
1207 /* no alignment requirement */
1208 return 1;
1209 }
1210
1211}
1212
1213static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1214{
1215 u32 new_size;
1216 u32 alignment;
1217
1218 switch (mode) {
1219 case TSPP_MODE_RAW:
1220 /* must be a multiple of 192 */
1221 alignment = (TSPP_PACKET_LENGTH + 4);
1222 break;
1223
1224 case TSPP_MODE_RAW_NO_SUFFIX:
1225 /* must be a multiple of 188 */
1226 alignment = TSPP_PACKET_LENGTH;
1227 break;
1228
1229 case TSPP_MODE_DISABLED:
1230 case TSPP_MODE_PES:
1231 default:
1232 /* no alignment requirement - give the user what he asks for */
1233 alignment = 1;
1234 break;
1235 }
1236 /* align up */
1237 new_size = (((size + alignment - 1) / alignment) * alignment);
1238 return new_size;
1239}
1240
1241static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1242{
1243 int i;
1244 struct tspp_mem_buffer *pbuf, *temp;
1245
1246 pbuf = channel->data;
1247 for (i = 0; i < channel->buffer_count; i++) {
1248 if (pbuf->desc.phys_base) {
1249 if (channel->memfree) {
1250 channel->memfree(channel_id,
1251 pbuf->desc.size,
1252 pbuf->desc.virt_base,
1253 pbuf->desc.phys_base,
1254 channel->user_info);
1255 } else {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001256 if (!channel->dma_pool)
1257 dma_free_coherent(NULL,
1258 pbuf->desc.size,
1259 pbuf->desc.virt_base,
1260 pbuf->desc.phys_base);
1261 else
1262 dma_pool_free(channel->dma_pool,
1263 pbuf->desc.virt_base,
1264 pbuf->desc.phys_base);
Liron Kuch229090d2012-10-30 17:47:50 +02001265 }
1266 pbuf->desc.phys_base = 0;
1267 }
1268 pbuf->desc.virt_base = 0;
1269 pbuf->state = TSPP_BUF_STATE_EMPTY;
1270 temp = pbuf;
1271 pbuf = pbuf->next;
1272 kfree(temp);
1273 }
1274}
1275
Joel Nider5bd73f82011-12-14 16:53:30 +02001276/*** TSPP API functions ***/
Liron Kuch229090d2012-10-30 17:47:50 +02001277
1278/**
1279 * tspp_open_stream - open a TSPP stream for use.
1280 *
1281 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1282 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1283 * @source: stream source parameters.
1284 *
1285 * Return error status
1286 *
1287 */
1288int tspp_open_stream(u32 dev, u32 channel_id,
1289 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001290{
1291 u32 val;
1292 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001293 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001294
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001295 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1296 dev, channel_id, source->source, source->mode);
Liron Kuch229090d2012-10-30 17:47:50 +02001297
Joel Nider5bd73f82011-12-14 16:53:30 +02001298 if (dev >= TSPP_MAX_DEVICES) {
1299 pr_err("tspp: device id out of range");
1300 return -ENODEV;
1301 }
Joel Nider5556a852011-10-16 10:52:13 +02001302
Joel Nider5bd73f82011-12-14 16:53:30 +02001303 if (channel_id >= TSPP_NUM_CHANNELS) {
1304 pr_err("tspp: channel id out of range");
1305 return -ECHRNG;
1306 }
1307
1308 pdev = tspp_find_by_id(dev);
1309 if (!pdev) {
1310 pr_err("tspp_str: can't find device %i", dev);
1311 return -ENODEV;
1312 }
1313 channel = &pdev->channels[channel_id];
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001314 channel->src = source->source;
1315 tspp_set_tsif_mode(channel, source->mode);
1316 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch229090d2012-10-30 17:47:50 +02001317 source->data_inverse, source->sync_inverse,
1318 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001319
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001320 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001321 case TSPP_SOURCE_TSIF0:
Liron Kuch65067fa2013-02-10 15:19:32 +02001322 if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
1323 pr_err("tspp: error enabling tsif0 GPIOs\n");
1324 return -EBUSY;
1325 }
Joel Nider5556a852011-10-16 10:52:13 +02001326 /* make sure TSIF0 is running & enabled */
1327 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
1328 pr_err("tspp: error starting tsif0");
Joel Nider5bd73f82011-12-14 16:53:30 +02001329 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001330 }
Liron Kuchc2392df2013-02-14 16:26:38 +02001331 if (pdev->tsif[0].ref_count == 1) {
1332 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1333 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1334 pdev->base + TSPP_CONTROL);
1335 wmb();
1336 }
Joel Nider5556a852011-10-16 10:52:13 +02001337 break;
1338 case TSPP_SOURCE_TSIF1:
Liron Kuch65067fa2013-02-10 15:19:32 +02001339 if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
1340 pr_err("tspp: error enabling tsif1 GPIOs\n");
1341 return -EBUSY;
1342 }
Joel Nider5556a852011-10-16 10:52:13 +02001343 /* make sure TSIF1 is running & enabled */
1344 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
1345 pr_err("tspp: error starting tsif1");
Joel Nider5bd73f82011-12-14 16:53:30 +02001346 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001347 }
Liron Kuchc2392df2013-02-14 16:26:38 +02001348 if (pdev->tsif[1].ref_count == 1) {
1349 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1350 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1351 pdev->base + TSPP_CONTROL);
1352 wmb();
1353 }
Joel Nider5556a852011-10-16 10:52:13 +02001354 break;
1355 case TSPP_SOURCE_MEM:
1356 break;
1357 default:
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001358 pr_err("tspp: channel %i invalid source %i",
1359 channel->id, source->source);
Joel Nider5bd73f82011-12-14 16:53:30 +02001360 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001361 }
1362
Joel Nider5556a852011-10-16 10:52:13 +02001363 return 0;
1364}
1365EXPORT_SYMBOL(tspp_open_stream);
1366
Liron Kuch229090d2012-10-30 17:47:50 +02001367/**
1368 * tspp_close_stream - close a TSPP stream.
1369 *
1370 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1371 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1372 *
1373 * Return error status
1374 *
1375 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001376int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001377{
1378 u32 val;
Liron Kuchc2392df2013-02-14 16:26:38 +02001379 u32 prev_ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001380 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001381 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001382
Joel Nider5bd73f82011-12-14 16:53:30 +02001383 if (channel_id >= TSPP_NUM_CHANNELS) {
1384 pr_err("tspp: channel id out of range");
1385 return -ECHRNG;
1386 }
1387 pdev = tspp_find_by_id(dev);
1388 if (!pdev) {
1389 pr_err("tspp_cs: can't find device %i", dev);
1390 return -EBUSY;
1391 }
1392 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001393
1394 switch (channel->src) {
1395 case TSPP_SOURCE_TSIF0:
Liron Kuchc2392df2013-02-14 16:26:38 +02001396 prev_ref_count = pdev->tsif[0].ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001397 tspp_stop_tsif(&pdev->tsif[0]);
Liron Kuch65067fa2013-02-10 15:19:32 +02001398 if (tspp_config_gpios(pdev, channel->src, 0) != 0)
1399 pr_err("tspp: error disabling tsif0 GPIOs\n");
1400
Liron Kuchc2392df2013-02-14 16:26:38 +02001401 if (prev_ref_count == 1) {
1402 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1403 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1404 pdev->base + TSPP_CONTROL);
1405 wmb();
1406 }
Joel Nider5556a852011-10-16 10:52:13 +02001407 break;
1408 case TSPP_SOURCE_TSIF1:
Liron Kuchc2392df2013-02-14 16:26:38 +02001409 prev_ref_count = pdev->tsif[1].ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001410 tspp_stop_tsif(&pdev->tsif[1]);
Liron Kuch65067fa2013-02-10 15:19:32 +02001411 if (tspp_config_gpios(pdev, channel->src, 0) != 0)
1412 pr_err("tspp: error disabling tsif0 GPIOs\n");
1413
Liron Kuchc2392df2013-02-14 16:26:38 +02001414 if (prev_ref_count == 1) {
1415 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1416 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1417 pdev->base + TSPP_CONTROL);
1418 wmb();
1419 }
Joel Nider5556a852011-10-16 10:52:13 +02001420 break;
1421 case TSPP_SOURCE_MEM:
1422 break;
1423 case TSPP_SOURCE_NONE:
1424 break;
1425 }
1426
Joel Nider5bd73f82011-12-14 16:53:30 +02001427 channel->src = TSPP_SOURCE_NONE;
Joel Nider5556a852011-10-16 10:52:13 +02001428 return 0;
1429}
1430EXPORT_SYMBOL(tspp_close_stream);
1431
Liron Kuch229090d2012-10-30 17:47:50 +02001432/**
1433 * tspp_open_channel - open a TSPP channel.
1434 *
1435 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1436 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1437 *
1438 * Return error status
1439 *
1440 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001441int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001442{
1443 int rc = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001444 struct sps_connect *config;
1445 struct sps_register_event *event;
1446 struct tspp_channel *channel;
1447 struct tspp_device *pdev;
1448
1449 if (channel_id >= TSPP_NUM_CHANNELS) {
1450 pr_err("tspp: channel id out of range");
1451 return -ECHRNG;
1452 }
1453 pdev = tspp_find_by_id(dev);
1454 if (!pdev) {
1455 pr_err("tspp_oc: can't find device %i", dev);
1456 return -ENODEV;
1457 }
1458 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001459
1460 if (channel->used) {
1461 pr_err("tspp channel already in use");
Joel Nider5bd73f82011-12-14 16:53:30 +02001462 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001463 }
1464
Joel Nider5bd73f82011-12-14 16:53:30 +02001465 config = &channel->config;
1466 event = &channel->event;
1467
1468 /* start the clocks if needed */
Liron Kuch8fa85b02013-01-01 18:29:47 +02001469 if (tspp_channels_in_use(pdev) == 0) {
Liron Kuchde8cbf92013-02-21 14:25:57 +02001470 rc = tspp_clock_start(pdev);
1471 if (rc)
1472 return rc;
1473
Joel Nider5bd73f82011-12-14 16:53:30 +02001474 wake_lock(&pdev->wake_lock);
Liron Kuch8fa85b02013-01-01 18:29:47 +02001475 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001476
Joel Nider5556a852011-10-16 10:52:13 +02001477 /* mark it as used */
1478 channel->used = 1;
1479
1480 /* start the bam */
1481 channel->pipe = sps_alloc_endpoint();
1482 if (channel->pipe == 0) {
1483 pr_err("tspp: error allocating endpoint");
1484 rc = -ENOMEM;
1485 goto err_sps_alloc;
1486 }
1487
1488 /* get default configuration */
1489 sps_get_config(channel->pipe, config);
1490
Joel Nider5bd73f82011-12-14 16:53:30 +02001491 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001492 config->destination = SPS_DEV_HANDLE_MEM;
1493 config->mode = SPS_MODE_SRC;
Joel Nider5bd73f82011-12-14 16:53:30 +02001494 config->options =
1495 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1496 SPS_O_STREAMING | /* streaming mode */
1497 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
Hamad Kadmany567bed82012-11-29 14:15:57 +02001498 SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
1499 SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001500 config->src_pipe_index = channel->id;
1501 config->desc.size =
Hamad Kadmany567bed82012-11-29 14:15:57 +02001502 TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
Joel Nider5556a852011-10-16 10:52:13 +02001503 config->desc.base = dma_alloc_coherent(NULL,
1504 config->desc.size,
1505 &config->desc.phys_base,
1506 GFP_KERNEL);
1507 if (config->desc.base == 0) {
1508 pr_err("tspp: error allocating sps descriptors");
1509 rc = -ENOMEM;
1510 goto err_desc_alloc;
1511 }
1512
1513 memset(config->desc.base, 0, config->desc.size);
1514
1515 rc = sps_connect(channel->pipe, config);
1516 if (rc) {
1517 pr_err("tspp: error connecting bam");
1518 goto err_connect;
1519 }
1520
1521 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider5bd73f82011-12-14 16:53:30 +02001522 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001523 event->callback = tspp_sps_complete_cb;
1524 event->xfer_done = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001525 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001526
1527 rc = sps_register_event(channel->pipe, event);
1528 if (rc) {
1529 pr_err("tspp: error registering event");
1530 goto err_event;
1531 }
1532
Hamad Kadmany567bed82012-11-29 14:15:57 +02001533 init_timer(&channel->expiration_timer);
1534 channel->expiration_timer.function = tspp_expiration_timer;
1535 channel->expiration_timer.data = (unsigned long)pdev;
1536 channel->expiration_timer.expires = 0xffffffffL;
1537
Joel Nider5bd73f82011-12-14 16:53:30 +02001538 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001539 if (rc < 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001540 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001541 "Runtime PM: Unable to wake up tspp device, rc = %d",
1542 rc);
1543 }
Joel Nider5556a852011-10-16 10:52:13 +02001544 return 0;
1545
1546err_event:
1547 sps_disconnect(channel->pipe);
1548err_connect:
1549 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1550 config->desc.phys_base);
1551err_desc_alloc:
1552 sps_free_endpoint(channel->pipe);
1553err_sps_alloc:
1554 return rc;
1555}
1556EXPORT_SYMBOL(tspp_open_channel);
1557
Liron Kuch229090d2012-10-30 17:47:50 +02001558/**
1559 * tspp_close_channel - close a TSPP channel.
1560 *
1561 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1562 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1563 *
1564 * Return error status
1565 *
1566 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001567int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001568{
1569 int i;
1570 int id;
Liron Kuch98fb17c2013-03-28 09:39:17 +02001571 int table_idx;
Joel Nider5556a852011-10-16 10:52:13 +02001572 u32 val;
Liron Kuchf2fa7102013-04-21 13:16:45 +03001573 unsigned long flags;
Joel Nider5556a852011-10-16 10:52:13 +02001574
Joel Nider5bd73f82011-12-14 16:53:30 +02001575 struct sps_connect *config;
1576 struct tspp_device *pdev;
1577 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02001578
1579 if (channel_id >= TSPP_NUM_CHANNELS) {
1580 pr_err("tspp: channel id out of range");
1581 return -ECHRNG;
1582 }
1583 pdev = tspp_find_by_id(dev);
1584 if (!pdev) {
1585 pr_err("tspp_close: can't find device %i", dev);
1586 return -ENODEV;
1587 }
1588 channel = &pdev->channels[channel_id];
1589
1590 /* if the channel is not used, we are done */
1591 if (!channel->used)
1592 return 0;
1593
Liron Kuchf2fa7102013-04-21 13:16:45 +03001594 /*
1595 * Need to protect access to used and waiting fields, as they are
1596 * used by the tasklet which is invoked from interrupt context
1597 */
1598 spin_lock_irqsave(&pdev->spinlock, flags);
1599 channel->used = 0;
1600 channel->waiting = NULL;
1601 spin_unlock_irqrestore(&pdev->spinlock, flags);
1602
Hamad Kadmany567bed82012-11-29 14:15:57 +02001603 if (channel->expiration_period_ms)
1604 del_timer(&channel->expiration_timer);
1605
Joel Nider5bd73f82011-12-14 16:53:30 +02001606 channel->notifier = NULL;
1607 channel->notify_data = NULL;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001608 channel->expiration_period_ms = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001609
1610 config = &channel->config;
1611 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001612
1613 /* disable pipe (channel) */
1614 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1615 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1616 wmb();
1617
1618 /* unregister all filters for this channel */
Liron Kuch98fb17c2013-03-28 09:39:17 +02001619 for (table_idx = 0; table_idx < TSPP_FILTER_TABLES; table_idx++) {
1620 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1621 struct tspp_pid_filter *filter =
1622 &pdev->filters[table_idx]->filter[i];
1623 id = FILTER_GET_PIPE_NUMBER0(filter);
1624 if (id == channel->id) {
1625 if (FILTER_HAS_ENCRYPTION(filter))
1626 tspp_free_key_entry(
1627 FILTER_GET_KEY_NUMBER(filter));
1628 filter->config = 0;
1629 filter->filter = 0;
1630 }
Joel Nider5556a852011-10-16 10:52:13 +02001631 }
1632 }
1633 channel->filter_count = 0;
1634
Joel Nider5556a852011-10-16 10:52:13 +02001635 /* disconnect the bam */
1636 if (sps_disconnect(channel->pipe) != 0)
1637 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1638
1639 /* destroy the buffers */
1640 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1641 config->desc.phys_base);
1642
Liron Kuch229090d2012-10-30 17:47:50 +02001643 tspp_destroy_buffers(channel_id, channel);
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001644 if (channel->dma_pool) {
1645 dma_pool_destroy(channel->dma_pool);
1646 channel->dma_pool = NULL;
1647 }
Liron Kuch229090d2012-10-30 17:47:50 +02001648
1649 channel->src = TSPP_SOURCE_NONE;
1650 channel->mode = TSPP_MODE_DISABLED;
1651 channel->memfree = NULL;
1652 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001653 channel->buffer_count = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001654 channel->data = NULL;
1655 channel->read = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001656 channel->locked = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001657
Liron Kuch8fa85b02013-01-01 18:29:47 +02001658 if (tspp_channels_in_use(pdev) == 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001659 wake_unlock(&pdev->wake_lock);
Liron Kuch8fa85b02013-01-01 18:29:47 +02001660 tspp_clock_stop(pdev);
1661 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001662
Liron Kuchde8cbf92013-02-21 14:25:57 +02001663 pm_runtime_put(&pdev->pdev->dev);
1664
Joel Nider5556a852011-10-16 10:52:13 +02001665 return 0;
1666}
1667EXPORT_SYMBOL(tspp_close_channel);
1668
Liron Kuch229090d2012-10-30 17:47:50 +02001669/**
Hamad Kadmany586fb392013-01-31 14:49:20 +02001670 * tspp_get_ref_clk_counter - return the TSIF clock reference (TCR) counter.
1671 *
1672 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1673 * @source: The TSIF source from which the counter should be read
1674 * @tcr_counter: the value of TCR counter
1675 *
1676 * Return error status
1677 *
1678 * TCR increments at a rate equal to 27 MHz/256 = 105.47 kHz.
1679 * If source is neither TSIF 0 or TSIF1 0 is returned.
1680 */
1681int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter)
1682{
1683 struct tspp_device *pdev;
1684 struct tspp_tsif_device *tsif_device;
1685
1686 if (!tcr_counter)
1687 return -EINVAL;
1688
1689 pdev = tspp_find_by_id(dev);
1690 if (!pdev) {
1691 pr_err("tspp_get_ref_clk_counter: can't find device %i\n", dev);
1692 return -ENODEV;
1693 }
1694
1695 switch (source) {
1696 case TSPP_SOURCE_TSIF0:
1697 tsif_device = &pdev->tsif[0];
1698 break;
1699
1700 case TSPP_SOURCE_TSIF1:
1701 tsif_device = &pdev->tsif[1];
1702 break;
1703
1704 default:
1705 tsif_device = NULL;
1706 break;
1707 }
1708
1709 if (tsif_device && tsif_device->ref_count)
1710 *tcr_counter = ioread32(tsif_device->base + TSIF_CLK_REF_OFF);
1711 else
1712 *tcr_counter = 0;
1713
1714 return 0;
1715}
1716EXPORT_SYMBOL(tspp_get_ref_clk_counter);
1717
1718/**
Liron Kuch229090d2012-10-30 17:47:50 +02001719 * tspp_add_filter - add a TSPP filter to a channel.
1720 *
1721 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1722 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1723 * @filter: TSPP filter parameters
1724 *
1725 * Return error status
1726 *
1727 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001728int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001729 struct tspp_filter *filter)
1730{
Liron Kuch229090d2012-10-30 17:47:50 +02001731 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001732 int other_channel;
1733 int entry;
1734 u32 val, pid, enabled;
Joel Nider5bd73f82011-12-14 16:53:30 +02001735 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001736 struct tspp_pid_filter p;
Joel Nider5bd73f82011-12-14 16:53:30 +02001737 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001738
Joel Nider5bd73f82011-12-14 16:53:30 +02001739 TSPP_DEBUG("tspp: add filter");
1740 if (channel_id >= TSPP_NUM_CHANNELS) {
1741 pr_err("tspp: channel id out of range");
1742 return -ECHRNG;
1743 }
1744 pdev = tspp_find_by_id(dev);
1745 if (!pdev) {
1746 pr_err("tspp_add: can't find device %i", dev);
1747 return -ENODEV;
1748 }
1749
1750 channel = &pdev->channels[channel_id];
1751
Joel Nider5556a852011-10-16 10:52:13 +02001752 if (filter->source > TSPP_SOURCE_MEM) {
1753 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001754 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001755 }
1756
1757 if (filter->priority >= TSPP_NUM_PRIORITIES) {
Hamad Kadmany197e6c32013-11-17 11:31:01 +02001758 pr_err("tspp invalid filter priority");
Joel Nider5bd73f82011-12-14 16:53:30 +02001759 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001760 }
1761
Liron Kuch229090d2012-10-30 17:47:50 +02001762 channel->mode = filter->mode;
1763 /*
1764 * if buffers are already allocated, verify they fulfil
1765 * the alignment requirements.
1766 */
1767 if ((channel->buffer_count > 0) &&
1768 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1769 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001770
1771 if (filter->mode == TSPP_MODE_PES) {
1772 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1773 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001774 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001775 pid = FILTER_GET_PIPE_PID((tspp_filter));
1776 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1777 if (enabled && (pid == filter->pid)) {
1778 other_channel =
1779 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1780 pr_err("tspp: pid 0x%x already in use by channel %i",
1781 filter->pid, other_channel);
Joel Nider5bd73f82011-12-14 16:53:30 +02001782 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001783 }
1784 }
1785 }
1786
1787 /* make sure this priority is not already in use */
1788 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider5bd73f82011-12-14 16:53:30 +02001789 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001790 if (enabled) {
1791 pr_err("tspp: filter priority %i source %i is already enabled\n",
1792 filter->priority, channel->src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001793 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001794 }
1795
1796 if (channel->mode == TSPP_MODE_PES) {
1797 /* if we are already processing in PES mode, disable pipe
1798 (channel) and filter to be updated */
1799 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1800 writel_relaxed(val | (1 << channel->id),
1801 pdev->base + TSPP_PS_DISABLE);
1802 wmb();
1803 }
1804
1805 /* update entry */
1806 p.filter = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001807 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001808 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1809 FILTER_SET_PIPE_PID((&p), filter->pid);
1810 FILTER_SET_PID_MASK((&p), filter->mask);
1811 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1812 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1813 if (filter->decrypt) {
1814 entry = tspp_get_key_entry();
1815 if (entry == -1) {
1816 pr_err("tspp: no more keys available!");
1817 } else {
1818 p.config |= FILTER_DECRYPT;
1819 FILTER_SET_KEY_NUMBER((&p), entry);
1820 }
1821 }
Joel Nider5556a852011-10-16 10:52:13 +02001822
Joel Nider5bd73f82011-12-14 16:53:30 +02001823 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001824 filter[filter->priority].config = p.config;
Joel Nider5bd73f82011-12-14 16:53:30 +02001825 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001826 filter[filter->priority].filter = p.filter;
1827
Liron Kuch229090d2012-10-30 17:47:50 +02001828 /*
1829 * allocate buffers if needed (i.e. if user did has not already called
1830 * tspp_allocate_buffers() explicitly).
1831 */
1832 if (channel->buffer_count == 0) {
1833 channel->buffer_size =
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001834 tspp_align_buffer_size_by_mode(channel->buffer_size,
Liron Kuch229090d2012-10-30 17:47:50 +02001835 channel->mode);
1836 rc = tspp_allocate_buffers(dev, channel->id,
1837 channel->max_buffers,
1838 channel->buffer_size,
1839 channel->int_freq, NULL, NULL, NULL);
1840 if (rc != 0) {
1841 pr_err("tspp: tspp_allocate_buffers failed\n");
1842 return rc;
1843 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001844 }
1845
Joel Nider5556a852011-10-16 10:52:13 +02001846 /* reenable pipe */
1847 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1848 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1849 wmb();
1850 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1851
Joel Nider5556a852011-10-16 10:52:13 +02001852 channel->filter_count++;
1853
1854 return 0;
1855}
1856EXPORT_SYMBOL(tspp_add_filter);
1857
Liron Kuch229090d2012-10-30 17:47:50 +02001858/**
1859 * tspp_remove_filter - remove a TSPP filter from a channel.
1860 *
1861 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1862 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1863 * @filter: TSPP filter parameters
1864 *
1865 * Return error status
1866 *
1867 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001868int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001869 struct tspp_filter *filter)
1870{
1871 int entry;
1872 u32 val;
Joel Nider5bd73f82011-12-14 16:53:30 +02001873 struct tspp_device *pdev;
1874 int src;
1875 struct tspp_pid_filter *tspp_filter;
1876 struct tspp_channel *channel;
1877
1878 if (channel_id >= TSPP_NUM_CHANNELS) {
1879 pr_err("tspp: channel id out of range");
1880 return -ECHRNG;
1881 }
1882 pdev = tspp_find_by_id(dev);
1883 if (!pdev) {
1884 pr_err("tspp_remove: can't find device %i", dev);
1885 return -ENODEV;
1886 }
Hamad Kadmany197e6c32013-11-17 11:31:01 +02001887 if (filter->priority >= TSPP_NUM_PRIORITIES) {
1888 pr_err("tspp invalid filter priority");
1889 return -ENOSR;
1890 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001891 channel = &pdev->channels[channel_id];
1892
1893 src = channel->src;
1894 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02001895
1896 /* disable pipe (channel) */
1897 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1898 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1899 wmb();
1900
1901 /* update data keys */
1902 if (tspp_filter->config & FILTER_DECRYPT) {
1903 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
1904 tspp_free_key_entry(entry);
1905 }
1906
1907 /* update pid table */
1908 tspp_filter->config = 0;
1909 tspp_filter->filter = 0;
1910
1911 channel->filter_count--;
1912
1913 /* reenable pipe */
1914 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1915 writel_relaxed(val & ~(1 << channel->id),
1916 pdev->base + TSPP_PS_DISABLE);
1917 wmb();
1918 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1919
1920 return 0;
1921}
1922EXPORT_SYMBOL(tspp_remove_filter);
1923
Liron Kuch229090d2012-10-30 17:47:50 +02001924/**
1925 * tspp_set_key - set TSPP key in key table.
1926 *
1927 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1928 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1929 * @key: TSPP key parameters
1930 *
1931 * Return error status
1932 *
1933 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001934int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02001935{
1936 int i;
1937 int id;
1938 int key_index;
1939 int data;
Joel Nider5bd73f82011-12-14 16:53:30 +02001940 struct tspp_channel *channel;
1941 struct tspp_device *pdev;
1942
1943 if (channel_id >= TSPP_NUM_CHANNELS) {
1944 pr_err("tspp: channel id out of range");
1945 return -ECHRNG;
1946 }
1947 pdev = tspp_find_by_id(dev);
1948 if (!pdev) {
1949 pr_err("tspp_set: can't find device %i", dev);
1950 return -ENODEV;
1951 }
1952 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001953
1954 /* read the key index used by this channel */
1955 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1956 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001957 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02001958 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1959 if (id == channel->id) {
1960 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
1961 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
1962 break;
1963 }
1964 }
1965 }
1966 if (i == TSPP_NUM_PRIORITIES) {
1967 pr_err("tspp: no encryption on this channel");
Joel Nider5bd73f82011-12-14 16:53:30 +02001968 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02001969 }
1970
1971 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001972 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
1973 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001974 } else {
Joel Nider5bd73f82011-12-14 16:53:30 +02001975 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
1976 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001977 }
1978 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
1979
1980 return 0;
1981}
1982EXPORT_SYMBOL(tspp_set_key);
1983
Liron Kuch229090d2012-10-30 17:47:50 +02001984/**
1985 * tspp_register_notification - register TSPP channel notification function.
1986 *
1987 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1988 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1989 * @pNotify: notification function
1990 * @userdata: user data to pass to notification function
1991 * @timer_ms: notification for partially filled buffers
1992 *
1993 * Return error status
1994 *
1995 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001996int tspp_register_notification(u32 dev, u32 channel_id,
1997 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02001998{
Joel Nider5bd73f82011-12-14 16:53:30 +02001999 struct tspp_channel *channel;
2000 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002001
Joel Nider5bd73f82011-12-14 16:53:30 +02002002 if (channel_id >= TSPP_NUM_CHANNELS) {
2003 pr_err("tspp: channel id out of range");
2004 return -ECHRNG;
2005 }
2006 pdev = tspp_find_by_id(dev);
2007 if (!pdev) {
2008 pr_err("tspp_reg: can't find device %i", dev);
2009 return -ENODEV;
2010 }
2011 channel = &pdev->channels[channel_id];
2012 channel->notifier = pNotify;
2013 channel->notify_data = userdata;
Hamad Kadmany567bed82012-11-29 14:15:57 +02002014 channel->expiration_period_ms = timer_ms;
2015
Joel Nider5556a852011-10-16 10:52:13 +02002016 return 0;
2017}
Joel Nider5bd73f82011-12-14 16:53:30 +02002018EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02002019
Liron Kuch229090d2012-10-30 17:47:50 +02002020/**
2021 * tspp_unregister_notification - unregister TSPP channel notification function.
2022 *
2023 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2024 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2025 *
2026 * Return error status
2027 *
2028 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002029int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002030{
Joel Nider5bd73f82011-12-14 16:53:30 +02002031 struct tspp_channel *channel;
2032 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002033
Joel Nider5bd73f82011-12-14 16:53:30 +02002034 if (channel_id >= TSPP_NUM_CHANNELS) {
2035 pr_err("tspp: channel id out of range");
2036 return -ECHRNG;
2037 }
2038 pdev = tspp_find_by_id(dev);
2039 if (!pdev) {
2040 pr_err("tspp_unreg: can't find device %i", dev);
2041 return -ENODEV;
2042 }
2043 channel = &pdev->channels[channel_id];
2044 channel->notifier = NULL;
2045 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02002046 return 0;
2047}
Joel Nider5bd73f82011-12-14 16:53:30 +02002048EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02002049
Liron Kuch229090d2012-10-30 17:47:50 +02002050/**
2051 * tspp_get_buffer - get TSPP data buffer.
2052 *
2053 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2054 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2055 *
2056 * Return error status
2057 *
2058 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002059const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002060{
Joel Nider5bd73f82011-12-14 16:53:30 +02002061 struct tspp_mem_buffer *buffer;
2062 struct tspp_channel *channel;
2063 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002064
Joel Nider5bd73f82011-12-14 16:53:30 +02002065 if (channel_id >= TSPP_NUM_CHANNELS) {
2066 pr_err("tspp: channel id out of range");
2067 return NULL;
2068 }
2069 pdev = tspp_find_by_id(dev);
2070 if (!pdev) {
2071 pr_err("tspp_get: can't find device %i", dev);
2072 return NULL;
2073 }
2074 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02002075
Joel Nider5bd73f82011-12-14 16:53:30 +02002076 if (!channel->read) {
2077 pr_warn("tspp: no buffer to get on channel %i!",
2078 channel->id);
2079 return NULL;
2080 }
2081
2082 buffer = channel->read;
2083 /* see if we have any buffers ready to read */
2084 if (buffer->state != TSPP_BUF_STATE_DATA)
2085 return 0;
2086
2087 if (buffer->state == TSPP_BUF_STATE_DATA) {
2088 /* mark the buffer as busy */
2089 buffer->state = TSPP_BUF_STATE_LOCKED;
2090
2091 /* increment the pointer along the list */
2092 channel->read = channel->read->next;
2093 }
2094
2095 return &buffer->desc;
2096}
2097EXPORT_SYMBOL(tspp_get_buffer);
2098
Liron Kuch229090d2012-10-30 17:47:50 +02002099/**
2100 * tspp_release_buffer - release TSPP data buffer back to TSPP.
2101 *
2102 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2103 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2104 * @descriptor_id: buffer descriptor ID
2105 *
2106 * Return error status
2107 *
2108 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002109int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
2110{
2111 int i, found = 0;
2112 struct tspp_mem_buffer *buffer;
2113 struct tspp_channel *channel;
2114 struct tspp_device *pdev;
2115
2116 if (channel_id >= TSPP_NUM_CHANNELS) {
2117 pr_err("tspp: channel id out of range");
2118 return -ECHRNG;
2119 }
2120 pdev = tspp_find_by_id(dev);
2121 if (!pdev) {
2122 pr_err("tspp: can't find device %i", dev);
2123 return -ENODEV;
2124 }
2125 channel = &pdev->channels[channel_id];
2126
2127 if (descriptor_id > channel->buffer_count)
2128 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
2129
2130 /* find the correct descriptor */
2131 buffer = channel->locked;
2132 for (i = 0; i < channel->buffer_count; i++) {
2133 if (buffer->desc.id == descriptor_id) {
2134 found = 1;
2135 break;
2136 }
2137 buffer = buffer->next;
2138 }
2139 channel->locked = channel->locked->next;
2140
2141 if (!found) {
2142 pr_err("tspp: cant find desc %i", descriptor_id);
2143 return -EINVAL;
2144 }
2145
2146 /* make sure the buffer is in the expected state */
2147 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
2148 pr_err("tspp: buffer %i not locked", descriptor_id);
2149 return -EINVAL;
2150 }
2151 /* unlock the buffer and requeue it */
2152 buffer->state = TSPP_BUF_STATE_WAITING;
2153
2154 if (tspp_queue_buffer(channel, buffer))
2155 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02002156 return 0;
2157}
Joel Nider5bd73f82011-12-14 16:53:30 +02002158EXPORT_SYMBOL(tspp_release_buffer);
2159
Liron Kuch229090d2012-10-30 17:47:50 +02002160/**
2161 * tspp_allocate_buffers - allocate TSPP data buffers.
2162 *
2163 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2164 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2165 * @count: number of buffers to allocate
2166 * @size: size of each buffer to allocate
2167 * @int_freq: interrupt frequency
2168 * @alloc: user defined memory allocator function. Pass NULL for default.
2169 * @memfree: user defined memory free function. Pass NULL for default.
2170 * @user: user data to pass to the memory allocator/free function
2171 *
2172 * Return error status
2173 *
2174 * The user can optionally call this function explicitly to allocate the TSPP
2175 * data buffers. Alternatively, if the user did not call this function, it
2176 * is called implicitly by tspp_add_filter().
2177 */
2178int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
2179 u32 int_freq, tspp_allocator *alloc,
2180 tspp_memfree *memfree, void *user)
Joel Nider5bd73f82011-12-14 16:53:30 +02002181{
2182 struct tspp_channel *channel;
2183 struct tspp_device *pdev;
2184 struct tspp_mem_buffer *last = NULL;
2185
2186 TSPP_DEBUG("tspp_allocate_buffers");
2187
2188 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch229090d2012-10-30 17:47:50 +02002189 pr_err("%s: channel id out of range", __func__);
Joel Nider5bd73f82011-12-14 16:53:30 +02002190 return -ECHRNG;
2191 }
Liron Kuch229090d2012-10-30 17:47:50 +02002192
Joel Nider5bd73f82011-12-14 16:53:30 +02002193 pdev = tspp_find_by_id(dev);
2194 if (!pdev) {
Liron Kuch229090d2012-10-30 17:47:50 +02002195 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider5bd73f82011-12-14 16:53:30 +02002196 return -ENODEV;
2197 }
Liron Kuch229090d2012-10-30 17:47:50 +02002198
2199 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
2200 pr_err("%s: tspp requires a minimum of %i buffers\n",
2201 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
2202 return -EINVAL;
2203 }
2204
Hamad Kadmany45f3f062013-05-22 15:40:38 +03002205 if (count > TSPP_NUM_BUFFERS) {
2206 pr_err("%s: tspp requires a maximum of %i buffers\n",
2207 __func__, TSPP_NUM_BUFFERS);
2208 return -EINVAL;
2209 }
2210
Joel Nider5bd73f82011-12-14 16:53:30 +02002211 channel = &pdev->channels[channel_id];
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002212
Liron Kuch229090d2012-10-30 17:47:50 +02002213 /* allow buffer allocation only if there was no previous buffer
2214 * allocation for this channel.
2215 */
2216 if (channel->buffer_count > 0) {
2217 pr_err("%s: buffers already allocated for channel %u",
2218 __func__, channel_id);
2219 return -EINVAL;
2220 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002221
2222 channel->max_buffers = count;
2223
2224 /* set up interrupt frequency */
Liron Kuch229090d2012-10-30 17:47:50 +02002225 if (int_freq > channel->max_buffers) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002226 int_freq = channel->max_buffers;
Liron Kuch229090d2012-10-30 17:47:50 +02002227 pr_warn("%s: setting interrupt frequency to %u\n",
2228 __func__, int_freq);
Joel Nider5bd73f82011-12-14 16:53:30 +02002229 }
Liron Kuch229090d2012-10-30 17:47:50 +02002230 channel->int_freq = int_freq;
2231 /*
2232 * it is the responsibility of the caller to tspp_allocate_buffers(),
2233 * whether it's the user or the driver, to make sure the size parameter
2234 * is compatible to the channel mode.
2235 */
2236 channel->buffer_size = size;
Joel Nider5bd73f82011-12-14 16:53:30 +02002237
Liron Kuch229090d2012-10-30 17:47:50 +02002238 /* save user defined memory free function for later use */
2239 channel->memfree = memfree;
2240 channel->user_info = user;
2241
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002242 /*
2243 * For small buffers, create a DMA pool so that memory
2244 * is not wasted through dma_alloc_coherent.
2245 */
2246 if (TSPP_USE_DMA_POOL(channel->buffer_size)) {
2247 channel->dma_pool = dma_pool_create("tspp",
2248 NULL, channel->buffer_size, 0, 0);
2249 if (!channel->dma_pool) {
2250 pr_err("%s: Can't allocate memory pool\n", __func__);
2251 return -ENOMEM;
2252 }
2253 } else {
2254 channel->dma_pool = NULL;
2255 }
2256
2257
Liron Kuch229090d2012-10-30 17:47:50 +02002258 for (channel->buffer_count = 0;
2259 channel->buffer_count < channel->max_buffers;
Joel Nider5bd73f82011-12-14 16:53:30 +02002260 channel->buffer_count++) {
2261
2262 /* allocate the descriptor */
2263 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2264 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2265 if (!desc) {
Liron Kuch229090d2012-10-30 17:47:50 +02002266 pr_warn("%s: Can't allocate desc %i",
2267 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002268 break;
2269 }
2270
2271 desc->desc.id = channel->buffer_count;
2272 /* allocate the buffer */
2273 if (tspp_alloc_buffer(channel_id, &desc->desc,
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002274 channel->buffer_size, channel->dma_pool,
2275 alloc, user) != 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002276 kfree(desc);
Liron Kuch229090d2012-10-30 17:47:50 +02002277 pr_warn("%s: Can't allocate buffer %i",
2278 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002279 break;
2280 }
2281
2282 /* add the descriptor to the list */
2283 desc->filled = 0;
2284 desc->read_index = 0;
2285 if (!channel->data) {
2286 channel->data = desc;
2287 desc->next = channel->data;
2288 } else {
2289 last->next = desc;
2290 }
2291 last = desc;
2292 desc->next = channel->data;
2293
2294 /* prepare the sps descriptor */
2295 desc->sps.phys_base = desc->desc.phys_base;
2296 desc->sps.base = desc->desc.virt_base;
2297 desc->sps.size = desc->desc.size;
2298
2299 /* start the transfer */
2300 if (tspp_queue_buffer(channel, desc))
Liron Kuch229090d2012-10-30 17:47:50 +02002301 pr_err("%s: can't queue buffer %i",
2302 __func__, desc->desc.id);
2303 }
2304
2305 if (channel->buffer_count < channel->max_buffers) {
2306 /*
2307 * we failed to allocate the requested number of buffers.
2308 * we don't allow a partial success, so need to clean up here.
2309 */
2310 tspp_destroy_buffers(channel_id, channel);
2311 channel->buffer_count = 0;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002312
2313 if (channel->dma_pool) {
2314 dma_pool_destroy(channel->dma_pool);
2315 channel->dma_pool = NULL;
2316 }
Liron Kuch229090d2012-10-30 17:47:50 +02002317 return -ENOMEM;
Joel Nider5bd73f82011-12-14 16:53:30 +02002318 }
2319
2320 channel->waiting = channel->data;
2321 channel->read = channel->data;
2322 channel->locked = channel->data;
Liron Kuch229090d2012-10-30 17:47:50 +02002323
Hamad Kadmany567bed82012-11-29 14:15:57 +02002324 /* Now that buffers are scheduled to HW, kick data expiration timer */
2325 if (channel->expiration_period_ms)
2326 mod_timer(&channel->expiration_timer,
2327 jiffies +
2328 MSEC_TO_JIFFIES(
2329 channel->expiration_period_ms));
2330
Joel Nider5bd73f82011-12-14 16:53:30 +02002331 return 0;
2332}
2333EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002334
2335/*** File Operations ***/
2336static ssize_t tspp_open(struct inode *inode, struct file *filp)
2337{
Joel Nider5bd73f82011-12-14 16:53:30 +02002338 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002339 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002340
2341 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002342 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2343 filp->private_data = channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002344 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002345
2346 /* if this channel is already in use, quit */
2347 if (channel->used) {
2348 pr_err("tspp channel %i already in use",
2349 MINOR(channel->cdev.dev));
2350 return -EACCES;
2351 }
2352
Joel Nider5bd73f82011-12-14 16:53:30 +02002353 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002354 pr_err("tspp: error opening channel");
2355 return -EACCES;
2356 }
2357
2358 return 0;
2359}
2360
2361static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2362{
2363 unsigned long flags;
2364 unsigned int mask = 0;
2365 struct tspp_channel *channel;
2366 channel = filp->private_data;
2367
2368 /* register the wait queue for this channel */
2369 poll_wait(filp, &channel->in_queue, p);
2370
2371 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider5bd73f82011-12-14 16:53:30 +02002372 if (channel->read &&
2373 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002374 mask = POLLIN | POLLRDNORM;
2375
2376 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2377
2378 return mask;
2379}
2380
2381static ssize_t tspp_release(struct inode *inode, struct file *filp)
2382{
Joel Nider5bd73f82011-12-14 16:53:30 +02002383 struct tspp_channel *channel = filp->private_data;
2384 u32 dev = channel->pdev->pdev->id;
2385 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002386
Joel Nider5bd73f82011-12-14 16:53:30 +02002387 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002388
2389 return 0;
2390}
2391
2392static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2393 loff_t *f_pos)
2394{
2395 size_t size = 0;
2396 size_t transferred = 0;
2397 struct tspp_channel *channel;
2398 struct tspp_mem_buffer *buffer;
2399 channel = filp->private_data;
2400
2401 TSPP_DEBUG("tspp_read");
Joel Nider5bd73f82011-12-14 16:53:30 +02002402
2403 while (!channel->read) {
2404 if (filp->f_flags & O_NONBLOCK) {
2405 pr_warn("tspp: no buffer on channel %i!",
2406 channel->id);
2407 return -EAGAIN;
2408 }
2409 /* go to sleep if there is nothing to read */
2410 if (wait_event_interruptible(channel->in_queue,
2411 (channel->read != NULL))) {
2412 pr_err("tspp: rude awakening\n");
2413 return -ERESTARTSYS;
2414 }
2415 }
2416
2417 buffer = channel->read;
2418
Joel Nider5556a852011-10-16 10:52:13 +02002419 /* see if we have any buffers ready to read */
2420 while (buffer->state != TSPP_BUF_STATE_DATA) {
2421 if (filp->f_flags & O_NONBLOCK) {
2422 pr_warn("tspp: nothing to read on channel %i!",
2423 channel->id);
2424 return -EAGAIN;
2425 }
2426 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002427 if (wait_event_interruptible(channel->in_queue,
2428 (buffer->state == TSPP_BUF_STATE_DATA))) {
2429 pr_err("tspp: rude awakening\n");
2430 return -ERESTARTSYS;
2431 }
2432 }
2433
2434 while (buffer->state == TSPP_BUF_STATE_DATA) {
2435 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002436 if (size == 0)
2437 break;
2438
Joel Nider5bd73f82011-12-14 16:53:30 +02002439 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002440 buffer->read_index, size)) {
2441 pr_err("tspp: error copying to user buffer");
Joel Nider5bd73f82011-12-14 16:53:30 +02002442 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002443 }
2444 buf += size;
2445 count -= size;
2446 transferred += size;
2447 buffer->read_index += size;
2448
Liron Kuch229090d2012-10-30 17:47:50 +02002449 /*
2450 * after reading the end of the buffer, requeue it,
2451 * and set up for reading the next one
2452 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002453 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002454 buffer->state = TSPP_BUF_STATE_WAITING;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002455
Joel Nider5bd73f82011-12-14 16:53:30 +02002456 if (tspp_queue_buffer(channel, buffer))
2457 pr_err("tspp: can't submit transfer");
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002458
Joel Nider5bd73f82011-12-14 16:53:30 +02002459 channel->locked = channel->read;
2460 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002461 }
2462 }
2463
2464 return transferred;
2465}
2466
2467static long tspp_ioctl(struct file *filp,
2468 unsigned int param0, unsigned long param1)
2469{
Joel Nider5bd73f82011-12-14 16:53:30 +02002470 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002471 int rc = -1;
2472 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002473 struct tspp_select_source ss;
2474 struct tspp_filter f;
2475 struct tspp_key k;
2476 struct tspp_iv iv;
2477 struct tspp_system_keys sk;
2478 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002479 channel = filp->private_data;
Joel Nider5bd73f82011-12-14 16:53:30 +02002480 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002481
Liron Kuchc2392df2013-02-14 16:26:38 +02002482 if ((param0 != TSPP_IOCTL_CLOSE_STREAM) && !param1)
Joel Nider5556a852011-10-16 10:52:13 +02002483 return -EINVAL;
2484
2485 switch (param0) {
2486 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002487 if (!access_ok(VERIFY_READ, param1,
2488 sizeof(struct tspp_select_source))) {
2489 return -EBUSY;
2490 }
2491 if (__copy_from_user(&ss, (void *)param1,
2492 sizeof(struct tspp_select_source)) == 0)
2493 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002494 break;
2495 case TSPP_IOCTL_ADD_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002496 if (!access_ok(VERIFY_READ, param1,
2497 sizeof(struct tspp_filter))) {
2498 return -ENOSR;
2499 }
2500 if (__copy_from_user(&f, (void *)param1,
2501 sizeof(struct tspp_filter)) == 0)
2502 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002503 break;
2504 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002505 if (!access_ok(VERIFY_READ, param1,
2506 sizeof(struct tspp_filter))) {
2507 return -EBUSY;
2508 }
2509 if (__copy_from_user(&f, (void *)param1,
2510 sizeof(struct tspp_filter)) == 0)
2511 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002512 break;
2513 case TSPP_IOCTL_SET_KEY:
Joel Nider5bd73f82011-12-14 16:53:30 +02002514 if (!access_ok(VERIFY_READ, param1,
2515 sizeof(struct tspp_key))) {
2516 return -EBUSY;
2517 }
2518 if (__copy_from_user(&k, (void *)param1,
2519 sizeof(struct tspp_key)) == 0)
2520 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002521 break;
2522 case TSPP_IOCTL_SET_IV:
Joel Nider5bd73f82011-12-14 16:53:30 +02002523 if (!access_ok(VERIFY_READ, param1,
2524 sizeof(struct tspp_iv))) {
2525 return -EBUSY;
2526 }
2527 if (__copy_from_user(&iv, (void *)param1,
2528 sizeof(struct tspp_iv)) == 0)
2529 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002530 break;
2531 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider5bd73f82011-12-14 16:53:30 +02002532 if (!access_ok(VERIFY_READ, param1,
2533 sizeof(struct tspp_system_keys))) {
2534 return -EINVAL;
2535 }
2536 if (__copy_from_user(&sk, (void *)param1,
2537 sizeof(struct tspp_system_keys)) == 0)
2538 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002539 break;
2540 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002541 if (!access_ok(VERIFY_READ, param1,
2542 sizeof(struct tspp_buffer))) {
2543 rc = -EINVAL;
2544 }
2545 if (__copy_from_user(&b, (void *)param1,
2546 sizeof(struct tspp_buffer)) == 0)
2547 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002548 break;
Liron Kuchc2392df2013-02-14 16:26:38 +02002549 case TSPP_IOCTL_CLOSE_STREAM:
2550 rc = tspp_close_stream(dev, channel->id);
2551 break;
Joel Nider5556a852011-10-16 10:52:13 +02002552 default:
2553 pr_err("tspp: Unknown ioctl %i", param0);
2554 }
2555
Liron Kuch229090d2012-10-30 17:47:50 +02002556 /*
2557 * normalize the return code in case one of the subfunctions does
2558 * something weird
2559 */
Joel Nider5556a852011-10-16 10:52:13 +02002560 if (rc != 0)
Joel Nider5bd73f82011-12-14 16:53:30 +02002561 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002562
2563 return rc;
2564}
2565
2566/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002567static int debugfs_iomem_x32_set(void *data, u64 val)
2568{
2569 writel_relaxed(val, data);
2570 wmb();
2571 return 0;
2572}
2573
2574static int debugfs_iomem_x32_get(void *data, u64 *val)
2575{
2576 *val = readl_relaxed(data);
2577 return 0;
2578}
2579
2580DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2581 debugfs_iomem_x32_set, "0x%08llx");
2582
2583static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2584 int instance)
2585{
2586 char name[10];
2587 snprintf(name, 10, "tsif%i", instance);
2588 tsif_device->dent_tsif = debugfs_create_dir(
2589 name, NULL);
2590 if (tsif_device->dent_tsif) {
2591 int i;
2592 void __iomem *base = tsif_device->base;
2593 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2594 tsif_device->debugfs_tsif_regs[i] =
2595 debugfs_create_file(
2596 debugfs_tsif_regs[i].name,
2597 debugfs_tsif_regs[i].mode,
2598 tsif_device->dent_tsif,
2599 base + debugfs_tsif_regs[i].offset,
2600 &fops_iomem_x32);
2601 }
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002602
2603 debugfs_create_u32(
2604 "stat_rx_chunks",
Hamad Kadmany8c6c8972013-03-28 08:23:26 +02002605 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002606 tsif_device->dent_tsif,
2607 &tsif_device->stat_rx);
2608
2609 debugfs_create_u32(
2610 "stat_overflow",
Hamad Kadmany8c6c8972013-03-28 08:23:26 +02002611 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002612 tsif_device->dent_tsif,
2613 &tsif_device->stat_overflow);
2614
2615 debugfs_create_u32(
2616 "stat_lost_sync",
Hamad Kadmany8c6c8972013-03-28 08:23:26 +02002617 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002618 tsif_device->dent_tsif,
2619 &tsif_device->stat_lost_sync);
2620
2621 debugfs_create_u32(
2622 "stat_timeout",
Hamad Kadmany8c6c8972013-03-28 08:23:26 +02002623 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002624 tsif_device->dent_tsif,
2625 &tsif_device->stat_timeout);
Joel Nider5556a852011-10-16 10:52:13 +02002626 }
2627}
2628
2629static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2630{
2631 if (tsif_device->dent_tsif) {
2632 int i;
2633 debugfs_remove_recursive(tsif_device->dent_tsif);
2634 tsif_device->dent_tsif = NULL;
2635 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2636 tsif_device->debugfs_tsif_regs[i] = NULL;
2637 }
2638}
2639
2640static void tspp_debugfs_init(struct tspp_device *device, int instance)
2641{
2642 char name[10];
2643 snprintf(name, 10, "tspp%i", instance);
2644 device->dent = debugfs_create_dir(
2645 name, NULL);
2646 if (device->dent) {
2647 int i;
2648 void __iomem *base = device->base;
2649 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2650 device->debugfs_regs[i] =
2651 debugfs_create_file(
2652 debugfs_tspp_regs[i].name,
2653 debugfs_tspp_regs[i].mode,
2654 device->dent,
2655 base + debugfs_tspp_regs[i].offset,
2656 &fops_iomem_x32);
2657 }
2658 }
2659}
2660
2661static void tspp_debugfs_exit(struct tspp_device *device)
2662{
2663 if (device->dent) {
2664 int i;
2665 debugfs_remove_recursive(device->dent);
2666 device->dent = NULL;
2667 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2668 device->debugfs_regs[i] = NULL;
2669 }
2670}
Joel Nider5556a852011-10-16 10:52:13 +02002671
Liron Kuch8fa85b02013-01-01 18:29:47 +02002672/* copy device-tree data to platfrom data struct */
2673static __devinit struct msm_tspp_platform_data *
2674msm_tspp_dt_to_pdata(struct platform_device *pdev)
2675{
2676 struct device_node *node = pdev->dev.of_node;
2677 struct msm_tspp_platform_data *data;
2678 struct msm_gpio *gpios;
2679 int i, rc;
2680 int gpio;
2681 u32 gpio_func;
2682
2683 /* Note: memory allocated by devm_kzalloc is freed automatically */
2684 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
2685 if (!data) {
2686 pr_err("tspp: Unable to allocate platform data\n");
2687 return NULL;
2688 }
2689 rc = of_property_read_string(node, "qcom,tsif-pclk", &data->tsif_pclk);
2690 if (rc) {
2691 pr_err("tspp: Could not find tsif-pclk property, err = %d\n",
2692 rc);
2693 return NULL;
2694 }
2695 rc = of_property_read_string(node, "qcom,tsif-ref-clk",
2696 &data->tsif_ref_clk);
2697 if (rc) {
2698 pr_err("tspp: Could not find tsif-ref-clk property, err = %d\n",
2699 rc);
2700 return NULL;
2701 }
2702
2703 data->num_gpios = of_gpio_count(node);
2704 if (data->num_gpios == 0) {
2705 pr_err("tspp: Could not find GPIO definitions\n");
2706 return NULL;
2707 }
2708 gpios = devm_kzalloc(&pdev->dev,
2709 (data->num_gpios * sizeof(struct msm_gpio)),
2710 GFP_KERNEL);
2711 if (!gpios) {
2712 pr_err("tspp: Unable to allocate memory for GPIOs table\n");
2713 return NULL;
2714 }
2715 /* Assuming GPIO FUNC property is the same for all GPIOs */
2716 if (of_property_read_u32(node, "qcom,gpios-func", &gpio_func)) {
2717 pr_err("tspp: Could not find gpios-func property\n");
2718 return NULL;
2719 }
2720 for (i = 0; i < data->num_gpios; i++) {
2721 gpio = of_get_gpio(node, i);
2722 gpios[i].gpio_cfg = GPIO_CFG(gpio, gpio_func,
2723 GPIO_CFG_INPUT,
2724 GPIO_CFG_PULL_DOWN,
2725 GPIO_CFG_2MA);
2726 rc = of_property_read_string_index(node, "qcom,gpio-names",
2727 i, &gpios[i].label);
2728 if (rc)
2729 pr_warn("tspp: Could not find gpio-names property\n");
2730 }
2731
2732 data->gpios = gpios;
2733
2734 return data;
2735}
2736
2737static int msm_tspp_map_irqs(struct platform_device *pdev,
2738 struct tspp_device *device)
2739{
2740 int rc;
2741 int i;
2742
2743 /* get IRQ numbers from platform information */
2744
2745 /* map TSPP IRQ */
2746 rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ");
2747 if (rc > 0) {
2748 device->tspp_irq = rc;
2749 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
2750 dev_name(&pdev->dev), device);
2751 if (rc) {
2752 dev_err(&pdev->dev,
2753 "failed to request TSPP IRQ %d : %d",
2754 device->tspp_irq, rc);
2755 device->tspp_irq = 0;
2756 return -EINVAL;
2757 }
2758 } else {
2759 dev_err(&pdev->dev, "failed to get TSPP IRQ");
2760 return -EINVAL;
2761 }
2762
2763 /* map TSIF IRQs */
2764 rc = platform_get_irq_byname(pdev, "TSIF0_IRQ");
2765 if (rc > 0) {
2766 device->tsif[0].tsif_irq = rc;
2767 } else {
2768 dev_err(&pdev->dev, "failed to get TSIF0 IRQ");
2769 return -EINVAL;
2770 }
2771
2772 rc = platform_get_irq_byname(pdev, "TSIF1_IRQ");
2773 if (rc > 0) {
2774 device->tsif[1].tsif_irq = rc;
2775 } else {
2776 dev_err(&pdev->dev, "failed to get TSIF1 IRQ");
2777 return -EINVAL;
2778 }
2779
2780 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
2781 rc = request_irq(device->tsif[i].tsif_irq,
2782 tsif_isr, IRQF_SHARED,
2783 dev_name(&pdev->dev), &device->tsif[i]);
2784 if (rc) {
2785 dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
2786 i, rc);
2787 device->tsif[i].tsif_irq = 0;
2788 }
2789 }
2790
2791 /* map BAM IRQ */
2792 rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ");
2793 if (rc > 0) {
2794 device->bam_irq = rc;
2795 } else {
2796 dev_err(&pdev->dev, "failed to get TSPP BAM IRQ");
2797 return -EINVAL;
2798 }
2799
2800 return 0;
2801}
2802
Joel Nider5556a852011-10-16 10:52:13 +02002803static int __devinit msm_tspp_probe(struct platform_device *pdev)
2804{
2805 int rc = -ENODEV;
2806 u32 version;
Liron Kuch229090d2012-10-30 17:47:50 +02002807 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002808 struct msm_tspp_platform_data *data;
2809 struct tspp_device *device;
2810 struct resource *mem_tsif0;
2811 struct resource *mem_tsif1;
2812 struct resource *mem_tspp;
2813 struct resource *mem_bam;
Liron Kuch229090d2012-10-30 17:47:50 +02002814 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002815
Liron Kuch8fa85b02013-01-01 18:29:47 +02002816 if (pdev->dev.of_node) {
2817 /* get information from device tree */
2818 data = msm_tspp_dt_to_pdata(pdev);
2819 /* get device ID */
2820 rc = of_property_read_u32(pdev->dev.of_node,
2821 "cell-index", &pdev->id);
2822 if (rc)
2823 pdev->id = -1;
2824
2825 pdev->dev.platform_data = data;
2826 } else {
2827 /* must have platform data */
2828 data = pdev->dev.platform_data;
2829 }
Joel Nider5556a852011-10-16 10:52:13 +02002830 if (!data) {
2831 pr_err("tspp: Platform data not available");
2832 rc = -EINVAL;
2833 goto out;
2834 }
2835
2836 /* check for valid device id */
Joel Nider5bd73f82011-12-14 16:53:30 +02002837 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002838 pr_err("tspp: Invalid device ID %d", pdev->id);
2839 rc = -EINVAL;
2840 goto out;
2841 }
2842
2843 /* OK, we will use this device */
2844 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2845 if (!device) {
2846 pr_err("tspp: Failed to allocate memory for device");
2847 rc = -ENOMEM;
2848 goto out;
2849 }
2850
2851 /* set up references */
2852 device->pdev = pdev;
2853 platform_set_drvdata(pdev, device);
2854
2855 /* map clocks */
2856 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002857 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02002858 if (IS_ERR(device->tsif_pclk)) {
2859 pr_err("tspp: failed to get %s",
2860 data->tsif_pclk);
2861 rc = PTR_ERR(device->tsif_pclk);
2862 device->tsif_pclk = NULL;
2863 goto err_pclock;
2864 }
2865 }
2866 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002867 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02002868 if (IS_ERR(device->tsif_ref_clk)) {
2869 pr_err("tspp: failed to get %s",
2870 data->tsif_ref_clk);
2871 rc = PTR_ERR(device->tsif_ref_clk);
2872 device->tsif_ref_clk = NULL;
2873 goto err_refclock;
2874 }
2875 }
2876
2877 /* map I/O memory */
Liron Kuch8fa85b02013-01-01 18:29:47 +02002878 mem_tsif0 = platform_get_resource_byname(pdev,
2879 IORESOURCE_MEM, "MSM_TSIF0_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002880 if (!mem_tsif0) {
2881 pr_err("tspp: Missing tsif0 MEM resource");
2882 rc = -ENXIO;
2883 goto err_res_tsif0;
2884 }
2885 device->tsif[0].base = ioremap(mem_tsif0->start,
2886 resource_size(mem_tsif0));
2887 if (!device->tsif[0].base) {
2888 pr_err("tspp: ioremap failed");
2889 goto err_map_tsif0;
2890 }
2891
Liron Kuch8fa85b02013-01-01 18:29:47 +02002892 mem_tsif1 = platform_get_resource_byname(pdev,
2893 IORESOURCE_MEM, "MSM_TSIF1_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002894 if (!mem_tsif1) {
2895 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
2896 rc = -ENXIO;
2897 goto err_res_tsif1;
2898 }
2899 device->tsif[1].base = ioremap(mem_tsif1->start,
2900 resource_size(mem_tsif1));
2901 if (!device->tsif[1].base) {
2902 dev_err(&pdev->dev, "ioremap failed");
2903 goto err_map_tsif1;
2904 }
2905
Liron Kuch8fa85b02013-01-01 18:29:47 +02002906 mem_tspp = platform_get_resource_byname(pdev,
2907 IORESOURCE_MEM, "MSM_TSPP_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002908 if (!mem_tspp) {
2909 dev_err(&pdev->dev, "Missing MEM resource");
2910 rc = -ENXIO;
2911 goto err_res_dev;
2912 }
2913 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
2914 if (!device->base) {
2915 dev_err(&pdev->dev, "ioremap failed");
2916 goto err_map_dev;
2917 }
2918
Liron Kuch8fa85b02013-01-01 18:29:47 +02002919 mem_bam = platform_get_resource_byname(pdev,
2920 IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002921 if (!mem_bam) {
2922 pr_err("tspp: Missing bam MEM resource");
2923 rc = -ENXIO;
2924 goto err_res_bam;
2925 }
2926 memset(&device->bam_props, 0, sizeof(device->bam_props));
2927 device->bam_props.phys_addr = mem_bam->start;
2928 device->bam_props.virt_addr = ioremap(mem_bam->start,
2929 resource_size(mem_bam));
2930 if (!device->bam_props.virt_addr) {
2931 dev_err(&pdev->dev, "ioremap failed");
2932 goto err_map_bam;
2933 }
2934
Liron Kuch8fa85b02013-01-01 18:29:47 +02002935 if (msm_tspp_map_irqs(pdev, device))
Joel Nider5556a852011-10-16 10:52:13 +02002936 goto err_irq;
Joel Nider5556a852011-10-16 10:52:13 +02002937
Joel Nider5556a852011-10-16 10:52:13 +02002938 /* power management */
2939 pm_runtime_set_active(&pdev->dev);
2940 pm_runtime_enable(&pdev->dev);
2941
Joel Nider5556a852011-10-16 10:52:13 +02002942 tspp_debugfs_init(device, 0);
2943
2944 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2945 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02002946
2947 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
2948 dev_name(&pdev->dev));
2949
2950 /* set up pointers to ram-based 'registers' */
Joel Nider5bd73f82011-12-14 16:53:30 +02002951 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
2952 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
2953 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
2954 device->tspp_key_table = device->base + TSPP_DATA_KEY;
2955 device->tspp_global_performance =
2956 device->base + TSPP_GLOBAL_PERFORMANCE;
2957 device->tspp_pipe_context =
2958 device->base + TSPP_PIPE_CONTEXT;
2959 device->tspp_pipe_performance =
2960 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02002961
2962 device->bam_props.summing_threshold = 0x10;
2963 device->bam_props.irq = device->bam_irq;
2964 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
2965
Liron Kuch8fa85b02013-01-01 18:29:47 +02002966 if (tspp_clock_start(device) != 0) {
2967 dev_err(&pdev->dev, "Can't start clocks");
2968 goto err_clock;
2969 }
2970
Joel Nider5556a852011-10-16 10:52:13 +02002971 if (sps_register_bam_device(&device->bam_props,
2972 &device->bam_handle) != 0) {
2973 pr_err("tspp: failed to register bam");
2974 goto err_bam;
2975 }
2976
Joel Nider5556a852011-10-16 10:52:13 +02002977 spin_lock_init(&device->spinlock);
2978 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
2979 (unsigned long)device);
2980
2981 /* initialize everything to a known state */
2982 tspp_global_reset(device);
2983
2984 version = readl_relaxed(device->base + TSPP_VERSION);
Liron Kuch8fa85b02013-01-01 18:29:47 +02002985 /*
2986 * TSPP version can be bits [7:0] or alternatively,
2987 * TSPP major version is bits [31:28].
2988 */
2989 if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1))
Joel Nider5556a852011-10-16 10:52:13 +02002990 pr_warn("tspp: unrecognized hw version=%i", version);
2991
Joel Nider5bd73f82011-12-14 16:53:30 +02002992 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02002993 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002994 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
2995 pr_err("tspp_channel_init failed");
2996 goto err_channel;
2997 }
Joel Nider5556a852011-10-16 10:52:13 +02002998 }
2999
Joel Nider5bd73f82011-12-14 16:53:30 +02003000 /* stop the clocks for power savings */
3001 tspp_clock_stop(device);
3002
3003 /* everything is ok, so add the device to the list */
3004 list_add_tail(&(device->devlist), &tspp_devices);
3005
Joel Nider5556a852011-10-16 10:52:13 +02003006 return 0;
3007
Joel Nider5bd73f82011-12-14 16:53:30 +02003008err_channel:
Liron Kuch8fa85b02013-01-01 18:29:47 +02003009 /* un-initialize channels */
Liron Kuch229090d2012-10-30 17:47:50 +02003010 for (j = 0; j < i; j++) {
3011 channel = &(device->channels[i]);
3012 device_destroy(tspp_class, channel->cdev.dev);
3013 cdev_del(&channel->cdev);
3014 }
Liron Kuch8fa85b02013-01-01 18:29:47 +02003015
Joel Nider5556a852011-10-16 10:52:13 +02003016 sps_deregister_bam_device(device->bam_handle);
Liron Kuch8fa85b02013-01-01 18:29:47 +02003017err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02003018err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02003019 tspp_debugfs_exit(device);
3020 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3021 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02003022err_irq:
Liron Kuch8fa85b02013-01-01 18:29:47 +02003023 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
3024 if (device->tsif[i].tsif_irq)
3025 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
3026 }
3027 if (device->tspp_irq)
3028 free_irq(device->tspp_irq, device);
3029
Joel Nider5556a852011-10-16 10:52:13 +02003030 iounmap(device->bam_props.virt_addr);
3031err_map_bam:
3032err_res_bam:
3033 iounmap(device->base);
3034err_map_dev:
3035err_res_dev:
3036 iounmap(device->tsif[1].base);
3037err_map_tsif1:
3038err_res_tsif1:
3039 iounmap(device->tsif[0].base);
3040err_map_tsif0:
3041err_res_tsif0:
3042 if (device->tsif_ref_clk)
3043 clk_put(device->tsif_ref_clk);
3044err_refclock:
3045 if (device->tsif_pclk)
3046 clk_put(device->tsif_pclk);
3047err_pclock:
3048 kfree(device);
3049
3050out:
3051 return rc;
3052}
3053
3054static int __devexit msm_tspp_remove(struct platform_device *pdev)
3055{
Joel Nider5bd73f82011-12-14 16:53:30 +02003056 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02003057 u32 i;
Liron Kuchde8cbf92013-02-21 14:25:57 +02003058 int rc;
Joel Nider5556a852011-10-16 10:52:13 +02003059
3060 struct tspp_device *device = platform_get_drvdata(pdev);
3061
Joel Nider5bd73f82011-12-14 16:53:30 +02003062 /* free the buffers, and delete the channels */
3063 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
3064 channel = &device->channels[i];
3065 tspp_close_channel(device->pdev->id, i);
3066 device_destroy(tspp_class, channel->cdev.dev);
3067 cdev_del(&channel->cdev);
3068 }
3069
Liron Kuch8fa85b02013-01-01 18:29:47 +02003070 /* de-registering BAM device requires clocks */
Liron Kuchde8cbf92013-02-21 14:25:57 +02003071 rc = tspp_clock_start(device);
3072 if (rc == 0) {
3073 sps_deregister_bam_device(device->bam_handle);
3074 tspp_clock_stop(device);
3075 }
Joel Nider5556a852011-10-16 10:52:13 +02003076
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02003077 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
Joel Nider5556a852011-10-16 10:52:13 +02003078 tsif_debugfs_exit(&device->tsif[i]);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02003079 if (device->tsif[i].tsif_irq)
3080 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
3081 }
Joel Nider5556a852011-10-16 10:52:13 +02003082
3083 wake_lock_destroy(&device->wake_lock);
3084 free_irq(device->tspp_irq, device);
Joel Nider5556a852011-10-16 10:52:13 +02003085
3086 iounmap(device->bam_props.virt_addr);
3087 iounmap(device->base);
3088 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3089 iounmap(device->tsif[i].base);
3090
3091 if (device->tsif_ref_clk)
3092 clk_put(device->tsif_ref_clk);
3093
3094 if (device->tsif_pclk)
3095 clk_put(device->tsif_pclk);
3096
3097 pm_runtime_disable(&pdev->dev);
Liron Kuchde8cbf92013-02-21 14:25:57 +02003098
Joel Nider5556a852011-10-16 10:52:13 +02003099 kfree(device);
3100
3101 return 0;
3102}
3103
3104/*** power management ***/
3105
3106static int tspp_runtime_suspend(struct device *dev)
3107{
3108 dev_dbg(dev, "pm_runtime: suspending...");
3109 return 0;
3110}
3111
3112static int tspp_runtime_resume(struct device *dev)
3113{
3114 dev_dbg(dev, "pm_runtime: resuming...");
3115 return 0;
3116}
3117
3118static const struct dev_pm_ops tspp_dev_pm_ops = {
3119 .runtime_suspend = tspp_runtime_suspend,
3120 .runtime_resume = tspp_runtime_resume,
3121};
3122
Liron Kuch8fa85b02013-01-01 18:29:47 +02003123static struct of_device_id msm_match_table[] = {
3124 {.compatible = "qcom,msm_tspp"},
3125 {}
3126};
3127
Joel Nider5556a852011-10-16 10:52:13 +02003128static struct platform_driver msm_tspp_driver = {
3129 .probe = msm_tspp_probe,
3130 .remove = __exit_p(msm_tspp_remove),
3131 .driver = {
3132 .name = "msm_tspp",
3133 .pm = &tspp_dev_pm_ops,
Liron Kuch8fa85b02013-01-01 18:29:47 +02003134 .of_match_table = msm_match_table,
Joel Nider5556a852011-10-16 10:52:13 +02003135 },
3136};
3137
3138
3139static int __init mod_init(void)
3140{
Joel Nider5556a852011-10-16 10:52:13 +02003141 int rc;
3142
Joel Nider5bd73f82011-12-14 16:53:30 +02003143 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02003144 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
3145 if (rc) {
3146 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
3147 goto err_devrgn;
3148 }
3149
3150 tspp_class = class_create(THIS_MODULE, "tspp");
3151 if (IS_ERR(tspp_class)) {
3152 rc = PTR_ERR(tspp_class);
3153 pr_err("tspp: Error creating class: %d", rc);
3154 goto err_class;
3155 }
3156
Joel Nider5bd73f82011-12-14 16:53:30 +02003157 /* register the driver, and check hardware */
3158 rc = platform_driver_register(&msm_tspp_driver);
3159 if (rc) {
3160 pr_err("tspp: platform_driver_register failed: %d", rc);
3161 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02003162 }
3163
3164 return 0;
3165
Joel Nider5bd73f82011-12-14 16:53:30 +02003166err_register:
3167 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02003168err_class:
3169 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
3170err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02003171 return rc;
3172}
3173
3174static void __exit mod_exit(void)
3175{
Joel Nider5bd73f82011-12-14 16:53:30 +02003176 /* delete low level driver */
3177 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02003178
Joel Nider5bd73f82011-12-14 16:53:30 +02003179 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02003180 class_destroy(tspp_class);
3181 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02003182}
3183
3184module_init(mod_init);
3185module_exit(mod_exit);
3186
Joel Nider5bd73f82011-12-14 16:53:30 +02003187MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02003188MODULE_LICENSE("GPL v2");