Commit 21cbc105 authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'scmi-updates-6.10' of...

Merge tag 'scmi-updates-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers

Arm SCMI updates for v6.10

1. Basic support for SCMI v3.2 pincontrol protocol

   SCMI v3.2 introduces pincontrol protocol which is intended for
   controlling pins and their configuration. The pin control protocol
   provides commands to:
   - List the pins, groups of pins, available functions, and their
     association with each other.
   - Set the parameter configuration and multiplexing of the pins or
     groups of pins
   - Optionally request exclusive access to a pin or group of pins.
   - Optionally configure the permissions of an agent to access a pin
     or group of pins.

  These changes adds basic support for the same in the SCMI core layer
  and an implementation of the generic scmi-pinctrl driver with associated
  DT bindings.

2. Framework support for multiple vendors custom protocols

   With the fixed space for vendor protocols, the possibility of having
   multiple vendors implementing distinct SCMI vendor protocols with
   the same overlapping protocol number is very high and with the need
   to support them all in a single kernel image or a module is also high.

   In order to implement the same we assume:
   - vendor protocols has to be tagged at build time with a vendor_id
   - vendor protocols could also optionally be tagged at build time with
     sub_vendor_id and implementation version

  At the initialisation all the built vendor protocols are registered
  with the SCMI core using a key derived from the above tags

3. Logging and tracing improvements

   This includes using dev_err_probe() to bail out from probe, adding
   message dump traces for bad and unexpected replies and widening of
   the tag buffer in trace_scmi_dump_msg to allow diverse tag names

4. Miscellaneous updates or improvements

   This includes adding the accessor function get_max_msg_size() used
   in pinctl protocol, updation of dt-bindings examples for protocol@13
   to promote new bindings and simplification of scmi_devm_notifier_unregister

* tag 'scmi-updates-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  pinctrl: Implementation of the generic scmi-pinctrl driver
  firmware: arm_scmi: Add basic support for SCMI v3.2 pincontrol protocol
  dt-bindings: firmware: Support SCMI pinctrl protocol
  firmware: arm_scmi: Introduce get_max_msg_size() helper/accessor
  firmware: arm_scmi: Add support for multiple vendors custom protocols
  dt-bindings: firmware: arm,scmi: Update examples for protocol@13
  firmware: arm_scmi: Avoid non-constant printk format strings
  firmware: arm_scmi: Use dev_err_probe to bail out
  firmware: arm_scmi: Simplify scmi_devm_notifier_unregister
  firmware: arm_scmi: Add message dump traces for bad and unexpected replies
  firmware: arm_scmi: Add helper to trace bad messages
  include: trace: Widen the tag buffer in trace_scmi_dump_msg
  firmware: arm_scmi: Log the perf domain names in the error paths

