281 lines
9.0 KiB
C
281 lines
9.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
|
|
/*
|
|
* Apple SMC (System Management Controller) core definitions
|
|
*
|
|
* Copyright (C) The Asahi Linux Contributors
|
|
*/
|
|
|
|
#ifndef _LINUX_MFD_MACSMC_H
|
|
#define _LINUX_MFD_MACSMC_H
|
|
|
|
#include <linux/soc/apple/rtkit.h>
|
|
|
|
/**
|
|
* typedef smc_key - Alias for u32 to be used for SMC keys
|
|
*
|
|
* SMC keys are 32bit integers containing packed ASCII characters in natural
|
|
* integer order, i.e. 0xAABBCCDD, which represent the FourCC ABCD.
|
|
* The SMC driver is designed with this assumption and ensures the right
|
|
* endianness is used when these are stored to memory and sent to or received
|
|
* from the actual SMC firmware (which can be done in either shared memory or
|
|
* as 64bit mailbox message on Apple Silicon).
|
|
* Internally, SMC stores these keys in a table sorted lexicographically and
|
|
* allows resolving an index into this table to the corresponding SMC key.
|
|
* Thus, storing keys as u32 is very convenient as it allows to e.g. use
|
|
* normal comparison operators which directly map to the natural order used
|
|
* by SMC firmware.
|
|
*
|
|
* This simple type alias is introduced to allow easy recognition of SMC key
|
|
* variables and arguments.
|
|
*/
|
|
typedef u32 smc_key;
|
|
|
|
/**
|
|
* SMC_KEY - Convert FourCC SMC keys in source code to smc_key
|
|
*
|
|
* This macro can be used to easily define FourCC SMC keys in source code
|
|
* and convert these to u32 / smc_key, e.g. SMC_KEY(NTAP) will expand to
|
|
* 0x4e544150.
|
|
*
|
|
* @s: FourCC SMC key to be converted
|
|
*/
|
|
#define SMC_KEY(s) (smc_key)(_SMC_KEY(#s))
|
|
#define _SMC_KEY(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3])
|
|
#define __SMC_KEY(a, b, c, d) (((u32)(a) << 24) | ((u32)(b) << 16) | ((u32)(c) << 8) | ((u32)(d)))
|
|
|
|
#define APPLE_SMC_READABLE BIT(7)
|
|
#define APPLE_SMC_WRITABLE BIT(6)
|
|
#define APPLE_SMC_FUNCTION BIT(4)
|
|
|
|
/**
|
|
* struct apple_smc_key_info - Information for a SMC key as returned by SMC
|
|
* @type_code: FourCC code indicating the type for this key.
|
|
* Known types:
|
|
* ch8*: ASCII string
|
|
* flag: Boolean, 1 or 0
|
|
* flt: 32-bit single-precision IEEE 754 float
|
|
* hex: Binary data
|
|
* ioft: 64bit Unsigned fixed-point intger (48.16)
|
|
* {si,ui}{8,16,32,64}: Signed/Unsigned 8-/16-/32-/64-bit integer
|
|
* @size: Size of the buffer associated with this key
|
|
* @flags: Bitfield encoding flags (APPLE_SMC_{READABLE,WRITABLE,FUNCTION})
|
|
*/
|
|
struct apple_smc_key_info {
|
|
u32 type_code;
|
|
u8 size;
|
|
u8 flags;
|
|
};
|
|
|
|
/**
|
|
* enum apple_smc_boot_stage - SMC boot stage
|
|
* @APPLE_SMC_BOOTING: SMC is booting
|
|
* @APPLE_SMC_INITIALIZED: SMC is initialized and ready to use
|
|
* @APPLE_SMC_ERROR_NO_SHMEM: Shared memory could not be initialized during boot
|
|
* @APPLE_SMC_ERROR_CRASHED: SMC has crashed
|
|
*/
|
|
enum apple_smc_boot_stage {
|
|
APPLE_SMC_BOOTING,
|
|
APPLE_SMC_INITIALIZED,
|
|
APPLE_SMC_ERROR_NO_SHMEM,
|
|
APPLE_SMC_ERROR_CRASHED
|
|
};
|
|
|
|
/**
|
|
* struct apple_smc
|
|
* @dev: Underlying device struct for the physical backend device
|
|
* @key_count: Number of available SMC keys
|
|
* @first_key: First valid SMC key
|
|
* @last_key: Last valid SMC key
|
|
* @event_handlers: Notifier call chain for events received from SMC
|
|
* @rtk: Pointer to Apple RTKit instance
|
|
* @init_done: Completion for initialization
|
|
* @boot_stage: Current boot stage of SMC
|
|
* @sram: Pointer to SRAM resource
|
|
* @sram_base: SRAM base address
|
|
* @shmem: RTKit shared memory structure for SRAM
|
|
* @msg_id: Current message id for commands, will be incremented for each command
|
|
* @atomic_mode: Flag set when atomic mode is entered
|
|
* @atomic_pending: Flag indicating pending atomic command
|
|
* @cmd_done: Completion for command execution in non-atomic mode
|
|
* @cmd_ret: Return value from SMC for last command
|
|
* @mutex: Mutex for non-atomic mode
|
|
* @lock: Spinlock for atomic mode
|
|
*/
|
|
struct apple_smc {
|
|
struct device *dev;
|
|
|
|
u32 key_count;
|
|
smc_key first_key;
|
|
smc_key last_key;
|
|
|
|
struct blocking_notifier_head event_handlers;
|
|
|
|
struct apple_rtkit *rtk;
|
|
|
|
struct completion init_done;
|
|
enum apple_smc_boot_stage boot_stage;
|
|
|
|
struct resource *sram;
|
|
void __iomem *sram_base;
|
|
struct apple_rtkit_shmem shmem;
|
|
|
|
unsigned int msg_id;
|
|
|
|
bool atomic_mode;
|
|
bool atomic_pending;
|
|
struct completion cmd_done;
|
|
u64 cmd_ret;
|
|
|
|
struct mutex mutex;
|
|
spinlock_t lock;
|
|
};
|
|
|
|
/**
|
|
* apple_smc_read - Read size bytes from given SMC key into buf
|
|
* @smc: Pointer to apple_smc struct
|
|
* @key: smc_key to be read
|
|
* @buf: Buffer into which size bytes of data will be read from SMC
|
|
* @size: Number of bytes to be read into buf
|
|
*
|
|
* Return: Zero on success, negative errno on error
|
|
*/
|
|
int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size);
|
|
|
|
/**
|
|
* apple_smc_write - Write size bytes into given SMC key from buf
|
|
* @smc: Pointer to apple_smc struct
|
|
* @key: smc_key data will be written to
|
|
* @buf: Buffer from which size bytes of data will be written to SMC
|
|
* @size: Number of bytes to be written
|
|
*
|
|
* Return: Zero on success, negative errno on error
|
|
*/
|
|
int apple_smc_write(struct apple_smc *smc, smc_key key, const void *buf, size_t size);
|
|
|
|
/**
|
|
* apple_smc_enter_atomic - Enter atomic mode to be able to use apple_smc_write_atomic
|
|
* @smc: Pointer to apple_smc struct
|
|
*
|
|
* This function switches the SMC backend to atomic mode which allows the
|
|
* use of apple_smc_write_atomic while disabling *all* other functions.
|
|
* This is only used for shutdown/reboot which requires writing to a SMC
|
|
* key from atomic context.
|
|
*
|
|
* Return: Zero on success, negative errno on error
|
|
*/
|
|
int apple_smc_enter_atomic(struct apple_smc *smc);
|
|
|
|
/**
|
|
* apple_smc_write_atomic - Write size bytes into given SMC key from buf without sleeping
|
|
* @smc: Pointer to apple_smc struct
|
|
* @key: smc_key data will be written to
|
|
* @buf: Buffer from which size bytes of data will be written to SMC
|
|
* @size: Number of bytes to be written
|
|
*
|
|
* Note that this function will fail if apple_smc_enter_atomic hasn't been
|
|
* called before.
|
|
*
|
|
* Return: Zero on success, negative errno on error
|
|
*/
|
|
int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, const void *buf, size_t size);
|
|
|
|
/**
|
|
* apple_smc_rw - Write and then read using the given SMC key
|
|
* @smc: Pointer to apple_smc struct
|
|
* @key: smc_key data will be written to
|
|
* @wbuf: Buffer from which size bytes of data will be written to SMC
|
|
* @wsize: Number of bytes to be written
|
|
* @rbuf: Buffer to which size bytes of data will be read from SMC
|
|
* @rsize: Number of bytes to be read
|
|
*
|
|
* Return: Zero on success, negative errno on error
|
|
*/
|
|
int apple_smc_rw(struct apple_smc *smc, smc_key key, const void *wbuf, size_t wsize,
|
|
void *rbuf, size_t rsize);
|
|
|
|
/**
|
|
* apple_smc_get_key_by_index - Given an index return the corresponding SMC key
|
|
* @smc: Pointer to apple_smc struct
|
|
* @index: Index to be resolved
|
|
* @key: Buffer for SMC key to be returned
|
|
*
|
|
* Return: Zero on success, negative errno on error
|
|
*/
|
|
int apple_smc_get_key_by_index(struct apple_smc *smc, int index, smc_key *key);
|
|
|
|
/**
|
|
* apple_smc_get_key_info - Get key information from SMC
|
|
* @smc: Pointer to apple_smc struct
|
|
* @key: Key to acquire information for
|
|
* @info: Pointer to struct apple_smc_key_info which will be filled
|
|
*
|
|
* Return: Zero on success, negative errno on error
|
|
*/
|
|
int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_key_info *info);
|
|
|
|
/**
|
|
* apple_smc_key_exists - Check if the given SMC key exists
|
|
* @smc: Pointer to apple_smc struct
|
|
* @key: smc_key to be checked
|
|
*
|
|
* Return: True if the key exists, false otherwise
|
|
*/
|
|
static inline bool apple_smc_key_exists(struct apple_smc *smc, smc_key key)
|
|
{
|
|
return apple_smc_get_key_info(smc, key, NULL) >= 0;
|
|
}
|
|
|
|
#define APPLE_SMC_TYPE_OPS(type) \
|
|
static inline int apple_smc_read_##type(struct apple_smc *smc, smc_key key, type *p) \
|
|
{ \
|
|
int ret = apple_smc_read(smc, key, p, sizeof(*p)); \
|
|
return (ret < 0) ? ret : ((ret != sizeof(*p)) ? -EINVAL : 0); \
|
|
} \
|
|
static inline int apple_smc_write_##type(struct apple_smc *smc, smc_key key, type p) \
|
|
{ \
|
|
return apple_smc_write(smc, key, &p, sizeof(p)); \
|
|
} \
|
|
static inline int apple_smc_write_##type##_atomic(struct apple_smc *smc, smc_key key, type p) \
|
|
{ \
|
|
return apple_smc_write_atomic(smc, key, &p, sizeof(p)); \
|
|
} \
|
|
static inline int apple_smc_rw_##type(struct apple_smc *smc, smc_key key, \
|
|
type w, type *r) \
|
|
{ \
|
|
int ret = apple_smc_rw(smc, key, &w, sizeof(w), r, sizeof(*r)); \
|
|
return (ret < 0) ? ret : ((ret != sizeof(*r)) ? -EINVAL : 0); \
|
|
}
|
|
|
|
APPLE_SMC_TYPE_OPS(u64)
|
|
APPLE_SMC_TYPE_OPS(u32)
|
|
APPLE_SMC_TYPE_OPS(u16)
|
|
APPLE_SMC_TYPE_OPS(u8)
|
|
APPLE_SMC_TYPE_OPS(s64)
|
|
APPLE_SMC_TYPE_OPS(s32)
|
|
APPLE_SMC_TYPE_OPS(s16)
|
|
APPLE_SMC_TYPE_OPS(s8)
|
|
|
|
static inline int apple_smc_read_flag(struct apple_smc *smc, smc_key key, bool *flag)
|
|
{
|
|
u8 val;
|
|
int ret = apple_smc_read_u8(smc, key, &val);
|
|
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
*flag = val ? true : false;
|
|
return ret;
|
|
}
|
|
|
|
static inline int apple_smc_write_flag(struct apple_smc *smc, smc_key key, bool state)
|
|
{
|
|
return apple_smc_write_u8(smc, key, state ? 1 : 0);
|
|
}
|
|
|
|
static inline int apple_smc_write_flag_atomic(struct apple_smc *smc, smc_key key, bool state)
|
|
{
|
|
return apple_smc_write_u8_atomic(smc, key, state ? 1 : 0);
|
|
}
|
|
|
|
#endif
|