diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-msm/Kconfig | 10 | ||||
-rw-r--r-- | arch/arm/mach-msm/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-msm/include/mach/msm_smd.h | 107 | ||||
-rw-r--r-- | arch/arm/mach-msm/include/mach/system.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-msm/smd.c | 1330 | ||||
-rw-r--r-- | arch/arm/mach-msm/smd_private.h | 171 |
6 files changed, 1625 insertions, 1 deletions
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index b9fd5c528e5b..7cee7913f6f7 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig | |||
@@ -42,4 +42,14 @@ config MACH_TROUT | |||
42 | help | 42 | help |
43 | Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. | 43 | Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. |
44 | 44 | ||
45 | config MSM_SMD | ||
46 | default y | ||
47 | bool "MSM Shared Memory Driver (SMD)" | ||
48 | help | ||
49 | Support for the shared memory interface between the apps | ||
50 | processor and the baseband processor. Provides access to | ||
51 | the "shared heap", as well as virtual serial channels | ||
52 | used to communicate with various services on the baseband | ||
53 | processor. | ||
54 | |||
45 | endif | 55 | endif |
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 86bad4f0dc7b..d23fd0bf9fcc 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile | |||
@@ -5,6 +5,7 @@ obj-y += vreg.o | |||
5 | obj-y += acpuclock-arm11.o | 5 | obj-y += acpuclock-arm11.o |
6 | obj-y += clock.o clock-7x01a.o | 6 | obj-y += clock.o clock-7x01a.o |
7 | 7 | ||
8 | obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o | 8 | obj-$(CONFIG_MSM_SMD) += smd.o |
9 | 9 | ||
10 | obj-$(CONFIG_MACH_TROUT) += board-trout.o | 10 | obj-$(CONFIG_MACH_TROUT) += board-trout.o |
11 | obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o | ||
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h new file mode 100644 index 000000000000..bdf7731ab680 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_smd.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* linux/include/asm-arm/arch-msm/msm_smd.h | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * Author: Brian Swetland <swetland@google.com> | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __ASM_ARCH_MSM_SMD_H | ||
18 | #define __ASM_ARCH_MSM_SMD_H | ||
19 | |||
20 | typedef struct smd_channel smd_channel_t; | ||
21 | |||
22 | /* warning: notify() may be called before open returns */ | ||
23 | int smd_open(const char *name, smd_channel_t **ch, void *priv, | ||
24 | void (*notify)(void *priv, unsigned event)); | ||
25 | |||
26 | #define SMD_EVENT_DATA 1 | ||
27 | #define SMD_EVENT_OPEN 2 | ||
28 | #define SMD_EVENT_CLOSE 3 | ||
29 | |||
30 | int smd_close(smd_channel_t *ch); | ||
31 | |||
32 | /* passing a null pointer for data reads and discards */ | ||
33 | int smd_read(smd_channel_t *ch, void *data, int len); | ||
34 | |||
35 | /* Write to stream channels may do a partial write and return | ||
36 | ** the length actually written. | ||
37 | ** Write to packet channels will never do a partial write -- | ||
38 | ** it will return the requested length written or an error. | ||
39 | */ | ||
40 | int smd_write(smd_channel_t *ch, const void *data, int len); | ||
41 | |||
42 | int smd_write_avail(smd_channel_t *ch); | ||
43 | int smd_read_avail(smd_channel_t *ch); | ||
44 | |||
45 | /* Returns the total size of the current packet being read. | ||
46 | ** Returns 0 if no packets available or a stream channel. | ||
47 | */ | ||
48 | int smd_cur_packet_size(smd_channel_t *ch); | ||
49 | |||
50 | /* used for tty unthrottling and the like -- causes the notify() | ||
51 | ** callback to be called from the same lock context as is used | ||
52 | ** when it is called from channel updates | ||
53 | */ | ||
54 | void smd_kick(smd_channel_t *ch); | ||
55 | |||
56 | |||
57 | #if 0 | ||
58 | /* these are interruptable waits which will block you until the specified | ||
59 | ** number of bytes are readable or writable. | ||
60 | */ | ||
61 | int smd_wait_until_readable(smd_channel_t *ch, int bytes); | ||
62 | int smd_wait_until_writable(smd_channel_t *ch, int bytes); | ||
63 | #endif | ||
64 | |||
65 | typedef enum | ||
66 | { | ||
67 | SMD_PORT_DS = 0, | ||
68 | SMD_PORT_DIAG, | ||
69 | SMD_PORT_RPC_CALL, | ||
70 | SMD_PORT_RPC_REPLY, | ||
71 | SMD_PORT_BT, | ||
72 | SMD_PORT_CONTROL, | ||
73 | SMD_PORT_MEMCPY_SPARE1, | ||
74 | SMD_PORT_DATA1, | ||
75 | SMD_PORT_DATA2, | ||
76 | SMD_PORT_DATA3, | ||
77 | SMD_PORT_DATA4, | ||
78 | SMD_PORT_DATA5, | ||
79 | SMD_PORT_DATA6, | ||
80 | SMD_PORT_DATA7, | ||
81 | SMD_PORT_DATA8, | ||
82 | SMD_PORT_DATA9, | ||
83 | SMD_PORT_DATA10, | ||
84 | SMD_PORT_DATA11, | ||
85 | SMD_PORT_DATA12, | ||
86 | SMD_PORT_DATA13, | ||
87 | SMD_PORT_DATA14, | ||
88 | SMD_PORT_DATA15, | ||
89 | SMD_PORT_DATA16, | ||
90 | SMD_PORT_DATA17, | ||
91 | SMD_PORT_DATA18, | ||
92 | SMD_PORT_DATA19, | ||
93 | SMD_PORT_DATA20, | ||
94 | SMD_PORT_GPS_NMEA, | ||
95 | SMD_PORT_BRIDGE_1, | ||
96 | SMD_PORT_BRIDGE_2, | ||
97 | SMD_PORT_BRIDGE_3, | ||
98 | SMD_PORT_BRIDGE_4, | ||
99 | SMD_PORT_BRIDGE_5, | ||
100 | SMD_PORT_LOOPBACK, | ||
101 | SMD_PORT_CS_APPS_MODEM, | ||
102 | SMD_PORT_CS_APPS_DSP, | ||
103 | SMD_PORT_CS_MODEM_DSP, | ||
104 | SMD_NUM_PORTS, | ||
105 | } smd_port_id_type; | ||
106 | |||
107 | #endif | ||
diff --git a/arch/arm/mach-msm/include/mach/system.h b/arch/arm/mach-msm/include/mach/system.h index 574ccc493daf..d2e83f42ba16 100644 --- a/arch/arm/mach-msm/include/mach/system.h +++ b/arch/arm/mach-msm/include/mach/system.h | |||
@@ -21,3 +21,8 @@ static inline void arch_reset(char mode, const char *cmd) | |||
21 | { | 21 | { |
22 | for (;;) ; /* depends on IPC w/ other core */ | 22 | for (;;) ; /* depends on IPC w/ other core */ |
23 | } | 23 | } |
24 | |||
25 | /* low level hardware reset hook -- for example, hitting the | ||
26 | * PSHOLD line on the PMIC to hard reset the system | ||
27 | */ | ||
28 | extern void (*msm_hw_reset_hook)(void); | ||
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c new file mode 100644 index 000000000000..64d12323995e --- /dev/null +++ b/arch/arm/mach-msm/smd.c | |||
@@ -0,0 +1,1330 @@ | |||
1 | /* arch/arm/mach-msm/smd.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * Author: Brian Swetland <swetland@google.com> | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/cdev.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/wait.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/debugfs.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/io.h> | ||
30 | |||
31 | #include <mach/msm_smd.h> | ||
32 | #include <mach/msm_iomap.h> | ||
33 | #include <mach/system.h> | ||
34 | |||
35 | #include "smd_private.h" | ||
36 | #include "proc_comm.h" | ||
37 | |||
38 | void (*msm_hw_reset_hook)(void); | ||
39 | |||
40 | #define MODULE_NAME "msm_smd" | ||
41 | |||
42 | enum { | ||
43 | MSM_SMD_DEBUG = 1U << 0, | ||
44 | MSM_SMSM_DEBUG = 1U << 0, | ||
45 | }; | ||
46 | |||
47 | static int msm_smd_debug_mask; | ||
48 | |||
49 | module_param_named(debug_mask, msm_smd_debug_mask, | ||
50 | int, S_IRUGO | S_IWUSR | S_IWGRP); | ||
51 | |||
52 | void *smem_find(unsigned id, unsigned size); | ||
53 | static void smd_diag(void); | ||
54 | |||
55 | static unsigned last_heap_free = 0xffffffff; | ||
56 | |||
57 | #define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4) | ||
58 | |||
59 | static inline void notify_other_smsm(void) | ||
60 | { | ||
61 | writel(1, MSM_A2M_INT(5)); | ||
62 | } | ||
63 | |||
64 | static inline void notify_other_smd(void) | ||
65 | { | ||
66 | writel(1, MSM_A2M_INT(0)); | ||
67 | } | ||
68 | |||
69 | static void smd_diag(void) | ||
70 | { | ||
71 | char *x; | ||
72 | |||
73 | x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); | ||
74 | if (x != 0) { | ||
75 | x[SZ_DIAG_ERR_MSG - 1] = 0; | ||
76 | pr_info("smem: DIAG '%s'\n", x); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* call when SMSM_RESET flag is set in the A9's smsm_state */ | ||
81 | static void handle_modem_crash(void) | ||
82 | { | ||
83 | pr_err("ARM9 has CRASHED\n"); | ||
84 | smd_diag(); | ||
85 | |||
86 | /* hard reboot if possible */ | ||
87 | if (msm_hw_reset_hook) | ||
88 | msm_hw_reset_hook(); | ||
89 | |||
90 | /* in this case the modem or watchdog should reboot us */ | ||
91 | for (;;) | ||
92 | ; | ||
93 | } | ||
94 | |||
95 | extern int (*msm_check_for_modem_crash)(void); | ||
96 | |||
97 | static int check_for_modem_crash(void) | ||
98 | { | ||
99 | struct smsm_shared *smsm; | ||
100 | |||
101 | smsm = smem_find(ID_SHARED_STATE, 2 * sizeof(struct smsm_shared)); | ||
102 | |||
103 | /* if the modem's not ready yet, we have to hope for the best */ | ||
104 | if (!smsm) | ||
105 | return 0; | ||
106 | |||
107 | if (smsm[1].state & SMSM_RESET) { | ||
108 | handle_modem_crash(); | ||
109 | return -1; | ||
110 | } else { | ||
111 | return 0; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | #define SMD_SS_CLOSED 0x00000000 | ||
116 | #define SMD_SS_OPENING 0x00000001 | ||
117 | #define SMD_SS_OPENED 0x00000002 | ||
118 | #define SMD_SS_FLUSHING 0x00000003 | ||
119 | #define SMD_SS_CLOSING 0x00000004 | ||
120 | #define SMD_SS_RESET 0x00000005 | ||
121 | #define SMD_SS_RESET_OPENING 0x00000006 | ||
122 | |||
123 | #define SMD_BUF_SIZE 8192 | ||
124 | #define SMD_CHANNELS 64 | ||
125 | |||
126 | #define SMD_HEADER_SIZE 20 | ||
127 | |||
128 | |||
129 | /* the spinlock is used to synchronize between the | ||
130 | ** irq handler and code that mutates the channel | ||
131 | ** list or fiddles with channel state | ||
132 | */ | ||
133 | static DEFINE_SPINLOCK(smd_lock); | ||
134 | static DEFINE_SPINLOCK(smem_lock); | ||
135 | |||
136 | /* the mutex is used during open() and close() | ||
137 | ** operations to avoid races while creating or | ||
138 | ** destroying smd_channel structures | ||
139 | */ | ||
140 | static DEFINE_MUTEX(smd_creation_mutex); | ||
141 | |||
142 | static int smd_initialized; | ||
143 | |||
144 | struct smd_alloc_elm { | ||
145 | char name[20]; | ||
146 | uint32_t cid; | ||
147 | uint32_t ctype; | ||
148 | uint32_t ref_count; | ||
149 | }; | ||
150 | |||
151 | struct smd_half_channel { | ||
152 | unsigned state; | ||
153 | unsigned char fDSR; | ||
154 | unsigned char fCTS; | ||
155 | unsigned char fCD; | ||
156 | unsigned char fRI; | ||
157 | unsigned char fHEAD; | ||
158 | unsigned char fTAIL; | ||
159 | unsigned char fSTATE; | ||
160 | unsigned char fUNUSED; | ||
161 | unsigned tail; | ||
162 | unsigned head; | ||
163 | unsigned char data[SMD_BUF_SIZE]; | ||
164 | }; | ||
165 | |||
166 | struct smd_shared { | ||
167 | struct smd_half_channel ch0; | ||
168 | struct smd_half_channel ch1; | ||
169 | }; | ||
170 | |||
171 | struct smd_channel { | ||
172 | volatile struct smd_half_channel *send; | ||
173 | volatile struct smd_half_channel *recv; | ||
174 | struct list_head ch_list; | ||
175 | |||
176 | unsigned current_packet; | ||
177 | unsigned n; | ||
178 | void *priv; | ||
179 | void (*notify)(void *priv, unsigned flags); | ||
180 | |||
181 | int (*read)(smd_channel_t *ch, void *data, int len); | ||
182 | int (*write)(smd_channel_t *ch, const void *data, int len); | ||
183 | int (*read_avail)(smd_channel_t *ch); | ||
184 | int (*write_avail)(smd_channel_t *ch); | ||
185 | |||
186 | void (*update_state)(smd_channel_t *ch); | ||
187 | unsigned last_state; | ||
188 | |||
189 | char name[32]; | ||
190 | struct platform_device pdev; | ||
191 | }; | ||
192 | |||
193 | static LIST_HEAD(smd_ch_closed_list); | ||
194 | static LIST_HEAD(smd_ch_list); | ||
195 | |||
196 | static unsigned char smd_ch_allocated[64]; | ||
197 | static struct work_struct probe_work; | ||
198 | |||
199 | static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type); | ||
200 | |||
201 | static void smd_channel_probe_worker(struct work_struct *work) | ||
202 | { | ||
203 | struct smd_alloc_elm *shared; | ||
204 | unsigned n; | ||
205 | |||
206 | shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); | ||
207 | |||
208 | for (n = 0; n < 64; n++) { | ||
209 | if (smd_ch_allocated[n]) | ||
210 | continue; | ||
211 | if (!shared[n].ref_count) | ||
212 | continue; | ||
213 | if (!shared[n].name[0]) | ||
214 | continue; | ||
215 | smd_alloc_channel(shared[n].name, | ||
216 | shared[n].cid, | ||
217 | shared[n].ctype); | ||
218 | smd_ch_allocated[n] = 1; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static char *chstate(unsigned n) | ||
223 | { | ||
224 | switch (n) { | ||
225 | case SMD_SS_CLOSED: | ||
226 | return "CLOSED"; | ||
227 | case SMD_SS_OPENING: | ||
228 | return "OPENING"; | ||
229 | case SMD_SS_OPENED: | ||
230 | return "OPENED"; | ||
231 | case SMD_SS_FLUSHING: | ||
232 | return "FLUSHING"; | ||
233 | case SMD_SS_CLOSING: | ||
234 | return "CLOSING"; | ||
235 | case SMD_SS_RESET: | ||
236 | return "RESET"; | ||
237 | case SMD_SS_RESET_OPENING: | ||
238 | return "ROPENING"; | ||
239 | default: | ||
240 | return "UNKNOWN"; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* how many bytes are available for reading */ | ||
245 | static int smd_stream_read_avail(struct smd_channel *ch) | ||
246 | { | ||
247 | return (ch->recv->head - ch->recv->tail) & (SMD_BUF_SIZE - 1); | ||
248 | } | ||
249 | |||
250 | /* how many bytes we are free to write */ | ||
251 | static int smd_stream_write_avail(struct smd_channel *ch) | ||
252 | { | ||
253 | return (SMD_BUF_SIZE - 1) - | ||
254 | ((ch->send->head - ch->send->tail) & (SMD_BUF_SIZE - 1)); | ||
255 | } | ||
256 | |||
257 | static int smd_packet_read_avail(struct smd_channel *ch) | ||
258 | { | ||
259 | if (ch->current_packet) { | ||
260 | int n = smd_stream_read_avail(ch); | ||
261 | if (n > ch->current_packet) | ||
262 | n = ch->current_packet; | ||
263 | return n; | ||
264 | } else { | ||
265 | return 0; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | static int smd_packet_write_avail(struct smd_channel *ch) | ||
270 | { | ||
271 | int n = smd_stream_write_avail(ch); | ||
272 | return n > SMD_HEADER_SIZE ? n - SMD_HEADER_SIZE : 0; | ||
273 | } | ||
274 | |||
275 | static int ch_is_open(struct smd_channel *ch) | ||
276 | { | ||
277 | return (ch->recv->state == SMD_SS_OPENED) && | ||
278 | (ch->send->state == SMD_SS_OPENED); | ||
279 | } | ||
280 | |||
281 | /* provide a pointer and length to readable data in the fifo */ | ||
282 | static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr) | ||
283 | { | ||
284 | unsigned head = ch->recv->head; | ||
285 | unsigned tail = ch->recv->tail; | ||
286 | *ptr = (void *) (ch->recv->data + tail); | ||
287 | |||
288 | if (tail <= head) | ||
289 | return head - tail; | ||
290 | else | ||
291 | return SMD_BUF_SIZE - tail; | ||
292 | } | ||
293 | |||
294 | /* advance the fifo read pointer after data from ch_read_buffer is consumed */ | ||
295 | static void ch_read_done(struct smd_channel *ch, unsigned count) | ||
296 | { | ||
297 | BUG_ON(count > smd_stream_read_avail(ch)); | ||
298 | ch->recv->tail = (ch->recv->tail + count) & (SMD_BUF_SIZE - 1); | ||
299 | ch->recv->fTAIL = 1; | ||
300 | } | ||
301 | |||
302 | /* basic read interface to ch_read_{buffer,done} used | ||
303 | ** by smd_*_read() and update_packet_state() | ||
304 | ** will read-and-discard if the _data pointer is null | ||
305 | */ | ||
306 | static int ch_read(struct smd_channel *ch, void *_data, int len) | ||
307 | { | ||
308 | void *ptr; | ||
309 | unsigned n; | ||
310 | unsigned char *data = _data; | ||
311 | int orig_len = len; | ||
312 | |||
313 | while (len > 0) { | ||
314 | n = ch_read_buffer(ch, &ptr); | ||
315 | if (n == 0) | ||
316 | break; | ||
317 | |||
318 | if (n > len) | ||
319 | n = len; | ||
320 | if (_data) | ||
321 | memcpy(data, ptr, n); | ||
322 | |||
323 | data += n; | ||
324 | len -= n; | ||
325 | ch_read_done(ch, n); | ||
326 | } | ||
327 | |||
328 | return orig_len - len; | ||
329 | } | ||
330 | |||
331 | static void update_stream_state(struct smd_channel *ch) | ||
332 | { | ||
333 | /* streams have no special state requiring updating */ | ||
334 | } | ||
335 | |||
336 | static void update_packet_state(struct smd_channel *ch) | ||
337 | { | ||
338 | unsigned hdr[5]; | ||
339 | int r; | ||
340 | |||
341 | /* can't do anything if we're in the middle of a packet */ | ||
342 | if (ch->current_packet != 0) | ||
343 | return; | ||
344 | |||
345 | /* don't bother unless we can get the full header */ | ||
346 | if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE) | ||
347 | return; | ||
348 | |||
349 | r = ch_read(ch, hdr, SMD_HEADER_SIZE); | ||
350 | BUG_ON(r != SMD_HEADER_SIZE); | ||
351 | |||
352 | ch->current_packet = hdr[0]; | ||
353 | } | ||
354 | |||
355 | /* provide a pointer and length to next free space in the fifo */ | ||
356 | static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr) | ||
357 | { | ||
358 | unsigned head = ch->send->head; | ||
359 | unsigned tail = ch->send->tail; | ||
360 | *ptr = (void *) (ch->send->data + head); | ||
361 | |||
362 | if (head < tail) { | ||
363 | return tail - head - 1; | ||
364 | } else { | ||
365 | if (tail == 0) | ||
366 | return SMD_BUF_SIZE - head - 1; | ||
367 | else | ||
368 | return SMD_BUF_SIZE - head; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | /* advace the fifo write pointer after freespace | ||
373 | * from ch_write_buffer is filled | ||
374 | */ | ||
375 | static void ch_write_done(struct smd_channel *ch, unsigned count) | ||
376 | { | ||
377 | BUG_ON(count > smd_stream_write_avail(ch)); | ||
378 | ch->send->head = (ch->send->head + count) & (SMD_BUF_SIZE - 1); | ||
379 | ch->send->fHEAD = 1; | ||
380 | } | ||
381 | |||
382 | static void hc_set_state(volatile struct smd_half_channel *hc, unsigned n) | ||
383 | { | ||
384 | if (n == SMD_SS_OPENED) { | ||
385 | hc->fDSR = 1; | ||
386 | hc->fCTS = 1; | ||
387 | hc->fCD = 1; | ||
388 | } else { | ||
389 | hc->fDSR = 0; | ||
390 | hc->fCTS = 0; | ||
391 | hc->fCD = 0; | ||
392 | } | ||
393 | hc->state = n; | ||
394 | hc->fSTATE = 1; | ||
395 | notify_other_smd(); | ||
396 | } | ||
397 | |||
398 | static void do_smd_probe(void) | ||
399 | { | ||
400 | struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; | ||
401 | if (shared->heap_info.free_offset != last_heap_free) { | ||
402 | last_heap_free = shared->heap_info.free_offset; | ||
403 | schedule_work(&probe_work); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | static void smd_state_change(struct smd_channel *ch, | ||
408 | unsigned last, unsigned next) | ||
409 | { | ||
410 | ch->last_state = next; | ||
411 | |||
412 | pr_info("SMD: ch %d %s -> %s\n", ch->n, | ||
413 | chstate(last), chstate(next)); | ||
414 | |||
415 | switch (next) { | ||
416 | case SMD_SS_OPENING: | ||
417 | ch->recv->tail = 0; | ||
418 | case SMD_SS_OPENED: | ||
419 | if (ch->send->state != SMD_SS_OPENED) | ||
420 | hc_set_state(ch->send, SMD_SS_OPENED); | ||
421 | ch->notify(ch->priv, SMD_EVENT_OPEN); | ||
422 | break; | ||
423 | case SMD_SS_FLUSHING: | ||
424 | case SMD_SS_RESET: | ||
425 | /* we should force them to close? */ | ||
426 | default: | ||
427 | ch->notify(ch->priv, SMD_EVENT_CLOSE); | ||
428 | } | ||
429 | } | ||
430 | |||
431 | static irqreturn_t smd_irq_handler(int irq, void *data) | ||
432 | { | ||
433 | unsigned long flags; | ||
434 | struct smd_channel *ch; | ||
435 | int do_notify = 0; | ||
436 | unsigned ch_flags; | ||
437 | unsigned tmp; | ||
438 | |||
439 | spin_lock_irqsave(&smd_lock, flags); | ||
440 | list_for_each_entry(ch, &smd_ch_list, ch_list) { | ||
441 | ch_flags = 0; | ||
442 | if (ch_is_open(ch)) { | ||
443 | if (ch->recv->fHEAD) { | ||
444 | ch->recv->fHEAD = 0; | ||
445 | ch_flags |= 1; | ||
446 | do_notify |= 1; | ||
447 | } | ||
448 | if (ch->recv->fTAIL) { | ||
449 | ch->recv->fTAIL = 0; | ||
450 | ch_flags |= 2; | ||
451 | do_notify |= 1; | ||
452 | } | ||
453 | if (ch->recv->fSTATE) { | ||
454 | ch->recv->fSTATE = 0; | ||
455 | ch_flags |= 4; | ||
456 | do_notify |= 1; | ||
457 | } | ||
458 | } | ||
459 | tmp = ch->recv->state; | ||
460 | if (tmp != ch->last_state) | ||
461 | smd_state_change(ch, ch->last_state, tmp); | ||
462 | if (ch_flags) { | ||
463 | ch->update_state(ch); | ||
464 | ch->notify(ch->priv, SMD_EVENT_DATA); | ||
465 | } | ||
466 | } | ||
467 | if (do_notify) | ||
468 | notify_other_smd(); | ||
469 | spin_unlock_irqrestore(&smd_lock, flags); | ||
470 | do_smd_probe(); | ||
471 | return IRQ_HANDLED; | ||
472 | } | ||
473 | |||
474 | static void smd_fake_irq_handler(unsigned long arg) | ||
475 | { | ||
476 | smd_irq_handler(0, NULL); | ||
477 | } | ||
478 | |||
479 | static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0); | ||
480 | |||
481 | void smd_sleep_exit(void) | ||
482 | { | ||
483 | unsigned long flags; | ||
484 | struct smd_channel *ch; | ||
485 | unsigned tmp; | ||
486 | int need_int = 0; | ||
487 | |||
488 | spin_lock_irqsave(&smd_lock, flags); | ||
489 | list_for_each_entry(ch, &smd_ch_list, ch_list) { | ||
490 | if (ch_is_open(ch)) { | ||
491 | if (ch->recv->fHEAD) { | ||
492 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
493 | pr_info("smd_sleep_exit ch %d fHEAD " | ||
494 | "%x %x %x\n", | ||
495 | ch->n, ch->recv->fHEAD, | ||
496 | ch->recv->head, ch->recv->tail); | ||
497 | need_int = 1; | ||
498 | break; | ||
499 | } | ||
500 | if (ch->recv->fTAIL) { | ||
501 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
502 | pr_info("smd_sleep_exit ch %d fTAIL " | ||
503 | "%x %x %x\n", | ||
504 | ch->n, ch->recv->fTAIL, | ||
505 | ch->send->head, ch->send->tail); | ||
506 | need_int = 1; | ||
507 | break; | ||
508 | } | ||
509 | if (ch->recv->fSTATE) { | ||
510 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
511 | pr_info("smd_sleep_exit ch %d fSTATE %x" | ||
512 | "\n", ch->n, ch->recv->fSTATE); | ||
513 | need_int = 1; | ||
514 | break; | ||
515 | } | ||
516 | tmp = ch->recv->state; | ||
517 | if (tmp != ch->last_state) { | ||
518 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
519 | pr_info("smd_sleep_exit ch %d " | ||
520 | "state %x != %x\n", | ||
521 | ch->n, tmp, ch->last_state); | ||
522 | need_int = 1; | ||
523 | break; | ||
524 | } | ||
525 | } | ||
526 | } | ||
527 | spin_unlock_irqrestore(&smd_lock, flags); | ||
528 | do_smd_probe(); | ||
529 | if (need_int) { | ||
530 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
531 | pr_info("smd_sleep_exit need interrupt\n"); | ||
532 | tasklet_schedule(&smd_fake_irq_tasklet); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | |||
537 | void smd_kick(smd_channel_t *ch) | ||
538 | { | ||
539 | unsigned long flags; | ||
540 | unsigned tmp; | ||
541 | |||
542 | spin_lock_irqsave(&smd_lock, flags); | ||
543 | ch->update_state(ch); | ||
544 | tmp = ch->recv->state; | ||
545 | if (tmp != ch->last_state) { | ||
546 | ch->last_state = tmp; | ||
547 | if (tmp == SMD_SS_OPENED) | ||
548 | ch->notify(ch->priv, SMD_EVENT_OPEN); | ||
549 | else | ||
550 | ch->notify(ch->priv, SMD_EVENT_CLOSE); | ||
551 | } | ||
552 | ch->notify(ch->priv, SMD_EVENT_DATA); | ||
553 | notify_other_smd(); | ||
554 | spin_unlock_irqrestore(&smd_lock, flags); | ||
555 | } | ||
556 | |||
557 | static int smd_is_packet(int chn) | ||
558 | { | ||
559 | if ((chn > 4) || (chn == 1)) | ||
560 | return 1; | ||
561 | else | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) | ||
566 | { | ||
567 | void *ptr; | ||
568 | const unsigned char *buf = _data; | ||
569 | unsigned xfer; | ||
570 | int orig_len = len; | ||
571 | |||
572 | if (len < 0) | ||
573 | return -EINVAL; | ||
574 | |||
575 | while ((xfer = ch_write_buffer(ch, &ptr)) != 0) { | ||
576 | if (!ch_is_open(ch)) | ||
577 | break; | ||
578 | if (xfer > len) | ||
579 | xfer = len; | ||
580 | memcpy(ptr, buf, xfer); | ||
581 | ch_write_done(ch, xfer); | ||
582 | len -= xfer; | ||
583 | buf += xfer; | ||
584 | if (len == 0) | ||
585 | break; | ||
586 | } | ||
587 | |||
588 | notify_other_smd(); | ||
589 | |||
590 | return orig_len - len; | ||
591 | } | ||
592 | |||
593 | static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) | ||
594 | { | ||
595 | unsigned hdr[5]; | ||
596 | |||
597 | if (len < 0) | ||
598 | return -EINVAL; | ||
599 | |||
600 | if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE)) | ||
601 | return -ENOMEM; | ||
602 | |||
603 | hdr[0] = len; | ||
604 | hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0; | ||
605 | |||
606 | smd_stream_write(ch, hdr, sizeof(hdr)); | ||
607 | smd_stream_write(ch, _data, len); | ||
608 | |||
609 | return len; | ||
610 | } | ||
611 | |||
612 | static int smd_stream_read(smd_channel_t *ch, void *data, int len) | ||
613 | { | ||
614 | int r; | ||
615 | |||
616 | if (len < 0) | ||
617 | return -EINVAL; | ||
618 | |||
619 | r = ch_read(ch, data, len); | ||
620 | if (r > 0) | ||
621 | notify_other_smd(); | ||
622 | |||
623 | return r; | ||
624 | } | ||
625 | |||
626 | static int smd_packet_read(smd_channel_t *ch, void *data, int len) | ||
627 | { | ||
628 | unsigned long flags; | ||
629 | int r; | ||
630 | |||
631 | if (len < 0) | ||
632 | return -EINVAL; | ||
633 | |||
634 | if (len > ch->current_packet) | ||
635 | len = ch->current_packet; | ||
636 | |||
637 | r = ch_read(ch, data, len); | ||
638 | if (r > 0) | ||
639 | notify_other_smd(); | ||
640 | |||
641 | spin_lock_irqsave(&smd_lock, flags); | ||
642 | ch->current_packet -= r; | ||
643 | update_packet_state(ch); | ||
644 | spin_unlock_irqrestore(&smd_lock, flags); | ||
645 | |||
646 | return r; | ||
647 | } | ||
648 | |||
649 | static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type) | ||
650 | { | ||
651 | struct smd_channel *ch; | ||
652 | struct smd_shared *shared; | ||
653 | |||
654 | shared = smem_alloc(ID_SMD_CHANNELS + cid, sizeof(*shared)); | ||
655 | if (!shared) { | ||
656 | pr_err("smd_alloc_channel() cid %d does not exist\n", cid); | ||
657 | return; | ||
658 | } | ||
659 | |||
660 | ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); | ||
661 | if (ch == 0) { | ||
662 | pr_err("smd_alloc_channel() out of memory\n"); | ||
663 | return; | ||
664 | } | ||
665 | |||
666 | ch->send = &shared->ch0; | ||
667 | ch->recv = &shared->ch1; | ||
668 | ch->n = cid; | ||
669 | |||
670 | if (smd_is_packet(cid)) { | ||
671 | ch->read = smd_packet_read; | ||
672 | ch->write = smd_packet_write; | ||
673 | ch->read_avail = smd_packet_read_avail; | ||
674 | ch->write_avail = smd_packet_write_avail; | ||
675 | ch->update_state = update_packet_state; | ||
676 | } else { | ||
677 | ch->read = smd_stream_read; | ||
678 | ch->write = smd_stream_write; | ||
679 | ch->read_avail = smd_stream_read_avail; | ||
680 | ch->write_avail = smd_stream_write_avail; | ||
681 | ch->update_state = update_stream_state; | ||
682 | } | ||
683 | |||
684 | memcpy(ch->name, "SMD_", 4); | ||
685 | memcpy(ch->name + 4, name, 20); | ||
686 | ch->name[23] = 0; | ||
687 | ch->pdev.name = ch->name; | ||
688 | ch->pdev.id = -1; | ||
689 | |||
690 | pr_info("smd_alloc_channel() '%s' cid=%d, shared=%p\n", | ||
691 | ch->name, ch->n, shared); | ||
692 | |||
693 | mutex_lock(&smd_creation_mutex); | ||
694 | list_add(&ch->ch_list, &smd_ch_closed_list); | ||
695 | mutex_unlock(&smd_creation_mutex); | ||
696 | |||
697 | platform_device_register(&ch->pdev); | ||
698 | } | ||
699 | |||
700 | static void do_nothing_notify(void *priv, unsigned flags) | ||
701 | { | ||
702 | } | ||
703 | |||
704 | struct smd_channel *smd_get_channel(const char *name) | ||
705 | { | ||
706 | struct smd_channel *ch; | ||
707 | |||
708 | mutex_lock(&smd_creation_mutex); | ||
709 | list_for_each_entry(ch, &smd_ch_closed_list, ch_list) { | ||
710 | if (!strcmp(name, ch->name)) { | ||
711 | list_del(&ch->ch_list); | ||
712 | mutex_unlock(&smd_creation_mutex); | ||
713 | return ch; | ||
714 | } | ||
715 | } | ||
716 | mutex_unlock(&smd_creation_mutex); | ||
717 | |||
718 | return NULL; | ||
719 | } | ||
720 | |||
721 | int smd_open(const char *name, smd_channel_t **_ch, | ||
722 | void *priv, void (*notify)(void *, unsigned)) | ||
723 | { | ||
724 | struct smd_channel *ch; | ||
725 | unsigned long flags; | ||
726 | |||
727 | if (smd_initialized == 0) { | ||
728 | pr_info("smd_open() before smd_init()\n"); | ||
729 | return -ENODEV; | ||
730 | } | ||
731 | |||
732 | ch = smd_get_channel(name); | ||
733 | if (!ch) | ||
734 | return -ENODEV; | ||
735 | |||
736 | if (notify == 0) | ||
737 | notify = do_nothing_notify; | ||
738 | |||
739 | ch->notify = notify; | ||
740 | ch->current_packet = 0; | ||
741 | ch->last_state = SMD_SS_CLOSED; | ||
742 | ch->priv = priv; | ||
743 | |||
744 | *_ch = ch; | ||
745 | |||
746 | spin_lock_irqsave(&smd_lock, flags); | ||
747 | list_add(&ch->ch_list, &smd_ch_list); | ||
748 | |||
749 | /* If the remote side is CLOSING, we need to get it to | ||
750 | * move to OPENING (which we'll do by moving from CLOSED to | ||
751 | * OPENING) and then get it to move from OPENING to | ||
752 | * OPENED (by doing the same state change ourselves). | ||
753 | * | ||
754 | * Otherwise, it should be OPENING and we can move directly | ||
755 | * to OPENED so that it will follow. | ||
756 | */ | ||
757 | if (ch->recv->state == SMD_SS_CLOSING) { | ||
758 | ch->send->head = 0; | ||
759 | hc_set_state(ch->send, SMD_SS_OPENING); | ||
760 | } else { | ||
761 | hc_set_state(ch->send, SMD_SS_OPENED); | ||
762 | } | ||
763 | spin_unlock_irqrestore(&smd_lock, flags); | ||
764 | smd_kick(ch); | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | int smd_close(smd_channel_t *ch) | ||
770 | { | ||
771 | unsigned long flags; | ||
772 | |||
773 | pr_info("smd_close(%p)\n", ch); | ||
774 | |||
775 | if (ch == 0) | ||
776 | return -1; | ||
777 | |||
778 | spin_lock_irqsave(&smd_lock, flags); | ||
779 | ch->notify = do_nothing_notify; | ||
780 | list_del(&ch->ch_list); | ||
781 | hc_set_state(ch->send, SMD_SS_CLOSED); | ||
782 | spin_unlock_irqrestore(&smd_lock, flags); | ||
783 | |||
784 | mutex_lock(&smd_creation_mutex); | ||
785 | list_add(&ch->ch_list, &smd_ch_closed_list); | ||
786 | mutex_unlock(&smd_creation_mutex); | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | int smd_read(smd_channel_t *ch, void *data, int len) | ||
792 | { | ||
793 | return ch->read(ch, data, len); | ||
794 | } | ||
795 | |||
796 | int smd_write(smd_channel_t *ch, const void *data, int len) | ||
797 | { | ||
798 | return ch->write(ch, data, len); | ||
799 | } | ||
800 | |||
801 | int smd_read_avail(smd_channel_t *ch) | ||
802 | { | ||
803 | return ch->read_avail(ch); | ||
804 | } | ||
805 | |||
806 | int smd_write_avail(smd_channel_t *ch) | ||
807 | { | ||
808 | return ch->write_avail(ch); | ||
809 | } | ||
810 | |||
811 | int smd_wait_until_readable(smd_channel_t *ch, int bytes) | ||
812 | { | ||
813 | return -1; | ||
814 | } | ||
815 | |||
816 | int smd_wait_until_writable(smd_channel_t *ch, int bytes) | ||
817 | { | ||
818 | return -1; | ||
819 | } | ||
820 | |||
821 | int smd_cur_packet_size(smd_channel_t *ch) | ||
822 | { | ||
823 | return ch->current_packet; | ||
824 | } | ||
825 | |||
826 | |||
827 | /* ------------------------------------------------------------------------- */ | ||
828 | |||
829 | void *smem_alloc(unsigned id, unsigned size) | ||
830 | { | ||
831 | return smem_find(id, size); | ||
832 | } | ||
833 | |||
834 | static void *_smem_find(unsigned id, unsigned *size) | ||
835 | { | ||
836 | struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; | ||
837 | struct smem_heap_entry *toc = shared->heap_toc; | ||
838 | |||
839 | if (id >= SMEM_NUM_ITEMS) | ||
840 | return 0; | ||
841 | |||
842 | if (toc[id].allocated) { | ||
843 | *size = toc[id].size; | ||
844 | return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset); | ||
845 | } | ||
846 | |||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | void *smem_find(unsigned id, unsigned size_in) | ||
851 | { | ||
852 | unsigned size; | ||
853 | void *ptr; | ||
854 | |||
855 | ptr = _smem_find(id, &size); | ||
856 | if (!ptr) | ||
857 | return 0; | ||
858 | |||
859 | size_in = ALIGN(size_in, 8); | ||
860 | if (size_in != size) { | ||
861 | pr_err("smem_find(%d, %d): wrong size %d\n", | ||
862 | id, size_in, size); | ||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | return ptr; | ||
867 | } | ||
868 | |||
869 | static irqreturn_t smsm_irq_handler(int irq, void *data) | ||
870 | { | ||
871 | unsigned long flags; | ||
872 | struct smsm_shared *smsm; | ||
873 | |||
874 | spin_lock_irqsave(&smem_lock, flags); | ||
875 | smsm = smem_alloc(ID_SHARED_STATE, | ||
876 | 2 * sizeof(struct smsm_shared)); | ||
877 | |||
878 | if (smsm == 0) { | ||
879 | pr_info("<SM NO STATE>\n"); | ||
880 | } else { | ||
881 | unsigned apps = smsm[0].state; | ||
882 | unsigned modm = smsm[1].state; | ||
883 | |||
884 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
885 | pr_info("<SM %08x %08x>\n", apps, modm); | ||
886 | if (modm & SMSM_RESET) { | ||
887 | handle_modem_crash(); | ||
888 | } else { | ||
889 | apps |= SMSM_INIT; | ||
890 | if (modm & SMSM_SMDINIT) | ||
891 | apps |= SMSM_SMDINIT; | ||
892 | if (modm & SMSM_RPCINIT) | ||
893 | apps |= SMSM_RPCINIT; | ||
894 | } | ||
895 | |||
896 | if (smsm[0].state != apps) { | ||
897 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
898 | pr_info("<SM %08x NOTIFY>\n", apps); | ||
899 | smsm[0].state = apps; | ||
900 | do_smd_probe(); | ||
901 | notify_other_smsm(); | ||
902 | } | ||
903 | } | ||
904 | spin_unlock_irqrestore(&smem_lock, flags); | ||
905 | return IRQ_HANDLED; | ||
906 | } | ||
907 | |||
908 | int smsm_change_state(uint32_t clear_mask, uint32_t set_mask) | ||
909 | { | ||
910 | unsigned long flags; | ||
911 | struct smsm_shared *smsm; | ||
912 | |||
913 | spin_lock_irqsave(&smem_lock, flags); | ||
914 | |||
915 | smsm = smem_alloc(ID_SHARED_STATE, | ||
916 | 2 * sizeof(struct smsm_shared)); | ||
917 | |||
918 | if (smsm) { | ||
919 | if (smsm[1].state & SMSM_RESET) | ||
920 | handle_modem_crash(); | ||
921 | smsm[0].state = (smsm[0].state & ~clear_mask) | set_mask; | ||
922 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
923 | pr_info("smsm_change_state %x\n", | ||
924 | smsm[0].state); | ||
925 | notify_other_smsm(); | ||
926 | } | ||
927 | |||
928 | spin_unlock_irqrestore(&smem_lock, flags); | ||
929 | |||
930 | if (smsm == NULL) { | ||
931 | pr_err("smsm_change_state <SM NO STATE>\n"); | ||
932 | return -EIO; | ||
933 | } | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | uint32_t smsm_get_state(void) | ||
938 | { | ||
939 | unsigned long flags; | ||
940 | struct smsm_shared *smsm; | ||
941 | uint32_t rv; | ||
942 | |||
943 | spin_lock_irqsave(&smem_lock, flags); | ||
944 | |||
945 | smsm = smem_alloc(ID_SHARED_STATE, | ||
946 | 2 * sizeof(struct smsm_shared)); | ||
947 | |||
948 | if (smsm) | ||
949 | rv = smsm[1].state; | ||
950 | else | ||
951 | rv = 0; | ||
952 | |||
953 | if (rv & SMSM_RESET) | ||
954 | handle_modem_crash(); | ||
955 | |||
956 | spin_unlock_irqrestore(&smem_lock, flags); | ||
957 | |||
958 | if (smsm == NULL) | ||
959 | pr_err("smsm_get_state <SM NO STATE>\n"); | ||
960 | return rv; | ||
961 | } | ||
962 | |||
963 | int smsm_set_sleep_duration(uint32_t delay) | ||
964 | { | ||
965 | uint32_t *ptr; | ||
966 | |||
967 | ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); | ||
968 | if (ptr == NULL) { | ||
969 | pr_err("smsm_set_sleep_duration <SM NO SLEEP_DELAY>\n"); | ||
970 | return -EIO; | ||
971 | } | ||
972 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
973 | pr_info("smsm_set_sleep_duration %d -> %d\n", | ||
974 | *ptr, delay); | ||
975 | *ptr = delay; | ||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | int smsm_set_interrupt_info(struct smsm_interrupt_info *info) | ||
980 | { | ||
981 | struct smsm_interrupt_info *ptr; | ||
982 | |||
983 | ptr = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*ptr)); | ||
984 | if (ptr == NULL) { | ||
985 | pr_err("smsm_set_sleep_duration <SM NO INT_INFO>\n"); | ||
986 | return -EIO; | ||
987 | } | ||
988 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
989 | pr_info("smsm_set_interrupt_info %x %x -> %x %x\n", | ||
990 | ptr->aArm_en_mask, ptr->aArm_interrupts_pending, | ||
991 | info->aArm_en_mask, info->aArm_interrupts_pending); | ||
992 | *ptr = *info; | ||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | #define MAX_NUM_SLEEP_CLIENTS 64 | ||
997 | #define MAX_SLEEP_NAME_LEN 8 | ||
998 | |||
999 | #define NUM_GPIO_INT_REGISTERS 6 | ||
1000 | #define GPIO_SMEM_NUM_GROUPS 2 | ||
1001 | #define GPIO_SMEM_MAX_PC_INTERRUPTS 8 | ||
1002 | |||
1003 | struct tramp_gpio_save { | ||
1004 | unsigned int enable; | ||
1005 | unsigned int detect; | ||
1006 | unsigned int polarity; | ||
1007 | }; | ||
1008 | |||
1009 | struct tramp_gpio_smem { | ||
1010 | uint16_t num_fired[GPIO_SMEM_NUM_GROUPS]; | ||
1011 | uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS]; | ||
1012 | uint32_t enabled[NUM_GPIO_INT_REGISTERS]; | ||
1013 | uint32_t detection[NUM_GPIO_INT_REGISTERS]; | ||
1014 | uint32_t polarity[NUM_GPIO_INT_REGISTERS]; | ||
1015 | }; | ||
1016 | |||
1017 | |||
1018 | void smsm_print_sleep_info(void) | ||
1019 | { | ||
1020 | unsigned long flags; | ||
1021 | uint32_t *ptr; | ||
1022 | struct tramp_gpio_smem *gpio; | ||
1023 | struct smsm_interrupt_info *int_info; | ||
1024 | |||
1025 | |||
1026 | spin_lock_irqsave(&smem_lock, flags); | ||
1027 | |||
1028 | ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); | ||
1029 | if (ptr) | ||
1030 | pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", *ptr); | ||
1031 | |||
1032 | ptr = smem_alloc(SMEM_SMSM_LIMIT_SLEEP, sizeof(*ptr)); | ||
1033 | if (ptr) | ||
1034 | pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", *ptr); | ||
1035 | |||
1036 | ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr)); | ||
1037 | if (ptr) | ||
1038 | pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr); | ||
1039 | |||
1040 | int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); | ||
1041 | if (int_info) | ||
1042 | pr_info("SMEM_SMSM_INT_INFO %x %x %x\n", | ||
1043 | int_info->aArm_en_mask, | ||
1044 | int_info->aArm_interrupts_pending, | ||
1045 | int_info->aArm_wakeup_reason); | ||
1046 | |||
1047 | gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio)); | ||
1048 | if (gpio) { | ||
1049 | int i; | ||
1050 | for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++) | ||
1051 | pr_info("SMEM_GPIO_INT: %d: e %x d %x p %x\n", | ||
1052 | i, gpio->enabled[i], gpio->detection[i], | ||
1053 | gpio->polarity[i]); | ||
1054 | |||
1055 | for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) | ||
1056 | pr_info("SMEM_GPIO_INT: %d: f %d: %d %d...\n", | ||
1057 | i, gpio->num_fired[i], gpio->fired[i][0], | ||
1058 | gpio->fired[i][1]); | ||
1059 | } | ||
1060 | |||
1061 | spin_unlock_irqrestore(&smem_lock, flags); | ||
1062 | } | ||
1063 | |||
1064 | int smd_core_init(void) | ||
1065 | { | ||
1066 | int r; | ||
1067 | pr_info("smd_core_init()\n"); | ||
1068 | |||
1069 | r = request_irq(INT_A9_M2A_0, smd_irq_handler, | ||
1070 | IRQF_TRIGGER_RISING, "smd_dev", 0); | ||
1071 | if (r < 0) | ||
1072 | return r; | ||
1073 | r = enable_irq_wake(INT_A9_M2A_0); | ||
1074 | if (r < 0) | ||
1075 | pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_0\n"); | ||
1076 | |||
1077 | r = request_irq(INT_A9_M2A_5, smsm_irq_handler, | ||
1078 | IRQF_TRIGGER_RISING, "smsm_dev", 0); | ||
1079 | if (r < 0) { | ||
1080 | free_irq(INT_A9_M2A_0, 0); | ||
1081 | return r; | ||
1082 | } | ||
1083 | r = enable_irq_wake(INT_A9_M2A_5); | ||
1084 | if (r < 0) | ||
1085 | pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); | ||
1086 | |||
1087 | /* we may have missed a signal while booting -- fake | ||
1088 | * an interrupt to make sure we process any existing | ||
1089 | * state | ||
1090 | */ | ||
1091 | smsm_irq_handler(0, 0); | ||
1092 | |||
1093 | pr_info("smd_core_init() done\n"); | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | #if defined(CONFIG_DEBUG_FS) | ||
1099 | |||
1100 | static int dump_ch(char *buf, int max, int n, | ||
1101 | struct smd_half_channel *s, | ||
1102 | struct smd_half_channel *r) | ||
1103 | { | ||
1104 | return scnprintf( | ||
1105 | buf, max, | ||
1106 | "ch%02d:" | ||
1107 | " %8s(%04d/%04d) %c%c%c%c%c%c%c <->" | ||
1108 | " %8s(%04d/%04d) %c%c%c%c%c%c%c\n", n, | ||
1109 | chstate(s->state), s->tail, s->head, | ||
1110 | s->fDSR ? 'D' : 'd', | ||
1111 | s->fCTS ? 'C' : 'c', | ||
1112 | s->fCD ? 'C' : 'c', | ||
1113 | s->fRI ? 'I' : 'i', | ||
1114 | s->fHEAD ? 'W' : 'w', | ||
1115 | s->fTAIL ? 'R' : 'r', | ||
1116 | s->fSTATE ? 'S' : 's', | ||
1117 | chstate(r->state), r->tail, r->head, | ||
1118 | r->fDSR ? 'D' : 'd', | ||
1119 | r->fCTS ? 'R' : 'r', | ||
1120 | r->fCD ? 'C' : 'c', | ||
1121 | r->fRI ? 'I' : 'i', | ||
1122 | r->fHEAD ? 'W' : 'w', | ||
1123 | r->fTAIL ? 'R' : 'r', | ||
1124 | r->fSTATE ? 'S' : 's' | ||
1125 | ); | ||
1126 | } | ||
1127 | |||
1128 | static int debug_read_stat(char *buf, int max) | ||
1129 | { | ||
1130 | struct smsm_shared *smsm; | ||
1131 | char *msg; | ||
1132 | int i = 0; | ||
1133 | |||
1134 | smsm = smem_find(ID_SHARED_STATE, | ||
1135 | 2 * sizeof(struct smsm_shared)); | ||
1136 | |||
1137 | msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); | ||
1138 | |||
1139 | if (smsm) { | ||
1140 | if (smsm[1].state & SMSM_RESET) | ||
1141 | i += scnprintf(buf + i, max - i, | ||
1142 | "smsm: ARM9 HAS CRASHED\n"); | ||
1143 | i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n", | ||
1144 | smsm[0].state, smsm[1].state); | ||
1145 | } else { | ||
1146 | i += scnprintf(buf + i, max - i, "smsm: cannot find\n"); | ||
1147 | } | ||
1148 | if (msg) { | ||
1149 | msg[SZ_DIAG_ERR_MSG - 1] = 0; | ||
1150 | i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg); | ||
1151 | } | ||
1152 | return i; | ||
1153 | } | ||
1154 | |||
1155 | static int debug_read_mem(char *buf, int max) | ||
1156 | { | ||
1157 | unsigned n; | ||
1158 | struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; | ||
1159 | struct smem_heap_entry *toc = shared->heap_toc; | ||
1160 | int i = 0; | ||
1161 | |||
1162 | i += scnprintf(buf + i, max - i, | ||
1163 | "heap: init=%d free=%d remain=%d\n", | ||
1164 | shared->heap_info.initialized, | ||
1165 | shared->heap_info.free_offset, | ||
1166 | shared->heap_info.heap_remaining); | ||
1167 | |||
1168 | for (n = 0; n < SMEM_NUM_ITEMS; n++) { | ||
1169 | if (toc[n].allocated == 0) | ||
1170 | continue; | ||
1171 | i += scnprintf(buf + i, max - i, | ||
1172 | "%04d: offsed %08x size %08x\n", | ||
1173 | n, toc[n].offset, toc[n].size); | ||
1174 | } | ||
1175 | return i; | ||
1176 | } | ||
1177 | |||
1178 | static int debug_read_ch(char *buf, int max) | ||
1179 | { | ||
1180 | struct smd_shared *shared; | ||
1181 | int n, i = 0; | ||
1182 | |||
1183 | for (n = 0; n < SMD_CHANNELS; n++) { | ||
1184 | shared = smem_find(ID_SMD_CHANNELS + n, | ||
1185 | sizeof(struct smd_shared)); | ||
1186 | if (shared == 0) | ||
1187 | continue; | ||
1188 | i += dump_ch(buf + i, max - i, n, &shared->ch0, &shared->ch1); | ||
1189 | } | ||
1190 | |||
1191 | return i; | ||
1192 | } | ||
1193 | |||
1194 | static int debug_read_version(char *buf, int max) | ||
1195 | { | ||
1196 | struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; | ||
1197 | unsigned version = shared->version[VERSION_MODEM]; | ||
1198 | return sprintf(buf, "%d.%d\n", version >> 16, version & 0xffff); | ||
1199 | } | ||
1200 | |||
1201 | static int debug_read_build_id(char *buf, int max) | ||
1202 | { | ||
1203 | unsigned size; | ||
1204 | void *data; | ||
1205 | |||
1206 | data = _smem_find(SMEM_HW_SW_BUILD_ID, &size); | ||
1207 | if (!data) | ||
1208 | return 0; | ||
1209 | |||
1210 | if (size >= max) | ||
1211 | size = max; | ||
1212 | memcpy(buf, data, size); | ||
1213 | |||
1214 | return size; | ||
1215 | } | ||
1216 | |||
1217 | static int debug_read_alloc_tbl(char *buf, int max) | ||
1218 | { | ||
1219 | struct smd_alloc_elm *shared; | ||
1220 | int n, i = 0; | ||
1221 | |||
1222 | shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); | ||
1223 | |||
1224 | for (n = 0; n < 64; n++) { | ||
1225 | if (shared[n].ref_count == 0) | ||
1226 | continue; | ||
1227 | i += scnprintf(buf + i, max - i, | ||
1228 | "%03d: %20s cid=%02d ctype=%d ref_count=%d\n", | ||
1229 | n, shared[n].name, shared[n].cid, | ||
1230 | shared[n].ctype, shared[n].ref_count); | ||
1231 | } | ||
1232 | |||
1233 | return i; | ||
1234 | } | ||
1235 | |||
1236 | static int debug_boom(char *buf, int max) | ||
1237 | { | ||
1238 | unsigned ms = 5000; | ||
1239 | msm_proc_comm(PCOM_RESET_MODEM, &ms, 0); | ||
1240 | return 0; | ||
1241 | } | ||
1242 | |||
1243 | #define DEBUG_BUFMAX 4096 | ||
1244 | static char debug_buffer[DEBUG_BUFMAX]; | ||
1245 | |||
1246 | static ssize_t debug_read(struct file *file, char __user *buf, | ||
1247 | size_t count, loff_t *ppos) | ||
1248 | { | ||
1249 | int (*fill)(char *buf, int max) = file->private_data; | ||
1250 | int bsize = fill(debug_buffer, DEBUG_BUFMAX); | ||
1251 | return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize); | ||
1252 | } | ||
1253 | |||
1254 | static int debug_open(struct inode *inode, struct file *file) | ||
1255 | { | ||
1256 | file->private_data = inode->i_private; | ||
1257 | return 0; | ||
1258 | } | ||
1259 | |||
1260 | static const struct file_operations debug_ops = { | ||
1261 | .read = debug_read, | ||
1262 | .open = debug_open, | ||
1263 | }; | ||
1264 | |||
1265 | static void debug_create(const char *name, mode_t mode, | ||
1266 | struct dentry *dent, | ||
1267 | int (*fill)(char *buf, int max)) | ||
1268 | { | ||
1269 | debugfs_create_file(name, mode, dent, fill, &debug_ops); | ||
1270 | } | ||
1271 | |||
1272 | static void smd_debugfs_init(void) | ||
1273 | { | ||
1274 | struct dentry *dent; | ||
1275 | |||
1276 | dent = debugfs_create_dir("smd", 0); | ||
1277 | if (IS_ERR(dent)) | ||
1278 | return; | ||
1279 | |||
1280 | debug_create("ch", 0444, dent, debug_read_ch); | ||
1281 | debug_create("stat", 0444, dent, debug_read_stat); | ||
1282 | debug_create("mem", 0444, dent, debug_read_mem); | ||
1283 | debug_create("version", 0444, dent, debug_read_version); | ||
1284 | debug_create("tbl", 0444, dent, debug_read_alloc_tbl); | ||
1285 | debug_create("build", 0444, dent, debug_read_build_id); | ||
1286 | debug_create("boom", 0444, dent, debug_boom); | ||
1287 | } | ||
1288 | #else | ||
1289 | static void smd_debugfs_init(void) {} | ||
1290 | #endif | ||
1291 | |||
1292 | static int __init msm_smd_probe(struct platform_device *pdev) | ||
1293 | { | ||
1294 | pr_info("smd_init()\n"); | ||
1295 | |||
1296 | INIT_WORK(&probe_work, smd_channel_probe_worker); | ||
1297 | |||
1298 | if (smd_core_init()) { | ||
1299 | pr_err("smd_core_init() failed\n"); | ||
1300 | return -1; | ||
1301 | } | ||
1302 | |||
1303 | do_smd_probe(); | ||
1304 | |||
1305 | msm_check_for_modem_crash = check_for_modem_crash; | ||
1306 | |||
1307 | smd_debugfs_init(); | ||
1308 | smd_initialized = 1; | ||
1309 | |||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | static struct platform_driver msm_smd_driver = { | ||
1314 | .probe = msm_smd_probe, | ||
1315 | .driver = { | ||
1316 | .name = MODULE_NAME, | ||
1317 | .owner = THIS_MODULE, | ||
1318 | }, | ||
1319 | }; | ||
1320 | |||
1321 | static int __init msm_smd_init(void) | ||
1322 | { | ||
1323 | return platform_driver_register(&msm_smd_driver); | ||
1324 | } | ||
1325 | |||
1326 | module_init(msm_smd_init); | ||
1327 | |||
1328 | MODULE_DESCRIPTION("MSM Shared Memory Core"); | ||
1329 | MODULE_AUTHOR("Brian Swetland <swetland@google.com>"); | ||
1330 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h new file mode 100644 index 000000000000..c0eb3de1be54 --- /dev/null +++ b/arch/arm/mach-msm/smd_private.h | |||
@@ -0,0 +1,171 @@ | |||
1 | /* arch/arm/mach-msm/smd_private.h | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * Copyright (c) 2007 QUALCOMM Incorporated | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | #ifndef _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_ | ||
17 | #define _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_ | ||
18 | |||
19 | struct smem_heap_info | ||
20 | { | ||
21 | unsigned initialized; | ||
22 | unsigned free_offset; | ||
23 | unsigned heap_remaining; | ||
24 | unsigned reserved; | ||
25 | }; | ||
26 | |||
27 | struct smem_heap_entry | ||
28 | { | ||
29 | unsigned allocated; | ||
30 | unsigned offset; | ||
31 | unsigned size; | ||
32 | unsigned reserved; | ||
33 | }; | ||
34 | |||
35 | struct smem_proc_comm | ||
36 | { | ||
37 | unsigned command; | ||
38 | unsigned status; | ||
39 | unsigned data1; | ||
40 | unsigned data2; | ||
41 | }; | ||
42 | |||
43 | #define PC_APPS 0 | ||
44 | #define PC_MODEM 1 | ||
45 | |||
46 | #define VERSION_QDSP6 4 | ||
47 | #define VERSION_APPS_SBL 6 | ||
48 | #define VERSION_MODEM_SBL 7 | ||
49 | #define VERSION_APPS 8 | ||
50 | #define VERSION_MODEM 9 | ||
51 | |||
52 | struct smem_shared | ||
53 | { | ||
54 | struct smem_proc_comm proc_comm[4]; | ||
55 | unsigned version[32]; | ||
56 | struct smem_heap_info heap_info; | ||
57 | struct smem_heap_entry heap_toc[128]; | ||
58 | }; | ||
59 | |||
60 | struct smsm_shared | ||
61 | { | ||
62 | unsigned host; | ||
63 | unsigned state; | ||
64 | }; | ||
65 | |||
66 | struct smsm_interrupt_info | ||
67 | { | ||
68 | uint32_t aArm_en_mask; | ||
69 | uint32_t aArm_interrupts_pending; | ||
70 | uint32_t aArm_wakeup_reason; | ||
71 | }; | ||
72 | |||
73 | #define SZ_DIAG_ERR_MSG 0xC8 | ||
74 | #define ID_DIAG_ERR_MSG SMEM_DIAG_ERR_MESSAGE | ||
75 | #define ID_SMD_CHANNELS SMEM_SMD_BASE_ID | ||
76 | #define ID_SHARED_STATE SMEM_SMSM_SHARED_STATE | ||
77 | #define ID_CH_ALLOC_TBL SMEM_CHANNEL_ALLOC_TBL | ||
78 | |||
79 | #define SMSM_INIT 0x000001 | ||
80 | #define SMSM_SMDINIT 0x000008 | ||
81 | #define SMSM_RPCINIT 0x000020 | ||
82 | #define SMSM_RESET 0x000040 | ||
83 | #define SMSM_RSA 0x0080 | ||
84 | #define SMSM_RUN 0x000100 | ||
85 | #define SMSM_PWRC 0x0200 | ||
86 | #define SMSM_TIMEWAIT 0x0400 | ||
87 | #define SMSM_TIMEINIT 0x0800 | ||
88 | #define SMSM_PWRC_EARLY_EXIT 0x1000 | ||
89 | #define SMSM_WFPI 0x2000 | ||
90 | #define SMSM_SLEEP 0x4000 | ||
91 | #define SMSM_SLEEPEXIT 0x8000 | ||
92 | #define SMSM_OEMSBL_RELEASE 0x10000 | ||
93 | #define SMSM_PWRC_SUSPEND 0x200000 | ||
94 | |||
95 | #define SMSM_WKUP_REASON_RPC 0x00000001 | ||
96 | #define SMSM_WKUP_REASON_INT 0x00000002 | ||
97 | #define SMSM_WKUP_REASON_GPIO 0x00000004 | ||
98 | #define SMSM_WKUP_REASON_TIMER 0x00000008 | ||
99 | #define SMSM_WKUP_REASON_ALARM 0x00000010 | ||
100 | #define SMSM_WKUP_REASON_RESET 0x00000020 | ||
101 | |||
102 | void *smem_alloc(unsigned id, unsigned size); | ||
103 | int smsm_change_state(uint32_t clear_mask, uint32_t set_mask); | ||
104 | uint32_t smsm_get_state(void); | ||
105 | int smsm_set_sleep_duration(uint32_t delay); | ||
106 | int smsm_set_interrupt_info(struct smsm_interrupt_info *info); | ||
107 | void smsm_print_sleep_info(void); | ||
108 | |||
109 | #define SMEM_NUM_SMD_CHANNELS 64 | ||
110 | |||
111 | typedef enum | ||
112 | { | ||
113 | /* fixed items */ | ||
114 | SMEM_PROC_COMM = 0, | ||
115 | SMEM_HEAP_INFO, | ||
116 | SMEM_ALLOCATION_TABLE, | ||
117 | SMEM_VERSION_INFO, | ||
118 | SMEM_HW_RESET_DETECT, | ||
119 | SMEM_AARM_WARM_BOOT, | ||
120 | SMEM_DIAG_ERR_MESSAGE, | ||
121 | SMEM_SPINLOCK_ARRAY, | ||
122 | SMEM_MEMORY_BARRIER_LOCATION, | ||
123 | |||
124 | /* dynamic items */ | ||
125 | SMEM_AARM_PARTITION_TABLE, | ||
126 | SMEM_AARM_BAD_BLOCK_TABLE, | ||
127 | SMEM_RESERVE_BAD_BLOCKS, | ||
128 | SMEM_WM_UUID, | ||
129 | SMEM_CHANNEL_ALLOC_TBL, | ||
130 | SMEM_SMD_BASE_ID, | ||
131 | SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_CHANNELS, | ||
132 | SMEM_SMEM_LOG_EVENTS, | ||
133 | SMEM_SMEM_STATIC_LOG_IDX, | ||
134 | SMEM_SMEM_STATIC_LOG_EVENTS, | ||
135 | SMEM_SMEM_SLOW_CLOCK_SYNC, | ||
136 | SMEM_SMEM_SLOW_CLOCK_VALUE, | ||
137 | SMEM_BIO_LED_BUF, | ||
138 | SMEM_SMSM_SHARED_STATE, | ||
139 | SMEM_SMSM_INT_INFO, | ||
140 | SMEM_SMSM_SLEEP_DELAY, | ||
141 | SMEM_SMSM_LIMIT_SLEEP, | ||
142 | SMEM_SLEEP_POWER_COLLAPSE_DISABLED, | ||
143 | SMEM_KEYPAD_KEYS_PRESSED, | ||
144 | SMEM_KEYPAD_STATE_UPDATED, | ||
145 | SMEM_KEYPAD_STATE_IDX, | ||
146 | SMEM_GPIO_INT, | ||
147 | SMEM_MDDI_LCD_IDX, | ||
148 | SMEM_MDDI_HOST_DRIVER_STATE, | ||
149 | SMEM_MDDI_LCD_DISP_STATE, | ||
150 | SMEM_LCD_CUR_PANEL, | ||
151 | SMEM_MARM_BOOT_SEGMENT_INFO, | ||
152 | SMEM_AARM_BOOT_SEGMENT_INFO, | ||
153 | SMEM_SLEEP_STATIC, | ||
154 | SMEM_SCORPION_FREQUENCY, | ||
155 | SMEM_SMD_PROFILES, | ||
156 | SMEM_TSSC_BUSY, | ||
157 | SMEM_HS_SUSPEND_FILTER_INFO, | ||
158 | SMEM_BATT_INFO, | ||
159 | SMEM_APPS_BOOT_MODE, | ||
160 | SMEM_VERSION_FIRST, | ||
161 | SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24, | ||
162 | SMEM_OSS_RRCASN1_BUF1, | ||
163 | SMEM_OSS_RRCASN1_BUF2, | ||
164 | SMEM_ID_VENDOR0, | ||
165 | SMEM_ID_VENDOR1, | ||
166 | SMEM_ID_VENDOR2, | ||
167 | SMEM_HW_SW_BUILD_ID, | ||
168 | SMEM_NUM_ITEMS, | ||
169 | } smem_mem_type; | ||
170 | |||
171 | #endif | ||