162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef __PMAC_PFUNC_H__ 362306a36Sopenharmony_ci#define __PMAC_PFUNC_H__ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <linux/list.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* Flags in command lists */ 962306a36Sopenharmony_ci#define PMF_FLAGS_ON_INIT 0x80000000u 1062306a36Sopenharmony_ci#define PMF_FLGAS_ON_TERM 0x40000000u 1162306a36Sopenharmony_ci#define PMF_FLAGS_ON_SLEEP 0x20000000u 1262306a36Sopenharmony_ci#define PMF_FLAGS_ON_WAKE 0x10000000u 1362306a36Sopenharmony_ci#define PMF_FLAGS_ON_DEMAND 0x08000000u 1462306a36Sopenharmony_ci#define PMF_FLAGS_INT_GEN 0x04000000u 1562306a36Sopenharmony_ci#define PMF_FLAGS_HIGH_SPEED 0x02000000u 1662306a36Sopenharmony_ci#define PMF_FLAGS_LOW_SPEED 0x01000000u 1762306a36Sopenharmony_ci#define PMF_FLAGS_SIDE_EFFECTS 0x00800000u 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Arguments to a platform function call. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * NOTE: By convention, pointer arguments point to an u32 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_cistruct pmf_args { 2562306a36Sopenharmony_ci union { 2662306a36Sopenharmony_ci u32 v; 2762306a36Sopenharmony_ci u32 *p; 2862306a36Sopenharmony_ci } u[4]; 2962306a36Sopenharmony_ci unsigned int count; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * A driver capable of interpreting commands provides a handlers 3462306a36Sopenharmony_ci * structure filled with whatever handlers are implemented by this 3562306a36Sopenharmony_ci * driver. Non implemented handlers are left NULL. 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * PMF_STD_ARGS are the same arguments that are passed to the parser 3862306a36Sopenharmony_ci * and that gets passed back to the various handlers. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Interpreting a given function always start with a begin() call which 4162306a36Sopenharmony_ci * returns an instance data to be passed around subsequent calls, and 4262306a36Sopenharmony_ci * ends with an end() call. This allows the low level driver to implement 4362306a36Sopenharmony_ci * locking policy or per-function instance data. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * For interrupt capable functions, irq_enable() is called when a client 4662306a36Sopenharmony_ci * registers, and irq_disable() is called when the last client unregisters 4762306a36Sopenharmony_ci * Note that irq_enable & irq_disable are called within a semaphore held 4862306a36Sopenharmony_ci * by the core, thus you should not try to register yourself to some other 4962306a36Sopenharmony_ci * pmf interrupt during those calls. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define PMF_STD_ARGS struct pmf_function *func, void *instdata, \ 5362306a36Sopenharmony_ci struct pmf_args *args 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct pmf_function; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct pmf_handlers { 5862306a36Sopenharmony_ci void * (*begin)(struct pmf_function *func, struct pmf_args *args); 5962306a36Sopenharmony_ci void (*end)(struct pmf_function *func, void *instdata); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci int (*irq_enable)(struct pmf_function *func); 6262306a36Sopenharmony_ci int (*irq_disable)(struct pmf_function *func); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci int (*write_gpio)(PMF_STD_ARGS, u8 value, u8 mask); 6562306a36Sopenharmony_ci int (*read_gpio)(PMF_STD_ARGS, u8 mask, int rshift, u8 xor); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci int (*write_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask); 6862306a36Sopenharmony_ci int (*read_reg32)(PMF_STD_ARGS, u32 offset); 6962306a36Sopenharmony_ci int (*write_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask); 7062306a36Sopenharmony_ci int (*read_reg16)(PMF_STD_ARGS, u32 offset); 7162306a36Sopenharmony_ci int (*write_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask); 7262306a36Sopenharmony_ci int (*read_reg8)(PMF_STD_ARGS, u32 offset); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci int (*delay)(PMF_STD_ARGS, u32 duration); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci int (*wait_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask); 7762306a36Sopenharmony_ci int (*wait_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask); 7862306a36Sopenharmony_ci int (*wait_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci int (*read_i2c)(PMF_STD_ARGS, u32 len); 8162306a36Sopenharmony_ci int (*write_i2c)(PMF_STD_ARGS, u32 len, const u8 *data); 8262306a36Sopenharmony_ci int (*rmw_i2c)(PMF_STD_ARGS, u32 masklen, u32 valuelen, u32 totallen, 8362306a36Sopenharmony_ci const u8 *maskdata, const u8 *valuedata); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci int (*read_cfg)(PMF_STD_ARGS, u32 offset, u32 len); 8662306a36Sopenharmony_ci int (*write_cfg)(PMF_STD_ARGS, u32 offset, u32 len, const u8 *data); 8762306a36Sopenharmony_ci int (*rmw_cfg)(PMF_STD_ARGS, u32 offset, u32 masklen, u32 valuelen, 8862306a36Sopenharmony_ci u32 totallen, const u8 *maskdata, const u8 *valuedata); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci int (*read_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len); 9162306a36Sopenharmony_ci int (*write_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len, const u8 *data); 9262306a36Sopenharmony_ci int (*set_i2c_mode)(PMF_STD_ARGS, int mode); 9362306a36Sopenharmony_ci int (*rmw_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 masklen, u32 valuelen, 9462306a36Sopenharmony_ci u32 totallen, const u8 *maskdata, 9562306a36Sopenharmony_ci const u8 *valuedata); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci int (*read_reg32_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift, 9862306a36Sopenharmony_ci u32 xor); 9962306a36Sopenharmony_ci int (*read_reg16_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift, 10062306a36Sopenharmony_ci u32 xor); 10162306a36Sopenharmony_ci int (*read_reg8_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift, 10262306a36Sopenharmony_ci u32 xor); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci int (*write_reg32_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask); 10562306a36Sopenharmony_ci int (*write_reg16_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask); 10662306a36Sopenharmony_ci int (*write_reg8_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci int (*mask_and_compare)(PMF_STD_ARGS, u32 len, const u8 *maskdata, 10962306a36Sopenharmony_ci const u8 *valuedata); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci struct module *owner; 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* 11662306a36Sopenharmony_ci * Drivers who expose platform functions register at init time, this 11762306a36Sopenharmony_ci * causes the platform functions for that device node to be parsed in 11862306a36Sopenharmony_ci * advance and associated with the device. The data structures are 11962306a36Sopenharmony_ci * partially public so a driver can walk the list of platform functions 12062306a36Sopenharmony_ci * and eventually inspect the flags 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_cistruct pmf_device; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistruct pmf_function { 12562306a36Sopenharmony_ci /* All functions for a given driver are linked */ 12662306a36Sopenharmony_ci struct list_head link; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Function node & driver data */ 12962306a36Sopenharmony_ci struct device_node *node; 13062306a36Sopenharmony_ci void *driver_data; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* For internal use by core */ 13362306a36Sopenharmony_ci struct pmf_device *dev; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* The name is the "xxx" in "platform-do-xxx", this is how 13662306a36Sopenharmony_ci * platform functions are identified by this code. Some functions 13762306a36Sopenharmony_ci * only operate for a given target, in which case the phandle is 13862306a36Sopenharmony_ci * here (or 0 if the filter doesn't apply) 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci const char *name; 14162306a36Sopenharmony_ci u32 phandle; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* The flags for that function. You can have several functions 14462306a36Sopenharmony_ci * with the same name and different flag 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci u32 flags; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* The actual tokenized function blob */ 14962306a36Sopenharmony_ci const void *data; 15062306a36Sopenharmony_ci unsigned int length; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Interrupt clients */ 15362306a36Sopenharmony_ci struct list_head irq_clients; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Refcounting */ 15662306a36Sopenharmony_ci struct kref ref; 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * For platform functions that are interrupts, one can register 16162306a36Sopenharmony_ci * irq_client structures. You canNOT use the same structure twice 16262306a36Sopenharmony_ci * as it contains a link member. Also, the callback is called with 16362306a36Sopenharmony_ci * a spinlock held, you must not call back into any of the pmf_* functions 16462306a36Sopenharmony_ci * from within that callback 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistruct pmf_irq_client { 16762306a36Sopenharmony_ci void (*handler)(void *data); 16862306a36Sopenharmony_ci void *data; 16962306a36Sopenharmony_ci struct module *owner; 17062306a36Sopenharmony_ci struct list_head link; 17162306a36Sopenharmony_ci struct pmf_function *func; 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci * Register/Unregister a function-capable driver and its handlers 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ciextern int pmf_register_driver(struct device_node *np, 17962306a36Sopenharmony_ci struct pmf_handlers *handlers, 18062306a36Sopenharmony_ci void *driverdata); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ciextern void pmf_unregister_driver(struct device_node *np); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* 18662306a36Sopenharmony_ci * Register/Unregister interrupt clients 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ciextern int pmf_register_irq_client(struct device_node *np, 18962306a36Sopenharmony_ci const char *name, 19062306a36Sopenharmony_ci struct pmf_irq_client *client); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciextern void pmf_unregister_irq_client(struct pmf_irq_client *client); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* 19562306a36Sopenharmony_ci * Called by the handlers when an irq happens 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ciextern void pmf_do_irq(struct pmf_function *func); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* 20162306a36Sopenharmony_ci * Low level call to platform functions. 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * The phandle can filter on the target object for functions that have 20462306a36Sopenharmony_ci * multiple targets, the flags allow you to restrict the call to a given 20562306a36Sopenharmony_ci * combination of flags. 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * The args array contains as many arguments as is required by the function, 20862306a36Sopenharmony_ci * this is dependent on the function you are calling, unfortunately Apple 20962306a36Sopenharmony_ci * mechanism provides no way to encode that so you have to get it right at 21062306a36Sopenharmony_ci * the call site. Some functions require no args, in which case, you can 21162306a36Sopenharmony_ci * pass NULL. 21262306a36Sopenharmony_ci * 21362306a36Sopenharmony_ci * You can also pass NULL to the name. This will match any function that has 21462306a36Sopenharmony_ci * the appropriate combination of flags & phandle or you can pass 0 to the 21562306a36Sopenharmony_ci * phandle to match any 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ciextern int pmf_do_functions(struct device_node *np, const char *name, 21862306a36Sopenharmony_ci u32 phandle, u32 flags, struct pmf_args *args); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * High level call to a platform function. 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * This one looks for the platform-xxx first so you should call it to the 22662306a36Sopenharmony_ci * actual target if any. It will fallback to platform-do-xxx if it can't 22762306a36Sopenharmony_ci * find one. It will also exclusively target functions that have 22862306a36Sopenharmony_ci * the "OnDemand" flag. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ciextern int pmf_call_function(struct device_node *target, const char *name, 23262306a36Sopenharmony_ci struct pmf_args *args); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* 23662306a36Sopenharmony_ci * For low latency interrupt usage, you can lookup for on-demand functions 23762306a36Sopenharmony_ci * using the functions below 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ciextern struct pmf_function *pmf_find_function(struct device_node *target, 24162306a36Sopenharmony_ci const char *name); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciextern struct pmf_function * pmf_get_function(struct pmf_function *func); 24462306a36Sopenharmony_ciextern void pmf_put_function(struct pmf_function *func); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciextern int pmf_call_one(struct pmf_function *func, struct pmf_args *args); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ciint pmac_pfunc_base_install(void); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* Suspend/resume code called by via-pmu directly for now */ 25162306a36Sopenharmony_ciextern void pmac_pfunc_base_suspend(void); 25262306a36Sopenharmony_ciextern void pmac_pfunc_base_resume(void); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci#endif /* __PMAC_PFUNC_H__ */ 255