HW:SMC
The SMC is a piece of hardware handling access to such things as temperature sensors, voltage/power meters, battery status, fan status, and the LCD backlight and lid switch.
It is “documented”, to the extent that it is, in https://github.com/corellium/linux-m1/blob/master/drivers/hwmon/apple-m1-smc.c, but that’s just the protocol, which essentially allows you to do three things:
-
read data for each of many, many four-ASCII-character “keys”. There are about 1,400 such keys on the MacBook Pro.
-
read data for a key, supplying a payload.
-
write data for a key.
In addition to receiving the bytes of data, the SMC provides a type for that data, encoded as four ASCII characters, and a flags byte.
So far, I haven’t been brave enough to try (2) or (3).
Encoded as four ASCII characters, the last of which I omit if it’s a space.
flt
: a 32-bit single-precision IEEE float. In at least one case, the byte order is actually reversed.si8
,ui8
,si16
,ui16
,si32
,ui32
,si64
,ui64
: signed/unsigned 8-/16-/32-/64-bit valueshex_
: random binary dataflag
: 1 or 0ioft
: this appears to be a 64-bit unsigned fixed-point value (48.16, most likely).ch8*
: ASCII string{jst
: unknown. Possibly some sort of binary-encoded structured document?
Almost totally unknown. Keys with 0xf0
flags don’t appear to return non-zero values reliably (see Quirks).
Many. https://github.com/torvalds/linux/blob/master/drivers/hwmon/applesmc.c documents some, but mostly you have to guess based on the four-character name. There are more than 1,400 such keys on the MacBook Pro, with many apparently unused.
Some guesses as to what they might mean:
T???
: temperature values, in Celsius, as float. There are many of those. The question marks specify, presumably, the location (and possibly whether or not the value is averaged to provide a more meaningful reading?)TB0T
: battery temperatureTCHP
: charger temperature (increases sligtly when charging)TW0P
: wireless temperature (increases slightly when wireless is turned on)Ts0P
: palm rest temperatureTs1P
: palm rest temperatureV???
: voltages. Probably in volts.gP??
: “GPIO” pins. Actually output only, and there appears to be a bug preventing you from reading the level of a pin non-destructively, except it works for the very first such pin to be read.gP0d
: controls the WiFi/BT chips. Without enabling this, the PCI devices for WiFi and BT don’t show up. Used to implement “rfkill” functionality?gP12
: on at least one system, the LCD backlight. Can be turned off, which reduces apparent power consumption, and turned back on.gp??
(note capitalization): presumably also some kind of GPIO pin?D1??
: information about the device connected to the first USB-C portD1in
: name of the connected chargerD1is
: serial number of the connected chargerD2??
: refer toD1??
P???
: power meters, presumably in wattsPSTR
: entire system’s power consumption in WSBA?
: system battery informationSBA1
: battery cell 1 voltage in mVSBA2
: battery cell 2 voltage in mVSBA3
: battery cell 3 voltage in mVSBAV
: battery voltage in mV (sum ofSBA1
,SBA2
andSBA3
, same asB0AV
but as aflt
)SBAR
: battery remaining capacity in mAh (same asB0RM
but as aflt
)SBAS
: battery charge in percent (same asBRSC
but as aflt
)RPlt
: platform name, such as “J293”.a???
: highly volatile power-related measurement, so possibly current going to various device parts.F???
: fan information. Refer to https://github.com/torvalds/linux/blob/master/drivers/hwmon/applesmc.c.CL??
: various times, measured in microseconds since (possibly) manufacturing/RTC reset timeCLKU
: continuously-updated current timeCLBT
: SMC boot time (e.g. AC power applied)CLSP
: possibly the time the SMC last went to sleepCLWK
: possibly the time the SMC last woke upMSLD
: the lid switch, 1 for closed, 0 for openbHLD
: power button currently pressedMBSe
: power button pressed since last read, read-to-clearB0CT
: battery charge cycle countB0AV
: battery voltage in mV (same asSBAV
but as ansi16
)BRSC
: battery charge in percent (same asSBAS
but as aui16
)B0DC
: battery design capacity in mAhB0FC
: battery full capacity in mAhB0RM
: battery remaining capacity in mAh (same asSBAR
but as aui16
in reverse byte order)B0TE
: battery time-to-empty in minutesB0TF
: battery time-to-full in minutesID0R
: input current in AVD0R
: input voltage in VPDTR
: input power in W
Or possibly quirks?
#KEY
: contains the number of keys in the SMC, but in reversed byte order.VP3b
: apparently byte-reversedgP??
: latched in a weird way: the first time one of these keys is read, the data indicates the pin’s power status. But reading any of the keys afterwards returns0
, except after a write to one of them, which allows you to read data once more (but just once), for any of the pins. So you can read all pins by repeatedly writing 1 to a pin you know to be at high level, then reading the other pin levels one by one. Reading with a payload of 0xffffffff or 0x00000001 returns the right value.rLD0
etc. cannot be read normally, but can be read with a 0x00000001 or 0x00ffffff payload. Maybe that’s related to the “flags” byte being 0xf0.
Setting the “NTAP” (notify application processor, maybe?) flag to 1 makes the SMC send notifications when certain system events happen, such as power being connected and disconnected, the power button being pressed, or the lid being opened or closed. Notifications are mailbox messages apparently limited to the 64-bit payload.
In addition to the keys accessible “directly” through the SMC, there is what appears to be a muxed single-channel ADC providing access to 111 further values. It is accessed through “aDC#” (giving the number of keys), “aDC?” (query key name using a numeric payload), and “aDCR”, the actual result value.