diff options
author | Jan Dabros <jsd@semihalf.com> | 2022-02-08 15:12:18 +0100 |
---|---|---|
committer | Wolfram Sang <wsa@kernel.org> | 2022-02-11 15:38:23 +0100 |
commit | 78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c (patch) | |
tree | 8b5d5d765f5b3068645db94da8553e76483098ad /drivers/i2c/busses/i2c-designware-core.h | |
parent | i2c: designware: Add missing locks (diff) | |
download | linux-78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c.tar.xz linux-78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c.zip |
i2c: designware: Add AMD PSP I2C bus support
Implement an I2C controller sharing mechanism between the host (kernel)
and PSP co-processor on some platforms equipped with AMD Cezanne SoC.
On these platforms we need to implement "software" i2c arbitration.
Default arbitration owner is PSP and kernel asks for acquire as well
as inform about release of the i2c bus via mailbox mechanism.
+---------+
<- ACQUIRE | |
+---------| CPU |\
| | | \ +----------+ SDA
| +---------+ \ | |-------
MAILBOX +--> | I2C-DW | SCL
| +---------+ | |-------
| | | +----------+
+---------| PSP |
<- ACK | |
+---------+
+---------+
<- RELEASE | |
+---------| CPU |
| | | +----------+ SDA
| +---------+ | |-------
MAILBOX +--> | I2C-DW | SCL
| +---------+ / | |-------
| | | / +----------+
+---------| PSP |/
<- ACK | |
+---------+
The solution is similar to i2c-designware-baytrail.c implementation, where
we are using a generic i2c-designware-* driver with a small "wrapper".
In contrary to baytrail semaphore implementation, beside internal
acquire_lock() and release_lock() methods we are also applying quirks to
lock_bus() and unlock_bus() global adapter methods. With this in place
all i2c clients drivers may lock i2c bus for a desired number of i2c
transactions (e.g. write-wait-read) without being aware of that such bus
is shared with another entity.
Modify i2c_dw_probe_lock_support() to select correct semaphore
implementation at runtime, since now we have more than one available.
Configure new matching ACPI ID "AMDI0019" and register
ARBITRATION_SEMAPHORE flag in order to distinguish setup with PSP
arbitration.
Add myself as a reviewer for I2C DesignWare in order to help with reviewing
and testing possible changes touching new i2c-designware-amdpsp.c module.
Signed-off-by: Jan Dabros <jsd@semihalf.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
[wsa: removed unneeded blank line and curly braces]
Signed-off-by: Wolfram Sang <wsa@kernel.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-core.h')
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.h | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 4b26cba40139..1d65212fddbd 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -227,6 +227,8 @@ struct reset_control; * @hs_lcnt: high speed LCNT value * @acquire_lock: function to acquire a hardware lock on the bus * @release_lock: function to release a hardware lock on the bus + * @semaphore_idx: Index of table with semaphore type attached to the bus. It's + * -1 if there is no semaphore. * @shared_with_punit: true if this bus is shared with the SoCs PUNIT * @disable: function to disable the controller * @disable_int: function to disable all interrupts @@ -285,6 +287,7 @@ struct dw_i2c_dev { u16 hs_lcnt; int (*acquire_lock)(void); void (*release_lock)(void); + int semaphore_idx; bool shared_with_punit; void (*disable)(struct dw_i2c_dev *dev); void (*disable_int)(struct dw_i2c_dev *dev); @@ -297,6 +300,7 @@ struct dw_i2c_dev { #define ACCESS_INTR_MASK BIT(0) #define ACCESS_NO_IRQ_SUSPEND BIT(1) +#define ARBITRATION_SEMAPHORE BIT(2) #define MODEL_MSCC_OCELOT BIT(8) #define MODEL_BAIKAL_BT1 BIT(9) @@ -310,6 +314,11 @@ struct dw_i2c_dev { #define AMD_UCSI_INTR_REG 0x474 #define AMD_UCSI_INTR_EN 0xd +struct i2c_dw_semaphore_callbacks { + int (*probe)(struct dw_i2c_dev *dev); + void (*remove)(struct dw_i2c_dev *dev); +}; + int i2c_dw_init_regmap(struct dw_i2c_dev *dev); u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); @@ -370,9 +379,12 @@ static inline void i2c_dw_configure(struct dw_i2c_dev *dev) } #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) -extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev); -#else -static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; } +int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev); +#endif + +#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_AMDPSP) +int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev); +void i2c_dw_amdpsp_remove_lock_support(struct dw_i2c_dev *dev); #endif int i2c_dw_validate_speed(struct dw_i2c_dev *dev); |