Link: https://lore.kernel.org/r/20240426105031.1526987-1-sudeep.holla@arm.comSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 40b561e5 eb524cb6
......@@ -247,6 +247,37 @@ properties:
reg:
const: 0x18
protocol@19:
type: object
allOf:
- $ref: '#/$defs/protocol-node'
- $ref: /schemas/pinctrl/pinctrl.yaml
unevaluatedProperties: false
properties:
reg:
const: 0x19
patternProperties:
'-pins$':
type: object
allOf:
- $ref: /schemas/pinctrl/pincfg-node.yaml#
- $ref: /schemas/pinctrl/pinmux-node.yaml#
unevaluatedProperties: false
description:
A pin multiplexing sub-node describes how to configure a
set of pins in some desired function.
A single sub-node may define several pin configurations.
This sub-node is using the default pinctrl bindings to configure
pin multiplexing and using SCMI protocol to apply a specified
configuration.
required:
- reg
additionalProperties: false
$defs:
......@@ -355,7 +386,7 @@ examples:
scmi_dvfs: protocol@13 {
reg = <0x13>;
#clock-cells = <1>;
#power-domain-cells = <1>;
mboxes = <&mhuB 1 0>,
<&mhuB 1 1>;
......@@ -401,6 +432,25 @@ examples:
scmi_powercap: protocol@18 {
reg = <0x18>;
};
scmi_pinctrl: protocol@19 {
reg = <0x19>;
i2c2-pins {
groups = "g_i2c2_a", "g_i2c2_b";
function = "f_i2c2";
};
mdio-pins {
groups = "g_avb_mdio";
drive-strength = <24>;
};
keys_pins: keys-pins {
pins = "gpio_5_17", "gpio_5_20", "gpio_5_22", "gpio_2_1";
bias-pull-up;
};
};
};
};
......@@ -468,7 +518,7 @@ examples:
reg = <0x13>;
linaro,optee-channel-id = <1>;
shmem = <&cpu_optee_lpri0>;
#clock-cells = <1>;
#power-domain-cells = <1>;
};
scmi_clk0: protocol@14 {
......
......@@ -21522,6 +21522,7 @@ F: drivers/cpufreq/sc[mp]i-cpufreq.c
F: drivers/firmware/arm_scmi/
F: drivers/firmware/arm_scpi.c
F: drivers/hwmon/scmi-hwmon.c
F: drivers/pinctrl/pinctrl-scmi.c
F: drivers/pmdomain/arm/
F: drivers/powercap/arm_scmi_powercap.c
F: drivers/regulator/scmi-regulator.c
......
......@@ -10,7 +10,8 @@ scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o
scmi-protocols-y := base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o
scmi-protocols-y += pinctrl.o
scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y)
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o
......
......@@ -301,6 +301,17 @@ extern const struct scmi_desc scmi_optee_desc;
void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv);
enum scmi_bad_msg {
MSG_UNEXPECTED = -1,
MSG_INVALID = -2,
MSG_UNKNOWN = -3,
MSG_NOMEM = -4,
MSG_MBOX_SPURIOUS = -5,
};
void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr,
enum scmi_bad_msg err);
/* shmem related declarations */
struct scmi_shared_mem;
......
This diff is collapsed.
......@@ -56,6 +56,9 @@ static void rx_callback(struct mbox_client *cl, void *m)
*/
if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) {
dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n");
scmi_bad_message_trace(smbox->cinfo,
shmem_read_header(smbox->shmem),
MSG_MBOX_SPURIOUS);
return;
}
......
......@@ -1513,17 +1513,12 @@ static int scmi_devm_notifier_register(struct scmi_device *sdev,
static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
{
struct scmi_notifier_devres *dres = res;
struct scmi_notifier_devres *xres = data;
struct notifier_block *nb = data;
if (WARN_ON(!dres || !xres))
if (WARN_ON(!dres || !nb))
return 0;
return dres->proto_id == xres->proto_id &&
dres->evt_id == xres->evt_id &&
dres->nb == xres->nb &&
((!dres->src_id && !xres->src_id) ||
(dres->src_id && xres->src_id &&
dres->__src_id == xres->__src_id));
return dres->nb == nb;
}
/**
......@@ -1531,10 +1526,6 @@ static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
* notifier_block for an event
* @sdev: A reference to an scmi_device whose embedded struct device is to
* be used for devres accounting.
* @proto_id: Protocol ID
* @evt_id: Event ID
* @src_id: Source ID, when NULL register for events coming form ALL possible
* sources
* @nb: A standard notifier block to register for the specified event
*
* Generic devres managed helper to explicitly un-register a notifier_block
......@@ -1544,25 +1535,12 @@ static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
* Return: 0 on Success
*/
static int scmi_devm_notifier_unregister(struct scmi_device *sdev,
u8 proto_id, u8 evt_id,
const u32 *src_id,
struct notifier_block *nb)
{
int ret;
struct scmi_notifier_devres dres;
dres.handle = sdev->handle;
dres.proto_id = proto_id;
dres.evt_id = evt_id;
if (src_id) {
dres.__src_id = *src_id;
dres.src_id = &dres.__src_id;
} else {
dres.src_id = NULL;
}
ret = devres_release(&sdev->dev, scmi_devm_release_notifier,
scmi_devm_notifier_match, &dres);
scmi_devm_notifier_match, nb);
WARN_ON(ret);
......
......@@ -387,8 +387,8 @@ process_response_opp(struct device *dev, struct perf_dom_info *dom,
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
if (ret)
dev_warn(dev, "Failed to add opps_by_lvl at %d - ret:%d\n",
opp->perf, ret);
dev_warn(dev, "Failed to add opps_by_lvl at %d for %s - ret:%d\n",
opp->perf, dom->info.name, ret);
}
static inline void
......@@ -405,8 +405,8 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
if (ret)
dev_warn(dev, "Failed to add opps_by_lvl at %d - ret:%d\n",
opp->perf, ret);
dev_warn(dev, "Failed to add opps_by_lvl at %d for %s - ret:%d\n",
opp->perf, dom->info.name, ret);
/* Note that PERF v4 reports always five 32-bit words */
opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq);
......@@ -417,8 +417,8 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
GFP_KERNEL);
if (ret)
dev_warn(dev,
"Failed to add opps_by_idx at %d - ret:%d\n",
opp->level_index, ret);
"Failed to add opps_by_idx at %d for %s - ret:%d\n",
opp->level_index, dom->info.name, ret);
hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq);
}
......@@ -879,7 +879,8 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
ret = dev_pm_opp_add_dynamic(dev, &data);
if (ret) {
dev_warn(dev, "failed to add opp %luHz\n", freq);
dev_warn(dev, "[%d][%s]: Failed to add OPP[%d] %lu\n",
domain, dom->info.name, idx, freq);
dev_pm_opp_remove_all_dynamic(dev);
return ret;
}
......
This diff is collapsed.
......@@ -29,6 +29,8 @@
#define PROTOCOL_REV_MAJOR(x) ((u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x))))
#define PROTOCOL_REV_MINOR(x) ((u16)(FIELD_GET(PROTOCOL_REV_MINOR_MASK, (x))))
#define SCMI_PROTOCOL_VENDOR_BASE 0x80
enum scmi_common_cmd {
PROTOCOL_VERSION = 0x0,
PROTOCOL_ATTRIBUTES = 0x1,
......@@ -258,6 +260,7 @@ struct scmi_fc_info {
* @fastchannel_init: A common helper used to initialize FC descriptors by
* gathering FC descriptions from the SCMI platform server.
* @fastchannel_db_ring: A common helper to ring a FC doorbell.
* @get_max_msg_size: A common helper to get the maximum message size.
*/
struct scmi_proto_helpers_ops {
int (*extended_name_get)(const struct scmi_protocol_handle *ph,
......@@ -277,6 +280,7 @@ struct scmi_proto_helpers_ops {
struct scmi_fc_db_info **p_db,
u32 *rate_limit);
void (*fastchannel_db_ring)(struct scmi_fc_db_info *db);
int (*get_max_msg_size)(const struct scmi_protocol_handle *ph);
};
/**
......@@ -323,6 +327,16 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
* protocol by the agent. Each protocol implementation
* in the agent is supposed to downgrade to match the
* protocol version supported by the platform.
* @vendor_id: A firmware vendor string for vendor protocols matching.
* Ignored when @id identifies a standard protocol, cannot be NULL
* otherwise.
* @sub_vendor_id: A firmware sub_vendor string for vendor protocols matching.
* Ignored if NULL or when @id identifies a standard protocol.
* @impl_ver: A firmware implementation version for vendor protocols matching.
* Ignored if zero or if @id identifies a standard protocol.
*
* Note that vendor protocols matching at load time is performed by attempting
* the closest match first against the tuple (vendor, sub_vendor, impl_ver)
*/
struct scmi_protocol {
const u8 id;
......@@ -332,6 +346,9 @@ struct scmi_protocol {
const void *ops;
const struct scmi_protocol_events *events;
unsigned int supported_version;
char *vendor_id;
char *sub_vendor_id;
u32 impl_ver;
};
#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(name, proto) \
......@@ -353,6 +370,7 @@ void __exit scmi_##name##_unregister(void) \
DECLARE_SCMI_REGISTER_UNREGISTER(base);
DECLARE_SCMI_REGISTER_UNREGISTER(clock);
DECLARE_SCMI_REGISTER_UNREGISTER(perf);
DECLARE_SCMI_REGISTER_UNREGISTER(pinctrl);
DECLARE_SCMI_REGISTER_UNREGISTER(power);
DECLARE_SCMI_REGISTER_UNREGISTER(reset);
DECLARE_SCMI_REGISTER_UNREGISTER(sensors);
......
......@@ -450,6 +450,17 @@ config PINCTRL_ROCKCHIP
help
This support pinctrl and GPIO driver for Rockchip SoCs.
config PINCTRL_SCMI
tristate "Pinctrl driver using SCMI protocol interface"
depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
select PINMUX
select GENERIC_PINCONF
help
This driver provides support for pinctrl which is controlled
by firmware that implements the SCMI interface.
It uses SCMI Message Protocol to interact with the
firmware providing all the pinctrl controls.
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
......
......@@ -45,6 +45,7 @@ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o
obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SCMI) += pinctrl-scmi.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o
......
This diff is collapsed.
......@@ -737,6 +737,89 @@ struct scmi_powercap_proto_ops {
u32 *power_thresh_high);
};
enum scmi_pinctrl_selector_type {
PIN_TYPE = 0,
GROUP_TYPE,
FUNCTION_TYPE,
};
enum scmi_pinctrl_conf_type {
SCMI_PIN_DEFAULT = 0,
SCMI_PIN_BIAS_BUS_HOLD = 1,
SCMI_PIN_BIAS_DISABLE = 2,
SCMI_PIN_BIAS_HIGH_IMPEDANCE = 3,
SCMI_PIN_BIAS_PULL_UP = 4,
SCMI_PIN_BIAS_PULL_DEFAULT = 5,
SCMI_PIN_BIAS_PULL_DOWN = 6,
SCMI_PIN_DRIVE_OPEN_DRAIN = 7,
SCMI_PIN_DRIVE_OPEN_SOURCE = 8,
SCMI_PIN_DRIVE_PUSH_PULL = 9,
SCMI_PIN_DRIVE_STRENGTH = 10,
SCMI_PIN_INPUT_DEBOUNCE = 11,
SCMI_PIN_INPUT_MODE = 12,
SCMI_PIN_PULL_MODE = 13,
SCMI_PIN_INPUT_VALUE = 14,
SCMI_PIN_INPUT_SCHMITT = 15,
SCMI_PIN_LOW_POWER_MODE = 16,
SCMI_PIN_OUTPUT_MODE = 17,
SCMI_PIN_OUTPUT_VALUE = 18,
SCMI_PIN_POWER_SOURCE = 19,
SCMI_PIN_SLEW_RATE = 20,
SCMI_PIN_OEM_START = 192,
SCMI_PIN_OEM_END = 255,
};
/**
* struct scmi_pinctrl_proto_ops - represents the various operations provided
* by SCMI Pinctrl Protocol
*
* @count_get: returns count of the registered elements in given type
* @name_get: returns name by index of given type
* @group_pins_get: returns the set of pins, assigned to the specified group
* @function_groups_get: returns the set of groups, assigned to the specified
* function
* @mux_set: set muxing function for groups of pins
* @settings_get_one: returns one configuration parameter for pin or group
* specified by config_type
* @settings_get_all: returns all configuration parameters for pin or group
* @settings_conf: sets the configuration parameter for pin or group
* @pin_request: aquire pin before selecting mux setting
* @pin_free: frees pin, acquired by request_pin call
*/
struct scmi_pinctrl_proto_ops {
int (*count_get)(const struct scmi_protocol_handle *ph,
enum scmi_pinctrl_selector_type type);
int (*name_get)(const struct scmi_protocol_handle *ph, u32 selector,
enum scmi_pinctrl_selector_type type,
const char **name);
int (*group_pins_get)(const struct scmi_protocol_handle *ph,
u32 selector, const unsigned int **pins,
unsigned int *nr_pins);
int (*function_groups_get)(const struct scmi_protocol_handle *ph,
u32 selector, unsigned int *nr_groups,
const unsigned int **groups);
int (*mux_set)(const struct scmi_protocol_handle *ph, u32 selector,
u32 group);
int (*settings_get_one)(const struct scmi_protocol_handle *ph,
u32 selector,
enum scmi_pinctrl_selector_type type,
enum scmi_pinctrl_conf_type config_type,
u32 *config_value);
int (*settings_get_all)(const struct scmi_protocol_handle *ph,
u32 selector,
enum scmi_pinctrl_selector_type type,
unsigned int *nr_configs,
enum scmi_pinctrl_conf_type *config_types,
u32 *config_values);
int (*settings_conf)(const struct scmi_protocol_handle *ph,
u32 selector, enum scmi_pinctrl_selector_type type,
unsigned int nr_configs,
enum scmi_pinctrl_conf_type *config_type,
u32 *config_value);
int (*pin_request)(const struct scmi_protocol_handle *ph, u32 pin);
int (*pin_free)(const struct scmi_protocol_handle *ph, u32 pin);
};
/**
* struct scmi_notify_ops - represents notifications' operations provided by
* SCMI core
......@@ -783,8 +866,6 @@ struct scmi_notify_ops {
const u32 *src_id,
struct notifier_block *nb);
int (*devm_event_notifier_unregister)(struct scmi_device *sdev,
u8 proto_id, u8 evt_id,
const u32 *src_id,
struct notifier_block *nb);
int (*event_notifier_register)(const struct scmi_handle *handle,
u8 proto_id, u8 evt_id,
......@@ -844,6 +925,7 @@ enum scmi_std_protocol {
SCMI_PROTOCOL_RESET = 0x16,
SCMI_PROTOCOL_VOLTAGE = 0x17,
SCMI_PROTOCOL_POWERCAP = 0x18,
SCMI_PROTOCOL_PINCTRL = 0x19,
};
enum scmi_system_events {
......
......@@ -7,6 +7,8 @@
#include <linux/tracepoint.h>
#define TRACE_SCMI_MAX_TAG_LEN 6
TRACE_EVENT(scmi_fc_call,
TP_PROTO(u8 protocol_id, u8 msg_id, u32 res_id, u32 val1, u32 val2),
TP_ARGS(protocol_id, msg_id, res_id, val1, val2),
......@@ -150,7 +152,7 @@ TRACE_EVENT(scmi_msg_dump,
__field(u8, channel_id)
__field(u8, protocol_id)
__field(u8, msg_id)
__array(char, tag, 5)
__array(char, tag, TRACE_SCMI_MAX_TAG_LEN)
__field(u16, seq)
__field(int, status)
__field(size_t, len)
......@@ -162,7 +164,7 @@ TRACE_EVENT(scmi_msg_dump,
__entry->channel_id = channel_id;
__entry->protocol_id = protocol_id;
__entry->msg_id = msg_id;
strscpy(__entry->tag, tag, 5);
strscpy(__entry->tag, tag, TRACE_SCMI_MAX_TAG_LEN);
__entry->seq = seq;
__entry->status = status;
__entry->len = len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment