1*c167b9c7SMaximilian Luz /* SPDX-License-Identifier: GPL-2.0+ */ 2*c167b9c7SMaximilian Luz /* 3*c167b9c7SMaximilian Luz * Main SSAM/SSH controller structure and functionality. 4*c167b9c7SMaximilian Luz * 5*c167b9c7SMaximilian Luz * Copyright (C) 2019-2020 Maximilian Luz <[email protected]> 6*c167b9c7SMaximilian Luz */ 7*c167b9c7SMaximilian Luz 8*c167b9c7SMaximilian Luz #ifndef _SURFACE_AGGREGATOR_CONTROLLER_H 9*c167b9c7SMaximilian Luz #define _SURFACE_AGGREGATOR_CONTROLLER_H 10*c167b9c7SMaximilian Luz 11*c167b9c7SMaximilian Luz #include <linux/kref.h> 12*c167b9c7SMaximilian Luz #include <linux/list.h> 13*c167b9c7SMaximilian Luz #include <linux/mutex.h> 14*c167b9c7SMaximilian Luz #include <linux/rbtree.h> 15*c167b9c7SMaximilian Luz #include <linux/rwsem.h> 16*c167b9c7SMaximilian Luz #include <linux/serdev.h> 17*c167b9c7SMaximilian Luz #include <linux/spinlock.h> 18*c167b9c7SMaximilian Luz #include <linux/srcu.h> 19*c167b9c7SMaximilian Luz #include <linux/types.h> 20*c167b9c7SMaximilian Luz #include <linux/workqueue.h> 21*c167b9c7SMaximilian Luz 22*c167b9c7SMaximilian Luz #include <linux/surface_aggregator/controller.h> 23*c167b9c7SMaximilian Luz #include <linux/surface_aggregator/serial_hub.h> 24*c167b9c7SMaximilian Luz 25*c167b9c7SMaximilian Luz #include "ssh_request_layer.h" 26*c167b9c7SMaximilian Luz 27*c167b9c7SMaximilian Luz 28*c167b9c7SMaximilian Luz /* -- Safe counters. -------------------------------------------------------- */ 29*c167b9c7SMaximilian Luz 30*c167b9c7SMaximilian Luz /** 31*c167b9c7SMaximilian Luz * struct ssh_seq_counter - Safe counter for SSH sequence IDs. 32*c167b9c7SMaximilian Luz * @value: The current counter value. 33*c167b9c7SMaximilian Luz */ 34*c167b9c7SMaximilian Luz struct ssh_seq_counter { 35*c167b9c7SMaximilian Luz u8 value; 36*c167b9c7SMaximilian Luz }; 37*c167b9c7SMaximilian Luz 38*c167b9c7SMaximilian Luz /** 39*c167b9c7SMaximilian Luz * struct ssh_rqid_counter - Safe counter for SSH request IDs. 40*c167b9c7SMaximilian Luz * @value: The current counter value. 41*c167b9c7SMaximilian Luz */ 42*c167b9c7SMaximilian Luz struct ssh_rqid_counter { 43*c167b9c7SMaximilian Luz u16 value; 44*c167b9c7SMaximilian Luz }; 45*c167b9c7SMaximilian Luz 46*c167b9c7SMaximilian Luz 47*c167b9c7SMaximilian Luz /* -- Event/notification system. -------------------------------------------- */ 48*c167b9c7SMaximilian Luz 49*c167b9c7SMaximilian Luz /** 50*c167b9c7SMaximilian Luz * struct ssam_nf_head - Notifier head for SSAM events. 51*c167b9c7SMaximilian Luz * @srcu: The SRCU struct for synchronization. 52*c167b9c7SMaximilian Luz * @head: List-head for notifier blocks registered under this head. 53*c167b9c7SMaximilian Luz */ 54*c167b9c7SMaximilian Luz struct ssam_nf_head { 55*c167b9c7SMaximilian Luz struct srcu_struct srcu; 56*c167b9c7SMaximilian Luz struct list_head head; 57*c167b9c7SMaximilian Luz }; 58*c167b9c7SMaximilian Luz 59*c167b9c7SMaximilian Luz /** 60*c167b9c7SMaximilian Luz * struct ssam_nf - Notifier callback- and activation-registry for SSAM events. 61*c167b9c7SMaximilian Luz * @lock: Lock guarding (de-)registration of notifier blocks. Note: This 62*c167b9c7SMaximilian Luz * lock does not need to be held for notifier calls, only 63*c167b9c7SMaximilian Luz * registration and deregistration. 64*c167b9c7SMaximilian Luz * @refcount: The root of the RB-tree used for reference-counting enabled 65*c167b9c7SMaximilian Luz * events/notifications. 66*c167b9c7SMaximilian Luz * @head: The list of notifier heads for event/notification callbacks. 67*c167b9c7SMaximilian Luz */ 68*c167b9c7SMaximilian Luz struct ssam_nf { 69*c167b9c7SMaximilian Luz struct mutex lock; 70*c167b9c7SMaximilian Luz struct rb_root refcount; 71*c167b9c7SMaximilian Luz struct ssam_nf_head head[SSH_NUM_EVENTS]; 72*c167b9c7SMaximilian Luz }; 73*c167b9c7SMaximilian Luz 74*c167b9c7SMaximilian Luz 75*c167b9c7SMaximilian Luz /* -- Event/async request completion system. -------------------------------- */ 76*c167b9c7SMaximilian Luz 77*c167b9c7SMaximilian Luz struct ssam_cplt; 78*c167b9c7SMaximilian Luz 79*c167b9c7SMaximilian Luz /** 80*c167b9c7SMaximilian Luz * struct ssam_event_item - Struct for event queuing and completion. 81*c167b9c7SMaximilian Luz * @node: The node in the queue. 82*c167b9c7SMaximilian Luz * @rqid: The request ID of the event. 83*c167b9c7SMaximilian Luz * @event: Actual event data. 84*c167b9c7SMaximilian Luz */ 85*c167b9c7SMaximilian Luz struct ssam_event_item { 86*c167b9c7SMaximilian Luz struct list_head node; 87*c167b9c7SMaximilian Luz u16 rqid; 88*c167b9c7SMaximilian Luz 89*c167b9c7SMaximilian Luz struct ssam_event event; /* must be last */ 90*c167b9c7SMaximilian Luz }; 91*c167b9c7SMaximilian Luz 92*c167b9c7SMaximilian Luz /** 93*c167b9c7SMaximilian Luz * struct ssam_event_queue - Queue for completing received events. 94*c167b9c7SMaximilian Luz * @cplt: Reference to the completion system on which this queue is active. 95*c167b9c7SMaximilian Luz * @lock: The lock for any operation on the queue. 96*c167b9c7SMaximilian Luz * @head: The list-head of the queue. 97*c167b9c7SMaximilian Luz * @work: The &struct work_struct performing completion work for this queue. 98*c167b9c7SMaximilian Luz */ 99*c167b9c7SMaximilian Luz struct ssam_event_queue { 100*c167b9c7SMaximilian Luz struct ssam_cplt *cplt; 101*c167b9c7SMaximilian Luz 102*c167b9c7SMaximilian Luz spinlock_t lock; 103*c167b9c7SMaximilian Luz struct list_head head; 104*c167b9c7SMaximilian Luz struct work_struct work; 105*c167b9c7SMaximilian Luz }; 106*c167b9c7SMaximilian Luz 107*c167b9c7SMaximilian Luz /** 108*c167b9c7SMaximilian Luz * struct ssam_event_target - Set of queues for a single SSH target ID. 109*c167b9c7SMaximilian Luz * @queue: The array of queues, one queue per event ID. 110*c167b9c7SMaximilian Luz */ 111*c167b9c7SMaximilian Luz struct ssam_event_target { 112*c167b9c7SMaximilian Luz struct ssam_event_queue queue[SSH_NUM_EVENTS]; 113*c167b9c7SMaximilian Luz }; 114*c167b9c7SMaximilian Luz 115*c167b9c7SMaximilian Luz /** 116*c167b9c7SMaximilian Luz * struct ssam_cplt - SSAM event/async request completion system. 117*c167b9c7SMaximilian Luz * @dev: The device with which this system is associated. Only used 118*c167b9c7SMaximilian Luz * for logging. 119*c167b9c7SMaximilian Luz * @wq: The &struct workqueue_struct on which all completion work 120*c167b9c7SMaximilian Luz * items are queued. 121*c167b9c7SMaximilian Luz * @event: Event completion management. 122*c167b9c7SMaximilian Luz * @event.target: Array of &struct ssam_event_target, one for each target. 123*c167b9c7SMaximilian Luz * @event.notif: Notifier callbacks and event activation reference counting. 124*c167b9c7SMaximilian Luz */ 125*c167b9c7SMaximilian Luz struct ssam_cplt { 126*c167b9c7SMaximilian Luz struct device *dev; 127*c167b9c7SMaximilian Luz struct workqueue_struct *wq; 128*c167b9c7SMaximilian Luz 129*c167b9c7SMaximilian Luz struct { 130*c167b9c7SMaximilian Luz struct ssam_event_target target[SSH_NUM_TARGETS]; 131*c167b9c7SMaximilian Luz struct ssam_nf notif; 132*c167b9c7SMaximilian Luz } event; 133*c167b9c7SMaximilian Luz }; 134*c167b9c7SMaximilian Luz 135*c167b9c7SMaximilian Luz 136*c167b9c7SMaximilian Luz /* -- Main SSAM device structures. ------------------------------------------ */ 137*c167b9c7SMaximilian Luz 138*c167b9c7SMaximilian Luz /** 139*c167b9c7SMaximilian Luz * enum ssam_controller_state - State values for &struct ssam_controller. 140*c167b9c7SMaximilian Luz * @SSAM_CONTROLLER_UNINITIALIZED: 141*c167b9c7SMaximilian Luz * The controller has not been initialized yet or has been deinitialized. 142*c167b9c7SMaximilian Luz * @SSAM_CONTROLLER_INITIALIZED: 143*c167b9c7SMaximilian Luz * The controller is initialized, but has not been started yet. 144*c167b9c7SMaximilian Luz * @SSAM_CONTROLLER_STARTED: 145*c167b9c7SMaximilian Luz * The controller has been started and is ready to use. 146*c167b9c7SMaximilian Luz * @SSAM_CONTROLLER_STOPPED: 147*c167b9c7SMaximilian Luz * The controller has been stopped. 148*c167b9c7SMaximilian Luz * @SSAM_CONTROLLER_SUSPENDED: 149*c167b9c7SMaximilian Luz * The controller has been suspended. 150*c167b9c7SMaximilian Luz */ 151*c167b9c7SMaximilian Luz enum ssam_controller_state { 152*c167b9c7SMaximilian Luz SSAM_CONTROLLER_UNINITIALIZED, 153*c167b9c7SMaximilian Luz SSAM_CONTROLLER_INITIALIZED, 154*c167b9c7SMaximilian Luz SSAM_CONTROLLER_STARTED, 155*c167b9c7SMaximilian Luz SSAM_CONTROLLER_STOPPED, 156*c167b9c7SMaximilian Luz SSAM_CONTROLLER_SUSPENDED, 157*c167b9c7SMaximilian Luz }; 158*c167b9c7SMaximilian Luz 159*c167b9c7SMaximilian Luz /** 160*c167b9c7SMaximilian Luz * struct ssam_controller_caps - Controller device capabilities. 161*c167b9c7SMaximilian Luz * @ssh_power_profile: SSH power profile. 162*c167b9c7SMaximilian Luz * @ssh_buffer_size: SSH driver UART buffer size. 163*c167b9c7SMaximilian Luz * @screen_on_sleep_idle_timeout: SAM UART screen-on sleep idle timeout. 164*c167b9c7SMaximilian Luz * @screen_off_sleep_idle_timeout: SAM UART screen-off sleep idle timeout. 165*c167b9c7SMaximilian Luz * @d3_closes_handle: SAM closes UART handle in D3. 166*c167b9c7SMaximilian Luz * 167*c167b9c7SMaximilian Luz * Controller and SSH device capabilities found in ACPI. 168*c167b9c7SMaximilian Luz */ 169*c167b9c7SMaximilian Luz struct ssam_controller_caps { 170*c167b9c7SMaximilian Luz u32 ssh_power_profile; 171*c167b9c7SMaximilian Luz u32 ssh_buffer_size; 172*c167b9c7SMaximilian Luz u32 screen_on_sleep_idle_timeout; 173*c167b9c7SMaximilian Luz u32 screen_off_sleep_idle_timeout; 174*c167b9c7SMaximilian Luz u32 d3_closes_handle:1; 175*c167b9c7SMaximilian Luz }; 176*c167b9c7SMaximilian Luz 177*c167b9c7SMaximilian Luz /** 178*c167b9c7SMaximilian Luz * struct ssam_controller - SSAM controller device. 179*c167b9c7SMaximilian Luz * @kref: Reference count of the controller. 180*c167b9c7SMaximilian Luz * @lock: Main lock for the controller, used to guard state changes. 181*c167b9c7SMaximilian Luz * @state: Controller state. 182*c167b9c7SMaximilian Luz * @rtl: Request transport layer for SSH I/O. 183*c167b9c7SMaximilian Luz * @cplt: Completion system for SSH/SSAM events and asynchronous requests. 184*c167b9c7SMaximilian Luz * @counter: Safe SSH message ID counters. 185*c167b9c7SMaximilian Luz * @counter.seq: Sequence ID counter. 186*c167b9c7SMaximilian Luz * @counter.rqid: Request ID counter. 187*c167b9c7SMaximilian Luz * @irq: Wakeup IRQ resources. 188*c167b9c7SMaximilian Luz * @irq.num: The wakeup IRQ number. 189*c167b9c7SMaximilian Luz * @irq.wakeup_enabled: Whether wakeup by IRQ is enabled during suspend. 190*c167b9c7SMaximilian Luz * @caps: The controller device capabilities. 191*c167b9c7SMaximilian Luz */ 192*c167b9c7SMaximilian Luz struct ssam_controller { 193*c167b9c7SMaximilian Luz struct kref kref; 194*c167b9c7SMaximilian Luz 195*c167b9c7SMaximilian Luz struct rw_semaphore lock; 196*c167b9c7SMaximilian Luz enum ssam_controller_state state; 197*c167b9c7SMaximilian Luz 198*c167b9c7SMaximilian Luz struct ssh_rtl rtl; 199*c167b9c7SMaximilian Luz struct ssam_cplt cplt; 200*c167b9c7SMaximilian Luz 201*c167b9c7SMaximilian Luz struct { 202*c167b9c7SMaximilian Luz struct ssh_seq_counter seq; 203*c167b9c7SMaximilian Luz struct ssh_rqid_counter rqid; 204*c167b9c7SMaximilian Luz } counter; 205*c167b9c7SMaximilian Luz 206*c167b9c7SMaximilian Luz struct { 207*c167b9c7SMaximilian Luz int num; 208*c167b9c7SMaximilian Luz bool wakeup_enabled; 209*c167b9c7SMaximilian Luz } irq; 210*c167b9c7SMaximilian Luz 211*c167b9c7SMaximilian Luz struct ssam_controller_caps caps; 212*c167b9c7SMaximilian Luz }; 213*c167b9c7SMaximilian Luz 214*c167b9c7SMaximilian Luz #define to_ssam_controller(ptr, member) \ 215*c167b9c7SMaximilian Luz container_of(ptr, struct ssam_controller, member) 216*c167b9c7SMaximilian Luz 217*c167b9c7SMaximilian Luz #define ssam_dbg(ctrl, fmt, ...) rtl_dbg(&(ctrl)->rtl, fmt, ##__VA_ARGS__) 218*c167b9c7SMaximilian Luz #define ssam_info(ctrl, fmt, ...) rtl_info(&(ctrl)->rtl, fmt, ##__VA_ARGS__) 219*c167b9c7SMaximilian Luz #define ssam_warn(ctrl, fmt, ...) rtl_warn(&(ctrl)->rtl, fmt, ##__VA_ARGS__) 220*c167b9c7SMaximilian Luz #define ssam_err(ctrl, fmt, ...) rtl_err(&(ctrl)->rtl, fmt, ##__VA_ARGS__) 221*c167b9c7SMaximilian Luz 222*c167b9c7SMaximilian Luz /** 223*c167b9c7SMaximilian Luz * ssam_controller_receive_buf() - Provide input-data to the controller. 224*c167b9c7SMaximilian Luz * @ctrl: The controller. 225*c167b9c7SMaximilian Luz * @buf: The input buffer. 226*c167b9c7SMaximilian Luz * @n: The number of bytes in the input buffer. 227*c167b9c7SMaximilian Luz * 228*c167b9c7SMaximilian Luz * Provide input data to be evaluated by the controller, which has been 229*c167b9c7SMaximilian Luz * received via the lower-level transport. 230*c167b9c7SMaximilian Luz * 231*c167b9c7SMaximilian Luz * Return: Returns the number of bytes consumed, or, if the packet transport 232*c167b9c7SMaximilian Luz * layer of the controller has been shut down, %-ESHUTDOWN. 233*c167b9c7SMaximilian Luz */ 234*c167b9c7SMaximilian Luz static inline 235*c167b9c7SMaximilian Luz int ssam_controller_receive_buf(struct ssam_controller *ctrl, 236*c167b9c7SMaximilian Luz const unsigned char *buf, size_t n) 237*c167b9c7SMaximilian Luz { 238*c167b9c7SMaximilian Luz return ssh_ptl_rx_rcvbuf(&ctrl->rtl.ptl, buf, n); 239*c167b9c7SMaximilian Luz } 240*c167b9c7SMaximilian Luz 241*c167b9c7SMaximilian Luz /** 242*c167b9c7SMaximilian Luz * ssam_controller_write_wakeup() - Notify the controller that the underlying 243*c167b9c7SMaximilian Luz * device has space available for data to be written. 244*c167b9c7SMaximilian Luz * @ctrl: The controller. 245*c167b9c7SMaximilian Luz */ 246*c167b9c7SMaximilian Luz static inline void ssam_controller_write_wakeup(struct ssam_controller *ctrl) 247*c167b9c7SMaximilian Luz { 248*c167b9c7SMaximilian Luz ssh_ptl_tx_wakeup_transfer(&ctrl->rtl.ptl); 249*c167b9c7SMaximilian Luz } 250*c167b9c7SMaximilian Luz 251*c167b9c7SMaximilian Luz int ssam_controller_init(struct ssam_controller *ctrl, struct serdev_device *s); 252*c167b9c7SMaximilian Luz int ssam_controller_start(struct ssam_controller *ctrl); 253*c167b9c7SMaximilian Luz void ssam_controller_shutdown(struct ssam_controller *ctrl); 254*c167b9c7SMaximilian Luz void ssam_controller_destroy(struct ssam_controller *ctrl); 255*c167b9c7SMaximilian Luz 256*c167b9c7SMaximilian Luz int ssam_notifier_disable_registered(struct ssam_controller *ctrl); 257*c167b9c7SMaximilian Luz void ssam_notifier_restore_registered(struct ssam_controller *ctrl); 258*c167b9c7SMaximilian Luz 259*c167b9c7SMaximilian Luz int ssam_irq_setup(struct ssam_controller *ctrl); 260*c167b9c7SMaximilian Luz void ssam_irq_free(struct ssam_controller *ctrl); 261*c167b9c7SMaximilian Luz int ssam_irq_arm_for_wakeup(struct ssam_controller *ctrl); 262*c167b9c7SMaximilian Luz void ssam_irq_disarm_wakeup(struct ssam_controller *ctrl); 263*c167b9c7SMaximilian Luz 264*c167b9c7SMaximilian Luz void ssam_controller_lock(struct ssam_controller *c); 265*c167b9c7SMaximilian Luz void ssam_controller_unlock(struct ssam_controller *c); 266*c167b9c7SMaximilian Luz 267*c167b9c7SMaximilian Luz int ssam_get_firmware_version(struct ssam_controller *ctrl, u32 *version); 268*c167b9c7SMaximilian Luz int ssam_ctrl_notif_display_off(struct ssam_controller *ctrl); 269*c167b9c7SMaximilian Luz int ssam_ctrl_notif_display_on(struct ssam_controller *ctrl); 270*c167b9c7SMaximilian Luz int ssam_ctrl_notif_d0_exit(struct ssam_controller *ctrl); 271*c167b9c7SMaximilian Luz int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl); 272*c167b9c7SMaximilian Luz 273*c167b9c7SMaximilian Luz int ssam_controller_suspend(struct ssam_controller *ctrl); 274*c167b9c7SMaximilian Luz int ssam_controller_resume(struct ssam_controller *ctrl); 275*c167b9c7SMaximilian Luz 276*c167b9c7SMaximilian Luz #endif /* _SURFACE_AGGREGATOR_CONTROLLER_H */ 277