blob: 73cae32772e9adc17a5bc7016cad66e87f9d8a7a [file] [log] [blame]
Hamad Kadmany090709b2013-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 Nider435ad8e2011-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 Nider435ad8e2011-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 Nider435ad8e2011-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 Nider435ad8e2011-12-14 16:53:30 +020026#include <linux/ioport.h> /* XXX_ mem_region */
27#include <linux/dma-mapping.h> /* dma_XXX */
Hamad Kadmany090709b2013-01-06 12:08:13 +020028#include <linux/dmapool.h> /* DMA pools */
Joel Nider435ad8e2011-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 Nider435ad8e2011-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 Nider435ad8e2011-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 Nider435ad8e2011-12-14 16:53:30 +020038#include <linux/wakelock.h> /* Locking functions */
Hamad Kadmany81cee052012-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 Kuch59339922013-01-01 18:29:47 +020044#include <linux/of.h>
45#include <linux/of_gpio.h>
Liron Kuch275c0b32013-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 Kuch275c0b32013-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 Nider435ad8e2011-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 Kadmany81cee052012-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.
63 * Restrict it to half of this to save DMA memory.
64 */
65#define TSPP_SPS_DESCRIPTOR_COUNT (4 * 1024 - 1)
Joel Nider5556a852011-10-16 10:52:13 +020066#define TSPP_PACKET_LENGTH 188
67#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
Hamad Kadmany81cee052012-11-29 14:15:57 +020068
69/* Max descriptor buffer size allowed by SPS */
70#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
71
72/*
Hamad Kadmany090709b2013-01-06 12:08:13 +020073 * Returns whether to use DMA pool for TSPP output buffers.
74 * For buffers smaller than page size, using DMA pool
75 * provides better memory utilization as dma_alloc_coherent
76 * allocates minimum of page size.
77 */
78#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE)
79
80/*
Hamad Kadmany81cee052012-11-29 14:15:57 +020081 * Max allowed TSPP buffers/descriptors.
82 * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
83 */
84#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
Joel Nider5556a852011-10-16 10:52:13 +020085#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
86#define SPS_DESCRIPTOR_SIZE 8
87#define MIN_ACCEPTABLE_BUFFER_COUNT 2
Joel Nider435ad8e2011-12-14 16:53:30 +020088#define TSPP_DEBUG(msg...)
Joel Nider5556a852011-10-16 10:52:13 +020089
90/*
91 * TSIF register offsets
92 */
93#define TSIF_STS_CTL_OFF (0x0)
94#define TSIF_TIME_LIMIT_OFF (0x4)
95#define TSIF_CLK_REF_OFF (0x8)
96#define TSIF_LPBK_FLAGS_OFF (0xc)
97#define TSIF_LPBK_DATA_OFF (0x10)
98#define TSIF_TEST_CTL_OFF (0x14)
99#define TSIF_TEST_MODE_OFF (0x18)
100#define TSIF_TEST_RESET_OFF (0x1c)
101#define TSIF_TEST_EXPORT_OFF (0x20)
102#define TSIF_TEST_CURRENT_OFF (0x24)
103
104#define TSIF_DATA_PORT_OFF (0x100)
105
106/* bits for TSIF_STS_CTL register */
107#define TSIF_STS_CTL_EN_IRQ BIT(28)
108#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
109#define TSIF_STS_CTL_1ST_PACKET BIT(26)
110#define TSIF_STS_CTL_OVERFLOW BIT(25)
111#define TSIF_STS_CTL_LOST_SYNC BIT(24)
112#define TSIF_STS_CTL_TIMEOUT BIT(23)
113#define TSIF_STS_CTL_INV_SYNC BIT(21)
114#define TSIF_STS_CTL_INV_NULL BIT(20)
115#define TSIF_STS_CTL_INV_ERROR BIT(19)
116#define TSIF_STS_CTL_INV_ENABLE BIT(18)
117#define TSIF_STS_CTL_INV_DATA BIT(17)
118#define TSIF_STS_CTL_INV_CLOCK BIT(16)
119#define TSIF_STS_CTL_SPARE BIT(15)
120#define TSIF_STS_CTL_EN_NULL BIT(11)
121#define TSIF_STS_CTL_EN_ERROR BIT(10)
122#define TSIF_STS_CTL_LAST_BIT BIT(9)
123#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
124#define TSIF_STS_CTL_EN_TCR BIT(7)
125#define TSIF_STS_CTL_TEST_MODE BIT(6)
Joel Nider435ad8e2011-12-14 16:53:30 +0200126#define TSIF_STS_CTL_MODE_2 BIT(5)
Joel Nider5556a852011-10-16 10:52:13 +0200127#define TSIF_STS_CTL_EN_DM BIT(4)
128#define TSIF_STS_CTL_STOP BIT(3)
129#define TSIF_STS_CTL_START BIT(0)
130
131/*
132 * TSPP register offsets
133 */
Liron Kuch72b78552012-10-30 17:47:50 +0200134#define TSPP_RST 0x00
Joel Nider5556a852011-10-16 10:52:13 +0200135#define TSPP_CLK_CONTROL 0x04
Liron Kuch72b78552012-10-30 17:47:50 +0200136#define TSPP_CONFIG 0x08
137#define TSPP_CONTROL 0x0C
Joel Nider5556a852011-10-16 10:52:13 +0200138#define TSPP_PS_DISABLE 0x10
Liron Kuch72b78552012-10-30 17:47:50 +0200139#define TSPP_MSG_IRQ_STATUS 0x14
Joel Nider5556a852011-10-16 10:52:13 +0200140#define TSPP_MSG_IRQ_MASK 0x18
141#define TSPP_IRQ_STATUS 0x1C
142#define TSPP_IRQ_MASK 0x20
143#define TSPP_IRQ_CLEAR 0x24
144#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2))
Liron Kuch72b78552012-10-30 17:47:50 +0200145#define TSPP_STATUS 0x68
146#define TSPP_CURR_TSP_HEADER 0x6C
147#define TSPP_CURR_PID_FILTER 0x70
148#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2))
149#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2))
150#define TSPP_DATA_KEY_RESET 0x9C
Joel Nider5556a852011-10-16 10:52:13 +0200151#define TSPP_KEY_VALID 0xA0
152#define TSPP_KEY_ERROR 0xA4
153#define TSPP_TEST_CTRL 0xA8
Liron Kuch72b78552012-10-30 17:47:50 +0200154#define TSPP_VERSION 0xAC
Joel Nider5556a852011-10-16 10:52:13 +0200155#define TSPP_GENERICS 0xB0
Liron Kuch72b78552012-10-30 17:47:50 +0200156#define TSPP_NOP 0xB4
Joel Nider5556a852011-10-16 10:52:13 +0200157
158/*
159 * Register bit definitions
160 */
161/* TSPP_RST */
162#define TSPP_RST_RESET BIT(0)
163
164/* TSPP_CLK_CONTROL */
165#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9)
166#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8)
167#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7)
168#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6)
169#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5)
170#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
171#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3)
172#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
173#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
174#define TSPP_CLK_CONTROL_SET_CLKON BIT(0)
175
176/* TSPP_CONFIG */
177#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
178((_b & 0xF) << 8))
179#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
180#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7)
181#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6)
182#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5)
183#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
184#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3)
185#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2)
186#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1)
187#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0)
188
189/* TSPP_CONTROL */
190#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5)
191#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4)
192#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3)
193#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2)
194#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1)
195#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0)
196
197/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
198#define TSPP_MSG_TSPP_IRQ BIT(2)
199#define TSPP_MSG_TSIF_1_IRQ BIT(1)
200#define TSPP_MSG_TSIF_0_IRQ BIT(0)
201
202/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
Liron Kuch72b78552012-10-30 17:47:50 +0200203#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19)
204#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18)
Joel Nider5556a852011-10-16 10:52:13 +0200205#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17)
206#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16)
207#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n))
208
209/* TSPP_PIPE_ERROR_STATUS */
Liron Kuch72b78552012-10-30 17:47:50 +0200210#define TSPP_PIPE_PES_SYNC_ERROR BIT(3)
211#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2)
Joel Nider5556a852011-10-16 10:52:13 +0200212#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1)
Liron Kuch72b78552012-10-30 17:47:50 +0200213#define TSPP_PIP_PS_LOST_START BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200214
215/* TSPP_STATUS */
Liron Kuch72b78552012-10-30 17:47:50 +0200216#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10)
217#define TSPP_STATUS_TSIF1_DM_REQ BIT(6)
218#define TSPP_STATUS_TSIF0_DM_REQ BIT(2)
219#define TSPP_CURR_FILTER_TABLE BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200220
221/* TSPP_GENERICS */
Liron Kuch72b78552012-10-30 17:47:50 +0200222#define TSPP_GENERICS_CRYPTO_GEN BIT(12)
Joel Nider5556a852011-10-16 10:52:13 +0200223#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7)
Liron Kuch72b78552012-10-30 17:47:50 +0200224#define TSPP_GENERICS_MAX_PIPES BIT(2)
225#define TSPP_GENERICS_TSIF_1_GEN BIT(1)
226#define TSPP_GENERICS_TSIF_0_GEN BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200227
228/*
229 * TSPP memory regions
230 */
231#define TSPP_PID_FILTER_TABLE0 0x800
232#define TSPP_PID_FILTER_TABLE1 0x880
233#define TSPP_PID_FILTER_TABLE2 0x900
234#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */
235#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */
236#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */
237#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
238#define TSPP_DATA_KEY 0xCD0
239
Joel Nider5556a852011-10-16 10:52:13 +0200240struct debugfs_entry {
241 const char *name;
242 mode_t mode;
243 int offset;
244};
245
246static const struct debugfs_entry debugfs_tsif_regs[] = {
247 {"sts_ctl", S_IRUGO | S_IWUSR, TSIF_STS_CTL_OFF},
248 {"time_limit", S_IRUGO | S_IWUSR, TSIF_TIME_LIMIT_OFF},
249 {"clk_ref", S_IRUGO | S_IWUSR, TSIF_CLK_REF_OFF},
250 {"lpbk_flags", S_IRUGO | S_IWUSR, TSIF_LPBK_FLAGS_OFF},
251 {"lpbk_data", S_IRUGO | S_IWUSR, TSIF_LPBK_DATA_OFF},
252 {"test_ctl", S_IRUGO | S_IWUSR, TSIF_TEST_CTL_OFF},
253 {"test_mode", S_IRUGO | S_IWUSR, TSIF_TEST_MODE_OFF},
254 {"test_reset", S_IWUSR, TSIF_TEST_RESET_OFF},
255 {"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
256 {"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
257 {"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
258};
259
260static const struct debugfs_entry debugfs_tspp_regs[] = {
261 {"rst", S_IRUGO | S_IWUSR, TSPP_RST},
262 {"clk_control", S_IRUGO | S_IWUSR, TSPP_CLK_CONTROL},
263 {"config", S_IRUGO | S_IWUSR, TSPP_CONFIG},
264 {"control", S_IRUGO | S_IWUSR, TSPP_CONTROL},
265 {"ps_disable", S_IRUGO | S_IWUSR, TSPP_PS_DISABLE},
266 {"msg_irq_status", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_STATUS},
267 {"msg_irq_mask", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_MASK},
268 {"irq_status", S_IRUGO | S_IWUSR, TSPP_IRQ_STATUS},
269 {"irq_mask", S_IRUGO | S_IWUSR, TSPP_IRQ_MASK},
270 {"irq_clear", S_IRUGO | S_IWUSR, TSPP_IRQ_CLEAR},
271 /* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
272 {"status", S_IRUGO | S_IWUSR, TSPP_STATUS},
273 {"curr_tsp_header", S_IRUGO | S_IWUSR, TSPP_CURR_TSP_HEADER},
274 {"curr_pid_filter", S_IRUGO | S_IWUSR, TSPP_CURR_PID_FILTER},
275 /* {"system_key", S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
276 /* {"cbc_init_val", S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
277 {"data_key_reset", S_IRUGO | S_IWUSR, TSPP_DATA_KEY_RESET},
278 {"key_valid", S_IRUGO | S_IWUSR, TSPP_KEY_VALID},
279 {"key_error", S_IRUGO | S_IWUSR, TSPP_KEY_ERROR},
280 {"test_ctrl", S_IRUGO | S_IWUSR, TSPP_TEST_CTRL},
281 {"version", S_IRUGO | S_IWUSR, TSPP_VERSION},
282 {"generics", S_IRUGO | S_IWUSR, TSPP_GENERICS},
283 {"pid_filter_table0", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE0},
284 {"pid_filter_table1", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE1},
285 {"pid_filter_table2", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE2},
286 {"global_performance", S_IRUGO | S_IWUSR, TSPP_GLOBAL_PERFORMANCE},
287 {"pipe_context", S_IRUGO | S_IWUSR, TSPP_PIPE_CONTEXT},
288 {"pipe_performance", S_IRUGO | S_IWUSR, TSPP_PIPE_PERFORMANCE},
289 {"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
290};
291
Joel Nider5556a852011-10-16 10:52:13 +0200292struct tspp_pid_filter {
293 u32 filter; /* see FILTER_ macros */
294 u32 config; /* see FILTER_ macros */
295};
296
297/* tsp_info */
298#define FILTER_HEADER_ERROR_MASK BIT(7)
299#define FILTER_TRANS_END_DISABLE BIT(6)
300#define FILTER_DEC_ON_ERROR_EN BIT(5)
301#define FILTER_DECRYPT BIT(4)
302#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT)
303#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF)
304#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \
305 (_p->config & ~0xF) | (_b & 0xF))
306#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3)
307#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \
308 (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
309#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF)
310#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \
311 (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
312#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF)
313#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \
314 (_p->filter & ~0x1FFF) | (_b & 0x1FFF))
315#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3)
316#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \
317 (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
318#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7)
319#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \
320 (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
321
322struct tspp_global_performance_regs {
323 u32 tsp_total;
324 u32 tsp_ignored;
325 u32 tsp_error;
326 u32 tsp_sync;
327};
328
329struct tspp_pipe_context_regs {
330 u16 pes_bytes_left;
331 u16 count;
332 u32 tsif_suffix;
333} __packed;
334#define CONTEXT_GET_STATE(_a) (_a & 0x3)
335#define CONTEXT_UNSPEC_LENGTH BIT(11)
336#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
337
Hamad Kadmany81cee052012-11-29 14:15:57 +0200338#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
339
Joel Nider5556a852011-10-16 10:52:13 +0200340struct tspp_pipe_performance_regs {
341 u32 tsp_total;
342 u32 ps_duplicate_tsp;
343 u32 tsp_no_payload;
344 u32 tsp_broken_ps;
345 u32 ps_total_num;
346 u32 ps_continuity_error;
347 u32 ps_length_error;
348 u32 pes_sync_error;
349};
350
351struct tspp_tsif_device {
352 void __iomem *base;
353 u32 time_limit;
354 u32 ref_count;
Joel Nider435ad8e2011-12-14 16:53:30 +0200355 enum tspp_tsif_mode mode;
Hamad Kadmany92705b32012-10-23 14:15:41 +0200356 int clock_inverse;
357 int data_inverse;
358 int sync_inverse;
359 int enable_inverse;
Hamad Kadmany44307d32012-11-25 09:49:51 +0200360 u32 tsif_irq;
Joel Nider5556a852011-10-16 10:52:13 +0200361
362 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200363 struct dentry *dent_tsif;
364 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Hamad Kadmany44307d32012-11-25 09:49:51 +0200365 u32 stat_rx;
366 u32 stat_overflow;
367 u32 stat_lost_sync;
368 u32 stat_timeout;
Joel Nider5556a852011-10-16 10:52:13 +0200369};
370
371enum tspp_buf_state {
372 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
373 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider435ad8e2011-12-14 16:53:30 +0200374 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
375 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200376};
377
378struct tspp_mem_buffer {
Joel Nider435ad8e2011-12-14 16:53:30 +0200379 struct tspp_mem_buffer *next;
380 struct sps_mem_buffer sps;
381 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200382 enum tspp_buf_state state;
383 size_t filled; /* how much data this buffer is holding */
384 int read_index; /* where to start reading data from */
385};
386
387/* this represents each char device 'channel' */
388struct tspp_channel {
389 struct cdev cdev;
390 struct device *dd;
Joel Nider435ad8e2011-12-14 16:53:30 +0200391 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200392 struct sps_pipe *pipe;
393 struct sps_connect config;
394 struct sps_register_event event;
Joel Nider435ad8e2011-12-14 16:53:30 +0200395 struct tspp_mem_buffer *data; /* list of buffers */
396 struct tspp_mem_buffer *read; /* first buffer ready to be read */
397 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
398 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200399 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider435ad8e2011-12-14 16:53:30 +0200400 u32 id; /* channel id (0-15) */
401 int used; /* is this channel in use? */
402 int key; /* which encryption key index is used */
403 u32 buffer_size; /* size of the sps transfer buffers */
404 u32 max_buffers; /* how many buffers should be allocated */
405 u32 buffer_count; /* how many buffers are actually allocated */
406 u32 filter_count; /* how many filters have been added to this channel */
407 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200408 enum tspp_source src;
409 enum tspp_mode mode;
Joel Nider435ad8e2011-12-14 16:53:30 +0200410 tspp_notifier *notifier; /* used only with kernel api */
411 void *notify_data; /* data to be passed with the notifier */
Hamad Kadmany81cee052012-11-29 14:15:57 +0200412 u32 expiration_period_ms; /* notification on partially filled buffers */
413 struct timer_list expiration_timer;
Hamad Kadmany090709b2013-01-06 12:08:13 +0200414 struct dma_pool *dma_pool;
Liron Kuch72b78552012-10-30 17:47:50 +0200415 tspp_memfree *memfree; /* user defined memory free function */
416 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200417};
418
419struct tspp_pid_filter_table {
420 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
421};
422
423struct tspp_key_entry {
424 u32 even_lsb;
425 u32 even_msb;
426 u32 odd_lsb;
427 u32 odd_msb;
428};
429
430struct tspp_key_table {
431 struct tspp_key_entry entry[TSPP_NUM_KEYS];
432};
433
Joel Nider435ad8e2011-12-14 16:53:30 +0200434/* this represents the actual hardware device */
435struct tspp_device {
436 struct list_head devlist; /* list of all devices */
437 struct platform_device *pdev;
438 void __iomem *base;
439 unsigned int tspp_irq;
440 unsigned int bam_irq;
441 u32 bam_handle;
442 struct sps_bam_props bam_props;
443 struct wake_lock wake_lock;
444 spinlock_t spinlock;
445 struct tasklet_struct tlet;
446 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
447 /* clocks */
448 struct clk *tsif_pclk;
449 struct clk *tsif_ref_clk;
450 /* data */
451 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
452 struct tspp_channel channels[TSPP_NUM_CHANNELS];
453 struct tspp_key_table *tspp_key_table;
454 struct tspp_global_performance_regs *tspp_global_performance;
455 struct tspp_pipe_context_regs *tspp_pipe_context;
456 struct tspp_pipe_performance_regs *tspp_pipe_performance;
457
458 struct dentry *dent;
459 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
460};
461
462
Joel Nider5556a852011-10-16 10:52:13 +0200463static struct class *tspp_class;
464static int tspp_key_entry;
465static dev_t tspp_minor; /* next minor number to assign */
Joel Nider435ad8e2011-12-14 16:53:30 +0200466
467static LIST_HEAD(tspp_devices);
468
469/* forward declarations */
470static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
471static ssize_t tspp_open(struct inode *inode, struct file *filp);
472static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
473static ssize_t tspp_release(struct inode *inode, struct file *filp);
474static long tspp_ioctl(struct file *, unsigned int, unsigned long);
475
476/* file operations */
477static const struct file_operations tspp_fops = {
478 .owner = THIS_MODULE,
479 .read = tspp_read,
480 .open = tspp_open,
481 .poll = tspp_poll,
482 .release = tspp_release,
483 .unlocked_ioctl = tspp_ioctl,
484};
Joel Nider5556a852011-10-16 10:52:13 +0200485
486/*** IRQ ***/
Joel Nider435ad8e2011-12-14 16:53:30 +0200487static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200488{
Joel Nider435ad8e2011-12-14 16:53:30 +0200489 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200490 u32 status, mask;
491 u32 data;
492
493 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
494 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
495 status &= mask;
496
497 if (!status) {
498 dev_warn(&device->pdev->dev, "Spurious interrupt");
499 return IRQ_NONE;
500 }
501
502 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
503
504 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
505 /* read the key error info */
506 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
507 dev_info(&device->pdev->dev, "key error 0x%x", data);
508 }
509 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
510 data = readl_relaxed(device->base + TSPP_KEY_VALID);
511 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
512 }
513 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
514 dev_info(&device->pdev->dev, "key switched");
515
516 if (status & 0xffff)
Joel Nider435ad8e2011-12-14 16:53:30 +0200517 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200518
519 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
Hamad Kadmany44307d32012-11-25 09:49:51 +0200520
521 /*
522 * Before returning IRQ_HANDLED to the generic interrupt handling
523 * framework need to make sure all operations including clearing of
524 * interrupt status registers in the hardware is performed.
525 * Thus a barrier after clearing the interrupt status register
526 * is required to guarantee that the interrupt status register has
527 * really been cleared by the time we return from this handler.
528 */
529 wmb();
530 return IRQ_HANDLED;
531}
532
533static irqreturn_t tsif_isr(int irq, void *dev)
534{
535 struct tspp_tsif_device *tsif_device = dev;
536 u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
537
538 if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
539 TSIF_STS_CTL_OVERFLOW |
540 TSIF_STS_CTL_LOST_SYNC |
541 TSIF_STS_CTL_TIMEOUT)))
542 return IRQ_NONE;
543
544 if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
545 tsif_device->stat_overflow++;
546
547 if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
548 tsif_device->stat_lost_sync++;
549
550 if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
551 tsif_device->stat_timeout++;
552
553 iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
554
555 /*
556 * Before returning IRQ_HANDLED to the generic interrupt handling
557 * framework need to make sure all operations including clearing of
558 * interrupt status registers in the hardware is performed.
559 * Thus a barrier after clearing the interrupt status register
560 * is required to guarantee that the interrupt status register has
561 * really been cleared by the time we return from this handler.
562 */
Joel Nider5556a852011-10-16 10:52:13 +0200563 wmb();
564 return IRQ_HANDLED;
565}
566
567/*** callbacks ***/
568static void tspp_sps_complete_cb(struct sps_event_notify *notify)
569{
Joel Nider435ad8e2011-12-14 16:53:30 +0200570 struct tspp_device *pdev = notify->user;
571 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200572}
573
Hamad Kadmany81cee052012-11-29 14:15:57 +0200574static void tspp_expiration_timer(unsigned long data)
575{
576 struct tspp_device *pdev = (struct tspp_device *)data;
577
578 if (pdev)
579 tasklet_schedule(&pdev->tlet);
580}
581
Joel Nider5556a852011-10-16 10:52:13 +0200582/*** tasklet ***/
583static void tspp_sps_complete_tlet(unsigned long data)
584{
585 int i;
586 int complete;
587 unsigned long flags;
588 struct sps_iovec iovec;
589 struct tspp_channel *channel;
590 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200591 spin_lock_irqsave(&device->spinlock, flags);
592
593 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
594 complete = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +0200595 channel = &device->channels[i];
Hamad Kadmany81cee052012-11-29 14:15:57 +0200596
Joel Nider435ad8e2011-12-14 16:53:30 +0200597 if (!channel->used || !channel->waiting)
598 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200599
Hamad Kadmany81cee052012-11-29 14:15:57 +0200600 /* stop the expiration timer */
601 if (channel->expiration_period_ms)
602 del_timer(&channel->expiration_timer);
603
Joel Nider5556a852011-10-16 10:52:13 +0200604 /* get completions */
Joel Nider435ad8e2011-12-14 16:53:30 +0200605 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200606 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
607 pr_err("tspp: Error in iovec on channel %i",
608 channel->id);
609 break;
610 }
611 if (iovec.size == 0)
612 break;
613
Joel Nider435ad8e2011-12-14 16:53:30 +0200614 if (iovec.addr != channel->waiting->sps.phys_base)
Joel Nider5556a852011-10-16 10:52:13 +0200615 pr_err("tspp: buffer mismatch 0x%08x",
Joel Nider435ad8e2011-12-14 16:53:30 +0200616 channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200617
618 complete = 1;
Joel Nider435ad8e2011-12-14 16:53:30 +0200619 channel->waiting->state = TSPP_BUF_STATE_DATA;
620 channel->waiting->filled = iovec.size;
621 channel->waiting->read_index = 0;
622
Hamad Kadmany44307d32012-11-25 09:49:51 +0200623 if (channel->src == TSPP_SOURCE_TSIF0)
624 device->tsif[0].stat_rx++;
625 else if (channel->src == TSPP_SOURCE_TSIF1)
626 device->tsif[1].stat_rx++;
627
Joel Nider435ad8e2011-12-14 16:53:30 +0200628 /* update the pointers */
629 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200630 }
631
Joel Nider435ad8e2011-12-14 16:53:30 +0200632 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200633 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200634 wake_up_interruptible(&channel->in_queue);
Joel Nider435ad8e2011-12-14 16:53:30 +0200635
636 /* call notifiers */
637 if (channel->notifier)
638 channel->notifier(channel->id,
639 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200640 }
Hamad Kadmany81cee052012-11-29 14:15:57 +0200641
642 /* restart expiration timer */
643 if (channel->expiration_period_ms)
644 mod_timer(&channel->expiration_timer,
645 jiffies +
646 MSEC_TO_JIFFIES(
647 channel->expiration_period_ms));
Joel Nider5556a852011-10-16 10:52:13 +0200648 }
649
650 spin_unlock_irqrestore(&device->spinlock, flags);
651}
652
653/*** GPIO functions ***/
Liron Kuch275c0b32013-02-10 15:19:32 +0200654static int tspp_gpios_disable(const struct tspp_tsif_device *tsif_device,
655 const struct msm_gpio *table,
656 int size)
Joel Nider5556a852011-10-16 10:52:13 +0200657{
658 int rc = 0;
659 int i;
660 const struct msm_gpio *g;
Liron Kuch59339922013-01-01 18:29:47 +0200661
Joel Nider5556a852011-10-16 10:52:13 +0200662 for (i = size-1; i >= 0; i--) {
663 int tmp;
664 g = table + i;
Liron Kuch59339922013-01-01 18:29:47 +0200665
Liron Kuch275c0b32013-02-10 15:19:32 +0200666 /* don't use sync GPIO when not working in mode 2 */
667 if ((tsif_device->mode != TSPP_TSIF_MODE_2) &&
668 (strnstr(g->label, "sync", strlen(g->label)) != NULL))
669 continue;
670
Liron Kuch59339922013-01-01 18:29:47 +0200671 tmp = gpio_tlmm_config(GPIO_CFG(GPIO_PIN(g->gpio_cfg),
672 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
673 GPIO_CFG_DISABLE);
Joel Nider5556a852011-10-16 10:52:13 +0200674 if (tmp) {
Liron Kuch72b78552012-10-30 17:47:50 +0200675 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200676 g->gpio_cfg, g->label ?: "?", rc);
677 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
678 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
679 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
680 GPIO_DRVSTR(g->gpio_cfg));
681 if (!rc)
682 rc = tmp;
683 }
684 }
685
686 return rc;
687}
688
Liron Kuch275c0b32013-02-10 15:19:32 +0200689static int tspp_gpios_enable(const struct tspp_tsif_device *tsif_device,
690 const struct msm_gpio *table,
691 int size)
Joel Nider5556a852011-10-16 10:52:13 +0200692{
693 int rc;
Liron Kuch275c0b32013-02-10 15:19:32 +0200694 int i;
Joel Nider5556a852011-10-16 10:52:13 +0200695 const struct msm_gpio *g;
Liron Kuch59339922013-01-01 18:29:47 +0200696
Joel Nider5556a852011-10-16 10:52:13 +0200697 for (i = 0; i < size; i++) {
698 g = table + i;
Liron Kuch275c0b32013-02-10 15:19:32 +0200699
700 /* don't use sync GPIO when not working in mode 2 */
701 if ((tsif_device->mode != TSPP_TSIF_MODE_2) &&
702 (strnstr(g->label, "sync", strlen(g->label)) != NULL))
703 continue;
704
Joel Nider5556a852011-10-16 10:52:13 +0200705 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
706 if (rc) {
Liron Kuch72b78552012-10-30 17:47:50 +0200707 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200708 g->gpio_cfg, g->label ?: "?", rc);
709 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
710 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
711 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
712 GPIO_DRVSTR(g->gpio_cfg));
713 goto err;
714 }
715 }
716 return 0;
717err:
Liron Kuch275c0b32013-02-10 15:19:32 +0200718 tspp_gpios_disable(tsif_device, table, i);
Joel Nider5556a852011-10-16 10:52:13 +0200719
Joel Nider5556a852011-10-16 10:52:13 +0200720 return rc;
721}
722
Liron Kuch275c0b32013-02-10 15:19:32 +0200723
724static int tspp_config_gpios(struct tspp_device *device,
725 enum tspp_source source,
726 int enable)
Joel Nider5556a852011-10-16 10:52:13 +0200727{
Liron Kuch275c0b32013-02-10 15:19:32 +0200728 const struct msm_gpio *table;
729 struct msm_tspp_platform_data *pdata = device->pdev->dev.platform_data;
730 int num_gpios = (pdata->num_gpios / TSPP_TSIF_INSTANCES);
731 int i = 0;
Liron Kuch59339922013-01-01 18:29:47 +0200732
Liron Kuch275c0b32013-02-10 15:19:32 +0200733 if (num_gpios != TSPP_GPIOS_PER_TSIF) {
734 pr_err("tspp %s: unexpected number of GPIOs %d, expected %d\n",
735 __func__, num_gpios, TSPP_GPIOS_PER_TSIF);
736 return -EINVAL;
737 }
Joel Nider5556a852011-10-16 10:52:13 +0200738
Liron Kuch275c0b32013-02-10 15:19:32 +0200739 /*
740 * Note: this code assumes that the GPIO definitions in the
741 * pdata->gpios table are according to the TSIF instance number,
742 * i.e., that TSIF0 GPIOs are defined first, then TSIF1 GPIOs etc.
743 */
744 switch (source) {
745 case TSPP_SOURCE_TSIF0:
746 i = 0;
747 break;
748 case TSPP_SOURCE_TSIF1:
749 i = 1;
750 break;
751 default:
752 pr_err("tspp %s: invalid source\n", __func__);
753 return -EINVAL;
754 }
Liron Kuch59339922013-01-01 18:29:47 +0200755
Liron Kuch275c0b32013-02-10 15:19:32 +0200756 table = pdata->gpios + (i * num_gpios);
757 if (enable)
758 return tspp_gpios_enable(&device->tsif[i], table, num_gpios);
759 else
760 return tspp_gpios_disable(&device->tsif[i], table, num_gpios);
Joel Nider5556a852011-10-16 10:52:13 +0200761}
762
Joel Nider435ad8e2011-12-14 16:53:30 +0200763/*** Clock functions ***/
764static int tspp_clock_start(struct tspp_device *device)
765{
Liron Kuch605cc122013-02-21 14:25:57 +0200766 if (device == NULL) {
767 pr_err("tspp: Can't start clocks, invalid device\n");
768 return -EINVAL;
769 }
770
Joel Nider435ad8e2011-12-14 16:53:30 +0200771 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
772 pr_err("tspp: Can't start pclk");
773 return -EBUSY;
774 }
775
776 if (device->tsif_ref_clk &&
777 clk_prepare_enable(device->tsif_ref_clk) != 0) {
778 pr_err("tspp: Can't start ref clk");
779 clk_disable_unprepare(device->tsif_pclk);
780 return -EBUSY;
781 }
782
783 return 0;
784}
785
786static void tspp_clock_stop(struct tspp_device *device)
787{
Liron Kuch605cc122013-02-21 14:25:57 +0200788 if (device == NULL) {
789 pr_err("tspp: Can't stop clocks, invalid device\n");
790 return;
791 }
792
Joel Nider435ad8e2011-12-14 16:53:30 +0200793 if (device->tsif_pclk)
Liron Kuch605cc122013-02-21 14:25:57 +0200794 clk_disable_unprepare(device->tsif_pclk);
Joel Nider435ad8e2011-12-14 16:53:30 +0200795
796 if (device->tsif_ref_clk)
Liron Kuch605cc122013-02-21 14:25:57 +0200797 clk_disable_unprepare(device->tsif_ref_clk);
Joel Nider435ad8e2011-12-14 16:53:30 +0200798}
799
Joel Nider5556a852011-10-16 10:52:13 +0200800/*** TSIF functions ***/
801static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
802{
803 int start_hardware = 0;
804 u32 ctl;
805
806 if (tsif_device->ref_count == 0) {
807 start_hardware = 1;
808 } else if (tsif_device->ref_count > 0) {
809 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
810 if ((ctl & TSIF_STS_CTL_START) != 1) {
811 /* this hardware should already be running */
812 pr_warn("tspp: tsif hw not started but ref count > 0");
813 start_hardware = 1;
814 }
815 }
816
817 if (start_hardware) {
Joel Nider435ad8e2011-12-14 16:53:30 +0200818 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200819 TSIF_STS_CTL_EN_DM;
Hamad Kadmany92705b32012-10-23 14:15:41 +0200820
821 if (tsif_device->clock_inverse)
822 ctl |= TSIF_STS_CTL_INV_CLOCK;
823
824 if (tsif_device->data_inverse)
825 ctl |= TSIF_STS_CTL_INV_DATA;
826
827 if (tsif_device->sync_inverse)
828 ctl |= TSIF_STS_CTL_INV_SYNC;
829
830 if (tsif_device->enable_inverse)
831 ctl |= TSIF_STS_CTL_INV_ENABLE;
832
Joel Nider435ad8e2011-12-14 16:53:30 +0200833 switch (tsif_device->mode) {
834 case TSPP_TSIF_MODE_LOOPBACK:
835 ctl |= TSIF_STS_CTL_EN_NULL |
836 TSIF_STS_CTL_EN_ERROR |
837 TSIF_STS_CTL_TEST_MODE;
838 break;
839 case TSPP_TSIF_MODE_1:
840 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
841 TSIF_STS_CTL_EN_TCR;
842 break;
843 case TSPP_TSIF_MODE_2:
844 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
845 TSIF_STS_CTL_EN_TCR |
846 TSIF_STS_CTL_MODE_2;
847 break;
848 default:
849 pr_warn("tspp: unknown tsif mode 0x%x",
850 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200851 }
852 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
853 writel_relaxed(tsif_device->time_limit,
854 tsif_device->base + TSIF_TIME_LIMIT_OFF);
855 wmb();
856 writel_relaxed(ctl | TSIF_STS_CTL_START,
857 tsif_device->base + TSIF_STS_CTL_OFF);
858 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200859 }
860
Joel Nider435ad8e2011-12-14 16:53:30 +0200861 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Joel Nider5556a852011-10-16 10:52:13 +0200862 tsif_device->ref_count++;
863
Joel Nider435ad8e2011-12-14 16:53:30 +0200864 return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200865}
866
867static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
868{
869 if (tsif_device->ref_count == 0)
870 return;
871
872 tsif_device->ref_count--;
873
874 if (tsif_device->ref_count == 0) {
875 writel_relaxed(TSIF_STS_CTL_STOP,
876 tsif_device->base + TSIF_STS_CTL_OFF);
877 wmb();
878 }
879}
880
Joel Nider435ad8e2011-12-14 16:53:30 +0200881/*** local TSPP functions ***/
882static int tspp_channels_in_use(struct tspp_device *pdev)
883{
884 int i;
885 int count = 0;
886 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
887 count += (pdev->channels[i].used ? 1 : 0);
888
889 return count;
890}
891
892static struct tspp_device *tspp_find_by_id(int id)
893{
894 struct tspp_device *dev;
895 list_for_each_entry(dev, &tspp_devices, devlist) {
896 if (dev->pdev->id == id)
897 return dev;
898 }
899 return NULL;
900}
901
Joel Nider5556a852011-10-16 10:52:13 +0200902static int tspp_get_key_entry(void)
903{
904 int i;
905 for (i = 0; i < TSPP_NUM_KEYS; i++) {
906 if (!(tspp_key_entry & (1 << i))) {
907 tspp_key_entry |= (1 << i);
908 return i;
909 }
910 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200911 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200912}
913
914static void tspp_free_key_entry(int entry)
915{
916 if (entry > TSPP_NUM_KEYS) {
917 pr_err("tspp_free_key_entry: index out of bounds");
918 return;
919 }
920
921 tspp_key_entry &= ~(1 << entry);
922}
923
Joel Nider435ad8e2011-12-14 16:53:30 +0200924static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
Hamad Kadmany090709b2013-01-06 12:08:13 +0200925 u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200926{
Joel Nider435ad8e2011-12-14 16:53:30 +0200927 if (size < TSPP_MIN_BUFFER_SIZE ||
928 size > TSPP_MAX_BUFFER_SIZE) {
929 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200930 return -ENOMEM;
931 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200932
933 if (alloc) {
934 TSPP_DEBUG("tspp using alloc function");
935 desc->virt_base = alloc(channel_id, size,
936 &desc->phys_base, user);
937 } else {
Hamad Kadmany090709b2013-01-06 12:08:13 +0200938 if (!dma_pool)
939 desc->virt_base = dma_alloc_coherent(NULL, size,
940 &desc->phys_base, GFP_KERNEL);
941 else
942 desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL,
943 &desc->phys_base);
944
Liron Kuch72b78552012-10-30 17:47:50 +0200945 if (desc->virt_base == 0) {
Hamad Kadmany090709b2013-01-06 12:08:13 +0200946 pr_err("tspp: dma buffer allocation failed %i\n", size);
Liron Kuch72b78552012-10-30 17:47:50 +0200947 return -ENOMEM;
948 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200949 }
950
951 desc->size = size;
952 return 0;
953}
954
955static int tspp_queue_buffer(struct tspp_channel *channel,
956 struct tspp_mem_buffer *buffer)
957{
958 int rc;
959 u32 flags = 0;
960
961 /* make sure the interrupt frequency is valid */
962 if (channel->int_freq < 1)
963 channel->int_freq = 1;
964
965 /* generate interrupt according to requested frequency */
966 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
Hamad Kadmany81cee052012-11-29 14:15:57 +0200967 flags = SPS_IOVEC_FLAG_INT;
Joel Nider435ad8e2011-12-14 16:53:30 +0200968
969 /* start the transfer */
970 rc = sps_transfer_one(channel->pipe,
971 buffer->sps.phys_base,
972 buffer->sps.size,
973 channel->pdev,
974 flags);
975 if (rc < 0)
976 return rc;
977
978 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +0200979
980 return 0;
981}
982
983static int tspp_global_reset(struct tspp_device *pdev)
984{
985 u32 i, val;
986
987 /* stop all TSIFs */
988 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
989 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
990 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
991 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmany92705b32012-10-23 14:15:41 +0200992 pdev->tsif[i].clock_inverse = 0;
993 pdev->tsif[i].data_inverse = 0;
994 pdev->tsif[i].sync_inverse = 0;
995 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +0200996 }
997 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
998 wmb();
999
1000 /* BAM */
1001 if (sps_device_reset(pdev->bam_handle) != 0) {
1002 pr_err("tspp: error resetting bam");
Joel Nider435ad8e2011-12-14 16:53:30 +02001003 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001004 }
1005
1006 /* TSPP tables */
1007 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider435ad8e2011-12-14 16:53:30 +02001008 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +02001009 0, sizeof(struct tspp_pid_filter_table));
1010
1011 /* disable all filters */
1012 val = (2 << TSPP_NUM_CHANNELS) - 1;
1013 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
1014
1015 /* TSPP registers */
1016 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1017 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1018 pdev->base + TSPP_CONTROL);
1019 wmb();
Joel Nider435ad8e2011-12-14 16:53:30 +02001020 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001021 sizeof(struct tspp_global_performance_regs));
Joel Nider435ad8e2011-12-14 16:53:30 +02001022 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001023 sizeof(struct tspp_pipe_context_regs));
Joel Nider435ad8e2011-12-14 16:53:30 +02001024 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001025 sizeof(struct tspp_pipe_performance_regs));
1026 wmb();
1027 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1028 pdev->base + TSPP_CONTROL);
1029 wmb();
1030
1031 val = readl_relaxed(pdev->base + TSPP_CONFIG);
1032 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
1033 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
1034 TSPP_CONFIG_PS_CONT_ERR_MASK);
1035 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
1036 writel_relaxed(val, pdev->base + TSPP_CONFIG);
Hamad Kadmany6bac7832012-12-20 18:30:40 +02001037 writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK);
Joel Nider5556a852011-10-16 10:52:13 +02001038 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
1039 writel_relaxed(0, pdev->base + TSPP_RST);
1040 wmb();
1041
1042 tspp_key_entry = 0;
1043
1044 return 0;
1045}
1046
Joel Nider435ad8e2011-12-14 16:53:30 +02001047static int tspp_select_source(u32 dev, u32 channel_id,
1048 struct tspp_select_source *src)
1049{
1050 /* make sure the requested src id is in bounds */
1051 if (src->source > TSPP_SOURCE_MEM) {
1052 pr_err("tspp source out of bounds");
1053 return -EINVAL;
1054 }
1055
1056 /* open the stream */
Hamad Kadmany92705b32012-10-23 14:15:41 +02001057 tspp_open_stream(dev, channel_id, src);
Joel Nider435ad8e2011-12-14 16:53:30 +02001058
1059 return 0;
1060}
1061
1062static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
1063{
1064 struct tspp_device *pdev = channel->pdev;
1065
1066 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
1067 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
1068 return 0;
1069}
1070
1071static int tspp_set_system_keys(struct tspp_channel *channel,
1072 struct tspp_system_keys *keys)
1073{
1074 int i;
1075 struct tspp_device *pdev = channel->pdev;
1076
1077 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
1078 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
1079
1080 return 0;
1081}
1082
1083static int tspp_channel_init(struct tspp_channel *channel,
1084 struct tspp_device *pdev)
1085{
1086 channel->cdev.owner = THIS_MODULE;
1087 cdev_init(&channel->cdev, &tspp_fops);
1088 channel->pdev = pdev;
1089 channel->data = NULL;
1090 channel->read = NULL;
1091 channel->waiting = NULL;
1092 channel->locked = NULL;
1093 channel->id = MINOR(tspp_minor);
1094 channel->used = 0;
1095 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1096 channel->max_buffers = TSPP_NUM_BUFFERS;
1097 channel->buffer_count = 0;
1098 channel->filter_count = 0;
1099 channel->int_freq = 1;
Liron Kuch72b78552012-10-30 17:47:50 +02001100 channel->src = TSPP_SOURCE_NONE;
1101 channel->mode = TSPP_MODE_DISABLED;
Joel Nider435ad8e2011-12-14 16:53:30 +02001102 channel->notifier = NULL;
1103 channel->notify_data = NULL;
Hamad Kadmany81cee052012-11-29 14:15:57 +02001104 channel->expiration_period_ms = 0;
Liron Kuch72b78552012-10-30 17:47:50 +02001105 channel->memfree = NULL;
1106 channel->user_info = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001107 init_waitqueue_head(&channel->in_queue);
1108
1109 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
1110 pr_err("tspp: cdev_add failed");
1111 return -EBUSY;
1112 }
1113
1114 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
1115 channel, "tspp%02d", channel->id);
1116 if (IS_ERR(channel->dd)) {
1117 pr_err("tspp: device_create failed: %i",
1118 (int)PTR_ERR(channel->dd));
1119 cdev_del(&channel->cdev);
1120 return -EBUSY;
1121 }
1122
1123 return 0;
1124}
1125
1126static int tspp_set_buffer_size(struct tspp_channel *channel,
1127 struct tspp_buffer *buf)
1128{
Liron Kuch72b78552012-10-30 17:47:50 +02001129 if (channel->buffer_count > 0) {
1130 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1131 return -EPERM;
1132 }
1133
Joel Nider435ad8e2011-12-14 16:53:30 +02001134 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1135 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1136 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1137 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1138 else
1139 channel->buffer_size = buf->size;
1140
1141 return 0;
1142}
1143
1144static void tspp_set_tsif_mode(struct tspp_channel *channel,
1145 enum tspp_tsif_mode mode)
1146{
1147 int index;
1148
1149 switch (channel->src) {
1150 case TSPP_SOURCE_TSIF0:
1151 index = 0;
1152 break;
1153 case TSPP_SOURCE_TSIF1:
1154 index = 1;
1155 break;
1156 default:
1157 pr_warn("tspp: can't set mode for non-tsif source %d",
1158 channel->src);
1159 return;
1160 }
1161 channel->pdev->tsif[index].mode = mode;
1162}
1163
Hamad Kadmany92705b32012-10-23 14:15:41 +02001164static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch72b78552012-10-30 17:47:50 +02001165 int clock_inverse, int data_inverse,
1166 int sync_inverse, int enable_inverse)
Hamad Kadmany92705b32012-10-23 14:15:41 +02001167{
1168 int index;
1169
1170 switch (channel->src) {
1171 case TSPP_SOURCE_TSIF0:
1172 index = 0;
1173 break;
1174 case TSPP_SOURCE_TSIF1:
1175 index = 1;
1176 break;
1177 default:
1178 return;
1179 }
1180 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1181 channel->pdev->tsif[index].data_inverse = data_inverse;
1182 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1183 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1184}
1185
Liron Kuch72b78552012-10-30 17:47:50 +02001186static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1187{
1188 u32 alignment;
1189
1190 switch (mode) {
1191 case TSPP_MODE_RAW:
1192 /* must be a multiple of 192 */
1193 alignment = (TSPP_PACKET_LENGTH + 4);
1194 if (size % alignment)
1195 return 0;
1196 return 1;
1197
1198 case TSPP_MODE_RAW_NO_SUFFIX:
1199 /* must be a multiple of 188 */
1200 alignment = TSPP_PACKET_LENGTH;
1201 if (size % alignment)
1202 return 0;
1203 return 1;
1204
1205 case TSPP_MODE_DISABLED:
1206 case TSPP_MODE_PES:
1207 default:
1208 /* no alignment requirement */
1209 return 1;
1210 }
1211
1212}
1213
1214static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1215{
1216 u32 new_size;
1217 u32 alignment;
1218
1219 switch (mode) {
1220 case TSPP_MODE_RAW:
1221 /* must be a multiple of 192 */
1222 alignment = (TSPP_PACKET_LENGTH + 4);
1223 break;
1224
1225 case TSPP_MODE_RAW_NO_SUFFIX:
1226 /* must be a multiple of 188 */
1227 alignment = TSPP_PACKET_LENGTH;
1228 break;
1229
1230 case TSPP_MODE_DISABLED:
1231 case TSPP_MODE_PES:
1232 default:
1233 /* no alignment requirement - give the user what he asks for */
1234 alignment = 1;
1235 break;
1236 }
1237 /* align up */
1238 new_size = (((size + alignment - 1) / alignment) * alignment);
1239 return new_size;
1240}
1241
1242static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1243{
1244 int i;
1245 struct tspp_mem_buffer *pbuf, *temp;
1246
1247 pbuf = channel->data;
1248 for (i = 0; i < channel->buffer_count; i++) {
1249 if (pbuf->desc.phys_base) {
1250 if (channel->memfree) {
1251 channel->memfree(channel_id,
1252 pbuf->desc.size,
1253 pbuf->desc.virt_base,
1254 pbuf->desc.phys_base,
1255 channel->user_info);
1256 } else {
Hamad Kadmany090709b2013-01-06 12:08:13 +02001257 if (!channel->dma_pool)
1258 dma_free_coherent(NULL,
1259 pbuf->desc.size,
1260 pbuf->desc.virt_base,
1261 pbuf->desc.phys_base);
1262 else
1263 dma_pool_free(channel->dma_pool,
1264 pbuf->desc.virt_base,
1265 pbuf->desc.phys_base);
Liron Kuch72b78552012-10-30 17:47:50 +02001266 }
1267 pbuf->desc.phys_base = 0;
1268 }
1269 pbuf->desc.virt_base = 0;
1270 pbuf->state = TSPP_BUF_STATE_EMPTY;
1271 temp = pbuf;
1272 pbuf = pbuf->next;
1273 kfree(temp);
1274 }
1275}
1276
Joel Nider435ad8e2011-12-14 16:53:30 +02001277/*** TSPP API functions ***/
Liron Kuch72b78552012-10-30 17:47:50 +02001278
1279/**
1280 * tspp_open_stream - open a TSPP stream for use.
1281 *
1282 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1283 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1284 * @source: stream source parameters.
1285 *
1286 * Return error status
1287 *
1288 */
1289int tspp_open_stream(u32 dev, u32 channel_id,
1290 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001291{
1292 u32 val;
1293 struct tspp_device *pdev;
Joel Nider435ad8e2011-12-14 16:53:30 +02001294 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001295
Hamad Kadmany92705b32012-10-23 14:15:41 +02001296 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1297 dev, channel_id, source->source, source->mode);
Liron Kuch72b78552012-10-30 17:47:50 +02001298
Joel Nider435ad8e2011-12-14 16:53:30 +02001299 if (dev >= TSPP_MAX_DEVICES) {
1300 pr_err("tspp: device id out of range");
1301 return -ENODEV;
1302 }
Joel Nider5556a852011-10-16 10:52:13 +02001303
Joel Nider435ad8e2011-12-14 16:53:30 +02001304 if (channel_id >= TSPP_NUM_CHANNELS) {
1305 pr_err("tspp: channel id out of range");
1306 return -ECHRNG;
1307 }
1308
1309 pdev = tspp_find_by_id(dev);
1310 if (!pdev) {
1311 pr_err("tspp_str: can't find device %i", dev);
1312 return -ENODEV;
1313 }
1314 channel = &pdev->channels[channel_id];
Hamad Kadmany92705b32012-10-23 14:15:41 +02001315 channel->src = source->source;
1316 tspp_set_tsif_mode(channel, source->mode);
1317 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch72b78552012-10-30 17:47:50 +02001318 source->data_inverse, source->sync_inverse,
1319 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001320
Hamad Kadmany92705b32012-10-23 14:15:41 +02001321 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001322 case TSPP_SOURCE_TSIF0:
Liron Kuch275c0b32013-02-10 15:19:32 +02001323 if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
1324 pr_err("tspp: error enabling tsif0 GPIOs\n");
1325 return -EBUSY;
1326 }
Joel Nider5556a852011-10-16 10:52:13 +02001327 /* make sure TSIF0 is running & enabled */
1328 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
1329 pr_err("tspp: error starting tsif0");
Joel Nider435ad8e2011-12-14 16:53:30 +02001330 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001331 }
Liron Kucha7b49ae2013-02-14 16:26:38 +02001332 if (pdev->tsif[0].ref_count == 1) {
1333 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1334 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1335 pdev->base + TSPP_CONTROL);
1336 wmb();
1337 }
Joel Nider5556a852011-10-16 10:52:13 +02001338 break;
1339 case TSPP_SOURCE_TSIF1:
Liron Kuch275c0b32013-02-10 15:19:32 +02001340 if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
1341 pr_err("tspp: error enabling tsif1 GPIOs\n");
1342 return -EBUSY;
1343 }
Joel Nider5556a852011-10-16 10:52:13 +02001344 /* make sure TSIF1 is running & enabled */
1345 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
1346 pr_err("tspp: error starting tsif1");
Joel Nider435ad8e2011-12-14 16:53:30 +02001347 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001348 }
Liron Kucha7b49ae2013-02-14 16:26:38 +02001349 if (pdev->tsif[1].ref_count == 1) {
1350 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1351 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1352 pdev->base + TSPP_CONTROL);
1353 wmb();
1354 }
Joel Nider5556a852011-10-16 10:52:13 +02001355 break;
1356 case TSPP_SOURCE_MEM:
1357 break;
1358 default:
Hamad Kadmany92705b32012-10-23 14:15:41 +02001359 pr_err("tspp: channel %i invalid source %i",
1360 channel->id, source->source);
Joel Nider435ad8e2011-12-14 16:53:30 +02001361 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001362 }
1363
Joel Nider5556a852011-10-16 10:52:13 +02001364 return 0;
1365}
1366EXPORT_SYMBOL(tspp_open_stream);
1367
Liron Kuch72b78552012-10-30 17:47:50 +02001368/**
1369 * tspp_close_stream - close a TSPP stream.
1370 *
1371 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1372 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1373 *
1374 * Return error status
1375 *
1376 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001377int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001378{
1379 u32 val;
Liron Kucha7b49ae2013-02-14 16:26:38 +02001380 u32 prev_ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001381 struct tspp_device *pdev;
Joel Nider435ad8e2011-12-14 16:53:30 +02001382 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001383
Joel Nider435ad8e2011-12-14 16:53:30 +02001384 if (channel_id >= TSPP_NUM_CHANNELS) {
1385 pr_err("tspp: channel id out of range");
1386 return -ECHRNG;
1387 }
1388 pdev = tspp_find_by_id(dev);
1389 if (!pdev) {
1390 pr_err("tspp_cs: can't find device %i", dev);
1391 return -EBUSY;
1392 }
1393 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001394
1395 switch (channel->src) {
1396 case TSPP_SOURCE_TSIF0:
Liron Kucha7b49ae2013-02-14 16:26:38 +02001397 prev_ref_count = pdev->tsif[0].ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001398 tspp_stop_tsif(&pdev->tsif[0]);
Liron Kuch275c0b32013-02-10 15:19:32 +02001399 if (tspp_config_gpios(pdev, channel->src, 0) != 0)
1400 pr_err("tspp: error disabling tsif0 GPIOs\n");
1401
Liron Kucha7b49ae2013-02-14 16:26:38 +02001402 if (prev_ref_count == 1) {
1403 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1404 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1405 pdev->base + TSPP_CONTROL);
1406 wmb();
1407 }
Joel Nider5556a852011-10-16 10:52:13 +02001408 break;
1409 case TSPP_SOURCE_TSIF1:
Liron Kucha7b49ae2013-02-14 16:26:38 +02001410 prev_ref_count = pdev->tsif[1].ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001411 tspp_stop_tsif(&pdev->tsif[1]);
Liron Kuch275c0b32013-02-10 15:19:32 +02001412 if (tspp_config_gpios(pdev, channel->src, 0) != 0)
1413 pr_err("tspp: error disabling tsif0 GPIOs\n");
1414
Liron Kucha7b49ae2013-02-14 16:26:38 +02001415 if (prev_ref_count == 1) {
1416 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1417 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1418 pdev->base + TSPP_CONTROL);
1419 wmb();
1420 }
Joel Nider5556a852011-10-16 10:52:13 +02001421 break;
1422 case TSPP_SOURCE_MEM:
1423 break;
1424 case TSPP_SOURCE_NONE:
1425 break;
1426 }
1427
Joel Nider435ad8e2011-12-14 16:53:30 +02001428 channel->src = TSPP_SOURCE_NONE;
Joel Nider5556a852011-10-16 10:52:13 +02001429 return 0;
1430}
1431EXPORT_SYMBOL(tspp_close_stream);
1432
Liron Kuch72b78552012-10-30 17:47:50 +02001433/**
1434 * tspp_open_channel - open a TSPP channel.
1435 *
1436 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1437 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1438 *
1439 * Return error status
1440 *
1441 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001442int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001443{
1444 int rc = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001445 struct sps_connect *config;
1446 struct sps_register_event *event;
1447 struct tspp_channel *channel;
1448 struct tspp_device *pdev;
1449
1450 if (channel_id >= TSPP_NUM_CHANNELS) {
1451 pr_err("tspp: channel id out of range");
1452 return -ECHRNG;
1453 }
1454 pdev = tspp_find_by_id(dev);
1455 if (!pdev) {
1456 pr_err("tspp_oc: can't find device %i", dev);
1457 return -ENODEV;
1458 }
1459 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001460
1461 if (channel->used) {
1462 pr_err("tspp channel already in use");
Joel Nider435ad8e2011-12-14 16:53:30 +02001463 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001464 }
1465
Joel Nider435ad8e2011-12-14 16:53:30 +02001466 config = &channel->config;
1467 event = &channel->event;
1468
1469 /* start the clocks if needed */
Liron Kuch59339922013-01-01 18:29:47 +02001470 if (tspp_channels_in_use(pdev) == 0) {
Liron Kuch605cc122013-02-21 14:25:57 +02001471 rc = tspp_clock_start(pdev);
1472 if (rc)
1473 return rc;
1474
Joel Nider435ad8e2011-12-14 16:53:30 +02001475 wake_lock(&pdev->wake_lock);
Liron Kuch59339922013-01-01 18:29:47 +02001476 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001477
Joel Nider5556a852011-10-16 10:52:13 +02001478 /* mark it as used */
1479 channel->used = 1;
1480
1481 /* start the bam */
1482 channel->pipe = sps_alloc_endpoint();
1483 if (channel->pipe == 0) {
1484 pr_err("tspp: error allocating endpoint");
1485 rc = -ENOMEM;
1486 goto err_sps_alloc;
1487 }
1488
1489 /* get default configuration */
1490 sps_get_config(channel->pipe, config);
1491
Joel Nider435ad8e2011-12-14 16:53:30 +02001492 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001493 config->destination = SPS_DEV_HANDLE_MEM;
1494 config->mode = SPS_MODE_SRC;
Joel Nider435ad8e2011-12-14 16:53:30 +02001495 config->options =
1496 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1497 SPS_O_STREAMING | /* streaming mode */
1498 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
Hamad Kadmany81cee052012-11-29 14:15:57 +02001499 SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
1500 SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001501 config->src_pipe_index = channel->id;
1502 config->desc.size =
Hamad Kadmany81cee052012-11-29 14:15:57 +02001503 TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
Joel Nider5556a852011-10-16 10:52:13 +02001504 config->desc.base = dma_alloc_coherent(NULL,
1505 config->desc.size,
1506 &config->desc.phys_base,
1507 GFP_KERNEL);
1508 if (config->desc.base == 0) {
1509 pr_err("tspp: error allocating sps descriptors");
1510 rc = -ENOMEM;
1511 goto err_desc_alloc;
1512 }
1513
1514 memset(config->desc.base, 0, config->desc.size);
1515
1516 rc = sps_connect(channel->pipe, config);
1517 if (rc) {
1518 pr_err("tspp: error connecting bam");
1519 goto err_connect;
1520 }
1521
1522 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider435ad8e2011-12-14 16:53:30 +02001523 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001524 event->callback = tspp_sps_complete_cb;
1525 event->xfer_done = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001526 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001527
1528 rc = sps_register_event(channel->pipe, event);
1529 if (rc) {
1530 pr_err("tspp: error registering event");
1531 goto err_event;
1532 }
1533
Hamad Kadmany81cee052012-11-29 14:15:57 +02001534 init_timer(&channel->expiration_timer);
1535 channel->expiration_timer.function = tspp_expiration_timer;
1536 channel->expiration_timer.data = (unsigned long)pdev;
1537 channel->expiration_timer.expires = 0xffffffffL;
1538
Joel Nider435ad8e2011-12-14 16:53:30 +02001539 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001540 if (rc < 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02001541 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001542 "Runtime PM: Unable to wake up tspp device, rc = %d",
1543 rc);
1544 }
Joel Nider5556a852011-10-16 10:52:13 +02001545 return 0;
1546
1547err_event:
1548 sps_disconnect(channel->pipe);
1549err_connect:
1550 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1551 config->desc.phys_base);
1552err_desc_alloc:
1553 sps_free_endpoint(channel->pipe);
1554err_sps_alloc:
1555 return rc;
1556}
1557EXPORT_SYMBOL(tspp_open_channel);
1558
Liron Kuch72b78552012-10-30 17:47:50 +02001559/**
1560 * tspp_close_channel - close a TSPP channel.
1561 *
1562 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1563 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1564 *
1565 * Return error status
1566 *
1567 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001568int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001569{
1570 int i;
1571 int id;
Liron Kuch4ed3bf62013-03-28 09:44:42 +02001572 int table_idx;
Joel Nider5556a852011-10-16 10:52:13 +02001573 u32 val;
Liron Kuche0acb412013-04-21 13:16:45 +03001574 unsigned long flags;
Joel Nider5556a852011-10-16 10:52:13 +02001575
Joel Nider435ad8e2011-12-14 16:53:30 +02001576 struct sps_connect *config;
1577 struct tspp_device *pdev;
1578 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02001579
1580 if (channel_id >= TSPP_NUM_CHANNELS) {
1581 pr_err("tspp: channel id out of range");
1582 return -ECHRNG;
1583 }
1584 pdev = tspp_find_by_id(dev);
1585 if (!pdev) {
1586 pr_err("tspp_close: can't find device %i", dev);
1587 return -ENODEV;
1588 }
1589 channel = &pdev->channels[channel_id];
1590
1591 /* if the channel is not used, we are done */
1592 if (!channel->used)
1593 return 0;
1594
Liron Kuche0acb412013-04-21 13:16:45 +03001595 /*
1596 * Need to protect access to used and waiting fields, as they are
1597 * used by the tasklet which is invoked from interrupt context
1598 */
1599 spin_lock_irqsave(&pdev->spinlock, flags);
1600 channel->used = 0;
1601 channel->waiting = NULL;
1602 spin_unlock_irqrestore(&pdev->spinlock, flags);
1603
Hamad Kadmany81cee052012-11-29 14:15:57 +02001604 if (channel->expiration_period_ms)
1605 del_timer(&channel->expiration_timer);
1606
Joel Nider435ad8e2011-12-14 16:53:30 +02001607 channel->notifier = NULL;
1608 channel->notify_data = NULL;
Hamad Kadmany81cee052012-11-29 14:15:57 +02001609 channel->expiration_period_ms = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001610
1611 config = &channel->config;
1612 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001613
1614 /* disable pipe (channel) */
1615 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1616 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1617 wmb();
1618
1619 /* unregister all filters for this channel */
Liron Kuch4ed3bf62013-03-28 09:44:42 +02001620 for (table_idx = 0; table_idx < TSPP_FILTER_TABLES; table_idx++) {
1621 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1622 struct tspp_pid_filter *filter =
1623 &pdev->filters[table_idx]->filter[i];
1624 id = FILTER_GET_PIPE_NUMBER0(filter);
1625 if (id == channel->id) {
1626 if (FILTER_HAS_ENCRYPTION(filter))
1627 tspp_free_key_entry(
1628 FILTER_GET_KEY_NUMBER(filter));
1629 filter->config = 0;
1630 filter->filter = 0;
1631 }
Joel Nider5556a852011-10-16 10:52:13 +02001632 }
1633 }
1634 channel->filter_count = 0;
1635
Joel Nider5556a852011-10-16 10:52:13 +02001636 /* disconnect the bam */
1637 if (sps_disconnect(channel->pipe) != 0)
1638 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1639
1640 /* destroy the buffers */
1641 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1642 config->desc.phys_base);
1643
Liron Kuch72b78552012-10-30 17:47:50 +02001644 tspp_destroy_buffers(channel_id, channel);
Hamad Kadmany090709b2013-01-06 12:08:13 +02001645 if (channel->dma_pool) {
1646 dma_pool_destroy(channel->dma_pool);
1647 channel->dma_pool = NULL;
1648 }
Liron Kuch72b78552012-10-30 17:47:50 +02001649
1650 channel->src = TSPP_SOURCE_NONE;
1651 channel->mode = TSPP_MODE_DISABLED;
1652 channel->memfree = NULL;
1653 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001654 channel->buffer_count = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001655 channel->data = NULL;
1656 channel->read = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001657 channel->locked = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001658
Liron Kuch59339922013-01-01 18:29:47 +02001659 if (tspp_channels_in_use(pdev) == 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02001660 wake_unlock(&pdev->wake_lock);
Liron Kuch59339922013-01-01 18:29:47 +02001661 tspp_clock_stop(pdev);
1662 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001663
Liron Kuch605cc122013-02-21 14:25:57 +02001664 pm_runtime_put(&pdev->pdev->dev);
1665
Joel Nider5556a852011-10-16 10:52:13 +02001666 return 0;
1667}
1668EXPORT_SYMBOL(tspp_close_channel);
1669
Liron Kuch72b78552012-10-30 17:47:50 +02001670/**
Hamad Kadmany6d2a9c72013-01-31 14:49:20 +02001671 * tspp_get_ref_clk_counter - return the TSIF clock reference (TCR) counter.
1672 *
1673 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1674 * @source: The TSIF source from which the counter should be read
1675 * @tcr_counter: the value of TCR counter
1676 *
1677 * Return error status
1678 *
1679 * TCR increments at a rate equal to 27 MHz/256 = 105.47 kHz.
1680 * If source is neither TSIF 0 or TSIF1 0 is returned.
1681 */
1682int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter)
1683{
1684 struct tspp_device *pdev;
1685 struct tspp_tsif_device *tsif_device;
1686
1687 if (!tcr_counter)
1688 return -EINVAL;
1689
1690 pdev = tspp_find_by_id(dev);
1691 if (!pdev) {
1692 pr_err("tspp_get_ref_clk_counter: can't find device %i\n", dev);
1693 return -ENODEV;
1694 }
1695
1696 switch (source) {
1697 case TSPP_SOURCE_TSIF0:
1698 tsif_device = &pdev->tsif[0];
1699 break;
1700
1701 case TSPP_SOURCE_TSIF1:
1702 tsif_device = &pdev->tsif[1];
1703 break;
1704
1705 default:
1706 tsif_device = NULL;
1707 break;
1708 }
1709
1710 if (tsif_device && tsif_device->ref_count)
1711 *tcr_counter = ioread32(tsif_device->base + TSIF_CLK_REF_OFF);
1712 else
1713 *tcr_counter = 0;
1714
1715 return 0;
1716}
1717EXPORT_SYMBOL(tspp_get_ref_clk_counter);
1718
1719/**
Liron Kuch72b78552012-10-30 17:47:50 +02001720 * tspp_add_filter - add a TSPP filter to a channel.
1721 *
1722 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1723 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1724 * @filter: TSPP filter parameters
1725 *
1726 * Return error status
1727 *
1728 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001729int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001730 struct tspp_filter *filter)
1731{
Liron Kuch72b78552012-10-30 17:47:50 +02001732 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001733 int other_channel;
1734 int entry;
1735 u32 val, pid, enabled;
Joel Nider435ad8e2011-12-14 16:53:30 +02001736 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001737 struct tspp_pid_filter p;
Joel Nider435ad8e2011-12-14 16:53:30 +02001738 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001739
Joel Nider435ad8e2011-12-14 16:53:30 +02001740 TSPP_DEBUG("tspp: add filter");
1741 if (channel_id >= TSPP_NUM_CHANNELS) {
1742 pr_err("tspp: channel id out of range");
1743 return -ECHRNG;
1744 }
1745 pdev = tspp_find_by_id(dev);
1746 if (!pdev) {
1747 pr_err("tspp_add: can't find device %i", dev);
1748 return -ENODEV;
1749 }
1750
1751 channel = &pdev->channels[channel_id];
1752
Joel Nider5556a852011-10-16 10:52:13 +02001753 if (filter->source > TSPP_SOURCE_MEM) {
1754 pr_err("tspp invalid source");
Joel Nider435ad8e2011-12-14 16:53:30 +02001755 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001756 }
1757
1758 if (filter->priority >= TSPP_NUM_PRIORITIES) {
1759 pr_err("tspp invalid source");
Joel Nider435ad8e2011-12-14 16:53:30 +02001760 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001761 }
1762
Liron Kuch72b78552012-10-30 17:47:50 +02001763 channel->mode = filter->mode;
1764 /*
1765 * if buffers are already allocated, verify they fulfil
1766 * the alignment requirements.
1767 */
1768 if ((channel->buffer_count > 0) &&
1769 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1770 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001771
1772 if (filter->mode == TSPP_MODE_PES) {
1773 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1774 struct tspp_pid_filter *tspp_filter =
Joel Nider435ad8e2011-12-14 16:53:30 +02001775 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001776 pid = FILTER_GET_PIPE_PID((tspp_filter));
1777 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1778 if (enabled && (pid == filter->pid)) {
1779 other_channel =
1780 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1781 pr_err("tspp: pid 0x%x already in use by channel %i",
1782 filter->pid, other_channel);
Joel Nider435ad8e2011-12-14 16:53:30 +02001783 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001784 }
1785 }
1786 }
1787
1788 /* make sure this priority is not already in use */
1789 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider435ad8e2011-12-14 16:53:30 +02001790 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001791 if (enabled) {
1792 pr_err("tspp: filter priority %i source %i is already enabled\n",
1793 filter->priority, channel->src);
Joel Nider435ad8e2011-12-14 16:53:30 +02001794 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001795 }
1796
1797 if (channel->mode == TSPP_MODE_PES) {
1798 /* if we are already processing in PES mode, disable pipe
1799 (channel) and filter to be updated */
1800 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1801 writel_relaxed(val | (1 << channel->id),
1802 pdev->base + TSPP_PS_DISABLE);
1803 wmb();
1804 }
1805
1806 /* update entry */
1807 p.filter = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001808 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001809 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1810 FILTER_SET_PIPE_PID((&p), filter->pid);
1811 FILTER_SET_PID_MASK((&p), filter->mask);
1812 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1813 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1814 if (filter->decrypt) {
1815 entry = tspp_get_key_entry();
1816 if (entry == -1) {
1817 pr_err("tspp: no more keys available!");
1818 } else {
1819 p.config |= FILTER_DECRYPT;
1820 FILTER_SET_KEY_NUMBER((&p), entry);
1821 }
1822 }
Joel Nider5556a852011-10-16 10:52:13 +02001823
Joel Nider435ad8e2011-12-14 16:53:30 +02001824 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001825 filter[filter->priority].config = p.config;
Joel Nider435ad8e2011-12-14 16:53:30 +02001826 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001827 filter[filter->priority].filter = p.filter;
1828
Liron Kuch72b78552012-10-30 17:47:50 +02001829 /*
1830 * allocate buffers if needed (i.e. if user did has not already called
1831 * tspp_allocate_buffers() explicitly).
1832 */
1833 if (channel->buffer_count == 0) {
1834 channel->buffer_size =
Hamad Kadmany090709b2013-01-06 12:08:13 +02001835 tspp_align_buffer_size_by_mode(channel->buffer_size,
Liron Kuch72b78552012-10-30 17:47:50 +02001836 channel->mode);
1837 rc = tspp_allocate_buffers(dev, channel->id,
1838 channel->max_buffers,
1839 channel->buffer_size,
1840 channel->int_freq, NULL, NULL, NULL);
1841 if (rc != 0) {
1842 pr_err("tspp: tspp_allocate_buffers failed\n");
1843 return rc;
1844 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001845 }
1846
Joel Nider5556a852011-10-16 10:52:13 +02001847 /* reenable pipe */
1848 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1849 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1850 wmb();
1851 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1852
Joel Nider5556a852011-10-16 10:52:13 +02001853 channel->filter_count++;
1854
1855 return 0;
1856}
1857EXPORT_SYMBOL(tspp_add_filter);
1858
Liron Kuch72b78552012-10-30 17:47:50 +02001859/**
1860 * tspp_remove_filter - remove a TSPP filter from a channel.
1861 *
1862 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1863 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1864 * @filter: TSPP filter parameters
1865 *
1866 * Return error status
1867 *
1868 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001869int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001870 struct tspp_filter *filter)
1871{
1872 int entry;
1873 u32 val;
Joel Nider435ad8e2011-12-14 16:53:30 +02001874 struct tspp_device *pdev;
1875 int src;
1876 struct tspp_pid_filter *tspp_filter;
1877 struct tspp_channel *channel;
1878
1879 if (channel_id >= TSPP_NUM_CHANNELS) {
1880 pr_err("tspp: channel id out of range");
1881 return -ECHRNG;
1882 }
1883 pdev = tspp_find_by_id(dev);
1884 if (!pdev) {
1885 pr_err("tspp_remove: can't find device %i", dev);
1886 return -ENODEV;
1887 }
1888 channel = &pdev->channels[channel_id];
1889
1890 src = channel->src;
1891 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02001892
1893 /* disable pipe (channel) */
1894 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1895 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1896 wmb();
1897
1898 /* update data keys */
1899 if (tspp_filter->config & FILTER_DECRYPT) {
1900 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
1901 tspp_free_key_entry(entry);
1902 }
1903
1904 /* update pid table */
1905 tspp_filter->config = 0;
1906 tspp_filter->filter = 0;
1907
1908 channel->filter_count--;
1909
1910 /* reenable pipe */
1911 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1912 writel_relaxed(val & ~(1 << channel->id),
1913 pdev->base + TSPP_PS_DISABLE);
1914 wmb();
1915 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1916
1917 return 0;
1918}
1919EXPORT_SYMBOL(tspp_remove_filter);
1920
Liron Kuch72b78552012-10-30 17:47:50 +02001921/**
1922 * tspp_set_key - set TSPP key in key table.
1923 *
1924 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1925 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1926 * @key: TSPP key parameters
1927 *
1928 * Return error status
1929 *
1930 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001931int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02001932{
1933 int i;
1934 int id;
1935 int key_index;
1936 int data;
Joel Nider435ad8e2011-12-14 16:53:30 +02001937 struct tspp_channel *channel;
1938 struct tspp_device *pdev;
1939
1940 if (channel_id >= TSPP_NUM_CHANNELS) {
1941 pr_err("tspp: channel id out of range");
1942 return -ECHRNG;
1943 }
1944 pdev = tspp_find_by_id(dev);
1945 if (!pdev) {
1946 pr_err("tspp_set: can't find device %i", dev);
1947 return -ENODEV;
1948 }
1949 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001950
1951 /* read the key index used by this channel */
1952 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1953 struct tspp_pid_filter *tspp_filter =
Joel Nider435ad8e2011-12-14 16:53:30 +02001954 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02001955 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1956 if (id == channel->id) {
1957 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
1958 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
1959 break;
1960 }
1961 }
1962 }
1963 if (i == TSPP_NUM_PRIORITIES) {
1964 pr_err("tspp: no encryption on this channel");
Joel Nider435ad8e2011-12-14 16:53:30 +02001965 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02001966 }
1967
1968 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider435ad8e2011-12-14 16:53:30 +02001969 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
1970 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001971 } else {
Joel Nider435ad8e2011-12-14 16:53:30 +02001972 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
1973 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001974 }
1975 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
1976
1977 return 0;
1978}
1979EXPORT_SYMBOL(tspp_set_key);
1980
Liron Kuch72b78552012-10-30 17:47:50 +02001981/**
1982 * tspp_register_notification - register TSPP channel notification function.
1983 *
1984 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1985 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1986 * @pNotify: notification function
1987 * @userdata: user data to pass to notification function
1988 * @timer_ms: notification for partially filled buffers
1989 *
1990 * Return error status
1991 *
1992 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001993int tspp_register_notification(u32 dev, u32 channel_id,
1994 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02001995{
Joel Nider435ad8e2011-12-14 16:53:30 +02001996 struct tspp_channel *channel;
1997 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001998
Joel Nider435ad8e2011-12-14 16:53:30 +02001999 if (channel_id >= TSPP_NUM_CHANNELS) {
2000 pr_err("tspp: channel id out of range");
2001 return -ECHRNG;
2002 }
2003 pdev = tspp_find_by_id(dev);
2004 if (!pdev) {
2005 pr_err("tspp_reg: can't find device %i", dev);
2006 return -ENODEV;
2007 }
2008 channel = &pdev->channels[channel_id];
2009 channel->notifier = pNotify;
2010 channel->notify_data = userdata;
Hamad Kadmany81cee052012-11-29 14:15:57 +02002011 channel->expiration_period_ms = timer_ms;
2012
Joel Nider5556a852011-10-16 10:52:13 +02002013 return 0;
2014}
Joel Nider435ad8e2011-12-14 16:53:30 +02002015EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02002016
Liron Kuch72b78552012-10-30 17:47:50 +02002017/**
2018 * tspp_unregister_notification - unregister TSPP channel notification function.
2019 *
2020 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2021 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2022 *
2023 * Return error status
2024 *
2025 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002026int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002027{
Joel Nider435ad8e2011-12-14 16:53:30 +02002028 struct tspp_channel *channel;
2029 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002030
Joel Nider435ad8e2011-12-14 16:53:30 +02002031 if (channel_id >= TSPP_NUM_CHANNELS) {
2032 pr_err("tspp: channel id out of range");
2033 return -ECHRNG;
2034 }
2035 pdev = tspp_find_by_id(dev);
2036 if (!pdev) {
2037 pr_err("tspp_unreg: can't find device %i", dev);
2038 return -ENODEV;
2039 }
2040 channel = &pdev->channels[channel_id];
2041 channel->notifier = NULL;
2042 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02002043 return 0;
2044}
Joel Nider435ad8e2011-12-14 16:53:30 +02002045EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02002046
Liron Kuch72b78552012-10-30 17:47:50 +02002047/**
2048 * tspp_get_buffer - get TSPP data buffer.
2049 *
2050 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2051 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2052 *
2053 * Return error status
2054 *
2055 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002056const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002057{
Joel Nider435ad8e2011-12-14 16:53:30 +02002058 struct tspp_mem_buffer *buffer;
2059 struct tspp_channel *channel;
2060 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002061
Joel Nider435ad8e2011-12-14 16:53:30 +02002062 if (channel_id >= TSPP_NUM_CHANNELS) {
2063 pr_err("tspp: channel id out of range");
2064 return NULL;
2065 }
2066 pdev = tspp_find_by_id(dev);
2067 if (!pdev) {
2068 pr_err("tspp_get: can't find device %i", dev);
2069 return NULL;
2070 }
2071 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02002072
Joel Nider435ad8e2011-12-14 16:53:30 +02002073 if (!channel->read) {
2074 pr_warn("tspp: no buffer to get on channel %i!",
2075 channel->id);
2076 return NULL;
2077 }
2078
2079 buffer = channel->read;
2080 /* see if we have any buffers ready to read */
2081 if (buffer->state != TSPP_BUF_STATE_DATA)
2082 return 0;
2083
2084 if (buffer->state == TSPP_BUF_STATE_DATA) {
2085 /* mark the buffer as busy */
2086 buffer->state = TSPP_BUF_STATE_LOCKED;
2087
2088 /* increment the pointer along the list */
2089 channel->read = channel->read->next;
2090 }
2091
2092 return &buffer->desc;
2093}
2094EXPORT_SYMBOL(tspp_get_buffer);
2095
Liron Kuch72b78552012-10-30 17:47:50 +02002096/**
2097 * tspp_release_buffer - release TSPP data buffer back to TSPP.
2098 *
2099 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2100 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2101 * @descriptor_id: buffer descriptor ID
2102 *
2103 * Return error status
2104 *
2105 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002106int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
2107{
2108 int i, found = 0;
2109 struct tspp_mem_buffer *buffer;
2110 struct tspp_channel *channel;
2111 struct tspp_device *pdev;
2112
2113 if (channel_id >= TSPP_NUM_CHANNELS) {
2114 pr_err("tspp: channel id out of range");
2115 return -ECHRNG;
2116 }
2117 pdev = tspp_find_by_id(dev);
2118 if (!pdev) {
2119 pr_err("tspp: can't find device %i", dev);
2120 return -ENODEV;
2121 }
2122 channel = &pdev->channels[channel_id];
2123
2124 if (descriptor_id > channel->buffer_count)
2125 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
2126
2127 /* find the correct descriptor */
2128 buffer = channel->locked;
2129 for (i = 0; i < channel->buffer_count; i++) {
2130 if (buffer->desc.id == descriptor_id) {
2131 found = 1;
2132 break;
2133 }
2134 buffer = buffer->next;
2135 }
2136 channel->locked = channel->locked->next;
2137
2138 if (!found) {
2139 pr_err("tspp: cant find desc %i", descriptor_id);
2140 return -EINVAL;
2141 }
2142
2143 /* make sure the buffer is in the expected state */
2144 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
2145 pr_err("tspp: buffer %i not locked", descriptor_id);
2146 return -EINVAL;
2147 }
2148 /* unlock the buffer and requeue it */
2149 buffer->state = TSPP_BUF_STATE_WAITING;
2150
2151 if (tspp_queue_buffer(channel, buffer))
2152 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02002153 return 0;
2154}
Joel Nider435ad8e2011-12-14 16:53:30 +02002155EXPORT_SYMBOL(tspp_release_buffer);
2156
Liron Kuch72b78552012-10-30 17:47:50 +02002157/**
2158 * tspp_allocate_buffers - allocate TSPP data buffers.
2159 *
2160 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2161 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2162 * @count: number of buffers to allocate
2163 * @size: size of each buffer to allocate
2164 * @int_freq: interrupt frequency
2165 * @alloc: user defined memory allocator function. Pass NULL for default.
2166 * @memfree: user defined memory free function. Pass NULL for default.
2167 * @user: user data to pass to the memory allocator/free function
2168 *
2169 * Return error status
2170 *
2171 * The user can optionally call this function explicitly to allocate the TSPP
2172 * data buffers. Alternatively, if the user did not call this function, it
2173 * is called implicitly by tspp_add_filter().
2174 */
2175int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
2176 u32 int_freq, tspp_allocator *alloc,
2177 tspp_memfree *memfree, void *user)
Joel Nider435ad8e2011-12-14 16:53:30 +02002178{
2179 struct tspp_channel *channel;
2180 struct tspp_device *pdev;
2181 struct tspp_mem_buffer *last = NULL;
2182
2183 TSPP_DEBUG("tspp_allocate_buffers");
2184
2185 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch72b78552012-10-30 17:47:50 +02002186 pr_err("%s: channel id out of range", __func__);
Joel Nider435ad8e2011-12-14 16:53:30 +02002187 return -ECHRNG;
2188 }
Liron Kuch72b78552012-10-30 17:47:50 +02002189
Joel Nider435ad8e2011-12-14 16:53:30 +02002190 pdev = tspp_find_by_id(dev);
2191 if (!pdev) {
Liron Kuch72b78552012-10-30 17:47:50 +02002192 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider435ad8e2011-12-14 16:53:30 +02002193 return -ENODEV;
2194 }
Liron Kuch72b78552012-10-30 17:47:50 +02002195
2196 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
2197 pr_err("%s: tspp requires a minimum of %i buffers\n",
2198 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
2199 return -EINVAL;
2200 }
2201
Joel Nider435ad8e2011-12-14 16:53:30 +02002202 channel = &pdev->channels[channel_id];
Hamad Kadmany090709b2013-01-06 12:08:13 +02002203
Liron Kuch72b78552012-10-30 17:47:50 +02002204 /* allow buffer allocation only if there was no previous buffer
2205 * allocation for this channel.
2206 */
2207 if (channel->buffer_count > 0) {
2208 pr_err("%s: buffers already allocated for channel %u",
2209 __func__, channel_id);
2210 return -EINVAL;
2211 }
Joel Nider435ad8e2011-12-14 16:53:30 +02002212
2213 channel->max_buffers = count;
2214
2215 /* set up interrupt frequency */
Liron Kuch72b78552012-10-30 17:47:50 +02002216 if (int_freq > channel->max_buffers) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002217 int_freq = channel->max_buffers;
Liron Kuch72b78552012-10-30 17:47:50 +02002218 pr_warn("%s: setting interrupt frequency to %u\n",
2219 __func__, int_freq);
Joel Nider435ad8e2011-12-14 16:53:30 +02002220 }
Liron Kuch72b78552012-10-30 17:47:50 +02002221 channel->int_freq = int_freq;
2222 /*
2223 * it is the responsibility of the caller to tspp_allocate_buffers(),
2224 * whether it's the user or the driver, to make sure the size parameter
2225 * is compatible to the channel mode.
2226 */
2227 channel->buffer_size = size;
Joel Nider435ad8e2011-12-14 16:53:30 +02002228
Liron Kuch72b78552012-10-30 17:47:50 +02002229 /* save user defined memory free function for later use */
2230 channel->memfree = memfree;
2231 channel->user_info = user;
2232
Hamad Kadmany090709b2013-01-06 12:08:13 +02002233 /*
2234 * For small buffers, create a DMA pool so that memory
2235 * is not wasted through dma_alloc_coherent.
2236 */
2237 if (TSPP_USE_DMA_POOL(channel->buffer_size)) {
2238 channel->dma_pool = dma_pool_create("tspp",
2239 NULL, channel->buffer_size, 0, 0);
2240 if (!channel->dma_pool) {
2241 pr_err("%s: Can't allocate memory pool\n", __func__);
2242 return -ENOMEM;
2243 }
2244 } else {
2245 channel->dma_pool = NULL;
2246 }
2247
2248
Liron Kuch72b78552012-10-30 17:47:50 +02002249 for (channel->buffer_count = 0;
2250 channel->buffer_count < channel->max_buffers;
Joel Nider435ad8e2011-12-14 16:53:30 +02002251 channel->buffer_count++) {
2252
2253 /* allocate the descriptor */
2254 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2255 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2256 if (!desc) {
Liron Kuch72b78552012-10-30 17:47:50 +02002257 pr_warn("%s: Can't allocate desc %i",
2258 __func__, channel->buffer_count);
Joel Nider435ad8e2011-12-14 16:53:30 +02002259 break;
2260 }
2261
2262 desc->desc.id = channel->buffer_count;
2263 /* allocate the buffer */
2264 if (tspp_alloc_buffer(channel_id, &desc->desc,
Hamad Kadmany090709b2013-01-06 12:08:13 +02002265 channel->buffer_size, channel->dma_pool,
2266 alloc, user) != 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002267 kfree(desc);
Liron Kuch72b78552012-10-30 17:47:50 +02002268 pr_warn("%s: Can't allocate buffer %i",
2269 __func__, channel->buffer_count);
Joel Nider435ad8e2011-12-14 16:53:30 +02002270 break;
2271 }
2272
2273 /* add the descriptor to the list */
2274 desc->filled = 0;
2275 desc->read_index = 0;
2276 if (!channel->data) {
2277 channel->data = desc;
2278 desc->next = channel->data;
2279 } else {
2280 last->next = desc;
2281 }
2282 last = desc;
2283 desc->next = channel->data;
2284
2285 /* prepare the sps descriptor */
2286 desc->sps.phys_base = desc->desc.phys_base;
2287 desc->sps.base = desc->desc.virt_base;
2288 desc->sps.size = desc->desc.size;
2289
2290 /* start the transfer */
2291 if (tspp_queue_buffer(channel, desc))
Liron Kuch72b78552012-10-30 17:47:50 +02002292 pr_err("%s: can't queue buffer %i",
2293 __func__, desc->desc.id);
2294 }
2295
2296 if (channel->buffer_count < channel->max_buffers) {
2297 /*
2298 * we failed to allocate the requested number of buffers.
2299 * we don't allow a partial success, so need to clean up here.
2300 */
2301 tspp_destroy_buffers(channel_id, channel);
2302 channel->buffer_count = 0;
Hamad Kadmany090709b2013-01-06 12:08:13 +02002303
2304 if (channel->dma_pool) {
2305 dma_pool_destroy(channel->dma_pool);
2306 channel->dma_pool = NULL;
2307 }
Liron Kuch72b78552012-10-30 17:47:50 +02002308 return -ENOMEM;
Joel Nider435ad8e2011-12-14 16:53:30 +02002309 }
2310
2311 channel->waiting = channel->data;
2312 channel->read = channel->data;
2313 channel->locked = channel->data;
Liron Kuch72b78552012-10-30 17:47:50 +02002314
Hamad Kadmany81cee052012-11-29 14:15:57 +02002315 /* Now that buffers are scheduled to HW, kick data expiration timer */
2316 if (channel->expiration_period_ms)
2317 mod_timer(&channel->expiration_timer,
2318 jiffies +
2319 MSEC_TO_JIFFIES(
2320 channel->expiration_period_ms));
2321
Joel Nider435ad8e2011-12-14 16:53:30 +02002322 return 0;
2323}
2324EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002325
2326/*** File Operations ***/
2327static ssize_t tspp_open(struct inode *inode, struct file *filp)
2328{
Joel Nider435ad8e2011-12-14 16:53:30 +02002329 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002330 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002331
2332 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002333 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2334 filp->private_data = channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002335 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002336
2337 /* if this channel is already in use, quit */
2338 if (channel->used) {
2339 pr_err("tspp channel %i already in use",
2340 MINOR(channel->cdev.dev));
2341 return -EACCES;
2342 }
2343
Joel Nider435ad8e2011-12-14 16:53:30 +02002344 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002345 pr_err("tspp: error opening channel");
2346 return -EACCES;
2347 }
2348
2349 return 0;
2350}
2351
2352static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2353{
2354 unsigned long flags;
2355 unsigned int mask = 0;
2356 struct tspp_channel *channel;
2357 channel = filp->private_data;
2358
2359 /* register the wait queue for this channel */
2360 poll_wait(filp, &channel->in_queue, p);
2361
2362 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider435ad8e2011-12-14 16:53:30 +02002363 if (channel->read &&
2364 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002365 mask = POLLIN | POLLRDNORM;
2366
2367 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2368
2369 return mask;
2370}
2371
2372static ssize_t tspp_release(struct inode *inode, struct file *filp)
2373{
Joel Nider435ad8e2011-12-14 16:53:30 +02002374 struct tspp_channel *channel = filp->private_data;
2375 u32 dev = channel->pdev->pdev->id;
2376 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002377
Joel Nider435ad8e2011-12-14 16:53:30 +02002378 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002379
2380 return 0;
2381}
2382
2383static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2384 loff_t *f_pos)
2385{
2386 size_t size = 0;
2387 size_t transferred = 0;
2388 struct tspp_channel *channel;
2389 struct tspp_mem_buffer *buffer;
2390 channel = filp->private_data;
2391
2392 TSPP_DEBUG("tspp_read");
Joel Nider435ad8e2011-12-14 16:53:30 +02002393
2394 while (!channel->read) {
2395 if (filp->f_flags & O_NONBLOCK) {
2396 pr_warn("tspp: no buffer on channel %i!",
2397 channel->id);
2398 return -EAGAIN;
2399 }
2400 /* go to sleep if there is nothing to read */
2401 if (wait_event_interruptible(channel->in_queue,
2402 (channel->read != NULL))) {
2403 pr_err("tspp: rude awakening\n");
2404 return -ERESTARTSYS;
2405 }
2406 }
2407
2408 buffer = channel->read;
2409
Joel Nider5556a852011-10-16 10:52:13 +02002410 /* see if we have any buffers ready to read */
2411 while (buffer->state != TSPP_BUF_STATE_DATA) {
2412 if (filp->f_flags & O_NONBLOCK) {
2413 pr_warn("tspp: nothing to read on channel %i!",
2414 channel->id);
2415 return -EAGAIN;
2416 }
2417 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002418 if (wait_event_interruptible(channel->in_queue,
2419 (buffer->state == TSPP_BUF_STATE_DATA))) {
2420 pr_err("tspp: rude awakening\n");
2421 return -ERESTARTSYS;
2422 }
2423 }
2424
2425 while (buffer->state == TSPP_BUF_STATE_DATA) {
2426 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002427 if (size == 0)
2428 break;
2429
Joel Nider435ad8e2011-12-14 16:53:30 +02002430 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002431 buffer->read_index, size)) {
2432 pr_err("tspp: error copying to user buffer");
Joel Nider435ad8e2011-12-14 16:53:30 +02002433 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002434 }
2435 buf += size;
2436 count -= size;
2437 transferred += size;
2438 buffer->read_index += size;
2439
Liron Kuch72b78552012-10-30 17:47:50 +02002440 /*
2441 * after reading the end of the buffer, requeue it,
2442 * and set up for reading the next one
2443 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002444 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002445 buffer->state = TSPP_BUF_STATE_WAITING;
Hamad Kadmany090709b2013-01-06 12:08:13 +02002446
Joel Nider435ad8e2011-12-14 16:53:30 +02002447 if (tspp_queue_buffer(channel, buffer))
2448 pr_err("tspp: can't submit transfer");
Hamad Kadmany090709b2013-01-06 12:08:13 +02002449
Joel Nider435ad8e2011-12-14 16:53:30 +02002450 channel->locked = channel->read;
2451 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002452 }
2453 }
2454
2455 return transferred;
2456}
2457
2458static long tspp_ioctl(struct file *filp,
2459 unsigned int param0, unsigned long param1)
2460{
Joel Nider435ad8e2011-12-14 16:53:30 +02002461 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002462 int rc = -1;
2463 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002464 struct tspp_select_source ss;
2465 struct tspp_filter f;
2466 struct tspp_key k;
2467 struct tspp_iv iv;
2468 struct tspp_system_keys sk;
2469 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002470 channel = filp->private_data;
Joel Nider435ad8e2011-12-14 16:53:30 +02002471 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002472
Liron Kucha7b49ae2013-02-14 16:26:38 +02002473 if ((param0 != TSPP_IOCTL_CLOSE_STREAM) && !param1)
Joel Nider5556a852011-10-16 10:52:13 +02002474 return -EINVAL;
2475
2476 switch (param0) {
2477 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider435ad8e2011-12-14 16:53:30 +02002478 if (!access_ok(VERIFY_READ, param1,
2479 sizeof(struct tspp_select_source))) {
2480 return -EBUSY;
2481 }
2482 if (__copy_from_user(&ss, (void *)param1,
2483 sizeof(struct tspp_select_source)) == 0)
2484 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002485 break;
2486 case TSPP_IOCTL_ADD_FILTER:
Joel Nider435ad8e2011-12-14 16:53:30 +02002487 if (!access_ok(VERIFY_READ, param1,
2488 sizeof(struct tspp_filter))) {
2489 return -ENOSR;
2490 }
2491 if (__copy_from_user(&f, (void *)param1,
2492 sizeof(struct tspp_filter)) == 0)
2493 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002494 break;
2495 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider435ad8e2011-12-14 16:53:30 +02002496 if (!access_ok(VERIFY_READ, param1,
2497 sizeof(struct tspp_filter))) {
2498 return -EBUSY;
2499 }
2500 if (__copy_from_user(&f, (void *)param1,
2501 sizeof(struct tspp_filter)) == 0)
2502 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002503 break;
2504 case TSPP_IOCTL_SET_KEY:
Joel Nider435ad8e2011-12-14 16:53:30 +02002505 if (!access_ok(VERIFY_READ, param1,
2506 sizeof(struct tspp_key))) {
2507 return -EBUSY;
2508 }
2509 if (__copy_from_user(&k, (void *)param1,
2510 sizeof(struct tspp_key)) == 0)
2511 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002512 break;
2513 case TSPP_IOCTL_SET_IV:
Joel Nider435ad8e2011-12-14 16:53:30 +02002514 if (!access_ok(VERIFY_READ, param1,
2515 sizeof(struct tspp_iv))) {
2516 return -EBUSY;
2517 }
2518 if (__copy_from_user(&iv, (void *)param1,
2519 sizeof(struct tspp_iv)) == 0)
2520 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002521 break;
2522 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider435ad8e2011-12-14 16:53:30 +02002523 if (!access_ok(VERIFY_READ, param1,
2524 sizeof(struct tspp_system_keys))) {
2525 return -EINVAL;
2526 }
2527 if (__copy_from_user(&sk, (void *)param1,
2528 sizeof(struct tspp_system_keys)) == 0)
2529 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002530 break;
2531 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider435ad8e2011-12-14 16:53:30 +02002532 if (!access_ok(VERIFY_READ, param1,
2533 sizeof(struct tspp_buffer))) {
2534 rc = -EINVAL;
2535 }
2536 if (__copy_from_user(&b, (void *)param1,
2537 sizeof(struct tspp_buffer)) == 0)
2538 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002539 break;
Liron Kucha7b49ae2013-02-14 16:26:38 +02002540 case TSPP_IOCTL_CLOSE_STREAM:
2541 rc = tspp_close_stream(dev, channel->id);
2542 break;
Joel Nider5556a852011-10-16 10:52:13 +02002543 default:
2544 pr_err("tspp: Unknown ioctl %i", param0);
2545 }
2546
Liron Kuch72b78552012-10-30 17:47:50 +02002547 /*
2548 * normalize the return code in case one of the subfunctions does
2549 * something weird
2550 */
Joel Nider5556a852011-10-16 10:52:13 +02002551 if (rc != 0)
Joel Nider435ad8e2011-12-14 16:53:30 +02002552 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002553
2554 return rc;
2555}
2556
2557/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002558static int debugfs_iomem_x32_set(void *data, u64 val)
2559{
2560 writel_relaxed(val, data);
2561 wmb();
2562 return 0;
2563}
2564
2565static int debugfs_iomem_x32_get(void *data, u64 *val)
2566{
2567 *val = readl_relaxed(data);
2568 return 0;
2569}
2570
2571DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2572 debugfs_iomem_x32_set, "0x%08llx");
2573
2574static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2575 int instance)
2576{
2577 char name[10];
2578 snprintf(name, 10, "tsif%i", instance);
2579 tsif_device->dent_tsif = debugfs_create_dir(
2580 name, NULL);
2581 if (tsif_device->dent_tsif) {
2582 int i;
2583 void __iomem *base = tsif_device->base;
2584 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2585 tsif_device->debugfs_tsif_regs[i] =
2586 debugfs_create_file(
2587 debugfs_tsif_regs[i].name,
2588 debugfs_tsif_regs[i].mode,
2589 tsif_device->dent_tsif,
2590 base + debugfs_tsif_regs[i].offset,
2591 &fops_iomem_x32);
2592 }
Hamad Kadmany44307d32012-11-25 09:49:51 +02002593
2594 debugfs_create_u32(
2595 "stat_rx_chunks",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002596 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002597 tsif_device->dent_tsif,
2598 &tsif_device->stat_rx);
2599
2600 debugfs_create_u32(
2601 "stat_overflow",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002602 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002603 tsif_device->dent_tsif,
2604 &tsif_device->stat_overflow);
2605
2606 debugfs_create_u32(
2607 "stat_lost_sync",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002608 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002609 tsif_device->dent_tsif,
2610 &tsif_device->stat_lost_sync);
2611
2612 debugfs_create_u32(
2613 "stat_timeout",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002614 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002615 tsif_device->dent_tsif,
2616 &tsif_device->stat_timeout);
Joel Nider5556a852011-10-16 10:52:13 +02002617 }
2618}
2619
2620static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2621{
2622 if (tsif_device->dent_tsif) {
2623 int i;
2624 debugfs_remove_recursive(tsif_device->dent_tsif);
2625 tsif_device->dent_tsif = NULL;
2626 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2627 tsif_device->debugfs_tsif_regs[i] = NULL;
2628 }
2629}
2630
2631static void tspp_debugfs_init(struct tspp_device *device, int instance)
2632{
2633 char name[10];
2634 snprintf(name, 10, "tspp%i", instance);
2635 device->dent = debugfs_create_dir(
2636 name, NULL);
2637 if (device->dent) {
2638 int i;
2639 void __iomem *base = device->base;
2640 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2641 device->debugfs_regs[i] =
2642 debugfs_create_file(
2643 debugfs_tspp_regs[i].name,
2644 debugfs_tspp_regs[i].mode,
2645 device->dent,
2646 base + debugfs_tspp_regs[i].offset,
2647 &fops_iomem_x32);
2648 }
2649 }
2650}
2651
2652static void tspp_debugfs_exit(struct tspp_device *device)
2653{
2654 if (device->dent) {
2655 int i;
2656 debugfs_remove_recursive(device->dent);
2657 device->dent = NULL;
2658 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2659 device->debugfs_regs[i] = NULL;
2660 }
2661}
Joel Nider5556a852011-10-16 10:52:13 +02002662
Liron Kuch59339922013-01-01 18:29:47 +02002663/* copy device-tree data to platfrom data struct */
2664static __devinit struct msm_tspp_platform_data *
2665msm_tspp_dt_to_pdata(struct platform_device *pdev)
2666{
2667 struct device_node *node = pdev->dev.of_node;
2668 struct msm_tspp_platform_data *data;
2669 struct msm_gpio *gpios;
2670 int i, rc;
2671 int gpio;
2672 u32 gpio_func;
2673
2674 /* Note: memory allocated by devm_kzalloc is freed automatically */
2675 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
2676 if (!data) {
2677 pr_err("tspp: Unable to allocate platform data\n");
2678 return NULL;
2679 }
2680 rc = of_property_read_string(node, "qcom,tsif-pclk", &data->tsif_pclk);
2681 if (rc) {
2682 pr_err("tspp: Could not find tsif-pclk property, err = %d\n",
2683 rc);
2684 return NULL;
2685 }
2686 rc = of_property_read_string(node, "qcom,tsif-ref-clk",
2687 &data->tsif_ref_clk);
2688 if (rc) {
2689 pr_err("tspp: Could not find tsif-ref-clk property, err = %d\n",
2690 rc);
2691 return NULL;
2692 }
2693
2694 data->num_gpios = of_gpio_count(node);
2695 if (data->num_gpios == 0) {
2696 pr_err("tspp: Could not find GPIO definitions\n");
2697 return NULL;
2698 }
2699 gpios = devm_kzalloc(&pdev->dev,
2700 (data->num_gpios * sizeof(struct msm_gpio)),
2701 GFP_KERNEL);
2702 if (!gpios) {
2703 pr_err("tspp: Unable to allocate memory for GPIOs table\n");
2704 return NULL;
2705 }
2706 /* Assuming GPIO FUNC property is the same for all GPIOs */
2707 if (of_property_read_u32(node, "qcom,gpios-func", &gpio_func)) {
2708 pr_err("tspp: Could not find gpios-func property\n");
2709 return NULL;
2710 }
2711 for (i = 0; i < data->num_gpios; i++) {
2712 gpio = of_get_gpio(node, i);
2713 gpios[i].gpio_cfg = GPIO_CFG(gpio, gpio_func,
2714 GPIO_CFG_INPUT,
2715 GPIO_CFG_PULL_DOWN,
2716 GPIO_CFG_2MA);
2717 rc = of_property_read_string_index(node, "qcom,gpio-names",
2718 i, &gpios[i].label);
2719 if (rc)
2720 pr_warn("tspp: Could not find gpio-names property\n");
2721 }
2722
2723 data->gpios = gpios;
2724
2725 return data;
2726}
2727
2728static int msm_tspp_map_irqs(struct platform_device *pdev,
2729 struct tspp_device *device)
2730{
2731 int rc;
2732 int i;
2733
2734 /* get IRQ numbers from platform information */
2735
2736 /* map TSPP IRQ */
2737 rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ");
2738 if (rc > 0) {
2739 device->tspp_irq = rc;
2740 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
2741 dev_name(&pdev->dev), device);
2742 if (rc) {
2743 dev_err(&pdev->dev,
2744 "failed to request TSPP IRQ %d : %d",
2745 device->tspp_irq, rc);
2746 device->tspp_irq = 0;
2747 return -EINVAL;
2748 }
2749 } else {
2750 dev_err(&pdev->dev, "failed to get TSPP IRQ");
2751 return -EINVAL;
2752 }
2753
2754 /* map TSIF IRQs */
2755 rc = platform_get_irq_byname(pdev, "TSIF0_IRQ");
2756 if (rc > 0) {
2757 device->tsif[0].tsif_irq = rc;
2758 } else {
2759 dev_err(&pdev->dev, "failed to get TSIF0 IRQ");
2760 return -EINVAL;
2761 }
2762
2763 rc = platform_get_irq_byname(pdev, "TSIF1_IRQ");
2764 if (rc > 0) {
2765 device->tsif[1].tsif_irq = rc;
2766 } else {
2767 dev_err(&pdev->dev, "failed to get TSIF1 IRQ");
2768 return -EINVAL;
2769 }
2770
2771 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
2772 rc = request_irq(device->tsif[i].tsif_irq,
2773 tsif_isr, IRQF_SHARED,
2774 dev_name(&pdev->dev), &device->tsif[i]);
2775 if (rc) {
2776 dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
2777 i, rc);
2778 device->tsif[i].tsif_irq = 0;
2779 }
2780 }
2781
2782 /* map BAM IRQ */
2783 rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ");
2784 if (rc > 0) {
2785 device->bam_irq = rc;
2786 } else {
2787 dev_err(&pdev->dev, "failed to get TSPP BAM IRQ");
2788 return -EINVAL;
2789 }
2790
2791 return 0;
2792}
2793
Joel Nider5556a852011-10-16 10:52:13 +02002794static int __devinit msm_tspp_probe(struct platform_device *pdev)
2795{
2796 int rc = -ENODEV;
2797 u32 version;
Liron Kuch72b78552012-10-30 17:47:50 +02002798 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002799 struct msm_tspp_platform_data *data;
2800 struct tspp_device *device;
2801 struct resource *mem_tsif0;
2802 struct resource *mem_tsif1;
2803 struct resource *mem_tspp;
2804 struct resource *mem_bam;
Liron Kuch72b78552012-10-30 17:47:50 +02002805 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002806
Liron Kuch59339922013-01-01 18:29:47 +02002807 if (pdev->dev.of_node) {
2808 /* get information from device tree */
2809 data = msm_tspp_dt_to_pdata(pdev);
2810 /* get device ID */
2811 rc = of_property_read_u32(pdev->dev.of_node,
2812 "cell-index", &pdev->id);
2813 if (rc)
2814 pdev->id = -1;
2815
2816 pdev->dev.platform_data = data;
2817 } else {
2818 /* must have platform data */
2819 data = pdev->dev.platform_data;
2820 }
Joel Nider5556a852011-10-16 10:52:13 +02002821 if (!data) {
2822 pr_err("tspp: Platform data not available");
2823 rc = -EINVAL;
2824 goto out;
2825 }
2826
2827 /* check for valid device id */
Joel Nider435ad8e2011-12-14 16:53:30 +02002828 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002829 pr_err("tspp: Invalid device ID %d", pdev->id);
2830 rc = -EINVAL;
2831 goto out;
2832 }
2833
2834 /* OK, we will use this device */
2835 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2836 if (!device) {
2837 pr_err("tspp: Failed to allocate memory for device");
2838 rc = -ENOMEM;
2839 goto out;
2840 }
2841
2842 /* set up references */
2843 device->pdev = pdev;
2844 platform_set_drvdata(pdev, device);
2845
2846 /* map clocks */
2847 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002848 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02002849 if (IS_ERR(device->tsif_pclk)) {
Joel Nider5556a852011-10-16 10:52:13 +02002850 rc = PTR_ERR(device->tsif_pclk);
2851 device->tsif_pclk = NULL;
2852 goto err_pclock;
2853 }
2854 }
2855 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002856 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02002857 if (IS_ERR(device->tsif_ref_clk)) {
Joel Nider5556a852011-10-16 10:52:13 +02002858 rc = PTR_ERR(device->tsif_ref_clk);
2859 device->tsif_ref_clk = NULL;
2860 goto err_refclock;
2861 }
2862 }
2863
2864 /* map I/O memory */
Liron Kuch59339922013-01-01 18:29:47 +02002865 mem_tsif0 = platform_get_resource_byname(pdev,
2866 IORESOURCE_MEM, "MSM_TSIF0_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002867 if (!mem_tsif0) {
2868 pr_err("tspp: Missing tsif0 MEM resource");
2869 rc = -ENXIO;
2870 goto err_res_tsif0;
2871 }
2872 device->tsif[0].base = ioremap(mem_tsif0->start,
2873 resource_size(mem_tsif0));
2874 if (!device->tsif[0].base) {
2875 pr_err("tspp: ioremap failed");
2876 goto err_map_tsif0;
2877 }
2878
Liron Kuch59339922013-01-01 18:29:47 +02002879 mem_tsif1 = platform_get_resource_byname(pdev,
2880 IORESOURCE_MEM, "MSM_TSIF1_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002881 if (!mem_tsif1) {
2882 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
2883 rc = -ENXIO;
2884 goto err_res_tsif1;
2885 }
2886 device->tsif[1].base = ioremap(mem_tsif1->start,
2887 resource_size(mem_tsif1));
2888 if (!device->tsif[1].base) {
2889 dev_err(&pdev->dev, "ioremap failed");
2890 goto err_map_tsif1;
2891 }
2892
Liron Kuch59339922013-01-01 18:29:47 +02002893 mem_tspp = platform_get_resource_byname(pdev,
2894 IORESOURCE_MEM, "MSM_TSPP_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002895 if (!mem_tspp) {
2896 dev_err(&pdev->dev, "Missing MEM resource");
2897 rc = -ENXIO;
2898 goto err_res_dev;
2899 }
2900 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
2901 if (!device->base) {
2902 dev_err(&pdev->dev, "ioremap failed");
2903 goto err_map_dev;
2904 }
2905
Liron Kuch59339922013-01-01 18:29:47 +02002906 mem_bam = platform_get_resource_byname(pdev,
2907 IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002908 if (!mem_bam) {
2909 pr_err("tspp: Missing bam MEM resource");
2910 rc = -ENXIO;
2911 goto err_res_bam;
2912 }
2913 memset(&device->bam_props, 0, sizeof(device->bam_props));
2914 device->bam_props.phys_addr = mem_bam->start;
2915 device->bam_props.virt_addr = ioremap(mem_bam->start,
2916 resource_size(mem_bam));
2917 if (!device->bam_props.virt_addr) {
2918 dev_err(&pdev->dev, "ioremap failed");
2919 goto err_map_bam;
2920 }
2921
Liron Kuch59339922013-01-01 18:29:47 +02002922 if (msm_tspp_map_irqs(pdev, device))
Joel Nider5556a852011-10-16 10:52:13 +02002923 goto err_irq;
Joel Nider5556a852011-10-16 10:52:13 +02002924
Joel Nider5556a852011-10-16 10:52:13 +02002925 /* power management */
2926 pm_runtime_set_active(&pdev->dev);
2927 pm_runtime_enable(&pdev->dev);
2928
Joel Nider5556a852011-10-16 10:52:13 +02002929 tspp_debugfs_init(device, 0);
2930
2931 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2932 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02002933
2934 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
2935 dev_name(&pdev->dev));
2936
2937 /* set up pointers to ram-based 'registers' */
Joel Nider435ad8e2011-12-14 16:53:30 +02002938 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
2939 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
2940 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
2941 device->tspp_key_table = device->base + TSPP_DATA_KEY;
2942 device->tspp_global_performance =
2943 device->base + TSPP_GLOBAL_PERFORMANCE;
2944 device->tspp_pipe_context =
2945 device->base + TSPP_PIPE_CONTEXT;
2946 device->tspp_pipe_performance =
2947 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02002948
2949 device->bam_props.summing_threshold = 0x10;
2950 device->bam_props.irq = device->bam_irq;
2951 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
2952
Liron Kuch59339922013-01-01 18:29:47 +02002953 if (tspp_clock_start(device) != 0) {
2954 dev_err(&pdev->dev, "Can't start clocks");
2955 goto err_clock;
2956 }
2957
Joel Nider5556a852011-10-16 10:52:13 +02002958 if (sps_register_bam_device(&device->bam_props,
2959 &device->bam_handle) != 0) {
2960 pr_err("tspp: failed to register bam");
2961 goto err_bam;
2962 }
2963
Joel Nider5556a852011-10-16 10:52:13 +02002964 spin_lock_init(&device->spinlock);
2965 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
2966 (unsigned long)device);
2967
2968 /* initialize everything to a known state */
2969 tspp_global_reset(device);
2970
2971 version = readl_relaxed(device->base + TSPP_VERSION);
Liron Kuch59339922013-01-01 18:29:47 +02002972 /*
2973 * TSPP version can be bits [7:0] or alternatively,
2974 * TSPP major version is bits [31:28].
2975 */
2976 if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1))
Joel Nider5556a852011-10-16 10:52:13 +02002977 pr_warn("tspp: unrecognized hw version=%i", version);
2978
Joel Nider435ad8e2011-12-14 16:53:30 +02002979 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02002980 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002981 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
2982 pr_err("tspp_channel_init failed");
2983 goto err_channel;
2984 }
Joel Nider5556a852011-10-16 10:52:13 +02002985 }
2986
Joel Nider435ad8e2011-12-14 16:53:30 +02002987 /* stop the clocks for power savings */
2988 tspp_clock_stop(device);
2989
2990 /* everything is ok, so add the device to the list */
2991 list_add_tail(&(device->devlist), &tspp_devices);
2992
Joel Nider5556a852011-10-16 10:52:13 +02002993 return 0;
2994
Joel Nider435ad8e2011-12-14 16:53:30 +02002995err_channel:
Liron Kuch59339922013-01-01 18:29:47 +02002996 /* un-initialize channels */
Liron Kuch72b78552012-10-30 17:47:50 +02002997 for (j = 0; j < i; j++) {
2998 channel = &(device->channels[i]);
2999 device_destroy(tspp_class, channel->cdev.dev);
3000 cdev_del(&channel->cdev);
3001 }
Liron Kuch59339922013-01-01 18:29:47 +02003002
Joel Nider5556a852011-10-16 10:52:13 +02003003 sps_deregister_bam_device(device->bam_handle);
Liron Kuch59339922013-01-01 18:29:47 +02003004err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02003005err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02003006 tspp_debugfs_exit(device);
3007 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3008 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02003009err_irq:
Liron Kuch59339922013-01-01 18:29:47 +02003010 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
3011 if (device->tsif[i].tsif_irq)
3012 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
3013 }
3014 if (device->tspp_irq)
3015 free_irq(device->tspp_irq, device);
3016
Joel Nider5556a852011-10-16 10:52:13 +02003017 iounmap(device->bam_props.virt_addr);
3018err_map_bam:
3019err_res_bam:
3020 iounmap(device->base);
3021err_map_dev:
3022err_res_dev:
3023 iounmap(device->tsif[1].base);
3024err_map_tsif1:
3025err_res_tsif1:
3026 iounmap(device->tsif[0].base);
3027err_map_tsif0:
3028err_res_tsif0:
3029 if (device->tsif_ref_clk)
3030 clk_put(device->tsif_ref_clk);
3031err_refclock:
3032 if (device->tsif_pclk)
3033 clk_put(device->tsif_pclk);
3034err_pclock:
3035 kfree(device);
3036
3037out:
3038 return rc;
3039}
3040
3041static int __devexit msm_tspp_remove(struct platform_device *pdev)
3042{
Joel Nider435ad8e2011-12-14 16:53:30 +02003043 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02003044 u32 i;
Liron Kuch605cc122013-02-21 14:25:57 +02003045 int rc;
Joel Nider5556a852011-10-16 10:52:13 +02003046
3047 struct tspp_device *device = platform_get_drvdata(pdev);
3048
Joel Nider435ad8e2011-12-14 16:53:30 +02003049 /* free the buffers, and delete the channels */
3050 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
3051 channel = &device->channels[i];
3052 tspp_close_channel(device->pdev->id, i);
3053 device_destroy(tspp_class, channel->cdev.dev);
3054 cdev_del(&channel->cdev);
3055 }
3056
Liron Kuch59339922013-01-01 18:29:47 +02003057 /* de-registering BAM device requires clocks */
Liron Kuch605cc122013-02-21 14:25:57 +02003058 rc = tspp_clock_start(device);
3059 if (rc == 0) {
3060 sps_deregister_bam_device(device->bam_handle);
3061 tspp_clock_stop(device);
3062 }
Joel Nider5556a852011-10-16 10:52:13 +02003063
Hamad Kadmany44307d32012-11-25 09:49:51 +02003064 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
Joel Nider5556a852011-10-16 10:52:13 +02003065 tsif_debugfs_exit(&device->tsif[i]);
Hamad Kadmany44307d32012-11-25 09:49:51 +02003066 if (device->tsif[i].tsif_irq)
3067 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
3068 }
Joel Nider5556a852011-10-16 10:52:13 +02003069
3070 wake_lock_destroy(&device->wake_lock);
3071 free_irq(device->tspp_irq, device);
Joel Nider5556a852011-10-16 10:52:13 +02003072
3073 iounmap(device->bam_props.virt_addr);
3074 iounmap(device->base);
3075 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3076 iounmap(device->tsif[i].base);
3077
3078 if (device->tsif_ref_clk)
3079 clk_put(device->tsif_ref_clk);
3080
3081 if (device->tsif_pclk)
3082 clk_put(device->tsif_pclk);
3083
3084 pm_runtime_disable(&pdev->dev);
Liron Kuch605cc122013-02-21 14:25:57 +02003085
Joel Nider5556a852011-10-16 10:52:13 +02003086 kfree(device);
3087
3088 return 0;
3089}
3090
3091/*** power management ***/
3092
3093static int tspp_runtime_suspend(struct device *dev)
3094{
3095 dev_dbg(dev, "pm_runtime: suspending...");
3096 return 0;
3097}
3098
3099static int tspp_runtime_resume(struct device *dev)
3100{
3101 dev_dbg(dev, "pm_runtime: resuming...");
3102 return 0;
3103}
3104
3105static const struct dev_pm_ops tspp_dev_pm_ops = {
3106 .runtime_suspend = tspp_runtime_suspend,
3107 .runtime_resume = tspp_runtime_resume,
3108};
3109
Liron Kuch59339922013-01-01 18:29:47 +02003110static struct of_device_id msm_match_table[] = {
3111 {.compatible = "qcom,msm_tspp"},
3112 {}
3113};
3114
Joel Nider5556a852011-10-16 10:52:13 +02003115static struct platform_driver msm_tspp_driver = {
3116 .probe = msm_tspp_probe,
3117 .remove = __exit_p(msm_tspp_remove),
3118 .driver = {
3119 .name = "msm_tspp",
3120 .pm = &tspp_dev_pm_ops,
Liron Kuch59339922013-01-01 18:29:47 +02003121 .of_match_table = msm_match_table,
Joel Nider5556a852011-10-16 10:52:13 +02003122 },
3123};
3124
3125
3126static int __init mod_init(void)
3127{
Joel Nider5556a852011-10-16 10:52:13 +02003128 int rc;
3129
Joel Nider435ad8e2011-12-14 16:53:30 +02003130 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02003131 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
3132 if (rc) {
3133 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
3134 goto err_devrgn;
3135 }
3136
3137 tspp_class = class_create(THIS_MODULE, "tspp");
3138 if (IS_ERR(tspp_class)) {
3139 rc = PTR_ERR(tspp_class);
3140 pr_err("tspp: Error creating class: %d", rc);
3141 goto err_class;
3142 }
3143
Joel Nider435ad8e2011-12-14 16:53:30 +02003144 /* register the driver, and check hardware */
3145 rc = platform_driver_register(&msm_tspp_driver);
3146 if (rc) {
3147 pr_err("tspp: platform_driver_register failed: %d", rc);
3148 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02003149 }
3150
3151 return 0;
3152
Joel Nider435ad8e2011-12-14 16:53:30 +02003153err_register:
3154 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02003155err_class:
3156 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
3157err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02003158 return rc;
3159}
3160
3161static void __exit mod_exit(void)
3162{
Joel Nider435ad8e2011-12-14 16:53:30 +02003163 /* delete low level driver */
3164 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02003165
Joel Nider435ad8e2011-12-14 16:53:30 +02003166 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02003167 class_destroy(tspp_class);
3168 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02003169}
3170
3171module_init(mod_init);
3172module_exit(mod_exit);
3173
Joel Nider435ad8e2011-12-14 16:53:30 +02003174MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02003175MODULE_LICENSE("GPL v2");