Add smc.py script to enable radios

Add a basic SMC client and a script in experiments/ using it to enable
the radios. Running this before booting Linux will make the network
controller devices show up in lspci, even if Linux lacks an SMC driver.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
Alyssa Rosenzweig 2021-10-02 17:59:47 -04:00 committed by Hector Martin
parent 925215aea2
commit 8010e38376
2 changed files with 120 additions and 0 deletions

View file

@ -0,0 +1,31 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
import sys, pathlib
import time
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
import struct
from m1n1.setup import *
from m1n1.fw.smc import SMCClient
smc_addr = u.adt["arm-io/smc"].get_reg(0)[0]
smc = SMCClient(u, smc_addr)
smc.start()
smc.start_ep(0x20)
smcep = smc.epmap[0x20]
def fourcc_key(fourcc):
assert(len(fourcc) == 4)
return sum([ord(x) << (8 * (3 - i)) for i, x in enumerate(fourcc)])
def gpio_key(pin):
assert(pin < (1 << 16))
fourcc = 'gP' + ('00'+(hex(pin)[2:]))[-2:]
return fourcc_key(fourcc)
# Enable wifi/bluetooth
RFKILL_PIN = 13
smcep.write_key(gpio_key(RFKILL_PIN), struct.pack('<I', 0x800000 | 0x0))
smcep.write_key(gpio_key(RFKILL_PIN), struct.pack('<I', 0x800000 | 0x1))

View file

@ -0,0 +1,89 @@
# SPDX-License-Identifier: MIT
import struct
from ..utils import *
from .asc import StandardASC
from .asc.base import *
SMC_READ_KEY = 0x10
SMC_WRITE_KEY = 0x11
SMC_GET_KEY_BY_INDEX = 0x12
SMC_GET_KEY_INFO = 0x13
SMC_GET_SRAM_ADDR = 0x17
SMC_NOTIFICATION = 0x18
SMC_READ_KEY_PAYLOAD = 0x20
class SMCGetSRAMAddr(Register64):
TYPE = 8, 0, Constant(0x17)
ID = 16, 12
class SMCWriteKey(Register64):
TYPE = 8, 0, Constant(0x11)
ID = 16, 12
SIZE = 32, 16
KEY = 64, 32
class SMCMessage(Register64):
TYPE = 0, 0
VALUE = 64, 0
class SMCMessage(Register64):
TYPE = 8, 0
ID = 16, 12
HPARAM = 32, 16
WPARAM = 64, 32
class SMCEndpoint(ASCBaseEndpoint):
BASE_MESSAGE = SMCMessage
SHORT = "smcep"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.shmem = None
self.msgid = 0
self.outstanding = set()
def start(self):
self.send(SMCGetSRAMAddr(ID = self.new_msgid()))
while self.shmem is None:
self.asc.work()
def new_msgid(self):
mid = (self.msgid & 0xF)
self.msgid += 1
assert(mid not in self.outstanding)
self.outstanding.add(mid)
return mid
def write_key(self, key, data):
print(self.shmem, key, data, len(data))
self.asc.iface.writemem(self.shmem, data)
ID = self.new_msgid()
self.send(SMCWriteKey(ID = ID, KEY = key, SIZE = len(data)))
while ID in self.outstanding:
self.asc.work()
return True
@msg_handler(0x00, SMCMessage)
def Startup(self, msg):
self.log(hex(msg.value))
if self.shmem is None:
self.log("Starting up")
self.shmem = msg.value
else:
ret = msg.value & 0xFF
mid = (msg.value >> 12) & 0xF
print(f"msg {mid} return value {ret}")
self.outstanding.discard(mid)
return True
class SMCClient(StandardASC):
pass
ENDPOINTS = {
0x20: SMCEndpoint,
}