/* 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 32 bit integers containing packed ASCII characters in natural
* integer order , i . e . 0 xAABBCCDD , 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 64 bit 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
* 0 x4e544150 .
*
* @ 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 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 : 64 bit 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, 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, 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, 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
Messung V0.5 in Prozent C=95 H=100 G=97
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet am 2026-09-27)
¤
*© Formatika GbR, Deutschland