aboutsummaryrefslogtreecommitdiff
path: root/include/linux/mhi.h
blob: fdae363d0142cc3022c2205fe8a722d80c7f5c3d (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
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 *
 */
#ifndef _MHI_H_
#define _MHI_H_

#include <linux/device.h>
#include <linux/dma-direction.h>
#include <linux/mutex.h>
#include <linux/rwlock_types.h>
#include <linux/slab.h>
#include <linux/spinlock_types.h>
#include <linux/wait.h>
#include <linux/workqueue.h>

struct mhi_chan;
struct mhi_event;
struct mhi_ctxt;
struct mhi_cmd;
struct mhi_buf_info;

/**
 * enum mhi_callback - MHI callback
 * @MHI_CB_IDLE: MHI entered idle state
 * @MHI_CB_PENDING_DATA: New data available for client to process
 * @MHI_CB_LPM_ENTER: MHI host entered low power mode
 * @MHI_CB_LPM_EXIT: MHI host about to exit low power mode
 * @MHI_CB_EE_RDDM: MHI device entered RDDM exec env
 * @MHI_CB_EE_MISSION_MODE: MHI device entered Mission Mode exec env
 * @MHI_CB_SYS_ERROR: MHI device entered error state (may recover)
 * @MHI_CB_FATAL_ERROR: MHI device entered fatal error state
 */
enum mhi_callback {
	MHI_CB_IDLE,
	MHI_CB_PENDING_DATA,
	MHI_CB_LPM_ENTER,
	MHI_CB_LPM_EXIT,
	MHI_CB_EE_RDDM,
	MHI_CB_EE_MISSION_MODE,
	MHI_CB_SYS_ERROR,
	MHI_CB_FATAL_ERROR,
};

/**
 * enum mhi_flags - Transfer flags
 * @MHI_EOB: End of buffer for bulk transfer
 * @MHI_EOT: End of transfer
 * @MHI_CHAIN: Linked transfer
 */
enum mhi_flags {
	MHI_EOB,
	MHI_EOT,
	MHI_CHAIN,
};

/**
 * enum mhi_device_type - Device types
 * @MHI_DEVICE_XFER: Handles data transfer
 * @MHI_DEVICE_TIMESYNC: Use for timesync feature
 * @MHI_DEVICE_CONTROLLER: Control device
 */
enum mhi_device_type {
	MHI_DEVICE_XFER,
	MHI_DEVICE_TIMESYNC,
	MHI_DEVICE_CONTROLLER,
};

/**
 * enum mhi_ch_type - Channel types
 * @MHI_CH_TYPE_INVALID: Invalid channel type
 * @MHI_CH_TYPE_OUTBOUND: Outbound channel to the device
 * @MHI_CH_TYPE_INBOUND: Inbound channel from the device
 * @MHI_CH_TYPE_INBOUND_COALESCED: Coalesced channel for the device to combine
 *				   multiple packets and send them as a single
 *				   large packet to reduce CPU consumption
 */
enum mhi_ch_type {
	MHI_CH_TYPE_INVALID = 0,
	MHI_CH_TYPE_OUTBOUND = DMA_TO_DEVICE,
	MHI_CH_TYPE_INBOUND = DMA_FROM_DEVICE,
	MHI_CH_TYPE_INBOUND_COALESCED = 3,
};

/**
 * struct mhi_link_info - BW requirement
 * target_link_speed - Link speed as defined by TLS bits in LinkControl reg
 * target_link_width - Link width as defined by NLW bits in LinkStatus reg
 */
struct mhi_link_info {
	unsigned int target_link_speed;
	unsigned int target_link_width;
};

/**
 * enum mhi_ee_type - Execution environment types
 * @MHI_EE_PBL: Primary Bootloader
 * @MHI_EE_SBL: Secondary Bootloader
 * @MHI_EE_AMSS: Modem, aka the primary runtime EE
 * @MHI_EE_RDDM: Ram dump download mode
 * @MHI_EE_WFW: WLAN firmware mode
 * @MHI_EE_PTHRU: Passthrough
 * @MHI_EE_EDL: Embedded downloader
 */
enum mhi_ee_type {
	MHI_EE_PBL,
	MHI_EE_SBL,
	MHI_EE_AMSS,
	MHI_EE_RDDM,
	MHI_EE_WFW,
	MHI_EE_PTHRU,
	MHI_EE_EDL,
	MHI_EE_MAX_SUPPORTED = MHI_EE_EDL,
	MHI_EE_DISABLE_TRANSITION, /* local EE, not related to mhi spec */
	MHI_EE_NOT_SUPPORTED,
	MHI_EE_MAX,
};

/**
 * enum mhi_state - MHI states
 * @MHI_STATE_RESET: Reset state
 * @MHI_STATE_READY: Ready state
 * @MHI_STATE_M0: M0 state
 * @MHI_STATE_M1: M1 state
 * @MHI_STATE_M2: M2 state
 * @MHI_STATE_M3: M3 state
 * @MHI_STATE_M3_FAST: M3 Fast state
 * @MHI_STATE_BHI: BHI state
 * @MHI_STATE_SYS_ERR: System Error state
 */
enum mhi_state {
	MHI_STATE_RESET = 0x0,
	MHI_STATE_READY = 0x1,
	MHI_STATE_M0 = 0x2,
	MHI_STATE_M1 = 0x3,
	MHI_STATE_M2 = 0x4,
	MHI_STATE_M3 = 0x5,
	MHI_STATE_M3_FAST = 0x6,
	MHI_STATE_BHI = 0x7,
	MHI_STATE_SYS_ERR = 0xFF,
	MHI_STATE_MAX,
};

/**
 * enum mhi_buf_type - Accepted buffer type for the channel
 * @MHI_BUF_RAW: Raw buffer
 * @MHI_BUF_SKB: SKB struct
 * @MHI_BUF_SCLIST: Scatter-gather list
 * @MHI_BUF_NOP: CPU offload channel, host does not accept transfer
 * @MHI_BUF_DMA: Receive DMA address mapped by client
 * @MHI_BUF_RSC_DMA: RSC type premapped buffer
 */
enum mhi_buf_type {
	MHI_BUF_RAW,
	MHI_BUF_SKB,
	MHI_BUF_SCLIST,
	MHI_BUF_NOP,
	MHI_BUF_DMA,
	MHI_BUF_RSC_DMA,
};

/**
 * enum mhi_er_data_type - Event ring data types
 * @MHI_ER_DATA: Only client data over this ring
 * @MHI_ER_CTRL: MHI control data and client data
 * @MHI_ER_TSYNC: Time sync events
 */
enum mhi_er_data_type {
	MHI_ER_DATA,
	MHI_ER_CTRL,
	MHI_ER_TSYNC,
};

/**
 * enum mhi_db_brst_mode - Doorbell mode
 * @MHI_DB_BRST_DISABLE: Burst mode disable
 * @MHI_DB_BRST_ENABLE: Burst mode enable
 */
enum mhi_db_brst_mode {
	MHI_DB_BRST_DISABLE = 0x2,
	MHI_DB_BRST_ENABLE = 0x3,
};

/**
 * struct mhi_channel_config - Channel configuration structure for controller
 * @num: The number assigned to this channel
 * @name: The name of this channel
 * @num_elements: The number of elements that can be queued to this channel
 * @local_elements: The local ring length of the channel
 * @event_ring: The event rung index that services this channel
 * @dir: Direction that data may flow on this channel
 * @type: Channel type
 * @ee_mask: Execution Environment mask for this channel
 * @pollcfg: Polling configuration for burst mode.  0 is default.  milliseconds
	     for UL channels, multiple of 8 ring elements for DL channels
 * @data_type: Data type accepted by this channel
 * @doorbell: Doorbell mode
 * @lpm_notify: The channel master requires low power mode notifications
 * @offload_channel: The client manages the channel completely
 * @doorbell_mode_switch: Channel switches to doorbell mode on M0 transition
 * @auto_queue: Framework will automatically queue buffers for DL traffic
 * @auto_start: Automatically start (open) this channel
 * @wake-capable: Channel capable of waking up the system
 */
struct mhi_channel_config {
	u32 num;
	char *name;
	u32 num_elements;
	u32 local_elements;
	u32 event_ring;
	enum dma_data_direction dir;
	enum mhi_ch_type type;
	u32 ee_mask;
	u32 pollcfg;
	enum mhi_buf_type data_type;
	enum mhi_db_brst_mode doorbell;
	bool lpm_notify;
	bool offload_channel;
	bool doorbell_mode_switch;
	bool auto_queue;
	bool auto_start;
	bool wake_capable;
};

/**
 * struct mhi_event_config - Event ring configuration structure for controller
 * @num_elements: The number of elements that can be queued to this ring
 * @irq_moderation_ms: Delay irq for additional events to be aggregated
 * @irq: IRQ associated with this ring
 * @channel: Dedicated channel number. U32_MAX indicates a non-dedicated ring
 * @mode: Doorbell mode
 * @data_type: Type of data this ring will process
 * @hardware_event: This ring is associated with hardware channels
 * @client_managed: This ring is client managed
 * @offload_channel: This ring is associated with an offloaded channel
 * @priority: Priority of this ring. Use 1 for now
 */
struct mhi_event_config {
	u32 num_elements;
	u32 irq_moderation_ms;
	u32 irq;
	u32 channel;
	enum mhi_db_brst_mode mode;
	enum mhi_er_data_type data_type;
	bool hardware_event;
	bool client_managed;
	bool offload_channel;
	u32 priority;
};

/**
 * struct mhi_controller_config - Root MHI controller configuration
 * @max_channels: Maximum number of channels supported
 * @timeout_ms: Timeout value for operations. 0 means use default
 * @use_bounce_buf: Use a bounce buffer pool due to limited DDR access
 * @m2_no_db: Host is not allowed to ring DB in M2 state
 * @buf_len: Size of automatically allocated buffers. 0 means use default
 * @num_channels: Number of channels defined in @ch_cfg
 * @ch_cfg: Array of defined channels
 * @num_events: Number of event rings defined in @event_cfg
 * @event_cfg: Array of defined event rings
 */
struct mhi_controller_config {
	u32 max_channels;
	u32 timeout_ms;
	bool use_bounce_buf;
	bool m2_no_db;
	u32 buf_len;
	u32 num_channels;
	struct mhi_channel_config *ch_cfg;
	u32 num_events;
	struct mhi_event_config *event_cfg;
};

/**
 * struct mhi_controller - Master MHI controller structure
 * @name: Name of the controller
 * @dev: Driver model device node for the controller
 * @mhi_dev: MHI device instance for the controller
 * @dev_id: Device ID of the controller
 * @bus_id: Physical bus instance used by the controller
 * @regs: Base address of MHI MMIO register space
 * @bhi: Points to base of MHI BHI register space
 * @wake_db: MHI WAKE doorbell register address
 * @iova_start: IOMMU starting address for data
 * @iova_stop: IOMMU stop address for data
 * @fw_image: Firmware image name for normal booting
 * @edl_image: Firmware image name for emergency download mode
 * @fbc_download: MHI host needs to do complete image transfer
 * @rddm_size: RAM dump size that host should allocate for debugging purpose
 * @sbl_size: SBL image size
 * @seg_len: BHIe vector size
 * @max_chan: Maximum number of channels the controller supports
 * @mhi_chan: Points to the channel configuration table
 * @lpm_chans: List of channels that require LPM notifications
 * @total_ev_rings: Total # of event rings allocated
 * @hw_ev_rings: Number of hardware event rings
 * @sw_ev_rings: Number of software event rings
 * @nr_irqs_req: Number of IRQs required to operate
 * @nr_irqs: Number of IRQ allocated by bus master
 * @irq: base irq # to request
 * @mhi_event: MHI event ring configurations table
 * @mhi_cmd: MHI command ring configurations table
 * @mhi_ctxt: MHI device context, shared memory between host and device
 * @timeout_ms: Timeout in ms for state transitions
 * @pm_mutex: Mutex for suspend/resume operation
 * @pre_init: MHI host needs to do pre-initialization before power up
 * @pm_lock: Lock for protecting MHI power management state
 * @pm_state: MHI power management state
 * @db_access: DB access states
 * @ee: MHI device execution environment
 * @dev_state: MHI device state
 * @wake_set: Device wakeup set flag
 * @dev_wake: Device wakeup count
 * @alloc_size: Total memory allocations size of the controller
 * @pending_pkts: Pending packets for the controller
 * @transition_list: List of MHI state transitions
 * @wlock: Lock for protecting device wakeup
 * @mhi_link_info: Device bandwidth info
 * @M0: M0 state counter for debugging
 * @M2: M2 state counter for debugging
 * @M3: M3 state counter for debugging
 * @M3_FAST: M3 Fast state counter for debugging
 * @st_worker: State transition worker
 * @fw_worker: Firmware download worker
 * @syserr_worker: System error worker
 * @state_event: State change event
 * @status_cb: CB function to notify various power states to bus master
 * @link_status: CB function to query link status of the device
 * @wake_get: CB function to assert device wake
 * @wake_put: CB function to de-assert device wake
 * @wake_toggle: CB function to assert and deasset (toggle) device wake
 * @runtime_get: CB function to controller runtime resume
 * @runtimet_put: CB function to decrement pm usage
 * @lpm_disable: CB function to request disable link level low power modes
 * @lpm_enable: CB function to request enable link level low power modes again
 * @map_single: CB function to create TRE buffer
 * @unmap_single: CB function to destroy TRE buffer
 * @bounce_buf: Use of bounce buffer
 * @buffer_len: Bounce buffer length
 * @priv_data: Points to bus master's private data
 */
struct mhi_controller {
	const char *name;
	struct device *dev;
	struct mhi_device *mhi_dev;
	u32 dev_id;
	u32 bus_id;
	void __iomem *regs;
	void __iomem *bhi;
	void __iomem *wake_db;

	dma_addr_t iova_start;
	dma_addr_t iova_stop;
	const char *fw_image;
	const char *edl_image;
	bool fbc_download;
	size_t rddm_size;
	size_t sbl_size;
	size_t seg_len;
	u32 max_chan;
	struct mhi_chan *mhi_chan;
	struct list_head lpm_chans;
	u32 total_ev_rings;
	u32 hw_ev_rings;
	u32 sw_ev_rings;
	u32 nr_irqs_req;
	u32 nr_irqs;
	int *irq;

	struct mhi_event *mhi_event;
	struct mhi_cmd *mhi_cmd;
	struct mhi_ctxt *mhi_ctxt;

	u32 timeout_ms;
	struct mutex pm_mutex;
	bool pre_init;
	rwlock_t pm_lock;
	u32 pm_state;
	u32 db_access;
	enum mhi_ee_type ee;
	enum mhi_state dev_state;
	bool wake_set;
	atomic_t dev_wake;
	atomic_t alloc_size;
	atomic_t pending_pkts;
	struct list_head transition_list;
	spinlock_t transition_lock;
	spinlock_t wlock;
	struct mhi_link_info mhi_link_info;

	u32 M0, M2, M3, M3_FAST;
	struct work_struct st_worker;
	struct work_struct fw_worker;
	struct work_struct syserr_worker;
	wait_queue_head_t state_event;

	void (*status_cb)(struct mhi_controller *mhi_cntrl, void *priv,
			  enum mhi_callback cb);
	int (*link_status)(struct mhi_controller *mhi_cntrl, void *priv);
	void (*wake_get)(struct mhi_controller *mhi_cntrl, bool override);
	void (*wake_put)(struct mhi_controller *mhi_cntrl, bool override);
	void (*wake_toggle)(struct mhi_controller *mhi_cntrl);
	int (*runtime_get)(struct mhi_controller *mhi_cntrl, void *priv);
	void (*runtime_put)(struct mhi_controller *mhi_cntrl, void *priv);
	void (*lpm_disable)(struct mhi_controller *mhi_cntrl, void *priv);
	void (*lpm_enable)(struct mhi_controller *mhi_cntrl, void *priv);
	int (*map_single)(struct mhi_controller *mhi_cntrl,
			  struct mhi_buf_info *buf);
	void (*unmap_single)(struct mhi_controller *mhi_cntrl,
			     struct mhi_buf_info *buf);

	bool bounce_buf;
	size_t buffer_len;
	void *priv_data;
};

/**
 * struct mhi_device - Structure representing a MHI device which binds
 *                     to channels
 * @dev: Driver model device node for the MHI device
 * @ul_chan_id: MHI channel id for UL transfer
 * @dl_chan_id: MHI channel id for DL transfer
 * @tiocm: Device current terminal settings
 * @id: Pointer to MHI device ID struct
 * @chan_name: Name of the channel to which the device binds
 * @mhi_cntrl: Controller the device belongs to
 * @ul_chan: UL channel for the device
 * @dl_chan: DL channel for the device
 * @dev_wake: Device wakeup counter
 * @dev_type: MHI device type
 */
struct mhi_device {
	struct device dev;
	int ul_chan_id;
	int dl_chan_id;
	u32 tiocm;
	const struct mhi_device_id *id;
	const char *chan_name;
	struct mhi_controller *mhi_cntrl;
	struct mhi_chan *ul_chan;
	struct mhi_chan *dl_chan;
	atomic_t dev_wake;
	enum mhi_device_type dev_type;
};

/**
 * struct mhi_result - Completed buffer information
 * @buf_addr: Address of data buffer
 * @dir: Channel direction
 * @bytes_xfer: # of bytes transferred
 * @transaction_status: Status of last transaction
 */
struct mhi_result {
	void *buf_addr;
	enum dma_data_direction dir;
	size_t bytes_xferd;
	int transaction_status;
};

/**
 * struct mhi_buf - MHI Buffer description
 * @buf: Virtual address of the buffer
 * @dma_addr: IOMMU address of the buffer
 * @len: # of bytes
 * @name: Buffer label. For offload channel, configurations name must be:
 *        ECA - Event context array data
 *        CCA - Channel context array data
 */
struct mhi_buf {
	void *buf;
	dma_addr_t dma_addr;
	size_t len;
	const char *name;
};

/**
 * struct mhi_driver - Structure representing a MHI client driver
 * @probe: CB function for client driver probe function
 * @remove: CB function for client driver remove function
 * @ul_xfer_cb: CB function for UL data transfer
 * @dl_xfer_cb: CB function for DL data transfer
 * @status_cb: CB functions for asynchronous status
 * @driver: Device driver model driver
 */
struct mhi_driver {
	const struct mhi_device_id *id_table;
	int (*probe)(struct mhi_device *mhi_dev,
		     const struct mhi_device_id *id);
	void (*remove)(struct mhi_device *mhi_dev);
	void (*ul_xfer_cb)(struct mhi_device *mhi_dev,
			   struct mhi_result *result);
	void (*dl_xfer_cb)(struct mhi_device *mhi_dev,
			   struct mhi_result *result);
	void (*status_cb)(struct mhi_device *mhi_dev, enum mhi_callback mhi_cb);
	struct device_driver driver;
};

#define to_mhi_driver(drv) container_of(drv, struct mhi_driver, driver)
#define to_mhi_device(dev) container_of(dev, struct mhi_device, dev)

/**
 * mhi_controller_set_devdata - Set MHI controller private data
 * @mhi_cntrl: MHI controller to set data
 */
static inline void mhi_controller_set_devdata(struct mhi_controller *mhi_cntrl,
					 void *priv)
{
	mhi_cntrl->priv_data = priv;
}

/**
 * mhi_controller_get_devdata - Get MHI controller private data
 * @mhi_cntrl: MHI controller to get data
 */
static inline void *mhi_controller_get_devdata(struct mhi_controller *mhi_cntrl)
{
	return mhi_cntrl->priv_data;
}

/**
 * mhi_free_controller - Free MHI controller resources
 * @mhi_cntrl: MHI controller to free
 */
static inline void mhi_free_controller(struct mhi_controller *mhi_cntrl)
{
	kfree(mhi_cntrl);
}

/**
 * mhi_device_get - Disable device low power mode
 * @mhi_dev: Device associated with the channel
 */
void mhi_device_get(struct mhi_device *mhi_dev);

/**
 * mhi_device_get_sync - Disable device low power mode. Synchronously
 *                       take the controller out of suspended state
 * @mhi_dev: Device associated with the channel
 */
int mhi_device_get_sync(struct mhi_device *mhi_dev);

/**
 * mhi_device_put - Re-enable device low power mode
 * @mhi_dev: Device associated with the channel
 */
void mhi_device_put(struct mhi_device *mhi_dev);

/**
 * mhi_alloc_controller - Allocate mhi_controller structure.
 */
struct mhi_controller *mhi_alloc_controller(void);

/**
 * mhi_register_controller - Register MHI controller
 * @mhi_cntrl: MHI controller to register
 * @config: Configuration to use for the controller
 */
int mhi_register_controller(struct mhi_controller *mhi_cntrl,
			    struct mhi_controller_config *config);

/**
 * mhi_unregister_controller - Unregister MHI controller
 * @mhi_cntrl: MHI controller to unregister
 */
void mhi_unregister_controller(struct mhi_controller *mhi_cntrl);

/**
 * mhi_driver_register - Register driver with MHI framework
 * @mhi_drv: Driver associated with the device
 */
int mhi_driver_register(struct mhi_driver *mhi_drv);

/**
 * mhi_driver_unregister - Unregister a driver for mhi_devices
 * @mhi_drv: Driver associated with the device
 */
void mhi_driver_unregister(struct mhi_driver *mhi_drv);

#endif /* _MHI_H_ */