1*057d44b0SMatthew Maurer // SPDX-License-Identifier: GPL-2.0 2*057d44b0SMatthew Maurer 3*057d44b0SMatthew Maurer // Copyright (C) 2025 Google LLC. 4*057d44b0SMatthew Maurer 5*057d44b0SMatthew Maurer //! SoC Driver Abstraction. 6*057d44b0SMatthew Maurer //! 7*057d44b0SMatthew Maurer //! C header: [`include/linux/sys_soc.h`](srctree/include/linux/sys_soc.h) 8*057d44b0SMatthew Maurer 9*057d44b0SMatthew Maurer use crate::{ 10*057d44b0SMatthew Maurer bindings, 11*057d44b0SMatthew Maurer error, 12*057d44b0SMatthew Maurer prelude::*, 13*057d44b0SMatthew Maurer str::CString, 14*057d44b0SMatthew Maurer types::Opaque, // 15*057d44b0SMatthew Maurer }; 16*057d44b0SMatthew Maurer use core::ptr::NonNull; 17*057d44b0SMatthew Maurer 18*057d44b0SMatthew Maurer /// Attributes for a SoC device. 19*057d44b0SMatthew Maurer /// 20*057d44b0SMatthew Maurer /// These are both exported to userspace under /sys/devices/socX and provided to other drivers to 21*057d44b0SMatthew Maurer /// match against via `soc_device_match` (not yet available in Rust) to enable quirks or 22*057d44b0SMatthew Maurer /// device-specific support where necessary. 23*057d44b0SMatthew Maurer /// 24*057d44b0SMatthew Maurer /// All fields are freeform - they have no specific formatting, just defined meanings. 25*057d44b0SMatthew Maurer /// For example, the [`machine`](`Attributes::machine`) field could be "DB8500" or 26*057d44b0SMatthew Maurer /// "Qualcomm Technologies, Inc. SM8560 HDK", but regardless it should identify a board or product. 27*057d44b0SMatthew Maurer pub struct Attributes { 28*057d44b0SMatthew Maurer /// Should generally be a board ID or product ID. Examples 29*057d44b0SMatthew Maurer /// include DB8500 (ST-Ericsson) or "Qualcomm Technologies, inc. SM8560 HDK". 30*057d44b0SMatthew Maurer /// 31*057d44b0SMatthew Maurer /// If this field is not populated, the SoC infrastructure will try to populate it from 32*057d44b0SMatthew Maurer /// `/model` in the device tree. 33*057d44b0SMatthew Maurer pub machine: Option<CString>, 34*057d44b0SMatthew Maurer /// The broader class this SoC belongs to. Examples include ux500 35*057d44b0SMatthew Maurer /// (for DB8500) or Snapdragon (for SM8650). 36*057d44b0SMatthew Maurer /// 37*057d44b0SMatthew Maurer /// On chips with ARM firmware supporting SMCCC v1.2+, this may be a JEDEC JEP106 manufacturer 38*057d44b0SMatthew Maurer /// identification. 39*057d44b0SMatthew Maurer pub family: Option<CString>, 40*057d44b0SMatthew Maurer /// The manufacturing revision of the part. Frequently this is MAJOR.MINOR, but not always. 41*057d44b0SMatthew Maurer pub revision: Option<CString>, 42*057d44b0SMatthew Maurer /// Serial Number - uniquely identifies a specific SoC. If present, should be unique (buying a 43*057d44b0SMatthew Maurer /// replacement part should change it if present). This field cannot be matched on and is 44*057d44b0SMatthew Maurer /// solely present to export through /sys. 45*057d44b0SMatthew Maurer pub serial_number: Option<CString>, 46*057d44b0SMatthew Maurer /// SoC ID - identifies a specific SoC kind in question, sometimes more specifically than 47*057d44b0SMatthew Maurer /// `machine` if the same SoC is used in multiple products. Some devices use this to specify a 48*057d44b0SMatthew Maurer /// SoC name, e.g. "I.MX??", and others just print an ID number (e.g. Tegra and Qualcomm). 49*057d44b0SMatthew Maurer /// 50*057d44b0SMatthew Maurer /// On chips with ARM firmware supporting SMCCC v1.2+, this may be a JEDEC JEP106 manufacturer 51*057d44b0SMatthew Maurer /// identification (the family value) followed by a colon and then a 4-digit ID value. 52*057d44b0SMatthew Maurer pub soc_id: Option<CString>, 53*057d44b0SMatthew Maurer } 54*057d44b0SMatthew Maurer 55*057d44b0SMatthew Maurer struct BuiltAttributes { 56*057d44b0SMatthew Maurer // While `inner` has pointers to `_backing`, it is to the interior of the `CStrings`, not 57*057d44b0SMatthew Maurer // `backing` itself, so it does not need to be pinned. 58*057d44b0SMatthew Maurer _backing: Attributes, 59*057d44b0SMatthew Maurer // `Opaque` makes us `!Unpin`, as the registration holds a pointer to `inner` when used. 60*057d44b0SMatthew Maurer inner: Opaque<bindings::soc_device_attribute>, 61*057d44b0SMatthew Maurer } 62*057d44b0SMatthew Maurer 63*057d44b0SMatthew Maurer fn cstring_to_c(mcs: &Option<CString>) -> *const kernel::ffi::c_char { 64*057d44b0SMatthew Maurer mcs.as_ref() 65*057d44b0SMatthew Maurer .map(|cs| cs.as_char_ptr()) 66*057d44b0SMatthew Maurer .unwrap_or(core::ptr::null()) 67*057d44b0SMatthew Maurer } 68*057d44b0SMatthew Maurer 69*057d44b0SMatthew Maurer impl BuiltAttributes { 70*057d44b0SMatthew Maurer fn as_mut_ptr(&self) -> *mut bindings::soc_device_attribute { 71*057d44b0SMatthew Maurer self.inner.get() 72*057d44b0SMatthew Maurer } 73*057d44b0SMatthew Maurer } 74*057d44b0SMatthew Maurer 75*057d44b0SMatthew Maurer impl Attributes { 76*057d44b0SMatthew Maurer fn build(self) -> BuiltAttributes { 77*057d44b0SMatthew Maurer BuiltAttributes { 78*057d44b0SMatthew Maurer inner: Opaque::new(bindings::soc_device_attribute { 79*057d44b0SMatthew Maurer machine: cstring_to_c(&self.machine), 80*057d44b0SMatthew Maurer family: cstring_to_c(&self.family), 81*057d44b0SMatthew Maurer revision: cstring_to_c(&self.revision), 82*057d44b0SMatthew Maurer serial_number: cstring_to_c(&self.serial_number), 83*057d44b0SMatthew Maurer soc_id: cstring_to_c(&self.soc_id), 84*057d44b0SMatthew Maurer data: core::ptr::null(), 85*057d44b0SMatthew Maurer custom_attr_group: core::ptr::null(), 86*057d44b0SMatthew Maurer }), 87*057d44b0SMatthew Maurer _backing: self, 88*057d44b0SMatthew Maurer } 89*057d44b0SMatthew Maurer } 90*057d44b0SMatthew Maurer } 91*057d44b0SMatthew Maurer 92*057d44b0SMatthew Maurer #[pin_data(PinnedDrop)] 93*057d44b0SMatthew Maurer /// Registration handle for your soc_dev. If you let it go out of scope, your soc_dev will be 94*057d44b0SMatthew Maurer /// unregistered. 95*057d44b0SMatthew Maurer pub struct Registration { 96*057d44b0SMatthew Maurer #[pin] 97*057d44b0SMatthew Maurer attr: BuiltAttributes, 98*057d44b0SMatthew Maurer soc_dev: NonNull<bindings::soc_device>, 99*057d44b0SMatthew Maurer } 100*057d44b0SMatthew Maurer 101*057d44b0SMatthew Maurer // SAFETY: We provide no operations through `&Registration`. 102*057d44b0SMatthew Maurer unsafe impl Sync for Registration {} 103*057d44b0SMatthew Maurer 104*057d44b0SMatthew Maurer // SAFETY: All pointers are normal allocations, not thread-specific. 105*057d44b0SMatthew Maurer unsafe impl Send for Registration {} 106*057d44b0SMatthew Maurer 107*057d44b0SMatthew Maurer #[pinned_drop] 108*057d44b0SMatthew Maurer impl PinnedDrop for Registration { 109*057d44b0SMatthew Maurer fn drop(self: Pin<&mut Self>) { 110*057d44b0SMatthew Maurer // SAFETY: Device always contains a live pointer to a soc_device that can be unregistered 111*057d44b0SMatthew Maurer unsafe { bindings::soc_device_unregister(self.soc_dev.as_ptr()) } 112*057d44b0SMatthew Maurer } 113*057d44b0SMatthew Maurer } 114*057d44b0SMatthew Maurer 115*057d44b0SMatthew Maurer impl Registration { 116*057d44b0SMatthew Maurer /// Register a new SoC device 117*057d44b0SMatthew Maurer pub fn new(attr: Attributes) -> impl PinInit<Self, Error> { 118*057d44b0SMatthew Maurer try_pin_init!(Self { 119*057d44b0SMatthew Maurer attr: attr.build(), 120*057d44b0SMatthew Maurer soc_dev: { 121*057d44b0SMatthew Maurer // SAFETY: 122*057d44b0SMatthew Maurer // * The struct provided through attr is backed by pinned data next to it, 123*057d44b0SMatthew Maurer // so as long as attr lives, the strings pointed to by the struct will too. 124*057d44b0SMatthew Maurer // * `attr` is pinned, so the pinned data won't move. 125*057d44b0SMatthew Maurer // * If it returns a device, and so others may try to read this data, by 126*057d44b0SMatthew Maurer // caller invariant, `attr` won't be released until the device is. 127*057d44b0SMatthew Maurer let raw_soc = error::from_err_ptr(unsafe { 128*057d44b0SMatthew Maurer bindings::soc_device_register(attr.as_mut_ptr()) 129*057d44b0SMatthew Maurer })?; 130*057d44b0SMatthew Maurer 131*057d44b0SMatthew Maurer NonNull::new(raw_soc).ok_or(EINVAL)? 132*057d44b0SMatthew Maurer }, 133*057d44b0SMatthew Maurer }? Error) 134*057d44b0SMatthew Maurer } 135*057d44b0SMatthew Maurer } 136