Skip to content

Add reset and UART VDM support to tipd #399

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 330 commits into
base: asahi
Choose a base branch
from

Conversation

martinyrm
Copy link

This patch adds macvdmtool-like functionality to tipd, supporting target reboot and target+local UART over USB-C (SBU mux)

Two new sysfs entries are created: /sys/class/typec/portX/device/cd321x_vdm/reboot and /sys/class/typec/portX/device/cd321x_vdm/serial

Writing to reboot sends a VDM that resets the connected device (tested by myself on M1 MBA J313AP)

Writing to serial first sends a VDM that causes the target device to enter UART mode and then puts the local CD321x device into UART mode - enabling serial communication between two M1 machines
(many thanks to chaos_princess who tested this successfully with a M1 Pro J314s as the host machine).

asahilina and others added 30 commits April 25, 2025 19:20
The missing SAFETY comments should be fixed later...

Signed-off-by: Asahi Lina <lina@asahilina.net>
The missing SAFETY comments should be fixed later...

Signed-off-by: Asahi Lina <lina@asahilina.net>
The missing SAFETY comments should be fixed later...

Signed-off-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Asahi Lina <lina@asahilina.net>
Previously imported through "*RFL import: kernel::platform".

Signed-off-by: Janne Grunau <j@jannau.net>
Required by the asahi driver for its driver data.

Signed-off-by: Janne Grunau <j@jannau.net>
Adapted from
*RFL import: kernel::io_mem

Commit reference: 3dfc5eb

Signed-off-by: Janne Grunau <j@jannau.net>
Signed-off-by: Sasha Finkelstein <fnkl.kernel@gmail.com>
Signed-off-by: Janne Grunau <j@jannau.net>
DMA fences are the internal synchronization primitive used for DMA
operations like GPU rendering, video en/decoding, etc. Add an
abstraction to allow Rust drivers to interact with this subsystem.

Note: This uses a raw spinlock living next to the fence, since we do
not interact with it other than for initialization.
TODO: Expose this to the user at some point with a safe abstraction.

Signed-off-by: Asahi Lina <lina@asahilina.net>
DRM drivers need to be able to declare which driver-specific ioctls they
support. Add an abstraction implementing the required types and a helper
macro to generate the ioctl definition inside the DRM driver.

Note that this macro is not usable until further bits of the abstraction
are in place (but it will not fail to compile on its own, if not called).

Signed-off-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Implement the DRM driver abstractions.

The `Driver` trait provides the interface to the actual driver to fill
in the driver specific data, such as the `DriverInfo`, driver features
and IOCTLs.

Co-developed-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Implement the abstraction for a `struct drm_device`.

A `drm::device::Device` creates a static const `struct drm_driver` filled
with the data from the `drm::drv::Driver` trait implementation of the
actual driver creating the `drm::device::Device`.

Co-developed-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Implement the DRM driver `Registration`.

The `Registration` structure is responsible to register and unregister a
DRM driver. It makes use of the `Devres` container in order to allow the
`Registration` to be owned by devres, such that it is automatically
dropped (and the DRM driver unregistered) once the parent device is
unbound.

Co-developed-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
A DRM File is the DRM counterpart to a kernel file structure,
representing an open DRM file descriptor. Add a Rust abstraction to
allow drivers to implement their own File types that implement the
DriverFile trait.

Signed-off-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
The DRM GEM subsystem is the DRM memory management subsystem used by
most modern drivers. Add a Rust abstraction to allow Rust DRM driver
implementations to use it.

Signed-off-by: Asahi Lina <lina@asahilina.net>
Co-developed-by: Danilo Krummrich <dakr@redhat.com>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Since commit 21aa27d ("drm/shmem-helper: Switch to reservation
lock"), the drm_gem_shmem_vmap and drm_gem_shmem_vunmap functions
require that the caller holds the DMA reservation lock for the object.
Add lockdep assertions to help validate this.

Signed-off-by: Asahi Lina <lina@asahilina.net>
There doesn't seem to be a way for the Rust bindings to get a
compile-time constant reference to drm_gem_shmem_vm_ops, so we need to
duplicate that structure in Rust... this isn't nice...

Signed-off-by: Asahi Lina <lina@asahilina.net>
This is just for basic usage in the DRM shmem abstractions for implied
locking, not intended as a full DMA Reservation abstraction yet.

Signed-off-by: Asahi Lina <lina@asahilina.net>
The DRM shmem helper includes common code useful for drivers which
allocate GEM objects as anonymous shmem. Add a Rust abstraction for
this. Drivers can choose the raw GEM implementation or the shmem layer,
depending on their needs.

Signed-off-by: Asahi Lina <lina@asahilina.net>
Drivers may want to support driver-private objects, which cannot be
shared. This allows them to share a single lock and enables other
optimizations.

Add an `exportable` field to drm_gem_object, which blocks PRIME export
if set to false. It is initialized to true in
drm_gem_private_object_init.

Signed-off-by: Asahi Lina <lina@asahilina.net>
This allows drivers to control whether a given GEM object is allowed to
be exported via PRIME to other drivers.
Allow a GEM object to share another object's DMA reservation, for use
with drm_gpuvm. To keep memory safety, we hold a reference to the GEM
object owning the resv, and drop it when the child object is freed.

Signed-off-by: Asahi Lina <lina@asahilina.net>
drm_mm provides a simple range allocator, useful for managing virtual
address ranges. Add a Rust abstraction to expose this module to Rust
drivers.

Signed-off-by: Asahi Lina <lina@asahilina.net>
DRM Sync Objects are a container for a DMA fence, and can be waited on
signaled, exported, and imported from userspace. Add a Rust abstraction
so Rust DRM drivers can support this functionality.

Signed-off-by: Asahi Lina <lina@asahilina.net>
Used by Apple SEP driver.

Signed-off-by: Sasha Finkelstein <fnkl.kernel@gmail.com>
A signaled scheduler fence can outlive its scheduler, since fences are
independencly reference counted. Therefore, we can't reference the
scheduler in the get_timeline_name() implementation.

Fixes oopses on `cat /sys/kernel/debug/dma_buf/bufinfo` when shared
dma-bufs reference fences from GPU schedulers that no longer exist.

Signed-off-by: Asahi Lina <lina@asahilina.net>
The GPU scheduler manages scheduling GPU jobs and dependencies between
them. This Rust abstraction allows Rust DRM drivers to use this
functionality.

Signed-off-by: Asahi Lina <lina@asahilina.net>
drm_sched_fini() currently leaves any pending jobs dangling, which
causes segfaults and other badness when job completion fences are
signaled after the scheduler is torn down.

Explicitly detach all jobs from their completion callbacks and free
them. This makes it possible to write a sensible safe abstraction for
drm_sched, without having to externally duplicate the tracking of
in-flight jobs.

This shouldn't regress any existing drivers, since calling
drm_sched_fini() with any pending jobs is broken and this change should
be a no-op if there are no pending jobs.

Signed-off-by: Asahi Lina <lina@asahilina.net>
Fixes build error after Box -> KBox conversion.

Signed-off-by: Janne Grunau <j@jannau.net>
Analogous to drm_gpuvm_bo_unmap_ops_create, this is a callback-driven
unmap function for a given BO.

Signed-off-by: Asahi Lina <lina@asahilina.net>
jannau and others added 19 commits May 9, 2025 22:04
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
SMC most certainly does not return linux errno values as result. The
return value of 132 for missing SMC keys does not make sense as ERFKILL.

Signed-off-by: Janne Grunau <j@jannau.net>
The SMC firmware in macOS 15.4 dropped "AC-i" and "AC-n" (and all keys
with lower case last letter) without obvious replacement. Stop reporting
VOLTAGE_NOW / INPUT_CURRENT_LIMIT if "AC-n" is not present.

Signed-off-by: Janne Grunau <j@jannau.net>
Adds two new sysfs entries:  /sys/class/typec/portX/device/cd321x_vdm/reboot and /sys/class/typec/portX/device/cd321x_vdm/serial
Writing to reboot resets the connected device 
Writing to serial muxes  UART over SBU for both the target and local machines (/dev/ttySACy)






Signed-off-by: Martin R <me@martinyr.com>
dev_err(tps->dev, "Failed reading device tree");
return -EINVAL;
}
else {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please run it through b4 check, or checkpatch.pl. Kernel has a very specific code formatting style

key = cd321x_get_key(tps);

if (key < 0) {
dev_err(tps->dev, "Could not fetch device unlock key");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would end up with two error messages, no?


if (ret) {
dev_err(tps->dev, "Unlock command failed or device is already unlocked");
dev_err(tps->dev, "%d", ret);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please merge with the line above

int ret;
int mode;

ret = tps6598x_exec_cmd(tps, "DBMa", 1, "\x01", 0, NULL);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error not checked

@@ -1437,6 +1608,14 @@ static int tps6598x_probe(struct i2c_client *client)
enable_irq_wake(client->irq);
}

if (device_is_compatible(tps->dev, "apple,cd321x")) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a "apple_vdm" or something flag to tipd_data, set it to true only in cd321x_data, and use that to decide if the sysfs group should be created

};

static const struct attribute_group vdm_group = {
.name = "cd321x_vdm",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe apple_vdm? Apple also has ACE3 which seems to be the same chip, but over spmi instead of i2c.


u32 vdm[] = {0x5ac8012, 0x1840306};

cd321x_unlock(tps);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No error checking

struct tps6598x *tps = i2c_get_clientdata(client);

u32 vdm[] = {0x5ac8012, 0x105, 0x80000000};
cd321x_unlock(tps);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No error checking

u8 vdm[13];
u8 header = 0x33;

memcpy(&vdm[0], &header, 1);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for a memcpy, just do vdm[0] = header

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, and header should probably be a #define constant

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants