aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/modem_if/modem_link_device_memory.h
blob: 29a84acee9664aab146f0d725ac9af1023796e4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
/*
 * Copyright (C) 2010 Samsung Electronics.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef __MODEM_LINK_DEVICE_MEMORY_H__
#define __MODEM_LINK_DEVICE_MEMORY_H__

#include <linux/spinlock.h>
#include <linux/wakelock.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/notifier.h>
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#elif defined(CONFIG_FB)
#include <linux/fb.h>
#endif

#include "modem.h"
#include "modem_prj.h"

#define DPRAM_MAGIC_CODE	0xAA

/* interrupt masks.*/
#define INT_MASK_VALID		0x0080
#define INT_MASK_CMD		0x0040
#define INT_VALID(x)		((x) & INT_MASK_VALID)
#define INT_CMD_VALID(x)	((x) & INT_MASK_CMD)
#define INT_NON_CMD(x)		(INT_MASK_VALID | (x))
#define INT_CMD(x)		(INT_MASK_VALID | INT_MASK_CMD | (x))

#define EXT_UDL_MASK		0xF000
#define EXT_UDL_CMD(x)		((x) & EXT_UDL_MASK)
#define EXT_INT_VALID_MASK	0x8000
#define EXT_CMD_VALID_MASK	0x4000
#define UDL_CMD_VALID_MASK	0x2000
#define EXT_INT_VALID(x)	((x) & EXT_INT_VALID_MASK)
#define EXT_CMD_VALID(x)	((x) & EXT_CMD_VALID_MASK)
#define UDL_CMD_VALID(x)	((x) & UDL_CMD_VALID_MASK)
#define INT_EXT_CMD(x)		(EXT_INT_VALID_MASK | EXT_CMD_VALID_MASK | (x))

#define EXT_CMD_MASK(x)		((x) & 0x0FFF)
#define EXT_CMD_SET_SPEED_LOW	0x0011
#define EXT_CMD_SET_SPEED_MID	0x0012
#define EXT_CMD_SET_SPEED_HIGH	0x0013

#define UDL_RESULT_SUCCESS	0x1
#define UDL_RESULT_FAIL		0x2

#define UDL_CMD_MASK(x)		(((x) >> 8) & 0xF)
#define UDL_CMD_RECV_READY	0x1
#define UDL_CMD_DL_START_REQ	0x2
#define UDL_CMD_DL_START_RESP	0x3
#define UDL_CMD_IMAGE_SEND_REQ	0x4
#define UDL_CMD_SEND_DONE_RESP	0x5
#define UDL_CMD_SEND_DONE_REQ	0x6
#define UDL_CMD_UPDATE_DONE	0x7
#define UDL_CMD_STATUS_UPDATE	0x8
#define UDL_CMD_IMAGE_SEND_RESP	0x9
#define UDL_CMD_EFS_CLEAR_RESP	0xB
#define UDL_CMD_ALARM_BOOT_OK	0xC
#define UDL_CMD_ALARM_BOOT_FAIL	0xD

#define CMD_DL_READY		0xA100
#define CMD_DL_START_REQ	0x9200
#define CMD_DL_START_RESP	0xA301
#define CMD_DL_SEND_REQ		0x9400
#define CMD_DL_SEND_RESP	0xA501
#define CMD_DL_DONE_REQ		0x9600
#define CMD_DL_DONE_RESP	0xA701

#define CMD_UL_RECV_RESP	0x9601
#define CMD_UL_RECV_DONE_REQ	0xA700
#define CMD_UL_RECV_DONE_RESP	0x9801

/* special interrupt cmd indicating modem boot failure. */
#define INT_POWERSAFE_FAIL	0xDEAD

#define INT_MASK_REQ_ACK_F	0x0020
#define INT_MASK_REQ_ACK_R	0x0010
#define INT_MASK_RES_ACK_F	0x0008
#define INT_MASK_RES_ACK_R	0x0004
#define INT_MASK_SEND_F		0x0002
#define INT_MASK_SEND_R		0x0001

#define INT_MASK_REQ_ACK_RFS	0x0400 /* Request RES_ACK_RFS		*/
#define INT_MASK_RES_ACK_RFS	0x0200 /* Response of REQ_ACK_RFS	*/
#define INT_MASK_SEND_RFS	0x0100 /* Indicate sending RFS data	*/

#define INT_MASK_REQ_ACK_SET \
	(INT_MASK_REQ_ACK_F | INT_MASK_REQ_ACK_R | INT_MASK_REQ_ACK_RFS)

#define INT_MASK_RES_ACK_SET \
	(INT_MASK_RES_ACK_F | INT_MASK_RES_ACK_R | INT_MASK_RES_ACK_RFS)

