summaryrefslogtreecommitdiffstats
path: root/drivers/platform/surface/aggregator/controller.h
blob: f1638c2081e8bbb19826d9a75df3995d93a02e39 (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
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Main SSAM/SSH controller structure and functionality.
 *
 * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
 */

#ifndef _SURFACE_AGGREGATOR_CONTROLLER_H
#define _SURFACE_AGGREGATOR_CONTROLLER_H

#include <linux/kref.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/rbtree.h>
#include <linux/rwsem.h>
#include <linux/serdev.h>
#include <linux/spinlock.h>
#include <linux/srcu.h>
#include <linux/types.h>
#include <linux/workqueue.h>

#include <linux/surface_aggregator/controller.h>
#include <linux/surface_aggregator/serial_hub.h>

#include "ssh_request_layer.h"


/* -- Safe counters. -------------------------------------------------------- */

/**
 * struct ssh_seq_counter - Safe counter for SSH sequence IDs.
 * @value: The current counter value.
 */
struct ssh_seq_counter {
	u8 value;
};

/**
 * struct ssh_rqid_counter - Safe counter for SSH request IDs.
 * @value: The current counter value.
 */
struct ssh_rqid_counter {
	u16 value;
};


/* -- Event/notification system. -------------------------------------------- */

/**
 * struct ssam_nf_head - Notifier head for SSAM events.
 * @srcu: The SRCU struct for synchronization.
 * @head: List-head for notifier blocks registered under this head.
 */
struct ssam_nf_head {
	struct srcu_struct srcu;
	struct list_head head;
};

/**
 * struct ssam_nf - Notifier callback- and activation-registry for SSAM events.
 * @lock:     Lock guarding (de-)registration of notifier blocks. Note: This
 *            lock does not need to be held for notifier calls, only
 *            registration and deregistration.
 * @refcount: The root of the RB-tree used for reference-counting enabled
 *            events/notifications.
 * @head:     The list of notifier heads for event/notification callbacks.
 */
struct ssam_nf {
	struct mutex lock;
	struct rb_root refcount;
	struct ssam_nf_head head[SSH_NUM_EVENTS];
};


/* -- Event/async request completion system. -------------------------------- */

struct ssam_cplt;

/**
 * struct ssam_event_item - Struct for event queuing and completion.
 * @node:     The node in the queue.
 * @rqid:     The request ID of the event.
 * @ops:      Instance specific functions.
 * @ops.free: Callback for freeing this event item.
 * @event:    Actual event data.
 */
struct ssam_event_item {
	struct list_head node;
	u16 rqid;

	struct {
		void (*free)(struct ssam_event_item *event);
	} ops;

	struct ssam_event event;	/* must be last */
};

/**
 * struct ssam_event_queue - Queue for completing received events.
 * @cplt: Reference to the completion system on which this queue is active.
 * @lock: The lock for any operation on the queue.
 * @head: The list-head of the queue.
 * @work: The &struct work_struct performing completion work for this queue.
 */
struct ssam_event_queue {
	struct ssam_cplt *cplt;

	spinlock_t lock;
	struct list_head head;
	struct work_struct work;
};

/**
 * struct ssam_event_target - Set of queues for a single SSH target ID.
 * @queue: The array of queues, one queue per event ID.
 */
struct ssam_event_target {
	struct ssam_event_queue queue[SSH_NUM_EVENTS];
};

/**
 * struct ssam_cplt - SSAM event/async request completion system.
 * @dev:          The device with which this system is associated. Only used
 *                for logging.
 * @wq:           The &struct workqueue_struct on which all completion work
 *                items are queued.
 * @event:        Event completion management.
 * @event.target: Array of &struct ssam_event_target, one for each target.
 * @event.notif:  Notifier callbacks and event activation reference counting.
 */
struct ssam_cplt {
	struct device *dev;
	struct workqueue_struct *wq;

	struct {
		struct ssam_event_target target[SSH_NUM_TARGETS];
		struct ssam_nf notif;
	} event;
};


/* -- Main SSAM device structures. ------------------------------------------ */

/**
 * enum ssam_controller_state - State values for &struct ssam_controller.
 * @SSAM_CONTROLLER_UNINITIALIZED:
 *	The controller has not been initialized yet or has been deinitialized.
 * @SSAM_CONTROLLER_INITIALIZED:
 *	The controller is initialized, but has not been started yet.
 * @SSAM_CONTROLLER_STARTED:
 *	The controller has been started and is ready to use.
 * @SSAM_CONTROLLER_STOPPED:
 *	The controller has been stopped.
 * @SSAM_CONTROLLER_SUSPENDED:
 *	The controller has been suspended.
 */
enum ssam_controller_state {
	SSAM_CONTROLLER_UNINITIALIZED,
	SSAM_CONTROLLER_INITIALIZED,
	SSAM_CONTROLLER_STARTED,
	SSAM_CONTROLLER_STOPPED,
	SSAM_CONTROLLER_SUSPENDED,
};

/**
 * struct ssam_controller_caps - Controller device capabilities.
 * @ssh_power_profile:             SSH power profile.
 * @ssh_buffer_size:               SSH driver UART buffer size.
 * @screen_on_sleep_idle_timeout:  SAM UART screen-on sleep idle timeout.
 * @screen_off_sleep_idle_timeout: SAM UART screen-off sleep idle timeout.
 * @d3_closes_handle:              SAM closes UART handle in D3.
 *
 * Controller and SSH device capabilities found in ACPI.
 */
struct ssam_controller_caps {
	u32 ssh_power_profile;
	u32 ssh_buffer_size;
	u32 screen_on_sleep_idle_timeout;
	u32 screen_off_sleep_idle_timeout;
	u32 d3_closes_handle:1;
};

/**
 * struct ssam_controller - SSAM controller device.
 * @kref:  Reference count of the controller.
 * @lock:  Main lock for the controller, used to guard state changes.
 * @state: Controller state.
 * @rtl:   Request transport layer for SSH I/O.
 * @cplt:  Completion system for SSH/SSAM events and asynchronous requests.
 * @counter:      Safe SSH message ID counters.
 * @counter.seq:  Sequence ID counter.
 * @counter.rqid: Request ID counter.
 * @irq:          Wakeup IRQ resources.
 * @irq.num:      The wakeup IRQ number.
 * @irq.wakeup_enabled: Whether wakeup by IRQ is enabled during suspend.
 * @caps: The controller device capabilities.
 */
struct ssam_controller {
	struct kref kref;

	struct rw_semaphore lock;
	enum ssam_controller_state state;

	struct ssh_rtl rtl;
	struct ssam_cplt cplt;

	struct {
		struct ssh_seq_counter seq;
		struct ssh_rqid_counter rqid;
	} counter;

	struct {
		int num;
		bool wakeup_enabled;
	} irq;

	struct ssam_controller_caps caps;
};

#define to_ssam_controller(ptr, member) \
	container_of(ptr, struct ssam_controller, member)

#define ssam_dbg(ctrl, fmt, ...)  rtl_dbg(&(ctrl)->rtl, fmt, ##__VA_ARGS__)
#define ssam_info(ctrl, fmt, ...) rtl_info(&(ctrl)->rtl, fmt, ##__VA_ARGS__)
#define ssam_warn(ctrl, fmt, ...) rtl_warn(&(ctrl)->rtl, fmt, ##__VA_ARGS__)
#define ssam_err(ctrl, fmt, ...)  rtl_err(&(ctrl)->rtl, fmt, ##__VA_ARGS__)

/**
 * ssam_controller_receive_buf() - Provide input-data to the controller.
 * @ctrl: The controller.
 * @buf:  The input buffer.
 * @n:    The number of bytes in the input buffer.
 *
 * Provide input data to be evaluated by the controller, which has been
 * received via the lower-level transport.
 *
 * Return: Returns the number of bytes consumed, or, if the packet transport
 * layer of the controller has been shut down, %-ESHUTDOWN.
 */
static inline
ssize_t ssam_controller_receive_buf(struct ssam_controller *ctrl, const u8 *buf,
				    size_t n)
{
	return ssh_ptl_rx_rcvbuf(&ctrl->rtl.ptl, buf, n);
}

/**
 * ssam_controller_write_wakeup() - Notify the controller that the underlying
 * device has space available for data to be written.
 * @ctrl: The controller.
 */
static inline void ssam_controller_write_wakeup(struct ssam_controller *ctrl)
{
	ssh_ptl_tx_wakeup_transfer(&ctrl->rtl.ptl);
}

int ssam_controller_init(struct ssam_controller *ctrl, struct serdev_device *s);
int ssam_controller_start(struct ssam_controller *ctrl);
void ssam_controller_shutdown(struct ssam_controller *ctrl);
void ssam_controller_destroy(struct ssam_controller *ctrl);

int ssam_notifier_disable_registered(struct ssam_controller *ctrl);
void ssam_notifier_restore_registered(struct ssam_controller *ctrl);

int ssam_irq_setup(struct ssam_controller *ctrl);
void ssam_irq_free(struct ssam_controller *ctrl);
int ssam_irq_arm_for_wakeup(struct ssam_controller *ctrl);
void ssam_irq_disarm_wakeup(struct ssam_controller *ctrl);

void ssam_controller_lock(struct ssam_controller *c);
void ssam_controller_unlock(struct ssam_controller *c);

int ssam_get_firmware_version(struct ssam_controller *ctrl, u32 *version);
int ssam_ctrl_notif_display_off(struct ssam_controller *ctrl);
int ssam_ctrl_notif_display_on(struct ssam_controller *ctrl);
int ssam_ctrl_notif_d0_exit(struct ssam_controller *ctrl);
int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl);

int ssam_controller_suspend(struct ssam_controller *ctrl);
int ssam_controller_resume(struct ssam_controller *ctrl);

int ssam_event_item_cache_init(void);
void ssam_event_item_cache_destroy(void);

#endif /* _SURFACE_AGGREGATOR_CONTROLLER_H */