/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* AMD MP2 I2C adapter driver
*
* Authors : Shyam Sundar S K < Shyam - sundar . S - k @ amd . com >
* Elie Morisse < syniurge @ gmail . com >
*/
#ifndef I2C_AMD_PCI_MP2_H
#define I2C_AMD_PCI_MP2_H
#include <linux/i2c.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#define PCI_DEVICE_ID_AMD_MP2 0 x15E6
struct amd_i2c_common;
struct amd_mp2_dev;
enum {
/* MP2 C2P Message Registers */
AMD_C2P_MSG0 = 0 x10500, /* MP2 Message for I2C0 */
AMD_C2P_MSG1 = 0 x10504, /* MP2 Message for I2C1 */
AMD_C2P_MSG2 = 0 x10508, /* DRAM Address Lo / Data 0 */
AMD_C2P_MSG3 = 0 x1050c, /* DRAM Address HI / Data 1 */
AMD_C2P_MSG4 = 0 x10510, /* Data 2 */
AMD_C2P_MSG5 = 0 x10514, /* Data 3 */
AMD_C2P_MSG6 = 0 x10518, /* Data 4 */
AMD_C2P_MSG7 = 0 x1051c, /* Data 5 */
AMD_C2P_MSG8 = 0 x10520, /* Data 6 */
AMD_C2P_MSG9 = 0 x10524, /* Data 7 */
/* MP2 P2C Message Registers */
AMD_P2C_MSG0 = 0 x10680, /* Do not use */
AMD_P2C_MSG1 = 0 x10684, /* I2C0 interrupt register */
AMD_P2C_MSG2 = 0 x10688, /* I2C1 interrupt register */
AMD_P2C_MSG3 = 0 x1068C, /* MP2 debug info */
AMD_P2C_MSG_INTEN = 0 x10690, /* MP2 interrupt gen register */
AMD_P2C_MSG_INTSTS = 0 x10694, /* Interrupt status */
};
/* Command register data structures */
#define i2c_none (-1 )
enum i2c_cmd {
i2c_read = 0 ,
i2c_write,
i2c_enable,
i2c_disable,
number_of_sensor_discovered,
is_mp2_active,
invalid_cmd = 0 xF,
};
enum speed_enum {
speed100k = 0 ,
speed400k = 1 ,
speed1000k = 2 ,
speed1400k = 3 ,
speed3400k = 4
};
enum mem_type {
use_dram = 0 ,
use_c2pmsg = 1 ,
};
/**
* union i2c_cmd_base : bit access of C2P commands
* @ i2c_cmd : bit 0 . . 3 i2c R / W command
* @ bus_id : bit 4 . . 7 i2c bus index
* @ slave_addr : bit 8 . . 15 slave address
* @ length : bit 16 . . 27 read / write length
* @ i2c_speed : bit 28 . . 30 bus speed
* @ mem_type : bit 31 0 - DRAM ; 1 - C2P msg o / p
*/
union i2c_cmd_base {
u32 ul;
struct {
enum i2c_cmd i2c_cmd : 4 ;
u8 bus_id : 4 ;
u32 slave_addr : 8 ;
u32 length : 12 ;
enum speed_enum i2c_speed : 3 ;
enum mem_type mem_type : 1 ;
} s;
};
enum response_type {
invalid_response = 0 ,
command_success = 1 ,
command_failed = 2 ,
};
enum status_type {
i2c_readcomplete_event = 0 ,
i2c_readfail_event = 1 ,
i2c_writecomplete_event = 2 ,
i2c_writefail_event = 3 ,
i2c_busenable_complete = 4 ,
i2c_busenable_failed = 5 ,
i2c_busdisable_complete = 6 ,
i2c_busdisable_failed = 7 ,
invalid_data_length = 8 ,
invalid_slave_address = 9 ,
invalid_i2cbus_id = 10 ,
invalid_dram_addr = 11 ,
invalid_command = 12 ,
mp2_active = 13 ,
numberof_sensors_discovered_resp = 14 ,
i2c_bus_notinitialized
};
/**
* union i2c_event : bit access of P2C events
* @ response : bit 0 . . 1 i2c response type
* @ status : bit 2 . . 6 status_type
* @ mem_type : bit 7 0 - DRAM ; 1 - C2P msg o / p
* @ bus_id : bit 8 . . 11 i2c bus id
* @ length : bit 12 . . 23 message length
* @ slave_addr : bit 24 - 31 slave address
*/
union i2c_event {
u32 ul;
struct {
enum response_type response : 2 ;
enum status_type status : 5 ;
enum mem_type mem_type : 1 ;
u8 bus_id : 4 ;
u32 length : 12 ;
u32 slave_addr : 8 ;
} r;
};
/**
* struct amd_i2c_common - per bus / i2c adapter context , shared
* between the pci and the platform driver
* @ eventval : MP2 event value set by the IRQ handler
* @ mp2_dev : MP2 pci device this adapter is part of
* @ msg : i2c message
* @ cmd_completion : function called by the IRQ handler to signal
* the platform driver
* @ reqcmd : requested i2c command type
* @ cmd_success : set to true if the MP2 responded to a command with
* the expected status and response type
* @ bus_id : bus index
* @ i2c_speed : i2c bus speed determined by the slowest slave
* @ dma_buf : if msg length > 32 , holds the DMA buffer virtual address
* @ dma_addr : if msg length > 32 , holds the DMA buffer address
*/
struct amd_i2c_common {
union i2c_event eventval;
struct amd_mp2_dev *mp2_dev;
struct i2c_msg *msg;
void (*cmd_completion)(struct amd_i2c_common *i2c_common);
enum i2c_cmd reqcmd;
u8 cmd_success;
u8 bus_id;
enum speed_enum i2c_speed;
u8 *dma_buf;
dma_addr_t dma_addr;
#ifdef CONFIG_PM
int (*suspend)(struct amd_i2c_common *i2c_common);
int (*resume)(struct amd_i2c_common *i2c_common);
#endif /* CONFIG_PM */
};
/**
* struct amd_mp2_dev - per PCI device context
* @ pci_dev : PCI driver node
* @ busses : MP2 devices may have up to two busses ,
* each bus corresponding to an i2c adapter
* @ mmio : iommapped registers
* @ c2p_lock : controls access to the C2P mailbox shared between
* the two adapters
* @ c2p_lock_busid : id of the adapter which locked c2p_lock
*/
struct amd_mp2_dev {
struct pci_dev *pci_dev;
struct amd_i2c_common *busses[2 ];
void __iomem *mmio;
struct mutex c2p_lock;
u8 c2p_lock_busid;
unsigned int probed;
int dev_irq;
};
/* PCIe communication driver */
int amd_mp2_rw(struct amd_i2c_common *i2c_common, enum i2c_cmd reqcmd);
int amd_mp2_bus_enable_set(struct amd_i2c_common *i2c_common, bool enable);
void amd_mp2_process_event(struct amd_i2c_common *i2c_common);
void amd_mp2_rw_timeout(struct amd_i2c_common *i2c_common);
int amd_mp2_register_cb(struct amd_i2c_common *i2c_common);
int amd_mp2_unregister_cb(struct amd_i2c_common *i2c_common);
struct amd_mp2_dev *amd_mp2_find_device(void );
static inline void amd_mp2_pm_runtime_get(struct amd_mp2_dev *mp2_dev)
{
pm_runtime_get_sync(&mp2_dev->pci_dev->dev);
}
static inline void amd_mp2_pm_runtime_put(struct amd_mp2_dev *mp2_dev)
{
pm_runtime_mark_last_busy(&mp2_dev->pci_dev->dev);
pm_runtime_put_autosuspend(&mp2_dev->pci_dev->dev);
}
#endif
Messung V0.5 in Prozent C=96 H=99 G=97
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-09-27)
¤
*© Formatika GbR, Deutschland