#define INT_CMD_MASK(x)			((x) & 0xF)
#define INT_CMD_INIT_START		0x1
#define INT_CMD_INIT_END		0x2
#define INT_CMD_REQ_ACTIVE		0x3
#define INT_CMD_RES_ACTIVE		0x4
#define INT_CMD_REQ_TIME_SYNC		0x5
#define INT_CMD_CRASH_RESET		0x7
#define INT_CMD_PHONE_START		0x8
#define INT_CMD_ERR_DISPLAY		0x9
#define INT_CMD_CRASH_EXIT		0x9
#define INT_CMD_CP_DEEP_SLEEP		0xA
#define INT_CMD_NV_REBUILDING		0xB
#define INT_CMD_EMER_DOWN		0xC
#define INT_CMD_PIF_INIT_DONE		0xD
#define INT_CMD_SILENT_NV_REBUILDING	0xE
#define INT_CMD_NORMAL_POWER_OFF	0xF

/* AP_IDPRAM PM control command with QSC6085 */
#define INT_CMD_IDPRAM_SUSPEND_REQ	0xD
#define INT_CMD_IDPRAM_SUSPEND_ACK	0xB
#define INT_CMD_IDPRAM_WAKEUP_START	0xE
#define INT_CMD_IDPRAM_RESUME_REQ	0xC

#define START_FLAG		0x7F
#define END_FLAG		0x7E

#define DP_MAGIC_DMDL		0x4445444C
#define DP_MAGIC_UMDL		0x4445444D
#define DP_DPRAM_SIZE		0x4000
#define DP_DEFAULT_WRITE_LEN	8168
#define DP_DEFAULT_DUMP_LEN	16128
#define DP_DUMP_HEADER_SIZE	7

#define UDL_TIMEOUT		(50 * HZ)
#define UDL_SEND_TIMEOUT	(200 * HZ)
#define FORCE_CRASH_ACK_TIMEOUT	(5 * HZ)
#define DUMP_TIMEOUT		(30 * HZ)
#define DUMP_START_TIMEOUT	(100 * HZ)
#define DUMP_WAIT_TIMEOUT	(HZ >> 10)	/* 1/1024 second */

#define IDPRAM_SUSPEND_REQ_TIMEOUT	(50 * HZ)

#define RES_ACK_WAIT_TIMEOUT	10		/* 10 ms */
#define REQ_ACK_DELAY		10		/* 10 ms */

#ifdef DEBUG_MODEM_IF
#define MAX_RETRY_CNT	1
#else
#define MAX_RETRY_CNT	3
#endif

#define MAX_SKB_TXQ_DEPTH	1024

struct memif_boot_map {
	u32 __iomem *magic;
	u8  __iomem *buff;
	u32 __iomem *req;
	u32 __iomem *resp;
	u32          space;
};

struct memif_dload_map {
	u32 __iomem *magic;
	u8  __iomem *buff;
	u32 space;
};

struct memif_uload_map {
	u32 __iomem *magic;
	u8  __iomem *cmd;
	u32 cmd_size;
	u8  __iomem *buff;
	u32 space;
};

#define DP_BOOT_BUFF_OFFSET	4
#define DP_DLOAD_MAGIC_SIZE	4
#define DP_DLOAD_BUFF_OFFSET	4
#define DP_ULOAD_MAGIC_SIZE	4
#define DP_ULOAD_BUFF_OFFSET	4
#define DP_BOOT_REQ_OFFSET	0
#define DP_BOOT_RESP_OFFSET	8
#define DP_MBX_SET_SIZE		4
#define DP_MAX_PAYLOAD_SIZE	0x2000

enum circ_dir_type {
	TX,
	RX,
	MAX_DIR,
};

enum circ_ptr_type {
	HEAD,
	TAIL,
};

static inline bool circ_valid(u32 qsize, u32 in, u32 out)
{
	if (in >= qsize)
		return false;

	if (out >= qsize)
		return false;

	return true;
}

static inline u32 circ_get_space(u32 qsize, u32 in, u32 out)
{
	return (in < out) ? (out - in - 1) : (qsize + out - in - 1);
}

static inline u32 circ_get_usage(u32 qsize, u32 in, u32 out)
{
	return (in >= out) ? (in - out) : (qsize - out + in);
}

static inline u32 circ_new_pointer(u32 qsize, u32 p, u32 len)
{
	p += len;
	return (p < qsize) ? p : (p - qsize);
}

/**
 * circ_read
 * @dst: start address of the destination buffer
 * @src: start address of the buffer in a circular queue
 * @qsize: size of the circular queue
 * @out: offset to read
 * @len: length of data to be read
 *
 * Should be invoked after checking data length
 */
static inline void circ_read(void *dst, void *src, u32 qsize, u32 out, u32 len)
{
	unsigned len1;

	if ((out + len) <= qsize) {
		/* ----- (out)         (in) ----- */
		/* -----   7f 00 00 7e      ----- */
		memcpy(dst, (src + out), len);
	} else {
		/*       (in) ----------- (out)   */
		/* 00 7e      -----------   7f 00 */

		/* 1) data start (out) ~ buffer end */
		len1 = qsize - out;
		memcpy(dst, (src + out), len1);

		/* 2) buffer start ~ data end (in?) */
		memcpy((dst + len1), src, (len - len1));
	}
}

/**
 * circ_write
 * @dst: pointer to the start of the circular queue
 * @src: pointer to the source
 * @qsize: size of the circular queue
 * @in: offset to write
 * @len: length of data to be written
 *
 * Should be invoked after checking free space
 */
static inline void circ_write(void *dst, void *src, u32 qsize, u32 in, u32 len)
{
	u32 space;

	if ((in + len) < qsize) {
		/*       (in) ----------- (out)   */
		/* 00 7e      -----------   7f 00 */
		memcpy((dst + in), src, len);
	} else {
		/* ----- (out)         (in) ----- */
		/* -----   7f 00 00 7e      ----- */

		/* 1) space start (in) ~ buffer end */
		space = qsize - in;
		memcpy((dst + in), src, ((len > space) ? space : len));

		/* 2) buffer start ~ data end */
		if (len > space)
			memcpy(dst, (src + space), (len - space));
	}
}

/**
 * circ_dir
 * @dir: communication direction (enum circ_dir_type)
 *
 * Returns the direction of a circular queue
 *
 */
static const inline char *circ_dir(enum circ_dir_type dir)
{
	if (dir == TX)
		return "TXQ";
	else
		return "RXQ";
}

/**
 * circ_ptr
 * @ptr: circular queue pointer (enum circ_ptr_type)
 *
 * Returns the name of a circular queue pointer
 *
 */
static const inline char *circ_ptr(enum circ_ptr_type ptr)
{
	if (ptr == HEAD)
		return "head";
	else
		return "tail";
}

/**
 * get_dir_str
 * @dir: communication direction (enum circ_dir_type)
 *
 * Returns the direction of a circular queue
 *
 */
static const inline char *get_dir_str(enum circ_dir_type dir)
{
	if (dir == TX)
		return "AP->CP";
	else
		return "CP->AP";
}

void memcpy16_from_io(const void *to, const void __iomem *from, u32 count);
void memcpy16_to_io(const void __iomem *to, const void *from, u32 count);
int memcmp16_to_io(const void __iomem *to, const void *from, u32 count);
void circ_read16_from_io(void *dst, void *src, u32 qsize, u32 out, u32 len);
void circ_write16_to_io(void *dst, void *src, u32 qsize, u32 in, u32 len);
int copy_circ_to_user(void __user *dst, void *src, u32 qsize, u32 out, u32 len);
int copy_user_to_circ(void *dst, void __user *src, u32 qsize, u32 in, u32 len);

#define MAX_MEM_LOG_CNT	8192
#define MAX_TRACE_SIZE	1024

struct mem_status {
	/* Timestamp */
	struct timespec ts;

	/* Direction (TX or RX) */
	enum circ_dir_type dir;

	/* The status of memory interface at the time */
	u32 magic;
	u32 access;

	u32 head[MAX_IPC_DEV][MAX_DIR];
	u32 tail[MAX_IPC_DEV][MAX_DIR];

	u16 int2ap;
	u16 int2cp;
};

struct mem_status_queue {
	spinlock_t lock;
	u32 in;
	u32 out;
	struct mem_status stat[MAX_MEM_LOG_CNT];
};

struct circ_status {
	u8 *buff;
	u32 qsize;	/* the size of a circular buffer */
	u32 in;
	u32 out;
	u32 size;	/* the size of free space or received data */
};

struct trace_data {
	struct timespec ts;
	enum dev_format dev;
	struct circ_status circ_stat;
	u8 *data;
	u32 size;
};

struct trace_data_queue {
	spinlock_t lock;
	u32 in;
	u32 out;
	struct trace_data trd[MAX_TRACE_SIZE];
};

struct mem_status *msq_get_free_slot(struct mem_status_queue *msq);
struct mem_status *msq_get_data_slot(struct mem_status_queue *msq);

void print_mem_status(struct link_device *ld, struct mem_status *mst);
void print_circ_status(struct link_device *ld, int dev, struct mem_status *mst);
void print_ipc_trace(struct link_device *ld, int dev, struct circ_status *stat,
			struct timespec *ts, u8 *buff, u32 rcvd);

u8 *capture_mem_dump(struct link_device *ld, u8 *base, u32 size);
struct trace_data *trq_get_free_slot(struct trace_data_queue *trq);
struct trace_data *trq_get_data_slot(struct trace_data_queue *trq);

#endif