blob: 3b678c528b1909d7462e6a2bbe8aca9c653069af [file] [log] [blame]
Joel Niderb9662ca2012-06-10 14:21:11 +03001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Joel Nider5556a852011-10-16 10:52:13 +02002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Joel Nider5bd73f82011-12-14 16:53:30 +020013#include <linux/module.h> /* Just for modules */
14#include <linux/kernel.h> /* Only for KERN_INFO */
15#include <linux/err.h> /* Error macros */
16#include <linux/list.h> /* Linked list */
Joel Nider5556a852011-10-16 10:52:13 +020017#include <linux/cdev.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020018#include <linux/init.h> /* Needed for the macros */
19#include <linux/io.h> /* IO macros */
20#include <linux/device.h> /* Device drivers need this */
21#include <linux/sched.h> /* Externally defined globals */
22#include <linux/pm_runtime.h> /* Runtime power management */
Joel Nider5556a852011-10-16 10:52:13 +020023#include <linux/fs.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020024#include <linux/uaccess.h> /* copy_to_user */
Joel Nider5556a852011-10-16 10:52:13 +020025#include <linux/slab.h> /* kfree, kzalloc */
Joel Nider5bd73f82011-12-14 16:53:30 +020026#include <linux/ioport.h> /* XXX_ mem_region */
27#include <linux/dma-mapping.h> /* dma_XXX */
28#include <linux/delay.h> /* msleep */
29#include <linux/platform_device.h>
Joel Nider5556a852011-10-16 10:52:13 +020030#include <linux/clk.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020031#include <linux/poll.h> /* poll() file op */
32#include <linux/wait.h> /* wait() macros, sleeping */
33#include <linux/tspp.h> /* tspp functions */
Joel Nider5556a852011-10-16 10:52:13 +020034#include <linux/bitops.h> /* BIT() macro */
Joel Nider5bd73f82011-12-14 16:53:30 +020035#include <mach/sps.h> /* BAM stuff */
Joel Nider5556a852011-10-16 10:52:13 +020036#include <mach/gpio.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020037#include <linux/wakelock.h> /* Locking functions */
Joel Nider5556a852011-10-16 10:52:13 +020038#include <mach/dma.h>
39#include <mach/msm_tspp.h>
Joel Nider5556a852011-10-16 10:52:13 +020040#include <linux/debugfs.h>
Joel Nider5556a852011-10-16 10:52:13 +020041
42/*
43 * General defines
44 */
Joel Nider5556a852011-10-16 10:52:13 +020045#define TSPP_TSIF_INSTANCES 2
46#define TSPP_FILTER_TABLES 3
Joel Nider5bd73f82011-12-14 16:53:30 +020047#define TSPP_MAX_DEVICES 1
Joel Nider5556a852011-10-16 10:52:13 +020048#define TSPP_NUM_CHANNELS 16
49#define TSPP_NUM_PRIORITIES 16
50#define TSPP_NUM_KEYS 8
51#define INVALID_CHANNEL 0xFFFFFFFF
Joel Nider5bd73f82011-12-14 16:53:30 +020052#define TSPP_SPS_DESCRIPTOR_COUNT 128
Joel Nider5556a852011-10-16 10:52:13 +020053#define TSPP_PACKET_LENGTH 188
54#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
Joel Nider5bd73f82011-12-14 16:53:30 +020055#define TSPP_MAX_BUFFER_SIZE (32 * 1024)
56#define TSPP_NUM_BUFFERS 64
Joel Nider5556a852011-10-16 10:52:13 +020057#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
58#define SPS_DESCRIPTOR_SIZE 8
59#define MIN_ACCEPTABLE_BUFFER_COUNT 2
Joel Nider5bd73f82011-12-14 16:53:30 +020060#define TSPP_DEBUG(msg...)
Joel Nider5556a852011-10-16 10:52:13 +020061
62/*
63 * TSIF register offsets
64 */
65#define TSIF_STS_CTL_OFF (0x0)
66#define TSIF_TIME_LIMIT_OFF (0x4)
67#define TSIF_CLK_REF_OFF (0x8)
68#define TSIF_LPBK_FLAGS_OFF (0xc)
69#define TSIF_LPBK_DATA_OFF (0x10)
70#define TSIF_TEST_CTL_OFF (0x14)
71#define TSIF_TEST_MODE_OFF (0x18)
72#define TSIF_TEST_RESET_OFF (0x1c)
73#define TSIF_TEST_EXPORT_OFF (0x20)
74#define TSIF_TEST_CURRENT_OFF (0x24)
75
76#define TSIF_DATA_PORT_OFF (0x100)
77
78/* bits for TSIF_STS_CTL register */
79#define TSIF_STS_CTL_EN_IRQ BIT(28)
80#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
81#define TSIF_STS_CTL_1ST_PACKET BIT(26)
82#define TSIF_STS_CTL_OVERFLOW BIT(25)
83#define TSIF_STS_CTL_LOST_SYNC BIT(24)
84#define TSIF_STS_CTL_TIMEOUT BIT(23)
85#define TSIF_STS_CTL_INV_SYNC BIT(21)
86#define TSIF_STS_CTL_INV_NULL BIT(20)
87#define TSIF_STS_CTL_INV_ERROR BIT(19)
88#define TSIF_STS_CTL_INV_ENABLE BIT(18)
89#define TSIF_STS_CTL_INV_DATA BIT(17)
90#define TSIF_STS_CTL_INV_CLOCK BIT(16)
91#define TSIF_STS_CTL_SPARE BIT(15)
92#define TSIF_STS_CTL_EN_NULL BIT(11)
93#define TSIF_STS_CTL_EN_ERROR BIT(10)
94#define TSIF_STS_CTL_LAST_BIT BIT(9)
95#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
96#define TSIF_STS_CTL_EN_TCR BIT(7)
97#define TSIF_STS_CTL_TEST_MODE BIT(6)
Joel Nider5bd73f82011-12-14 16:53:30 +020098#define TSIF_STS_CTL_MODE_2 BIT(5)
Joel Nider5556a852011-10-16 10:52:13 +020099#define TSIF_STS_CTL_EN_DM BIT(4)
100#define TSIF_STS_CTL_STOP BIT(3)
101#define TSIF_STS_CTL_START BIT(0)
102
103/*
104 * TSPP register offsets
105 */
Liron Kuch229090d2012-10-30 17:47:50 +0200106#define TSPP_RST 0x00
Joel Nider5556a852011-10-16 10:52:13 +0200107#define TSPP_CLK_CONTROL 0x04
Liron Kuch229090d2012-10-30 17:47:50 +0200108#define TSPP_CONFIG 0x08
109#define TSPP_CONTROL 0x0C
Joel Nider5556a852011-10-16 10:52:13 +0200110#define TSPP_PS_DISABLE 0x10
Liron Kuch229090d2012-10-30 17:47:50 +0200111#define TSPP_MSG_IRQ_STATUS 0x14
Joel Nider5556a852011-10-16 10:52:13 +0200112#define TSPP_MSG_IRQ_MASK 0x18
113#define TSPP_IRQ_STATUS 0x1C
114#define TSPP_IRQ_MASK 0x20
115#define TSPP_IRQ_CLEAR 0x24
116#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2))
Liron Kuch229090d2012-10-30 17:47:50 +0200117#define TSPP_STATUS 0x68
118#define TSPP_CURR_TSP_HEADER 0x6C
119#define TSPP_CURR_PID_FILTER 0x70
120#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2))
121#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2))
122#define TSPP_DATA_KEY_RESET 0x9C
Joel Nider5556a852011-10-16 10:52:13 +0200123#define TSPP_KEY_VALID 0xA0
124#define TSPP_KEY_ERROR 0xA4
125#define TSPP_TEST_CTRL 0xA8
Liron Kuch229090d2012-10-30 17:47:50 +0200126#define TSPP_VERSION 0xAC
Joel Nider5556a852011-10-16 10:52:13 +0200127#define TSPP_GENERICS 0xB0
Liron Kuch229090d2012-10-30 17:47:50 +0200128#define TSPP_NOP 0xB4
Joel Nider5556a852011-10-16 10:52:13 +0200129
130/*
131 * Register bit definitions
132 */
133/* TSPP_RST */
134#define TSPP_RST_RESET BIT(0)
135
136/* TSPP_CLK_CONTROL */
137#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9)
138#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8)
139#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7)
140#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6)
141#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5)
142#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
143#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3)
144#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
145#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
146#define TSPP_CLK_CONTROL_SET_CLKON BIT(0)
147
148/* TSPP_CONFIG */
149#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
150((_b & 0xF) << 8))
151#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
152#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7)
153#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6)
154#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5)
155#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
156#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3)
157#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2)
158#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1)
159#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0)
160
161/* TSPP_CONTROL */
162#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5)
163#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4)
164#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3)
165#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2)
166#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1)
167#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0)
168
169/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
170#define TSPP_MSG_TSPP_IRQ BIT(2)
171#define TSPP_MSG_TSIF_1_IRQ BIT(1)
172#define TSPP_MSG_TSIF_0_IRQ BIT(0)
173
174/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
Liron Kuch229090d2012-10-30 17:47:50 +0200175#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19)
176#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18)
Joel Nider5556a852011-10-16 10:52:13 +0200177#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17)
178#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16)
179#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n))
180
181/* TSPP_PIPE_ERROR_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200182#define TSPP_PIPE_PES_SYNC_ERROR BIT(3)
183#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2)
Joel Nider5556a852011-10-16 10:52:13 +0200184#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1)
Liron Kuch229090d2012-10-30 17:47:50 +0200185#define TSPP_PIP_PS_LOST_START BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200186
187/* TSPP_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200188#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10)
189#define TSPP_STATUS_TSIF1_DM_REQ BIT(6)
190#define TSPP_STATUS_TSIF0_DM_REQ BIT(2)
191#define TSPP_CURR_FILTER_TABLE BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200192
193/* TSPP_GENERICS */
Liron Kuch229090d2012-10-30 17:47:50 +0200194#define TSPP_GENERICS_CRYPTO_GEN BIT(12)
Joel Nider5556a852011-10-16 10:52:13 +0200195#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7)
Liron Kuch229090d2012-10-30 17:47:50 +0200196#define TSPP_GENERICS_MAX_PIPES BIT(2)
197#define TSPP_GENERICS_TSIF_1_GEN BIT(1)
198#define TSPP_GENERICS_TSIF_0_GEN BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200199
200/*
201 * TSPP memory regions
202 */
203#define TSPP_PID_FILTER_TABLE0 0x800
204#define TSPP_PID_FILTER_TABLE1 0x880
205#define TSPP_PID_FILTER_TABLE2 0x900
206#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */
207#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */
208#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */
209#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
210#define TSPP_DATA_KEY 0xCD0
211
Joel Nider5556a852011-10-16 10:52:13 +0200212struct debugfs_entry {
213 const char *name;
214 mode_t mode;
215 int offset;
216};
217
218static const struct debugfs_entry debugfs_tsif_regs[] = {
219 {"sts_ctl", S_IRUGO | S_IWUSR, TSIF_STS_CTL_OFF},
220 {"time_limit", S_IRUGO | S_IWUSR, TSIF_TIME_LIMIT_OFF},
221 {"clk_ref", S_IRUGO | S_IWUSR, TSIF_CLK_REF_OFF},
222 {"lpbk_flags", S_IRUGO | S_IWUSR, TSIF_LPBK_FLAGS_OFF},
223 {"lpbk_data", S_IRUGO | S_IWUSR, TSIF_LPBK_DATA_OFF},
224 {"test_ctl", S_IRUGO | S_IWUSR, TSIF_TEST_CTL_OFF},
225 {"test_mode", S_IRUGO | S_IWUSR, TSIF_TEST_MODE_OFF},
226 {"test_reset", S_IWUSR, TSIF_TEST_RESET_OFF},
227 {"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
228 {"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
229 {"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
230};
231
232static const struct debugfs_entry debugfs_tspp_regs[] = {
233 {"rst", S_IRUGO | S_IWUSR, TSPP_RST},
234 {"clk_control", S_IRUGO | S_IWUSR, TSPP_CLK_CONTROL},
235 {"config", S_IRUGO | S_IWUSR, TSPP_CONFIG},
236 {"control", S_IRUGO | S_IWUSR, TSPP_CONTROL},
237 {"ps_disable", S_IRUGO | S_IWUSR, TSPP_PS_DISABLE},
238 {"msg_irq_status", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_STATUS},
239 {"msg_irq_mask", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_MASK},
240 {"irq_status", S_IRUGO | S_IWUSR, TSPP_IRQ_STATUS},
241 {"irq_mask", S_IRUGO | S_IWUSR, TSPP_IRQ_MASK},
242 {"irq_clear", S_IRUGO | S_IWUSR, TSPP_IRQ_CLEAR},
243 /* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
244 {"status", S_IRUGO | S_IWUSR, TSPP_STATUS},
245 {"curr_tsp_header", S_IRUGO | S_IWUSR, TSPP_CURR_TSP_HEADER},
246 {"curr_pid_filter", S_IRUGO | S_IWUSR, TSPP_CURR_PID_FILTER},
247 /* {"system_key", S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
248 /* {"cbc_init_val", S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
249 {"data_key_reset", S_IRUGO | S_IWUSR, TSPP_DATA_KEY_RESET},
250 {"key_valid", S_IRUGO | S_IWUSR, TSPP_KEY_VALID},
251 {"key_error", S_IRUGO | S_IWUSR, TSPP_KEY_ERROR},
252 {"test_ctrl", S_IRUGO | S_IWUSR, TSPP_TEST_CTRL},
253 {"version", S_IRUGO | S_IWUSR, TSPP_VERSION},
254 {"generics", S_IRUGO | S_IWUSR, TSPP_GENERICS},
255 {"pid_filter_table0", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE0},
256 {"pid_filter_table1", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE1},
257 {"pid_filter_table2", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE2},
258 {"global_performance", S_IRUGO | S_IWUSR, TSPP_GLOBAL_PERFORMANCE},
259 {"pipe_context", S_IRUGO | S_IWUSR, TSPP_PIPE_CONTEXT},
260 {"pipe_performance", S_IRUGO | S_IWUSR, TSPP_PIPE_PERFORMANCE},
261 {"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
262};
263
Joel Nider5556a852011-10-16 10:52:13 +0200264struct tspp_pid_filter {
265 u32 filter; /* see FILTER_ macros */
266 u32 config; /* see FILTER_ macros */
267};
268
269/* tsp_info */
270#define FILTER_HEADER_ERROR_MASK BIT(7)
271#define FILTER_TRANS_END_DISABLE BIT(6)
272#define FILTER_DEC_ON_ERROR_EN BIT(5)
273#define FILTER_DECRYPT BIT(4)
274#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT)
275#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF)
276#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \
277 (_p->config & ~0xF) | (_b & 0xF))
278#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3)
279#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \
280 (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
281#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF)
282#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \
283 (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
284#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF)
285#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \
286 (_p->filter & ~0x1FFF) | (_b & 0x1FFF))
287#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3)
288#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \
289 (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
290#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7)
291#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \
292 (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
293
294struct tspp_global_performance_regs {
295 u32 tsp_total;
296 u32 tsp_ignored;
297 u32 tsp_error;
298 u32 tsp_sync;
299};
300
301struct tspp_pipe_context_regs {
302 u16 pes_bytes_left;
303 u16 count;
304 u32 tsif_suffix;
305} __packed;
306#define CONTEXT_GET_STATE(_a) (_a & 0x3)
307#define CONTEXT_UNSPEC_LENGTH BIT(11)
308#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
309
310struct tspp_pipe_performance_regs {
311 u32 tsp_total;
312 u32 ps_duplicate_tsp;
313 u32 tsp_no_payload;
314 u32 tsp_broken_ps;
315 u32 ps_total_num;
316 u32 ps_continuity_error;
317 u32 ps_length_error;
318 u32 pes_sync_error;
319};
320
321struct tspp_tsif_device {
322 void __iomem *base;
323 u32 time_limit;
324 u32 ref_count;
Joel Nider5bd73f82011-12-14 16:53:30 +0200325 enum tspp_tsif_mode mode;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200326 int clock_inverse;
327 int data_inverse;
328 int sync_inverse;
329 int enable_inverse;
Joel Nider5556a852011-10-16 10:52:13 +0200330
331 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200332 struct dentry *dent_tsif;
333 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Joel Nider5556a852011-10-16 10:52:13 +0200334};
335
336enum tspp_buf_state {
337 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
338 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider5bd73f82011-12-14 16:53:30 +0200339 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
340 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200341};
342
343struct tspp_mem_buffer {
Joel Nider5bd73f82011-12-14 16:53:30 +0200344 struct tspp_mem_buffer *next;
345 struct sps_mem_buffer sps;
346 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200347 enum tspp_buf_state state;
348 size_t filled; /* how much data this buffer is holding */
349 int read_index; /* where to start reading data from */
350};
351
352/* this represents each char device 'channel' */
353struct tspp_channel {
354 struct cdev cdev;
355 struct device *dd;
Joel Nider5bd73f82011-12-14 16:53:30 +0200356 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200357 struct sps_pipe *pipe;
358 struct sps_connect config;
359 struct sps_register_event event;
Joel Nider5bd73f82011-12-14 16:53:30 +0200360 struct tspp_mem_buffer *data; /* list of buffers */
361 struct tspp_mem_buffer *read; /* first buffer ready to be read */
362 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
363 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200364 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider5bd73f82011-12-14 16:53:30 +0200365 u32 id; /* channel id (0-15) */
366 int used; /* is this channel in use? */
367 int key; /* which encryption key index is used */
368 u32 buffer_size; /* size of the sps transfer buffers */
369 u32 max_buffers; /* how many buffers should be allocated */
370 u32 buffer_count; /* how many buffers are actually allocated */
371 u32 filter_count; /* how many filters have been added to this channel */
372 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200373 enum tspp_source src;
374 enum tspp_mode mode;
Joel Nider5bd73f82011-12-14 16:53:30 +0200375 tspp_notifier *notifier; /* used only with kernel api */
376 void *notify_data; /* data to be passed with the notifier */
377 u32 notify_timer; /* notification for partially filled buffers */
Liron Kuch229090d2012-10-30 17:47:50 +0200378 tspp_memfree *memfree; /* user defined memory free function */
379 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200380};
381
382struct tspp_pid_filter_table {
383 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
384};
385
386struct tspp_key_entry {
387 u32 even_lsb;
388 u32 even_msb;
389 u32 odd_lsb;
390 u32 odd_msb;
391};
392
393struct tspp_key_table {
394 struct tspp_key_entry entry[TSPP_NUM_KEYS];
395};
396
Joel Nider5bd73f82011-12-14 16:53:30 +0200397/* this represents the actual hardware device */
398struct tspp_device {
399 struct list_head devlist; /* list of all devices */
400 struct platform_device *pdev;
401 void __iomem *base;
402 unsigned int tspp_irq;
403 unsigned int bam_irq;
404 u32 bam_handle;
405 struct sps_bam_props bam_props;
406 struct wake_lock wake_lock;
407 spinlock_t spinlock;
408 struct tasklet_struct tlet;
409 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
410 /* clocks */
411 struct clk *tsif_pclk;
412 struct clk *tsif_ref_clk;
413 /* data */
414 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
415 struct tspp_channel channels[TSPP_NUM_CHANNELS];
416 struct tspp_key_table *tspp_key_table;
417 struct tspp_global_performance_regs *tspp_global_performance;
418 struct tspp_pipe_context_regs *tspp_pipe_context;
419 struct tspp_pipe_performance_regs *tspp_pipe_performance;
420
421 struct dentry *dent;
422 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
423};
424
425
Joel Nider5556a852011-10-16 10:52:13 +0200426static struct class *tspp_class;
427static int tspp_key_entry;
428static dev_t tspp_minor; /* next minor number to assign */
Joel Nider5bd73f82011-12-14 16:53:30 +0200429
430static LIST_HEAD(tspp_devices);
431
432/* forward declarations */
433static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
434static ssize_t tspp_open(struct inode *inode, struct file *filp);
435static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
436static ssize_t tspp_release(struct inode *inode, struct file *filp);
437static long tspp_ioctl(struct file *, unsigned int, unsigned long);
438
439/* file operations */
440static const struct file_operations tspp_fops = {
441 .owner = THIS_MODULE,
442 .read = tspp_read,
443 .open = tspp_open,
444 .poll = tspp_poll,
445 .release = tspp_release,
446 .unlocked_ioctl = tspp_ioctl,
447};
Joel Nider5556a852011-10-16 10:52:13 +0200448
449/*** IRQ ***/
Joel Nider5bd73f82011-12-14 16:53:30 +0200450static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200451{
Joel Nider5bd73f82011-12-14 16:53:30 +0200452 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200453 u32 status, mask;
454 u32 data;
455
456 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
457 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
458 status &= mask;
459
460 if (!status) {
461 dev_warn(&device->pdev->dev, "Spurious interrupt");
462 return IRQ_NONE;
463 }
464
465 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
466
467 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
468 /* read the key error info */
469 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
470 dev_info(&device->pdev->dev, "key error 0x%x", data);
471 }
472 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
473 data = readl_relaxed(device->base + TSPP_KEY_VALID);
474 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
475 }
476 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
477 dev_info(&device->pdev->dev, "key switched");
478
479 if (status & 0xffff)
Joel Nider5bd73f82011-12-14 16:53:30 +0200480 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200481
482 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
483 wmb();
484 return IRQ_HANDLED;
485}
486
487/*** callbacks ***/
488static void tspp_sps_complete_cb(struct sps_event_notify *notify)
489{
Joel Nider5bd73f82011-12-14 16:53:30 +0200490 struct tspp_device *pdev = notify->user;
491 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200492}
493
494/*** tasklet ***/
495static void tspp_sps_complete_tlet(unsigned long data)
496{
497 int i;
498 int complete;
499 unsigned long flags;
500 struct sps_iovec iovec;
501 struct tspp_channel *channel;
502 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200503 spin_lock_irqsave(&device->spinlock, flags);
504
505 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
506 complete = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +0200507 channel = &device->channels[i];
508 if (!channel->used || !channel->waiting)
509 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200510
511 /* get completions */
Joel Nider5bd73f82011-12-14 16:53:30 +0200512 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200513 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
514 pr_err("tspp: Error in iovec on channel %i",
515 channel->id);
516 break;
517 }
518 if (iovec.size == 0)
519 break;
520
Joel Nider5bd73f82011-12-14 16:53:30 +0200521 if (iovec.addr != channel->waiting->sps.phys_base)
Joel Nider5556a852011-10-16 10:52:13 +0200522 pr_err("tspp: buffer mismatch 0x%08x",
Joel Nider5bd73f82011-12-14 16:53:30 +0200523 channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200524
525 complete = 1;
Joel Nider5bd73f82011-12-14 16:53:30 +0200526 channel->waiting->state = TSPP_BUF_STATE_DATA;
527 channel->waiting->filled = iovec.size;
528 channel->waiting->read_index = 0;
529
530 /* update the pointers */
531 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200532 }
533
Joel Nider5bd73f82011-12-14 16:53:30 +0200534 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200535 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200536 wake_up_interruptible(&channel->in_queue);
Joel Nider5bd73f82011-12-14 16:53:30 +0200537
538 /* call notifiers */
539 if (channel->notifier)
540 channel->notifier(channel->id,
541 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200542 }
543 }
544
545 spin_unlock_irqrestore(&device->spinlock, flags);
546}
547
548/*** GPIO functions ***/
549static void tspp_gpios_free(const struct msm_gpio *table, int size)
550{
551 int i;
552 const struct msm_gpio *g;
553 for (i = size-1; i >= 0; i--) {
554 g = table + i;
555 gpio_free(GPIO_PIN(g->gpio_cfg));
556 }
557}
558
559static int tspp_gpios_request(const struct msm_gpio *table, int size)
560{
561 int rc;
562 int i;
563 const struct msm_gpio *g;
564 for (i = 0; i < size; i++) {
565 g = table + i;
566 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
567 if (rc) {
568 pr_err("tspp: gpio_request(%d) <%s> failed: %d\n",
569 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
570 goto err;
571 }
572 }
573 return 0;
574err:
575 tspp_gpios_free(table, i);
576 return rc;
577}
578
579static int tspp_gpios_disable(const struct msm_gpio *table, int size)
580{
581 int rc = 0;
582 int i;
583 const struct msm_gpio *g;
584 for (i = size-1; i >= 0; i--) {
585 int tmp;
586 g = table + i;
587 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
588 if (tmp) {
Liron Kuch229090d2012-10-30 17:47:50 +0200589 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200590 g->gpio_cfg, g->label ?: "?", rc);
591 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
592 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
593 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
594 GPIO_DRVSTR(g->gpio_cfg));
595 if (!rc)
596 rc = tmp;
597 }
598 }
599
600 return rc;
601}
602
603static int tspp_gpios_enable(const struct msm_gpio *table, int size)
604{
605 int rc;
606 int i;
607 const struct msm_gpio *g;
608 for (i = 0; i < size; i++) {
609 g = table + i;
610 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
611 if (rc) {
Liron Kuch229090d2012-10-30 17:47:50 +0200612 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200613 g->gpio_cfg, g->label ?: "?", rc);
614 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
615 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
616 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
617 GPIO_DRVSTR(g->gpio_cfg));
618 goto err;
619 }
620 }
621 return 0;
622err:
623 tspp_gpios_disable(table, i);
624 return rc;
625}
626
627static int tspp_gpios_request_enable(const struct msm_gpio *table, int size)
628{
629 int rc = tspp_gpios_request(table, size);
630 if (rc)
631 return rc;
632 rc = tspp_gpios_enable(table, size);
633 if (rc)
634 tspp_gpios_free(table, size);
635 return rc;
636}
637
638static void tspp_gpios_disable_free(const struct msm_gpio *table, int size)
639{
640 tspp_gpios_disable(table, size);
641 tspp_gpios_free(table, size);
642}
643
644static int tspp_start_gpios(struct tspp_device *device)
645{
646 struct msm_tspp_platform_data *pdata =
647 device->pdev->dev.platform_data;
648 return tspp_gpios_request_enable(pdata->gpios, pdata->num_gpios);
649}
650
651static void tspp_stop_gpios(struct tspp_device *device)
652{
653 struct msm_tspp_platform_data *pdata =
654 device->pdev->dev.platform_data;
655 tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios);
656}
657
Joel Nider5bd73f82011-12-14 16:53:30 +0200658/*** Clock functions ***/
659static int tspp_clock_start(struct tspp_device *device)
660{
661 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
662 pr_err("tspp: Can't start pclk");
663 return -EBUSY;
664 }
665
666 if (device->tsif_ref_clk &&
667 clk_prepare_enable(device->tsif_ref_clk) != 0) {
668 pr_err("tspp: Can't start ref clk");
669 clk_disable_unprepare(device->tsif_pclk);
670 return -EBUSY;
671 }
672
673 return 0;
674}
675
676static void tspp_clock_stop(struct tspp_device *device)
677{
678 if (device->tsif_pclk)
679 clk_disable(device->tsif_pclk);
680
681 if (device->tsif_ref_clk)
682 clk_disable(device->tsif_ref_clk);
683}
684
Joel Nider5556a852011-10-16 10:52:13 +0200685/*** TSIF functions ***/
686static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
687{
688 int start_hardware = 0;
689 u32 ctl;
690
691 if (tsif_device->ref_count == 0) {
692 start_hardware = 1;
693 } else if (tsif_device->ref_count > 0) {
694 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
695 if ((ctl & TSIF_STS_CTL_START) != 1) {
696 /* this hardware should already be running */
697 pr_warn("tspp: tsif hw not started but ref count > 0");
698 start_hardware = 1;
699 }
700 }
701
702 if (start_hardware) {
Joel Nider5bd73f82011-12-14 16:53:30 +0200703 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200704 TSIF_STS_CTL_EN_DM;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200705
706 if (tsif_device->clock_inverse)
707 ctl |= TSIF_STS_CTL_INV_CLOCK;
708
709 if (tsif_device->data_inverse)
710 ctl |= TSIF_STS_CTL_INV_DATA;
711
712 if (tsif_device->sync_inverse)
713 ctl |= TSIF_STS_CTL_INV_SYNC;
714
715 if (tsif_device->enable_inverse)
716 ctl |= TSIF_STS_CTL_INV_ENABLE;
717
Joel Nider5bd73f82011-12-14 16:53:30 +0200718 switch (tsif_device->mode) {
719 case TSPP_TSIF_MODE_LOOPBACK:
720 ctl |= TSIF_STS_CTL_EN_NULL |
721 TSIF_STS_CTL_EN_ERROR |
722 TSIF_STS_CTL_TEST_MODE;
723 break;
724 case TSPP_TSIF_MODE_1:
725 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
726 TSIF_STS_CTL_EN_TCR;
727 break;
728 case TSPP_TSIF_MODE_2:
729 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
730 TSIF_STS_CTL_EN_TCR |
731 TSIF_STS_CTL_MODE_2;
732 break;
733 default:
734 pr_warn("tspp: unknown tsif mode 0x%x",
735 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200736 }
737 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
738 writel_relaxed(tsif_device->time_limit,
739 tsif_device->base + TSIF_TIME_LIMIT_OFF);
740 wmb();
741 writel_relaxed(ctl | TSIF_STS_CTL_START,
742 tsif_device->base + TSIF_STS_CTL_OFF);
743 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200744 }
745
Joel Nider5bd73f82011-12-14 16:53:30 +0200746 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Joel Nider5556a852011-10-16 10:52:13 +0200747 tsif_device->ref_count++;
748
Joel Nider5bd73f82011-12-14 16:53:30 +0200749 return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200750}
751
752static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
753{
754 if (tsif_device->ref_count == 0)
755 return;
756
757 tsif_device->ref_count--;
758
759 if (tsif_device->ref_count == 0) {
760 writel_relaxed(TSIF_STS_CTL_STOP,
761 tsif_device->base + TSIF_STS_CTL_OFF);
762 wmb();
763 }
764}
765
Joel Nider5bd73f82011-12-14 16:53:30 +0200766/*** local TSPP functions ***/
767static int tspp_channels_in_use(struct tspp_device *pdev)
768{
769 int i;
770 int count = 0;
771 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
772 count += (pdev->channels[i].used ? 1 : 0);
773
774 return count;
775}
776
777static struct tspp_device *tspp_find_by_id(int id)
778{
779 struct tspp_device *dev;
780 list_for_each_entry(dev, &tspp_devices, devlist) {
781 if (dev->pdev->id == id)
782 return dev;
783 }
784 return NULL;
785}
786
Joel Nider5556a852011-10-16 10:52:13 +0200787static int tspp_get_key_entry(void)
788{
789 int i;
790 for (i = 0; i < TSPP_NUM_KEYS; i++) {
791 if (!(tspp_key_entry & (1 << i))) {
792 tspp_key_entry |= (1 << i);
793 return i;
794 }
795 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200796 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200797}
798
799static void tspp_free_key_entry(int entry)
800{
801 if (entry > TSPP_NUM_KEYS) {
802 pr_err("tspp_free_key_entry: index out of bounds");
803 return;
804 }
805
806 tspp_key_entry &= ~(1 << entry);
807}
808
Joel Nider5bd73f82011-12-14 16:53:30 +0200809static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
810 u32 size, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200811{
Joel Nider5bd73f82011-12-14 16:53:30 +0200812 if (size < TSPP_MIN_BUFFER_SIZE ||
813 size > TSPP_MAX_BUFFER_SIZE) {
814 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200815 return -ENOMEM;
816 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200817
818 if (alloc) {
819 TSPP_DEBUG("tspp using alloc function");
820 desc->virt_base = alloc(channel_id, size,
821 &desc->phys_base, user);
822 } else {
Liron Kuch229090d2012-10-30 17:47:50 +0200823 desc->virt_base = dma_alloc_coherent(NULL, size,
824 &desc->phys_base, GFP_KERNEL);
825 if (desc->virt_base == 0) {
826 pr_err("tspp dma alloc coherent failed %i", size);
827 return -ENOMEM;
828 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200829 }
830
831 desc->size = size;
832 return 0;
833}
834
835static int tspp_queue_buffer(struct tspp_channel *channel,
836 struct tspp_mem_buffer *buffer)
837{
838 int rc;
839 u32 flags = 0;
840
841 /* make sure the interrupt frequency is valid */
842 if (channel->int_freq < 1)
843 channel->int_freq = 1;
844
845 /* generate interrupt according to requested frequency */
846 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
847 flags = SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOB;
848
849 /* start the transfer */
850 rc = sps_transfer_one(channel->pipe,
851 buffer->sps.phys_base,
852 buffer->sps.size,
853 channel->pdev,
854 flags);
855 if (rc < 0)
856 return rc;
857
858 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +0200859
860 return 0;
861}
862
863static int tspp_global_reset(struct tspp_device *pdev)
864{
865 u32 i, val;
866
867 /* stop all TSIFs */
868 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
869 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
870 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
871 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200872 pdev->tsif[i].clock_inverse = 0;
873 pdev->tsif[i].data_inverse = 0;
874 pdev->tsif[i].sync_inverse = 0;
875 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +0200876 }
877 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
878 wmb();
879
880 /* BAM */
881 if (sps_device_reset(pdev->bam_handle) != 0) {
882 pr_err("tspp: error resetting bam");
Joel Nider5bd73f82011-12-14 16:53:30 +0200883 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200884 }
885
886 /* TSPP tables */
887 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider5bd73f82011-12-14 16:53:30 +0200888 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +0200889 0, sizeof(struct tspp_pid_filter_table));
890
891 /* disable all filters */
892 val = (2 << TSPP_NUM_CHANNELS) - 1;
893 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
894
895 /* TSPP registers */
896 val = readl_relaxed(pdev->base + TSPP_CONTROL);
897 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
898 pdev->base + TSPP_CONTROL);
899 wmb();
Joel Nider5bd73f82011-12-14 16:53:30 +0200900 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200901 sizeof(struct tspp_global_performance_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +0200902 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200903 sizeof(struct tspp_pipe_context_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +0200904 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200905 sizeof(struct tspp_pipe_performance_regs));
906 wmb();
907 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
908 pdev->base + TSPP_CONTROL);
909 wmb();
910
911 val = readl_relaxed(pdev->base + TSPP_CONFIG);
912 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
913 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
914 TSPP_CONFIG_PS_CONT_ERR_MASK);
915 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
916 writel_relaxed(val, pdev->base + TSPP_CONFIG);
917 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_MASK);
918 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
919 writel_relaxed(0, pdev->base + TSPP_RST);
920 wmb();
921
922 tspp_key_entry = 0;
923
924 return 0;
925}
926
Joel Nider5bd73f82011-12-14 16:53:30 +0200927static int tspp_select_source(u32 dev, u32 channel_id,
928 struct tspp_select_source *src)
929{
930 /* make sure the requested src id is in bounds */
931 if (src->source > TSPP_SOURCE_MEM) {
932 pr_err("tspp source out of bounds");
933 return -EINVAL;
934 }
935
936 /* open the stream */
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200937 tspp_open_stream(dev, channel_id, src);
Joel Nider5bd73f82011-12-14 16:53:30 +0200938
939 return 0;
940}
941
942static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
943{
944 struct tspp_device *pdev = channel->pdev;
945
946 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
947 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
948 return 0;
949}
950
951static int tspp_set_system_keys(struct tspp_channel *channel,
952 struct tspp_system_keys *keys)
953{
954 int i;
955 struct tspp_device *pdev = channel->pdev;
956
957 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
958 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
959
960 return 0;
961}
962
963static int tspp_channel_init(struct tspp_channel *channel,
964 struct tspp_device *pdev)
965{
966 channel->cdev.owner = THIS_MODULE;
967 cdev_init(&channel->cdev, &tspp_fops);
968 channel->pdev = pdev;
969 channel->data = NULL;
970 channel->read = NULL;
971 channel->waiting = NULL;
972 channel->locked = NULL;
973 channel->id = MINOR(tspp_minor);
974 channel->used = 0;
975 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
976 channel->max_buffers = TSPP_NUM_BUFFERS;
977 channel->buffer_count = 0;
978 channel->filter_count = 0;
979 channel->int_freq = 1;
Liron Kuch229090d2012-10-30 17:47:50 +0200980 channel->src = TSPP_SOURCE_NONE;
981 channel->mode = TSPP_MODE_DISABLED;
Joel Nider5bd73f82011-12-14 16:53:30 +0200982 channel->notifier = NULL;
983 channel->notify_data = NULL;
984 channel->notify_timer = 0;
Liron Kuch229090d2012-10-30 17:47:50 +0200985 channel->memfree = NULL;
986 channel->user_info = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +0200987 init_waitqueue_head(&channel->in_queue);
988
989 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
990 pr_err("tspp: cdev_add failed");
991 return -EBUSY;
992 }
993
994 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
995 channel, "tspp%02d", channel->id);
996 if (IS_ERR(channel->dd)) {
997 pr_err("tspp: device_create failed: %i",
998 (int)PTR_ERR(channel->dd));
999 cdev_del(&channel->cdev);
1000 return -EBUSY;
1001 }
1002
1003 return 0;
1004}
1005
1006static int tspp_set_buffer_size(struct tspp_channel *channel,
1007 struct tspp_buffer *buf)
1008{
Liron Kuch229090d2012-10-30 17:47:50 +02001009 if (channel->buffer_count > 0) {
1010 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1011 return -EPERM;
1012 }
1013
Joel Nider5bd73f82011-12-14 16:53:30 +02001014 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1015 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1016 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1017 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1018 else
1019 channel->buffer_size = buf->size;
1020
1021 return 0;
1022}
1023
1024static void tspp_set_tsif_mode(struct tspp_channel *channel,
1025 enum tspp_tsif_mode mode)
1026{
1027 int index;
1028
1029 switch (channel->src) {
1030 case TSPP_SOURCE_TSIF0:
1031 index = 0;
1032 break;
1033 case TSPP_SOURCE_TSIF1:
1034 index = 1;
1035 break;
1036 default:
1037 pr_warn("tspp: can't set mode for non-tsif source %d",
1038 channel->src);
1039 return;
1040 }
1041 channel->pdev->tsif[index].mode = mode;
1042}
1043
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001044static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch229090d2012-10-30 17:47:50 +02001045 int clock_inverse, int data_inverse,
1046 int sync_inverse, int enable_inverse)
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001047{
1048 int index;
1049
1050 switch (channel->src) {
1051 case TSPP_SOURCE_TSIF0:
1052 index = 0;
1053 break;
1054 case TSPP_SOURCE_TSIF1:
1055 index = 1;
1056 break;
1057 default:
1058 return;
1059 }
1060 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1061 channel->pdev->tsif[index].data_inverse = data_inverse;
1062 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1063 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1064}
1065
Liron Kuch229090d2012-10-30 17:47:50 +02001066static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1067{
1068 u32 alignment;
1069
1070 switch (mode) {
1071 case TSPP_MODE_RAW:
1072 /* must be a multiple of 192 */
1073 alignment = (TSPP_PACKET_LENGTH + 4);
1074 if (size % alignment)
1075 return 0;
1076 return 1;
1077
1078 case TSPP_MODE_RAW_NO_SUFFIX:
1079 /* must be a multiple of 188 */
1080 alignment = TSPP_PACKET_LENGTH;
1081 if (size % alignment)
1082 return 0;
1083 return 1;
1084
1085 case TSPP_MODE_DISABLED:
1086 case TSPP_MODE_PES:
1087 default:
1088 /* no alignment requirement */
1089 return 1;
1090 }
1091
1092}
1093
1094static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1095{
1096 u32 new_size;
1097 u32 alignment;
1098
1099 switch (mode) {
1100 case TSPP_MODE_RAW:
1101 /* must be a multiple of 192 */
1102 alignment = (TSPP_PACKET_LENGTH + 4);
1103 break;
1104
1105 case TSPP_MODE_RAW_NO_SUFFIX:
1106 /* must be a multiple of 188 */
1107 alignment = TSPP_PACKET_LENGTH;
1108 break;
1109
1110 case TSPP_MODE_DISABLED:
1111 case TSPP_MODE_PES:
1112 default:
1113 /* no alignment requirement - give the user what he asks for */
1114 alignment = 1;
1115 break;
1116 }
1117 /* align up */
1118 new_size = (((size + alignment - 1) / alignment) * alignment);
1119 return new_size;
1120}
1121
1122static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1123{
1124 int i;
1125 struct tspp_mem_buffer *pbuf, *temp;
1126
1127 pbuf = channel->data;
1128 for (i = 0; i < channel->buffer_count; i++) {
1129 if (pbuf->desc.phys_base) {
1130 if (channel->memfree) {
1131 channel->memfree(channel_id,
1132 pbuf->desc.size,
1133 pbuf->desc.virt_base,
1134 pbuf->desc.phys_base,
1135 channel->user_info);
1136 } else {
1137 dma_free_coherent(NULL,
1138 pbuf->desc.size,
1139 pbuf->desc.virt_base,
1140 pbuf->desc.phys_base);
1141 }
1142 pbuf->desc.phys_base = 0;
1143 }
1144 pbuf->desc.virt_base = 0;
1145 pbuf->state = TSPP_BUF_STATE_EMPTY;
1146 temp = pbuf;
1147 pbuf = pbuf->next;
1148 kfree(temp);
1149 }
1150}
1151
Joel Nider5bd73f82011-12-14 16:53:30 +02001152/*** TSPP API functions ***/
Liron Kuch229090d2012-10-30 17:47:50 +02001153
1154/**
1155 * tspp_open_stream - open a TSPP stream for use.
1156 *
1157 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1158 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1159 * @source: stream source parameters.
1160 *
1161 * Return error status
1162 *
1163 */
1164int tspp_open_stream(u32 dev, u32 channel_id,
1165 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001166{
1167 u32 val;
1168 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001169 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001170
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001171 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1172 dev, channel_id, source->source, source->mode);
Liron Kuch229090d2012-10-30 17:47:50 +02001173
Joel Nider5bd73f82011-12-14 16:53:30 +02001174 if (dev >= TSPP_MAX_DEVICES) {
1175 pr_err("tspp: device id out of range");
1176 return -ENODEV;
1177 }
Joel Nider5556a852011-10-16 10:52:13 +02001178
Joel Nider5bd73f82011-12-14 16:53:30 +02001179 if (channel_id >= TSPP_NUM_CHANNELS) {
1180 pr_err("tspp: channel id out of range");
1181 return -ECHRNG;
1182 }
1183
1184 pdev = tspp_find_by_id(dev);
1185 if (!pdev) {
1186 pr_err("tspp_str: can't find device %i", dev);
1187 return -ENODEV;
1188 }
1189 channel = &pdev->channels[channel_id];
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001190 channel->src = source->source;
1191 tspp_set_tsif_mode(channel, source->mode);
1192 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch229090d2012-10-30 17:47:50 +02001193 source->data_inverse, source->sync_inverse,
1194 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001195
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001196 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001197 case TSPP_SOURCE_TSIF0:
1198 /* make sure TSIF0 is running & enabled */
1199 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
1200 pr_err("tspp: error starting tsif0");
Joel Nider5bd73f82011-12-14 16:53:30 +02001201 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001202 }
1203 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1204 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1205 pdev->base + TSPP_CONTROL);
1206 wmb();
1207 break;
1208 case TSPP_SOURCE_TSIF1:
1209 /* make sure TSIF1 is running & enabled */
1210 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
1211 pr_err("tspp: error starting tsif1");
Joel Nider5bd73f82011-12-14 16:53:30 +02001212 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001213 }
1214 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1215 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1216 pdev->base + TSPP_CONTROL);
1217 wmb();
1218 break;
1219 case TSPP_SOURCE_MEM:
1220 break;
1221 default:
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001222 pr_err("tspp: channel %i invalid source %i",
1223 channel->id, source->source);
Joel Nider5bd73f82011-12-14 16:53:30 +02001224 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001225 }
1226
Joel Nider5556a852011-10-16 10:52:13 +02001227 return 0;
1228}
1229EXPORT_SYMBOL(tspp_open_stream);
1230
Liron Kuch229090d2012-10-30 17:47:50 +02001231/**
1232 * tspp_close_stream - close a TSPP stream.
1233 *
1234 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1235 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1236 *
1237 * Return error status
1238 *
1239 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001240int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001241{
1242 u32 val;
1243 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001244 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001245
Joel Nider5bd73f82011-12-14 16:53:30 +02001246 if (channel_id >= TSPP_NUM_CHANNELS) {
1247 pr_err("tspp: channel id out of range");
1248 return -ECHRNG;
1249 }
1250 pdev = tspp_find_by_id(dev);
1251 if (!pdev) {
1252 pr_err("tspp_cs: can't find device %i", dev);
1253 return -EBUSY;
1254 }
1255 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001256
1257 switch (channel->src) {
1258 case TSPP_SOURCE_TSIF0:
1259 tspp_stop_tsif(&pdev->tsif[0]);
1260 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1261 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1262 pdev->base + TSPP_CONTROL);
1263 wmb();
1264 break;
1265 case TSPP_SOURCE_TSIF1:
1266 tspp_stop_tsif(&pdev->tsif[1]);
1267 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1268 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1269 pdev->base + TSPP_CONTROL);
1270 break;
1271 case TSPP_SOURCE_MEM:
1272 break;
1273 case TSPP_SOURCE_NONE:
1274 break;
1275 }
1276
Joel Nider5bd73f82011-12-14 16:53:30 +02001277 channel->src = TSPP_SOURCE_NONE;
Joel Nider5556a852011-10-16 10:52:13 +02001278 return 0;
1279}
1280EXPORT_SYMBOL(tspp_close_stream);
1281
Liron Kuch229090d2012-10-30 17:47:50 +02001282/**
1283 * tspp_open_channel - open a TSPP channel.
1284 *
1285 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1286 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1287 *
1288 * Return error status
1289 *
1290 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001291int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001292{
1293 int rc = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001294 struct sps_connect *config;
1295 struct sps_register_event *event;
1296 struct tspp_channel *channel;
1297 struct tspp_device *pdev;
1298
1299 if (channel_id >= TSPP_NUM_CHANNELS) {
1300 pr_err("tspp: channel id out of range");
1301 return -ECHRNG;
1302 }
1303 pdev = tspp_find_by_id(dev);
1304 if (!pdev) {
1305 pr_err("tspp_oc: can't find device %i", dev);
1306 return -ENODEV;
1307 }
1308 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001309
1310 if (channel->used) {
1311 pr_err("tspp channel already in use");
Joel Nider5bd73f82011-12-14 16:53:30 +02001312 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001313 }
1314
Joel Nider5bd73f82011-12-14 16:53:30 +02001315 config = &channel->config;
1316 event = &channel->event;
1317
1318 /* start the clocks if needed */
1319 tspp_clock_start(pdev);
1320 if (tspp_channels_in_use(pdev) == 0)
1321 wake_lock(&pdev->wake_lock);
1322
Joel Nider5556a852011-10-16 10:52:13 +02001323 /* mark it as used */
1324 channel->used = 1;
1325
1326 /* start the bam */
1327 channel->pipe = sps_alloc_endpoint();
1328 if (channel->pipe == 0) {
1329 pr_err("tspp: error allocating endpoint");
1330 rc = -ENOMEM;
1331 goto err_sps_alloc;
1332 }
1333
1334 /* get default configuration */
1335 sps_get_config(channel->pipe, config);
1336
Joel Nider5bd73f82011-12-14 16:53:30 +02001337 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001338 config->destination = SPS_DEV_HANDLE_MEM;
1339 config->mode = SPS_MODE_SRC;
Joel Nider5bd73f82011-12-14 16:53:30 +02001340 config->options =
1341 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1342 SPS_O_STREAMING | /* streaming mode */
1343 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
1344 SPS_O_ACK_TRANSFERS; /* must use sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001345 config->src_pipe_index = channel->id;
1346 config->desc.size =
1347 (TSPP_SPS_DESCRIPTOR_COUNT + 1) * SPS_DESCRIPTOR_SIZE;
1348 config->desc.base = dma_alloc_coherent(NULL,
1349 config->desc.size,
1350 &config->desc.phys_base,
1351 GFP_KERNEL);
1352 if (config->desc.base == 0) {
1353 pr_err("tspp: error allocating sps descriptors");
1354 rc = -ENOMEM;
1355 goto err_desc_alloc;
1356 }
1357
1358 memset(config->desc.base, 0, config->desc.size);
1359
1360 rc = sps_connect(channel->pipe, config);
1361 if (rc) {
1362 pr_err("tspp: error connecting bam");
1363 goto err_connect;
1364 }
1365
1366 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider5bd73f82011-12-14 16:53:30 +02001367 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001368 event->callback = tspp_sps_complete_cb;
1369 event->xfer_done = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001370 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001371
1372 rc = sps_register_event(channel->pipe, event);
1373 if (rc) {
1374 pr_err("tspp: error registering event");
1375 goto err_event;
1376 }
1377
Joel Nider5bd73f82011-12-14 16:53:30 +02001378 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001379 if (rc < 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001380 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001381 "Runtime PM: Unable to wake up tspp device, rc = %d",
1382 rc);
1383 }
Joel Nider5556a852011-10-16 10:52:13 +02001384 return 0;
1385
1386err_event:
1387 sps_disconnect(channel->pipe);
1388err_connect:
1389 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1390 config->desc.phys_base);
1391err_desc_alloc:
1392 sps_free_endpoint(channel->pipe);
1393err_sps_alloc:
1394 return rc;
1395}
1396EXPORT_SYMBOL(tspp_open_channel);
1397
Liron Kuch229090d2012-10-30 17:47:50 +02001398/**
1399 * tspp_close_channel - close a TSPP channel.
1400 *
1401 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1402 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1403 *
1404 * Return error status
1405 *
1406 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001407int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001408{
1409 int i;
1410 int id;
1411 u32 val;
Joel Nider5556a852011-10-16 10:52:13 +02001412
Joel Nider5bd73f82011-12-14 16:53:30 +02001413 struct sps_connect *config;
1414 struct tspp_device *pdev;
1415 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02001416
1417 if (channel_id >= TSPP_NUM_CHANNELS) {
1418 pr_err("tspp: channel id out of range");
1419 return -ECHRNG;
1420 }
1421 pdev = tspp_find_by_id(dev);
1422 if (!pdev) {
1423 pr_err("tspp_close: can't find device %i", dev);
1424 return -ENODEV;
1425 }
1426 channel = &pdev->channels[channel_id];
1427
1428 /* if the channel is not used, we are done */
1429 if (!channel->used)
1430 return 0;
1431
1432 channel->notifier = NULL;
1433 channel->notify_data = NULL;
1434 channel->notify_timer = 0;
1435
1436 config = &channel->config;
1437 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001438
1439 /* disable pipe (channel) */
1440 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1441 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1442 wmb();
1443
1444 /* unregister all filters for this channel */
1445 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1446 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001447 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001448 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1449 if (id == channel->id) {
1450 if (FILTER_HAS_ENCRYPTION(tspp_filter))
1451 tspp_free_key_entry(
1452 FILTER_GET_KEY_NUMBER(tspp_filter));
1453 tspp_filter->config = 0;
1454 tspp_filter->filter = 0;
1455 }
1456 }
1457 channel->filter_count = 0;
1458
1459 /* stop the stream */
Joel Nider5bd73f82011-12-14 16:53:30 +02001460 tspp_close_stream(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02001461
1462 /* disconnect the bam */
1463 if (sps_disconnect(channel->pipe) != 0)
1464 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1465
1466 /* destroy the buffers */
1467 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1468 config->desc.phys_base);
1469
Liron Kuch229090d2012-10-30 17:47:50 +02001470 tspp_destroy_buffers(channel_id, channel);
1471
1472 channel->src = TSPP_SOURCE_NONE;
1473 channel->mode = TSPP_MODE_DISABLED;
1474 channel->memfree = NULL;
1475 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001476 channel->buffer_count = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001477 channel->data = NULL;
1478 channel->read = NULL;
1479 channel->waiting = NULL;
1480 channel->locked = NULL;
1481 channel->used = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001482
Joel Nider5bd73f82011-12-14 16:53:30 +02001483 if (tspp_channels_in_use(pdev) == 0)
1484 wake_unlock(&pdev->wake_lock);
1485 tspp_clock_stop(pdev);
1486
Joel Nider5556a852011-10-16 10:52:13 +02001487 return 0;
1488}
1489EXPORT_SYMBOL(tspp_close_channel);
1490
Liron Kuch229090d2012-10-30 17:47:50 +02001491/**
1492 * tspp_add_filter - add a TSPP filter to a channel.
1493 *
1494 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1495 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1496 * @filter: TSPP filter parameters
1497 *
1498 * Return error status
1499 *
1500 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001501int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001502 struct tspp_filter *filter)
1503{
Liron Kuch229090d2012-10-30 17:47:50 +02001504 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001505 int other_channel;
1506 int entry;
1507 u32 val, pid, enabled;
Joel Nider5bd73f82011-12-14 16:53:30 +02001508 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001509 struct tspp_pid_filter p;
Joel Nider5bd73f82011-12-14 16:53:30 +02001510 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001511
Joel Nider5bd73f82011-12-14 16:53:30 +02001512 TSPP_DEBUG("tspp: add filter");
1513 if (channel_id >= TSPP_NUM_CHANNELS) {
1514 pr_err("tspp: channel id out of range");
1515 return -ECHRNG;
1516 }
1517 pdev = tspp_find_by_id(dev);
1518 if (!pdev) {
1519 pr_err("tspp_add: can't find device %i", dev);
1520 return -ENODEV;
1521 }
1522
1523 channel = &pdev->channels[channel_id];
1524
Joel Nider5556a852011-10-16 10:52:13 +02001525 if (filter->source > TSPP_SOURCE_MEM) {
1526 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001527 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001528 }
1529
1530 if (filter->priority >= TSPP_NUM_PRIORITIES) {
1531 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001532 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001533 }
1534
Liron Kuch229090d2012-10-30 17:47:50 +02001535 channel->mode = filter->mode;
1536 /*
1537 * if buffers are already allocated, verify they fulfil
1538 * the alignment requirements.
1539 */
1540 if ((channel->buffer_count > 0) &&
1541 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1542 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001543
1544 if (filter->mode == TSPP_MODE_PES) {
1545 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1546 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001547 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001548 pid = FILTER_GET_PIPE_PID((tspp_filter));
1549 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1550 if (enabled && (pid == filter->pid)) {
1551 other_channel =
1552 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1553 pr_err("tspp: pid 0x%x already in use by channel %i",
1554 filter->pid, other_channel);
Joel Nider5bd73f82011-12-14 16:53:30 +02001555 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001556 }
1557 }
1558 }
1559
1560 /* make sure this priority is not already in use */
1561 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider5bd73f82011-12-14 16:53:30 +02001562 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001563 if (enabled) {
1564 pr_err("tspp: filter priority %i source %i is already enabled\n",
1565 filter->priority, channel->src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001566 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001567 }
1568
1569 if (channel->mode == TSPP_MODE_PES) {
1570 /* if we are already processing in PES mode, disable pipe
1571 (channel) and filter to be updated */
1572 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1573 writel_relaxed(val | (1 << channel->id),
1574 pdev->base + TSPP_PS_DISABLE);
1575 wmb();
1576 }
1577
1578 /* update entry */
1579 p.filter = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001580 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001581 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1582 FILTER_SET_PIPE_PID((&p), filter->pid);
1583 FILTER_SET_PID_MASK((&p), filter->mask);
1584 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1585 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1586 if (filter->decrypt) {
1587 entry = tspp_get_key_entry();
1588 if (entry == -1) {
1589 pr_err("tspp: no more keys available!");
1590 } else {
1591 p.config |= FILTER_DECRYPT;
1592 FILTER_SET_KEY_NUMBER((&p), entry);
1593 }
1594 }
Joel Nider5556a852011-10-16 10:52:13 +02001595
Joel Nider5bd73f82011-12-14 16:53:30 +02001596 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001597 filter[filter->priority].config = p.config;
Joel Nider5bd73f82011-12-14 16:53:30 +02001598 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001599 filter[filter->priority].filter = p.filter;
1600
Liron Kuch229090d2012-10-30 17:47:50 +02001601 /*
1602 * allocate buffers if needed (i.e. if user did has not already called
1603 * tspp_allocate_buffers() explicitly).
1604 */
1605 if (channel->buffer_count == 0) {
1606 channel->buffer_size =
1607 tspp_align_buffer_size_by_mode(channel->buffer_size,
1608 channel->mode);
1609 rc = tspp_allocate_buffers(dev, channel->id,
1610 channel->max_buffers,
1611 channel->buffer_size,
1612 channel->int_freq, NULL, NULL, NULL);
1613 if (rc != 0) {
1614 pr_err("tspp: tspp_allocate_buffers failed\n");
1615 return rc;
1616 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001617 }
1618
Joel Nider5556a852011-10-16 10:52:13 +02001619 /* reenable pipe */
1620 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1621 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1622 wmb();
1623 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1624
Joel Nider5556a852011-10-16 10:52:13 +02001625 channel->filter_count++;
1626
1627 return 0;
1628}
1629EXPORT_SYMBOL(tspp_add_filter);
1630
Liron Kuch229090d2012-10-30 17:47:50 +02001631/**
1632 * tspp_remove_filter - remove a TSPP filter from a channel.
1633 *
1634 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1635 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1636 * @filter: TSPP filter parameters
1637 *
1638 * Return error status
1639 *
1640 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001641int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001642 struct tspp_filter *filter)
1643{
1644 int entry;
1645 u32 val;
Joel Nider5bd73f82011-12-14 16:53:30 +02001646 struct tspp_device *pdev;
1647 int src;
1648 struct tspp_pid_filter *tspp_filter;
1649 struct tspp_channel *channel;
1650
1651 if (channel_id >= TSPP_NUM_CHANNELS) {
1652 pr_err("tspp: channel id out of range");
1653 return -ECHRNG;
1654 }
1655 pdev = tspp_find_by_id(dev);
1656 if (!pdev) {
1657 pr_err("tspp_remove: can't find device %i", dev);
1658 return -ENODEV;
1659 }
1660 channel = &pdev->channels[channel_id];
1661
1662 src = channel->src;
1663 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02001664
1665 /* disable pipe (channel) */
1666 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1667 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1668 wmb();
1669
1670 /* update data keys */
1671 if (tspp_filter->config & FILTER_DECRYPT) {
1672 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
1673 tspp_free_key_entry(entry);
1674 }
1675
1676 /* update pid table */
1677 tspp_filter->config = 0;
1678 tspp_filter->filter = 0;
1679
1680 channel->filter_count--;
1681
1682 /* reenable pipe */
1683 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1684 writel_relaxed(val & ~(1 << channel->id),
1685 pdev->base + TSPP_PS_DISABLE);
1686 wmb();
1687 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1688
1689 return 0;
1690}
1691EXPORT_SYMBOL(tspp_remove_filter);
1692
Liron Kuch229090d2012-10-30 17:47:50 +02001693/**
1694 * tspp_set_key - set TSPP key in key table.
1695 *
1696 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1697 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1698 * @key: TSPP key parameters
1699 *
1700 * Return error status
1701 *
1702 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001703int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02001704{
1705 int i;
1706 int id;
1707 int key_index;
1708 int data;
Joel Nider5bd73f82011-12-14 16:53:30 +02001709 struct tspp_channel *channel;
1710 struct tspp_device *pdev;
1711
1712 if (channel_id >= TSPP_NUM_CHANNELS) {
1713 pr_err("tspp: channel id out of range");
1714 return -ECHRNG;
1715 }
1716 pdev = tspp_find_by_id(dev);
1717 if (!pdev) {
1718 pr_err("tspp_set: can't find device %i", dev);
1719 return -ENODEV;
1720 }
1721 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001722
1723 /* read the key index used by this channel */
1724 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1725 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001726 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02001727 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1728 if (id == channel->id) {
1729 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
1730 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
1731 break;
1732 }
1733 }
1734 }
1735 if (i == TSPP_NUM_PRIORITIES) {
1736 pr_err("tspp: no encryption on this channel");
Joel Nider5bd73f82011-12-14 16:53:30 +02001737 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02001738 }
1739
1740 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001741 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
1742 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001743 } else {
Joel Nider5bd73f82011-12-14 16:53:30 +02001744 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
1745 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001746 }
1747 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
1748
1749 return 0;
1750}
1751EXPORT_SYMBOL(tspp_set_key);
1752
Liron Kuch229090d2012-10-30 17:47:50 +02001753/**
1754 * tspp_register_notification - register TSPP channel notification function.
1755 *
1756 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1757 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1758 * @pNotify: notification function
1759 * @userdata: user data to pass to notification function
1760 * @timer_ms: notification for partially filled buffers
1761 *
1762 * Return error status
1763 *
1764 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001765int tspp_register_notification(u32 dev, u32 channel_id,
1766 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02001767{
Joel Nider5bd73f82011-12-14 16:53:30 +02001768 struct tspp_channel *channel;
1769 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001770
Joel Nider5bd73f82011-12-14 16:53:30 +02001771 if (channel_id >= TSPP_NUM_CHANNELS) {
1772 pr_err("tspp: channel id out of range");
1773 return -ECHRNG;
1774 }
1775 pdev = tspp_find_by_id(dev);
1776 if (!pdev) {
1777 pr_err("tspp_reg: can't find device %i", dev);
1778 return -ENODEV;
1779 }
1780 channel = &pdev->channels[channel_id];
1781 channel->notifier = pNotify;
1782 channel->notify_data = userdata;
1783 channel->notify_timer = timer_ms;
Joel Nider5556a852011-10-16 10:52:13 +02001784 return 0;
1785}
Joel Nider5bd73f82011-12-14 16:53:30 +02001786EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001787
Liron Kuch229090d2012-10-30 17:47:50 +02001788/**
1789 * tspp_unregister_notification - unregister TSPP channel notification function.
1790 *
1791 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1792 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1793 *
1794 * Return error status
1795 *
1796 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001797int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001798{
Joel Nider5bd73f82011-12-14 16:53:30 +02001799 struct tspp_channel *channel;
1800 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001801
Joel Nider5bd73f82011-12-14 16:53:30 +02001802 if (channel_id >= TSPP_NUM_CHANNELS) {
1803 pr_err("tspp: channel id out of range");
1804 return -ECHRNG;
1805 }
1806 pdev = tspp_find_by_id(dev);
1807 if (!pdev) {
1808 pr_err("tspp_unreg: can't find device %i", dev);
1809 return -ENODEV;
1810 }
1811 channel = &pdev->channels[channel_id];
1812 channel->notifier = NULL;
1813 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001814 return 0;
1815}
Joel Nider5bd73f82011-12-14 16:53:30 +02001816EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001817
Liron Kuch229090d2012-10-30 17:47:50 +02001818/**
1819 * tspp_get_buffer - get TSPP data buffer.
1820 *
1821 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1822 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1823 *
1824 * Return error status
1825 *
1826 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001827const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001828{
Joel Nider5bd73f82011-12-14 16:53:30 +02001829 struct tspp_mem_buffer *buffer;
1830 struct tspp_channel *channel;
1831 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001832
Joel Nider5bd73f82011-12-14 16:53:30 +02001833 if (channel_id >= TSPP_NUM_CHANNELS) {
1834 pr_err("tspp: channel id out of range");
1835 return NULL;
1836 }
1837 pdev = tspp_find_by_id(dev);
1838 if (!pdev) {
1839 pr_err("tspp_get: can't find device %i", dev);
1840 return NULL;
1841 }
1842 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001843
Joel Nider5bd73f82011-12-14 16:53:30 +02001844 if (!channel->read) {
1845 pr_warn("tspp: no buffer to get on channel %i!",
1846 channel->id);
1847 return NULL;
1848 }
1849
1850 buffer = channel->read;
1851 /* see if we have any buffers ready to read */
1852 if (buffer->state != TSPP_BUF_STATE_DATA)
1853 return 0;
1854
1855 if (buffer->state == TSPP_BUF_STATE_DATA) {
1856 /* mark the buffer as busy */
1857 buffer->state = TSPP_BUF_STATE_LOCKED;
1858
1859 /* increment the pointer along the list */
1860 channel->read = channel->read->next;
1861 }
1862
1863 return &buffer->desc;
1864}
1865EXPORT_SYMBOL(tspp_get_buffer);
1866
Liron Kuch229090d2012-10-30 17:47:50 +02001867/**
1868 * tspp_release_buffer - release TSPP data buffer back to TSPP.
1869 *
1870 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1871 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1872 * @descriptor_id: buffer descriptor ID
1873 *
1874 * Return error status
1875 *
1876 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001877int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
1878{
1879 int i, found = 0;
1880 struct tspp_mem_buffer *buffer;
1881 struct tspp_channel *channel;
1882 struct tspp_device *pdev;
1883
1884 if (channel_id >= TSPP_NUM_CHANNELS) {
1885 pr_err("tspp: channel id out of range");
1886 return -ECHRNG;
1887 }
1888 pdev = tspp_find_by_id(dev);
1889 if (!pdev) {
1890 pr_err("tspp: can't find device %i", dev);
1891 return -ENODEV;
1892 }
1893 channel = &pdev->channels[channel_id];
1894
1895 if (descriptor_id > channel->buffer_count)
1896 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
1897
1898 /* find the correct descriptor */
1899 buffer = channel->locked;
1900 for (i = 0; i < channel->buffer_count; i++) {
1901 if (buffer->desc.id == descriptor_id) {
1902 found = 1;
1903 break;
1904 }
1905 buffer = buffer->next;
1906 }
1907 channel->locked = channel->locked->next;
1908
1909 if (!found) {
1910 pr_err("tspp: cant find desc %i", descriptor_id);
1911 return -EINVAL;
1912 }
1913
1914 /* make sure the buffer is in the expected state */
1915 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
1916 pr_err("tspp: buffer %i not locked", descriptor_id);
1917 return -EINVAL;
1918 }
1919 /* unlock the buffer and requeue it */
1920 buffer->state = TSPP_BUF_STATE_WAITING;
1921
1922 if (tspp_queue_buffer(channel, buffer))
1923 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02001924 return 0;
1925}
Joel Nider5bd73f82011-12-14 16:53:30 +02001926EXPORT_SYMBOL(tspp_release_buffer);
1927
Liron Kuch229090d2012-10-30 17:47:50 +02001928/**
1929 * tspp_allocate_buffers - allocate TSPP data buffers.
1930 *
1931 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1932 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1933 * @count: number of buffers to allocate
1934 * @size: size of each buffer to allocate
1935 * @int_freq: interrupt frequency
1936 * @alloc: user defined memory allocator function. Pass NULL for default.
1937 * @memfree: user defined memory free function. Pass NULL for default.
1938 * @user: user data to pass to the memory allocator/free function
1939 *
1940 * Return error status
1941 *
1942 * The user can optionally call this function explicitly to allocate the TSPP
1943 * data buffers. Alternatively, if the user did not call this function, it
1944 * is called implicitly by tspp_add_filter().
1945 */
1946int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
1947 u32 int_freq, tspp_allocator *alloc,
1948 tspp_memfree *memfree, void *user)
Joel Nider5bd73f82011-12-14 16:53:30 +02001949{
1950 struct tspp_channel *channel;
1951 struct tspp_device *pdev;
1952 struct tspp_mem_buffer *last = NULL;
1953
1954 TSPP_DEBUG("tspp_allocate_buffers");
1955
1956 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch229090d2012-10-30 17:47:50 +02001957 pr_err("%s: channel id out of range", __func__);
Joel Nider5bd73f82011-12-14 16:53:30 +02001958 return -ECHRNG;
1959 }
Liron Kuch229090d2012-10-30 17:47:50 +02001960
Joel Nider5bd73f82011-12-14 16:53:30 +02001961 pdev = tspp_find_by_id(dev);
1962 if (!pdev) {
Liron Kuch229090d2012-10-30 17:47:50 +02001963 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider5bd73f82011-12-14 16:53:30 +02001964 return -ENODEV;
1965 }
Liron Kuch229090d2012-10-30 17:47:50 +02001966
1967 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
1968 pr_err("%s: tspp requires a minimum of %i buffers\n",
1969 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
1970 return -EINVAL;
1971 }
1972
Joel Nider5bd73f82011-12-14 16:53:30 +02001973 channel = &pdev->channels[channel_id];
Liron Kuch229090d2012-10-30 17:47:50 +02001974 /* allow buffer allocation only if there was no previous buffer
1975 * allocation for this channel.
1976 */
1977 if (channel->buffer_count > 0) {
1978 pr_err("%s: buffers already allocated for channel %u",
1979 __func__, channel_id);
1980 return -EINVAL;
1981 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001982
1983 channel->max_buffers = count;
1984
1985 /* set up interrupt frequency */
Liron Kuch229090d2012-10-30 17:47:50 +02001986 if (int_freq > channel->max_buffers) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001987 int_freq = channel->max_buffers;
Liron Kuch229090d2012-10-30 17:47:50 +02001988 pr_warn("%s: setting interrupt frequency to %u\n",
1989 __func__, int_freq);
Joel Nider5bd73f82011-12-14 16:53:30 +02001990 }
Liron Kuch229090d2012-10-30 17:47:50 +02001991 channel->int_freq = int_freq;
1992 /*
1993 * it is the responsibility of the caller to tspp_allocate_buffers(),
1994 * whether it's the user or the driver, to make sure the size parameter
1995 * is compatible to the channel mode.
1996 */
1997 channel->buffer_size = size;
Joel Nider5bd73f82011-12-14 16:53:30 +02001998
Liron Kuch229090d2012-10-30 17:47:50 +02001999 /* save user defined memory free function for later use */
2000 channel->memfree = memfree;
2001 channel->user_info = user;
2002
2003 for (channel->buffer_count = 0;
2004 channel->buffer_count < channel->max_buffers;
Joel Nider5bd73f82011-12-14 16:53:30 +02002005 channel->buffer_count++) {
2006
2007 /* allocate the descriptor */
2008 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2009 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2010 if (!desc) {
Liron Kuch229090d2012-10-30 17:47:50 +02002011 pr_warn("%s: Can't allocate desc %i",
2012 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002013 break;
2014 }
2015
2016 desc->desc.id = channel->buffer_count;
2017 /* allocate the buffer */
2018 if (tspp_alloc_buffer(channel_id, &desc->desc,
2019 channel->buffer_size, alloc, user) != 0) {
2020 kfree(desc);
Liron Kuch229090d2012-10-30 17:47:50 +02002021 pr_warn("%s: Can't allocate buffer %i",
2022 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002023 break;
2024 }
2025
2026 /* add the descriptor to the list */
2027 desc->filled = 0;
2028 desc->read_index = 0;
2029 if (!channel->data) {
2030 channel->data = desc;
2031 desc->next = channel->data;
2032 } else {
2033 last->next = desc;
2034 }
2035 last = desc;
2036 desc->next = channel->data;
2037
2038 /* prepare the sps descriptor */
2039 desc->sps.phys_base = desc->desc.phys_base;
2040 desc->sps.base = desc->desc.virt_base;
2041 desc->sps.size = desc->desc.size;
2042
2043 /* start the transfer */
2044 if (tspp_queue_buffer(channel, desc))
Liron Kuch229090d2012-10-30 17:47:50 +02002045 pr_err("%s: can't queue buffer %i",
2046 __func__, desc->desc.id);
2047 }
2048
2049 if (channel->buffer_count < channel->max_buffers) {
2050 /*
2051 * we failed to allocate the requested number of buffers.
2052 * we don't allow a partial success, so need to clean up here.
2053 */
2054 tspp_destroy_buffers(channel_id, channel);
2055 channel->buffer_count = 0;
2056 return -ENOMEM;
Joel Nider5bd73f82011-12-14 16:53:30 +02002057 }
2058
2059 channel->waiting = channel->data;
2060 channel->read = channel->data;
2061 channel->locked = channel->data;
Liron Kuch229090d2012-10-30 17:47:50 +02002062
Joel Nider5bd73f82011-12-14 16:53:30 +02002063 return 0;
2064}
2065EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002066
2067/*** File Operations ***/
2068static ssize_t tspp_open(struct inode *inode, struct file *filp)
2069{
Joel Nider5bd73f82011-12-14 16:53:30 +02002070 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002071 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002072
2073 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002074 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2075 filp->private_data = channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002076 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002077
2078 /* if this channel is already in use, quit */
2079 if (channel->used) {
2080 pr_err("tspp channel %i already in use",
2081 MINOR(channel->cdev.dev));
2082 return -EACCES;
2083 }
2084
Joel Nider5bd73f82011-12-14 16:53:30 +02002085 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002086 pr_err("tspp: error opening channel");
2087 return -EACCES;
2088 }
2089
2090 return 0;
2091}
2092
2093static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2094{
2095 unsigned long flags;
2096 unsigned int mask = 0;
2097 struct tspp_channel *channel;
2098 channel = filp->private_data;
2099
2100 /* register the wait queue for this channel */
2101 poll_wait(filp, &channel->in_queue, p);
2102
2103 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider5bd73f82011-12-14 16:53:30 +02002104 if (channel->read &&
2105 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002106 mask = POLLIN | POLLRDNORM;
2107
2108 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2109
2110 return mask;
2111}
2112
2113static ssize_t tspp_release(struct inode *inode, struct file *filp)
2114{
Joel Nider5bd73f82011-12-14 16:53:30 +02002115 struct tspp_channel *channel = filp->private_data;
2116 u32 dev = channel->pdev->pdev->id;
2117 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002118
Joel Nider5bd73f82011-12-14 16:53:30 +02002119 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002120
2121 return 0;
2122}
2123
2124static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2125 loff_t *f_pos)
2126{
2127 size_t size = 0;
2128 size_t transferred = 0;
2129 struct tspp_channel *channel;
2130 struct tspp_mem_buffer *buffer;
2131 channel = filp->private_data;
2132
2133 TSPP_DEBUG("tspp_read");
Joel Nider5bd73f82011-12-14 16:53:30 +02002134
2135 while (!channel->read) {
2136 if (filp->f_flags & O_NONBLOCK) {
2137 pr_warn("tspp: no buffer on channel %i!",
2138 channel->id);
2139 return -EAGAIN;
2140 }
2141 /* go to sleep if there is nothing to read */
2142 if (wait_event_interruptible(channel->in_queue,
2143 (channel->read != NULL))) {
2144 pr_err("tspp: rude awakening\n");
2145 return -ERESTARTSYS;
2146 }
2147 }
2148
2149 buffer = channel->read;
2150
Joel Nider5556a852011-10-16 10:52:13 +02002151 /* see if we have any buffers ready to read */
2152 while (buffer->state != TSPP_BUF_STATE_DATA) {
2153 if (filp->f_flags & O_NONBLOCK) {
2154 pr_warn("tspp: nothing to read on channel %i!",
2155 channel->id);
2156 return -EAGAIN;
2157 }
2158 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002159 if (wait_event_interruptible(channel->in_queue,
2160 (buffer->state == TSPP_BUF_STATE_DATA))) {
2161 pr_err("tspp: rude awakening\n");
2162 return -ERESTARTSYS;
2163 }
2164 }
2165
2166 while (buffer->state == TSPP_BUF_STATE_DATA) {
2167 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002168 if (size == 0)
2169 break;
2170
Joel Nider5bd73f82011-12-14 16:53:30 +02002171 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002172 buffer->read_index, size)) {
2173 pr_err("tspp: error copying to user buffer");
Joel Nider5bd73f82011-12-14 16:53:30 +02002174 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002175 }
2176 buf += size;
2177 count -= size;
2178 transferred += size;
2179 buffer->read_index += size;
2180
Liron Kuch229090d2012-10-30 17:47:50 +02002181 /*
2182 * after reading the end of the buffer, requeue it,
2183 * and set up for reading the next one
2184 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002185 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002186 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5bd73f82011-12-14 16:53:30 +02002187 if (tspp_queue_buffer(channel, buffer))
2188 pr_err("tspp: can't submit transfer");
2189 channel->locked = channel->read;
2190 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002191 }
2192 }
2193
2194 return transferred;
2195}
2196
2197static long tspp_ioctl(struct file *filp,
2198 unsigned int param0, unsigned long param1)
2199{
Joel Nider5bd73f82011-12-14 16:53:30 +02002200 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002201 int rc = -1;
2202 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002203 struct tspp_select_source ss;
2204 struct tspp_filter f;
2205 struct tspp_key k;
2206 struct tspp_iv iv;
2207 struct tspp_system_keys sk;
2208 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002209 channel = filp->private_data;
Joel Nider5bd73f82011-12-14 16:53:30 +02002210 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002211
2212 if (!param1)
2213 return -EINVAL;
2214
2215 switch (param0) {
2216 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002217 if (!access_ok(VERIFY_READ, param1,
2218 sizeof(struct tspp_select_source))) {
2219 return -EBUSY;
2220 }
2221 if (__copy_from_user(&ss, (void *)param1,
2222 sizeof(struct tspp_select_source)) == 0)
2223 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002224 break;
2225 case TSPP_IOCTL_ADD_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002226 if (!access_ok(VERIFY_READ, param1,
2227 sizeof(struct tspp_filter))) {
2228 return -ENOSR;
2229 }
2230 if (__copy_from_user(&f, (void *)param1,
2231 sizeof(struct tspp_filter)) == 0)
2232 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002233 break;
2234 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002235 if (!access_ok(VERIFY_READ, param1,
2236 sizeof(struct tspp_filter))) {
2237 return -EBUSY;
2238 }
2239 if (__copy_from_user(&f, (void *)param1,
2240 sizeof(struct tspp_filter)) == 0)
2241 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002242 break;
2243 case TSPP_IOCTL_SET_KEY:
Joel Nider5bd73f82011-12-14 16:53:30 +02002244 if (!access_ok(VERIFY_READ, param1,
2245 sizeof(struct tspp_key))) {
2246 return -EBUSY;
2247 }
2248 if (__copy_from_user(&k, (void *)param1,
2249 sizeof(struct tspp_key)) == 0)
2250 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002251 break;
2252 case TSPP_IOCTL_SET_IV:
Joel Nider5bd73f82011-12-14 16:53:30 +02002253 if (!access_ok(VERIFY_READ, param1,
2254 sizeof(struct tspp_iv))) {
2255 return -EBUSY;
2256 }
2257 if (__copy_from_user(&iv, (void *)param1,
2258 sizeof(struct tspp_iv)) == 0)
2259 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002260 break;
2261 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider5bd73f82011-12-14 16:53:30 +02002262 if (!access_ok(VERIFY_READ, param1,
2263 sizeof(struct tspp_system_keys))) {
2264 return -EINVAL;
2265 }
2266 if (__copy_from_user(&sk, (void *)param1,
2267 sizeof(struct tspp_system_keys)) == 0)
2268 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002269 break;
2270 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002271 if (!access_ok(VERIFY_READ, param1,
2272 sizeof(struct tspp_buffer))) {
2273 rc = -EINVAL;
2274 }
2275 if (__copy_from_user(&b, (void *)param1,
2276 sizeof(struct tspp_buffer)) == 0)
2277 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002278 break;
2279 default:
2280 pr_err("tspp: Unknown ioctl %i", param0);
2281 }
2282
Liron Kuch229090d2012-10-30 17:47:50 +02002283 /*
2284 * normalize the return code in case one of the subfunctions does
2285 * something weird
2286 */
Joel Nider5556a852011-10-16 10:52:13 +02002287 if (rc != 0)
Joel Nider5bd73f82011-12-14 16:53:30 +02002288 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002289
2290 return rc;
2291}
2292
2293/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002294static int debugfs_iomem_x32_set(void *data, u64 val)
2295{
2296 writel_relaxed(val, data);
2297 wmb();
2298 return 0;
2299}
2300
2301static int debugfs_iomem_x32_get(void *data, u64 *val)
2302{
2303 *val = readl_relaxed(data);
2304 return 0;
2305}
2306
2307DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2308 debugfs_iomem_x32_set, "0x%08llx");
2309
2310static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2311 int instance)
2312{
2313 char name[10];
2314 snprintf(name, 10, "tsif%i", instance);
2315 tsif_device->dent_tsif = debugfs_create_dir(
2316 name, NULL);
2317 if (tsif_device->dent_tsif) {
2318 int i;
2319 void __iomem *base = tsif_device->base;
2320 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2321 tsif_device->debugfs_tsif_regs[i] =
2322 debugfs_create_file(
2323 debugfs_tsif_regs[i].name,
2324 debugfs_tsif_regs[i].mode,
2325 tsif_device->dent_tsif,
2326 base + debugfs_tsif_regs[i].offset,
2327 &fops_iomem_x32);
2328 }
2329 }
2330}
2331
2332static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2333{
2334 if (tsif_device->dent_tsif) {
2335 int i;
2336 debugfs_remove_recursive(tsif_device->dent_tsif);
2337 tsif_device->dent_tsif = NULL;
2338 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2339 tsif_device->debugfs_tsif_regs[i] = NULL;
2340 }
2341}
2342
2343static void tspp_debugfs_init(struct tspp_device *device, int instance)
2344{
2345 char name[10];
2346 snprintf(name, 10, "tspp%i", instance);
2347 device->dent = debugfs_create_dir(
2348 name, NULL);
2349 if (device->dent) {
2350 int i;
2351 void __iomem *base = device->base;
2352 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2353 device->debugfs_regs[i] =
2354 debugfs_create_file(
2355 debugfs_tspp_regs[i].name,
2356 debugfs_tspp_regs[i].mode,
2357 device->dent,
2358 base + debugfs_tspp_regs[i].offset,
2359 &fops_iomem_x32);
2360 }
2361 }
2362}
2363
2364static void tspp_debugfs_exit(struct tspp_device *device)
2365{
2366 if (device->dent) {
2367 int i;
2368 debugfs_remove_recursive(device->dent);
2369 device->dent = NULL;
2370 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2371 device->debugfs_regs[i] = NULL;
2372 }
2373}
Joel Nider5556a852011-10-16 10:52:13 +02002374
2375static int __devinit msm_tspp_probe(struct platform_device *pdev)
2376{
2377 int rc = -ENODEV;
2378 u32 version;
Liron Kuch229090d2012-10-30 17:47:50 +02002379 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002380 struct msm_tspp_platform_data *data;
2381 struct tspp_device *device;
2382 struct resource *mem_tsif0;
2383 struct resource *mem_tsif1;
2384 struct resource *mem_tspp;
2385 struct resource *mem_bam;
Liron Kuch229090d2012-10-30 17:47:50 +02002386 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002387
2388 /* must have platform data */
2389 data = pdev->dev.platform_data;
2390 if (!data) {
2391 pr_err("tspp: Platform data not available");
2392 rc = -EINVAL;
2393 goto out;
2394 }
2395
2396 /* check for valid device id */
Joel Nider5bd73f82011-12-14 16:53:30 +02002397 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002398 pr_err("tspp: Invalid device ID %d", pdev->id);
2399 rc = -EINVAL;
2400 goto out;
2401 }
2402
2403 /* OK, we will use this device */
2404 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2405 if (!device) {
2406 pr_err("tspp: Failed to allocate memory for device");
2407 rc = -ENOMEM;
2408 goto out;
2409 }
2410
2411 /* set up references */
2412 device->pdev = pdev;
2413 platform_set_drvdata(pdev, device);
2414
2415 /* map clocks */
2416 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002417 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02002418 if (IS_ERR(device->tsif_pclk)) {
2419 pr_err("tspp: failed to get %s",
2420 data->tsif_pclk);
2421 rc = PTR_ERR(device->tsif_pclk);
2422 device->tsif_pclk = NULL;
2423 goto err_pclock;
2424 }
2425 }
2426 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002427 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02002428 if (IS_ERR(device->tsif_ref_clk)) {
2429 pr_err("tspp: failed to get %s",
2430 data->tsif_ref_clk);
2431 rc = PTR_ERR(device->tsif_ref_clk);
2432 device->tsif_ref_clk = NULL;
2433 goto err_refclock;
2434 }
2435 }
2436
2437 /* map I/O memory */
2438 mem_tsif0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2439 if (!mem_tsif0) {
2440 pr_err("tspp: Missing tsif0 MEM resource");
2441 rc = -ENXIO;
2442 goto err_res_tsif0;
2443 }
2444 device->tsif[0].base = ioremap(mem_tsif0->start,
2445 resource_size(mem_tsif0));
2446 if (!device->tsif[0].base) {
2447 pr_err("tspp: ioremap failed");
2448 goto err_map_tsif0;
2449 }
2450
2451 mem_tsif1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2452 if (!mem_tsif1) {
2453 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
2454 rc = -ENXIO;
2455 goto err_res_tsif1;
2456 }
2457 device->tsif[1].base = ioremap(mem_tsif1->start,
2458 resource_size(mem_tsif1));
2459 if (!device->tsif[1].base) {
2460 dev_err(&pdev->dev, "ioremap failed");
2461 goto err_map_tsif1;
2462 }
2463
2464 mem_tspp = platform_get_resource(pdev, IORESOURCE_MEM, 2);
2465 if (!mem_tspp) {
2466 dev_err(&pdev->dev, "Missing MEM resource");
2467 rc = -ENXIO;
2468 goto err_res_dev;
2469 }
2470 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
2471 if (!device->base) {
2472 dev_err(&pdev->dev, "ioremap failed");
2473 goto err_map_dev;
2474 }
2475
2476 mem_bam = platform_get_resource(pdev, IORESOURCE_MEM, 3);
2477 if (!mem_bam) {
2478 pr_err("tspp: Missing bam MEM resource");
2479 rc = -ENXIO;
2480 goto err_res_bam;
2481 }
2482 memset(&device->bam_props, 0, sizeof(device->bam_props));
2483 device->bam_props.phys_addr = mem_bam->start;
2484 device->bam_props.virt_addr = ioremap(mem_bam->start,
2485 resource_size(mem_bam));
2486 if (!device->bam_props.virt_addr) {
2487 dev_err(&pdev->dev, "ioremap failed");
2488 goto err_map_bam;
2489 }
2490
2491 /* map TSPP IRQ */
2492 rc = platform_get_irq(pdev, 0);
2493 if (rc > 0) {
2494 device->tspp_irq = rc;
2495 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
2496 dev_name(&pdev->dev), device);
2497 if (rc) {
2498 dev_err(&pdev->dev, "failed to request IRQ %d : %d",
2499 device->tspp_irq, rc);
2500 goto err_irq;
2501 }
2502 } else {
2503 dev_err(&pdev->dev, "failed to get tspp IRQ");
2504 goto err_irq;
2505 }
2506
2507 /* BAM IRQ */
2508 device->bam_irq = TSIF_BAM_IRQ;
2509
2510 /* GPIOs */
2511 rc = tspp_start_gpios(device);
2512 if (rc)
2513 goto err_gpio;
2514
2515 /* power management */
2516 pm_runtime_set_active(&pdev->dev);
2517 pm_runtime_enable(&pdev->dev);
2518
Joel Nider5556a852011-10-16 10:52:13 +02002519 tspp_debugfs_init(device, 0);
2520
2521 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2522 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02002523
2524 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
2525 dev_name(&pdev->dev));
2526
2527 /* set up pointers to ram-based 'registers' */
Joel Nider5bd73f82011-12-14 16:53:30 +02002528 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
2529 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
2530 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
2531 device->tspp_key_table = device->base + TSPP_DATA_KEY;
2532 device->tspp_global_performance =
2533 device->base + TSPP_GLOBAL_PERFORMANCE;
2534 device->tspp_pipe_context =
2535 device->base + TSPP_PIPE_CONTEXT;
2536 device->tspp_pipe_performance =
2537 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02002538
2539 device->bam_props.summing_threshold = 0x10;
2540 device->bam_props.irq = device->bam_irq;
2541 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
2542
2543 if (sps_register_bam_device(&device->bam_props,
2544 &device->bam_handle) != 0) {
2545 pr_err("tspp: failed to register bam");
2546 goto err_bam;
2547 }
2548
Joel Nider5bd73f82011-12-14 16:53:30 +02002549 if (tspp_clock_start(device) != 0) {
2550 dev_err(&pdev->dev, "Can't start clocks");
2551 goto err_clock;
Joel Nider5556a852011-10-16 10:52:13 +02002552 }
2553
2554 spin_lock_init(&device->spinlock);
2555 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
2556 (unsigned long)device);
2557
2558 /* initialize everything to a known state */
2559 tspp_global_reset(device);
2560
2561 version = readl_relaxed(device->base + TSPP_VERSION);
2562 if (version != 1)
2563 pr_warn("tspp: unrecognized hw version=%i", version);
2564
Joel Nider5bd73f82011-12-14 16:53:30 +02002565 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02002566 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002567 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
2568 pr_err("tspp_channel_init failed");
2569 goto err_channel;
2570 }
Joel Nider5556a852011-10-16 10:52:13 +02002571 }
2572
Joel Nider5bd73f82011-12-14 16:53:30 +02002573 /* stop the clocks for power savings */
2574 tspp_clock_stop(device);
2575
2576 /* everything is ok, so add the device to the list */
2577 list_add_tail(&(device->devlist), &tspp_devices);
2578
Joel Nider5556a852011-10-16 10:52:13 +02002579 return 0;
2580
Joel Nider5bd73f82011-12-14 16:53:30 +02002581err_channel:
Liron Kuch229090d2012-10-30 17:47:50 +02002582 /* uninitialize channels */
2583 for (j = 0; j < i; j++) {
2584 channel = &(device->channels[i]);
2585 device_destroy(tspp_class, channel->cdev.dev);
2586 cdev_del(&channel->cdev);
2587 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002588err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02002589 sps_deregister_bam_device(device->bam_handle);
2590err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02002591 tspp_debugfs_exit(device);
2592 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2593 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02002594err_gpio:
2595err_irq:
2596 tspp_stop_gpios(device);
2597 iounmap(device->bam_props.virt_addr);
2598err_map_bam:
2599err_res_bam:
2600 iounmap(device->base);
2601err_map_dev:
2602err_res_dev:
2603 iounmap(device->tsif[1].base);
2604err_map_tsif1:
2605err_res_tsif1:
2606 iounmap(device->tsif[0].base);
2607err_map_tsif0:
2608err_res_tsif0:
2609 if (device->tsif_ref_clk)
2610 clk_put(device->tsif_ref_clk);
2611err_refclock:
2612 if (device->tsif_pclk)
2613 clk_put(device->tsif_pclk);
2614err_pclock:
2615 kfree(device);
2616
2617out:
2618 return rc;
2619}
2620
2621static int __devexit msm_tspp_remove(struct platform_device *pdev)
2622{
Joel Nider5bd73f82011-12-14 16:53:30 +02002623 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002624 u32 i;
Joel Nider5556a852011-10-16 10:52:13 +02002625
2626 struct tspp_device *device = platform_get_drvdata(pdev);
2627
Joel Nider5bd73f82011-12-14 16:53:30 +02002628 /* free the buffers, and delete the channels */
2629 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
2630 channel = &device->channels[i];
2631 tspp_close_channel(device->pdev->id, i);
2632 device_destroy(tspp_class, channel->cdev.dev);
2633 cdev_del(&channel->cdev);
2634 }
2635
Joel Nider5556a852011-10-16 10:52:13 +02002636 sps_deregister_bam_device(device->bam_handle);
2637
Joel Nider5556a852011-10-16 10:52:13 +02002638 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2639 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02002640
2641 wake_lock_destroy(&device->wake_lock);
2642 free_irq(device->tspp_irq, device);
2643 tspp_stop_gpios(device);
2644
2645 iounmap(device->bam_props.virt_addr);
2646 iounmap(device->base);
2647 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2648 iounmap(device->tsif[i].base);
2649
2650 if (device->tsif_ref_clk)
2651 clk_put(device->tsif_ref_clk);
2652
2653 if (device->tsif_pclk)
2654 clk_put(device->tsif_pclk);
2655
2656 pm_runtime_disable(&pdev->dev);
2657 pm_runtime_put(&pdev->dev);
2658 kfree(device);
2659
2660 return 0;
2661}
2662
2663/*** power management ***/
2664
2665static int tspp_runtime_suspend(struct device *dev)
2666{
2667 dev_dbg(dev, "pm_runtime: suspending...");
2668 return 0;
2669}
2670
2671static int tspp_runtime_resume(struct device *dev)
2672{
2673 dev_dbg(dev, "pm_runtime: resuming...");
2674 return 0;
2675}
2676
2677static const struct dev_pm_ops tspp_dev_pm_ops = {
2678 .runtime_suspend = tspp_runtime_suspend,
2679 .runtime_resume = tspp_runtime_resume,
2680};
2681
2682static struct platform_driver msm_tspp_driver = {
2683 .probe = msm_tspp_probe,
2684 .remove = __exit_p(msm_tspp_remove),
2685 .driver = {
2686 .name = "msm_tspp",
2687 .pm = &tspp_dev_pm_ops,
2688 },
2689};
2690
2691
2692static int __init mod_init(void)
2693{
Joel Nider5556a852011-10-16 10:52:13 +02002694 int rc;
2695
Joel Nider5bd73f82011-12-14 16:53:30 +02002696 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02002697 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
2698 if (rc) {
2699 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
2700 goto err_devrgn;
2701 }
2702
2703 tspp_class = class_create(THIS_MODULE, "tspp");
2704 if (IS_ERR(tspp_class)) {
2705 rc = PTR_ERR(tspp_class);
2706 pr_err("tspp: Error creating class: %d", rc);
2707 goto err_class;
2708 }
2709
Joel Nider5bd73f82011-12-14 16:53:30 +02002710 /* register the driver, and check hardware */
2711 rc = platform_driver_register(&msm_tspp_driver);
2712 if (rc) {
2713 pr_err("tspp: platform_driver_register failed: %d", rc);
2714 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02002715 }
2716
2717 return 0;
2718
Joel Nider5bd73f82011-12-14 16:53:30 +02002719err_register:
2720 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02002721err_class:
2722 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
2723err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02002724 return rc;
2725}
2726
2727static void __exit mod_exit(void)
2728{
Joel Nider5bd73f82011-12-14 16:53:30 +02002729 /* delete low level driver */
2730 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02002731
Joel Nider5bd73f82011-12-14 16:53:30 +02002732 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02002733 class_destroy(tspp_class);
2734 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02002735}
2736
2737module_init(mod_init);
2738module_exit(mod_exit);
2739
Joel Nider5bd73f82011-12-14 16:53:30 +02002740MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02002741MODULE_LICENSE("GPL v2");