@@ -12,12 +12,29 @@ use crate::{
12
12
clk:: Hertz ,
13
13
cpumask:: { Cpumask , CpumaskVar } ,
14
14
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 } ,
16
16
ffi:: c_ulong,
17
+ prelude:: * ,
18
+ str:: CString ,
17
19
types:: { ARef , AlwaysRefCounted , Opaque } ,
18
20
} ;
19
21
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
+ }
21
38
22
39
/// The voltage unit.
23
40
///
@@ -205,6 +222,280 @@ pub enum SearchType {
205
222
Ceil ,
206
223
}
207
224
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
+
208
499
/// A reference-counted OPP table.
209
500
///
210
501
/// Rust abstraction for the C `struct opp_table`.
0 commit comments