blob: 501da4c83bbdee14b8472bd1ba44d9af8c8afb3a [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 */
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -070036#include <linux/regulator/consumer.h>
Joel Nider435ad8e2011-12-14 16:53:30 +020037#include <mach/sps.h> /* BAM stuff */
Joel Nider5556a852011-10-16 10:52:13 +020038#include <mach/gpio.h>
Joel Nider435ad8e2011-12-14 16:53:30 +020039#include <linux/wakelock.h> /* Locking functions */
Hamad Kadmany81cee052012-11-29 14:15:57 +020040#include <linux/timer.h> /* Timer services */
41#include <linux/jiffies.h> /* Jiffies counter */
Joel Nider5556a852011-10-16 10:52:13 +020042#include <mach/dma.h>
43#include <mach/msm_tspp.h>
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -070044#include <mach/rpm-regulator-smd.h>
Joel Nider5556a852011-10-16 10:52:13 +020045#include <linux/debugfs.h>
Liron Kuch59339922013-01-01 18:29:47 +020046#include <linux/of.h>
47#include <linux/of_gpio.h>
Liron Kuch275c0b32013-02-10 15:19:32 +020048#include <linux/string.h>
Joel Nider5556a852011-10-16 10:52:13 +020049
50/*
51 * General defines
52 */
Joel Nider5556a852011-10-16 10:52:13 +020053#define TSPP_TSIF_INSTANCES 2
Liron Kuch275c0b32013-02-10 15:19:32 +020054#define TSPP_GPIOS_PER_TSIF 4
Joel Nider5556a852011-10-16 10:52:13 +020055#define TSPP_FILTER_TABLES 3
Joel Nider435ad8e2011-12-14 16:53:30 +020056#define TSPP_MAX_DEVICES 1
Joel Nider5556a852011-10-16 10:52:13 +020057#define TSPP_NUM_CHANNELS 16
58#define TSPP_NUM_PRIORITIES 16
59#define TSPP_NUM_KEYS 8
60#define INVALID_CHANNEL 0xFFFFFFFF
Hamad Kadmany81cee052012-11-29 14:15:57 +020061
62/*
63 * BAM descriptor FIFO size (in number of descriptors).
64 * Max number of descriptors allowed by SPS which is 8K-1.
65 * Restrict it to half of this to save DMA memory.
66 */
67#define TSPP_SPS_DESCRIPTOR_COUNT (4 * 1024 - 1)
Joel Nider5556a852011-10-16 10:52:13 +020068#define TSPP_PACKET_LENGTH 188
69#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
Hamad Kadmany81cee052012-11-29 14:15:57 +020070
71/* Max descriptor buffer size allowed by SPS */
72#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
73
74/*
Hamad Kadmany090709b2013-01-06 12:08:13 +020075 * Returns whether to use DMA pool for TSPP output buffers.
76 * For buffers smaller than page size, using DMA pool
77 * provides better memory utilization as dma_alloc_coherent
78 * allocates minimum of page size.
79 */
80#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE)
81
82/*
Hamad Kadmany81cee052012-11-29 14:15:57 +020083 * Max allowed TSPP buffers/descriptors.
84 * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
85 */
86#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
Joel Nider5556a852011-10-16 10:52:13 +020087#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
88#define SPS_DESCRIPTOR_SIZE 8
89#define MIN_ACCEPTABLE_BUFFER_COUNT 2
Joel Nider435ad8e2011-12-14 16:53:30 +020090#define TSPP_DEBUG(msg...)
Joel Nider5556a852011-10-16 10:52:13 +020091
92/*
93 * TSIF register offsets
94 */
95#define TSIF_STS_CTL_OFF (0x0)
96#define TSIF_TIME_LIMIT_OFF (0x4)
97#define TSIF_CLK_REF_OFF (0x8)
98#define TSIF_LPBK_FLAGS_OFF (0xc)
99#define TSIF_LPBK_DATA_OFF (0x10)
100#define TSIF_TEST_CTL_OFF (0x14)
101#define TSIF_TEST_MODE_OFF (0x18)
102#define TSIF_TEST_RESET_OFF (0x1c)
103#define TSIF_TEST_EXPORT_OFF (0x20)
104#define TSIF_TEST_CURRENT_OFF (0x24)
105
106#define TSIF_DATA_PORT_OFF (0x100)
107
108/* bits for TSIF_STS_CTL register */
109#define TSIF_STS_CTL_EN_IRQ BIT(28)
110#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
111#define TSIF_STS_CTL_1ST_PACKET BIT(26)
112#define TSIF_STS_CTL_OVERFLOW BIT(25)
113#define TSIF_STS_CTL_LOST_SYNC BIT(24)
114#define TSIF_STS_CTL_TIMEOUT BIT(23)
115#define TSIF_STS_CTL_INV_SYNC BIT(21)
116#define TSIF_STS_CTL_INV_NULL BIT(20)
117#define TSIF_STS_CTL_INV_ERROR BIT(19)
118#define TSIF_STS_CTL_INV_ENABLE BIT(18)
119#define TSIF_STS_CTL_INV_DATA BIT(17)
120#define TSIF_STS_CTL_INV_CLOCK BIT(16)
121#define TSIF_STS_CTL_SPARE BIT(15)
122#define TSIF_STS_CTL_EN_NULL BIT(11)
123#define TSIF_STS_CTL_EN_ERROR BIT(10)
124#define TSIF_STS_CTL_LAST_BIT BIT(9)
125#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
126#define TSIF_STS_CTL_EN_TCR BIT(7)
127#define TSIF_STS_CTL_TEST_MODE BIT(6)
Joel Nider435ad8e2011-12-14 16:53:30 +0200128#define TSIF_STS_CTL_MODE_2 BIT(5)
Joel Nider5556a852011-10-16 10:52:13 +0200129#define TSIF_STS_CTL_EN_DM BIT(4)
130#define TSIF_STS_CTL_STOP BIT(3)
131#define TSIF_STS_CTL_START BIT(0)
132
133/*
134 * TSPP register offsets
135 */
Liron Kuch72b78552012-10-30 17:47:50 +0200136#define TSPP_RST 0x00
Joel Nider5556a852011-10-16 10:52:13 +0200137#define TSPP_CLK_CONTROL 0x04
Liron Kuch72b78552012-10-30 17:47:50 +0200138#define TSPP_CONFIG 0x08
139#define TSPP_CONTROL 0x0C
Joel Nider5556a852011-10-16 10:52:13 +0200140#define TSPP_PS_DISABLE 0x10
Liron Kuch72b78552012-10-30 17:47:50 +0200141#define TSPP_MSG_IRQ_STATUS 0x14
Joel Nider5556a852011-10-16 10:52:13 +0200142#define TSPP_MSG_IRQ_MASK 0x18
143#define TSPP_IRQ_STATUS 0x1C
144#define TSPP_IRQ_MASK 0x20
145#define TSPP_IRQ_CLEAR 0x24
146#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2))
Liron Kuch72b78552012-10-30 17:47:50 +0200147#define TSPP_STATUS 0x68
148#define TSPP_CURR_TSP_HEADER 0x6C
149#define TSPP_CURR_PID_FILTER 0x70
150#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2))
151#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2))
152#define TSPP_DATA_KEY_RESET 0x9C
Joel Nider5556a852011-10-16 10:52:13 +0200153#define TSPP_KEY_VALID 0xA0
154#define TSPP_KEY_ERROR 0xA4
155#define TSPP_TEST_CTRL 0xA8
Liron Kuch72b78552012-10-30 17:47:50 +0200156#define TSPP_VERSION 0xAC
Joel Nider5556a852011-10-16 10:52:13 +0200157#define TSPP_GENERICS 0xB0
Liron Kuch72b78552012-10-30 17:47:50 +0200158#define TSPP_NOP 0xB4
Joel Nider5556a852011-10-16 10:52:13 +0200159
160/*
161 * Register bit definitions
162 */
163/* TSPP_RST */
164#define TSPP_RST_RESET BIT(0)
165
166/* TSPP_CLK_CONTROL */
167#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9)
168#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8)
169#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7)
170#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6)
171#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5)
172#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
173#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3)
174#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
175#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
176#define TSPP_CLK_CONTROL_SET_CLKON BIT(0)
177
178/* TSPP_CONFIG */
179#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
180((_b & 0xF) << 8))
181#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
182#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7)
183#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6)
184#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5)
185#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
186#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3)
187#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2)
188#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1)
189#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0)
190
191/* TSPP_CONTROL */
192#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5)
193#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4)
194#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3)
195#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2)
196#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1)
197#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0)
198
199/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
200#define TSPP_MSG_TSPP_IRQ BIT(2)
201#define TSPP_MSG_TSIF_1_IRQ BIT(1)
202#define TSPP_MSG_TSIF_0_IRQ BIT(0)
203
204/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
Liron Kuch72b78552012-10-30 17:47:50 +0200205#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19)
206#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18)
Joel Nider5556a852011-10-16 10:52:13 +0200207#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17)
208#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16)
209#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n))
210
211/* TSPP_PIPE_ERROR_STATUS */
Liron Kuch72b78552012-10-30 17:47:50 +0200212#define TSPP_PIPE_PES_SYNC_ERROR BIT(3)
213#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2)
Joel Nider5556a852011-10-16 10:52:13 +0200214#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1)
Liron Kuch72b78552012-10-30 17:47:50 +0200215#define TSPP_PIP_PS_LOST_START BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200216
217/* TSPP_STATUS */
Liron Kuch72b78552012-10-30 17:47:50 +0200218#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10)
219#define TSPP_STATUS_TSIF1_DM_REQ BIT(6)
220#define TSPP_STATUS_TSIF0_DM_REQ BIT(2)
221#define TSPP_CURR_FILTER_TABLE BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200222
223/* TSPP_GENERICS */
Liron Kuch72b78552012-10-30 17:47:50 +0200224#define TSPP_GENERICS_CRYPTO_GEN BIT(12)
Joel Nider5556a852011-10-16 10:52:13 +0200225#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7)
Liron Kuch72b78552012-10-30 17:47:50 +0200226#define TSPP_GENERICS_MAX_PIPES BIT(2)
227#define TSPP_GENERICS_TSIF_1_GEN BIT(1)
228#define TSPP_GENERICS_TSIF_0_GEN BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200229
230/*
231 * TSPP memory regions
232 */
233#define TSPP_PID_FILTER_TABLE0 0x800
234#define TSPP_PID_FILTER_TABLE1 0x880
235#define TSPP_PID_FILTER_TABLE2 0x900
236#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */
237#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */
238#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */
239#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
240#define TSPP_DATA_KEY 0xCD0
241
Joel Nider5556a852011-10-16 10:52:13 +0200242struct debugfs_entry {
243 const char *name;
244 mode_t mode;
245 int offset;
246};
247
248static const struct debugfs_entry debugfs_tsif_regs[] = {
249 {"sts_ctl", S_IRUGO | S_IWUSR, TSIF_STS_CTL_OFF},
250 {"time_limit", S_IRUGO | S_IWUSR, TSIF_TIME_LIMIT_OFF},
251 {"clk_ref", S_IRUGO | S_IWUSR, TSIF_CLK_REF_OFF},
252 {"lpbk_flags", S_IRUGO | S_IWUSR, TSIF_LPBK_FLAGS_OFF},
253 {"lpbk_data", S_IRUGO | S_IWUSR, TSIF_LPBK_DATA_OFF},
254 {"test_ctl", S_IRUGO | S_IWUSR, TSIF_TEST_CTL_OFF},
255 {"test_mode", S_IRUGO | S_IWUSR, TSIF_TEST_MODE_OFF},
256 {"test_reset", S_IWUSR, TSIF_TEST_RESET_OFF},
257 {"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
258 {"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
259 {"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
260};
261
262static const struct debugfs_entry debugfs_tspp_regs[] = {
263 {"rst", S_IRUGO | S_IWUSR, TSPP_RST},
264 {"clk_control", S_IRUGO | S_IWUSR, TSPP_CLK_CONTROL},
265 {"config", S_IRUGO | S_IWUSR, TSPP_CONFIG},
266 {"control", S_IRUGO | S_IWUSR, TSPP_CONTROL},
267 {"ps_disable", S_IRUGO | S_IWUSR, TSPP_PS_DISABLE},
268 {"msg_irq_status", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_STATUS},
269 {"msg_irq_mask", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_MASK},
270 {"irq_status", S_IRUGO | S_IWUSR, TSPP_IRQ_STATUS},
271 {"irq_mask", S_IRUGO | S_IWUSR, TSPP_IRQ_MASK},
272 {"irq_clear", S_IRUGO | S_IWUSR, TSPP_IRQ_CLEAR},
273 /* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
274 {"status", S_IRUGO | S_IWUSR, TSPP_STATUS},
275 {"curr_tsp_header", S_IRUGO | S_IWUSR, TSPP_CURR_TSP_HEADER},
276 {"curr_pid_filter", S_IRUGO | S_IWUSR, TSPP_CURR_PID_FILTER},
277 /* {"system_key", S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
278 /* {"cbc_init_val", S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
279 {"data_key_reset", S_IRUGO | S_IWUSR, TSPP_DATA_KEY_RESET},
280 {"key_valid", S_IRUGO | S_IWUSR, TSPP_KEY_VALID},
281 {"key_error", S_IRUGO | S_IWUSR, TSPP_KEY_ERROR},
282 {"test_ctrl", S_IRUGO | S_IWUSR, TSPP_TEST_CTRL},
283 {"version", S_IRUGO | S_IWUSR, TSPP_VERSION},
284 {"generics", S_IRUGO | S_IWUSR, TSPP_GENERICS},
285 {"pid_filter_table0", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE0},
286 {"pid_filter_table1", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE1},
287 {"pid_filter_table2", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE2},
288 {"global_performance", S_IRUGO | S_IWUSR, TSPP_GLOBAL_PERFORMANCE},
289 {"pipe_context", S_IRUGO | S_IWUSR, TSPP_PIPE_CONTEXT},
290 {"pipe_performance", S_IRUGO | S_IWUSR, TSPP_PIPE_PERFORMANCE},
291 {"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
292};
293
Joel Nider5556a852011-10-16 10:52:13 +0200294struct tspp_pid_filter {
295 u32 filter; /* see FILTER_ macros */
296 u32 config; /* see FILTER_ macros */
297};
298
299/* tsp_info */
300#define FILTER_HEADER_ERROR_MASK BIT(7)
301#define FILTER_TRANS_END_DISABLE BIT(6)
302#define FILTER_DEC_ON_ERROR_EN BIT(5)
303#define FILTER_DECRYPT BIT(4)
304#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT)
305#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF)
306#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \
307 (_p->config & ~0xF) | (_b & 0xF))
308#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3)
309#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \
310 (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
311#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF)
312#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \
313 (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
314#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF)
315#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \
316 (_p->filter & ~0x1FFF) | (_b & 0x1FFF))
317#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3)
318#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \
319 (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
320#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7)
321#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \
322 (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
323
324struct tspp_global_performance_regs {
325 u32 tsp_total;
326 u32 tsp_ignored;
327 u32 tsp_error;
328 u32 tsp_sync;
329};
330
331struct tspp_pipe_context_regs {
332 u16 pes_bytes_left;
333 u16 count;
334 u32 tsif_suffix;
335} __packed;
336#define CONTEXT_GET_STATE(_a) (_a & 0x3)
337#define CONTEXT_UNSPEC_LENGTH BIT(11)
338#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
339
Hamad Kadmany81cee052012-11-29 14:15:57 +0200340#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
341
Joel Nider5556a852011-10-16 10:52:13 +0200342struct tspp_pipe_performance_regs {
343 u32 tsp_total;
344 u32 ps_duplicate_tsp;
345 u32 tsp_no_payload;
346 u32 tsp_broken_ps;
347 u32 ps_total_num;
348 u32 ps_continuity_error;
349 u32 ps_length_error;
350 u32 pes_sync_error;
351};
352
353struct tspp_tsif_device {
354 void __iomem *base;
355 u32 time_limit;
356 u32 ref_count;
Joel Nider435ad8e2011-12-14 16:53:30 +0200357 enum tspp_tsif_mode mode;
Hamad Kadmany92705b32012-10-23 14:15:41 +0200358 int clock_inverse;
359 int data_inverse;
360 int sync_inverse;
361 int enable_inverse;
Hamad Kadmany44307d32012-11-25 09:49:51 +0200362 u32 tsif_irq;
Joel Nider5556a852011-10-16 10:52:13 +0200363
364 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200365 struct dentry *dent_tsif;
366 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Hamad Kadmany44307d32012-11-25 09:49:51 +0200367 u32 stat_rx;
368 u32 stat_overflow;
369 u32 stat_lost_sync;
370 u32 stat_timeout;
Joel Nider5556a852011-10-16 10:52:13 +0200371};
372
373enum tspp_buf_state {
374 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
375 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider435ad8e2011-12-14 16:53:30 +0200376 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
377 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200378};
379
380struct tspp_mem_buffer {
Joel Nider435ad8e2011-12-14 16:53:30 +0200381 struct tspp_mem_buffer *next;
382 struct sps_mem_buffer sps;
383 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200384 enum tspp_buf_state state;
385 size_t filled; /* how much data this buffer is holding */
386 int read_index; /* where to start reading data from */
387};
388
389/* this represents each char device 'channel' */
390struct tspp_channel {
391 struct cdev cdev;
392 struct device *dd;
Joel Nider435ad8e2011-12-14 16:53:30 +0200393 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200394 struct sps_pipe *pipe;
395 struct sps_connect config;
396 struct sps_register_event event;
Joel Nider435ad8e2011-12-14 16:53:30 +0200397 struct tspp_mem_buffer *data; /* list of buffers */
398 struct tspp_mem_buffer *read; /* first buffer ready to be read */
399 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
400 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200401 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider435ad8e2011-12-14 16:53:30 +0200402 u32 id; /* channel id (0-15) */
403 int used; /* is this channel in use? */
404 int key; /* which encryption key index is used */
405 u32 buffer_size; /* size of the sps transfer buffers */
406 u32 max_buffers; /* how many buffers should be allocated */
407 u32 buffer_count; /* how many buffers are actually allocated */
408 u32 filter_count; /* how many filters have been added to this channel */
409 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200410 enum tspp_source src;
411 enum tspp_mode mode;
Joel Nider435ad8e2011-12-14 16:53:30 +0200412 tspp_notifier *notifier; /* used only with kernel api */
413 void *notify_data; /* data to be passed with the notifier */
Hamad Kadmany81cee052012-11-29 14:15:57 +0200414 u32 expiration_period_ms; /* notification on partially filled buffers */
415 struct timer_list expiration_timer;
Hamad Kadmany090709b2013-01-06 12:08:13 +0200416 struct dma_pool *dma_pool;
Liron Kuch72b78552012-10-30 17:47:50 +0200417 tspp_memfree *memfree; /* user defined memory free function */
418 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200419};
420
421struct tspp_pid_filter_table {
422 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
423};
424
425struct tspp_key_entry {
426 u32 even_lsb;
427 u32 even_msb;
428 u32 odd_lsb;
429 u32 odd_msb;
430};
431
432struct tspp_key_table {
433 struct tspp_key_entry entry[TSPP_NUM_KEYS];
434};
435
Joel Nider435ad8e2011-12-14 16:53:30 +0200436/* this represents the actual hardware device */
437struct tspp_device {
438 struct list_head devlist; /* list of all devices */
439 struct platform_device *pdev;
440 void __iomem *base;
441 unsigned int tspp_irq;
442 unsigned int bam_irq;
443 u32 bam_handle;
444 struct sps_bam_props bam_props;
445 struct wake_lock wake_lock;
446 spinlock_t spinlock;
447 struct tasklet_struct tlet;
448 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
449 /* clocks */
450 struct clk *tsif_pclk;
451 struct clk *tsif_ref_clk;
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700452 /* regulators */
453 struct regulator *tsif_vreg;
Joel Nider435ad8e2011-12-14 16:53:30 +0200454 /* data */
455 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
456 struct tspp_channel channels[TSPP_NUM_CHANNELS];
457 struct tspp_key_table *tspp_key_table;
458 struct tspp_global_performance_regs *tspp_global_performance;
459 struct tspp_pipe_context_regs *tspp_pipe_context;
460 struct tspp_pipe_performance_regs *tspp_pipe_performance;
461
462 struct dentry *dent;
463 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
464};
465
466
Joel Nider5556a852011-10-16 10:52:13 +0200467static struct class *tspp_class;
468static int tspp_key_entry;
469static dev_t tspp_minor; /* next minor number to assign */
Joel Nider435ad8e2011-12-14 16:53:30 +0200470
471static LIST_HEAD(tspp_devices);
472
473/* forward declarations */
474static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
475static ssize_t tspp_open(struct inode *inode, struct file *filp);
476static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
477static ssize_t tspp_release(struct inode *inode, struct file *filp);
478static long tspp_ioctl(struct file *, unsigned int, unsigned long);
479
480/* file operations */
481static const struct file_operations tspp_fops = {
482 .owner = THIS_MODULE,
483 .read = tspp_read,
484 .open = tspp_open,
485 .poll = tspp_poll,
486 .release = tspp_release,
487 .unlocked_ioctl = tspp_ioctl,
488};
Joel Nider5556a852011-10-16 10:52:13 +0200489
490/*** IRQ ***/
Joel Nider435ad8e2011-12-14 16:53:30 +0200491static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200492{
Joel Nider435ad8e2011-12-14 16:53:30 +0200493 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200494 u32 status, mask;
495 u32 data;
496
497 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
498 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
499 status &= mask;
500
501 if (!status) {
502 dev_warn(&device->pdev->dev, "Spurious interrupt");
503 return IRQ_NONE;
504 }
505
506 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
507
508 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
509 /* read the key error info */
510 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
511 dev_info(&device->pdev->dev, "key error 0x%x", data);
512 }
513 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
514 data = readl_relaxed(device->base + TSPP_KEY_VALID);
515 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
516 }
517 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
518 dev_info(&device->pdev->dev, "key switched");
519
520 if (status & 0xffff)
Joel Nider435ad8e2011-12-14 16:53:30 +0200521 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200522
523 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
Hamad Kadmany44307d32012-11-25 09:49:51 +0200524
525 /*
526 * Before returning IRQ_HANDLED to the generic interrupt handling
527 * framework need to make sure all operations including clearing of
528 * interrupt status registers in the hardware is performed.
529 * Thus a barrier after clearing the interrupt status register
530 * is required to guarantee that the interrupt status register has
531 * really been cleared by the time we return from this handler.
532 */
533 wmb();
534 return IRQ_HANDLED;
535}
536
537static irqreturn_t tsif_isr(int irq, void *dev)
538{
539 struct tspp_tsif_device *tsif_device = dev;
540 u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
541
542 if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
543 TSIF_STS_CTL_OVERFLOW |
544 TSIF_STS_CTL_LOST_SYNC |
545 TSIF_STS_CTL_TIMEOUT)))
546 return IRQ_NONE;
547
548 if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
549 tsif_device->stat_overflow++;
550
551 if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
552 tsif_device->stat_lost_sync++;
553
554 if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
555 tsif_device->stat_timeout++;
556
557 iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
558
559 /*
560 * Before returning IRQ_HANDLED to the generic interrupt handling
561 * framework need to make sure all operations including clearing of
562 * interrupt status registers in the hardware is performed.
563 * Thus a barrier after clearing the interrupt status register
564 * is required to guarantee that the interrupt status register has
565 * really been cleared by the time we return from this handler.
566 */
Joel Nider5556a852011-10-16 10:52:13 +0200567 wmb();
568 return IRQ_HANDLED;
569}
570
571/*** callbacks ***/
572static void tspp_sps_complete_cb(struct sps_event_notify *notify)
573{
Joel Nider435ad8e2011-12-14 16:53:30 +0200574 struct tspp_device *pdev = notify->user;
575 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200576}
577
Hamad Kadmany81cee052012-11-29 14:15:57 +0200578static void tspp_expiration_timer(unsigned long data)
579{
580 struct tspp_device *pdev = (struct tspp_device *)data;
581
582 if (pdev)
583 tasklet_schedule(&pdev->tlet);
584}
585
Joel Nider5556a852011-10-16 10:52:13 +0200586/*** tasklet ***/
587static void tspp_sps_complete_tlet(unsigned long data)
588{
589 int i;
590 int complete;
591 unsigned long flags;
592 struct sps_iovec iovec;
593 struct tspp_channel *channel;
594 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200595 spin_lock_irqsave(&device->spinlock, flags);
596
597 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
598 complete = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +0200599 channel = &device->channels[i];
Hamad Kadmany81cee052012-11-29 14:15:57 +0200600
Joel Nider435ad8e2011-12-14 16:53:30 +0200601 if (!channel->used || !channel->waiting)
602 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200603
Hamad Kadmany81cee052012-11-29 14:15:57 +0200604 /* stop the expiration timer */
605 if (channel->expiration_period_ms)
606 del_timer(&channel->expiration_timer);
607
Joel Nider5556a852011-10-16 10:52:13 +0200608 /* get completions */
Joel Nider435ad8e2011-12-14 16:53:30 +0200609 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200610 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
611 pr_err("tspp: Error in iovec on channel %i",
612 channel->id);
613 break;
614 }
615 if (iovec.size == 0)
616 break;
617
Joel Nider435ad8e2011-12-14 16:53:30 +0200618 if (iovec.addr != channel->waiting->sps.phys_base)
Joel Nider5556a852011-10-16 10:52:13 +0200619 pr_err("tspp: buffer mismatch 0x%08x",
Joel Nider435ad8e2011-12-14 16:53:30 +0200620 channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200621
622 complete = 1;
Joel Nider435ad8e2011-12-14 16:53:30 +0200623 channel->waiting->state = TSPP_BUF_STATE_DATA;
624 channel->waiting->filled = iovec.size;
625 channel->waiting->read_index = 0;
626
Hamad Kadmany44307d32012-11-25 09:49:51 +0200627 if (channel->src == TSPP_SOURCE_TSIF0)
628 device->tsif[0].stat_rx++;
629 else if (channel->src == TSPP_SOURCE_TSIF1)
630 device->tsif[1].stat_rx++;
631
Joel Nider435ad8e2011-12-14 16:53:30 +0200632 /* update the pointers */
633 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200634 }
635
Joel Nider435ad8e2011-12-14 16:53:30 +0200636 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200637 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200638 wake_up_interruptible(&channel->in_queue);
Joel Nider435ad8e2011-12-14 16:53:30 +0200639
640 /* call notifiers */
641 if (channel->notifier)
642 channel->notifier(channel->id,
643 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200644 }
Hamad Kadmany81cee052012-11-29 14:15:57 +0200645
646 /* restart expiration timer */
647 if (channel->expiration_period_ms)
648 mod_timer(&channel->expiration_timer,
649 jiffies +
650 MSEC_TO_JIFFIES(
651 channel->expiration_period_ms));
Joel Nider5556a852011-10-16 10:52:13 +0200652 }
653
654 spin_unlock_irqrestore(&device->spinlock, flags);
655}
656
657/*** GPIO functions ***/
Liron Kuch275c0b32013-02-10 15:19:32 +0200658static int tspp_gpios_disable(const struct tspp_tsif_device *tsif_device,
659 const struct msm_gpio *table,
660 int size)
Joel Nider5556a852011-10-16 10:52:13 +0200661{
662 int rc = 0;
663 int i;
664 const struct msm_gpio *g;
Liron Kuch59339922013-01-01 18:29:47 +0200665
Joel Nider5556a852011-10-16 10:52:13 +0200666 for (i = size-1; i >= 0; i--) {
667 int tmp;
668 g = table + i;
Liron Kuch59339922013-01-01 18:29:47 +0200669
Liron Kuch275c0b32013-02-10 15:19:32 +0200670 /* don't use sync GPIO when not working in mode 2 */
671 if ((tsif_device->mode != TSPP_TSIF_MODE_2) &&
672 (strnstr(g->label, "sync", strlen(g->label)) != NULL))
673 continue;
674
Liron Kuch59339922013-01-01 18:29:47 +0200675 tmp = gpio_tlmm_config(GPIO_CFG(GPIO_PIN(g->gpio_cfg),
676 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
677 GPIO_CFG_DISABLE);
Joel Nider5556a852011-10-16 10:52:13 +0200678 if (tmp) {
Liron Kuch72b78552012-10-30 17:47:50 +0200679 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200680 g->gpio_cfg, g->label ?: "?", rc);
681 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
682 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
683 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
684 GPIO_DRVSTR(g->gpio_cfg));
685 if (!rc)
686 rc = tmp;
687 }
688 }
689
690 return rc;
691}
692
Liron Kuch275c0b32013-02-10 15:19:32 +0200693static int tspp_gpios_enable(const struct tspp_tsif_device *tsif_device,
694 const struct msm_gpio *table,
695 int size)
Joel Nider5556a852011-10-16 10:52:13 +0200696{
697 int rc;
Liron Kuch275c0b32013-02-10 15:19:32 +0200698 int i;
Joel Nider5556a852011-10-16 10:52:13 +0200699 const struct msm_gpio *g;
Liron Kuch59339922013-01-01 18:29:47 +0200700
Joel Nider5556a852011-10-16 10:52:13 +0200701 for (i = 0; i < size; i++) {
702 g = table + i;
Liron Kuch275c0b32013-02-10 15:19:32 +0200703
704 /* don't use sync GPIO when not working in mode 2 */
705 if ((tsif_device->mode != TSPP_TSIF_MODE_2) &&
706 (strnstr(g->label, "sync", strlen(g->label)) != NULL))
707 continue;
708
Joel Nider5556a852011-10-16 10:52:13 +0200709 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
710 if (rc) {
Liron Kuch72b78552012-10-30 17:47:50 +0200711 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200712 g->gpio_cfg, g->label ?: "?", rc);
713 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
714 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
715 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
716 GPIO_DRVSTR(g->gpio_cfg));
717 goto err;
718 }
719 }
720 return 0;
721err:
Liron Kuch275c0b32013-02-10 15:19:32 +0200722 tspp_gpios_disable(tsif_device, table, i);
Joel Nider5556a852011-10-16 10:52:13 +0200723
Joel Nider5556a852011-10-16 10:52:13 +0200724 return rc;
725}
726
Liron Kuch275c0b32013-02-10 15:19:32 +0200727
728static int tspp_config_gpios(struct tspp_device *device,
729 enum tspp_source source,
730 int enable)
Joel Nider5556a852011-10-16 10:52:13 +0200731{
Liron Kuch275c0b32013-02-10 15:19:32 +0200732 const struct msm_gpio *table;
733 struct msm_tspp_platform_data *pdata = device->pdev->dev.platform_data;
734 int num_gpios = (pdata->num_gpios / TSPP_TSIF_INSTANCES);
735 int i = 0;
Liron Kuch59339922013-01-01 18:29:47 +0200736
Liron Kuch275c0b32013-02-10 15:19:32 +0200737 if (num_gpios != TSPP_GPIOS_PER_TSIF) {
738 pr_err("tspp %s: unexpected number of GPIOs %d, expected %d\n",
739 __func__, num_gpios, TSPP_GPIOS_PER_TSIF);
740 return -EINVAL;
741 }
Joel Nider5556a852011-10-16 10:52:13 +0200742
Liron Kuch275c0b32013-02-10 15:19:32 +0200743 /*
744 * Note: this code assumes that the GPIO definitions in the
745 * pdata->gpios table are according to the TSIF instance number,
746 * i.e., that TSIF0 GPIOs are defined first, then TSIF1 GPIOs etc.
747 */
748 switch (source) {
749 case TSPP_SOURCE_TSIF0:
750 i = 0;
751 break;
752 case TSPP_SOURCE_TSIF1:
753 i = 1;
754 break;
755 default:
756 pr_err("tspp %s: invalid source\n", __func__);
757 return -EINVAL;
758 }
Liron Kuch59339922013-01-01 18:29:47 +0200759
Liron Kuch275c0b32013-02-10 15:19:32 +0200760 table = pdata->gpios + (i * num_gpios);
761 if (enable)
762 return tspp_gpios_enable(&device->tsif[i], table, num_gpios);
763 else
764 return tspp_gpios_disable(&device->tsif[i], table, num_gpios);
Joel Nider5556a852011-10-16 10:52:13 +0200765}
766
Joel Nider435ad8e2011-12-14 16:53:30 +0200767/*** Clock functions ***/
768static int tspp_clock_start(struct tspp_device *device)
769{
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700770 int rc;
771
Liron Kuch605cc122013-02-21 14:25:57 +0200772 if (device == NULL) {
773 pr_err("tspp: Can't start clocks, invalid device\n");
774 return -EINVAL;
775 }
776
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700777 if (device->tsif_vreg) {
778 rc = regulator_set_voltage(device->tsif_vreg,
779 RPM_REGULATOR_CORNER_SUPER_TURBO,
780 RPM_REGULATOR_CORNER_SUPER_TURBO);
781 if (rc) {
782 pr_err("Unable to set CX voltage.\n");
783 return rc;
784 }
785 }
786
Joel Nider435ad8e2011-12-14 16:53:30 +0200787 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
788 pr_err("tspp: Can't start pclk");
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700789
790 if (device->tsif_vreg) {
791 regulator_set_voltage(device->tsif_vreg,
792 RPM_REGULATOR_CORNER_SVS_SOC,
793 RPM_REGULATOR_CORNER_SUPER_TURBO);
794 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200795 return -EBUSY;
796 }
797
798 if (device->tsif_ref_clk &&
799 clk_prepare_enable(device->tsif_ref_clk) != 0) {
800 pr_err("tspp: Can't start ref clk");
801 clk_disable_unprepare(device->tsif_pclk);
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700802 if (device->tsif_vreg) {
803 regulator_set_voltage(device->tsif_vreg,
804 RPM_REGULATOR_CORNER_SVS_SOC,
805 RPM_REGULATOR_CORNER_SUPER_TURBO);
806 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200807 return -EBUSY;
808 }
809
810 return 0;
811}
812
813static void tspp_clock_stop(struct tspp_device *device)
814{
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700815 int rc;
816
Liron Kuch605cc122013-02-21 14:25:57 +0200817 if (device == NULL) {
818 pr_err("tspp: Can't stop clocks, invalid device\n");
819 return;
820 }
821
Joel Nider435ad8e2011-12-14 16:53:30 +0200822 if (device->tsif_pclk)
Liron Kuch605cc122013-02-21 14:25:57 +0200823 clk_disable_unprepare(device->tsif_pclk);
Joel Nider435ad8e2011-12-14 16:53:30 +0200824
825 if (device->tsif_ref_clk)
Liron Kuch605cc122013-02-21 14:25:57 +0200826 clk_disable_unprepare(device->tsif_ref_clk);
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700827
828 if (device->tsif_vreg) {
829 rc = regulator_set_voltage(device->tsif_vreg,
830 RPM_REGULATOR_CORNER_SVS_SOC,
831 RPM_REGULATOR_CORNER_SUPER_TURBO);
832 if (rc)
833 pr_err("Unable to set CX voltage.\n");
834 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200835}
836
Joel Nider5556a852011-10-16 10:52:13 +0200837/*** TSIF functions ***/
838static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
839{
840 int start_hardware = 0;
841 u32 ctl;
842
843 if (tsif_device->ref_count == 0) {
844 start_hardware = 1;
845 } else if (tsif_device->ref_count > 0) {
846 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
847 if ((ctl & TSIF_STS_CTL_START) != 1) {
848 /* this hardware should already be running */
849 pr_warn("tspp: tsif hw not started but ref count > 0");
850 start_hardware = 1;
851 }
852 }
853
854 if (start_hardware) {
Joel Nider435ad8e2011-12-14 16:53:30 +0200855 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200856 TSIF_STS_CTL_EN_DM;
Hamad Kadmany92705b32012-10-23 14:15:41 +0200857
858 if (tsif_device->clock_inverse)
859 ctl |= TSIF_STS_CTL_INV_CLOCK;
860
861 if (tsif_device->data_inverse)
862 ctl |= TSIF_STS_CTL_INV_DATA;
863
864 if (tsif_device->sync_inverse)
865 ctl |= TSIF_STS_CTL_INV_SYNC;
866
867 if (tsif_device->enable_inverse)
868 ctl |= TSIF_STS_CTL_INV_ENABLE;
869
Joel Nider435ad8e2011-12-14 16:53:30 +0200870 switch (tsif_device->mode) {
871 case TSPP_TSIF_MODE_LOOPBACK:
872 ctl |= TSIF_STS_CTL_EN_NULL |
873 TSIF_STS_CTL_EN_ERROR |
874 TSIF_STS_CTL_TEST_MODE;
875 break;
876 case TSPP_TSIF_MODE_1:
877 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
878 TSIF_STS_CTL_EN_TCR;
879 break;
880 case TSPP_TSIF_MODE_2:
881 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
882 TSIF_STS_CTL_EN_TCR |
883 TSIF_STS_CTL_MODE_2;
884 break;
885 default:
886 pr_warn("tspp: unknown tsif mode 0x%x",
887 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200888 }
889 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
890 writel_relaxed(tsif_device->time_limit,
891 tsif_device->base + TSIF_TIME_LIMIT_OFF);
892 wmb();
893 writel_relaxed(ctl | TSIF_STS_CTL_START,
894 tsif_device->base + TSIF_STS_CTL_OFF);
895 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200896 }
897
Joel Nider435ad8e2011-12-14 16:53:30 +0200898 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Joel Nider5556a852011-10-16 10:52:13 +0200899 tsif_device->ref_count++;
900
Joel Nider435ad8e2011-12-14 16:53:30 +0200901 return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200902}
903
904static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
905{
906 if (tsif_device->ref_count == 0)
907 return;
908
909 tsif_device->ref_count--;
910
911 if (tsif_device->ref_count == 0) {
912 writel_relaxed(TSIF_STS_CTL_STOP,
913 tsif_device->base + TSIF_STS_CTL_OFF);
914 wmb();
915 }
916}
917
Joel Nider435ad8e2011-12-14 16:53:30 +0200918/*** local TSPP functions ***/
919static int tspp_channels_in_use(struct tspp_device *pdev)
920{
921 int i;
922 int count = 0;
923 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
924 count += (pdev->channels[i].used ? 1 : 0);
925
926 return count;
927}
928
929static struct tspp_device *tspp_find_by_id(int id)
930{
931 struct tspp_device *dev;
932 list_for_each_entry(dev, &tspp_devices, devlist) {
933 if (dev->pdev->id == id)
934 return dev;
935 }
936 return NULL;
937}
938
Joel Nider5556a852011-10-16 10:52:13 +0200939static int tspp_get_key_entry(void)
940{
941 int i;
942 for (i = 0; i < TSPP_NUM_KEYS; i++) {
943 if (!(tspp_key_entry & (1 << i))) {
944 tspp_key_entry |= (1 << i);
945 return i;
946 }
947 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200948 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200949}
950
951static void tspp_free_key_entry(int entry)
952{
953 if (entry > TSPP_NUM_KEYS) {
954 pr_err("tspp_free_key_entry: index out of bounds");
955 return;
956 }
957
958 tspp_key_entry &= ~(1 << entry);
959}
960
Joel Nider435ad8e2011-12-14 16:53:30 +0200961static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
Hamad Kadmany090709b2013-01-06 12:08:13 +0200962 u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200963{
Joel Nider435ad8e2011-12-14 16:53:30 +0200964 if (size < TSPP_MIN_BUFFER_SIZE ||
965 size > TSPP_MAX_BUFFER_SIZE) {
966 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200967 return -ENOMEM;
968 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200969
970 if (alloc) {
971 TSPP_DEBUG("tspp using alloc function");
972 desc->virt_base = alloc(channel_id, size,
973 &desc->phys_base, user);
974 } else {
Hamad Kadmany090709b2013-01-06 12:08:13 +0200975 if (!dma_pool)
976 desc->virt_base = dma_alloc_coherent(NULL, size,
977 &desc->phys_base, GFP_KERNEL);
978 else
979 desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL,
980 &desc->phys_base);
981
Liron Kuch72b78552012-10-30 17:47:50 +0200982 if (desc->virt_base == 0) {
Hamad Kadmany090709b2013-01-06 12:08:13 +0200983 pr_err("tspp: dma buffer allocation failed %i\n", size);
Liron Kuch72b78552012-10-30 17:47:50 +0200984 return -ENOMEM;
985 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200986 }
987
988 desc->size = size;
989 return 0;
990}
991
992static int tspp_queue_buffer(struct tspp_channel *channel,
993 struct tspp_mem_buffer *buffer)
994{
995 int rc;
996 u32 flags = 0;
997
998 /* make sure the interrupt frequency is valid */
999 if (channel->int_freq < 1)
1000 channel->int_freq = 1;
1001
1002 /* generate interrupt according to requested frequency */
1003 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
Hamad Kadmany81cee052012-11-29 14:15:57 +02001004 flags = SPS_IOVEC_FLAG_INT;
Joel Nider435ad8e2011-12-14 16:53:30 +02001005
1006 /* start the transfer */
1007 rc = sps_transfer_one(channel->pipe,
1008 buffer->sps.phys_base,
1009 buffer->sps.size,
1010 channel->pdev,
1011 flags);
1012 if (rc < 0)
1013 return rc;
1014
1015 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +02001016
1017 return 0;
1018}
1019
1020static int tspp_global_reset(struct tspp_device *pdev)
1021{
1022 u32 i, val;
1023
1024 /* stop all TSIFs */
1025 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
1026 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
1027 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
1028 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmany92705b32012-10-23 14:15:41 +02001029 pdev->tsif[i].clock_inverse = 0;
1030 pdev->tsif[i].data_inverse = 0;
1031 pdev->tsif[i].sync_inverse = 0;
1032 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001033 }
1034 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
1035 wmb();
1036
1037 /* BAM */
1038 if (sps_device_reset(pdev->bam_handle) != 0) {
1039 pr_err("tspp: error resetting bam");
Joel Nider435ad8e2011-12-14 16:53:30 +02001040 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001041 }
1042
1043 /* TSPP tables */
1044 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider435ad8e2011-12-14 16:53:30 +02001045 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +02001046 0, sizeof(struct tspp_pid_filter_table));
1047
1048 /* disable all filters */
1049 val = (2 << TSPP_NUM_CHANNELS) - 1;
1050 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
1051
1052 /* TSPP registers */
1053 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1054 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1055 pdev->base + TSPP_CONTROL);
1056 wmb();
Joel Nider435ad8e2011-12-14 16:53:30 +02001057 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001058 sizeof(struct tspp_global_performance_regs));
Joel Nider435ad8e2011-12-14 16:53:30 +02001059 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001060 sizeof(struct tspp_pipe_context_regs));
Joel Nider435ad8e2011-12-14 16:53:30 +02001061 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001062 sizeof(struct tspp_pipe_performance_regs));
1063 wmb();
1064 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1065 pdev->base + TSPP_CONTROL);
1066 wmb();
1067
1068 val = readl_relaxed(pdev->base + TSPP_CONFIG);
1069 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
1070 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
1071 TSPP_CONFIG_PS_CONT_ERR_MASK);
1072 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
1073 writel_relaxed(val, pdev->base + TSPP_CONFIG);
Hamad Kadmany6bac7832012-12-20 18:30:40 +02001074 writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK);
Joel Nider5556a852011-10-16 10:52:13 +02001075 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
1076 writel_relaxed(0, pdev->base + TSPP_RST);
1077 wmb();
1078
1079 tspp_key_entry = 0;
1080
1081 return 0;
1082}
1083
Joel Nider435ad8e2011-12-14 16:53:30 +02001084static int tspp_select_source(u32 dev, u32 channel_id,
1085 struct tspp_select_source *src)
1086{
1087 /* make sure the requested src id is in bounds */
1088 if (src->source > TSPP_SOURCE_MEM) {
1089 pr_err("tspp source out of bounds");
1090 return -EINVAL;
1091 }
1092
1093 /* open the stream */
Hamad Kadmany92705b32012-10-23 14:15:41 +02001094 tspp_open_stream(dev, channel_id, src);
Joel Nider435ad8e2011-12-14 16:53:30 +02001095
1096 return 0;
1097}
1098
1099static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
1100{
1101 struct tspp_device *pdev = channel->pdev;
1102
1103 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
1104 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
1105 return 0;
1106}
1107
1108static int tspp_set_system_keys(struct tspp_channel *channel,
1109 struct tspp_system_keys *keys)
1110{
1111 int i;
1112 struct tspp_device *pdev = channel->pdev;
1113
1114 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
1115 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
1116
1117 return 0;
1118}
1119
1120static int tspp_channel_init(struct tspp_channel *channel,
1121 struct tspp_device *pdev)
1122{
1123 channel->cdev.owner = THIS_MODULE;
1124 cdev_init(&channel->cdev, &tspp_fops);
1125 channel->pdev = pdev;
1126 channel->data = NULL;
1127 channel->read = NULL;
1128 channel->waiting = NULL;
1129 channel->locked = NULL;
1130 channel->id = MINOR(tspp_minor);
1131 channel->used = 0;
1132 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1133 channel->max_buffers = TSPP_NUM_BUFFERS;
1134 channel->buffer_count = 0;
1135 channel->filter_count = 0;
1136 channel->int_freq = 1;
Liron Kuch72b78552012-10-30 17:47:50 +02001137 channel->src = TSPP_SOURCE_NONE;
1138 channel->mode = TSPP_MODE_DISABLED;
Joel Nider435ad8e2011-12-14 16:53:30 +02001139 channel->notifier = NULL;
1140 channel->notify_data = NULL;
Hamad Kadmany81cee052012-11-29 14:15:57 +02001141 channel->expiration_period_ms = 0;
Liron Kuch72b78552012-10-30 17:47:50 +02001142 channel->memfree = NULL;
1143 channel->user_info = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001144 init_waitqueue_head(&channel->in_queue);
1145
1146 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
1147 pr_err("tspp: cdev_add failed");
1148 return -EBUSY;
1149 }
1150
1151 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
1152 channel, "tspp%02d", channel->id);
1153 if (IS_ERR(channel->dd)) {
1154 pr_err("tspp: device_create failed: %i",
1155 (int)PTR_ERR(channel->dd));
1156 cdev_del(&channel->cdev);
1157 return -EBUSY;
1158 }
1159
1160 return 0;
1161}
1162
1163static int tspp_set_buffer_size(struct tspp_channel *channel,
1164 struct tspp_buffer *buf)
1165{
Liron Kuch72b78552012-10-30 17:47:50 +02001166 if (channel->buffer_count > 0) {
1167 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1168 return -EPERM;
1169 }
1170
Joel Nider435ad8e2011-12-14 16:53:30 +02001171 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1172 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1173 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1174 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1175 else
1176 channel->buffer_size = buf->size;
1177
1178 return 0;
1179}
1180
1181static void tspp_set_tsif_mode(struct tspp_channel *channel,
1182 enum tspp_tsif_mode mode)
1183{
1184 int index;
1185
1186 switch (channel->src) {
1187 case TSPP_SOURCE_TSIF0:
1188 index = 0;
1189 break;
1190 case TSPP_SOURCE_TSIF1:
1191 index = 1;
1192 break;
1193 default:
1194 pr_warn("tspp: can't set mode for non-tsif source %d",
1195 channel->src);
1196 return;
1197 }
1198 channel->pdev->tsif[index].mode = mode;
1199}
1200
Hamad Kadmany92705b32012-10-23 14:15:41 +02001201static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch72b78552012-10-30 17:47:50 +02001202 int clock_inverse, int data_inverse,
1203 int sync_inverse, int enable_inverse)
Hamad Kadmany92705b32012-10-23 14:15:41 +02001204{
1205 int index;
1206
1207 switch (channel->src) {
1208 case TSPP_SOURCE_TSIF0:
1209 index = 0;
1210 break;
1211 case TSPP_SOURCE_TSIF1:
1212 index = 1;
1213 break;
1214 default:
1215 return;
1216 }
1217 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1218 channel->pdev->tsif[index].data_inverse = data_inverse;
1219 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1220 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1221}
1222
Liron Kuch72b78552012-10-30 17:47:50 +02001223static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1224{
1225 u32 alignment;
1226
1227 switch (mode) {
1228 case TSPP_MODE_RAW:
1229 /* must be a multiple of 192 */
1230 alignment = (TSPP_PACKET_LENGTH + 4);
1231 if (size % alignment)
1232 return 0;
1233 return 1;
1234
1235 case TSPP_MODE_RAW_NO_SUFFIX:
1236 /* must be a multiple of 188 */
1237 alignment = TSPP_PACKET_LENGTH;
1238 if (size % alignment)
1239 return 0;
1240 return 1;
1241
1242 case TSPP_MODE_DISABLED:
1243 case TSPP_MODE_PES:
1244 default:
1245 /* no alignment requirement */
1246 return 1;
1247 }
1248
1249}
1250
1251static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1252{
1253 u32 new_size;
1254 u32 alignment;
1255
1256 switch (mode) {
1257 case TSPP_MODE_RAW:
1258 /* must be a multiple of 192 */
1259 alignment = (TSPP_PACKET_LENGTH + 4);
1260 break;
1261
1262 case TSPP_MODE_RAW_NO_SUFFIX:
1263 /* must be a multiple of 188 */
1264 alignment = TSPP_PACKET_LENGTH;
1265 break;
1266
1267 case TSPP_MODE_DISABLED:
1268 case TSPP_MODE_PES:
1269 default:
1270 /* no alignment requirement - give the user what he asks for */
1271 alignment = 1;
1272 break;
1273 }
1274 /* align up */
1275 new_size = (((size + alignment - 1) / alignment) * alignment);
1276 return new_size;
1277}
1278
1279static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1280{
1281 int i;
1282 struct tspp_mem_buffer *pbuf, *temp;
1283
1284 pbuf = channel->data;
1285 for (i = 0; i < channel->buffer_count; i++) {
1286 if (pbuf->desc.phys_base) {
1287 if (channel->memfree) {
1288 channel->memfree(channel_id,
1289 pbuf->desc.size,
1290 pbuf->desc.virt_base,
1291 pbuf->desc.phys_base,
1292 channel->user_info);
1293 } else {
Hamad Kadmany090709b2013-01-06 12:08:13 +02001294 if (!channel->dma_pool)
1295 dma_free_coherent(NULL,
1296 pbuf->desc.size,
1297 pbuf->desc.virt_base,
1298 pbuf->desc.phys_base);
1299 else
1300 dma_pool_free(channel->dma_pool,
1301 pbuf->desc.virt_base,
1302 pbuf->desc.phys_base);
Liron Kuch72b78552012-10-30 17:47:50 +02001303 }
1304 pbuf->desc.phys_base = 0;
1305 }
1306 pbuf->desc.virt_base = 0;
1307 pbuf->state = TSPP_BUF_STATE_EMPTY;
1308 temp = pbuf;
1309 pbuf = pbuf->next;
1310 kfree(temp);
1311 }
1312}
1313
Joel Nider435ad8e2011-12-14 16:53:30 +02001314/*** TSPP API functions ***/
Liron Kuch72b78552012-10-30 17:47:50 +02001315
1316/**
1317 * tspp_open_stream - open a TSPP stream for use.
1318 *
1319 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1320 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1321 * @source: stream source parameters.
1322 *
1323 * Return error status
1324 *
1325 */
1326int tspp_open_stream(u32 dev, u32 channel_id,
1327 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001328{
1329 u32 val;
1330 struct tspp_device *pdev;
Joel Nider435ad8e2011-12-14 16:53:30 +02001331 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001332
Hamad Kadmany92705b32012-10-23 14:15:41 +02001333 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1334 dev, channel_id, source->source, source->mode);
Liron Kuch72b78552012-10-30 17:47:50 +02001335
Joel Nider435ad8e2011-12-14 16:53:30 +02001336 if (dev >= TSPP_MAX_DEVICES) {
1337 pr_err("tspp: device id out of range");
1338 return -ENODEV;
1339 }
Joel Nider5556a852011-10-16 10:52:13 +02001340
Joel Nider435ad8e2011-12-14 16:53:30 +02001341 if (channel_id >= TSPP_NUM_CHANNELS) {
1342 pr_err("tspp: channel id out of range");
1343 return -ECHRNG;
1344 }
1345
1346 pdev = tspp_find_by_id(dev);
1347 if (!pdev) {
1348 pr_err("tspp_str: can't find device %i", dev);
1349 return -ENODEV;
1350 }
1351 channel = &pdev->channels[channel_id];
Hamad Kadmany92705b32012-10-23 14:15:41 +02001352 channel->src = source->source;
1353 tspp_set_tsif_mode(channel, source->mode);
1354 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch72b78552012-10-30 17:47:50 +02001355 source->data_inverse, source->sync_inverse,
1356 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001357
Hamad Kadmany92705b32012-10-23 14:15:41 +02001358 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001359 case TSPP_SOURCE_TSIF0:
Liron Kuch275c0b32013-02-10 15:19:32 +02001360 if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
1361 pr_err("tspp: error enabling tsif0 GPIOs\n");
1362 return -EBUSY;
1363 }
Joel Nider5556a852011-10-16 10:52:13 +02001364 /* make sure TSIF0 is running & enabled */
1365 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
1366 pr_err("tspp: error starting tsif0");
Joel Nider435ad8e2011-12-14 16:53:30 +02001367 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001368 }
Liron Kucha7b49ae2013-02-14 16:26:38 +02001369 if (pdev->tsif[0].ref_count == 1) {
1370 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1371 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1372 pdev->base + TSPP_CONTROL);
1373 wmb();
1374 }
Joel Nider5556a852011-10-16 10:52:13 +02001375 break;
1376 case TSPP_SOURCE_TSIF1:
Liron Kuch275c0b32013-02-10 15:19:32 +02001377 if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
1378 pr_err("tspp: error enabling tsif1 GPIOs\n");
1379 return -EBUSY;
1380 }
Joel Nider5556a852011-10-16 10:52:13 +02001381 /* make sure TSIF1 is running & enabled */
1382 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
1383 pr_err("tspp: error starting tsif1");
Joel Nider435ad8e2011-12-14 16:53:30 +02001384 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001385 }
Liron Kucha7b49ae2013-02-14 16:26:38 +02001386 if (pdev->tsif[1].ref_count == 1) {
1387 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1388 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1389 pdev->base + TSPP_CONTROL);
1390 wmb();
1391 }
Joel Nider5556a852011-10-16 10:52:13 +02001392 break;
1393 case TSPP_SOURCE_MEM:
1394 break;
1395 default:
Hamad Kadmany92705b32012-10-23 14:15:41 +02001396 pr_err("tspp: channel %i invalid source %i",
1397 channel->id, source->source);
Joel Nider435ad8e2011-12-14 16:53:30 +02001398 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001399 }
1400
Joel Nider5556a852011-10-16 10:52:13 +02001401 return 0;
1402}
1403EXPORT_SYMBOL(tspp_open_stream);
1404
Liron Kuch72b78552012-10-30 17:47:50 +02001405/**
1406 * tspp_close_stream - close a TSPP stream.
1407 *
1408 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1409 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1410 *
1411 * Return error status
1412 *
1413 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001414int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001415{
1416 u32 val;
Liron Kucha7b49ae2013-02-14 16:26:38 +02001417 u32 prev_ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001418 struct tspp_device *pdev;
Joel Nider435ad8e2011-12-14 16:53:30 +02001419 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001420
Joel Nider435ad8e2011-12-14 16:53:30 +02001421 if (channel_id >= TSPP_NUM_CHANNELS) {
1422 pr_err("tspp: channel id out of range");
1423 return -ECHRNG;
1424 }
1425 pdev = tspp_find_by_id(dev);
1426 if (!pdev) {
1427 pr_err("tspp_cs: can't find device %i", dev);
1428 return -EBUSY;
1429 }
1430 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001431
1432 switch (channel->src) {
1433 case TSPP_SOURCE_TSIF0:
Liron Kucha7b49ae2013-02-14 16:26:38 +02001434 prev_ref_count = pdev->tsif[0].ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001435 tspp_stop_tsif(&pdev->tsif[0]);
Liron Kuch275c0b32013-02-10 15:19:32 +02001436 if (tspp_config_gpios(pdev, channel->src, 0) != 0)
1437 pr_err("tspp: error disabling tsif0 GPIOs\n");
1438
Liron Kucha7b49ae2013-02-14 16:26:38 +02001439 if (prev_ref_count == 1) {
1440 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1441 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1442 pdev->base + TSPP_CONTROL);
1443 wmb();
1444 }
Joel Nider5556a852011-10-16 10:52:13 +02001445 break;
1446 case TSPP_SOURCE_TSIF1:
Liron Kucha7b49ae2013-02-14 16:26:38 +02001447 prev_ref_count = pdev->tsif[1].ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001448 tspp_stop_tsif(&pdev->tsif[1]);
Liron Kuch275c0b32013-02-10 15:19:32 +02001449 if (tspp_config_gpios(pdev, channel->src, 0) != 0)
1450 pr_err("tspp: error disabling tsif0 GPIOs\n");
1451
Liron Kucha7b49ae2013-02-14 16:26:38 +02001452 if (prev_ref_count == 1) {
1453 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1454 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1455 pdev->base + TSPP_CONTROL);
1456 wmb();
1457 }
Joel Nider5556a852011-10-16 10:52:13 +02001458 break;
1459 case TSPP_SOURCE_MEM:
1460 break;
1461 case TSPP_SOURCE_NONE:
1462 break;
1463 }
1464
Joel Nider435ad8e2011-12-14 16:53:30 +02001465 channel->src = TSPP_SOURCE_NONE;
Joel Nider5556a852011-10-16 10:52:13 +02001466 return 0;
1467}
1468EXPORT_SYMBOL(tspp_close_stream);
1469
Liron Kuch72b78552012-10-30 17:47:50 +02001470/**
1471 * tspp_open_channel - open a TSPP channel.
1472 *
1473 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1474 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1475 *
1476 * Return error status
1477 *
1478 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001479int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001480{
1481 int rc = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001482 struct sps_connect *config;
1483 struct sps_register_event *event;
1484 struct tspp_channel *channel;
1485 struct tspp_device *pdev;
1486
1487 if (channel_id >= TSPP_NUM_CHANNELS) {
1488 pr_err("tspp: channel id out of range");
1489 return -ECHRNG;
1490 }
1491 pdev = tspp_find_by_id(dev);
1492 if (!pdev) {
1493 pr_err("tspp_oc: can't find device %i", dev);
1494 return -ENODEV;
1495 }
1496 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001497
1498 if (channel->used) {
1499 pr_err("tspp channel already in use");
Joel Nider435ad8e2011-12-14 16:53:30 +02001500 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001501 }
1502
Joel Nider435ad8e2011-12-14 16:53:30 +02001503 config = &channel->config;
1504 event = &channel->event;
1505
1506 /* start the clocks if needed */
Liron Kuch59339922013-01-01 18:29:47 +02001507 if (tspp_channels_in_use(pdev) == 0) {
Liron Kuch605cc122013-02-21 14:25:57 +02001508 rc = tspp_clock_start(pdev);
1509 if (rc)
1510 return rc;
1511
Joel Nider435ad8e2011-12-14 16:53:30 +02001512 wake_lock(&pdev->wake_lock);
Liron Kuch59339922013-01-01 18:29:47 +02001513 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001514
Joel Nider5556a852011-10-16 10:52:13 +02001515 /* mark it as used */
1516 channel->used = 1;
1517
1518 /* start the bam */
1519 channel->pipe = sps_alloc_endpoint();
1520 if (channel->pipe == 0) {
1521 pr_err("tspp: error allocating endpoint");
1522 rc = -ENOMEM;
1523 goto err_sps_alloc;
1524 }
1525
1526 /* get default configuration */
1527 sps_get_config(channel->pipe, config);
1528
Joel Nider435ad8e2011-12-14 16:53:30 +02001529 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001530 config->destination = SPS_DEV_HANDLE_MEM;
1531 config->mode = SPS_MODE_SRC;
Joel Nider435ad8e2011-12-14 16:53:30 +02001532 config->options =
1533 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1534 SPS_O_STREAMING | /* streaming mode */
1535 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
Hamad Kadmany81cee052012-11-29 14:15:57 +02001536 SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
1537 SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001538 config->src_pipe_index = channel->id;
1539 config->desc.size =
Hamad Kadmany81cee052012-11-29 14:15:57 +02001540 TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
Joel Nider5556a852011-10-16 10:52:13 +02001541 config->desc.base = dma_alloc_coherent(NULL,
1542 config->desc.size,
1543 &config->desc.phys_base,
1544 GFP_KERNEL);
1545 if (config->desc.base == 0) {
1546 pr_err("tspp: error allocating sps descriptors");
1547 rc = -ENOMEM;
1548 goto err_desc_alloc;
1549 }
1550
1551 memset(config->desc.base, 0, config->desc.size);
1552
1553 rc = sps_connect(channel->pipe, config);
1554 if (rc) {
1555 pr_err("tspp: error connecting bam");
1556 goto err_connect;
1557 }
1558
1559 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider435ad8e2011-12-14 16:53:30 +02001560 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001561 event->callback = tspp_sps_complete_cb;
1562 event->xfer_done = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001563 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001564
1565 rc = sps_register_event(channel->pipe, event);
1566 if (rc) {
1567 pr_err("tspp: error registering event");
1568 goto err_event;
1569 }
1570
Hamad Kadmany81cee052012-11-29 14:15:57 +02001571 init_timer(&channel->expiration_timer);
1572 channel->expiration_timer.function = tspp_expiration_timer;
1573 channel->expiration_timer.data = (unsigned long)pdev;
1574 channel->expiration_timer.expires = 0xffffffffL;
1575
Joel Nider435ad8e2011-12-14 16:53:30 +02001576 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001577 if (rc < 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02001578 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001579 "Runtime PM: Unable to wake up tspp device, rc = %d",
1580 rc);
1581 }
Joel Nider5556a852011-10-16 10:52:13 +02001582 return 0;
1583
1584err_event:
1585 sps_disconnect(channel->pipe);
1586err_connect:
1587 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1588 config->desc.phys_base);
1589err_desc_alloc:
1590 sps_free_endpoint(channel->pipe);
1591err_sps_alloc:
1592 return rc;
1593}
1594EXPORT_SYMBOL(tspp_open_channel);
1595
Liron Kuch72b78552012-10-30 17:47:50 +02001596/**
1597 * tspp_close_channel - close a TSPP channel.
1598 *
1599 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1600 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1601 *
1602 * Return error status
1603 *
1604 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001605int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001606{
1607 int i;
1608 int id;
Liron Kuch4ed3bf62013-03-28 09:44:42 +02001609 int table_idx;
Joel Nider5556a852011-10-16 10:52:13 +02001610 u32 val;
Liron Kuche0acb412013-04-21 13:16:45 +03001611 unsigned long flags;
Joel Nider5556a852011-10-16 10:52:13 +02001612
Joel Nider435ad8e2011-12-14 16:53:30 +02001613 struct sps_connect *config;
1614 struct tspp_device *pdev;
1615 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02001616
1617 if (channel_id >= TSPP_NUM_CHANNELS) {
1618 pr_err("tspp: channel id out of range");
1619 return -ECHRNG;
1620 }
1621 pdev = tspp_find_by_id(dev);
1622 if (!pdev) {
1623 pr_err("tspp_close: can't find device %i", dev);
1624 return -ENODEV;
1625 }
1626 channel = &pdev->channels[channel_id];
1627
1628 /* if the channel is not used, we are done */
1629 if (!channel->used)
1630 return 0;
1631
Liron Kuche0acb412013-04-21 13:16:45 +03001632 /*
1633 * Need to protect access to used and waiting fields, as they are
1634 * used by the tasklet which is invoked from interrupt context
1635 */
1636 spin_lock_irqsave(&pdev->spinlock, flags);
1637 channel->used = 0;
1638 channel->waiting = NULL;
1639 spin_unlock_irqrestore(&pdev->spinlock, flags);
1640
Hamad Kadmany81cee052012-11-29 14:15:57 +02001641 if (channel->expiration_period_ms)
1642 del_timer(&channel->expiration_timer);
1643
Joel Nider435ad8e2011-12-14 16:53:30 +02001644 channel->notifier = NULL;
1645 channel->notify_data = NULL;
Hamad Kadmany81cee052012-11-29 14:15:57 +02001646 channel->expiration_period_ms = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001647
1648 config = &channel->config;
1649 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001650
1651 /* disable pipe (channel) */
1652 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1653 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1654 wmb();
1655
1656 /* unregister all filters for this channel */
Liron Kuch4ed3bf62013-03-28 09:44:42 +02001657 for (table_idx = 0; table_idx < TSPP_FILTER_TABLES; table_idx++) {
1658 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1659 struct tspp_pid_filter *filter =
1660 &pdev->filters[table_idx]->filter[i];
1661 id = FILTER_GET_PIPE_NUMBER0(filter);
1662 if (id == channel->id) {
1663 if (FILTER_HAS_ENCRYPTION(filter))
1664 tspp_free_key_entry(
1665 FILTER_GET_KEY_NUMBER(filter));
1666 filter->config = 0;
1667 filter->filter = 0;
1668 }
Joel Nider5556a852011-10-16 10:52:13 +02001669 }
1670 }
1671 channel->filter_count = 0;
1672
Joel Nider5556a852011-10-16 10:52:13 +02001673 /* disconnect the bam */
1674 if (sps_disconnect(channel->pipe) != 0)
1675 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1676
1677 /* destroy the buffers */
1678 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1679 config->desc.phys_base);
1680
Liron Kuch72b78552012-10-30 17:47:50 +02001681 tspp_destroy_buffers(channel_id, channel);
Hamad Kadmany090709b2013-01-06 12:08:13 +02001682 if (channel->dma_pool) {
1683 dma_pool_destroy(channel->dma_pool);
1684 channel->dma_pool = NULL;
1685 }
Liron Kuch72b78552012-10-30 17:47:50 +02001686
1687 channel->src = TSPP_SOURCE_NONE;
1688 channel->mode = TSPP_MODE_DISABLED;
1689 channel->memfree = NULL;
1690 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001691 channel->buffer_count = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001692 channel->data = NULL;
1693 channel->read = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001694 channel->locked = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001695
Liron Kuch59339922013-01-01 18:29:47 +02001696 if (tspp_channels_in_use(pdev) == 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02001697 wake_unlock(&pdev->wake_lock);
Liron Kuch59339922013-01-01 18:29:47 +02001698 tspp_clock_stop(pdev);
1699 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001700
Liron Kuch605cc122013-02-21 14:25:57 +02001701 pm_runtime_put(&pdev->pdev->dev);
1702
Joel Nider5556a852011-10-16 10:52:13 +02001703 return 0;
1704}
1705EXPORT_SYMBOL(tspp_close_channel);
1706
Liron Kuch72b78552012-10-30 17:47:50 +02001707/**
Hamad Kadmany6d2a9c72013-01-31 14:49:20 +02001708 * tspp_get_ref_clk_counter - return the TSIF clock reference (TCR) counter.
1709 *
1710 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1711 * @source: The TSIF source from which the counter should be read
1712 * @tcr_counter: the value of TCR counter
1713 *
1714 * Return error status
1715 *
1716 * TCR increments at a rate equal to 27 MHz/256 = 105.47 kHz.
1717 * If source is neither TSIF 0 or TSIF1 0 is returned.
1718 */
1719int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter)
1720{
1721 struct tspp_device *pdev;
1722 struct tspp_tsif_device *tsif_device;
1723
1724 if (!tcr_counter)
1725 return -EINVAL;
1726
1727 pdev = tspp_find_by_id(dev);
1728 if (!pdev) {
1729 pr_err("tspp_get_ref_clk_counter: can't find device %i\n", dev);
1730 return -ENODEV;
1731 }
1732
1733 switch (source) {
1734 case TSPP_SOURCE_TSIF0:
1735 tsif_device = &pdev->tsif[0];
1736 break;
1737
1738 case TSPP_SOURCE_TSIF1:
1739 tsif_device = &pdev->tsif[1];
1740 break;
1741
1742 default:
1743 tsif_device = NULL;
1744 break;
1745 }
1746
1747 if (tsif_device && tsif_device->ref_count)
1748 *tcr_counter = ioread32(tsif_device->base + TSIF_CLK_REF_OFF);
1749 else
1750 *tcr_counter = 0;
1751
1752 return 0;
1753}
1754EXPORT_SYMBOL(tspp_get_ref_clk_counter);
1755
1756/**
Liron Kuch72b78552012-10-30 17:47:50 +02001757 * tspp_add_filter - add a TSPP filter to a channel.
1758 *
1759 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1760 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1761 * @filter: TSPP filter parameters
1762 *
1763 * Return error status
1764 *
1765 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001766int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001767 struct tspp_filter *filter)
1768{
Liron Kuch72b78552012-10-30 17:47:50 +02001769 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001770 int other_channel;
1771 int entry;
1772 u32 val, pid, enabled;
Joel Nider435ad8e2011-12-14 16:53:30 +02001773 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001774 struct tspp_pid_filter p;
Joel Nider435ad8e2011-12-14 16:53:30 +02001775 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001776
Joel Nider435ad8e2011-12-14 16:53:30 +02001777 TSPP_DEBUG("tspp: add filter");
1778 if (channel_id >= TSPP_NUM_CHANNELS) {
1779 pr_err("tspp: channel id out of range");
1780 return -ECHRNG;
1781 }
1782 pdev = tspp_find_by_id(dev);
1783 if (!pdev) {
1784 pr_err("tspp_add: can't find device %i", dev);
1785 return -ENODEV;
1786 }
1787
1788 channel = &pdev->channels[channel_id];
1789
Joel Nider5556a852011-10-16 10:52:13 +02001790 if (filter->source > TSPP_SOURCE_MEM) {
1791 pr_err("tspp invalid source");
Joel Nider435ad8e2011-12-14 16:53:30 +02001792 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001793 }
1794
1795 if (filter->priority >= TSPP_NUM_PRIORITIES) {
1796 pr_err("tspp invalid source");
Joel Nider435ad8e2011-12-14 16:53:30 +02001797 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001798 }
1799
Liron Kuch72b78552012-10-30 17:47:50 +02001800 channel->mode = filter->mode;
1801 /*
1802 * if buffers are already allocated, verify they fulfil
1803 * the alignment requirements.
1804 */
1805 if ((channel->buffer_count > 0) &&
1806 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1807 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001808
1809 if (filter->mode == TSPP_MODE_PES) {
1810 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1811 struct tspp_pid_filter *tspp_filter =
Joel Nider435ad8e2011-12-14 16:53:30 +02001812 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001813 pid = FILTER_GET_PIPE_PID((tspp_filter));
1814 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1815 if (enabled && (pid == filter->pid)) {
1816 other_channel =
1817 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1818 pr_err("tspp: pid 0x%x already in use by channel %i",
1819 filter->pid, other_channel);
Joel Nider435ad8e2011-12-14 16:53:30 +02001820 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001821 }
1822 }
1823 }
1824
1825 /* make sure this priority is not already in use */
1826 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider435ad8e2011-12-14 16:53:30 +02001827 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001828 if (enabled) {
1829 pr_err("tspp: filter priority %i source %i is already enabled\n",
1830 filter->priority, channel->src);
Joel Nider435ad8e2011-12-14 16:53:30 +02001831 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001832 }
1833
1834 if (channel->mode == TSPP_MODE_PES) {
1835 /* if we are already processing in PES mode, disable pipe
1836 (channel) and filter to be updated */
1837 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1838 writel_relaxed(val | (1 << channel->id),
1839 pdev->base + TSPP_PS_DISABLE);
1840 wmb();
1841 }
1842
1843 /* update entry */
1844 p.filter = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001845 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001846 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1847 FILTER_SET_PIPE_PID((&p), filter->pid);
1848 FILTER_SET_PID_MASK((&p), filter->mask);
1849 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1850 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1851 if (filter->decrypt) {
1852 entry = tspp_get_key_entry();
1853 if (entry == -1) {
1854 pr_err("tspp: no more keys available!");
1855 } else {
1856 p.config |= FILTER_DECRYPT;
1857 FILTER_SET_KEY_NUMBER((&p), entry);
1858 }
1859 }
Joel Nider5556a852011-10-16 10:52:13 +02001860
Joel Nider435ad8e2011-12-14 16:53:30 +02001861 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001862 filter[filter->priority].config = p.config;
Joel Nider435ad8e2011-12-14 16:53:30 +02001863 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001864 filter[filter->priority].filter = p.filter;
1865
Liron Kuch72b78552012-10-30 17:47:50 +02001866 /*
1867 * allocate buffers if needed (i.e. if user did has not already called
1868 * tspp_allocate_buffers() explicitly).
1869 */
1870 if (channel->buffer_count == 0) {
1871 channel->buffer_size =
Hamad Kadmany090709b2013-01-06 12:08:13 +02001872 tspp_align_buffer_size_by_mode(channel->buffer_size,
Liron Kuch72b78552012-10-30 17:47:50 +02001873 channel->mode);
1874 rc = tspp_allocate_buffers(dev, channel->id,
1875 channel->max_buffers,
1876 channel->buffer_size,
1877 channel->int_freq, NULL, NULL, NULL);
1878 if (rc != 0) {
1879 pr_err("tspp: tspp_allocate_buffers failed\n");
1880 return rc;
1881 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001882 }
1883
Joel Nider5556a852011-10-16 10:52:13 +02001884 /* reenable pipe */
1885 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1886 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1887 wmb();
1888 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1889
Joel Nider5556a852011-10-16 10:52:13 +02001890 channel->filter_count++;
1891
1892 return 0;
1893}
1894EXPORT_SYMBOL(tspp_add_filter);
1895
Liron Kuch72b78552012-10-30 17:47:50 +02001896/**
1897 * tspp_remove_filter - remove a TSPP filter from a channel.
1898 *
1899 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1900 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1901 * @filter: TSPP filter parameters
1902 *
1903 * Return error status
1904 *
1905 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001906int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001907 struct tspp_filter *filter)
1908{
1909 int entry;
1910 u32 val;
Joel Nider435ad8e2011-12-14 16:53:30 +02001911 struct tspp_device *pdev;
1912 int src;
1913 struct tspp_pid_filter *tspp_filter;
1914 struct tspp_channel *channel;
1915
1916 if (channel_id >= TSPP_NUM_CHANNELS) {
1917 pr_err("tspp: channel id out of range");
1918 return -ECHRNG;
1919 }
1920 pdev = tspp_find_by_id(dev);
1921 if (!pdev) {
1922 pr_err("tspp_remove: can't find device %i", dev);
1923 return -ENODEV;
1924 }
1925 channel = &pdev->channels[channel_id];
1926
1927 src = channel->src;
1928 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02001929
1930 /* disable pipe (channel) */
1931 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1932 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1933 wmb();
1934
1935 /* update data keys */
1936 if (tspp_filter->config & FILTER_DECRYPT) {
1937 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
1938 tspp_free_key_entry(entry);
1939 }
1940
1941 /* update pid table */
1942 tspp_filter->config = 0;
1943 tspp_filter->filter = 0;
1944
1945 channel->filter_count--;
1946
1947 /* reenable pipe */
1948 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1949 writel_relaxed(val & ~(1 << channel->id),
1950 pdev->base + TSPP_PS_DISABLE);
1951 wmb();
1952 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1953
1954 return 0;
1955}
1956EXPORT_SYMBOL(tspp_remove_filter);
1957
Liron Kuch72b78552012-10-30 17:47:50 +02001958/**
1959 * tspp_set_key - set TSPP key in key table.
1960 *
1961 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1962 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1963 * @key: TSPP key parameters
1964 *
1965 * Return error status
1966 *
1967 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001968int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02001969{
1970 int i;
1971 int id;
1972 int key_index;
1973 int data;
Joel Nider435ad8e2011-12-14 16:53:30 +02001974 struct tspp_channel *channel;
1975 struct tspp_device *pdev;
1976
1977 if (channel_id >= TSPP_NUM_CHANNELS) {
1978 pr_err("tspp: channel id out of range");
1979 return -ECHRNG;
1980 }
1981 pdev = tspp_find_by_id(dev);
1982 if (!pdev) {
1983 pr_err("tspp_set: can't find device %i", dev);
1984 return -ENODEV;
1985 }
1986 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001987
1988 /* read the key index used by this channel */
1989 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1990 struct tspp_pid_filter *tspp_filter =
Joel Nider435ad8e2011-12-14 16:53:30 +02001991 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02001992 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1993 if (id == channel->id) {
1994 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
1995 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
1996 break;
1997 }
1998 }
1999 }
2000 if (i == TSPP_NUM_PRIORITIES) {
2001 pr_err("tspp: no encryption on this channel");
Joel Nider435ad8e2011-12-14 16:53:30 +02002002 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02002003 }
2004
2005 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002006 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
2007 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02002008 } else {
Joel Nider435ad8e2011-12-14 16:53:30 +02002009 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
2010 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02002011 }
2012 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
2013
2014 return 0;
2015}
2016EXPORT_SYMBOL(tspp_set_key);
2017
Liron Kuch72b78552012-10-30 17:47:50 +02002018/**
2019 * tspp_register_notification - register TSPP channel notification function.
2020 *
2021 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2022 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2023 * @pNotify: notification function
2024 * @userdata: user data to pass to notification function
2025 * @timer_ms: notification for partially filled buffers
2026 *
2027 * Return error status
2028 *
2029 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002030int tspp_register_notification(u32 dev, u32 channel_id,
2031 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02002032{
Joel Nider435ad8e2011-12-14 16:53:30 +02002033 struct tspp_channel *channel;
2034 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002035
Joel Nider435ad8e2011-12-14 16:53:30 +02002036 if (channel_id >= TSPP_NUM_CHANNELS) {
2037 pr_err("tspp: channel id out of range");
2038 return -ECHRNG;
2039 }
2040 pdev = tspp_find_by_id(dev);
2041 if (!pdev) {
2042 pr_err("tspp_reg: can't find device %i", dev);
2043 return -ENODEV;
2044 }
2045 channel = &pdev->channels[channel_id];
2046 channel->notifier = pNotify;
2047 channel->notify_data = userdata;
Hamad Kadmany81cee052012-11-29 14:15:57 +02002048 channel->expiration_period_ms = timer_ms;
2049
Joel Nider5556a852011-10-16 10:52:13 +02002050 return 0;
2051}
Joel Nider435ad8e2011-12-14 16:53:30 +02002052EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02002053
Liron Kuch72b78552012-10-30 17:47:50 +02002054/**
2055 * tspp_unregister_notification - unregister TSPP channel notification function.
2056 *
2057 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2058 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2059 *
2060 * Return error status
2061 *
2062 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002063int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002064{
Joel Nider435ad8e2011-12-14 16:53:30 +02002065 struct tspp_channel *channel;
2066 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002067
Joel Nider435ad8e2011-12-14 16:53:30 +02002068 if (channel_id >= TSPP_NUM_CHANNELS) {
2069 pr_err("tspp: channel id out of range");
2070 return -ECHRNG;
2071 }
2072 pdev = tspp_find_by_id(dev);
2073 if (!pdev) {
2074 pr_err("tspp_unreg: can't find device %i", dev);
2075 return -ENODEV;
2076 }
2077 channel = &pdev->channels[channel_id];
2078 channel->notifier = NULL;
2079 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02002080 return 0;
2081}
Joel Nider435ad8e2011-12-14 16:53:30 +02002082EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02002083
Liron Kuch72b78552012-10-30 17:47:50 +02002084/**
2085 * tspp_get_buffer - get TSPP data buffer.
2086 *
2087 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2088 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2089 *
2090 * Return error status
2091 *
2092 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002093const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002094{
Joel Nider435ad8e2011-12-14 16:53:30 +02002095 struct tspp_mem_buffer *buffer;
2096 struct tspp_channel *channel;
2097 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002098
Joel Nider435ad8e2011-12-14 16:53:30 +02002099 if (channel_id >= TSPP_NUM_CHANNELS) {
2100 pr_err("tspp: channel id out of range");
2101 return NULL;
2102 }
2103 pdev = tspp_find_by_id(dev);
2104 if (!pdev) {
2105 pr_err("tspp_get: can't find device %i", dev);
2106 return NULL;
2107 }
2108 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02002109
Joel Nider435ad8e2011-12-14 16:53:30 +02002110 if (!channel->read) {
2111 pr_warn("tspp: no buffer to get on channel %i!",
2112 channel->id);
2113 return NULL;
2114 }
2115
2116 buffer = channel->read;
2117 /* see if we have any buffers ready to read */
2118 if (buffer->state != TSPP_BUF_STATE_DATA)
2119 return 0;
2120
2121 if (buffer->state == TSPP_BUF_STATE_DATA) {
2122 /* mark the buffer as busy */
2123 buffer->state = TSPP_BUF_STATE_LOCKED;
2124
2125 /* increment the pointer along the list */
2126 channel->read = channel->read->next;
2127 }
2128
2129 return &buffer->desc;
2130}
2131EXPORT_SYMBOL(tspp_get_buffer);
2132
Liron Kuch72b78552012-10-30 17:47:50 +02002133/**
2134 * tspp_release_buffer - release TSPP data buffer back to TSPP.
2135 *
2136 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2137 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2138 * @descriptor_id: buffer descriptor ID
2139 *
2140 * Return error status
2141 *
2142 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002143int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
2144{
2145 int i, found = 0;
2146 struct tspp_mem_buffer *buffer;
2147 struct tspp_channel *channel;
2148 struct tspp_device *pdev;
2149
2150 if (channel_id >= TSPP_NUM_CHANNELS) {
2151 pr_err("tspp: channel id out of range");
2152 return -ECHRNG;
2153 }
2154 pdev = tspp_find_by_id(dev);
2155 if (!pdev) {
2156 pr_err("tspp: can't find device %i", dev);
2157 return -ENODEV;
2158 }
2159 channel = &pdev->channels[channel_id];
2160
2161 if (descriptor_id > channel->buffer_count)
2162 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
2163
2164 /* find the correct descriptor */
2165 buffer = channel->locked;
2166 for (i = 0; i < channel->buffer_count; i++) {
2167 if (buffer->desc.id == descriptor_id) {
2168 found = 1;
2169 break;
2170 }
2171 buffer = buffer->next;
2172 }
2173 channel->locked = channel->locked->next;
2174
2175 if (!found) {
2176 pr_err("tspp: cant find desc %i", descriptor_id);
2177 return -EINVAL;
2178 }
2179
2180 /* make sure the buffer is in the expected state */
2181 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
2182 pr_err("tspp: buffer %i not locked", descriptor_id);
2183 return -EINVAL;
2184 }
2185 /* unlock the buffer and requeue it */
2186 buffer->state = TSPP_BUF_STATE_WAITING;
2187
2188 if (tspp_queue_buffer(channel, buffer))
2189 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02002190 return 0;
2191}
Joel Nider435ad8e2011-12-14 16:53:30 +02002192EXPORT_SYMBOL(tspp_release_buffer);
2193
Liron Kuch72b78552012-10-30 17:47:50 +02002194/**
2195 * tspp_allocate_buffers - allocate TSPP data buffers.
2196 *
2197 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2198 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2199 * @count: number of buffers to allocate
2200 * @size: size of each buffer to allocate
2201 * @int_freq: interrupt frequency
2202 * @alloc: user defined memory allocator function. Pass NULL for default.
2203 * @memfree: user defined memory free function. Pass NULL for default.
2204 * @user: user data to pass to the memory allocator/free function
2205 *
2206 * Return error status
2207 *
2208 * The user can optionally call this function explicitly to allocate the TSPP
2209 * data buffers. Alternatively, if the user did not call this function, it
2210 * is called implicitly by tspp_add_filter().
2211 */
2212int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
2213 u32 int_freq, tspp_allocator *alloc,
2214 tspp_memfree *memfree, void *user)
Joel Nider435ad8e2011-12-14 16:53:30 +02002215{
2216 struct tspp_channel *channel;
2217 struct tspp_device *pdev;
2218 struct tspp_mem_buffer *last = NULL;
2219
2220 TSPP_DEBUG("tspp_allocate_buffers");
2221
2222 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch72b78552012-10-30 17:47:50 +02002223 pr_err("%s: channel id out of range", __func__);
Joel Nider435ad8e2011-12-14 16:53:30 +02002224 return -ECHRNG;
2225 }
Liron Kuch72b78552012-10-30 17:47:50 +02002226
Joel Nider435ad8e2011-12-14 16:53:30 +02002227 pdev = tspp_find_by_id(dev);
2228 if (!pdev) {
Liron Kuch72b78552012-10-30 17:47:50 +02002229 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider435ad8e2011-12-14 16:53:30 +02002230 return -ENODEV;
2231 }
Liron Kuch72b78552012-10-30 17:47:50 +02002232
2233 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
2234 pr_err("%s: tspp requires a minimum of %i buffers\n",
2235 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
2236 return -EINVAL;
2237 }
2238
Joel Nider435ad8e2011-12-14 16:53:30 +02002239 channel = &pdev->channels[channel_id];
Hamad Kadmany090709b2013-01-06 12:08:13 +02002240
Liron Kuch72b78552012-10-30 17:47:50 +02002241 /* allow buffer allocation only if there was no previous buffer
2242 * allocation for this channel.
2243 */
2244 if (channel->buffer_count > 0) {
2245 pr_err("%s: buffers already allocated for channel %u",
2246 __func__, channel_id);
2247 return -EINVAL;
2248 }
Joel Nider435ad8e2011-12-14 16:53:30 +02002249
2250 channel->max_buffers = count;
2251
2252 /* set up interrupt frequency */
Liron Kuch72b78552012-10-30 17:47:50 +02002253 if (int_freq > channel->max_buffers) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002254 int_freq = channel->max_buffers;
Liron Kuch72b78552012-10-30 17:47:50 +02002255 pr_warn("%s: setting interrupt frequency to %u\n",
2256 __func__, int_freq);
Joel Nider435ad8e2011-12-14 16:53:30 +02002257 }
Liron Kuch72b78552012-10-30 17:47:50 +02002258 channel->int_freq = int_freq;
2259 /*
2260 * it is the responsibility of the caller to tspp_allocate_buffers(),
2261 * whether it's the user or the driver, to make sure the size parameter
2262 * is compatible to the channel mode.
2263 */
2264 channel->buffer_size = size;
Joel Nider435ad8e2011-12-14 16:53:30 +02002265
Liron Kuch72b78552012-10-30 17:47:50 +02002266 /* save user defined memory free function for later use */
2267 channel->memfree = memfree;
2268 channel->user_info = user;
2269
Hamad Kadmany090709b2013-01-06 12:08:13 +02002270 /*
2271 * For small buffers, create a DMA pool so that memory
2272 * is not wasted through dma_alloc_coherent.
2273 */
2274 if (TSPP_USE_DMA_POOL(channel->buffer_size)) {
2275 channel->dma_pool = dma_pool_create("tspp",
2276 NULL, channel->buffer_size, 0, 0);
2277 if (!channel->dma_pool) {
2278 pr_err("%s: Can't allocate memory pool\n", __func__);
2279 return -ENOMEM;
2280 }
2281 } else {
2282 channel->dma_pool = NULL;
2283 }
2284
2285
Liron Kuch72b78552012-10-30 17:47:50 +02002286 for (channel->buffer_count = 0;
2287 channel->buffer_count < channel->max_buffers;
Joel Nider435ad8e2011-12-14 16:53:30 +02002288 channel->buffer_count++) {
2289
2290 /* allocate the descriptor */
2291 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2292 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2293 if (!desc) {
Liron Kuch72b78552012-10-30 17:47:50 +02002294 pr_warn("%s: Can't allocate desc %i",
2295 __func__, channel->buffer_count);
Joel Nider435ad8e2011-12-14 16:53:30 +02002296 break;
2297 }
2298
2299 desc->desc.id = channel->buffer_count;
2300 /* allocate the buffer */
2301 if (tspp_alloc_buffer(channel_id, &desc->desc,
Hamad Kadmany090709b2013-01-06 12:08:13 +02002302 channel->buffer_size, channel->dma_pool,
2303 alloc, user) != 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002304 kfree(desc);
Liron Kuch72b78552012-10-30 17:47:50 +02002305 pr_warn("%s: Can't allocate buffer %i",
2306 __func__, channel->buffer_count);
Joel Nider435ad8e2011-12-14 16:53:30 +02002307 break;
2308 }
2309
2310 /* add the descriptor to the list */
2311 desc->filled = 0;
2312 desc->read_index = 0;
2313 if (!channel->data) {
2314 channel->data = desc;
2315 desc->next = channel->data;
2316 } else {
2317 last->next = desc;
2318 }
2319 last = desc;
2320 desc->next = channel->data;
2321
2322 /* prepare the sps descriptor */
2323 desc->sps.phys_base = desc->desc.phys_base;
2324 desc->sps.base = desc->desc.virt_base;
2325 desc->sps.size = desc->desc.size;
2326
2327 /* start the transfer */
2328 if (tspp_queue_buffer(channel, desc))
Liron Kuch72b78552012-10-30 17:47:50 +02002329 pr_err("%s: can't queue buffer %i",
2330 __func__, desc->desc.id);
2331 }
2332
2333 if (channel->buffer_count < channel->max_buffers) {
2334 /*
2335 * we failed to allocate the requested number of buffers.
2336 * we don't allow a partial success, so need to clean up here.
2337 */
2338 tspp_destroy_buffers(channel_id, channel);
2339 channel->buffer_count = 0;
Hamad Kadmany090709b2013-01-06 12:08:13 +02002340
2341 if (channel->dma_pool) {
2342 dma_pool_destroy(channel->dma_pool);
2343 channel->dma_pool = NULL;
2344 }
Liron Kuch72b78552012-10-30 17:47:50 +02002345 return -ENOMEM;
Joel Nider435ad8e2011-12-14 16:53:30 +02002346 }
2347
2348 channel->waiting = channel->data;
2349 channel->read = channel->data;
2350 channel->locked = channel->data;
Liron Kuch72b78552012-10-30 17:47:50 +02002351
Hamad Kadmany81cee052012-11-29 14:15:57 +02002352 /* Now that buffers are scheduled to HW, kick data expiration timer */
2353 if (channel->expiration_period_ms)
2354 mod_timer(&channel->expiration_timer,
2355 jiffies +
2356 MSEC_TO_JIFFIES(
2357 channel->expiration_period_ms));
2358
Joel Nider435ad8e2011-12-14 16:53:30 +02002359 return 0;
2360}
2361EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002362
2363/*** File Operations ***/
2364static ssize_t tspp_open(struct inode *inode, struct file *filp)
2365{
Joel Nider435ad8e2011-12-14 16:53:30 +02002366 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002367 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002368
2369 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002370 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2371 filp->private_data = channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002372 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002373
2374 /* if this channel is already in use, quit */
2375 if (channel->used) {
2376 pr_err("tspp channel %i already in use",
2377 MINOR(channel->cdev.dev));
2378 return -EACCES;
2379 }
2380
Joel Nider435ad8e2011-12-14 16:53:30 +02002381 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002382 pr_err("tspp: error opening channel");
2383 return -EACCES;
2384 }
2385
2386 return 0;
2387}
2388
2389static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2390{
2391 unsigned long flags;
2392 unsigned int mask = 0;
2393 struct tspp_channel *channel;
2394 channel = filp->private_data;
2395
2396 /* register the wait queue for this channel */
2397 poll_wait(filp, &channel->in_queue, p);
2398
2399 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider435ad8e2011-12-14 16:53:30 +02002400 if (channel->read &&
2401 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002402 mask = POLLIN | POLLRDNORM;
2403
2404 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2405
2406 return mask;
2407}
2408
2409static ssize_t tspp_release(struct inode *inode, struct file *filp)
2410{
Joel Nider435ad8e2011-12-14 16:53:30 +02002411 struct tspp_channel *channel = filp->private_data;
2412 u32 dev = channel->pdev->pdev->id;
2413 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002414
Joel Nider435ad8e2011-12-14 16:53:30 +02002415 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002416
2417 return 0;
2418}
2419
2420static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2421 loff_t *f_pos)
2422{
2423 size_t size = 0;
2424 size_t transferred = 0;
2425 struct tspp_channel *channel;
2426 struct tspp_mem_buffer *buffer;
2427 channel = filp->private_data;
2428
2429 TSPP_DEBUG("tspp_read");
Joel Nider435ad8e2011-12-14 16:53:30 +02002430
2431 while (!channel->read) {
2432 if (filp->f_flags & O_NONBLOCK) {
2433 pr_warn("tspp: no buffer on channel %i!",
2434 channel->id);
2435 return -EAGAIN;
2436 }
2437 /* go to sleep if there is nothing to read */
2438 if (wait_event_interruptible(channel->in_queue,
2439 (channel->read != NULL))) {
2440 pr_err("tspp: rude awakening\n");
2441 return -ERESTARTSYS;
2442 }
2443 }
2444
2445 buffer = channel->read;
2446
Joel Nider5556a852011-10-16 10:52:13 +02002447 /* see if we have any buffers ready to read */
2448 while (buffer->state != TSPP_BUF_STATE_DATA) {
2449 if (filp->f_flags & O_NONBLOCK) {
2450 pr_warn("tspp: nothing to read on channel %i!",
2451 channel->id);
2452 return -EAGAIN;
2453 }
2454 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002455 if (wait_event_interruptible(channel->in_queue,
2456 (buffer->state == TSPP_BUF_STATE_DATA))) {
2457 pr_err("tspp: rude awakening\n");
2458 return -ERESTARTSYS;
2459 }
2460 }
2461
2462 while (buffer->state == TSPP_BUF_STATE_DATA) {
2463 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002464 if (size == 0)
2465 break;
2466
Joel Nider435ad8e2011-12-14 16:53:30 +02002467 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002468 buffer->read_index, size)) {
2469 pr_err("tspp: error copying to user buffer");
Joel Nider435ad8e2011-12-14 16:53:30 +02002470 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002471 }
2472 buf += size;
2473 count -= size;
2474 transferred += size;
2475 buffer->read_index += size;
2476
Liron Kuch72b78552012-10-30 17:47:50 +02002477 /*
2478 * after reading the end of the buffer, requeue it,
2479 * and set up for reading the next one
2480 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002481 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002482 buffer->state = TSPP_BUF_STATE_WAITING;
Hamad Kadmany090709b2013-01-06 12:08:13 +02002483
Joel Nider435ad8e2011-12-14 16:53:30 +02002484 if (tspp_queue_buffer(channel, buffer))
2485 pr_err("tspp: can't submit transfer");
Hamad Kadmany090709b2013-01-06 12:08:13 +02002486
Joel Nider435ad8e2011-12-14 16:53:30 +02002487 channel->locked = channel->read;
2488 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002489 }
2490 }
2491
2492 return transferred;
2493}
2494
2495static long tspp_ioctl(struct file *filp,
2496 unsigned int param0, unsigned long param1)
2497{
Joel Nider435ad8e2011-12-14 16:53:30 +02002498 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002499 int rc = -1;
2500 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002501 struct tspp_select_source ss;
2502 struct tspp_filter f;
2503 struct tspp_key k;
2504 struct tspp_iv iv;
2505 struct tspp_system_keys sk;
2506 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002507 channel = filp->private_data;
Joel Nider435ad8e2011-12-14 16:53:30 +02002508 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002509
Liron Kucha7b49ae2013-02-14 16:26:38 +02002510 if ((param0 != TSPP_IOCTL_CLOSE_STREAM) && !param1)
Joel Nider5556a852011-10-16 10:52:13 +02002511 return -EINVAL;
2512
2513 switch (param0) {
2514 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider435ad8e2011-12-14 16:53:30 +02002515 if (!access_ok(VERIFY_READ, param1,
2516 sizeof(struct tspp_select_source))) {
2517 return -EBUSY;
2518 }
2519 if (__copy_from_user(&ss, (void *)param1,
2520 sizeof(struct tspp_select_source)) == 0)
2521 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002522 break;
2523 case TSPP_IOCTL_ADD_FILTER:
Joel Nider435ad8e2011-12-14 16:53:30 +02002524 if (!access_ok(VERIFY_READ, param1,
2525 sizeof(struct tspp_filter))) {
2526 return -ENOSR;
2527 }
2528 if (__copy_from_user(&f, (void *)param1,
2529 sizeof(struct tspp_filter)) == 0)
2530 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002531 break;
2532 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider435ad8e2011-12-14 16:53:30 +02002533 if (!access_ok(VERIFY_READ, param1,
2534 sizeof(struct tspp_filter))) {
2535 return -EBUSY;
2536 }
2537 if (__copy_from_user(&f, (void *)param1,
2538 sizeof(struct tspp_filter)) == 0)
2539 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002540 break;
2541 case TSPP_IOCTL_SET_KEY:
Joel Nider435ad8e2011-12-14 16:53:30 +02002542 if (!access_ok(VERIFY_READ, param1,
2543 sizeof(struct tspp_key))) {
2544 return -EBUSY;
2545 }
2546 if (__copy_from_user(&k, (void *)param1,
2547 sizeof(struct tspp_key)) == 0)
2548 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002549 break;
2550 case TSPP_IOCTL_SET_IV:
Joel Nider435ad8e2011-12-14 16:53:30 +02002551 if (!access_ok(VERIFY_READ, param1,
2552 sizeof(struct tspp_iv))) {
2553 return -EBUSY;
2554 }
2555 if (__copy_from_user(&iv, (void *)param1,
2556 sizeof(struct tspp_iv)) == 0)
2557 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002558 break;
2559 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider435ad8e2011-12-14 16:53:30 +02002560 if (!access_ok(VERIFY_READ, param1,
2561 sizeof(struct tspp_system_keys))) {
2562 return -EINVAL;
2563 }
2564 if (__copy_from_user(&sk, (void *)param1,
2565 sizeof(struct tspp_system_keys)) == 0)
2566 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002567 break;
2568 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider435ad8e2011-12-14 16:53:30 +02002569 if (!access_ok(VERIFY_READ, param1,
2570 sizeof(struct tspp_buffer))) {
2571 rc = -EINVAL;
2572 }
2573 if (__copy_from_user(&b, (void *)param1,
2574 sizeof(struct tspp_buffer)) == 0)
2575 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002576 break;
Liron Kucha7b49ae2013-02-14 16:26:38 +02002577 case TSPP_IOCTL_CLOSE_STREAM:
2578 rc = tspp_close_stream(dev, channel->id);
2579 break;
Joel Nider5556a852011-10-16 10:52:13 +02002580 default:
2581 pr_err("tspp: Unknown ioctl %i", param0);
2582 }
2583
Liron Kuch72b78552012-10-30 17:47:50 +02002584 /*
2585 * normalize the return code in case one of the subfunctions does
2586 * something weird
2587 */
Joel Nider5556a852011-10-16 10:52:13 +02002588 if (rc != 0)
Joel Nider435ad8e2011-12-14 16:53:30 +02002589 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002590
2591 return rc;
2592}
2593
2594/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002595static int debugfs_iomem_x32_set(void *data, u64 val)
2596{
2597 writel_relaxed(val, data);
2598 wmb();
2599 return 0;
2600}
2601
2602static int debugfs_iomem_x32_get(void *data, u64 *val)
2603{
2604 *val = readl_relaxed(data);
2605 return 0;
2606}
2607
2608DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2609 debugfs_iomem_x32_set, "0x%08llx");
2610
2611static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2612 int instance)
2613{
2614 char name[10];
2615 snprintf(name, 10, "tsif%i", instance);
2616 tsif_device->dent_tsif = debugfs_create_dir(
2617 name, NULL);
2618 if (tsif_device->dent_tsif) {
2619 int i;
2620 void __iomem *base = tsif_device->base;
2621 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2622 tsif_device->debugfs_tsif_regs[i] =
2623 debugfs_create_file(
2624 debugfs_tsif_regs[i].name,
2625 debugfs_tsif_regs[i].mode,
2626 tsif_device->dent_tsif,
2627 base + debugfs_tsif_regs[i].offset,
2628 &fops_iomem_x32);
2629 }
Hamad Kadmany44307d32012-11-25 09:49:51 +02002630
2631 debugfs_create_u32(
2632 "stat_rx_chunks",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002633 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002634 tsif_device->dent_tsif,
2635 &tsif_device->stat_rx);
2636
2637 debugfs_create_u32(
2638 "stat_overflow",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002639 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002640 tsif_device->dent_tsif,
2641 &tsif_device->stat_overflow);
2642
2643 debugfs_create_u32(
2644 "stat_lost_sync",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002645 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002646 tsif_device->dent_tsif,
2647 &tsif_device->stat_lost_sync);
2648
2649 debugfs_create_u32(
2650 "stat_timeout",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002651 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002652 tsif_device->dent_tsif,
2653 &tsif_device->stat_timeout);
Joel Nider5556a852011-10-16 10:52:13 +02002654 }
2655}
2656
2657static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2658{
2659 if (tsif_device->dent_tsif) {
2660 int i;
2661 debugfs_remove_recursive(tsif_device->dent_tsif);
2662 tsif_device->dent_tsif = NULL;
2663 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2664 tsif_device->debugfs_tsif_regs[i] = NULL;
2665 }
2666}
2667
2668static void tspp_debugfs_init(struct tspp_device *device, int instance)
2669{
2670 char name[10];
2671 snprintf(name, 10, "tspp%i", instance);
2672 device->dent = debugfs_create_dir(
2673 name, NULL);
2674 if (device->dent) {
2675 int i;
2676 void __iomem *base = device->base;
2677 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2678 device->debugfs_regs[i] =
2679 debugfs_create_file(
2680 debugfs_tspp_regs[i].name,
2681 debugfs_tspp_regs[i].mode,
2682 device->dent,
2683 base + debugfs_tspp_regs[i].offset,
2684 &fops_iomem_x32);
2685 }
2686 }
2687}
2688
2689static void tspp_debugfs_exit(struct tspp_device *device)
2690{
2691 if (device->dent) {
2692 int i;
2693 debugfs_remove_recursive(device->dent);
2694 device->dent = NULL;
2695 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2696 device->debugfs_regs[i] = NULL;
2697 }
2698}
Joel Nider5556a852011-10-16 10:52:13 +02002699
Liron Kuch59339922013-01-01 18:29:47 +02002700/* copy device-tree data to platfrom data struct */
2701static __devinit struct msm_tspp_platform_data *
2702msm_tspp_dt_to_pdata(struct platform_device *pdev)
2703{
2704 struct device_node *node = pdev->dev.of_node;
2705 struct msm_tspp_platform_data *data;
2706 struct msm_gpio *gpios;
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07002707 struct property *prop;
Liron Kuch59339922013-01-01 18:29:47 +02002708 int i, rc;
2709 int gpio;
2710 u32 gpio_func;
2711
2712 /* Note: memory allocated by devm_kzalloc is freed automatically */
2713 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
2714 if (!data) {
2715 pr_err("tspp: Unable to allocate platform data\n");
2716 return NULL;
2717 }
2718 rc = of_property_read_string(node, "qcom,tsif-pclk", &data->tsif_pclk);
2719 if (rc) {
2720 pr_err("tspp: Could not find tsif-pclk property, err = %d\n",
2721 rc);
2722 return NULL;
2723 }
2724 rc = of_property_read_string(node, "qcom,tsif-ref-clk",
2725 &data->tsif_ref_clk);
2726 if (rc) {
2727 pr_err("tspp: Could not find tsif-ref-clk property, err = %d\n",
2728 rc);
2729 return NULL;
2730 }
2731
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07002732 data->tsif_vreg_present = 0;
2733 prop = of_find_property(node, "vdd_cx-supply", NULL);
2734 if (prop)
2735 data->tsif_vreg_present = 1;
2736
Liron Kuch59339922013-01-01 18:29:47 +02002737 data->num_gpios = of_gpio_count(node);
2738 if (data->num_gpios == 0) {
2739 pr_err("tspp: Could not find GPIO definitions\n");
2740 return NULL;
2741 }
2742 gpios = devm_kzalloc(&pdev->dev,
2743 (data->num_gpios * sizeof(struct msm_gpio)),
2744 GFP_KERNEL);
2745 if (!gpios) {
2746 pr_err("tspp: Unable to allocate memory for GPIOs table\n");
2747 return NULL;
2748 }
2749 /* Assuming GPIO FUNC property is the same for all GPIOs */
2750 if (of_property_read_u32(node, "qcom,gpios-func", &gpio_func)) {
2751 pr_err("tspp: Could not find gpios-func property\n");
2752 return NULL;
2753 }
2754 for (i = 0; i < data->num_gpios; i++) {
2755 gpio = of_get_gpio(node, i);
2756 gpios[i].gpio_cfg = GPIO_CFG(gpio, gpio_func,
2757 GPIO_CFG_INPUT,
2758 GPIO_CFG_PULL_DOWN,
2759 GPIO_CFG_2MA);
2760 rc = of_property_read_string_index(node, "qcom,gpio-names",
2761 i, &gpios[i].label);
2762 if (rc)
2763 pr_warn("tspp: Could not find gpio-names property\n");
2764 }
2765
2766 data->gpios = gpios;
2767
2768 return data;
2769}
2770
2771static int msm_tspp_map_irqs(struct platform_device *pdev,
2772 struct tspp_device *device)
2773{
2774 int rc;
2775 int i;
2776
2777 /* get IRQ numbers from platform information */
2778
2779 /* map TSPP IRQ */
2780 rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ");
2781 if (rc > 0) {
2782 device->tspp_irq = rc;
2783 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
2784 dev_name(&pdev->dev), device);
2785 if (rc) {
2786 dev_err(&pdev->dev,
2787 "failed to request TSPP IRQ %d : %d",
2788 device->tspp_irq, rc);
2789 device->tspp_irq = 0;
2790 return -EINVAL;
2791 }
2792 } else {
2793 dev_err(&pdev->dev, "failed to get TSPP IRQ");
2794 return -EINVAL;
2795 }
2796
2797 /* map TSIF IRQs */
2798 rc = platform_get_irq_byname(pdev, "TSIF0_IRQ");
2799 if (rc > 0) {
2800 device->tsif[0].tsif_irq = rc;
2801 } else {
2802 dev_err(&pdev->dev, "failed to get TSIF0 IRQ");
2803 return -EINVAL;
2804 }
2805
2806 rc = platform_get_irq_byname(pdev, "TSIF1_IRQ");
2807 if (rc > 0) {
2808 device->tsif[1].tsif_irq = rc;
2809 } else {
2810 dev_err(&pdev->dev, "failed to get TSIF1 IRQ");
2811 return -EINVAL;
2812 }
2813
2814 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
2815 rc = request_irq(device->tsif[i].tsif_irq,
2816 tsif_isr, IRQF_SHARED,
2817 dev_name(&pdev->dev), &device->tsif[i]);
2818 if (rc) {
2819 dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
2820 i, rc);
2821 device->tsif[i].tsif_irq = 0;
2822 }
2823 }
2824
2825 /* map BAM IRQ */
2826 rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ");
2827 if (rc > 0) {
2828 device->bam_irq = rc;
2829 } else {
2830 dev_err(&pdev->dev, "failed to get TSPP BAM IRQ");
2831 return -EINVAL;
2832 }
2833
2834 return 0;
2835}
2836
Joel Nider5556a852011-10-16 10:52:13 +02002837static int __devinit msm_tspp_probe(struct platform_device *pdev)
2838{
2839 int rc = -ENODEV;
2840 u32 version;
Liron Kuch72b78552012-10-30 17:47:50 +02002841 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002842 struct msm_tspp_platform_data *data;
2843 struct tspp_device *device;
2844 struct resource *mem_tsif0;
2845 struct resource *mem_tsif1;
2846 struct resource *mem_tspp;
2847 struct resource *mem_bam;
Liron Kuch72b78552012-10-30 17:47:50 +02002848 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002849
Liron Kuch59339922013-01-01 18:29:47 +02002850 if (pdev->dev.of_node) {
2851 /* get information from device tree */
2852 data = msm_tspp_dt_to_pdata(pdev);
2853 /* get device ID */
2854 rc = of_property_read_u32(pdev->dev.of_node,
2855 "cell-index", &pdev->id);
2856 if (rc)
2857 pdev->id = -1;
2858
2859 pdev->dev.platform_data = data;
2860 } else {
2861 /* must have platform data */
2862 data = pdev->dev.platform_data;
2863 }
Joel Nider5556a852011-10-16 10:52:13 +02002864 if (!data) {
2865 pr_err("tspp: Platform data not available");
2866 rc = -EINVAL;
2867 goto out;
2868 }
2869
2870 /* check for valid device id */
Joel Nider435ad8e2011-12-14 16:53:30 +02002871 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002872 pr_err("tspp: Invalid device ID %d", pdev->id);
2873 rc = -EINVAL;
2874 goto out;
2875 }
2876
2877 /* OK, we will use this device */
2878 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2879 if (!device) {
2880 pr_err("tspp: Failed to allocate memory for device");
2881 rc = -ENOMEM;
2882 goto out;
2883 }
2884
2885 /* set up references */
2886 device->pdev = pdev;
2887 platform_set_drvdata(pdev, device);
2888
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07002889 /* map regulators */
2890 if (data->tsif_vreg_present) {
2891 device->tsif_vreg = devm_regulator_get(&pdev->dev, "vdd_cx");
2892 if (IS_ERR(device->tsif_vreg)) {
2893 rc = PTR_ERR(device->tsif_vreg);
2894 device->tsif_vreg = NULL;
2895 goto err_regultaor;
2896 }
2897
2898 /* Set an initial voltage and enable the regulator */
2899 rc = regulator_set_voltage(device->tsif_vreg,
2900 RPM_REGULATOR_CORNER_SVS_SOC,
2901 RPM_REGULATOR_CORNER_SUPER_TURBO);
2902 if (rc) {
2903 dev_err(&pdev->dev, "Unable to set CX voltage.\n");
2904 goto err_regultaor;
2905 }
2906
2907 rc = regulator_enable(device->tsif_vreg);
2908 if (rc) {
2909 dev_err(&pdev->dev, "Unable to enable CX regulator.\n");
2910 goto err_regultaor;
2911 }
2912 }
2913
Joel Nider5556a852011-10-16 10:52:13 +02002914 /* map clocks */
2915 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002916 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02002917 if (IS_ERR(device->tsif_pclk)) {
Joel Nider5556a852011-10-16 10:52:13 +02002918 rc = PTR_ERR(device->tsif_pclk);
2919 device->tsif_pclk = NULL;
2920 goto err_pclock;
2921 }
2922 }
2923 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002924 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02002925 if (IS_ERR(device->tsif_ref_clk)) {
Joel Nider5556a852011-10-16 10:52:13 +02002926 rc = PTR_ERR(device->tsif_ref_clk);
2927 device->tsif_ref_clk = NULL;
2928 goto err_refclock;
2929 }
2930 }
2931
2932 /* map I/O memory */
Liron Kuch59339922013-01-01 18:29:47 +02002933 mem_tsif0 = platform_get_resource_byname(pdev,
2934 IORESOURCE_MEM, "MSM_TSIF0_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002935 if (!mem_tsif0) {
2936 pr_err("tspp: Missing tsif0 MEM resource");
2937 rc = -ENXIO;
2938 goto err_res_tsif0;
2939 }
2940 device->tsif[0].base = ioremap(mem_tsif0->start,
2941 resource_size(mem_tsif0));
2942 if (!device->tsif[0].base) {
2943 pr_err("tspp: ioremap failed");
2944 goto err_map_tsif0;
2945 }
2946
Liron Kuch59339922013-01-01 18:29:47 +02002947 mem_tsif1 = platform_get_resource_byname(pdev,
2948 IORESOURCE_MEM, "MSM_TSIF1_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002949 if (!mem_tsif1) {
2950 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
2951 rc = -ENXIO;
2952 goto err_res_tsif1;
2953 }
2954 device->tsif[1].base = ioremap(mem_tsif1->start,
2955 resource_size(mem_tsif1));
2956 if (!device->tsif[1].base) {
2957 dev_err(&pdev->dev, "ioremap failed");
2958 goto err_map_tsif1;
2959 }
2960
Liron Kuch59339922013-01-01 18:29:47 +02002961 mem_tspp = platform_get_resource_byname(pdev,
2962 IORESOURCE_MEM, "MSM_TSPP_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002963 if (!mem_tspp) {
2964 dev_err(&pdev->dev, "Missing MEM resource");
2965 rc = -ENXIO;
2966 goto err_res_dev;
2967 }
2968 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
2969 if (!device->base) {
2970 dev_err(&pdev->dev, "ioremap failed");
2971 goto err_map_dev;
2972 }
2973
Liron Kuch59339922013-01-01 18:29:47 +02002974 mem_bam = platform_get_resource_byname(pdev,
2975 IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02002976 if (!mem_bam) {
2977 pr_err("tspp: Missing bam MEM resource");
2978 rc = -ENXIO;
2979 goto err_res_bam;
2980 }
2981 memset(&device->bam_props, 0, sizeof(device->bam_props));
2982 device->bam_props.phys_addr = mem_bam->start;
2983 device->bam_props.virt_addr = ioremap(mem_bam->start,
2984 resource_size(mem_bam));
2985 if (!device->bam_props.virt_addr) {
2986 dev_err(&pdev->dev, "ioremap failed");
2987 goto err_map_bam;
2988 }
2989
Liron Kuch59339922013-01-01 18:29:47 +02002990 if (msm_tspp_map_irqs(pdev, device))
Joel Nider5556a852011-10-16 10:52:13 +02002991 goto err_irq;
Joel Nider5556a852011-10-16 10:52:13 +02002992
Joel Nider5556a852011-10-16 10:52:13 +02002993 /* power management */
2994 pm_runtime_set_active(&pdev->dev);
2995 pm_runtime_enable(&pdev->dev);
2996
Joel Nider5556a852011-10-16 10:52:13 +02002997 tspp_debugfs_init(device, 0);
2998
2999 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3000 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02003001
3002 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
3003 dev_name(&pdev->dev));
3004
3005 /* set up pointers to ram-based 'registers' */
Joel Nider435ad8e2011-12-14 16:53:30 +02003006 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
3007 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
3008 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
3009 device->tspp_key_table = device->base + TSPP_DATA_KEY;
3010 device->tspp_global_performance =
3011 device->base + TSPP_GLOBAL_PERFORMANCE;
3012 device->tspp_pipe_context =
3013 device->base + TSPP_PIPE_CONTEXT;
3014 device->tspp_pipe_performance =
3015 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02003016
3017 device->bam_props.summing_threshold = 0x10;
3018 device->bam_props.irq = device->bam_irq;
3019 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
3020
Liron Kuch59339922013-01-01 18:29:47 +02003021 if (tspp_clock_start(device) != 0) {
3022 dev_err(&pdev->dev, "Can't start clocks");
3023 goto err_clock;
3024 }
3025
Joel Nider5556a852011-10-16 10:52:13 +02003026 if (sps_register_bam_device(&device->bam_props,
3027 &device->bam_handle) != 0) {
3028 pr_err("tspp: failed to register bam");
3029 goto err_bam;
3030 }
3031
Joel Nider5556a852011-10-16 10:52:13 +02003032 spin_lock_init(&device->spinlock);
3033 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
3034 (unsigned long)device);
3035
3036 /* initialize everything to a known state */
3037 tspp_global_reset(device);
3038
3039 version = readl_relaxed(device->base + TSPP_VERSION);
Liron Kuch59339922013-01-01 18:29:47 +02003040 /*
3041 * TSPP version can be bits [7:0] or alternatively,
3042 * TSPP major version is bits [31:28].
3043 */
3044 if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1))
Joel Nider5556a852011-10-16 10:52:13 +02003045 pr_warn("tspp: unrecognized hw version=%i", version);
3046
Joel Nider435ad8e2011-12-14 16:53:30 +02003047 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02003048 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider435ad8e2011-12-14 16:53:30 +02003049 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
3050 pr_err("tspp_channel_init failed");
3051 goto err_channel;
3052 }
Joel Nider5556a852011-10-16 10:52:13 +02003053 }
3054
Joel Nider435ad8e2011-12-14 16:53:30 +02003055 /* stop the clocks for power savings */
3056 tspp_clock_stop(device);
3057
3058 /* everything is ok, so add the device to the list */
3059 list_add_tail(&(device->devlist), &tspp_devices);
3060
Joel Nider5556a852011-10-16 10:52:13 +02003061 return 0;
3062
Joel Nider435ad8e2011-12-14 16:53:30 +02003063err_channel:
Liron Kuch59339922013-01-01 18:29:47 +02003064 /* un-initialize channels */
Liron Kuch72b78552012-10-30 17:47:50 +02003065 for (j = 0; j < i; j++) {
3066 channel = &(device->channels[i]);
3067 device_destroy(tspp_class, channel->cdev.dev);
3068 cdev_del(&channel->cdev);
3069 }
Liron Kuch59339922013-01-01 18:29:47 +02003070
Joel Nider5556a852011-10-16 10:52:13 +02003071 sps_deregister_bam_device(device->bam_handle);
Liron Kuch59339922013-01-01 18:29:47 +02003072err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02003073err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02003074 tspp_debugfs_exit(device);
3075 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3076 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02003077err_irq:
Liron Kuch59339922013-01-01 18:29:47 +02003078 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
3079 if (device->tsif[i].tsif_irq)
3080 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
3081 }
3082 if (device->tspp_irq)
3083 free_irq(device->tspp_irq, device);
3084
Joel Nider5556a852011-10-16 10:52:13 +02003085 iounmap(device->bam_props.virt_addr);
3086err_map_bam:
3087err_res_bam:
3088 iounmap(device->base);
3089err_map_dev:
3090err_res_dev:
3091 iounmap(device->tsif[1].base);
3092err_map_tsif1:
3093err_res_tsif1:
3094 iounmap(device->tsif[0].base);
3095err_map_tsif0:
3096err_res_tsif0:
3097 if (device->tsif_ref_clk)
3098 clk_put(device->tsif_ref_clk);
3099err_refclock:
3100 if (device->tsif_pclk)
3101 clk_put(device->tsif_pclk);
3102err_pclock:
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07003103 if (device->tsif_vreg)
3104 regulator_disable(device->tsif_vreg);
3105err_regultaor:
Joel Nider5556a852011-10-16 10:52:13 +02003106 kfree(device);
3107
3108out:
3109 return rc;
3110}
3111
3112static int __devexit msm_tspp_remove(struct platform_device *pdev)
3113{
Joel Nider435ad8e2011-12-14 16:53:30 +02003114 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02003115 u32 i;
Liron Kuch605cc122013-02-21 14:25:57 +02003116 int rc;
Joel Nider5556a852011-10-16 10:52:13 +02003117
3118 struct tspp_device *device = platform_get_drvdata(pdev);
3119
Joel Nider435ad8e2011-12-14 16:53:30 +02003120 /* free the buffers, and delete the channels */
3121 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
3122 channel = &device->channels[i];
3123 tspp_close_channel(device->pdev->id, i);
3124 device_destroy(tspp_class, channel->cdev.dev);
3125 cdev_del(&channel->cdev);
3126 }
3127
Liron Kuch59339922013-01-01 18:29:47 +02003128 /* de-registering BAM device requires clocks */
Liron Kuch605cc122013-02-21 14:25:57 +02003129 rc = tspp_clock_start(device);
3130 if (rc == 0) {
3131 sps_deregister_bam_device(device->bam_handle);
3132 tspp_clock_stop(device);
3133 }
Joel Nider5556a852011-10-16 10:52:13 +02003134
Hamad Kadmany44307d32012-11-25 09:49:51 +02003135 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
Joel Nider5556a852011-10-16 10:52:13 +02003136 tsif_debugfs_exit(&device->tsif[i]);
Hamad Kadmany44307d32012-11-25 09:49:51 +02003137 if (device->tsif[i].tsif_irq)
3138 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
3139 }
Joel Nider5556a852011-10-16 10:52:13 +02003140
3141 wake_lock_destroy(&device->wake_lock);
3142 free_irq(device->tspp_irq, device);
Joel Nider5556a852011-10-16 10:52:13 +02003143
3144 iounmap(device->bam_props.virt_addr);
3145 iounmap(device->base);
3146 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3147 iounmap(device->tsif[i].base);
3148
3149 if (device->tsif_ref_clk)
3150 clk_put(device->tsif_ref_clk);
3151
3152 if (device->tsif_pclk)
3153 clk_put(device->tsif_pclk);
3154
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07003155 if (device->tsif_vreg)
3156 regulator_disable(device->tsif_vreg);
3157
Joel Nider5556a852011-10-16 10:52:13 +02003158 pm_runtime_disable(&pdev->dev);
Liron Kuch605cc122013-02-21 14:25:57 +02003159
Joel Nider5556a852011-10-16 10:52:13 +02003160 kfree(device);
3161
3162 return 0;
3163}
3164
3165/*** power management ***/
3166
3167static int tspp_runtime_suspend(struct device *dev)
3168{
3169 dev_dbg(dev, "pm_runtime: suspending...");
3170 return 0;
3171}
3172
3173static int tspp_runtime_resume(struct device *dev)
3174{
3175 dev_dbg(dev, "pm_runtime: resuming...");
3176 return 0;
3177}
3178
3179static const struct dev_pm_ops tspp_dev_pm_ops = {
3180 .runtime_suspend = tspp_runtime_suspend,
3181 .runtime_resume = tspp_runtime_resume,
3182};
3183
Liron Kuch59339922013-01-01 18:29:47 +02003184static struct of_device_id msm_match_table[] = {
3185 {.compatible = "qcom,msm_tspp"},
3186 {}
3187};
3188
Joel Nider5556a852011-10-16 10:52:13 +02003189static struct platform_driver msm_tspp_driver = {
3190 .probe = msm_tspp_probe,
3191 .remove = __exit_p(msm_tspp_remove),
3192 .driver = {
3193 .name = "msm_tspp",
3194 .pm = &tspp_dev_pm_ops,
Liron Kuch59339922013-01-01 18:29:47 +02003195 .of_match_table = msm_match_table,
Joel Nider5556a852011-10-16 10:52:13 +02003196 },
3197};
3198
3199
3200static int __init mod_init(void)
3201{
Joel Nider5556a852011-10-16 10:52:13 +02003202 int rc;
3203
Joel Nider435ad8e2011-12-14 16:53:30 +02003204 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02003205 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
3206 if (rc) {
3207 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
3208 goto err_devrgn;
3209 }
3210
3211 tspp_class = class_create(THIS_MODULE, "tspp");
3212 if (IS_ERR(tspp_class)) {
3213 rc = PTR_ERR(tspp_class);
3214 pr_err("tspp: Error creating class: %d", rc);
3215 goto err_class;
3216 }
3217
Joel Nider435ad8e2011-12-14 16:53:30 +02003218 /* register the driver, and check hardware */
3219 rc = platform_driver_register(&msm_tspp_driver);
3220 if (rc) {
3221 pr_err("tspp: platform_driver_register failed: %d", rc);
3222 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02003223 }
3224
3225 return 0;
3226
Joel Nider435ad8e2011-12-14 16:53:30 +02003227err_register:
3228 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02003229err_class:
3230 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
3231err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02003232 return rc;
3233}
3234
3235static void __exit mod_exit(void)
3236{
Joel Nider435ad8e2011-12-14 16:53:30 +02003237 /* delete low level driver */
3238 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02003239
Joel Nider435ad8e2011-12-14 16:53:30 +02003240 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02003241 class_destroy(tspp_class);
3242 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02003243}
3244
3245module_init(mod_init);
3246module_exit(mod_exit);
3247
Joel Nider435ad8e2011-12-14 16:53:30 +02003248MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02003249MODULE_LICENSE("GPL v2");