pub/scm/linux/kernel/git/maz/cs-sw.git  about / heads / tags
Central Scritinizer gadget firmware
$ git log --pretty=format:'%h %s (%cs)%d'
7baed05 Add reset watchdog (2024-04-17)
	(HEAD -> master)
a234634 Add install target (2024-03-02)
0e129aa README: Add blurb about enabling the UART on the Mac (2023-11-24)
1039ad6 Reinstate "Don't measure CC lines twice" (2023-11-06)
d3d964d Revert "Don't measure CC lines twice" (2023-10-26)
def6319 Display FUSB302 ID register on probe failure (2023-10-22)
7553cdb Add README.txt link (2023-10-22)
c8a9d96 Only advertise a single CDC for single board configurations (2023-10-22)
9a1c099 Add macos nuild information (2023-10-15)
6380214 Let's state the obvious... (2023-10-04)

$ git cat-file blob HEAD:README
"This is the Central Scrutinizer"

So you have built (or otherwise obtained) a device labelled "Central
Scrutinizer" which allows you interact with the serial port of a M1/M2
and reboot it.

Otherwise, you can look at
for the hardware side of the project. Everything in this file
assumes that the board is assembled and functionnal.

This file describe how to build the software and flash it onto the
Raspberry-Pi Pico that controls the adapter. As for the HW, the SW
started its life as m1-ubmc, but let's be clear that its name really
is "Central Scrutinizer" so that you too can channel your inner FZ.

But first, credit where credit is due: this software is not an
original work, but is built on top of code which is:

  Copyright (c) 2014 The Chromium OS Authors
  Copyright (c) 2018 Reclaimer Labs -
  Copyright (c) 2020 The Asahi Linux Contributors

See the LICENSE file for the fine print.

** Install the pre-requisites

On a Debian system, this is what you need:

  sudo apt install cmake gcc-arm-none-eabi build-essential git

I'm sure there is an equivalent for other OSs, but life is too short
to use anything else.

On macos:

Kacper reports that you need to use the gcc-arm-embedded instead of
arm-none-gcc-eabi if compiling on macos. This looks like a packaging
problem (see

** Build the Pico firmware:

I'm now relying on git submodules for the Pico SDK, currently 1.5.1.

  git clone git://

  cd cs-sw

  [optionally checkout the dev branch you want]

  git submodule update --init --recursive

  [this will download a fsckload of useless things... oh well]

  mkdir build

  cd build

  cmake ..


You should end-up with a file called m1_ubmc.uf2 in the build
directory. If you don't, something is wrong. Finding what is wrong is
your responsibility, not mine! ;-)

** Flash it

Place the Pico in programming mode by pressing the BOOTROM button
while plugging the USB connector, and issue something along the lines

  sudo mount /dev/disk/by-id/usb-RPI_RP2_E0C9125B0D9B-0\:0-part1 /mnt

  sudo cp m1_ubmc.uf2 /mnt

  sudo eject /mnt

** Plug it
You will need a cable that contains most (if not all) of the USB-C
wires, and crucially the SBU signals. Cheap cables won't carry them,
but you won't find out until you actually try them.

