blob: f31052435d77beab9067c4e2df35cac26f7ea38e [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;
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200330 u32 tsif_irq;
Joel Nider5556a852011-10-16 10:52:13 +0200331
332 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200333 struct dentry *dent_tsif;
334 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200335 u32 stat_rx;
336 u32 stat_overflow;
337 u32 stat_lost_sync;
338 u32 stat_timeout;
Joel Nider5556a852011-10-16 10:52:13 +0200339};
340
341enum tspp_buf_state {
342 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
343 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider5bd73f82011-12-14 16:53:30 +0200344 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
345 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200346};
347
348struct tspp_mem_buffer {
Joel Nider5bd73f82011-12-14 16:53:30 +0200349 struct tspp_mem_buffer *next;
350 struct sps_mem_buffer sps;
351 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200352 enum tspp_buf_state state;
353 size_t filled; /* how much data this buffer is holding */
354 int read_index; /* where to start reading data from */
355};
356
357/* this represents each char device 'channel' */
358struct tspp_channel {
359 struct cdev cdev;
360 struct device *dd;
Joel Nider5bd73f82011-12-14 16:53:30 +0200361 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200362 struct sps_pipe *pipe;
363 struct sps_connect config;
364 struct sps_register_event event;
Joel Nider5bd73f82011-12-14 16:53:30 +0200365 struct tspp_mem_buffer *data; /* list of buffers */
366 struct tspp_mem_buffer *read; /* first buffer ready to be read */
367 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
368 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200369 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider5bd73f82011-12-14 16:53:30 +0200370 u32 id; /* channel id (0-15) */
371 int used; /* is this channel in use? */
372 int key; /* which encryption key index is used */
373 u32 buffer_size; /* size of the sps transfer buffers */
374 u32 max_buffers; /* how many buffers should be allocated */
375 u32 buffer_count; /* how many buffers are actually allocated */
376 u32 filter_count; /* how many filters have been added to this channel */
377 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200378 enum tspp_source src;
379 enum tspp_mode mode;
Joel Nider5bd73f82011-12-14 16:53:30 +0200380 tspp_notifier *notifier; /* used only with kernel api */
381 void *notify_data; /* data to be passed with the notifier */
382 u32 notify_timer; /* notification for partially filled buffers */
Liron Kuch229090d2012-10-30 17:47:50 +0200383 tspp_memfree *memfree; /* user defined memory free function */
384 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200385};
386
387struct tspp_pid_filter_table {
388 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
389};
390
391struct tspp_key_entry {
392 u32 even_lsb;
393 u32 even_msb;
394 u32 odd_lsb;
395 u32 odd_msb;
396};
397
398struct tspp_key_table {
399 struct tspp_key_entry entry[TSPP_NUM_KEYS];
400};
401
Joel Nider5bd73f82011-12-14 16:53:30 +0200402/* this represents the actual hardware device */
403struct tspp_device {
404 struct list_head devlist; /* list of all devices */
405 struct platform_device *pdev;
406 void __iomem *base;
407 unsigned int tspp_irq;
408 unsigned int bam_irq;
409 u32 bam_handle;
410 struct sps_bam_props bam_props;
411 struct wake_lock wake_lock;
412 spinlock_t spinlock;
413 struct tasklet_struct tlet;
414 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
415 /* clocks */
416 struct clk *tsif_pclk;
417 struct clk *tsif_ref_clk;
418 /* data */
419 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
420 struct tspp_channel channels[TSPP_NUM_CHANNELS];
421 struct tspp_key_table *tspp_key_table;
422 struct tspp_global_performance_regs *tspp_global_performance;
423 struct tspp_pipe_context_regs *tspp_pipe_context;
424 struct tspp_pipe_performance_regs *tspp_pipe_performance;
425
426 struct dentry *dent;
427 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
428};
429
430
Joel Nider5556a852011-10-16 10:52:13 +0200431static struct class *tspp_class;
432static int tspp_key_entry;
433static dev_t tspp_minor; /* next minor number to assign */
Joel Nider5bd73f82011-12-14 16:53:30 +0200434
435static LIST_HEAD(tspp_devices);
436
437/* forward declarations */
438static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
439static ssize_t tspp_open(struct inode *inode, struct file *filp);
440static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
441static ssize_t tspp_release(struct inode *inode, struct file *filp);
442static long tspp_ioctl(struct file *, unsigned int, unsigned long);
443
444/* file operations */
445static const struct file_operations tspp_fops = {
446 .owner = THIS_MODULE,
447 .read = tspp_read,
448 .open = tspp_open,
449 .poll = tspp_poll,
450 .release = tspp_release,
451 .unlocked_ioctl = tspp_ioctl,
452};
Joel Nider5556a852011-10-16 10:52:13 +0200453
454/*** IRQ ***/
Joel Nider5bd73f82011-12-14 16:53:30 +0200455static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200456{
Joel Nider5bd73f82011-12-14 16:53:30 +0200457 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200458 u32 status, mask;
459 u32 data;
460
461 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
462 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
463 status &= mask;
464
465 if (!status) {
466 dev_warn(&device->pdev->dev, "Spurious interrupt");
467 return IRQ_NONE;
468 }
469
470 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
471
472 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
473 /* read the key error info */
474 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
475 dev_info(&device->pdev->dev, "key error 0x%x", data);
476 }
477 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
478 data = readl_relaxed(device->base + TSPP_KEY_VALID);
479 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
480 }
481 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
482 dev_info(&device->pdev->dev, "key switched");
483
484 if (status & 0xffff)
Joel Nider5bd73f82011-12-14 16:53:30 +0200485 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200486
487 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200488
489 /*
490 * Before returning IRQ_HANDLED to the generic interrupt handling
491 * framework need to make sure all operations including clearing of
492 * interrupt status registers in the hardware is performed.
493 * Thus a barrier after clearing the interrupt status register
494 * is required to guarantee that the interrupt status register has
495 * really been cleared by the time we return from this handler.
496 */
497 wmb();
498 return IRQ_HANDLED;
499}
500
501static irqreturn_t tsif_isr(int irq, void *dev)
502{
503 struct tspp_tsif_device *tsif_device = dev;
504 u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
505
506 if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
507 TSIF_STS_CTL_OVERFLOW |
508 TSIF_STS_CTL_LOST_SYNC |
509 TSIF_STS_CTL_TIMEOUT)))
510 return IRQ_NONE;
511
512 if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
513 tsif_device->stat_overflow++;
514
515 if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
516 tsif_device->stat_lost_sync++;
517
518 if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
519 tsif_device->stat_timeout++;
520
521 iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
522
523 /*
524 * Before returning IRQ_HANDLED to the generic interrupt handling
525 * framework need to make sure all operations including clearing of
526 * interrupt status registers in the hardware is performed.
527 * Thus a barrier after clearing the interrupt status register
528 * is required to guarantee that the interrupt status register has
529 * really been cleared by the time we return from this handler.
530 */
Joel Nider5556a852011-10-16 10:52:13 +0200531 wmb();
532 return IRQ_HANDLED;
533}
534
535/*** callbacks ***/
536static void tspp_sps_complete_cb(struct sps_event_notify *notify)
537{
Joel Nider5bd73f82011-12-14 16:53:30 +0200538 struct tspp_device *pdev = notify->user;
539 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200540}
541
542/*** tasklet ***/
543static void tspp_sps_complete_tlet(unsigned long data)
544{
545 int i;
546 int complete;
547 unsigned long flags;
548 struct sps_iovec iovec;
549 struct tspp_channel *channel;
550 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200551 spin_lock_irqsave(&device->spinlock, flags);
552
553 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
554 complete = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +0200555 channel = &device->channels[i];
556 if (!channel->used || !channel->waiting)
557 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200558
559 /* get completions */
Joel Nider5bd73f82011-12-14 16:53:30 +0200560 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200561 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
562 pr_err("tspp: Error in iovec on channel %i",
563 channel->id);
564 break;
565 }
566 if (iovec.size == 0)
567 break;
568
Joel Nider5bd73f82011-12-14 16:53:30 +0200569 if (iovec.addr != channel->waiting->sps.phys_base)
Joel Nider5556a852011-10-16 10:52:13 +0200570 pr_err("tspp: buffer mismatch 0x%08x",
Joel Nider5bd73f82011-12-14 16:53:30 +0200571 channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200572
573 complete = 1;
Joel Nider5bd73f82011-12-14 16:53:30 +0200574 channel->waiting->state = TSPP_BUF_STATE_DATA;
575 channel->waiting->filled = iovec.size;
576 channel->waiting->read_index = 0;
577
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200578 if (channel->src == TSPP_SOURCE_TSIF0)
579 device->tsif[0].stat_rx++;
580 else if (channel->src == TSPP_SOURCE_TSIF1)
581 device->tsif[1].stat_rx++;
582
Joel Nider5bd73f82011-12-14 16:53:30 +0200583 /* update the pointers */
584 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200585 }
586
Joel Nider5bd73f82011-12-14 16:53:30 +0200587 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200588 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200589 wake_up_interruptible(&channel->in_queue);
Joel Nider5bd73f82011-12-14 16:53:30 +0200590
591 /* call notifiers */
592 if (channel->notifier)
593 channel->notifier(channel->id,
594 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200595 }
596 }
597
598 spin_unlock_irqrestore(&device->spinlock, flags);
599}
600
601/*** GPIO functions ***/
602static void tspp_gpios_free(const struct msm_gpio *table, int size)
603{
604 int i;
605 const struct msm_gpio *g;
606 for (i = size-1; i >= 0; i--) {
607 g = table + i;
608 gpio_free(GPIO_PIN(g->gpio_cfg));
609 }
610}
611
612static int tspp_gpios_request(const struct msm_gpio *table, int size)
613{
614 int rc;
615 int i;
616 const struct msm_gpio *g;
617 for (i = 0; i < size; i++) {
618 g = table + i;
619 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
620 if (rc) {
621 pr_err("tspp: gpio_request(%d) <%s> failed: %d\n",
622 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
623 goto err;
624 }
625 }
626 return 0;
627err:
628 tspp_gpios_free(table, i);
629 return rc;
630}
631
632static int tspp_gpios_disable(const struct msm_gpio *table, int size)
633{
634 int rc = 0;
635 int i;
636 const struct msm_gpio *g;
637 for (i = size-1; i >= 0; i--) {
638 int tmp;
639 g = table + i;
640 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
641 if (tmp) {
Liron Kuch229090d2012-10-30 17:47:50 +0200642 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200643 g->gpio_cfg, g->label ?: "?", rc);
644 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
645 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
646 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
647 GPIO_DRVSTR(g->gpio_cfg));
648 if (!rc)
649 rc = tmp;
650 }
651 }
652
653 return rc;
654}
655
656static int tspp_gpios_enable(const struct msm_gpio *table, int size)
657{
658 int rc;
659 int i;
660 const struct msm_gpio *g;
661 for (i = 0; i < size; i++) {
662 g = table + i;
663 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
664 if (rc) {
Liron Kuch229090d2012-10-30 17:47:50 +0200665 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200666 g->gpio_cfg, g->label ?: "?", rc);
667 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
668 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
669 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
670 GPIO_DRVSTR(g->gpio_cfg));
671 goto err;
672 }
673 }
674 return 0;
675err:
676 tspp_gpios_disable(table, i);
677 return rc;
678}
679
680static int tspp_gpios_request_enable(const struct msm_gpio *table, int size)
681{
682 int rc = tspp_gpios_request(table, size);
683 if (rc)
684 return rc;
685 rc = tspp_gpios_enable(table, size);
686 if (rc)
687 tspp_gpios_free(table, size);
688 return rc;
689}
690
691static void tspp_gpios_disable_free(const struct msm_gpio *table, int size)
692{
693 tspp_gpios_disable(table, size);
694 tspp_gpios_free(table, size);
695}
696
697static int tspp_start_gpios(struct tspp_device *device)
698{
699 struct msm_tspp_platform_data *pdata =
700 device->pdev->dev.platform_data;
701 return tspp_gpios_request_enable(pdata->gpios, pdata->num_gpios);
702}
703
704static void tspp_stop_gpios(struct tspp_device *device)
705{
706 struct msm_tspp_platform_data *pdata =
707 device->pdev->dev.platform_data;
708 tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios);
709}
710
Joel Nider5bd73f82011-12-14 16:53:30 +0200711/*** Clock functions ***/
712static int tspp_clock_start(struct tspp_device *device)
713{
714 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
715 pr_err("tspp: Can't start pclk");
716 return -EBUSY;
717 }
718
719 if (device->tsif_ref_clk &&
720 clk_prepare_enable(device->tsif_ref_clk) != 0) {
721 pr_err("tspp: Can't start ref clk");
722 clk_disable_unprepare(device->tsif_pclk);
723 return -EBUSY;
724 }
725
726 return 0;
727}
728
729static void tspp_clock_stop(struct tspp_device *device)
730{
731 if (device->tsif_pclk)
732 clk_disable(device->tsif_pclk);
733
734 if (device->tsif_ref_clk)
735 clk_disable(device->tsif_ref_clk);
736}
737
Joel Nider5556a852011-10-16 10:52:13 +0200738/*** TSIF functions ***/
739static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
740{
741 int start_hardware = 0;
742 u32 ctl;
743
744 if (tsif_device->ref_count == 0) {
745 start_hardware = 1;
746 } else if (tsif_device->ref_count > 0) {
747 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
748 if ((ctl & TSIF_STS_CTL_START) != 1) {
749 /* this hardware should already be running */
750 pr_warn("tspp: tsif hw not started but ref count > 0");
751 start_hardware = 1;
752 }
753 }
754
755 if (start_hardware) {
Joel Nider5bd73f82011-12-14 16:53:30 +0200756 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200757 TSIF_STS_CTL_EN_DM;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200758
759 if (tsif_device->clock_inverse)
760 ctl |= TSIF_STS_CTL_INV_CLOCK;
761
762 if (tsif_device->data_inverse)
763 ctl |= TSIF_STS_CTL_INV_DATA;
764
765 if (tsif_device->sync_inverse)
766 ctl |= TSIF_STS_CTL_INV_SYNC;
767
768 if (tsif_device->enable_inverse)
769 ctl |= TSIF_STS_CTL_INV_ENABLE;
770
Joel Nider5bd73f82011-12-14 16:53:30 +0200771 switch (tsif_device->mode) {
772 case TSPP_TSIF_MODE_LOOPBACK:
773 ctl |= TSIF_STS_CTL_EN_NULL |
774 TSIF_STS_CTL_EN_ERROR |
775 TSIF_STS_CTL_TEST_MODE;
776 break;
777 case TSPP_TSIF_MODE_1:
778 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
779 TSIF_STS_CTL_EN_TCR;
780 break;
781 case TSPP_TSIF_MODE_2:
782 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
783 TSIF_STS_CTL_EN_TCR |
784 TSIF_STS_CTL_MODE_2;
785 break;
786 default:
787 pr_warn("tspp: unknown tsif mode 0x%x",
788 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200789 }
790 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
791 writel_relaxed(tsif_device->time_limit,
792 tsif_device->base + TSIF_TIME_LIMIT_OFF);
793 wmb();
794 writel_relaxed(ctl | TSIF_STS_CTL_START,
795 tsif_device->base + TSIF_STS_CTL_OFF);
796 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200797 }
798
Joel Nider5bd73f82011-12-14 16:53:30 +0200799 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Joel Nider5556a852011-10-16 10:52:13 +0200800 tsif_device->ref_count++;
801
Joel Nider5bd73f82011-12-14 16:53:30 +0200802 return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200803}
804
805static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
806{
807 if (tsif_device->ref_count == 0)
808 return;
809
810 tsif_device->ref_count--;
811
812 if (tsif_device->ref_count == 0) {
813 writel_relaxed(TSIF_STS_CTL_STOP,
814 tsif_device->base + TSIF_STS_CTL_OFF);
815 wmb();
816 }
817}
818
Joel Nider5bd73f82011-12-14 16:53:30 +0200819/*** local TSPP functions ***/
820static int tspp_channels_in_use(struct tspp_device *pdev)
821{
822 int i;
823 int count = 0;
824 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
825 count += (pdev->channels[i].used ? 1 : 0);
826
827 return count;
828}
829
830static struct tspp_device *tspp_find_by_id(int id)
831{
832 struct tspp_device *dev;
833 list_for_each_entry(dev, &tspp_devices, devlist) {
834 if (dev->pdev->id == id)
835 return dev;
836 }
837 return NULL;
838}
839
Joel Nider5556a852011-10-16 10:52:13 +0200840static int tspp_get_key_entry(void)
841{
842 int i;
843 for (i = 0; i < TSPP_NUM_KEYS; i++) {
844 if (!(tspp_key_entry & (1 << i))) {
845 tspp_key_entry |= (1 << i);
846 return i;
847 }
848 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200849 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200850}
851
852static void tspp_free_key_entry(int entry)
853{
854 if (entry > TSPP_NUM_KEYS) {
855 pr_err("tspp_free_key_entry: index out of bounds");
856 return;
857 }
858
859 tspp_key_entry &= ~(1 << entry);
860}
861
Joel Nider5bd73f82011-12-14 16:53:30 +0200862static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
863 u32 size, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200864{
Joel Nider5bd73f82011-12-14 16:53:30 +0200865 if (size < TSPP_MIN_BUFFER_SIZE ||
866 size > TSPP_MAX_BUFFER_SIZE) {
867 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200868 return -ENOMEM;
869 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200870
871 if (alloc) {
872 TSPP_DEBUG("tspp using alloc function");
873 desc->virt_base = alloc(channel_id, size,
874 &desc->phys_base, user);
875 } else {
Liron Kuch229090d2012-10-30 17:47:50 +0200876 desc->virt_base = dma_alloc_coherent(NULL, size,
877 &desc->phys_base, GFP_KERNEL);
878 if (desc->virt_base == 0) {
879 pr_err("tspp dma alloc coherent failed %i", size);
880 return -ENOMEM;
881 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200882 }
883
884 desc->size = size;
885 return 0;
886}
887
888static int tspp_queue_buffer(struct tspp_channel *channel,
889 struct tspp_mem_buffer *buffer)
890{
891 int rc;
892 u32 flags = 0;
893
894 /* make sure the interrupt frequency is valid */
895 if (channel->int_freq < 1)
896 channel->int_freq = 1;
897
898 /* generate interrupt according to requested frequency */
899 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
900 flags = SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOB;
901
902 /* start the transfer */
903 rc = sps_transfer_one(channel->pipe,
904 buffer->sps.phys_base,
905 buffer->sps.size,
906 channel->pdev,
907 flags);
908 if (rc < 0)
909 return rc;
910
911 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +0200912
913 return 0;
914}
915
916static int tspp_global_reset(struct tspp_device *pdev)
917{
918 u32 i, val;
919
920 /* stop all TSIFs */
921 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
922 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
923 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
924 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200925 pdev->tsif[i].clock_inverse = 0;
926 pdev->tsif[i].data_inverse = 0;
927 pdev->tsif[i].sync_inverse = 0;
928 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +0200929 }
930 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
931 wmb();
932
933 /* BAM */
934 if (sps_device_reset(pdev->bam_handle) != 0) {
935 pr_err("tspp: error resetting bam");
Joel Nider5bd73f82011-12-14 16:53:30 +0200936 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200937 }
938
939 /* TSPP tables */
940 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider5bd73f82011-12-14 16:53:30 +0200941 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +0200942 0, sizeof(struct tspp_pid_filter_table));
943
944 /* disable all filters */
945 val = (2 << TSPP_NUM_CHANNELS) - 1;
946 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
947
948 /* TSPP registers */
949 val = readl_relaxed(pdev->base + TSPP_CONTROL);
950 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
951 pdev->base + TSPP_CONTROL);
952 wmb();
Joel Nider5bd73f82011-12-14 16:53:30 +0200953 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200954 sizeof(struct tspp_global_performance_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +0200955 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200956 sizeof(struct tspp_pipe_context_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +0200957 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +0200958 sizeof(struct tspp_pipe_performance_regs));
959 wmb();
960 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
961 pdev->base + TSPP_CONTROL);
962 wmb();
963
964 val = readl_relaxed(pdev->base + TSPP_CONFIG);
965 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
966 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
967 TSPP_CONFIG_PS_CONT_ERR_MASK);
968 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
969 writel_relaxed(val, pdev->base + TSPP_CONFIG);
970 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_MASK);
971 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
972 writel_relaxed(0, pdev->base + TSPP_RST);
973 wmb();
974
975 tspp_key_entry = 0;
976
977 return 0;
978}
979
Joel Nider5bd73f82011-12-14 16:53:30 +0200980static int tspp_select_source(u32 dev, u32 channel_id,
981 struct tspp_select_source *src)
982{
983 /* make sure the requested src id is in bounds */
984 if (src->source > TSPP_SOURCE_MEM) {
985 pr_err("tspp source out of bounds");
986 return -EINVAL;
987 }
988
989 /* open the stream */
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200990 tspp_open_stream(dev, channel_id, src);
Joel Nider5bd73f82011-12-14 16:53:30 +0200991
992 return 0;
993}
994
995static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
996{
997 struct tspp_device *pdev = channel->pdev;
998
999 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
1000 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
1001 return 0;
1002}
1003
1004static int tspp_set_system_keys(struct tspp_channel *channel,
1005 struct tspp_system_keys *keys)
1006{
1007 int i;
1008 struct tspp_device *pdev = channel->pdev;
1009
1010 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
1011 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
1012
1013 return 0;
1014}
1015
1016static int tspp_channel_init(struct tspp_channel *channel,
1017 struct tspp_device *pdev)
1018{
1019 channel->cdev.owner = THIS_MODULE;
1020 cdev_init(&channel->cdev, &tspp_fops);
1021 channel->pdev = pdev;
1022 channel->data = NULL;
1023 channel->read = NULL;
1024 channel->waiting = NULL;
1025 channel->locked = NULL;
1026 channel->id = MINOR(tspp_minor);
1027 channel->used = 0;
1028 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1029 channel->max_buffers = TSPP_NUM_BUFFERS;
1030 channel->buffer_count = 0;
1031 channel->filter_count = 0;
1032 channel->int_freq = 1;
Liron Kuch229090d2012-10-30 17:47:50 +02001033 channel->src = TSPP_SOURCE_NONE;
1034 channel->mode = TSPP_MODE_DISABLED;
Joel Nider5bd73f82011-12-14 16:53:30 +02001035 channel->notifier = NULL;
1036 channel->notify_data = NULL;
1037 channel->notify_timer = 0;
Liron Kuch229090d2012-10-30 17:47:50 +02001038 channel->memfree = NULL;
1039 channel->user_info = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001040 init_waitqueue_head(&channel->in_queue);
1041
1042 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
1043 pr_err("tspp: cdev_add failed");
1044 return -EBUSY;
1045 }
1046
1047 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
1048 channel, "tspp%02d", channel->id);
1049 if (IS_ERR(channel->dd)) {
1050 pr_err("tspp: device_create failed: %i",
1051 (int)PTR_ERR(channel->dd));
1052 cdev_del(&channel->cdev);
1053 return -EBUSY;
1054 }
1055
1056 return 0;
1057}
1058
1059static int tspp_set_buffer_size(struct tspp_channel *channel,
1060 struct tspp_buffer *buf)
1061{
Liron Kuch229090d2012-10-30 17:47:50 +02001062 if (channel->buffer_count > 0) {
1063 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1064 return -EPERM;
1065 }
1066
Joel Nider5bd73f82011-12-14 16:53:30 +02001067 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1068 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1069 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1070 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1071 else
1072 channel->buffer_size = buf->size;
1073
1074 return 0;
1075}
1076
1077static void tspp_set_tsif_mode(struct tspp_channel *channel,
1078 enum tspp_tsif_mode mode)
1079{
1080 int index;
1081
1082 switch (channel->src) {
1083 case TSPP_SOURCE_TSIF0:
1084 index = 0;
1085 break;
1086 case TSPP_SOURCE_TSIF1:
1087 index = 1;
1088 break;
1089 default:
1090 pr_warn("tspp: can't set mode for non-tsif source %d",
1091 channel->src);
1092 return;
1093 }
1094 channel->pdev->tsif[index].mode = mode;
1095}
1096
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001097static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch229090d2012-10-30 17:47:50 +02001098 int clock_inverse, int data_inverse,
1099 int sync_inverse, int enable_inverse)
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001100{
1101 int index;
1102
1103 switch (channel->src) {
1104 case TSPP_SOURCE_TSIF0:
1105 index = 0;
1106 break;
1107 case TSPP_SOURCE_TSIF1:
1108 index = 1;
1109 break;
1110 default:
1111 return;
1112 }
1113 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1114 channel->pdev->tsif[index].data_inverse = data_inverse;
1115 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1116 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1117}
1118
Liron Kuch229090d2012-10-30 17:47:50 +02001119static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1120{
1121 u32 alignment;
1122
1123 switch (mode) {
1124 case TSPP_MODE_RAW:
1125 /* must be a multiple of 192 */
1126 alignment = (TSPP_PACKET_LENGTH + 4);
1127 if (size % alignment)
1128 return 0;
1129 return 1;
1130
1131 case TSPP_MODE_RAW_NO_SUFFIX:
1132 /* must be a multiple of 188 */
1133 alignment = TSPP_PACKET_LENGTH;
1134 if (size % alignment)
1135 return 0;
1136 return 1;
1137
1138 case TSPP_MODE_DISABLED:
1139 case TSPP_MODE_PES:
1140 default:
1141 /* no alignment requirement */
1142 return 1;
1143 }
1144
1145}
1146
1147static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1148{
1149 u32 new_size;
1150 u32 alignment;
1151
1152 switch (mode) {
1153 case TSPP_MODE_RAW:
1154 /* must be a multiple of 192 */
1155 alignment = (TSPP_PACKET_LENGTH + 4);
1156 break;
1157
1158 case TSPP_MODE_RAW_NO_SUFFIX:
1159 /* must be a multiple of 188 */
1160 alignment = TSPP_PACKET_LENGTH;
1161 break;
1162
1163 case TSPP_MODE_DISABLED:
1164 case TSPP_MODE_PES:
1165 default:
1166 /* no alignment requirement - give the user what he asks for */
1167 alignment = 1;
1168 break;
1169 }
1170 /* align up */
1171 new_size = (((size + alignment - 1) / alignment) * alignment);
1172 return new_size;
1173}
1174
1175static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1176{
1177 int i;
1178 struct tspp_mem_buffer *pbuf, *temp;
1179
1180 pbuf = channel->data;
1181 for (i = 0; i < channel->buffer_count; i++) {
1182 if (pbuf->desc.phys_base) {
1183 if (channel->memfree) {
1184 channel->memfree(channel_id,
1185 pbuf->desc.size,
1186 pbuf->desc.virt_base,
1187 pbuf->desc.phys_base,
1188 channel->user_info);
1189 } else {
1190 dma_free_coherent(NULL,
1191 pbuf->desc.size,
1192 pbuf->desc.virt_base,
1193 pbuf->desc.phys_base);
1194 }
1195 pbuf->desc.phys_base = 0;
1196 }
1197 pbuf->desc.virt_base = 0;
1198 pbuf->state = TSPP_BUF_STATE_EMPTY;
1199 temp = pbuf;
1200 pbuf = pbuf->next;
1201 kfree(temp);
1202 }
1203}
1204
Joel Nider5bd73f82011-12-14 16:53:30 +02001205/*** TSPP API functions ***/
Liron Kuch229090d2012-10-30 17:47:50 +02001206
1207/**
1208 * tspp_open_stream - open a TSPP stream for use.
1209 *
1210 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1211 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1212 * @source: stream source parameters.
1213 *
1214 * Return error status
1215 *
1216 */
1217int tspp_open_stream(u32 dev, u32 channel_id,
1218 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001219{
1220 u32 val;
1221 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001222 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001223
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001224 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1225 dev, channel_id, source->source, source->mode);
Liron Kuch229090d2012-10-30 17:47:50 +02001226
Joel Nider5bd73f82011-12-14 16:53:30 +02001227 if (dev >= TSPP_MAX_DEVICES) {
1228 pr_err("tspp: device id out of range");
1229 return -ENODEV;
1230 }
Joel Nider5556a852011-10-16 10:52:13 +02001231
Joel Nider5bd73f82011-12-14 16:53:30 +02001232 if (channel_id >= TSPP_NUM_CHANNELS) {
1233 pr_err("tspp: channel id out of range");
1234 return -ECHRNG;
1235 }
1236
1237 pdev = tspp_find_by_id(dev);
1238 if (!pdev) {
1239 pr_err("tspp_str: can't find device %i", dev);
1240 return -ENODEV;
1241 }
1242 channel = &pdev->channels[channel_id];
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001243 channel->src = source->source;
1244 tspp_set_tsif_mode(channel, source->mode);
1245 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch229090d2012-10-30 17:47:50 +02001246 source->data_inverse, source->sync_inverse,
1247 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001248
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001249 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001250 case TSPP_SOURCE_TSIF0:
1251 /* make sure TSIF0 is running & enabled */
1252 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
1253 pr_err("tspp: error starting tsif0");
Joel Nider5bd73f82011-12-14 16:53:30 +02001254 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001255 }
1256 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1257 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1258 pdev->base + TSPP_CONTROL);
1259 wmb();
1260 break;
1261 case TSPP_SOURCE_TSIF1:
1262 /* make sure TSIF1 is running & enabled */
1263 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
1264 pr_err("tspp: error starting tsif1");
Joel Nider5bd73f82011-12-14 16:53:30 +02001265 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001266 }
1267 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1268 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1269 pdev->base + TSPP_CONTROL);
1270 wmb();
1271 break;
1272 case TSPP_SOURCE_MEM:
1273 break;
1274 default:
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001275 pr_err("tspp: channel %i invalid source %i",
1276 channel->id, source->source);
Joel Nider5bd73f82011-12-14 16:53:30 +02001277 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001278 }
1279
Joel Nider5556a852011-10-16 10:52:13 +02001280 return 0;
1281}
1282EXPORT_SYMBOL(tspp_open_stream);
1283
Liron Kuch229090d2012-10-30 17:47:50 +02001284/**
1285 * tspp_close_stream - close a TSPP stream.
1286 *
1287 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1288 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1289 *
1290 * Return error status
1291 *
1292 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001293int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001294{
1295 u32 val;
1296 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001297 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001298
Joel Nider5bd73f82011-12-14 16:53:30 +02001299 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_cs: can't find device %i", dev);
1306 return -EBUSY;
1307 }
1308 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001309
1310 switch (channel->src) {
1311 case TSPP_SOURCE_TSIF0:
1312 tspp_stop_tsif(&pdev->tsif[0]);
1313 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1314 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1315 pdev->base + TSPP_CONTROL);
1316 wmb();
1317 break;
1318 case TSPP_SOURCE_TSIF1:
1319 tspp_stop_tsif(&pdev->tsif[1]);
1320 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1321 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1322 pdev->base + TSPP_CONTROL);
1323 break;
1324 case TSPP_SOURCE_MEM:
1325 break;
1326 case TSPP_SOURCE_NONE:
1327 break;
1328 }
1329
Joel Nider5bd73f82011-12-14 16:53:30 +02001330 channel->src = TSPP_SOURCE_NONE;
Joel Nider5556a852011-10-16 10:52:13 +02001331 return 0;
1332}
1333EXPORT_SYMBOL(tspp_close_stream);
1334
Liron Kuch229090d2012-10-30 17:47:50 +02001335/**
1336 * tspp_open_channel - open a TSPP channel.
1337 *
1338 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1339 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1340 *
1341 * Return error status
1342 *
1343 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001344int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001345{
1346 int rc = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001347 struct sps_connect *config;
1348 struct sps_register_event *event;
1349 struct tspp_channel *channel;
1350 struct tspp_device *pdev;
1351
1352 if (channel_id >= TSPP_NUM_CHANNELS) {
1353 pr_err("tspp: channel id out of range");
1354 return -ECHRNG;
1355 }
1356 pdev = tspp_find_by_id(dev);
1357 if (!pdev) {
1358 pr_err("tspp_oc: can't find device %i", dev);
1359 return -ENODEV;
1360 }
1361 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001362
1363 if (channel->used) {
1364 pr_err("tspp channel already in use");
Joel Nider5bd73f82011-12-14 16:53:30 +02001365 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001366 }
1367
Joel Nider5bd73f82011-12-14 16:53:30 +02001368 config = &channel->config;
1369 event = &channel->event;
1370
1371 /* start the clocks if needed */
1372 tspp_clock_start(pdev);
1373 if (tspp_channels_in_use(pdev) == 0)
1374 wake_lock(&pdev->wake_lock);
1375
Joel Nider5556a852011-10-16 10:52:13 +02001376 /* mark it as used */
1377 channel->used = 1;
1378
1379 /* start the bam */
1380 channel->pipe = sps_alloc_endpoint();
1381 if (channel->pipe == 0) {
1382 pr_err("tspp: error allocating endpoint");
1383 rc = -ENOMEM;
1384 goto err_sps_alloc;
1385 }
1386
1387 /* get default configuration */
1388 sps_get_config(channel->pipe, config);
1389
Joel Nider5bd73f82011-12-14 16:53:30 +02001390 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001391 config->destination = SPS_DEV_HANDLE_MEM;
1392 config->mode = SPS_MODE_SRC;
Joel Nider5bd73f82011-12-14 16:53:30 +02001393 config->options =
1394 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1395 SPS_O_STREAMING | /* streaming mode */
1396 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
1397 SPS_O_ACK_TRANSFERS; /* must use sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001398 config->src_pipe_index = channel->id;
1399 config->desc.size =
1400 (TSPP_SPS_DESCRIPTOR_COUNT + 1) * SPS_DESCRIPTOR_SIZE;
1401 config->desc.base = dma_alloc_coherent(NULL,
1402 config->desc.size,
1403 &config->desc.phys_base,
1404 GFP_KERNEL);
1405 if (config->desc.base == 0) {
1406 pr_err("tspp: error allocating sps descriptors");
1407 rc = -ENOMEM;
1408 goto err_desc_alloc;
1409 }
1410
1411 memset(config->desc.base, 0, config->desc.size);
1412
1413 rc = sps_connect(channel->pipe, config);
1414 if (rc) {
1415 pr_err("tspp: error connecting bam");
1416 goto err_connect;
1417 }
1418
1419 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider5bd73f82011-12-14 16:53:30 +02001420 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001421 event->callback = tspp_sps_complete_cb;
1422 event->xfer_done = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001423 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001424
1425 rc = sps_register_event(channel->pipe, event);
1426 if (rc) {
1427 pr_err("tspp: error registering event");
1428 goto err_event;
1429 }
1430
Joel Nider5bd73f82011-12-14 16:53:30 +02001431 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001432 if (rc < 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001433 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001434 "Runtime PM: Unable to wake up tspp device, rc = %d",
1435 rc);
1436 }
Joel Nider5556a852011-10-16 10:52:13 +02001437 return 0;
1438
1439err_event:
1440 sps_disconnect(channel->pipe);
1441err_connect:
1442 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1443 config->desc.phys_base);
1444err_desc_alloc:
1445 sps_free_endpoint(channel->pipe);
1446err_sps_alloc:
1447 return rc;
1448}
1449EXPORT_SYMBOL(tspp_open_channel);
1450
Liron Kuch229090d2012-10-30 17:47:50 +02001451/**
1452 * tspp_close_channel - close a TSPP channel.
1453 *
1454 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1455 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1456 *
1457 * Return error status
1458 *
1459 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001460int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001461{
1462 int i;
1463 int id;
1464 u32 val;
Joel Nider5556a852011-10-16 10:52:13 +02001465
Joel Nider5bd73f82011-12-14 16:53:30 +02001466 struct sps_connect *config;
1467 struct tspp_device *pdev;
1468 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02001469
1470 if (channel_id >= TSPP_NUM_CHANNELS) {
1471 pr_err("tspp: channel id out of range");
1472 return -ECHRNG;
1473 }
1474 pdev = tspp_find_by_id(dev);
1475 if (!pdev) {
1476 pr_err("tspp_close: can't find device %i", dev);
1477 return -ENODEV;
1478 }
1479 channel = &pdev->channels[channel_id];
1480
1481 /* if the channel is not used, we are done */
1482 if (!channel->used)
1483 return 0;
1484
1485 channel->notifier = NULL;
1486 channel->notify_data = NULL;
1487 channel->notify_timer = 0;
1488
1489 config = &channel->config;
1490 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001491
1492 /* disable pipe (channel) */
1493 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1494 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1495 wmb();
1496
1497 /* unregister all filters for this channel */
1498 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1499 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001500 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001501 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1502 if (id == channel->id) {
1503 if (FILTER_HAS_ENCRYPTION(tspp_filter))
1504 tspp_free_key_entry(
1505 FILTER_GET_KEY_NUMBER(tspp_filter));
1506 tspp_filter->config = 0;
1507 tspp_filter->filter = 0;
1508 }
1509 }
1510 channel->filter_count = 0;
1511
1512 /* stop the stream */
Joel Nider5bd73f82011-12-14 16:53:30 +02001513 tspp_close_stream(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02001514
1515 /* disconnect the bam */
1516 if (sps_disconnect(channel->pipe) != 0)
1517 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1518
1519 /* destroy the buffers */
1520 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1521 config->desc.phys_base);
1522
Liron Kuch229090d2012-10-30 17:47:50 +02001523 tspp_destroy_buffers(channel_id, channel);
1524
1525 channel->src = TSPP_SOURCE_NONE;
1526 channel->mode = TSPP_MODE_DISABLED;
1527 channel->memfree = NULL;
1528 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001529 channel->buffer_count = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001530 channel->data = NULL;
1531 channel->read = NULL;
1532 channel->waiting = NULL;
1533 channel->locked = NULL;
1534 channel->used = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001535
Joel Nider5bd73f82011-12-14 16:53:30 +02001536 if (tspp_channels_in_use(pdev) == 0)
1537 wake_unlock(&pdev->wake_lock);
1538 tspp_clock_stop(pdev);
1539
Joel Nider5556a852011-10-16 10:52:13 +02001540 return 0;
1541}
1542EXPORT_SYMBOL(tspp_close_channel);
1543
Liron Kuch229090d2012-10-30 17:47:50 +02001544/**
1545 * tspp_add_filter - add a TSPP filter to a channel.
1546 *
1547 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1548 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1549 * @filter: TSPP filter parameters
1550 *
1551 * Return error status
1552 *
1553 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001554int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001555 struct tspp_filter *filter)
1556{
Liron Kuch229090d2012-10-30 17:47:50 +02001557 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001558 int other_channel;
1559 int entry;
1560 u32 val, pid, enabled;
Joel Nider5bd73f82011-12-14 16:53:30 +02001561 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001562 struct tspp_pid_filter p;
Joel Nider5bd73f82011-12-14 16:53:30 +02001563 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001564
Joel Nider5bd73f82011-12-14 16:53:30 +02001565 TSPP_DEBUG("tspp: add filter");
1566 if (channel_id >= TSPP_NUM_CHANNELS) {
1567 pr_err("tspp: channel id out of range");
1568 return -ECHRNG;
1569 }
1570 pdev = tspp_find_by_id(dev);
1571 if (!pdev) {
1572 pr_err("tspp_add: can't find device %i", dev);
1573 return -ENODEV;
1574 }
1575
1576 channel = &pdev->channels[channel_id];
1577
Joel Nider5556a852011-10-16 10:52:13 +02001578 if (filter->source > TSPP_SOURCE_MEM) {
1579 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001580 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001581 }
1582
1583 if (filter->priority >= TSPP_NUM_PRIORITIES) {
1584 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001585 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001586 }
1587
Liron Kuch229090d2012-10-30 17:47:50 +02001588 channel->mode = filter->mode;
1589 /*
1590 * if buffers are already allocated, verify they fulfil
1591 * the alignment requirements.
1592 */
1593 if ((channel->buffer_count > 0) &&
1594 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1595 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001596
1597 if (filter->mode == TSPP_MODE_PES) {
1598 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1599 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001600 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001601 pid = FILTER_GET_PIPE_PID((tspp_filter));
1602 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1603 if (enabled && (pid == filter->pid)) {
1604 other_channel =
1605 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1606 pr_err("tspp: pid 0x%x already in use by channel %i",
1607 filter->pid, other_channel);
Joel Nider5bd73f82011-12-14 16:53:30 +02001608 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001609 }
1610 }
1611 }
1612
1613 /* make sure this priority is not already in use */
1614 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider5bd73f82011-12-14 16:53:30 +02001615 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001616 if (enabled) {
1617 pr_err("tspp: filter priority %i source %i is already enabled\n",
1618 filter->priority, channel->src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001619 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001620 }
1621
1622 if (channel->mode == TSPP_MODE_PES) {
1623 /* if we are already processing in PES mode, disable pipe
1624 (channel) and filter to be updated */
1625 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1626 writel_relaxed(val | (1 << channel->id),
1627 pdev->base + TSPP_PS_DISABLE);
1628 wmb();
1629 }
1630
1631 /* update entry */
1632 p.filter = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001633 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001634 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1635 FILTER_SET_PIPE_PID((&p), filter->pid);
1636 FILTER_SET_PID_MASK((&p), filter->mask);
1637 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1638 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1639 if (filter->decrypt) {
1640 entry = tspp_get_key_entry();
1641 if (entry == -1) {
1642 pr_err("tspp: no more keys available!");
1643 } else {
1644 p.config |= FILTER_DECRYPT;
1645 FILTER_SET_KEY_NUMBER((&p), entry);
1646 }
1647 }
Joel Nider5556a852011-10-16 10:52:13 +02001648
Joel Nider5bd73f82011-12-14 16:53:30 +02001649 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001650 filter[filter->priority].config = p.config;
Joel Nider5bd73f82011-12-14 16:53:30 +02001651 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001652 filter[filter->priority].filter = p.filter;
1653
Liron Kuch229090d2012-10-30 17:47:50 +02001654 /*
1655 * allocate buffers if needed (i.e. if user did has not already called
1656 * tspp_allocate_buffers() explicitly).
1657 */
1658 if (channel->buffer_count == 0) {
1659 channel->buffer_size =
1660 tspp_align_buffer_size_by_mode(channel->buffer_size,
1661 channel->mode);
1662 rc = tspp_allocate_buffers(dev, channel->id,
1663 channel->max_buffers,
1664 channel->buffer_size,
1665 channel->int_freq, NULL, NULL, NULL);
1666 if (rc != 0) {
1667 pr_err("tspp: tspp_allocate_buffers failed\n");
1668 return rc;
1669 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001670 }
1671
Joel Nider5556a852011-10-16 10:52:13 +02001672 /* reenable pipe */
1673 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1674 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1675 wmb();
1676 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1677
Joel Nider5556a852011-10-16 10:52:13 +02001678 channel->filter_count++;
1679
1680 return 0;
1681}
1682EXPORT_SYMBOL(tspp_add_filter);
1683
Liron Kuch229090d2012-10-30 17:47:50 +02001684/**
1685 * tspp_remove_filter - remove a TSPP filter from a channel.
1686 *
1687 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1688 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1689 * @filter: TSPP filter parameters
1690 *
1691 * Return error status
1692 *
1693 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001694int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001695 struct tspp_filter *filter)
1696{
1697 int entry;
1698 u32 val;
Joel Nider5bd73f82011-12-14 16:53:30 +02001699 struct tspp_device *pdev;
1700 int src;
1701 struct tspp_pid_filter *tspp_filter;
1702 struct tspp_channel *channel;
1703
1704 if (channel_id >= TSPP_NUM_CHANNELS) {
1705 pr_err("tspp: channel id out of range");
1706 return -ECHRNG;
1707 }
1708 pdev = tspp_find_by_id(dev);
1709 if (!pdev) {
1710 pr_err("tspp_remove: can't find device %i", dev);
1711 return -ENODEV;
1712 }
1713 channel = &pdev->channels[channel_id];
1714
1715 src = channel->src;
1716 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02001717
1718 /* disable pipe (channel) */
1719 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1720 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1721 wmb();
1722
1723 /* update data keys */
1724 if (tspp_filter->config & FILTER_DECRYPT) {
1725 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
1726 tspp_free_key_entry(entry);
1727 }
1728
1729 /* update pid table */
1730 tspp_filter->config = 0;
1731 tspp_filter->filter = 0;
1732
1733 channel->filter_count--;
1734
1735 /* reenable pipe */
1736 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1737 writel_relaxed(val & ~(1 << channel->id),
1738 pdev->base + TSPP_PS_DISABLE);
1739 wmb();
1740 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1741
1742 return 0;
1743}
1744EXPORT_SYMBOL(tspp_remove_filter);
1745
Liron Kuch229090d2012-10-30 17:47:50 +02001746/**
1747 * tspp_set_key - set TSPP key in key table.
1748 *
1749 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1750 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1751 * @key: TSPP key parameters
1752 *
1753 * Return error status
1754 *
1755 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001756int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02001757{
1758 int i;
1759 int id;
1760 int key_index;
1761 int data;
Joel Nider5bd73f82011-12-14 16:53:30 +02001762 struct tspp_channel *channel;
1763 struct tspp_device *pdev;
1764
1765 if (channel_id >= TSPP_NUM_CHANNELS) {
1766 pr_err("tspp: channel id out of range");
1767 return -ECHRNG;
1768 }
1769 pdev = tspp_find_by_id(dev);
1770 if (!pdev) {
1771 pr_err("tspp_set: can't find device %i", dev);
1772 return -ENODEV;
1773 }
1774 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001775
1776 /* read the key index used by this channel */
1777 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1778 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001779 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02001780 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1781 if (id == channel->id) {
1782 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
1783 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
1784 break;
1785 }
1786 }
1787 }
1788 if (i == TSPP_NUM_PRIORITIES) {
1789 pr_err("tspp: no encryption on this channel");
Joel Nider5bd73f82011-12-14 16:53:30 +02001790 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02001791 }
1792
1793 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001794 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
1795 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001796 } else {
Joel Nider5bd73f82011-12-14 16:53:30 +02001797 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
1798 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001799 }
1800 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
1801
1802 return 0;
1803}
1804EXPORT_SYMBOL(tspp_set_key);
1805
Liron Kuch229090d2012-10-30 17:47:50 +02001806/**
1807 * tspp_register_notification - register TSPP channel notification function.
1808 *
1809 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1810 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1811 * @pNotify: notification function
1812 * @userdata: user data to pass to notification function
1813 * @timer_ms: notification for partially filled buffers
1814 *
1815 * Return error status
1816 *
1817 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001818int tspp_register_notification(u32 dev, u32 channel_id,
1819 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02001820{
Joel Nider5bd73f82011-12-14 16:53:30 +02001821 struct tspp_channel *channel;
1822 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001823
Joel Nider5bd73f82011-12-14 16:53:30 +02001824 if (channel_id >= TSPP_NUM_CHANNELS) {
1825 pr_err("tspp: channel id out of range");
1826 return -ECHRNG;
1827 }
1828 pdev = tspp_find_by_id(dev);
1829 if (!pdev) {
1830 pr_err("tspp_reg: can't find device %i", dev);
1831 return -ENODEV;
1832 }
1833 channel = &pdev->channels[channel_id];
1834 channel->notifier = pNotify;
1835 channel->notify_data = userdata;
1836 channel->notify_timer = timer_ms;
Joel Nider5556a852011-10-16 10:52:13 +02001837 return 0;
1838}
Joel Nider5bd73f82011-12-14 16:53:30 +02001839EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001840
Liron Kuch229090d2012-10-30 17:47:50 +02001841/**
1842 * tspp_unregister_notification - unregister TSPP channel notification function.
1843 *
1844 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1845 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1846 *
1847 * Return error status
1848 *
1849 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001850int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001851{
Joel Nider5bd73f82011-12-14 16:53:30 +02001852 struct tspp_channel *channel;
1853 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001854
Joel Nider5bd73f82011-12-14 16:53:30 +02001855 if (channel_id >= TSPP_NUM_CHANNELS) {
1856 pr_err("tspp: channel id out of range");
1857 return -ECHRNG;
1858 }
1859 pdev = tspp_find_by_id(dev);
1860 if (!pdev) {
1861 pr_err("tspp_unreg: can't find device %i", dev);
1862 return -ENODEV;
1863 }
1864 channel = &pdev->channels[channel_id];
1865 channel->notifier = NULL;
1866 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001867 return 0;
1868}
Joel Nider5bd73f82011-12-14 16:53:30 +02001869EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001870
Liron Kuch229090d2012-10-30 17:47:50 +02001871/**
1872 * tspp_get_buffer - get TSPP data buffer.
1873 *
1874 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1875 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1876 *
1877 * Return error status
1878 *
1879 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001880const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001881{
Joel Nider5bd73f82011-12-14 16:53:30 +02001882 struct tspp_mem_buffer *buffer;
1883 struct tspp_channel *channel;
1884 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001885
Joel Nider5bd73f82011-12-14 16:53:30 +02001886 if (channel_id >= TSPP_NUM_CHANNELS) {
1887 pr_err("tspp: channel id out of range");
1888 return NULL;
1889 }
1890 pdev = tspp_find_by_id(dev);
1891 if (!pdev) {
1892 pr_err("tspp_get: can't find device %i", dev);
1893 return NULL;
1894 }
1895 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001896
Joel Nider5bd73f82011-12-14 16:53:30 +02001897 if (!channel->read) {
1898 pr_warn("tspp: no buffer to get on channel %i!",
1899 channel->id);
1900 return NULL;
1901 }
1902
1903 buffer = channel->read;
1904 /* see if we have any buffers ready to read */
1905 if (buffer->state != TSPP_BUF_STATE_DATA)
1906 return 0;
1907
1908 if (buffer->state == TSPP_BUF_STATE_DATA) {
1909 /* mark the buffer as busy */
1910 buffer->state = TSPP_BUF_STATE_LOCKED;
1911
1912 /* increment the pointer along the list */
1913 channel->read = channel->read->next;
1914 }
1915
1916 return &buffer->desc;
1917}
1918EXPORT_SYMBOL(tspp_get_buffer);
1919
Liron Kuch229090d2012-10-30 17:47:50 +02001920/**
1921 * tspp_release_buffer - release TSPP data buffer back to TSPP.
1922 *
1923 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1924 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1925 * @descriptor_id: buffer descriptor ID
1926 *
1927 * Return error status
1928 *
1929 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001930int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
1931{
1932 int i, found = 0;
1933 struct tspp_mem_buffer *buffer;
1934 struct tspp_channel *channel;
1935 struct tspp_device *pdev;
1936
1937 if (channel_id >= TSPP_NUM_CHANNELS) {
1938 pr_err("tspp: channel id out of range");
1939 return -ECHRNG;
1940 }
1941 pdev = tspp_find_by_id(dev);
1942 if (!pdev) {
1943 pr_err("tspp: can't find device %i", dev);
1944 return -ENODEV;
1945 }
1946 channel = &pdev->channels[channel_id];
1947
1948 if (descriptor_id > channel->buffer_count)
1949 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
1950
1951 /* find the correct descriptor */
1952 buffer = channel->locked;
1953 for (i = 0; i < channel->buffer_count; i++) {
1954 if (buffer->desc.id == descriptor_id) {
1955 found = 1;
1956 break;
1957 }
1958 buffer = buffer->next;
1959 }
1960 channel->locked = channel->locked->next;
1961
1962 if (!found) {
1963 pr_err("tspp: cant find desc %i", descriptor_id);
1964 return -EINVAL;
1965 }
1966
1967 /* make sure the buffer is in the expected state */
1968 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
1969 pr_err("tspp: buffer %i not locked", descriptor_id);
1970 return -EINVAL;
1971 }
1972 /* unlock the buffer and requeue it */
1973 buffer->state = TSPP_BUF_STATE_WAITING;
1974
1975 if (tspp_queue_buffer(channel, buffer))
1976 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02001977 return 0;
1978}
Joel Nider5bd73f82011-12-14 16:53:30 +02001979EXPORT_SYMBOL(tspp_release_buffer);
1980
Liron Kuch229090d2012-10-30 17:47:50 +02001981/**
1982 * tspp_allocate_buffers - allocate TSPP data buffers.
1983 *
1984 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1985 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1986 * @count: number of buffers to allocate
1987 * @size: size of each buffer to allocate
1988 * @int_freq: interrupt frequency
1989 * @alloc: user defined memory allocator function. Pass NULL for default.
1990 * @memfree: user defined memory free function. Pass NULL for default.
1991 * @user: user data to pass to the memory allocator/free function
1992 *
1993 * Return error status
1994 *
1995 * The user can optionally call this function explicitly to allocate the TSPP
1996 * data buffers. Alternatively, if the user did not call this function, it
1997 * is called implicitly by tspp_add_filter().
1998 */
1999int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
2000 u32 int_freq, tspp_allocator *alloc,
2001 tspp_memfree *memfree, void *user)
Joel Nider5bd73f82011-12-14 16:53:30 +02002002{
2003 struct tspp_channel *channel;
2004 struct tspp_device *pdev;
2005 struct tspp_mem_buffer *last = NULL;
2006
2007 TSPP_DEBUG("tspp_allocate_buffers");
2008
2009 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch229090d2012-10-30 17:47:50 +02002010 pr_err("%s: channel id out of range", __func__);
Joel Nider5bd73f82011-12-14 16:53:30 +02002011 return -ECHRNG;
2012 }
Liron Kuch229090d2012-10-30 17:47:50 +02002013
Joel Nider5bd73f82011-12-14 16:53:30 +02002014 pdev = tspp_find_by_id(dev);
2015 if (!pdev) {
Liron Kuch229090d2012-10-30 17:47:50 +02002016 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider5bd73f82011-12-14 16:53:30 +02002017 return -ENODEV;
2018 }
Liron Kuch229090d2012-10-30 17:47:50 +02002019
2020 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
2021 pr_err("%s: tspp requires a minimum of %i buffers\n",
2022 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
2023 return -EINVAL;
2024 }
2025
Joel Nider5bd73f82011-12-14 16:53:30 +02002026 channel = &pdev->channels[channel_id];
Liron Kuch229090d2012-10-30 17:47:50 +02002027 /* allow buffer allocation only if there was no previous buffer
2028 * allocation for this channel.
2029 */
2030 if (channel->buffer_count > 0) {
2031 pr_err("%s: buffers already allocated for channel %u",
2032 __func__, channel_id);
2033 return -EINVAL;
2034 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002035
2036 channel->max_buffers = count;
2037
2038 /* set up interrupt frequency */
Liron Kuch229090d2012-10-30 17:47:50 +02002039 if (int_freq > channel->max_buffers) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002040 int_freq = channel->max_buffers;
Liron Kuch229090d2012-10-30 17:47:50 +02002041 pr_warn("%s: setting interrupt frequency to %u\n",
2042 __func__, int_freq);
Joel Nider5bd73f82011-12-14 16:53:30 +02002043 }
Liron Kuch229090d2012-10-30 17:47:50 +02002044 channel->int_freq = int_freq;
2045 /*
2046 * it is the responsibility of the caller to tspp_allocate_buffers(),
2047 * whether it's the user or the driver, to make sure the size parameter
2048 * is compatible to the channel mode.
2049 */
2050 channel->buffer_size = size;
Joel Nider5bd73f82011-12-14 16:53:30 +02002051
Liron Kuch229090d2012-10-30 17:47:50 +02002052 /* save user defined memory free function for later use */
2053 channel->memfree = memfree;
2054 channel->user_info = user;
2055
2056 for (channel->buffer_count = 0;
2057 channel->buffer_count < channel->max_buffers;
Joel Nider5bd73f82011-12-14 16:53:30 +02002058 channel->buffer_count++) {
2059
2060 /* allocate the descriptor */
2061 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2062 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2063 if (!desc) {
Liron Kuch229090d2012-10-30 17:47:50 +02002064 pr_warn("%s: Can't allocate desc %i",
2065 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002066 break;
2067 }
2068
2069 desc->desc.id = channel->buffer_count;
2070 /* allocate the buffer */
2071 if (tspp_alloc_buffer(channel_id, &desc->desc,
2072 channel->buffer_size, alloc, user) != 0) {
2073 kfree(desc);
Liron Kuch229090d2012-10-30 17:47:50 +02002074 pr_warn("%s: Can't allocate buffer %i",
2075 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002076 break;
2077 }
2078
2079 /* add the descriptor to the list */
2080 desc->filled = 0;
2081 desc->read_index = 0;
2082 if (!channel->data) {
2083 channel->data = desc;
2084 desc->next = channel->data;
2085 } else {
2086 last->next = desc;
2087 }
2088 last = desc;
2089 desc->next = channel->data;
2090
2091 /* prepare the sps descriptor */
2092 desc->sps.phys_base = desc->desc.phys_base;
2093 desc->sps.base = desc->desc.virt_base;
2094 desc->sps.size = desc->desc.size;
2095
2096 /* start the transfer */
2097 if (tspp_queue_buffer(channel, desc))
Liron Kuch229090d2012-10-30 17:47:50 +02002098 pr_err("%s: can't queue buffer %i",
2099 __func__, desc->desc.id);
2100 }
2101
2102 if (channel->buffer_count < channel->max_buffers) {
2103 /*
2104 * we failed to allocate the requested number of buffers.
2105 * we don't allow a partial success, so need to clean up here.
2106 */
2107 tspp_destroy_buffers(channel_id, channel);
2108 channel->buffer_count = 0;
2109 return -ENOMEM;
Joel Nider5bd73f82011-12-14 16:53:30 +02002110 }
2111
2112 channel->waiting = channel->data;
2113 channel->read = channel->data;
2114 channel->locked = channel->data;
Liron Kuch229090d2012-10-30 17:47:50 +02002115
Joel Nider5bd73f82011-12-14 16:53:30 +02002116 return 0;
2117}
2118EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002119
2120/*** File Operations ***/
2121static ssize_t tspp_open(struct inode *inode, struct file *filp)
2122{
Joel Nider5bd73f82011-12-14 16:53:30 +02002123 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002124 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002125
2126 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002127 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2128 filp->private_data = channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002129 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002130
2131 /* if this channel is already in use, quit */
2132 if (channel->used) {
2133 pr_err("tspp channel %i already in use",
2134 MINOR(channel->cdev.dev));
2135 return -EACCES;
2136 }
2137
Joel Nider5bd73f82011-12-14 16:53:30 +02002138 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002139 pr_err("tspp: error opening channel");
2140 return -EACCES;
2141 }
2142
2143 return 0;
2144}
2145
2146static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2147{
2148 unsigned long flags;
2149 unsigned int mask = 0;
2150 struct tspp_channel *channel;
2151 channel = filp->private_data;
2152
2153 /* register the wait queue for this channel */
2154 poll_wait(filp, &channel->in_queue, p);
2155
2156 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider5bd73f82011-12-14 16:53:30 +02002157 if (channel->read &&
2158 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002159 mask = POLLIN | POLLRDNORM;
2160
2161 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2162
2163 return mask;
2164}
2165
2166static ssize_t tspp_release(struct inode *inode, struct file *filp)
2167{
Joel Nider5bd73f82011-12-14 16:53:30 +02002168 struct tspp_channel *channel = filp->private_data;
2169 u32 dev = channel->pdev->pdev->id;
2170 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002171
Joel Nider5bd73f82011-12-14 16:53:30 +02002172 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002173
2174 return 0;
2175}
2176
2177static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2178 loff_t *f_pos)
2179{
2180 size_t size = 0;
2181 size_t transferred = 0;
2182 struct tspp_channel *channel;
2183 struct tspp_mem_buffer *buffer;
2184 channel = filp->private_data;
2185
2186 TSPP_DEBUG("tspp_read");
Joel Nider5bd73f82011-12-14 16:53:30 +02002187
2188 while (!channel->read) {
2189 if (filp->f_flags & O_NONBLOCK) {
2190 pr_warn("tspp: no buffer on channel %i!",
2191 channel->id);
2192 return -EAGAIN;
2193 }
2194 /* go to sleep if there is nothing to read */
2195 if (wait_event_interruptible(channel->in_queue,
2196 (channel->read != NULL))) {
2197 pr_err("tspp: rude awakening\n");
2198 return -ERESTARTSYS;
2199 }
2200 }
2201
2202 buffer = channel->read;
2203
Joel Nider5556a852011-10-16 10:52:13 +02002204 /* see if we have any buffers ready to read */
2205 while (buffer->state != TSPP_BUF_STATE_DATA) {
2206 if (filp->f_flags & O_NONBLOCK) {
2207 pr_warn("tspp: nothing to read on channel %i!",
2208 channel->id);
2209 return -EAGAIN;
2210 }
2211 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002212 if (wait_event_interruptible(channel->in_queue,
2213 (buffer->state == TSPP_BUF_STATE_DATA))) {
2214 pr_err("tspp: rude awakening\n");
2215 return -ERESTARTSYS;
2216 }
2217 }
2218
2219 while (buffer->state == TSPP_BUF_STATE_DATA) {
2220 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002221 if (size == 0)
2222 break;
2223
Joel Nider5bd73f82011-12-14 16:53:30 +02002224 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002225 buffer->read_index, size)) {
2226 pr_err("tspp: error copying to user buffer");
Joel Nider5bd73f82011-12-14 16:53:30 +02002227 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002228 }
2229 buf += size;
2230 count -= size;
2231 transferred += size;
2232 buffer->read_index += size;
2233
Liron Kuch229090d2012-10-30 17:47:50 +02002234 /*
2235 * after reading the end of the buffer, requeue it,
2236 * and set up for reading the next one
2237 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002238 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002239 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5bd73f82011-12-14 16:53:30 +02002240 if (tspp_queue_buffer(channel, buffer))
2241 pr_err("tspp: can't submit transfer");
2242 channel->locked = channel->read;
2243 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002244 }
2245 }
2246
2247 return transferred;
2248}
2249
2250static long tspp_ioctl(struct file *filp,
2251 unsigned int param0, unsigned long param1)
2252{
Joel Nider5bd73f82011-12-14 16:53:30 +02002253 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002254 int rc = -1;
2255 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002256 struct tspp_select_source ss;
2257 struct tspp_filter f;
2258 struct tspp_key k;
2259 struct tspp_iv iv;
2260 struct tspp_system_keys sk;
2261 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002262 channel = filp->private_data;
Joel Nider5bd73f82011-12-14 16:53:30 +02002263 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002264
2265 if (!param1)
2266 return -EINVAL;
2267
2268 switch (param0) {
2269 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002270 if (!access_ok(VERIFY_READ, param1,
2271 sizeof(struct tspp_select_source))) {
2272 return -EBUSY;
2273 }
2274 if (__copy_from_user(&ss, (void *)param1,
2275 sizeof(struct tspp_select_source)) == 0)
2276 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002277 break;
2278 case TSPP_IOCTL_ADD_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002279 if (!access_ok(VERIFY_READ, param1,
2280 sizeof(struct tspp_filter))) {
2281 return -ENOSR;
2282 }
2283 if (__copy_from_user(&f, (void *)param1,
2284 sizeof(struct tspp_filter)) == 0)
2285 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002286 break;
2287 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002288 if (!access_ok(VERIFY_READ, param1,
2289 sizeof(struct tspp_filter))) {
2290 return -EBUSY;
2291 }
2292 if (__copy_from_user(&f, (void *)param1,
2293 sizeof(struct tspp_filter)) == 0)
2294 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002295 break;
2296 case TSPP_IOCTL_SET_KEY:
Joel Nider5bd73f82011-12-14 16:53:30 +02002297 if (!access_ok(VERIFY_READ, param1,
2298 sizeof(struct tspp_key))) {
2299 return -EBUSY;
2300 }
2301 if (__copy_from_user(&k, (void *)param1,
2302 sizeof(struct tspp_key)) == 0)
2303 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002304 break;
2305 case TSPP_IOCTL_SET_IV:
Joel Nider5bd73f82011-12-14 16:53:30 +02002306 if (!access_ok(VERIFY_READ, param1,
2307 sizeof(struct tspp_iv))) {
2308 return -EBUSY;
2309 }
2310 if (__copy_from_user(&iv, (void *)param1,
2311 sizeof(struct tspp_iv)) == 0)
2312 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002313 break;
2314 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider5bd73f82011-12-14 16:53:30 +02002315 if (!access_ok(VERIFY_READ, param1,
2316 sizeof(struct tspp_system_keys))) {
2317 return -EINVAL;
2318 }
2319 if (__copy_from_user(&sk, (void *)param1,
2320 sizeof(struct tspp_system_keys)) == 0)
2321 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002322 break;
2323 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002324 if (!access_ok(VERIFY_READ, param1,
2325 sizeof(struct tspp_buffer))) {
2326 rc = -EINVAL;
2327 }
2328 if (__copy_from_user(&b, (void *)param1,
2329 sizeof(struct tspp_buffer)) == 0)
2330 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002331 break;
2332 default:
2333 pr_err("tspp: Unknown ioctl %i", param0);
2334 }
2335
Liron Kuch229090d2012-10-30 17:47:50 +02002336 /*
2337 * normalize the return code in case one of the subfunctions does
2338 * something weird
2339 */
Joel Nider5556a852011-10-16 10:52:13 +02002340 if (rc != 0)
Joel Nider5bd73f82011-12-14 16:53:30 +02002341 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002342
2343 return rc;
2344}
2345
2346/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002347static int debugfs_iomem_x32_set(void *data, u64 val)
2348{
2349 writel_relaxed(val, data);
2350 wmb();
2351 return 0;
2352}
2353
2354static int debugfs_iomem_x32_get(void *data, u64 *val)
2355{
2356 *val = readl_relaxed(data);
2357 return 0;
2358}
2359
2360DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2361 debugfs_iomem_x32_set, "0x%08llx");
2362
2363static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2364 int instance)
2365{
2366 char name[10];
2367 snprintf(name, 10, "tsif%i", instance);
2368 tsif_device->dent_tsif = debugfs_create_dir(
2369 name, NULL);
2370 if (tsif_device->dent_tsif) {
2371 int i;
2372 void __iomem *base = tsif_device->base;
2373 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2374 tsif_device->debugfs_tsif_regs[i] =
2375 debugfs_create_file(
2376 debugfs_tsif_regs[i].name,
2377 debugfs_tsif_regs[i].mode,
2378 tsif_device->dent_tsif,
2379 base + debugfs_tsif_regs[i].offset,
2380 &fops_iomem_x32);
2381 }
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002382
2383 debugfs_create_u32(
2384 "stat_rx_chunks",
2385 S_IRUGO|S_IWUGO,
2386 tsif_device->dent_tsif,
2387 &tsif_device->stat_rx);
2388
2389 debugfs_create_u32(
2390 "stat_overflow",
2391 S_IRUGO|S_IWUGO,
2392 tsif_device->dent_tsif,
2393 &tsif_device->stat_overflow);
2394
2395 debugfs_create_u32(
2396 "stat_lost_sync",
2397 S_IRUGO|S_IWUGO,
2398 tsif_device->dent_tsif,
2399 &tsif_device->stat_lost_sync);
2400
2401 debugfs_create_u32(
2402 "stat_timeout",
2403 S_IRUGO|S_IWUGO,
2404 tsif_device->dent_tsif,
2405 &tsif_device->stat_timeout);
2406
Joel Nider5556a852011-10-16 10:52:13 +02002407 }
2408}
2409
2410static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2411{
2412 if (tsif_device->dent_tsif) {
2413 int i;
2414 debugfs_remove_recursive(tsif_device->dent_tsif);
2415 tsif_device->dent_tsif = NULL;
2416 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2417 tsif_device->debugfs_tsif_regs[i] = NULL;
2418 }
2419}
2420
2421static void tspp_debugfs_init(struct tspp_device *device, int instance)
2422{
2423 char name[10];
2424 snprintf(name, 10, "tspp%i", instance);
2425 device->dent = debugfs_create_dir(
2426 name, NULL);
2427 if (device->dent) {
2428 int i;
2429 void __iomem *base = device->base;
2430 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2431 device->debugfs_regs[i] =
2432 debugfs_create_file(
2433 debugfs_tspp_regs[i].name,
2434 debugfs_tspp_regs[i].mode,
2435 device->dent,
2436 base + debugfs_tspp_regs[i].offset,
2437 &fops_iomem_x32);
2438 }
2439 }
2440}
2441
2442static void tspp_debugfs_exit(struct tspp_device *device)
2443{
2444 if (device->dent) {
2445 int i;
2446 debugfs_remove_recursive(device->dent);
2447 device->dent = NULL;
2448 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2449 device->debugfs_regs[i] = NULL;
2450 }
2451}
Joel Nider5556a852011-10-16 10:52:13 +02002452
2453static int __devinit msm_tspp_probe(struct platform_device *pdev)
2454{
2455 int rc = -ENODEV;
2456 u32 version;
Liron Kuch229090d2012-10-30 17:47:50 +02002457 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002458 struct msm_tspp_platform_data *data;
2459 struct tspp_device *device;
2460 struct resource *mem_tsif0;
2461 struct resource *mem_tsif1;
2462 struct resource *mem_tspp;
2463 struct resource *mem_bam;
Liron Kuch229090d2012-10-30 17:47:50 +02002464 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002465
2466 /* must have platform data */
2467 data = pdev->dev.platform_data;
2468 if (!data) {
2469 pr_err("tspp: Platform data not available");
2470 rc = -EINVAL;
2471 goto out;
2472 }
2473
2474 /* check for valid device id */
Joel Nider5bd73f82011-12-14 16:53:30 +02002475 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002476 pr_err("tspp: Invalid device ID %d", pdev->id);
2477 rc = -EINVAL;
2478 goto out;
2479 }
2480
2481 /* OK, we will use this device */
2482 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2483 if (!device) {
2484 pr_err("tspp: Failed to allocate memory for device");
2485 rc = -ENOMEM;
2486 goto out;
2487 }
2488
2489 /* set up references */
2490 device->pdev = pdev;
2491 platform_set_drvdata(pdev, device);
2492
2493 /* map clocks */
2494 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002495 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02002496 if (IS_ERR(device->tsif_pclk)) {
2497 pr_err("tspp: failed to get %s",
2498 data->tsif_pclk);
2499 rc = PTR_ERR(device->tsif_pclk);
2500 device->tsif_pclk = NULL;
2501 goto err_pclock;
2502 }
2503 }
2504 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002505 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02002506 if (IS_ERR(device->tsif_ref_clk)) {
2507 pr_err("tspp: failed to get %s",
2508 data->tsif_ref_clk);
2509 rc = PTR_ERR(device->tsif_ref_clk);
2510 device->tsif_ref_clk = NULL;
2511 goto err_refclock;
2512 }
2513 }
2514
2515 /* map I/O memory */
2516 mem_tsif0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2517 if (!mem_tsif0) {
2518 pr_err("tspp: Missing tsif0 MEM resource");
2519 rc = -ENXIO;
2520 goto err_res_tsif0;
2521 }
2522 device->tsif[0].base = ioremap(mem_tsif0->start,
2523 resource_size(mem_tsif0));
2524 if (!device->tsif[0].base) {
2525 pr_err("tspp: ioremap failed");
2526 goto err_map_tsif0;
2527 }
2528
2529 mem_tsif1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2530 if (!mem_tsif1) {
2531 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
2532 rc = -ENXIO;
2533 goto err_res_tsif1;
2534 }
2535 device->tsif[1].base = ioremap(mem_tsif1->start,
2536 resource_size(mem_tsif1));
2537 if (!device->tsif[1].base) {
2538 dev_err(&pdev->dev, "ioremap failed");
2539 goto err_map_tsif1;
2540 }
2541
2542 mem_tspp = platform_get_resource(pdev, IORESOURCE_MEM, 2);
2543 if (!mem_tspp) {
2544 dev_err(&pdev->dev, "Missing MEM resource");
2545 rc = -ENXIO;
2546 goto err_res_dev;
2547 }
2548 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
2549 if (!device->base) {
2550 dev_err(&pdev->dev, "ioremap failed");
2551 goto err_map_dev;
2552 }
2553
2554 mem_bam = platform_get_resource(pdev, IORESOURCE_MEM, 3);
2555 if (!mem_bam) {
2556 pr_err("tspp: Missing bam MEM resource");
2557 rc = -ENXIO;
2558 goto err_res_bam;
2559 }
2560 memset(&device->bam_props, 0, sizeof(device->bam_props));
2561 device->bam_props.phys_addr = mem_bam->start;
2562 device->bam_props.virt_addr = ioremap(mem_bam->start,
2563 resource_size(mem_bam));
2564 if (!device->bam_props.virt_addr) {
2565 dev_err(&pdev->dev, "ioremap failed");
2566 goto err_map_bam;
2567 }
2568
2569 /* map TSPP IRQ */
2570 rc = platform_get_irq(pdev, 0);
2571 if (rc > 0) {
2572 device->tspp_irq = rc;
2573 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
2574 dev_name(&pdev->dev), device);
2575 if (rc) {
2576 dev_err(&pdev->dev, "failed to request IRQ %d : %d",
2577 device->tspp_irq, rc);
2578 goto err_irq;
2579 }
2580 } else {
2581 dev_err(&pdev->dev, "failed to get tspp IRQ");
2582 goto err_irq;
2583 }
2584
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002585 /* map TSIF IRQs */
2586 device->tsif[0].tsif_irq = TSIF1_IRQ;
2587 device->tsif[1].tsif_irq = TSIF2_IRQ;
2588
2589 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
2590 rc = request_irq(device->tsif[i].tsif_irq,
2591 tsif_isr, IRQF_SHARED,
2592 dev_name(&pdev->dev), &device->tsif[i]);
2593 if (rc) {
2594 dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
2595 i, rc);
2596 device->tsif[i].tsif_irq = 0;
2597 }
2598 }
2599
Joel Nider5556a852011-10-16 10:52:13 +02002600 /* BAM IRQ */
2601 device->bam_irq = TSIF_BAM_IRQ;
2602
2603 /* GPIOs */
2604 rc = tspp_start_gpios(device);
2605 if (rc)
2606 goto err_gpio;
2607
2608 /* power management */
2609 pm_runtime_set_active(&pdev->dev);
2610 pm_runtime_enable(&pdev->dev);
2611
Joel Nider5556a852011-10-16 10:52:13 +02002612 tspp_debugfs_init(device, 0);
2613
2614 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2615 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02002616
2617 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
2618 dev_name(&pdev->dev));
2619
2620 /* set up pointers to ram-based 'registers' */
Joel Nider5bd73f82011-12-14 16:53:30 +02002621 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
2622 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
2623 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
2624 device->tspp_key_table = device->base + TSPP_DATA_KEY;
2625 device->tspp_global_performance =
2626 device->base + TSPP_GLOBAL_PERFORMANCE;
2627 device->tspp_pipe_context =
2628 device->base + TSPP_PIPE_CONTEXT;
2629 device->tspp_pipe_performance =
2630 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02002631
2632 device->bam_props.summing_threshold = 0x10;
2633 device->bam_props.irq = device->bam_irq;
2634 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
2635
2636 if (sps_register_bam_device(&device->bam_props,
2637 &device->bam_handle) != 0) {
2638 pr_err("tspp: failed to register bam");
2639 goto err_bam;
2640 }
2641
Joel Nider5bd73f82011-12-14 16:53:30 +02002642 if (tspp_clock_start(device) != 0) {
2643 dev_err(&pdev->dev, "Can't start clocks");
2644 goto err_clock;
Joel Nider5556a852011-10-16 10:52:13 +02002645 }
2646
2647 spin_lock_init(&device->spinlock);
2648 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
2649 (unsigned long)device);
2650
2651 /* initialize everything to a known state */
2652 tspp_global_reset(device);
2653
2654 version = readl_relaxed(device->base + TSPP_VERSION);
2655 if (version != 1)
2656 pr_warn("tspp: unrecognized hw version=%i", version);
2657
Joel Nider5bd73f82011-12-14 16:53:30 +02002658 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02002659 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002660 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
2661 pr_err("tspp_channel_init failed");
2662 goto err_channel;
2663 }
Joel Nider5556a852011-10-16 10:52:13 +02002664 }
2665
Joel Nider5bd73f82011-12-14 16:53:30 +02002666 /* stop the clocks for power savings */
2667 tspp_clock_stop(device);
2668
2669 /* everything is ok, so add the device to the list */
2670 list_add_tail(&(device->devlist), &tspp_devices);
2671
Joel Nider5556a852011-10-16 10:52:13 +02002672 return 0;
2673
Joel Nider5bd73f82011-12-14 16:53:30 +02002674err_channel:
Liron Kuch229090d2012-10-30 17:47:50 +02002675 /* uninitialize channels */
2676 for (j = 0; j < i; j++) {
2677 channel = &(device->channels[i]);
2678 device_destroy(tspp_class, channel->cdev.dev);
2679 cdev_del(&channel->cdev);
2680 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002681err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02002682 sps_deregister_bam_device(device->bam_handle);
2683err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02002684 tspp_debugfs_exit(device);
2685 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2686 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02002687err_gpio:
2688err_irq:
2689 tspp_stop_gpios(device);
2690 iounmap(device->bam_props.virt_addr);
2691err_map_bam:
2692err_res_bam:
2693 iounmap(device->base);
2694err_map_dev:
2695err_res_dev:
2696 iounmap(device->tsif[1].base);
2697err_map_tsif1:
2698err_res_tsif1:
2699 iounmap(device->tsif[0].base);
2700err_map_tsif0:
2701err_res_tsif0:
2702 if (device->tsif_ref_clk)
2703 clk_put(device->tsif_ref_clk);
2704err_refclock:
2705 if (device->tsif_pclk)
2706 clk_put(device->tsif_pclk);
2707err_pclock:
2708 kfree(device);
2709
2710out:
2711 return rc;
2712}
2713
2714static int __devexit msm_tspp_remove(struct platform_device *pdev)
2715{
Joel Nider5bd73f82011-12-14 16:53:30 +02002716 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002717 u32 i;
Joel Nider5556a852011-10-16 10:52:13 +02002718
2719 struct tspp_device *device = platform_get_drvdata(pdev);
2720
Joel Nider5bd73f82011-12-14 16:53:30 +02002721 /* free the buffers, and delete the channels */
2722 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
2723 channel = &device->channels[i];
2724 tspp_close_channel(device->pdev->id, i);
2725 device_destroy(tspp_class, channel->cdev.dev);
2726 cdev_del(&channel->cdev);
2727 }
2728
Joel Nider5556a852011-10-16 10:52:13 +02002729 sps_deregister_bam_device(device->bam_handle);
2730
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002731 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
Joel Nider5556a852011-10-16 10:52:13 +02002732 tsif_debugfs_exit(&device->tsif[i]);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002733 if (device->tsif[i].tsif_irq)
2734 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
2735 }
Joel Nider5556a852011-10-16 10:52:13 +02002736
2737 wake_lock_destroy(&device->wake_lock);
2738 free_irq(device->tspp_irq, device);
2739 tspp_stop_gpios(device);
2740
2741 iounmap(device->bam_props.virt_addr);
2742 iounmap(device->base);
2743 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2744 iounmap(device->tsif[i].base);
2745
2746 if (device->tsif_ref_clk)
2747 clk_put(device->tsif_ref_clk);
2748
2749 if (device->tsif_pclk)
2750 clk_put(device->tsif_pclk);
2751
2752 pm_runtime_disable(&pdev->dev);
2753 pm_runtime_put(&pdev->dev);
2754 kfree(device);
2755
2756 return 0;
2757}
2758
2759/*** power management ***/
2760
2761static int tspp_runtime_suspend(struct device *dev)
2762{
2763 dev_dbg(dev, "pm_runtime: suspending...");
2764 return 0;
2765}
2766
2767static int tspp_runtime_resume(struct device *dev)
2768{
2769 dev_dbg(dev, "pm_runtime: resuming...");
2770 return 0;
2771}
2772
2773static const struct dev_pm_ops tspp_dev_pm_ops = {
2774 .runtime_suspend = tspp_runtime_suspend,
2775 .runtime_resume = tspp_runtime_resume,
2776};
2777
2778static struct platform_driver msm_tspp_driver = {
2779 .probe = msm_tspp_probe,
2780 .remove = __exit_p(msm_tspp_remove),
2781 .driver = {
2782 .name = "msm_tspp",
2783 .pm = &tspp_dev_pm_ops,
2784 },
2785};
2786
2787
2788static int __init mod_init(void)
2789{
Joel Nider5556a852011-10-16 10:52:13 +02002790 int rc;
2791
Joel Nider5bd73f82011-12-14 16:53:30 +02002792 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02002793 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
2794 if (rc) {
2795 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
2796 goto err_devrgn;
2797 }
2798
2799 tspp_class = class_create(THIS_MODULE, "tspp");
2800 if (IS_ERR(tspp_class)) {
2801 rc = PTR_ERR(tspp_class);
2802 pr_err("tspp: Error creating class: %d", rc);
2803 goto err_class;
2804 }
2805
Joel Nider5bd73f82011-12-14 16:53:30 +02002806 /* register the driver, and check hardware */
2807 rc = platform_driver_register(&msm_tspp_driver);
2808 if (rc) {
2809 pr_err("tspp: platform_driver_register failed: %d", rc);
2810 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02002811 }
2812
2813 return 0;
2814
Joel Nider5bd73f82011-12-14 16:53:30 +02002815err_register:
2816 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02002817err_class:
2818 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
2819err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02002820 return rc;
2821}
2822
2823static void __exit mod_exit(void)
2824{
Joel Nider5bd73f82011-12-14 16:53:30 +02002825 /* delete low level driver */
2826 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02002827
Joel Nider5bd73f82011-12-14 16:53:30 +02002828 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02002829 class_destroy(tspp_class);
2830 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02002831}
2832
2833module_init(mod_init);
2834module_exit(mod_exit);
2835
Joel Nider5bd73f82011-12-14 16:53:30 +02002836MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02002837MODULE_LICENSE("GPL v2");