Char/Misc and other driver updates for 5.18-rc1
Here is the big set of char/misc and other small driver subsystem updates for 5.18-rc1. Included in here are merges from driver subsystems which contain: - iio driver updates and new drivers - fsi driver updates - fpga driver updates - habanalabs driver updates and support for new hardware - soundwire driver updates and new drivers - phy driver updates and new drivers - coresight driver updates - icc driver updates Individual changes include: - mei driver updates - interconnect driver updates - new PECI driver subsystem added - vmci driver updates - lots of tiny misc/char driver updates There will be two merge conflicts with your tree, one in MAINTAINERS which is obvious to fix up, and one in drivers/phy/freescale/Kconfig which also should be easy to resolve. All of these have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYkG3fQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykNEgCfaRG8CRxewDXOO4+GSeA3NGK+AIoAnR89donC R4bgCjfg8BWIBcVVXg3/ =WWXC -----END PGP SIGNATURE----- Merge tag 'char-misc-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc and other driver updates from Greg KH: "Here is the big set of char/misc and other small driver subsystem updates for 5.18-rc1. Included in here are merges from driver subsystems which contain: - iio driver updates and new drivers - fsi driver updates - fpga driver updates - habanalabs driver updates and support for new hardware - soundwire driver updates and new drivers - phy driver updates and new drivers - coresight driver updates - icc driver updates Individual changes include: - mei driver updates - interconnect driver updates - new PECI driver subsystem added - vmci driver updates - lots of tiny misc/char driver updates All of these have been in linux-next for a while with no reported problems" * tag 'char-misc-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (556 commits) firmware: google: Properly state IOMEM dependency kgdbts: fix return value of __setup handler firmware: sysfb: fix platform-device leak in error path firmware: stratix10-svc: add missing callback parameter on RSU arm64: dts: qcom: add non-secure domain property to fastrpc nodes misc: fastrpc: Add dma handle implementation misc: fastrpc: Add fdlist implementation misc: fastrpc: Add helper function to get list and page misc: fastrpc: Add support to secure memory map dt-bindings: misc: add fastrpc domain vmid property misc: fastrpc: check before loading process to the DSP misc: fastrpc: add secure domain support dt-bindings: misc: add property to support non-secure DSP misc: fastrpc: Add support to get DSP capabilities misc: fastrpc: add support for FASTRPC_IOCTL_MEM_MAP/UNMAP misc: fastrpc: separate fastrpc device from channel context dt-bindings: nvmem: brcm,nvram: add basic NVMEM cells dt-bindings: nvmem: make "reg" property optional nvmem: brcm_nvram: parse NVRAM content into NVMEM cells nvmem: dt-bindings: Fix the error of dt-bindings check ...
This commit is contained in:
commit
02e2af20f4
567 changed files with 27052 additions and 6728 deletions
|
|
@ -36,7 +36,6 @@
|
|||
extern struct bus_type coresight_bustype;
|
||||
|
||||
enum coresight_dev_type {
|
||||
CORESIGHT_DEV_TYPE_NONE,
|
||||
CORESIGHT_DEV_TYPE_SINK,
|
||||
CORESIGHT_DEV_TYPE_LINK,
|
||||
CORESIGHT_DEV_TYPE_LINKSINK,
|
||||
|
|
@ -46,7 +45,6 @@ enum coresight_dev_type {
|
|||
};
|
||||
|
||||
enum coresight_dev_subtype_sink {
|
||||
CORESIGHT_DEV_SUBTYPE_SINK_NONE,
|
||||
CORESIGHT_DEV_SUBTYPE_SINK_PORT,
|
||||
CORESIGHT_DEV_SUBTYPE_SINK_BUFFER,
|
||||
CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM,
|
||||
|
|
@ -54,21 +52,18 @@ enum coresight_dev_subtype_sink {
|
|||
};
|
||||
|
||||
enum coresight_dev_subtype_link {
|
||||
CORESIGHT_DEV_SUBTYPE_LINK_NONE,
|
||||
CORESIGHT_DEV_SUBTYPE_LINK_MERG,
|
||||
CORESIGHT_DEV_SUBTYPE_LINK_SPLIT,
|
||||
CORESIGHT_DEV_SUBTYPE_LINK_FIFO,
|
||||
};
|
||||
|
||||
enum coresight_dev_subtype_source {
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_NONE,
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_PROC,
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_BUS,
|
||||
CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE,
|
||||
};
|
||||
|
||||
enum coresight_dev_subtype_helper {
|
||||
CORESIGHT_DEV_SUBTYPE_HELPER_NONE,
|
||||
CORESIGHT_DEV_SUBTYPE_HELPER_CATU,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -321,8 +321,6 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
|
|||
#define INTEL_SIP_SMC_ECC_DBE \
|
||||
INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_ECC_DBE)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Request INTEL_SIP_SMC_RSU_NOTIFY
|
||||
*
|
||||
|
|
@ -404,3 +402,22 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
|
|||
#define INTEL_SIP_SMC_FUNCID_RSU_MAX_RETRY 18
|
||||
#define INTEL_SIP_SMC_RSU_MAX_RETRY \
|
||||
INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_MAX_RETRY)
|
||||
|
||||
/**
|
||||
* Request INTEL_SIP_SMC_FIRMWARE_VERSION
|
||||
*
|
||||
* Sync call used to query the version of running firmware
|
||||
*
|
||||
* Call register usage:
|
||||
* a0 INTEL_SIP_SMC_FIRMWARE_VERSION
|
||||
* a1-a7 not used
|
||||
*
|
||||
* Return status:
|
||||
* a0 INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_STATUS_ERROR
|
||||
* a1 running firmware version
|
||||
*/
|
||||
#define INTEL_SIP_SMC_FUNCID_FIRMWARE_VERSION 31
|
||||
#define INTEL_SIP_SMC_FIRMWARE_VERSION \
|
||||
INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FIRMWARE_VERSION)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ struct stratix10_svc_chan;
|
|||
*
|
||||
* @COMMAND_RSU_DCMF_VERSION: query firmware for the DCMF version, return status
|
||||
* is SVC_STATUS_OK or SVC_STATUS_ERROR
|
||||
*
|
||||
* @COMMAND_FIRMWARE_VERSION: query running firmware version, return status
|
||||
* is SVC_STATUS_OK or SVC_STATUS_ERROR
|
||||
*/
|
||||
enum stratix10_svc_command_code {
|
||||
COMMAND_NOOP = 0,
|
||||
|
|
@ -117,6 +120,7 @@ enum stratix10_svc_command_code {
|
|||
COMMAND_RSU_RETRY,
|
||||
COMMAND_RSU_MAX_RETRY,
|
||||
COMMAND_RSU_DCMF_VERSION,
|
||||
COMMAND_FIRMWARE_VERSION,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -144,6 +144,9 @@ enum pm_ioctl_id {
|
|||
IOCTL_OSPI_MUX_SELECT = 21,
|
||||
/* Register SGI to ATF */
|
||||
IOCTL_REGISTER_SGI = 25,
|
||||
/* Runtime feature configuration */
|
||||
IOCTL_SET_FEATURE_CONFIG = 26,
|
||||
IOCTL_GET_FEATURE_CONFIG = 27,
|
||||
};
|
||||
|
||||
enum pm_query_id {
|
||||
|
|
@ -377,6 +380,14 @@ enum ospi_mux_select_type {
|
|||
PM_OSPI_MUX_SEL_LINEAR = 1,
|
||||
};
|
||||
|
||||
enum pm_feature_config_id {
|
||||
PM_FEATURE_INVALID = 0,
|
||||
PM_FEATURE_OVERTEMP_STATUS = 1,
|
||||
PM_FEATURE_OVERTEMP_VALUE = 2,
|
||||
PM_FEATURE_EXTWDT_STATUS = 3,
|
||||
PM_FEATURE_EXTWDT_VALUE = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zynqmp_pm_query_data - PM query data
|
||||
* @qid: query ID
|
||||
|
|
@ -449,6 +460,8 @@ int zynqmp_pm_load_pdi(const u32 src, const u64 address);
|
|||
int zynqmp_pm_register_notifier(const u32 node, const u32 event,
|
||||
const u32 wake, const u32 enable);
|
||||
int zynqmp_pm_feature(const u32 api_id);
|
||||
int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value);
|
||||
int zynqmp_pm_get_feature_config(enum pm_feature_config_id id, u32 *payload);
|
||||
#else
|
||||
static inline int zynqmp_pm_get_api_version(u32 *version)
|
||||
{
|
||||
|
|
@ -697,6 +710,18 @@ static inline int zynqmp_pm_feature(const u32 api_id)
|
|||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int zynqmp_pm_set_feature_config(enum pm_feature_config_id id,
|
||||
u32 value)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,
|
||||
u32 *payload)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FIRMWARE_ZYNQMP_H__ */
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef QCOM_VADC_COMMON_H
|
||||
#define QCOM_VADC_COMMON_H
|
||||
|
||||
#include <linux/math.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define VADC_CONV_TIME_MIN_US 2000
|
||||
|
|
@ -79,16 +80,6 @@ struct vadc_linear_graph {
|
|||
s32 gnd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
|
||||
* @num: the inverse numerator of the gain applied to the input channel.
|
||||
* @den: the inverse denominator of the gain applied to the input channel.
|
||||
*/
|
||||
struct vadc_prescale_ratio {
|
||||
u32 num;
|
||||
u32 den;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum vadc_scale_fn_type - Scaling function to convert ADC code to
|
||||
* physical scaled units for the channel.
|
||||
|
|
@ -144,12 +135,12 @@ struct adc5_data {
|
|||
|
||||
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
|
||||
const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
const struct u32_fract *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result_mdec);
|
||||
|
||||
struct qcom_adc5_scale_type {
|
||||
int (*scale_fn)(const struct vadc_prescale_ratio *prescale,
|
||||
int (*scale_fn)(const struct u32_fract *prescale,
|
||||
const struct adc5_data *data, u16 adc_code, int *result);
|
||||
};
|
||||
|
||||
|
|
|
|||
36
include/linux/iio/afe/rescale.h
Normal file
36
include/linux/iio/afe/rescale.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2018 Axentia Technologies AB
|
||||
*/
|
||||
|
||||
#ifndef __IIO_RESCALE_H__
|
||||
#define __IIO_RESCALE_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
struct device;
|
||||
struct rescale;
|
||||
|
||||
struct rescale_cfg {
|
||||
enum iio_chan_type type;
|
||||
int (*props)(struct device *dev, struct rescale *rescale);
|
||||
};
|
||||
|
||||
struct rescale {
|
||||
const struct rescale_cfg *cfg;
|
||||
struct iio_channel *source;
|
||||
struct iio_chan_spec chan;
|
||||
struct iio_chan_spec_ext_info *ext_info;
|
||||
bool chan_processed;
|
||||
s32 numerator;
|
||||
s32 denominator;
|
||||
s32 offset;
|
||||
};
|
||||
|
||||
int rescale_process_scale(struct rescale *rescale, int scale_type,
|
||||
int *val, int *val2);
|
||||
int rescale_process_offset(struct rescale *rescale, int scale_type,
|
||||
int scale, int scale2, int schan_off,
|
||||
int *val, int *val2);
|
||||
#endif /* __IIO_RESCALE_H__ */
|
||||
|
|
@ -489,7 +489,7 @@ struct iio_buffer_setup_ops {
|
|||
/**
|
||||
* struct iio_dev - industrial I/O device
|
||||
* @modes: [DRIVER] operating modes supported by device
|
||||
* @currentmode: [DRIVER] current operating mode
|
||||
* @currentmode: [INTERN] current operating mode
|
||||
* @dev: [DRIVER] device structure, should be assigned a parent
|
||||
* and owner
|
||||
* @buffer: [DRIVER] any buffer present
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ struct adis_timeout {
|
|||
u16 sw_reset_ms;
|
||||
u16 self_test_ms;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adis_data - ADIS chip variant specific data
|
||||
* @read_delay: SPI delay for read operations in us
|
||||
|
|
@ -45,7 +46,7 @@ struct adis_timeout {
|
|||
* @self_test_mask: Bitmask of supported self-test operations
|
||||
* @self_test_reg: Register address to request self test command
|
||||
* @self_test_no_autoclear: True if device's self-test needs clear of ctrl reg
|
||||
* @status_error_msgs: Array of error messgaes
|
||||
* @status_error_msgs: Array of error messages
|
||||
* @status_error_mask: Bitmask of errors supported by the device
|
||||
* @timeouts: Chip specific delays
|
||||
* @enable_irq: Hook for ADIS devices that have a special IRQ enable/disable
|
||||
|
|
@ -130,12 +131,12 @@ struct adis {
|
|||
unsigned long irq_flag;
|
||||
void *buffer;
|
||||
|
||||
uint8_t tx[10] ____cacheline_aligned;
|
||||
uint8_t rx[4];
|
||||
u8 tx[10] ____cacheline_aligned;
|
||||
u8 rx[4];
|
||||
};
|
||||
|
||||
int adis_init(struct adis *adis, struct iio_dev *indio_dev,
|
||||
struct spi_device *spi, const struct adis_data *data);
|
||||
struct spi_device *spi, const struct adis_data *data);
|
||||
int __adis_reset(struct adis *adis);
|
||||
|
||||
/**
|
||||
|
|
@ -156,9 +157,9 @@ static inline int adis_reset(struct adis *adis)
|
|||
}
|
||||
|
||||
int __adis_write_reg(struct adis *adis, unsigned int reg,
|
||||
unsigned int val, unsigned int size);
|
||||
unsigned int val, unsigned int size);
|
||||
int __adis_read_reg(struct adis *adis, unsigned int reg,
|
||||
unsigned int *val, unsigned int size);
|
||||
unsigned int *val, unsigned int size);
|
||||
|
||||
/**
|
||||
* __adis_write_reg_8() - Write single byte to a register (unlocked)
|
||||
|
|
@ -167,7 +168,7 @@ int __adis_read_reg(struct adis *adis, unsigned int reg,
|
|||
* @value: The value to write
|
||||
*/
|
||||
static inline int __adis_write_reg_8(struct adis *adis, unsigned int reg,
|
||||
uint8_t val)
|
||||
u8 val)
|
||||
{
|
||||
return __adis_write_reg(adis, reg, val, 1);
|
||||
}
|
||||
|
|
@ -179,7 +180,7 @@ static inline int __adis_write_reg_8(struct adis *adis, unsigned int reg,
|
|||
* @value: Value to be written
|
||||
*/
|
||||
static inline int __adis_write_reg_16(struct adis *adis, unsigned int reg,
|
||||
uint16_t val)
|
||||
u16 val)
|
||||
{
|
||||
return __adis_write_reg(adis, reg, val, 2);
|
||||
}
|
||||
|
|
@ -191,7 +192,7 @@ static inline int __adis_write_reg_16(struct adis *adis, unsigned int reg,
|
|||
* @value: Value to be written
|
||||
*/
|
||||
static inline int __adis_write_reg_32(struct adis *adis, unsigned int reg,
|
||||
uint32_t val)
|
||||
u32 val)
|
||||
{
|
||||
return __adis_write_reg(adis, reg, val, 4);
|
||||
}
|
||||
|
|
@ -203,7 +204,7 @@ static inline int __adis_write_reg_32(struct adis *adis, unsigned int reg,
|
|||
* @val: The value read back from the device
|
||||
*/
|
||||
static inline int __adis_read_reg_16(struct adis *adis, unsigned int reg,
|
||||
uint16_t *val)
|
||||
u16 *val)
|
||||
{
|
||||
unsigned int tmp;
|
||||
int ret;
|
||||
|
|
@ -222,7 +223,7 @@ static inline int __adis_read_reg_16(struct adis *adis, unsigned int reg,
|
|||
* @val: The value read back from the device
|
||||
*/
|
||||
static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg,
|
||||
uint32_t *val)
|
||||
u32 *val)
|
||||
{
|
||||
unsigned int tmp;
|
||||
int ret;
|
||||
|
|
@ -242,7 +243,7 @@ static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg,
|
|||
* @size: The size of the @value (in bytes)
|
||||
*/
|
||||
static inline int adis_write_reg(struct adis *adis, unsigned int reg,
|
||||
unsigned int val, unsigned int size)
|
||||
unsigned int val, unsigned int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -261,7 +262,7 @@ static inline int adis_write_reg(struct adis *adis, unsigned int reg,
|
|||
* @size: The size of the @val buffer
|
||||
*/
|
||||
static int adis_read_reg(struct adis *adis, unsigned int reg,
|
||||
unsigned int *val, unsigned int size)
|
||||
unsigned int *val, unsigned int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -279,7 +280,7 @@ static int adis_read_reg(struct adis *adis, unsigned int reg,
|
|||
* @value: The value to write
|
||||
*/
|
||||
static inline int adis_write_reg_8(struct adis *adis, unsigned int reg,
|
||||
uint8_t val)
|
||||
u8 val)
|
||||
{
|
||||
return adis_write_reg(adis, reg, val, 1);
|
||||
}
|
||||
|
|
@ -291,7 +292,7 @@ static inline int adis_write_reg_8(struct adis *adis, unsigned int reg,
|
|||
* @value: Value to be written
|
||||
*/
|
||||
static inline int adis_write_reg_16(struct adis *adis, unsigned int reg,
|
||||
uint16_t val)
|
||||
u16 val)
|
||||
{
|
||||
return adis_write_reg(adis, reg, val, 2);
|
||||
}
|
||||
|
|
@ -303,7 +304,7 @@ static inline int adis_write_reg_16(struct adis *adis, unsigned int reg,
|
|||
* @value: Value to be written
|
||||
*/
|
||||
static inline int adis_write_reg_32(struct adis *adis, unsigned int reg,
|
||||
uint32_t val)
|
||||
u32 val)
|
||||
{
|
||||
return adis_write_reg(adis, reg, val, 4);
|
||||
}
|
||||
|
|
@ -315,7 +316,7 @@ static inline int adis_write_reg_32(struct adis *adis, unsigned int reg,
|
|||
* @val: The value read back from the device
|
||||
*/
|
||||
static inline int adis_read_reg_16(struct adis *adis, unsigned int reg,
|
||||
uint16_t *val)
|
||||
u16 *val)
|
||||
{
|
||||
unsigned int tmp;
|
||||
int ret;
|
||||
|
|
@ -334,7 +335,7 @@ static inline int adis_read_reg_16(struct adis *adis, unsigned int reg,
|
|||
* @val: The value read back from the device
|
||||
*/
|
||||
static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
|
||||
uint32_t *val)
|
||||
u32 *val)
|
||||
{
|
||||
unsigned int tmp;
|
||||
int ret;
|
||||
|
|
@ -381,10 +382,8 @@ static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
|
|||
* @val can lead to undesired behavior if the register to update is 16bit.
|
||||
*/
|
||||
#define adis_update_bits(adis, reg, mask, val) ({ \
|
||||
BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8); \
|
||||
__builtin_choose_expr(sizeof(val) == 4, \
|
||||
adis_update_bits_base(adis, reg, mask, val, 4), \
|
||||
adis_update_bits_base(adis, reg, mask, val, 2)); \
|
||||
BUILD_BUG_ON(sizeof(val) != 2 && sizeof(val) != 4); \
|
||||
adis_update_bits_base(adis, reg, mask, val, sizeof(val)); \
|
||||
})
|
||||
|
||||
/**
|
||||
|
|
@ -399,10 +398,8 @@ static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
|
|||
* @val can lead to undesired behavior if the register to update is 16bit.
|
||||
*/
|
||||
#define __adis_update_bits(adis, reg, mask, val) ({ \
|
||||
BUILD_BUG_ON(sizeof(val) == 1 || sizeof(val) == 8); \
|
||||
__builtin_choose_expr(sizeof(val) == 4, \
|
||||
__adis_update_bits_base(adis, reg, mask, val, 4), \
|
||||
__adis_update_bits_base(adis, reg, mask, val, 2)); \
|
||||
BUILD_BUG_ON(sizeof(val) != 2 && sizeof(val) != 4); \
|
||||
__adis_update_bits_base(adis, reg, mask, val, sizeof(val)); \
|
||||
})
|
||||
|
||||
int adis_enable_irq(struct adis *adis, bool enable);
|
||||
|
|
@ -443,8 +440,8 @@ static inline void adis_dev_unlock(struct adis *adis)
|
|||
}
|
||||
|
||||
int adis_single_conversion(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, unsigned int error_mask,
|
||||
int *val);
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int error_mask, int *val);
|
||||
|
||||
#define ADIS_VOLTAGE_CHAN(addr, si, chan, name, info_all, bits) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
|
|
@ -493,7 +490,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
|
|||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_ ## mod, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
info_sep, \
|
||||
(info_sep), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = info_all, \
|
||||
.address = (addr), \
|
||||
|
|
@ -527,7 +524,7 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
|
|||
int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
|
||||
|
||||
int adis_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask);
|
||||
const unsigned long *scan_mask);
|
||||
|
||||
#else /* CONFIG_IIO_BUFFER */
|
||||
|
||||
|
|
@ -551,7 +548,8 @@ static inline int devm_adis_probe_trigger(struct adis *adis,
|
|||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
int adis_debugfs_reg_access(struct iio_dev *indio_dev,
|
||||
unsigned int reg, unsigned int writeval, unsigned int *readval);
|
||||
unsigned int reg, unsigned int writeval,
|
||||
unsigned int *readval);
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
|||
|
|
@ -38,13 +38,6 @@ struct icc_bulk_data {
|
|||
u32 peak_bw;
|
||||
};
|
||||
|
||||
int __must_check of_icc_bulk_get(struct device *dev, int num_paths,
|
||||
struct icc_bulk_data *paths);
|
||||
void icc_bulk_put(int num_paths, struct icc_bulk_data *paths);
|
||||
int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths);
|
||||
int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths);
|
||||
void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths);
|
||||
|
||||
#if IS_ENABLED(CONFIG_INTERCONNECT)
|
||||
|
||||
struct icc_path *icc_get(struct device *dev, const int src_id,
|
||||
|
|
@ -58,6 +51,12 @@ int icc_disable(struct icc_path *path);
|
|||
int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw);
|
||||
void icc_set_tag(struct icc_path *path, u32 tag);
|
||||
const char *icc_get_name(struct icc_path *path);
|
||||
int __must_check of_icc_bulk_get(struct device *dev, int num_paths,
|
||||
struct icc_bulk_data *paths);
|
||||
void icc_bulk_put(int num_paths, struct icc_bulk_data *paths);
|
||||
int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths);
|
||||
int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths);
|
||||
void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths);
|
||||
|
||||
#else
|
||||
|
||||
|
|
@ -112,6 +111,29 @@ static inline const char *icc_get_name(struct icc_path *path)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline int of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void icc_bulk_put(int num_paths, struct icc_bulk_data *paths)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_INTERCONNECT */
|
||||
|
||||
#endif /* __LINUX_INTERCONNECT_H */
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#ifndef _LINUX_MATH_H
|
||||
#define _LINUX_MATH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/div64.h>
|
||||
#include <uapi/linux/kernel.h>
|
||||
|
||||
|
|
@ -106,6 +107,17 @@
|
|||
} \
|
||||
)
|
||||
|
||||
#define __STRUCT_FRACT(type) \
|
||||
struct type##_fract { \
|
||||
__##type numerator; \
|
||||
__##type denominator; \
|
||||
};
|
||||
__STRUCT_FRACT(s16)
|
||||
__STRUCT_FRACT(u16)
|
||||
__STRUCT_FRACT(s32)
|
||||
__STRUCT_FRACT(u32)
|
||||
#undef __STRUCT_FRACT
|
||||
|
||||
/*
|
||||
* Multiplies an integer by a fraction, while avoiding unnecessary
|
||||
* overflow or loss of precision.
|
||||
|
|
|
|||
|
|
@ -14,14 +14,19 @@
|
|||
|
||||
struct device;
|
||||
struct mux_control;
|
||||
struct mux_state;
|
||||
|
||||
unsigned int mux_control_states(struct mux_control *mux);
|
||||
int __must_check mux_control_select_delay(struct mux_control *mux,
|
||||
unsigned int state,
|
||||
unsigned int delay_us);
|
||||
int __must_check mux_state_select_delay(struct mux_state *mstate,
|
||||
unsigned int delay_us);
|
||||
int __must_check mux_control_try_select_delay(struct mux_control *mux,
|
||||
unsigned int state,
|
||||
unsigned int delay_us);
|
||||
int __must_check mux_state_try_select_delay(struct mux_state *mstate,
|
||||
unsigned int delay_us);
|
||||
|
||||
static inline int __must_check mux_control_select(struct mux_control *mux,
|
||||
unsigned int state)
|
||||
|
|
@ -29,18 +34,31 @@ static inline int __must_check mux_control_select(struct mux_control *mux,
|
|||
return mux_control_select_delay(mux, state, 0);
|
||||
}
|
||||
|
||||
static inline int __must_check mux_state_select(struct mux_state *mstate)
|
||||
{
|
||||
return mux_state_select_delay(mstate, 0);
|
||||
}
|
||||
|
||||
static inline int __must_check mux_control_try_select(struct mux_control *mux,
|
||||
unsigned int state)
|
||||
{
|
||||
return mux_control_try_select_delay(mux, state, 0);
|
||||
}
|
||||
|
||||
static inline int __must_check mux_state_try_select(struct mux_state *mstate)
|
||||
{
|
||||
return mux_state_try_select_delay(mstate, 0);
|
||||
}
|
||||
|
||||
int mux_control_deselect(struct mux_control *mux);
|
||||
int mux_state_deselect(struct mux_state *mstate);
|
||||
|
||||
struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
|
||||
void mux_control_put(struct mux_control *mux);
|
||||
|
||||
struct mux_control *devm_mux_control_get(struct device *dev,
|
||||
const char *mux_name);
|
||||
struct mux_state *devm_mux_state_get(struct device *dev,
|
||||
const char *mux_name);
|
||||
|
||||
#endif /* _LINUX_MUX_CONSUMER_H */
|
||||
|
|
|
|||
|
|
@ -135,8 +135,6 @@ void nvmem_unregister(struct nvmem_device *nvmem);
|
|||
struct nvmem_device *devm_nvmem_register(struct device *dev,
|
||||
const struct nvmem_config *cfg);
|
||||
|
||||
int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem);
|
||||
|
||||
void nvmem_add_cell_table(struct nvmem_cell_table *table);
|
||||
void nvmem_del_cell_table(struct nvmem_cell_table *table);
|
||||
|
||||
|
|
@ -155,12 +153,6 @@ devm_nvmem_register(struct device *dev, const struct nvmem_config *c)
|
|||
return nvmem_register(c);
|
||||
}
|
||||
|
||||
static inline int
|
||||
devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {}
|
||||
static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {}
|
||||
|
||||
|
|
|
|||
40
include/linux/peci-cpu.h
Normal file
40
include/linux/peci-cpu.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2021 Intel Corporation */
|
||||
|
||||
#ifndef __LINUX_PECI_CPU_H
|
||||
#define __LINUX_PECI_CPU_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../../arch/x86/include/asm/intel-family.h"
|
||||
|
||||
#define PECI_PCS_PKG_ID 0 /* Package Identifier Read */
|
||||
#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */
|
||||
#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */
|
||||
#define PECI_PKG_ID_DEVICE_ID 0x0002 /* Uncore Device ID */
|
||||
#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */
|
||||
#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */
|
||||
#define PECI_PKG_ID_MCA_ERROR_LOG 0x0005 /* Machine Check Status */
|
||||
#define PECI_PCS_MODULE_TEMP 9 /* Per Core DTS Temperature Read */
|
||||
#define PECI_PCS_THERMAL_MARGIN 10 /* DTS thermal margin */
|
||||
#define PECI_PCS_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */
|
||||
#define PECI_PCS_TEMP_TARGET 16 /* Temperature Target Read */
|
||||
#define PECI_PCS_TDP_UNITS 30 /* Units for power/energy registers */
|
||||
|
||||
struct peci_device;
|
||||
|
||||
int peci_temp_read(struct peci_device *device, s16 *temp_raw);
|
||||
|
||||
int peci_pcs_read(struct peci_device *device, u8 index,
|
||||
u16 param, u32 *data);
|
||||
|
||||
int peci_pci_local_read(struct peci_device *device, u8 bus, u8 dev,
|
||||
u8 func, u16 reg, u32 *data);
|
||||
|
||||
int peci_ep_pci_local_read(struct peci_device *device, u8 seg,
|
||||
u8 bus, u8 dev, u8 func, u16 reg, u32 *data);
|
||||
|
||||
int peci_mmio_read(struct peci_device *device, u8 bar, u8 seg,
|
||||
u8 bus, u8 dev, u8 func, u64 address, u32 *data);
|
||||
|
||||
#endif /* __LINUX_PECI_CPU_H */
|
||||
112
include/linux/peci.h
Normal file
112
include/linux/peci.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2018-2021 Intel Corporation */
|
||||
|
||||
#ifndef __LINUX_PECI_H
|
||||
#define __LINUX_PECI_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Currently we don't support any PECI command over 32 bytes.
|
||||
*/
|
||||
#define PECI_REQUEST_MAX_BUF_SIZE 32
|
||||
|
||||
struct peci_controller;
|
||||
struct peci_request;
|
||||
|
||||
/**
|
||||
* struct peci_controller_ops - PECI controller specific methods
|
||||
* @xfer: PECI transfer function
|
||||
*
|
||||
* PECI controllers may have different hardware interfaces - the drivers
|
||||
* implementing PECI controllers can use this structure to abstract away those
|
||||
* differences by exposing a common interface for PECI core.
|
||||
*/
|
||||
struct peci_controller_ops {
|
||||
int (*xfer)(struct peci_controller *controller, u8 addr, struct peci_request *req);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct peci_controller - PECI controller
|
||||
* @dev: device object to register PECI controller to the device model
|
||||
* @ops: pointer to device specific controller operations
|
||||
* @bus_lock: lock used to protect multiple callers
|
||||
* @id: PECI controller ID
|
||||
*
|
||||
* PECI controllers usually connect to their drivers using non-PECI bus,
|
||||
* such as the platform bus.
|
||||
* Each PECI controller can communicate with one or more PECI devices.
|
||||
*/
|
||||
struct peci_controller {
|
||||
struct device dev;
|
||||
struct peci_controller_ops *ops;
|
||||
struct mutex bus_lock; /* held for the duration of xfer */
|
||||
u8 id;
|
||||
};
|
||||
|
||||
struct peci_controller *devm_peci_controller_add(struct device *parent,
|
||||
struct peci_controller_ops *ops);
|
||||
|
||||
static inline struct peci_controller *to_peci_controller(void *d)
|
||||
{
|
||||
return container_of(d, struct peci_controller, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct peci_device - PECI device
|
||||
* @dev: device object to register PECI device to the device model
|
||||
* @controller: manages the bus segment hosting this PECI device
|
||||
* @info: PECI device characteristics
|
||||
* @info.family: device family
|
||||
* @info.model: device model
|
||||
* @info.peci_revision: PECI revision supported by the PECI device
|
||||
* @info.socket_id: the socket ID represented by the PECI device
|
||||
* @addr: address used on the PECI bus connected to the parent controller
|
||||
* @deleted: indicates that PECI device was already deleted
|
||||
*
|
||||
* A peci_device identifies a single device (i.e. CPU) connected to a PECI bus.
|
||||
* The behaviour exposed to the rest of the system is defined by the PECI driver
|
||||
* managing the device.
|
||||
*/
|
||||
struct peci_device {
|
||||
struct device dev;
|
||||
struct {
|
||||
u16 family;
|
||||
u8 model;
|
||||
u8 peci_revision;
|
||||
u8 socket_id;
|
||||
} info;
|
||||
u8 addr;
|
||||
bool deleted;
|
||||
};
|
||||
|
||||
static inline struct peci_device *to_peci_device(struct device *d)
|
||||
{
|
||||
return container_of(d, struct peci_device, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct peci_request - PECI request
|
||||
* @device: PECI device to which the request is sent
|
||||
* @tx: TX buffer specific data
|
||||
* @tx.buf: TX buffer
|
||||
* @tx.len: transfer data length in bytes
|
||||
* @rx: RX buffer specific data
|
||||
* @rx.buf: RX buffer
|
||||
* @rx.len: received data length in bytes
|
||||
*
|
||||
* A peci_request represents a request issued by PECI originator (TX) and
|
||||
* a response received from PECI responder (RX).
|
||||
*/
|
||||
struct peci_request {
|
||||
struct peci_device *device;
|
||||
struct {
|
||||
u8 buf[PECI_REQUEST_MAX_BUF_SIZE];
|
||||
u8 len;
|
||||
} rx, tx;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_PECI_H */
|
||||
|
|
@ -1095,7 +1095,7 @@ struct pcr_ops {
|
|||
unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr);
|
||||
int (*conv_clk_and_div_n)(int clk, int dir);
|
||||
void (*fetch_vendor_settings)(struct rtsx_pcr *pcr);
|
||||
void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
|
||||
void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state, bool runtime);
|
||||
void (*stop_cmd)(struct rtsx_pcr *pcr);
|
||||
|
||||
void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
|
||||
|
|
@ -1201,8 +1201,6 @@ struct rtsx_pcr {
|
|||
unsigned int card_exist;
|
||||
|
||||
struct delayed_work carddet_work;
|
||||
struct delayed_work idle_work;
|
||||
struct delayed_work rtd3_work;
|
||||
|
||||
spinlock_t lock;
|
||||
struct mutex pcr_mutex;
|
||||
|
|
@ -1212,7 +1210,6 @@ struct rtsx_pcr {
|
|||
unsigned int cur_clock;
|
||||
bool remove_pci;
|
||||
bool msi_en;
|
||||
bool is_runtime_suspended;
|
||||
|
||||
#define EXTRA_CAPS_SD_SDR50 (1 << 0)
|
||||
#define EXTRA_CAPS_SD_SDR104 (1 << 1)
|
||||
|
|
|
|||
|
|
@ -12,15 +12,20 @@
|
|||
#include <linux/bits.h>
|
||||
|
||||
/* Register offsets. */
|
||||
#define VMCI_STATUS_ADDR 0x00
|
||||
#define VMCI_CONTROL_ADDR 0x04
|
||||
#define VMCI_ICR_ADDR 0x08
|
||||
#define VMCI_IMR_ADDR 0x0c
|
||||
#define VMCI_DATA_OUT_ADDR 0x10
|
||||
#define VMCI_DATA_IN_ADDR 0x14
|
||||
#define VMCI_CAPS_ADDR 0x18
|
||||
#define VMCI_RESULT_LOW_ADDR 0x1c
|
||||
#define VMCI_RESULT_HIGH_ADDR 0x20
|
||||
#define VMCI_STATUS_ADDR 0x00
|
||||
#define VMCI_CONTROL_ADDR 0x04
|
||||
#define VMCI_ICR_ADDR 0x08
|
||||
#define VMCI_IMR_ADDR 0x0c
|
||||
#define VMCI_DATA_OUT_ADDR 0x10
|
||||
#define VMCI_DATA_IN_ADDR 0x14
|
||||
#define VMCI_CAPS_ADDR 0x18
|
||||
#define VMCI_RESULT_LOW_ADDR 0x1c
|
||||
#define VMCI_RESULT_HIGH_ADDR 0x20
|
||||
#define VMCI_DATA_OUT_LOW_ADDR 0x24
|
||||
#define VMCI_DATA_OUT_HIGH_ADDR 0x28
|
||||
#define VMCI_DATA_IN_LOW_ADDR 0x2c
|
||||
#define VMCI_DATA_IN_HIGH_ADDR 0x30
|
||||
#define VMCI_GUEST_PAGE_SHIFT 0x34
|
||||
|
||||
/* Max number of devices. */
|
||||
#define VMCI_MAX_DEVICES 1
|
||||
|
|
@ -39,17 +44,27 @@
|
|||
#define VMCI_CAPS_DATAGRAM BIT(2)
|
||||
#define VMCI_CAPS_NOTIFICATIONS BIT(3)
|
||||
#define VMCI_CAPS_PPN64 BIT(4)
|
||||
#define VMCI_CAPS_DMA_DATAGRAM BIT(5)
|
||||
|
||||
/* Interrupt Cause register bits. */
|
||||
#define VMCI_ICR_DATAGRAM BIT(0)
|
||||
#define VMCI_ICR_NOTIFICATION BIT(1)
|
||||
#define VMCI_ICR_DMA_DATAGRAM BIT(2)
|
||||
|
||||
/* Interrupt Mask register bits. */
|
||||
#define VMCI_IMR_DATAGRAM BIT(0)
|
||||
#define VMCI_IMR_NOTIFICATION BIT(1)
|
||||
#define VMCI_IMR_DMA_DATAGRAM BIT(2)
|
||||
|
||||
/* Maximum MSI/MSI-X interrupt vectors in the device. */
|
||||
#define VMCI_MAX_INTRS 2
|
||||
/*
|
||||
* Maximum MSI/MSI-X interrupt vectors in the device.
|
||||
* If VMCI_CAPS_DMA_DATAGRAM is supported by the device,
|
||||
* VMCI_MAX_INTRS_DMA_DATAGRAM vectors are available,
|
||||
* otherwise only VMCI_MAX_INTRS_NOTIFICATION.
|
||||
*/
|
||||
#define VMCI_MAX_INTRS_NOTIFICATION 2
|
||||
#define VMCI_MAX_INTRS_DMA_DATAGRAM 3
|
||||
#define VMCI_MAX_INTRS VMCI_MAX_INTRS_DMA_DATAGRAM
|
||||
|
||||
/*
|
||||
* Supported interrupt vectors. There is one for each ICR value above,
|
||||
|
|
@ -58,6 +73,7 @@
|
|||
enum {
|
||||
VMCI_INTR_DATAGRAM = 0,
|
||||
VMCI_INTR_NOTIFICATION = 1,
|
||||
VMCI_INTR_DMA_DATAGRAM = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -82,6 +98,52 @@ enum {
|
|||
*/
|
||||
#define VMCI_MAX_PINNED_QP_MEMORY ((size_t)(32 * 1024))
|
||||
|
||||
/*
|
||||
* The version of the VMCI device that supports MMIO access to registers
|
||||
* requests 256KB for BAR1 whereas the version of VMCI that supports
|
||||
* MSI/MSI-X only requests 8KB. The layout of the larger 256KB region is:
|
||||
* - the first 128KB are used for MSI/MSI-X.
|
||||
* - the following 64KB are used for MMIO register access.
|
||||
* - the remaining 64KB are unused.
|
||||
*/
|
||||
#define VMCI_WITH_MMIO_ACCESS_BAR_SIZE ((size_t)(256 * 1024))
|
||||
#define VMCI_MMIO_ACCESS_OFFSET ((size_t)(128 * 1024))
|
||||
#define VMCI_MMIO_ACCESS_SIZE ((size_t)(64 * 1024))
|
||||
|
||||
/*
|
||||
* For VMCI devices supporting the VMCI_CAPS_DMA_DATAGRAM capability, the
|
||||
* sending and receiving of datagrams can be performed using DMA to/from
|
||||
* a driver allocated buffer.
|
||||
* Sending and receiving will be handled as follows:
|
||||
* - when sending datagrams, the driver initializes the buffer where the
|
||||
* data part will refer to the outgoing VMCI datagram, sets the busy flag
|
||||
* to 1 and writes the address of the buffer to VMCI_DATA_OUT_HIGH_ADDR
|
||||
* and VMCI_DATA_OUT_LOW_ADDR. Writing to VMCI_DATA_OUT_LOW_ADDR triggers
|
||||
* the device processing of the buffer. When the device has processed the
|
||||
* buffer, it will write the result value to the buffer and then clear the
|
||||
* busy flag.
|
||||
* - when receiving datagrams, the driver initializes the buffer where the
|
||||
* data part will describe the receive buffer, clears the busy flag and
|
||||
* writes the address of the buffer to VMCI_DATA_IN_HIGH_ADDR and
|
||||
* VMCI_DATA_IN_LOW_ADDR. Writing to VMCI_DATA_IN_LOW_ADDR triggers the
|
||||
* device processing of the buffer. The device will copy as many available
|
||||
* datagrams into the buffer as possible, and then sets the busy flag.
|
||||
* When the busy flag is set, the driver will process the datagrams in the
|
||||
* buffer.
|
||||
*/
|
||||
struct vmci_data_in_out_header {
|
||||
uint32_t busy;
|
||||
uint32_t opcode;
|
||||
uint32_t size;
|
||||
uint32_t rsvd;
|
||||
uint64_t result;
|
||||
};
|
||||
|
||||
struct vmci_sg_elem {
|
||||
uint64_t addr;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
/*
|
||||
* We have a fixed set of resource IDs available in the VMX.
|
||||
* This allows us to have a very simple implementation since we statically
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue