@@ -12,12 +12,29 @@ use crate::{
1212 clk:: Hertz ,
1313 cpumask:: { Cpumask , CpumaskVar } ,
1414 device:: Device ,
15- error:: { code:: * , from_err_ptr, to_result, Error , Result } ,
15+ error:: { code:: * , from_err_ptr, from_result , to_result, Error , Result , VTABLE_DEFAULT_ERROR } ,
1616 ffi:: c_ulong,
17+ prelude:: * ,
18+ str:: CString ,
1719 types:: { ARef , AlwaysRefCounted , Opaque } ,
1820} ;
1921
20- use core:: ptr;
22+ use core:: { marker:: PhantomData , ptr} ;
23+
24+ use macros:: vtable;
25+
26+ /// Creates a null-terminated slice of pointers to [`Cstring`]s.
27+ fn to_c_str_array ( names : & [ CString ] ) -> Result < KVec < * const u8 > > {
28+ // Allocated a null-terminated vector of pointers.
29+ let mut list = KVec :: with_capacity ( names. len ( ) + 1 , GFP_KERNEL ) ?;
30+
31+ for name in names. iter ( ) {
32+ list. push ( name. as_ptr ( ) as _ , GFP_KERNEL ) ?;
33+ }
34+
35+ list. push ( ptr:: null ( ) , GFP_KERNEL ) ?;
36+ Ok ( list)
37+ }
2138
2239/// The voltage unit.
2340///
@@ -205,6 +222,280 @@ pub enum SearchType {
205222 Ceil ,
206223}
207224
225+ /// OPP configuration callbacks.
226+ ///
227+ /// Implement this trait to customize OPP clock and regulator setup for your device.
228+ #[ vtable]
229+ pub trait ConfigOps {
230+ /// This is typically used to scale clocks when transitioning between OPPs.
231+ #[ inline]
232+ fn config_clks ( _dev : & Device , _table : & Table , _opp : & OPP , _scaling_down : bool ) -> Result {
233+ build_error ! ( VTABLE_DEFAULT_ERROR )
234+ }
235+
236+ /// This provides access to the old and new OPPs, allowing for safe regulator adjustments.
237+ #[ inline]
238+ fn config_regulators (
239+ _dev : & Device ,
240+ _opp_old : & OPP ,
241+ _opp_new : & OPP ,
242+ _data : * mut * mut bindings:: regulator ,
243+ _count : u32 ,
244+ ) -> Result {
245+ build_error ! ( VTABLE_DEFAULT_ERROR )
246+ }
247+ }
248+
249+ /// OPP configuration token.
250+ ///
251+ /// Returned by the OPP core when configuration is applied to a [`Device`]. The associated
252+ /// configuration is automatically cleared when the token is dropped.
253+ pub struct ConfigToken ( i32 ) ;
254+
255+ impl Drop for ConfigToken {
256+ fn drop ( & mut self ) {
257+ // SAFETY: This is the same token value returned by the C code via `dev_pm_opp_set_config`.
258+ unsafe { bindings:: dev_pm_opp_clear_config ( self . 0 ) } ;
259+ }
260+ }
261+
262+ /// OPP configurations.
263+ ///
264+ /// Rust abstraction for the C `struct dev_pm_opp_config`.
265+ ///
266+ /// ## Examples
267+ ///
268+ /// The following example demonstrates how to set OPP property-name configuration for a [`Device`].
269+ ///
270+ /// ```
271+ /// use kernel::device::Device;
272+ /// use kernel::error::Result;
273+ /// use kernel::opp::{Config, ConfigOps, ConfigToken};
274+ /// use kernel::str::CString;
275+ /// use kernel::types::ARef;
276+ /// use kernel::macros::vtable;
277+ ///
278+ /// #[derive(Default)]
279+ /// struct Driver;
280+ ///
281+ /// #[vtable]
282+ /// impl ConfigOps for Driver {}
283+ ///
284+ /// fn configure(dev: &ARef<Device>) -> Result<ConfigToken> {
285+ /// let name = CString::try_from_fmt(fmt!("{}", "slow"))?;
286+ ///
287+ /// // The OPP configuration is cleared once the [`ConfigToken`] goes out of scope.
288+ /// Config::<Driver>::new()
289+ /// .set_prop_name(name)?
290+ /// .set(dev)
291+ /// }
292+ /// ```
293+ #[ derive( Default ) ]
294+ pub struct Config < T : ConfigOps >
295+ where
296+ T : Default ,
297+ {
298+ clk_names : Option < KVec < CString > > ,
299+ prop_name : Option < CString > ,
300+ regulator_names : Option < KVec < CString > > ,
301+ supported_hw : Option < KVec < u32 > > ,
302+
303+ // Tuple containing (required device, index)
304+ required_dev : Option < ( ARef < Device > , u32 ) > ,
305+ _data : PhantomData < T > ,
306+ }
307+
308+ impl < T : ConfigOps + Default > Config < T > {
309+ /// Creates a new instance of [`Config`].
310+ #[ inline]
311+ pub fn new ( ) -> Self {
312+ Self :: default ( )
313+ }
314+
315+ /// Initializes clock names.
316+ pub fn set_clk_names ( mut self , names : KVec < CString > ) -> Result < Self > {
317+ if self . clk_names . is_some ( ) {
318+ return Err ( EBUSY ) ;
319+ }
320+
321+ if names. is_empty ( ) {
322+ return Err ( EINVAL ) ;
323+ }
324+
325+ self . clk_names = Some ( names) ;
326+ Ok ( self )
327+ }
328+
329+ /// Initializes property name.
330+ pub fn set_prop_name ( mut self , name : CString ) -> Result < Self > {
331+ if self . prop_name . is_some ( ) {
332+ return Err ( EBUSY ) ;
333+ }
334+
335+ self . prop_name = Some ( name) ;
336+ Ok ( self )
337+ }
338+
339+ /// Initializes regulator names.
340+ pub fn set_regulator_names ( mut self , names : KVec < CString > ) -> Result < Self > {
341+ if self . regulator_names . is_some ( ) {
342+ return Err ( EBUSY ) ;
343+ }
344+
345+ if names. is_empty ( ) {
346+ return Err ( EINVAL ) ;
347+ }
348+
349+ self . regulator_names = Some ( names) ;
350+
351+ Ok ( self )
352+ }
353+
354+ /// Initializes required devices.
355+ pub fn set_required_dev ( mut self , dev : ARef < Device > , index : u32 ) -> Result < Self > {
356+ if self . required_dev . is_some ( ) {
357+ return Err ( EBUSY ) ;
358+ }
359+
360+ self . required_dev = Some ( ( dev, index) ) ;
361+ Ok ( self )
362+ }
363+
364+ /// Initializes supported hardware.
365+ pub fn set_supported_hw ( mut self , hw : KVec < u32 > ) -> Result < Self > {
366+ if self . supported_hw . is_some ( ) {
367+ return Err ( EBUSY ) ;
368+ }
369+
370+ if hw. is_empty ( ) {
371+ return Err ( EINVAL ) ;
372+ }
373+
374+ self . supported_hw = Some ( hw) ;
375+ Ok ( self )
376+ }
377+
378+ /// Sets the configuration with the OPP core.
379+ ///
380+ /// The returned [`ConfigToken`] will remove the configuration when dropped.
381+ pub fn set ( self , dev : & Device ) -> Result < ConfigToken > {
382+ let ( _clk_list, clk_names) = match & self . clk_names {
383+ Some ( x) => {
384+ let list = to_c_str_array ( x) ?;
385+ let ptr = list. as_ptr ( ) ;
386+ ( Some ( list) , ptr)
387+ }
388+ None => ( None , ptr:: null ( ) ) ,
389+ } ;
390+
391+ let ( _regulator_list, regulator_names) = match & self . regulator_names {
392+ Some ( x) => {
393+ let list = to_c_str_array ( x) ?;
394+ let ptr = list. as_ptr ( ) ;
395+ ( Some ( list) , ptr)
396+ }
397+ None => ( None , ptr:: null ( ) ) ,
398+ } ;
399+
400+ let prop_name = self
401+ . prop_name
402+ . as_ref ( )
403+ . map_or ( ptr:: null ( ) , |p| p. as_char_ptr ( ) ) ;
404+
405+ let ( supported_hw, supported_hw_count) = self
406+ . supported_hw
407+ . as_ref ( )
408+ . map_or ( ( ptr:: null ( ) , 0 ) , |hw| ( hw. as_ptr ( ) , hw. len ( ) as u32 ) ) ;
409+
410+ let ( required_dev, required_dev_index) = self
411+ . required_dev
412+ . as_ref ( )
413+ . map_or ( ( ptr:: null_mut ( ) , 0 ) , |( dev, idx) | ( dev. as_raw ( ) , * idx) ) ;
414+
415+ let mut config = bindings:: dev_pm_opp_config {
416+ clk_names,
417+ config_clks : if T :: HAS_CONFIG_CLKS {
418+ Some ( Self :: config_clks)
419+ } else {
420+ None
421+ } ,
422+ prop_name,
423+ regulator_names,
424+ config_regulators : if T :: HAS_CONFIG_REGULATORS {
425+ Some ( Self :: config_regulators)
426+ } else {
427+ None
428+ } ,
429+ supported_hw,
430+ supported_hw_count,
431+
432+ required_dev,
433+ required_dev_index,
434+ } ;
435+
436+ // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
437+ // requirements. The OPP core guarantees not to access fields of [`Config`] after this call
438+ // and so we don't need to save a copy of them for future use.
439+ let ret = unsafe { bindings:: dev_pm_opp_set_config ( dev. as_raw ( ) , & mut config) } ;
440+ if ret < 0 {
441+ Err ( Error :: from_errno ( ret) )
442+ } else {
443+ Ok ( ConfigToken ( ret) )
444+ }
445+ }
446+
447+ /// Config's clk callback.
448+ ///
449+ /// SAFETY: Called from C. Inputs must be valid pointers.
450+ extern "C" fn config_clks (
451+ dev : * mut bindings:: device ,
452+ opp_table : * mut bindings:: opp_table ,
453+ opp : * mut bindings:: dev_pm_opp ,
454+ _data : * mut kernel:: ffi:: c_void ,
455+ scaling_down : bool ,
456+ ) -> kernel:: ffi:: c_int {
457+ from_result ( || {
458+ // SAFETY: 'dev' is guaranteed by the C code to be valid.
459+ let dev = unsafe { Device :: get_device ( dev) } ;
460+ T :: config_clks (
461+ & dev,
462+ // SAFETY: 'opp_table' is guaranteed by the C code to be valid.
463+ & unsafe { Table :: from_raw_table ( opp_table, & dev) } ,
464+ // SAFETY: 'opp' is guaranteed by the C code to be valid.
465+ unsafe { OPP :: from_raw_opp ( opp) ? } ,
466+ scaling_down,
467+ )
468+ . map ( |( ) | 0 )
469+ } )
470+ }
471+
472+ /// Config's regulator callback.
473+ ///
474+ /// SAFETY: Called from C. Inputs must be valid pointers.
475+ extern "C" fn config_regulators (
476+ dev : * mut bindings:: device ,
477+ old_opp : * mut bindings:: dev_pm_opp ,
478+ new_opp : * mut bindings:: dev_pm_opp ,
479+ regulators : * mut * mut bindings:: regulator ,
480+ count : kernel:: ffi:: c_uint ,
481+ ) -> kernel:: ffi:: c_int {
482+ from_result ( || {
483+ // SAFETY: 'dev' is guaranteed by the C code to be valid.
484+ let dev = unsafe { Device :: get_device ( dev) } ;
485+ T :: config_regulators (
486+ & dev,
487+ // SAFETY: 'old_opp' is guaranteed by the C code to be valid.
488+ unsafe { OPP :: from_raw_opp ( old_opp) ? } ,
489+ // SAFETY: 'new_opp' is guaranteed by the C code to be valid.
490+ unsafe { OPP :: from_raw_opp ( new_opp) ? } ,
491+ regulators,
492+ count,
493+ )
494+ . map ( |( ) | 0 )
495+ } )
496+ }
497+ }
498+
208499/// A reference-counted OPP table.
209500///
210501/// Rust abstraction for the C `struct opp_table`.
0 commit comments