aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/modem_if_u1/modem_link_device_memory.h
blob: 2e83f0bd8ecdafbf87a61aa9db119cb18357c1d8 (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
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
/*
 * 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/platform_data/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_IMG_START_REQ	0x9200
#define CMD_IMG_SEND_REQ	0x9400
#define CMD_DL_SEND_DONE_REQ	0x9600
#define CMD_UL_RECV_RESP	0x9601
#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_RES_ACK_SET \
	(INT_MASK_RES_ACK_F | INT_MASK_RES_ACK_R | INT_MASK_RES_ACK_RFS)

#define INT_MASK_SEND_SET \
	(INT_MASK_SEND_F | INT_MASK_SEND_R | INT_MASK_SEND_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_PWR_OFF	0xF

#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 RES_ACK_WAIT_TIMEOUT	(HZ >> 8)	/* 1/256 second */
#define REQ_ACK_DELAY		(HZ >> 7)	/* 1/128 second */

#ifndef CONFIG_SAMSUNG_PRODUCT_SHIP
#define MAX_RETRY_CNT	1
#else
#define MAX_RETRY_CNT	3
#endif

#define MAX_SKB_TXQ_DEPTH	1024

enum host_boot_mode {
	HOST_BOOT_MODE_NORMAL,
	HOST_BOOT_MODE_DUMP,
};

enum dpram_init_status {
	DPRAM_INIT_STATE_NONE,
	DPRAM_INIT_STATE_READY,
};

enum circ_dir_type {
	TX,
	RX,
};

enum circ_ptr_type {
	HEAD,
	TAIL,
};

struct dpram_boot_img {
	char *addr;
	int size;
	enum host_boot_mode mode;
	unsigned req;
	unsigned resp;
};

#define MAX_PAYLOAD_SIZE 0x2000
struct dpram_boot_frame {
	unsigned req;		/* AP->CP request		*/
	unsigned resp;		/* response expected by AP	*/
	ssize_t len;		/* data size in the buffer	*/
	unsigned offset;	/* offset to write into DPRAM	*/
	char data[MAX_PAYLOAD_SIZE];
};

/* buffer type for modem image */
struct dpram_dump_arg {
	char *buff;		/* pointer to the buffer	*/
	int buff_size;		/* buffer size			*/
	unsigned req;		/* AP->CP request		*/
	unsigned resp;		/* CP->AP response		*/
	bool cmd;		/* AP->CP command		*/
};

struct dpram_boot_map {
	u32 __iomem *magic;
	u8  __iomem *buff;
	u32 __iomem *req;
	u32 __iomem *resp;
	u32          size;
};

struct qc_dpram_boot_map {
	u8 __iomem *buff;
	u16 __iomem *frame_size;
	u16 __iomem *tag;
	u16 __iomem *count;
};

struct dpram_dload_map {
	u32 __iomem *magic;
	u8  __iomem *buff;
};

struct dpram_uload_map {
	u32 __iomem *magic;
	u8  __iomem *buff;
};

struct ul_header {
	u8  bop;
	u16 total_frame;
	u16 curr_frame;
	u16 len;
} __packed;

struct dpram_udl_param {
	unsigned char *addr;
	unsigned int size;
	unsigned int count;
	unsigned int tag;
};

struct dpram_udl_check {
	unsigned int total_size;
	unsigned int rest_size;
	unsigned int send_size;
	unsigned int copy_start;
	unsigned int copy_complete;
	unsigned int boot_complete;
};

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

#define DP_BOOT_BUFF_OFFSET	4
#define DP_DLOAD_BUFF_OFFSET	4
#define DP_ULOAD_BUFF_OFFSET	4
#define DP_BOOT_REQ_OFFSET	0
#define DP_BOOT_RESP_OFFSET	8

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 int circ_get_space(int qsize, int in, int out)
{
	return (in < out) ? (out - in - 1) : (qsize + out - in - 1);
}

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

/**
 * 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(u8 *dst, u8 __iomem *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(u8 __iomem *dst, u8 *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";
}

#if 1
#define DPRAM_MAX_RXBQ_SIZE	256

struct mif_rxb {
	u8 *buff;
	unsigned size;

	u8 *data;
	unsigned len;
};

struct mif_rxb_queue {
	int size;
	int in;
	int out;
	struct mif_rxb *rxb;
};

/*
** RXB (DPRAM RX buffer) functions
*/
static inline struct mif_rxb *rxbq_create_pool(unsigned size, int count)
{
	struct mif_rxb *rxb;
	u8 *buff;
	int i;

	rxb = kzalloc(sizeof(struct mif_rxb) * count, GFP_KERNEL);
	if (!rxb) {
		mif_info("ERR! kzalloc rxb fail\n");
		return NULL;
	}

	buff = kzalloc((size * count), GFP_KERNEL|GFP_DMA);
	if (!buff) {
		mif_info("ERR! kzalloc buff fail\n");
		kfree(rxb);
		return NULL;
	}

	for (i = 0; i < count; i++) {
		rxb[i].buff = buff;
		rxb[i].size = size;
		buff += size;
	}

	return rxb;
}

static inline unsigned rxbq_get_page_size(unsigned len)
{
	return ((len + PAGE_SIZE - 1) >> PAGE_SHIFT) << PAGE_SHIFT;
}

static inline bool rxbq_empty(struct mif_rxb_queue *rxbq)
{
	return (rxbq->in == rxbq->out) ? true : false;
}

static inline int rxbq_free_size(struct mif_rxb_queue *rxbq)
{
	int in = rxbq->in;
	int out = rxbq->out;
	int qsize = rxbq->size;
	return (in < out) ? (out - in - 1) : (qsize + out - in - 1);
}

static inline struct mif_rxb *rxbq_get_free_rxb(struct mif_rxb_queue *rxbq)
{
	struct mif_rxb *rxb = NULL;

	if (likely(rxbq_free_size(rxbq) > 0)) {
		rxb = &rxbq->rxb[rxbq->in];
		rxbq->in++;
		if (rxbq->in >= rxbq->size)
			rxbq->in -= rxbq->size;
		rxb->data = rxb->buff;
	}

	return rxb;
}

static inline int rxbq_size(struct mif_rxb_queue *rxbq)
{
	int in = rxbq->in;
	int out = rxbq->out;
	int qsize = rxbq->size;
	return (in >= out) ? (in - out) : (qsize - out + in);
}

static inline struct mif_rxb *rxbq_get_data_rxb(struct mif_rxb_queue *rxbq)
{
	struct mif_rxb *rxb = NULL;

	if (likely(!rxbq_empty(rxbq))) {
		rxb = &rxbq->rxb[rxbq->out];
		rxbq->out++;
		if (rxbq->out >= rxbq->size)
			rxbq->out -= rxbq->size;
	}

	return rxb;
}

static inline u8 *rxb_put(struct mif_rxb *rxb, unsigned len)
{
	rxb->len = len;
	return rxb->data;
}

static inline void rxb_clear(struct mif_rxb *rxb)
{
	rxb->data = NULL;
	rxb->len = 0;
}
#endif

#ifndef CONFIG_SAMSUNG_PRODUCT_SHIP
#define MAX_TRACE_SIZE	1024

struct trace_data {
	struct timespec ts;
	enum dev_format dev;
	u8 *data;
	int size;
};

struct trace_queue {
	spinlock_t lock;
	int in;
	int out;
	struct trace_data trd[MAX_TRACE_SIZE];
};

static inline struct trace_data *trq_get_free_slot(struct trace_queue *trq)
{
	int in = trq->in;
	int out = trq->out;
	int qsize = MAX_TRACE_SIZE;
	struct trace_data *trd = NULL;
	unsigned long int flags;

	spin_lock_irqsave(&trq->lock, flags);

	if (circ_get_space(qsize, in, out) < 1) {
		spin_unlock_irqrestore(&trq->lock, flags);
		return NULL;
	}

	trd = &trq->trd[in];

	in++;
	if (in == qsize)
		trq->in = 0;
	else
		trq->in = in;

	spin_unlock_irqrestore(&trq->lock, flags);

	return trd;
}

static inline struct trace_data *trq_get_data_slot(struct trace_queue *trq)
{
	int in = trq->in;
	int out = trq->out;
	int qsize = MAX_TRACE_SIZE;
	struct trace_data *trd = NULL;
	unsigned long int flags;

	spin_lock_irqsave(&trq->lock, flags);

	if (circ_get_usage(qsize, in, out) < 1) {
		spin_unlock_irqrestore(&trq->lock, flags);
		return NULL;
	}

	trd = &trq->trd[out];

	out++;
	if (out == qsize)
		trq->out = 0;
	else
		trq->out = out;

	spin_unlock_irqrestore(&trq->lock, flags);

	return trd;
}
#endif

#endif