diff options
Diffstat (limited to 'drivers')
55 files changed, 2743 insertions, 306 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index e6742998f372..d5e7fa9173a1 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -186,11 +186,12 @@ config SUNXI_RSB config TEGRA_ACONNECT tristate "Tegra ACONNECT Bus Driver" - depends on ARCH_TEGRA_210_SOC + depends on ARCH_TEGRA depends on OF && PM help Driver for the Tegra ACONNECT bus which is used to interface with - the devices inside the Audio Processing Engine (APE) for Tegra210. + the devices inside the Audio Processing Engine (APE) for + Tegra210 and later. config TEGRA_GMI tristate "Tegra Generic Memory Interface bus driver" diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index fd3e9d82340a..1e29ba76615d 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -128,7 +128,7 @@ struct sunxi_rsb { }; /* bus / slave device related functions */ -static struct bus_type sunxi_rsb_bus; +static const struct bus_type sunxi_rsb_bus; static int sunxi_rsb_device_match(struct device *dev, struct device_driver *drv) { @@ -177,7 +177,7 @@ static int sunxi_rsb_device_modalias(const struct device *dev, struct kobj_ueven return of_device_uevent_modalias(dev, env); } -static struct bus_type sunxi_rsb_bus = { +static const struct bus_type sunxi_rsb_bus = { .name = RSB_CTRL_NAME, .match = sunxi_rsb_device_match, .probe = sunxi_rsb_device_probe, diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 245e5e827d0d..41d33f39efe5 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -2400,7 +2400,7 @@ static int sysc_child_add_clocks(struct sysc *ddata, return 0; } -static struct device_type sysc_device_type = { +static const struct device_type sysc_device_type = { }; static struct sysc *sysc_child_to_parent(struct device *dev) diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c index 1c7940ba5539..2f557e90f2eb 100644 --- a/drivers/firmware/arm_ffa/bus.c +++ b/drivers/firmware/arm_ffa/bus.c @@ -105,7 +105,7 @@ static struct attribute *ffa_device_attributes_attrs[] = { }; ATTRIBUTE_GROUPS(ffa_device_attributes); -struct bus_type ffa_bus_type = { +const struct bus_type ffa_bus_type = { .name = "arm_ffa", .match = ffa_device_match, .probe = ffa_device_probe, diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index c15928b8c5cc..77c78be6e79c 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -141,6 +141,17 @@ out: return ret; } +static int scmi_protocol_table_register(const struct scmi_device_id *id_table) +{ + int ret = 0; + const struct scmi_device_id *entry; + + for (entry = id_table; entry->name && ret == 0; entry++) + ret = scmi_protocol_device_request(entry); + + return ret; +} + /** * scmi_protocol_device_unrequest - Helper to unrequest a device * @@ -186,6 +197,15 @@ static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table mutex_unlock(&scmi_requested_devices_mtx); } +static void +scmi_protocol_table_unregister(const struct scmi_device_id *id_table) +{ + const struct scmi_device_id *entry; + + for (entry = id_table; entry->name; entry++) + scmi_protocol_device_unrequest(entry); +} + static const struct scmi_device_id * scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv) { @@ -263,7 +283,7 @@ static void scmi_dev_remove(struct device *dev) scmi_drv->remove(scmi_dev); } -struct bus_type scmi_bus_type = { +const struct bus_type scmi_bus_type = { .name = "scmi_protocol", .match = scmi_dev_match, .probe = scmi_dev_probe, @@ -279,7 +299,7 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner, if (!driver->probe) return -EINVAL; - retval = scmi_protocol_device_request(driver->id_table); + retval = scmi_protocol_table_register(driver->id_table); if (retval) return retval; @@ -299,7 +319,7 @@ EXPORT_SYMBOL_GPL(scmi_driver_register); void scmi_driver_unregister(struct scmi_driver *driver) { driver_unregister(&driver->driver); - scmi_protocol_device_unrequest(driver->id_table); + scmi_protocol_table_unregister(driver->id_table); } EXPORT_SYMBOL_GPL(scmi_driver_unregister); diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index e2050adbf85c..134019297d08 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -13,7 +13,7 @@ #include "notify.h" /* Updated only after ALL the mandatory features for that version are merged */ -#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 enum scmi_clock_protocol_cmd { CLOCK_ATTRIBUTES = 0x3, @@ -28,8 +28,13 @@ enum scmi_clock_protocol_cmd { CLOCK_POSSIBLE_PARENTS_GET = 0xC, CLOCK_PARENT_SET = 0xD, CLOCK_PARENT_GET = 0xE, + CLOCK_GET_PERMISSIONS = 0xF, }; +#define CLOCK_STATE_CONTROL_ALLOWED BIT(31) +#define CLOCK_PARENT_CONTROL_ALLOWED BIT(30) +#define CLOCK_RATE_CONTROL_ALLOWED BIT(29) + enum clk_state { CLK_STATE_DISABLE, CLK_STATE_ENABLE, @@ -49,6 +54,8 @@ struct scmi_msg_resp_clock_attributes { #define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x) ((x) & BIT(30)) #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) #define SUPPORTS_PARENT_CLOCK(x) ((x) & BIT(28)) +#define SUPPORTS_EXTENDED_CONFIG(x) ((x) & BIT(27)) +#define SUPPORTS_GET_PERMISSIONS(x) ((x) & BIT(1)) u8 name[SCMI_SHORT_NAME_MAX_SIZE]; __le32 clock_enable_latency; }; @@ -152,14 +159,18 @@ struct clock_info { u32 version; int num_clocks; int max_async_req; + bool notify_rate_changed_cmd; + bool notify_rate_change_requested_cmd; atomic_t cur_async_req; struct scmi_clock_info *clk; int (*clock_config_set)(const struct scmi_protocol_handle *ph, u32 clk_id, enum clk_state state, - u8 oem_type, u32 oem_val, bool atomic); + enum scmi_clock_oem_config oem_type, + u32 oem_val, bool atomic); int (*clock_config_get)(const struct scmi_protocol_handle *ph, - u32 clk_id, u8 oem_type, u32 *attributes, - bool *enabled, u32 *oem_val, bool atomic); + u32 clk_id, enum scmi_clock_oem_config oem_type, + u32 *attributes, bool *enabled, u32 *oem_val, + bool atomic); }; static enum scmi_clock_protocol_cmd evt_2_cmd[] = { @@ -167,6 +178,15 @@ static enum scmi_clock_protocol_cmd evt_2_cmd[] = { CLOCK_RATE_CHANGE_REQUESTED_NOTIFY, }; +static inline struct scmi_clock_info * +scmi_clock_domain_lookup(struct clock_info *ci, u32 clk_id) +{ + if (clk_id >= ci->num_clocks) + return ERR_PTR(-EINVAL); + + return ci->clk + clk_id; +} + static int scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph, struct clock_info *ci) @@ -189,6 +209,17 @@ scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph, } ph->xops->xfer_put(ph, t); + + if (!ret) { + if (!ph->hops->protocol_msg_check(ph, CLOCK_RATE_NOTIFY, NULL)) + ci->notify_rate_changed_cmd = true; + + if (!ph->hops->protocol_msg_check(ph, + CLOCK_RATE_CHANGE_REQUESTED_NOTIFY, + NULL)) + ci->notify_rate_change_requested_cmd = true; + } + return ret; } @@ -284,14 +315,44 @@ static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph, u3 return ret; } +static int +scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id, + struct scmi_clock_info *clk) +{ + struct scmi_xfer *t; + u32 perm; + int ret; + + ret = ph->xops->xfer_get_init(ph, CLOCK_GET_PERMISSIONS, + sizeof(clk_id), sizeof(perm), &t); + if (ret) + return ret; + + put_unaligned_le32(clk_id, t->tx.buf); + + ret = ph->xops->do_xfer(ph, t); + if (!ret) { + perm = get_unaligned_le32(t->rx.buf); + + clk->state_ctrl_forbidden = !(perm & CLOCK_STATE_CONTROL_ALLOWED); + clk->rate_ctrl_forbidden = !(perm & CLOCK_RATE_CONTROL_ALLOWED); + clk->parent_ctrl_forbidden = !(perm & CLOCK_PARENT_CONTROL_ALLOWED); + } + + ph->xops->xfer_put(ph, t); + + return ret; +} + static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, - u32 clk_id, struct scmi_clock_info *clk, + u32 clk_id, struct clock_info *cinfo, u32 version) { int ret; u32 attributes; struct scmi_xfer *t; struct scmi_msg_resp_clock_attributes *attr; + struct scmi_clock_info *clk = cinfo->clk + clk_id; ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES, sizeof(clk_id), sizeof(*attr), &t); @@ -324,12 +385,20 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, NULL, clk->name, SCMI_MAX_STR_SIZE); - if (SUPPORTS_RATE_CHANGED_NOTIF(attributes)) + if (cinfo->notify_rate_changed_cmd && + SUPPORTS_RATE_CHANGED_NOTIF(attributes)) clk->rate_changed_notifications = true; - if (SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes)) + if (cinfo->notify_rate_change_requested_cmd && + SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes)) clk->rate_change_requested_notifications = true; - if (SUPPORTS_PARENT_CLOCK(attributes)) - scmi_clock_possible_parents(ph, clk_id, clk); + if (PROTOCOL_REV_MAJOR(version) >= 0x3) { + if (SUPPORTS_PARENT_CLOCK(attributes)) + scmi_clock_possible_parents(ph, clk_id, clk); + if (SUPPORTS_GET_PERMISSIONS(attributes)) + scmi_clock_get_permissions(ph, clk_id, clk); + if (SUPPORTS_EXTENDED_CONFIG(attributes)) + clk->extended_config = true; + } } return ret; @@ -502,6 +571,14 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph, struct scmi_xfer *t; struct scmi_clock_set_rate *cfg; struct clock_info *ci = ph->get_priv(ph); + struct scmi_clock_info *clk; + + clk = scmi_clock_domain_lookup(ci, clk_id); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + if (clk->rate_ctrl_forbidden) + return -EACCES; ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_SET, sizeof(*cfg), 0, &t); if (ret) @@ -543,7 +620,8 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph, static int scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id, - enum clk_state state, u8 __unused0, u32 __unused1, + enum clk_state state, + enum scmi_clock_oem_config __unused0, u32 __unused1, bool atomic) { int ret; @@ -580,14 +658,16 @@ scmi_clock_set_parent(const struct scmi_protocol_handle *ph, u32 clk_id, struct clock_info *ci = ph->get_priv(ph); struct scmi_clock_info *clk; - if (clk_id >= ci->num_clocks) - return -EINVAL; - - clk = ci->clk + clk_id; + clk = scmi_clock_domain_lookup(ci, clk_id); + if (IS_ERR(clk)) + return PTR_ERR(clk); if (parent_id >= clk->num_parents) return -EINVAL; + if (clk->parent_ctrl_forbidden) + return -EACCES; + ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_SET, sizeof(*cfg), 0, &t); if (ret) @@ -628,10 +708,11 @@ scmi_clock_get_parent(const struct scmi_protocol_handle *ph, u32 clk_id, return ret; } -/* For SCMI clock v2.1 and onwards */ +/* For SCMI clock v3.0 and onwards */ static int scmi_clock_config_set_v2(const struct scmi_protocol_handle *ph, u32 clk_id, - enum clk_state state, u8 oem_type, u32 oem_val, + enum clk_state state, + enum scmi_clock_oem_config oem_type, u32 oem_val, bool atomic) { int ret; @@ -671,6 +752,14 @@ static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id, bool atomic) { struct clock_info *ci = ph->get_priv(ph); + struct scmi_clock_info *clk; + + clk = scmi_clock_domain_lookup(ci, clk_id); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + if (clk->state_ctrl_forbidden) + return -EACCES; return ci->clock_config_set(ph, clk_id, CLK_STATE_ENABLE, NULL_OEM_TYPE, 0, atomic); @@ -680,16 +769,24 @@ static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id, bool atomic) { struct clock_info *ci = ph->get_priv(ph); + struct scmi_clock_info *clk; + + clk = scmi_clock_domain_lookup(ci, clk_id); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + if (clk->state_ctrl_forbidden) + return -EACCES; return ci->clock_config_set(ph, clk_id, CLK_STATE_DISABLE, NULL_OEM_TYPE, 0, atomic); } -/* For SCMI clock v2.1 and onwards */ +/* For SCMI clock v3.0 and onwards */ static int scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id, - u8 oem_type, u32 *attributes, bool *enabled, - u32 *oem_val, bool atomic) + enum scmi_clock_oem_config oem_type, u32 *attributes, + bool *enabled, u32 *oem_val, bool atomic) { int ret; u32 flags; @@ -730,8 +827,8 @@ scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id, static int scmi_clock_config_get(const struct scmi_protocol_handle *ph, u32 clk_id, - u8 oem_type, u32 *attributes, bool *enabled, - u32 *oem_val, bool atomic) + enum scmi_clock_oem_config oem_type, u32 *attributes, + bool *enabled, u32 *oem_val, bool atomic) { int ret; struct scmi_xfer *t; @@ -768,20 +865,38 @@ static int scmi_clock_state_get(const struct scmi_protocol_handle *ph, } static int scmi_clock_config_oem_set(const struct scmi_protocol_handle *ph, - u32 clk_id, u8 oem_type, u32 oem_val, - bool atomic) + u32 clk_id, + enum scmi_clock_oem_config oem_type, + u32 oem_val, bool atomic) { struct clock_info *ci = ph->get_priv(ph); + struct scmi_clock_info *clk; + + clk = scmi_clock_domain_lookup(ci, clk_id); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + if (!clk->extended_config) + return -EOPNOTSUPP; return ci->clock_config_set(ph, clk_id, CLK_STATE_UNCHANGED, oem_type, oem_val, atomic); } static int scmi_clock_config_oem_get(const struct scmi_protocol_handle *ph, - u32 clk_id, u8 oem_type, u32 *oem_val, - u32 *attributes, bool atomic) + u32 clk_id, + enum scmi_clock_oem_config oem_type, + u32 *oem_val, u32 *attributes, bool atomic) { struct clock_info *ci = ph->get_priv(ph); + struct scmi_clock_info *clk; + + clk = scmi_clock_domain_lookup(ci, clk_id); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + if (!clk->extended_config) + return -EOPNOTSUPP; return ci->clock_config_get(ph, clk_id, oem_type, attributes, NULL, oem_val, atomic); @@ -800,10 +915,10 @@ scmi_clock_info_get(const struct scmi_protocol_handle *ph, u32 clk_id) struct scmi_clock_info *clk; struct clock_info *ci = ph->get_priv(ph); - if (clk_id >= ci->num_clocks) + clk = scmi_clock_domain_lookup(ci, clk_id); + if (IS_ERR(clk)) return NULL; - clk = ci->clk + clk_id; if (!clk->name[0]) return NULL; @@ -824,6 +939,28 @@ static const struct scmi_clk_proto_ops clk_proto_ops = { .parent_get = scmi_clock_get_parent, }; +static bool scmi_clk_notify_supported(const struct scmi_protocol_handle *ph, + u8 evt_id, u32 src_id) +{ + bool supported; + struct scmi_clock_info *clk; + struct clock_info *ci = ph->get_priv(ph); + + if (evt_id >= ARRAY_SIZE(evt_2_cmd)) + return false; + + clk = scmi_clock_domain_lookup(ci, src_id); + if (IS_ERR(clk)) + return false; + + if (evt_id == SCMI_EVENT_CLOCK_RATE_CHANGED) + supported = clk->rate_changed_notifications; + else + supported = clk->rate_change_requested_notifications; + + return supported; +} + static int scmi_clk_rate_notify(const struct scmi_protocol_handle *ph, u32 clk_id, int message_id, bool enable) { @@ -908,6 +1045,7 @@ static const struct scmi_event clk_events[] = { }; static const struct scmi_event_ops clk_event_ops = { + .is_notify_supported = scmi_clk_notify_supported, .get_num_sources = scmi_clk_get_num_sources, .set_notify_enabled = scmi_clk_set_notify_enabled, .fill_custom_report = scmi_clk_fill_custom_report, @@ -949,7 +1087,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) for (clkid = 0; clkid < cinfo->num_clocks; clkid++) { struct scmi_clock_info *clk = cinfo->clk + clkid; - ret = scmi_clock_attributes_get(ph, clkid, clk, version); + ret = scmi_clock_attributes_get(ph, clkid, cinfo, version); if (!ret) scmi_clock_describe_rates_get(ph, clkid, clk); } diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 00b165d1f502..6affbfdd1dec 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -141,7 +141,7 @@ scmi_revision_area_get(const struct scmi_protocol_handle *ph); void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph, u8 *prot_imp); -extern struct bus_type scmi_bus_type; +extern const struct bus_type scmi_bus_type; #define SCMI_BUS_NOTIFY_DEVICE_REQUEST 0 #define SCMI_BUS_NOTIFY_DEVICE_UNREQUEST 1 diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 3ea64b22cf0d..34d77802c990 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -86,6 +86,12 @@ struct scmi_xfers_info { * @users: A refcount to track effective users of this protocol. * @priv: Reference for optional protocol private data. * @version: Protocol version supported by the platform as detected at runtime. + * @negotiated_version: When the platform supports a newer protocol version, + * the agent will try to negotiate with the platform the + * usage of the newest version known to it, since + * backward compatibility is NOT automatically assured. + * This field is NON-zero when a successful negotiation + * has completed. * @ph: An embedded protocol handle that will be passed down to protocol * initialization code to identify this instance. * @@ -99,6 +105,7 @@ struct scmi_protocol_instance { refcount_t users; void *priv; unsigned int version; + unsigned int negotiated_version; struct scmi_protocol_handle ph; }; @@ -1754,10 +1761,44 @@ static void scmi_common_fastchannel_db_ring(struct scmi_fc_db_info *db) #endif } +/** + * scmi_protocol_msg_check - Check protocol message attributes + * + * @ph: A reference to the protocol handle. + * @message_id: The ID of the message to check. + * @attributes: A parameter to optionally return the retrieved message + * attributes, in case of Success. + * + * An helper to check protocol message attributes for a specific protocol + * and message pair. + * + * Return: 0 on SUCCESS + */ +static int scmi_protocol_msg_check(const struct scmi_protocol_handle *ph, + u32 message_id, u32 *attributes) +{ + int ret; + struct scmi_xfer *t; + + ret = xfer_get_init(ph, PROTOCOL_MESSAGE_ATTRIBUTES, + sizeof(__le32), 0, &t); + if (ret) + return ret; + + put_unaligned_le32(message_id, t->tx.buf); + ret = do_xfer(ph, t); + if (!ret && attributes) + *attributes = get_unaligned_le32(t->rx.buf); + xfer_put(ph, t); + + return ret; +} + static const struct scmi_proto_helpers_ops helpers_ops = { .extended_name_get = scmi_common_extended_name_get, .iter_response_init = scmi_iterator_init, .iter_response_run = scmi_iterator_run, + .protocol_msg_check = scmi_protocol_msg_check, .fastchannel_init = scmi_common_fastchannel_init, .fastchannel_db_ring = scmi_common_fastchannel_db_ring, }; @@ -1782,6 +1823,44 @@ scmi_revision_area_get(const struct scmi_protocol_handle *ph) } /** + * scmi_protocol_version_negotiate - Negotiate protocol version + * + * @ph: A reference to the protocol handle. + * + * An helper to negotiate a protocol version different from the latest + * advertised as supported from the platform: on Success backward + * compatibility is assured by the platform. + * + * Return: 0 on Success + */ +static int scmi_protocol_version_negotiate(struct scmi_protocol_handle *ph) +{ + int ret; + struct scmi_xfer *t; + struct scmi_protocol_instance *pi = ph_to_pi(ph); + + /* At first check if NEGOTIATE_PROTOCOL_VERSION is supported ... */ + ret = scmi_protocol_msg_check(ph, NEGOTIATE_PROTOCOL_VERSION, NULL); + if (ret) + return ret; + + /* ... then attempt protocol version negotiation */ + ret = xfer_get_init(ph, NEGOTIATE_PROTOCOL_VERSION, + sizeof(__le32), 0, &t); + if (ret) + return ret; + + put_unaligned_le32(pi->proto->supported_version, t->tx.buf); + ret = do_xfer(ph, t); + if (!ret) + pi->negotiated_version = pi->proto->supported_version; + + xfer_put(ph, t); + + return ret; +} + +/** * scmi_alloc_init_protocol_instance - Allocate and initialize a protocol * instance descriptor. * @info: The reference to the related SCMI instance. @@ -1853,11 +1932,21 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info, devres_close_group(handle->dev, pi->gid); dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id); - if (pi->version > proto->supported_version) - dev_warn(handle->dev, |
