162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Main SSAM/SSH controller structure and functionality. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _SURFACE_AGGREGATOR_CONTROLLER_H 962306a36Sopenharmony_ci#define _SURFACE_AGGREGATOR_CONTROLLER_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kref.h> 1262306a36Sopenharmony_ci#include <linux/list.h> 1362306a36Sopenharmony_ci#include <linux/mutex.h> 1462306a36Sopenharmony_ci#include <linux/rbtree.h> 1562306a36Sopenharmony_ci#include <linux/rwsem.h> 1662306a36Sopenharmony_ci#include <linux/serdev.h> 1762306a36Sopenharmony_ci#include <linux/spinlock.h> 1862306a36Sopenharmony_ci#include <linux/srcu.h> 1962306a36Sopenharmony_ci#include <linux/types.h> 2062306a36Sopenharmony_ci#include <linux/workqueue.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/surface_aggregator/controller.h> 2362306a36Sopenharmony_ci#include <linux/surface_aggregator/serial_hub.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "ssh_request_layer.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* -- Safe counters. -------------------------------------------------------- */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * struct ssh_seq_counter - Safe counter for SSH sequence IDs. 3262306a36Sopenharmony_ci * @value: The current counter value. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistruct ssh_seq_counter { 3562306a36Sopenharmony_ci u8 value; 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/** 3962306a36Sopenharmony_ci * struct ssh_rqid_counter - Safe counter for SSH request IDs. 4062306a36Sopenharmony_ci * @value: The current counter value. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistruct ssh_rqid_counter { 4362306a36Sopenharmony_ci u16 value; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* -- Event/notification system. -------------------------------------------- */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/** 5062306a36Sopenharmony_ci * struct ssam_nf_head - Notifier head for SSAM events. 5162306a36Sopenharmony_ci * @srcu: The SRCU struct for synchronization. 5262306a36Sopenharmony_ci * @head: List-head for notifier blocks registered under this head. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_cistruct ssam_nf_head { 5562306a36Sopenharmony_ci struct srcu_struct srcu; 5662306a36Sopenharmony_ci struct list_head head; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/** 6062306a36Sopenharmony_ci * struct ssam_nf - Notifier callback- and activation-registry for SSAM events. 6162306a36Sopenharmony_ci * @lock: Lock guarding (de-)registration of notifier blocks. Note: This 6262306a36Sopenharmony_ci * lock does not need to be held for notifier calls, only 6362306a36Sopenharmony_ci * registration and deregistration. 6462306a36Sopenharmony_ci * @refcount: The root of the RB-tree used for reference-counting enabled 6562306a36Sopenharmony_ci * events/notifications. 6662306a36Sopenharmony_ci * @head: The list of notifier heads for event/notification callbacks. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_cistruct ssam_nf { 6962306a36Sopenharmony_ci struct mutex lock; 7062306a36Sopenharmony_ci struct rb_root refcount; 7162306a36Sopenharmony_ci struct ssam_nf_head head[SSH_NUM_EVENTS]; 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* -- Event/async request completion system. -------------------------------- */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct ssam_cplt; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/** 8062306a36Sopenharmony_ci * struct ssam_event_item - Struct for event queuing and completion. 8162306a36Sopenharmony_ci * @node: The node in the queue. 8262306a36Sopenharmony_ci * @rqid: The request ID of the event. 8362306a36Sopenharmony_ci * @ops: Instance specific functions. 8462306a36Sopenharmony_ci * @ops.free: Callback for freeing this event item. 8562306a36Sopenharmony_ci * @event: Actual event data. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cistruct ssam_event_item { 8862306a36Sopenharmony_ci struct list_head node; 8962306a36Sopenharmony_ci u16 rqid; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci struct { 9262306a36Sopenharmony_ci void (*free)(struct ssam_event_item *event); 9362306a36Sopenharmony_ci } ops; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci struct ssam_event event; /* must be last */ 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/** 9962306a36Sopenharmony_ci * struct ssam_event_queue - Queue for completing received events. 10062306a36Sopenharmony_ci * @cplt: Reference to the completion system on which this queue is active. 10162306a36Sopenharmony_ci * @lock: The lock for any operation on the queue. 10262306a36Sopenharmony_ci * @head: The list-head of the queue. 10362306a36Sopenharmony_ci * @work: The &struct work_struct performing completion work for this queue. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cistruct ssam_event_queue { 10662306a36Sopenharmony_ci struct ssam_cplt *cplt; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci spinlock_t lock; 10962306a36Sopenharmony_ci struct list_head head; 11062306a36Sopenharmony_ci struct work_struct work; 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/** 11462306a36Sopenharmony_ci * struct ssam_event_target - Set of queues for a single SSH target ID. 11562306a36Sopenharmony_ci * @queue: The array of queues, one queue per event ID. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistruct ssam_event_target { 11862306a36Sopenharmony_ci struct ssam_event_queue queue[SSH_NUM_EVENTS]; 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/** 12262306a36Sopenharmony_ci * struct ssam_cplt - SSAM event/async request completion system. 12362306a36Sopenharmony_ci * @dev: The device with which this system is associated. Only used 12462306a36Sopenharmony_ci * for logging. 12562306a36Sopenharmony_ci * @wq: The &struct workqueue_struct on which all completion work 12662306a36Sopenharmony_ci * items are queued. 12762306a36Sopenharmony_ci * @event: Event completion management. 12862306a36Sopenharmony_ci * @event.target: Array of &struct ssam_event_target, one for each target. 12962306a36Sopenharmony_ci * @event.notif: Notifier callbacks and event activation reference counting. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_cistruct ssam_cplt { 13262306a36Sopenharmony_ci struct device *dev; 13362306a36Sopenharmony_ci struct workqueue_struct *wq; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci struct { 13662306a36Sopenharmony_ci struct ssam_event_target target[SSH_NUM_TARGETS]; 13762306a36Sopenharmony_ci struct ssam_nf notif; 13862306a36Sopenharmony_ci } event; 13962306a36Sopenharmony_ci}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* -- Main SSAM device structures. ------------------------------------------ */ 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/** 14562306a36Sopenharmony_ci * enum ssam_controller_state - State values for &struct ssam_controller. 14662306a36Sopenharmony_ci * @SSAM_CONTROLLER_UNINITIALIZED: 14762306a36Sopenharmony_ci * The controller has not been initialized yet or has been deinitialized. 14862306a36Sopenharmony_ci * @SSAM_CONTROLLER_INITIALIZED: 14962306a36Sopenharmony_ci * The controller is initialized, but has not been started yet. 15062306a36Sopenharmony_ci * @SSAM_CONTROLLER_STARTED: 15162306a36Sopenharmony_ci * The controller has been started and is ready to use. 15262306a36Sopenharmony_ci * @SSAM_CONTROLLER_STOPPED: 15362306a36Sopenharmony_ci * The controller has been stopped. 15462306a36Sopenharmony_ci * @SSAM_CONTROLLER_SUSPENDED: 15562306a36Sopenharmony_ci * The controller has been suspended. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cienum ssam_controller_state { 15862306a36Sopenharmony_ci SSAM_CONTROLLER_UNINITIALIZED, 15962306a36Sopenharmony_ci SSAM_CONTROLLER_INITIALIZED, 16062306a36Sopenharmony_ci SSAM_CONTROLLER_STARTED, 16162306a36Sopenharmony_ci SSAM_CONTROLLER_STOPPED, 16262306a36Sopenharmony_ci SSAM_CONTROLLER_SUSPENDED, 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/** 16662306a36Sopenharmony_ci * struct ssam_controller_caps - Controller device capabilities. 16762306a36Sopenharmony_ci * @ssh_power_profile: SSH power profile. 16862306a36Sopenharmony_ci * @ssh_buffer_size: SSH driver UART buffer size. 16962306a36Sopenharmony_ci * @screen_on_sleep_idle_timeout: SAM UART screen-on sleep idle timeout. 17062306a36Sopenharmony_ci * @screen_off_sleep_idle_timeout: SAM UART screen-off sleep idle timeout. 17162306a36Sopenharmony_ci * @d3_closes_handle: SAM closes UART handle in D3. 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * Controller and SSH device capabilities found in ACPI. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_cistruct ssam_controller_caps { 17662306a36Sopenharmony_ci u32 ssh_power_profile; 17762306a36Sopenharmony_ci u32 ssh_buffer_size; 17862306a36Sopenharmony_ci u32 screen_on_sleep_idle_timeout; 17962306a36Sopenharmony_ci u32 screen_off_sleep_idle_timeout; 18062306a36Sopenharmony_ci u32 d3_closes_handle:1; 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/** 18462306a36Sopenharmony_ci * struct ssam_controller - SSAM controller device. 18562306a36Sopenharmony_ci * @kref: Reference count of the controller. 18662306a36Sopenharmony_ci * @lock: Main lock for the controller, used to guard state changes. 18762306a36Sopenharmony_ci * @state: Controller state. 18862306a36Sopenharmony_ci * @rtl: Request transport layer for SSH I/O. 18962306a36Sopenharmony_ci * @cplt: Completion system for SSH/SSAM events and asynchronous requests. 19062306a36Sopenharmony_ci * @counter: Safe SSH message ID counters. 19162306a36Sopenharmony_ci * @counter.seq: Sequence ID counter. 19262306a36Sopenharmony_ci * @counter.rqid: Request ID counter. 19362306a36Sopenharmony_ci * @irq: Wakeup IRQ resources. 19462306a36Sopenharmony_ci * @irq.num: The wakeup IRQ number. 19562306a36Sopenharmony_ci * @irq.wakeup_enabled: Whether wakeup by IRQ is enabled during suspend. 19662306a36Sopenharmony_ci * @caps: The controller device capabilities. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_cistruct ssam_controller { 19962306a36Sopenharmony_ci struct kref kref; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci struct rw_semaphore lock; 20262306a36Sopenharmony_ci enum ssam_controller_state state; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci struct ssh_rtl rtl; 20562306a36Sopenharmony_ci struct ssam_cplt cplt; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci struct { 20862306a36Sopenharmony_ci struct ssh_seq_counter seq; 20962306a36Sopenharmony_ci struct ssh_rqid_counter rqid; 21062306a36Sopenharmony_ci } counter; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci struct { 21362306a36Sopenharmony_ci int num; 21462306a36Sopenharmony_ci bool wakeup_enabled; 21562306a36Sopenharmony_ci } irq; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci struct ssam_controller_caps caps; 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci#define to_ssam_controller(ptr, member) \ 22162306a36Sopenharmony_ci container_of(ptr, struct ssam_controller, member) 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#define ssam_dbg(ctrl, fmt, ...) rtl_dbg(&(ctrl)->rtl, fmt, ##__VA_ARGS__) 22462306a36Sopenharmony_ci#define ssam_info(ctrl, fmt, ...) rtl_info(&(ctrl)->rtl, fmt, ##__VA_ARGS__) 22562306a36Sopenharmony_ci#define ssam_warn(ctrl, fmt, ...) rtl_warn(&(ctrl)->rtl, fmt, ##__VA_ARGS__) 22662306a36Sopenharmony_ci#define ssam_err(ctrl, fmt, ...) rtl_err(&(ctrl)->rtl, fmt, ##__VA_ARGS__) 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/** 22962306a36Sopenharmony_ci * ssam_controller_receive_buf() - Provide input-data to the controller. 23062306a36Sopenharmony_ci * @ctrl: The controller. 23162306a36Sopenharmony_ci * @buf: The input buffer. 23262306a36Sopenharmony_ci * @n: The number of bytes in the input buffer. 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * Provide input data to be evaluated by the controller, which has been 23562306a36Sopenharmony_ci * received via the lower-level transport. 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * Return: Returns the number of bytes consumed, or, if the packet transport 23862306a36Sopenharmony_ci * layer of the controller has been shut down, %-ESHUTDOWN. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_cistatic inline 24162306a36Sopenharmony_ciint ssam_controller_receive_buf(struct ssam_controller *ctrl, 24262306a36Sopenharmony_ci const unsigned char *buf, size_t n) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci return ssh_ptl_rx_rcvbuf(&ctrl->rtl.ptl, buf, n); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * ssam_controller_write_wakeup() - Notify the controller that the underlying 24962306a36Sopenharmony_ci * device has space available for data to be written. 25062306a36Sopenharmony_ci * @ctrl: The controller. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic inline void ssam_controller_write_wakeup(struct ssam_controller *ctrl) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci ssh_ptl_tx_wakeup_transfer(&ctrl->rtl.ptl); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciint ssam_controller_init(struct ssam_controller *ctrl, struct serdev_device *s); 25862306a36Sopenharmony_ciint ssam_controller_start(struct ssam_controller *ctrl); 25962306a36Sopenharmony_civoid ssam_controller_shutdown(struct ssam_controller *ctrl); 26062306a36Sopenharmony_civoid ssam_controller_destroy(struct ssam_controller *ctrl); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ciint ssam_notifier_disable_registered(struct ssam_controller *ctrl); 26362306a36Sopenharmony_civoid ssam_notifier_restore_registered(struct ssam_controller *ctrl); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ciint ssam_irq_setup(struct ssam_controller *ctrl); 26662306a36Sopenharmony_civoid ssam_irq_free(struct ssam_controller *ctrl); 26762306a36Sopenharmony_ciint ssam_irq_arm_for_wakeup(struct ssam_controller *ctrl); 26862306a36Sopenharmony_civoid ssam_irq_disarm_wakeup(struct ssam_controller *ctrl); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_civoid ssam_controller_lock(struct ssam_controller *c); 27162306a36Sopenharmony_civoid ssam_controller_unlock(struct ssam_controller *c); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ciint ssam_get_firmware_version(struct ssam_controller *ctrl, u32 *version); 27462306a36Sopenharmony_ciint ssam_ctrl_notif_display_off(struct ssam_controller *ctrl); 27562306a36Sopenharmony_ciint ssam_ctrl_notif_display_on(struct ssam_controller *ctrl); 27662306a36Sopenharmony_ciint ssam_ctrl_notif_d0_exit(struct ssam_controller *ctrl); 27762306a36Sopenharmony_ciint ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciint ssam_controller_suspend(struct ssam_controller *ctrl); 28062306a36Sopenharmony_ciint ssam_controller_resume(struct ssam_controller *ctrl); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciint ssam_event_item_cache_init(void); 28362306a36Sopenharmony_civoid ssam_event_item_cache_destroy(void); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#endif /* _SURFACE_AGGREGATOR_CONTROLLER_H */ 286