You really want something that looks thick and stiff, and flimsy
cables are unlikely to work (the cable that ships with M1 laptops
doesn't). None of my cables labelled USB2.0 seem to work. I've had
good results with cables designed to carry video signals, and USB3.1
cables seem to do the trick.

If you are stuck with a USB2.0 cable that doesn't have the SBU1/2
signals, there is still a way to get a serial console by using the
USB2.0 lines if you have a v2 or later:

  - v2: you can connect SBU1 to USB_TX and SBU2 to USB_RX, which is
    only a matter of linking two sets of pins next to the micro-USB
    connector. In such a configuration, *DO NOT USE* the micro-USB
    connector *AT ALL* (put some tape or glue on it).  If you don't
    know how to perform this change, please don't try. You can then
    instruct the firmware to claim these pins instead of the SBU pins.

  - v3+: switching the serial lines is fully under SW control, and you
    can dynamically switch between the two configurations. Better use
    a proper SBU capable cable though, as you otherwise lose the USB
    passthrough capability.

Other oddities: because I'm lazy, the v0/v1 hardware only connects a
single CC line to the board's PD controller, and there is no provision
to swap TX and RX.  Which means that on the board side, there is only
a single valid orientation for the USB-C cable. Trial and error are,
as usual, your best friends. Put a label on the board's end of the
cable as an indication of the orientation. v2 and later boards have
the required logic to detect the orientation and swap the SBU pins,
making them easier to use.

Also, there is only *ONE* USB-C port that is capable of serial
output. The device will happily connect to others, and allow things
like rebooting the Mac, but you won't get any serial output. Please
use the correct port.

Models I know of:
- M1 mini 2020: USB-C port closest to the power supply
- M1 Ultra 2022: USB-C port closest to the Ethernet port
- M2 MacBook Air 2022: USB-C port closest to the MagSafe port
- M2 Pro mini 2023: USB-C port closest to the Ethernet port (Oliver)

Apple documents the correct port in their "Revive or restore a Mac
using Apple Configurator":

On desktop devices it is usually the port closest to the power supply.
On laptops it is the USB-C port on the back left side.

Optionally, you can make use of the micro-USB connector that is on
the other side of the board. It's main use it to allow interacting
with the Asahi m1n1 firmware, such as tethered booting. Do not connect
it to anything if you use the USB2.0 lines as the serial console.

Finally, the Pico itself must be connected to a host machine that
will drive it as a serial port as well as provide power for the whole
contraption. It should be obvious, but maybe it is better stating it.

** Use it

If you have correctly built and flashed the firmware, you will have
the Pico led blinking at the rate of twice a second, and one or two
/dev/ttyACM* devices being advertised by your host:

  [708023.097129] usb 1-4: new full-speed USB device number 72 using xhci_hcd
  [708023.265195] usb 1-4: New USB device found, idVendor=2e8a, idProduct=000a, bcdDevice= 1.00
  [708023.265213] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
  [708023.265219] usb 1-4: Product: Central Scrutinizer
  [708023.265223] usb 1-4: Manufacturer: AAAFNRAA
  [708023.265228] usb 1-4: SerialNumber: E66164084319392A
  [708023.273622] cdc_acm 1-4:1.0: ttyACM0: USB ACM device
  [708023.278612] cdc_acm 1-4:1.2: ttyACM1: USB ACM device

The board identifies itself as a Pico (as per VID/PID), and claims to
be the Central Scrutinizer, as you were hoping for.

Each of the two /dev/ttyACM* devices is a potential connection to a
Mac. Assuming the likely case that you have a single CS board attached
to the Pico, run:

  screen /dev/ttyACM0

and you should see something like:

  This is the Central Scrutinizer
  Control character is ^_
  Press ^_ + ? for help
  P0: Probing port 0
  P0: Device ID: B_revB (0x91)
  P0: Init
  P0: STATUS0: 0x80
  P0: Disconnected
  P0: Connected: cc1=2 cc2=1
  P0: Polarity: CC1 (normal)
  P0: VCONN on CC2
  P0: >VDM serial -> SBU1/2
  P0: <VDM RX SOP"DEBUG (5) [508f] 5ac8052 44740000 306 0 0

If you see the ">VDM serial -> SBU1/2" line, the serial line should
now be connected and you can interact with the M1. Note that you can
use any serial configuration you want on the Mac side as long as it is
115200n8. One day I may implement the required controls, but that's
super low priority on the list of things I want to do. Also, there is
no such list, and the current setup works well enough for me.

Replace "screen" with whatever you want to communicate with the
device, be it conserver, minicom, cu, or even cat (there is no
accounting for taste).

Typing ^_? (Control-Underscore followed by a question mark) will lead
to the follwing dump:

  P0: Current port
  ^_    Escape character
  ^_ ^_ Raw ^_
  ^_ !  DUT reset
  ^_ ^R Central Scrutinizer reset
  ^_ ^^ Central Scrutinizer reset to programming mode
  ^_ ^X Force disconnect
  ^_ ^D Toggle debug
  ^_ ^M Send empty debug VDM
  ^_ 1  Serial on Primary USB pins
  ^_ 2  Serial on SBU pins
  ^_ ?  This message
  P0: Port 0: present,cc1,SBU1/2
  P0: Port 1: absent

which is completely self explainatory, but let's expand on it anyway:

- ^_ ^_ sends a raw ^_, just in case you really need it

- ^_ ! resets the Mac without any warning. Yes, this is dangerous, use
  with caution and only when nothing else will do.

- ^_ ^R reboots the Central Scrutinizer itself. Not very useful, except
  when it is.

- ^_ ^^ reboots the Central Scrutinizer in programming mode, exactly
  as if you had plugged it with the BOOTROM button pressed. You end-up
  in mass-storage mode and can update the firmware.

- ^_ ^X forces a PD disconnection, in case either the CS or the Mac
  becomes a bit confused. It was useful a couple of times in debugging

- ^_ ^D toggles the "debug" internal flag. This has very little effect
  at the moment as most of the debug statements ignore the flag and
  spit out the junk on the console unconditionally.

- ^_ ^M sends an empty debug message to the remote PD controller.
  That's a debug feature...

- ^_ 1  Configure the Mac's serial on Primary USB pins. On v3+, this
  also isolates the micro-USB connector. On older versions, it
  doesn't, so make sure you don't have anything plugged there.

- ^_ 2 Configure the Mac's serial on SBU pins, which is the default.
  On v3+, this enables the use of the micro-USB connector.

- ^_ ^\ crashes the Central Scrutinizer when in debug mode. This
  allows testing the watchdog reset functionnality.

- ^_ ? prints the help message (duh).

Finally, the Port 0:/1: lines indicate which I2C/UART combinations the
board is using, as well as the CC line used, the pin set used for
serial, and potentially the debug status. The HW supports two boards
being driven by a single Pico (see the HW documentation for the gory

** Software configuration on the Mac itself

It is all good to have a serial port, something needs to interact with
it on the Mac as well.

- As far as I understand, MacOS doesn't directly provide a driver for
  the UART. It is apparently possible to enable it, but I can't help
  you with that.

- If running m1n1 (the Asahi low-level firmware), you should see some
  output from it.

- If running u-boot, you need to configure it to actually output to
  the UART. Please refer to the M1-specific u-boot documentation on
  how to enable the debug UART.

None of the above should be too hard if you are used to any sort of
low-level debugging, which should be the case if using a CS board.  Do
remember that 115200n8 is the one true configuration that the CS
firmware supports, though.

# heads (aka `branches'):
$ git for-each-ref --sort=-creatordate refs/heads \
	--format='%(HEAD) %(refname:short) %(subject) (%(creatordate:short))'
* master       Add reset watchdog (2024-04-17)
  v3-dev       Don't wait for a USB connection if detecting a RS232 adapter (2023-09-06)
  pin-sets     Allow selection of Primary USB as the serial pin set (2023-04-10)
  cdc-break    Move break handling over to CDC (2023-04-10)
  dual-port    README update (2023-04-02)

# tags:
$ git for-each-ref --sort=-creatordate refs/tags \
	--format='%(refname:short) %(subject) (%(creatordate:short))'
initdrop     Initial drop (2023-11-20) tar.gz

# associated public inboxes:
# (number on the left is used for dev purposes)
          1 lkml
          1 qemu-devel
          1 linux-cifs
          1 netdev
          1 util-linux

git clone