xref: /linux/include/linux/mfd/macsmc.h (revision 980190a9473dd2c842518057bf9ddcbaeba75209)
1 /* SPDX-License-Identifier: GPL-2.0-only OR MIT */
2 /*
3  * Apple SMC (System Management Controller) core definitions
4  *
5  * Copyright (C) The Asahi Linux Contributors
6  */
7 
8 #ifndef _LINUX_MFD_MACSMC_H
9 #define _LINUX_MFD_MACSMC_H
10 
11 #include <linux/soc/apple/rtkit.h>
12 
13 /**
14  * typedef smc_key - Alias for u32 to be used for SMC keys
15  *
16  * SMC keys are 32bit integers containing packed ASCII characters in natural
17  * integer order, i.e. 0xAABBCCDD, which represent the FourCC ABCD.
18  * The SMC driver is designed with this assumption and ensures the right
19  * endianness is used when these are stored to memory and sent to or received
20  * from the actual SMC firmware (which can be done in either shared memory or
21  * as 64bit mailbox message on Apple Silicon).
22  * Internally, SMC stores these keys in a table sorted lexicographically and
23  * allows resolving an index into this table to the corresponding SMC key.
24  * Thus, storing keys as u32 is very convenient as it allows to e.g. use
25  * normal comparison operators which directly map to the natural order used
26  * by SMC firmware.
27  *
28  * This simple type alias is introduced to allow easy recognition of SMC key
29  * variables and arguments.
30  */
31 typedef u32 smc_key;
32 
33 /**
34  * SMC_KEY - Convert FourCC SMC keys in source code to smc_key
35  *
36  * This macro can be used to easily define FourCC SMC keys in source code
37  * and convert these to u32 / smc_key, e.g. SMC_KEY(NTAP) will expand to
38  * 0x4e544150.
39  *
40  * @s: FourCC SMC key to be converted
41  */
42 #define SMC_KEY(s) (smc_key)(_SMC_KEY(#s))
43 #define _SMC_KEY(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3])
44 #define __SMC_KEY(a, b, c, d) (((u32)(a) << 24) | ((u32)(b) << 16) | ((u32)(c) << 8) | ((u32)(d)))
45 
46 #define APPLE_SMC_READABLE BIT(7)
47 #define APPLE_SMC_WRITABLE BIT(6)
48 #define APPLE_SMC_FUNCTION BIT(4)
49 
50 /**
51  * struct apple_smc_key_info - Information for a SMC key as returned by SMC
52  * @type_code: FourCC code indicating the type for this key.
53  *             Known types:
54  *              ch8*: ASCII string
55  *              flag: Boolean, 1 or 0
56  *              flt: 32-bit single-precision IEEE 754 float
57  *              hex: Binary data
58  *              ioft: 64bit Unsigned fixed-point intger (48.16)
59  *              {si,ui}{8,16,32,64}: Signed/Unsigned 8-/16-/32-/64-bit integer
60  * @size: Size of the buffer associated with this key
61  * @flags: Bitfield encoding flags (APPLE_SMC_{READABLE,WRITABLE,FUNCTION})
62  */
63 struct apple_smc_key_info {
64 	u32 type_code;
65 	u8 size;
66 	u8 flags;
67 };
68 
69 /**
70  * enum apple_smc_boot_stage - SMC boot stage
71  * @APPLE_SMC_BOOTING: SMC is booting
72  * @APPLE_SMC_INITIALIZED: SMC is initialized and ready to use
73  * @APPLE_SMC_ERROR_NO_SHMEM: Shared memory could not be initialized during boot
74  * @APPLE_SMC_ERROR_CRASHED: SMC has crashed
75  */
76 enum apple_smc_boot_stage {
77 	APPLE_SMC_BOOTING,
78 	APPLE_SMC_INITIALIZED,
79 	APPLE_SMC_ERROR_NO_SHMEM,
80 	APPLE_SMC_ERROR_CRASHED
81 };
82 
83 /**
84  * struct apple_smc
85  * @dev: Underlying device struct for the physical backend device
86  * @key_count: Number of available SMC keys
87  * @first_key: First valid SMC key
88  * @last_key: Last valid SMC key
89  * @event_handlers: Notifier call chain for events received from SMC
90  * @rtk: Pointer to Apple RTKit instance
91  * @init_done: Completion for initialization
92  * @boot_stage: Current boot stage of SMC
93  * @sram: Pointer to SRAM resource
94  * @sram_base: SRAM base address
95  * @shmem: RTKit shared memory structure for SRAM
96  * @msg_id: Current message id for commands, will be incremented for each command
97  * @atomic_mode: Flag set when atomic mode is entered
98  * @atomic_pending: Flag indicating pending atomic command
99  * @cmd_done: Completion for command execution in non-atomic mode
100  * @cmd_ret: Return value from SMC for last command
101  * @mutex: Mutex for non-atomic mode
102  * @lock: Spinlock for atomic mode
103  */
104 struct apple_smc {
105 	struct device *dev;
106 
107 	u32 key_count;
108 	smc_key first_key;
109 	smc_key last_key;
110 
111 	struct blocking_notifier_head event_handlers;
112 
113 	struct apple_rtkit *rtk;
114 
115 	struct completion init_done;
116 	enum apple_smc_boot_stage boot_stage;
117 
118 	struct resource *sram;
119 	void __iomem *sram_base;
120 	struct apple_rtkit_shmem shmem;
121 
122 	unsigned int msg_id;
123 
124 	bool atomic_mode;
125 	bool atomic_pending;
126 	struct completion cmd_done;
127 	u64 cmd_ret;
128 
129 	struct mutex mutex;
130 	spinlock_t lock;
131 };
132 
133 /**
134  * apple_smc_read - Read size bytes from given SMC key into buf
135  * @smc: Pointer to apple_smc struct
136  * @key: smc_key to be read
137  * @buf: Buffer into which size bytes of data will be read from SMC
138  * @size: Number of bytes to be read into buf
139  *
140  * Return: Zero on success, negative errno on error
141  */
142 int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size);
143 
144 /**
145  * apple_smc_write - Write size bytes into given SMC key from buf
146  * @smc: Pointer to apple_smc struct
147  * @key: smc_key data will be written to
148  * @buf: Buffer from which size bytes of data will be written to SMC
149  * @size: Number of bytes to be written
150  *
151  * Return: Zero on success, negative errno on error
152  */
153 int apple_smc_write(struct apple_smc *smc, smc_key key, const void *buf, size_t size);
154 
155 /**
156  * apple_smc_enter_atomic - Enter atomic mode to be able to use apple_smc_write_atomic
157  * @smc: Pointer to apple_smc struct
158  *
159  * This function switches the SMC backend to atomic mode which allows the
160  * use of apple_smc_write_atomic while disabling *all* other functions.
161  * This is only used for shutdown/reboot which requires writing to a SMC
162  * key from atomic context.
163  *
164  * Return: Zero on success, negative errno on error
165  */
166 int apple_smc_enter_atomic(struct apple_smc *smc);
167 
168 /**
169  * apple_smc_write_atomic - Write size bytes into given SMC key from buf without sleeping
170  * @smc: Pointer to apple_smc struct
171  * @key: smc_key data will be written to
172  * @buf: Buffer from which size bytes of data will be written to SMC
173  * @size: Number of bytes to be written
174  *
175  * Note that this function will fail if apple_smc_enter_atomic hasn't been
176  * called before.
177  *
178  * Return: Zero on success, negative errno on error
179  */
180 int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, const void *buf, size_t size);
181 
182 /**
183  * apple_smc_rw - Write and then read using the given SMC key
184  * @smc: Pointer to apple_smc struct
185  * @key: smc_key data will be written to
186  * @wbuf: Buffer from which size bytes of data will be written to SMC
187  * @wsize: Number of bytes to be written
188  * @rbuf: Buffer to which size bytes of data will be read from SMC
189  * @rsize: Number of bytes to be read
190  *
191  * Return: Zero on success, negative errno on error
192  */
193 int apple_smc_rw(struct apple_smc *smc, smc_key key, const void *wbuf, size_t wsize,
194 		 void *rbuf, size_t rsize);
195 
196 /**
197  * apple_smc_get_key_by_index - Given an index return the corresponding SMC key
198  * @smc: Pointer to apple_smc struct
199  * @index: Index to be resolved
200  * @key: Buffer for SMC key to be returned
201  *
202  * Return: Zero on success, negative errno on error
203  */
204 int apple_smc_get_key_by_index(struct apple_smc *smc, int index, smc_key *key);
205 
206 /**
207  * apple_smc_get_key_info - Get key information from SMC
208  * @smc: Pointer to apple_smc struct
209  * @key: Key to acquire information for
210  * @info: Pointer to struct apple_smc_key_info which will be filled
211  *
212  * Return: Zero on success, negative errno on error
213  */
214 int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_key_info *info);
215 
216 /**
217  * apple_smc_key_exists - Check if the given SMC key exists
218  * @smc: Pointer to apple_smc struct
219  * @key: smc_key to be checked
220  *
221  * Return: True if the key exists, false otherwise
222  */
223 static inline bool apple_smc_key_exists(struct apple_smc *smc, smc_key key)
224 {
225 	return apple_smc_get_key_info(smc, key, NULL) >= 0;
226 }
227 
228 #define APPLE_SMC_TYPE_OPS(type) \
229 	static inline int apple_smc_read_##type(struct apple_smc *smc, smc_key key, type *p) \
230 	{ \
231 		int ret = apple_smc_read(smc, key, p, sizeof(*p)); \
232 		return (ret < 0) ? ret : ((ret != sizeof(*p)) ? -EINVAL : 0); \
233 	} \
234 	static inline int apple_smc_write_##type(struct apple_smc *smc, smc_key key, type p) \
235 	{ \
236 		return apple_smc_write(smc, key, &p, sizeof(p)); \
237 	} \
238 	static inline int apple_smc_write_##type##_atomic(struct apple_smc *smc, smc_key key, type p) \
239 	{ \
240 		return apple_smc_write_atomic(smc, key, &p, sizeof(p)); \
241 	} \
242 	static inline int apple_smc_rw_##type(struct apple_smc *smc, smc_key key, \
243 					      type w, type *r) \
244 	{ \
245 		int ret = apple_smc_rw(smc, key, &w, sizeof(w), r, sizeof(*r)); \
246 		return (ret < 0) ? ret : ((ret != sizeof(*r)) ? -EINVAL : 0); \
247 	}
248 
249 APPLE_SMC_TYPE_OPS(u64)
250 APPLE_SMC_TYPE_OPS(u32)
251 APPLE_SMC_TYPE_OPS(u16)
252 APPLE_SMC_TYPE_OPS(u8)
253 APPLE_SMC_TYPE_OPS(s64)
254 APPLE_SMC_TYPE_OPS(s32)
255 APPLE_SMC_TYPE_OPS(s16)
256 APPLE_SMC_TYPE_OPS(s8)
257 
258 static inline int apple_smc_read_flag(struct apple_smc *smc, smc_key key, bool *flag)
259 {
260 	u8 val;
261 	int ret = apple_smc_read_u8(smc, key, &val);
262 
263 	if (ret < 0)
264 		return ret;
265 
266 	*flag = val ? true : false;
267 	return ret;
268 }
269 
270 static inline int apple_smc_write_flag(struct apple_smc *smc, smc_key key, bool state)
271 {
272 	return apple_smc_write_u8(smc, key, state ? 1 : 0);
273 }
274 
275 static inline int apple_smc_write_flag_atomic(struct apple_smc *smc, smc_key key, bool state)
276 {
277 	return apple_smc_write_u8_atomic(smc, key, state ? 1 : 0);
278 }
279 
280 #endif
281