diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-16 16:38:41 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-16 16:38:41 -0800 |
commit | 48c1c40ab40cb087b992e7b77518c3a2926743cc (patch) | |
tree | 8e5fcd8f0e45f6e05e08c2c8307417f17341768f /drivers/firmware | |
parent | 9805529ec544ea7a82d891d5239a8ebd3dbb2a3e (diff) | |
parent | 1dcdee6ee8f8fdfef5932699129d442d2f1a064d (diff) | |
download | linux-48c1c40ab40cb087b992e7b77518c3a2926743cc.tar.bz2 |
Merge tag 'arm-soc-drivers-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC driver updates from Arnd Bergmann:
"There are a couple of subsystems maintained by other people that merge
their drivers through the SoC tree, those changes include:
- The SCMI firmware framework gains support for sensor notifications
and for controlling voltage domains.
- A large update for the Tegra memory controller driver, integrating
it better with the interconnect framework
- The memory controller subsystem gains support for Mediatek MT8192
- The reset controller framework gains support for sharing pulsed
resets
For Soc specific drivers in drivers/soc, the main changes are
- The Allwinner/sunxi MBUS gets a rework for the way it handles
dma_map_ops and offsets between physical and dma address spaces.
- An errata fix plus some cleanups for Freescale Layerscape SoCs
- A cleanup for renesas drivers regarding MMIO accesses.
- New SoC specific drivers for Mediatek MT8192 and MT8183 power
domains
- New SoC specific drivers for Aspeed AST2600 LPC bus control and SoC
identification.
- Core Power Domain support for Qualcomm MSM8916, MSM8939, SDM660 and
SDX55.
- A rework of the TI AM33xx 'genpd' power domain support to use
information from DT instead of platform data
- Support for TI AM64x SoCs
- Allow building some Amlogic drivers as modules instead of built-in
Finally, there are numerous cleanups and smaller bug fixes for
Mediatek, Tegra, Samsung, Qualcomm, TI OMAP, Amlogic, Rockchips,
Renesas, and Xilinx SoCs"
* tag 'arm-soc-drivers-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (222 commits)
soc: mediatek: mmsys: Specify HAS_IOMEM dependency for MTK_MMSYS
firmware: xilinx: Properly align function parameter
firmware: xilinx: Add a blank line after function declaration
firmware: xilinx: Remove additional newline
firmware: xilinx: Fix kernel-doc warnings
firmware: xlnx-zynqmp: fix compilation warning
soc: xilinx: vcu: add missing register NUM_CORE
soc: xilinx: vcu: use vcu-settings syscon registers
dt-bindings: soc: xlnx: extract xlnx, vcu-settings to separate binding
soc: xilinx: vcu: drop useless success message
clk: samsung: mark PM functions as __maybe_unused
soc: samsung: exynos-chipid: initialize later - with arch_initcall
soc: samsung: exynos-chipid: order list of SoCs by name
memory: jz4780_nemc: Fix potential NULL dereference in jz4780_nemc_probe()
memory: ti-emif-sram: only build for ARMv7
memory: tegra30: Support interconnect framework
memory: tegra20: Support hardware versioning and clean up OPP table initialization
dt-bindings: memory: tegra20-emc: Document opp-supported-hw property
soc: rockchip: io-domain: Fix error return code in rockchip_iodomain_probe()
reset-controller: ti: force the write operation when assert or deassert
...
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/arm_scmi/notify.c | 10 | ||||
-rw-r--r-- | drivers/firmware/arm_scmi/sensors.c | 720 | ||||
-rw-r--r-- | drivers/firmware/imx/imx-dsp.c | 72 | ||||
-rw-r--r-- | drivers/firmware/imx/scu-pd.c | 12 | ||||
-rw-r--r-- | drivers/firmware/meson/Kconfig | 5 | ||||
-rw-r--r-- | drivers/firmware/meson/meson_sm.c | 1 | ||||
-rw-r--r-- | drivers/firmware/tegra/bpmp-debugfs.c | 6 | ||||
-rw-r--r-- | drivers/firmware/ti_sci.c | 213 | ||||
-rw-r--r-- | drivers/firmware/ti_sci.h | 72 | ||||
-rw-r--r-- | drivers/firmware/xilinx/zynqmp.c | 46 |
10 files changed, 862 insertions, 295 deletions
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c index ce336899d636..66196b293b6c 100644 --- a/drivers/firmware/arm_scmi/notify.c +++ b/drivers/firmware/arm_scmi/notify.c @@ -1474,17 +1474,17 @@ int scmi_notification_init(struct scmi_handle *handle) ni->gid = gid; ni->handle = handle; + ni->registered_protocols = devm_kcalloc(handle->dev, SCMI_MAX_PROTO, + sizeof(char *), GFP_KERNEL); + if (!ni->registered_protocols) + goto err; + ni->notify_wq = alloc_workqueue(dev_name(handle->dev), WQ_UNBOUND | WQ_FREEZABLE | WQ_SYSFS, 0); if (!ni->notify_wq) goto err; - ni->registered_protocols = devm_kcalloc(handle->dev, SCMI_MAX_PROTO, - sizeof(char *), GFP_KERNEL); - if (!ni->registered_protocols) - goto err; - mutex_init(&ni->pending_mtx); hash_init(ni->pending_events_handlers); diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index b4232d611033..4541b891b733 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -2,21 +2,30 @@ /* * System Control and Management Interface (SCMI) Sensor Protocol * - * Copyright (C) 2018 ARM Ltd. + * Copyright (C) 2018-2020 ARM Ltd. */ #define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt +#include <linux/bitfield.h> #include <linux/scmi_protocol.h> #include "common.h" #include "notify.h" +#define SCMI_MAX_NUM_SENSOR_AXIS 63 +#define SCMIv2_SENSOR_PROTOCOL 0x10000 + enum scmi_sensor_protocol_cmd { SENSOR_DESCRIPTION_GET = 0x3, SENSOR_TRIP_POINT_NOTIFY = 0x4, SENSOR_TRIP_POINT_CONFIG = 0x5, SENSOR_READING_GET = 0x6, + SENSOR_AXIS_DESCRIPTION_GET = 0x7, + SENSOR_LIST_UPDATE_INTERVALS = 0x8, + SENSOR_CONFIG_GET = 0x9, + SENSOR_CONFIG_SET = 0xA, + SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0xB, }; struct scmi_msg_resp_sensor_attributes { @@ -28,29 +37,106 @@ struct scmi_msg_resp_sensor_attributes { __le32 reg_size; }; +/* v3 attributes_low macros */ +#define SUPPORTS_UPDATE_NOTIFY(x) FIELD_GET(BIT(30), (x)) +#define SENSOR_TSTAMP_EXP(x) FIELD_GET(GENMASK(14, 10), (x)) +#define SUPPORTS_TIMESTAMP(x) FIELD_GET(BIT(9), (x)) +#define SUPPORTS_EXTEND_ATTRS(x) FIELD_GET(BIT(8), (x)) + +/* v2 attributes_high macros */ +#define SENSOR_UPDATE_BASE(x) FIELD_GET(GENMASK(31, 27), (x)) +#define SENSOR_UPDATE_SCALE(x) FIELD_GET(GENMASK(26, 22), (x)) + +/* v3 attributes_high macros */ +#define SENSOR_AXIS_NUMBER(x) FIELD_GET(GENMASK(21, 16), (x)) +#define SUPPORTS_AXIS(x) FIELD_GET(BIT(8), (x)) + +/* v3 resolution macros */ +#define SENSOR_RES(x) FIELD_GET(GENMASK(26, 0), (x)) +#define SENSOR_RES_EXP(x) FIELD_GET(GENMASK(31, 27), (x)) + +struct scmi_msg_resp_attrs { + __le32 min_range_low; + __le32 min_range_high; + __le32 max_range_low; + __le32 max_range_high; +}; + struct scmi_msg_resp_sensor_description { __le16 num_returned; __le16 num_remaining; - struct { + struct scmi_sensor_descriptor { __le32 id; __le32 attributes_low; -#define SUPPORTS_ASYNC_READ(x) ((x) & BIT(31)) -#define NUM_TRIP_POINTS(x) ((x) & 0xff) +/* Common attributes_low macros */ +#define SUPPORTS_ASYNC_READ(x) FIELD_GET(BIT(31), (x)) +#define NUM_TRIP_POINTS(x) FIELD_GET(GENMASK(7, 0), (x)) __le32 attributes_high; -#define SENSOR_TYPE(x) ((x) & 0xff) -#define SENSOR_SCALE(x) (((x) >> 11) & 0x1f) -#define SENSOR_SCALE_SIGN BIT(4) -#define SENSOR_SCALE_EXTEND GENMASK(7, 5) -#define SENSOR_UPDATE_SCALE(x) (((x) >> 22) & 0x1f) -#define SENSOR_UPDATE_BASE(x) (((x) >> 27) & 0x1f) - u8 name[SCMI_MAX_STR_SIZE]; - } desc[0]; +/* Common attributes_high macros */ +#define SENSOR_SCALE(x) FIELD_GET(GENMASK(15, 11), (x)) +#define SENSOR_SCALE_SIGN BIT(4) +#define SENSOR_SCALE_EXTEND GENMASK(31, 5) +#define SENSOR_TYPE(x) FIELD_GET(GENMASK(7, 0), (x)) + u8 name[SCMI_MAX_STR_SIZE]; + /* only for version > 2.0 */ + __le32 power; + __le32 resolution; + struct scmi_msg_resp_attrs scalar_attrs; + } desc[]; }; -struct scmi_msg_sensor_trip_point_notify { +/* Base scmi_sensor_descriptor size excluding extended attrs after name */ +#define SCMI_MSG_RESP_SENS_DESCR_BASE_SZ 28 + +/* Sign extend to a full s32 */ +#define S32_EXT(v) \ + ({ \ + int __v = (v); \ + \ + if (__v & SENSOR_SCALE_SIGN) \ + __v |= SENSOR_SCALE_EXTEND; \ + __v; \ + }) + +struct scmi_msg_sensor_axis_description_get { + __le32 id; + __le32 axis_desc_index; +}; + +struct scmi_msg_resp_sensor_axis_description { + __le32 num_axis_flags; +#define NUM_AXIS_RETURNED(x) FIELD_GET(GENMASK(5, 0), (x)) +#define NUM_AXIS_REMAINING(x) FIELD_GET(GENMASK(31, 26), (x)) + struct scmi_axis_descriptor { + __le32 id; + __le32 attributes_low; + __le32 attributes_high; + u8 name[SCMI_MAX_STR_SIZE]; + __le32 resolution; + struct scmi_msg_resp_attrs attrs; + } desc[]; +}; + +/* Base scmi_axis_descriptor size excluding extended attrs after name */ +#define SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ 28 + +struct scmi_msg_sensor_list_update_intervals { + __le32 id; + __le32 index; +}; + +struct scmi_msg_resp_sensor_list_update_intervals { + __le32 num_intervals_flags; +#define NUM_INTERVALS_RETURNED(x) FIELD_GET(GENMASK(11, 0), (x)) +#define SEGMENTED_INTVL_FORMAT(x) FIELD_GET(BIT(12), (x)) +#define NUM_INTERVALS_REMAINING(x) FIELD_GET(GENMASK(31, 16), (x)) + __le32 intervals[]; +}; + +struct scmi_msg_sensor_request_notify { __le32 id; __le32 event_control; -#define SENSOR_TP_NOTIFY_ALL BIT(0) +#define SENSOR_NOTIFY_ALL BIT(0) }; struct scmi_msg_set_sensor_trip_point { @@ -66,18 +152,46 @@ struct scmi_msg_set_sensor_trip_point { __le32 value_high; }; +struct scmi_msg_sensor_config_set { + __le32 id; + __le32 sensor_config; +}; + struct scmi_msg_sensor_reading_get { __le32 id; __le32 flags; #define SENSOR_READ_ASYNC BIT(0) }; +struct scmi_resp_sensor_reading_complete { + __le32 id; + __le64 readings; +}; + +struct scmi_sensor_reading_resp { + __le32 sensor_value_low; + __le32 sensor_value_high; + __le32 timestamp_low; + __le32 timestamp_high; +}; + +struct scmi_resp_sensor_reading_complete_v3 { + __le32 id; + struct scmi_sensor_reading_resp readings[]; +}; + struct scmi_sensor_trip_notify_payld { __le32 agent_id; __le32 sensor_id; __le32 trip_point_desc; }; +struct scmi_sensor_update_notify_payld { + __le32 agent_id; + __le32 sensor_id; + struct scmi_sensor_reading_resp readings[]; +}; + struct sensors_info { u32 version; int num_sensors; @@ -114,6 +228,194 @@ static int scmi_sensor_attributes_get(const struct scmi_handle *handle, return ret; } +static inline void scmi_parse_range_attrs(struct scmi_range_attrs *out, + struct scmi_msg_resp_attrs *in) +{ + out->min_range = get_unaligned_le64((void *)&in->min_range_low); + out->max_range = get_unaligned_le64((void *)&in->max_range_low); +} + +static int scmi_sensor_update_intervals(const struct scmi_handle *handle, + struct scmi_sensor_info *s) +{ + int ret, cnt; + u32 desc_index = 0; + u16 num_returned, num_remaining; + struct scmi_xfer *ti; + struct scmi_msg_resp_sensor_list_update_intervals *buf; + struct scmi_msg_sensor_list_update_intervals *msg; + + ret = scmi_xfer_get_init(handle, SENSOR_LIST_UPDATE_INTERVALS, + SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &ti); + if (ret) + return ret; + + buf = ti->rx.buf; + do { + u32 flags; + + msg = ti->tx.buf; + /* Set the number of sensors to be skipped/already read */ + msg->id = cpu_to_le32(s->id); + msg->index = cpu_to_le32(desc_index); + + ret = scmi_do_xfer(handle, ti); + if (ret) + break; + + flags = le32_to_cpu(buf->num_intervals_flags); + num_returned = NUM_INTERVALS_RETURNED(flags); + num_remaining = NUM_INTERVALS_REMAINING(flags); + + /* + * Max intervals is not declared previously anywhere so we + * assume it's returned+remaining. + */ + if (!s->intervals.count) { + s->intervals.segmented = SEGMENTED_INTVL_FORMAT(flags); + s->intervals.count = num_returned + num_remaining; + /* segmented intervals are reported in one triplet */ + if (s->intervals.segmented && + (num_remaining || num_returned != 3)) { + dev_err(handle->dev, + "Sensor ID:%d advertises an invalid segmented interval (%d)\n", + s->id, s->intervals.count); + s->intervals.segmented = false; + s->intervals.count = 0; + ret = -EINVAL; + break; + } + /* Direct allocation when exceeding pre-allocated */ + if (s->intervals.count >= SCMI_MAX_PREALLOC_POOL) { + s->intervals.desc = + devm_kcalloc(handle->dev, + s->intervals.count, + sizeof(*s->intervals.desc), + GFP_KERNEL); + if (!s->intervals.desc) { + s->intervals.segmented = false; + s->intervals.count = 0; + ret = -ENOMEM; + break; + } + } + } else if (desc_index + num_returned > s->intervals.count) { + dev_err(handle->dev, + "No. of update intervals can't exceed %d\n", + s->intervals.count); + ret = -EINVAL; + break; + } + + for (cnt = 0; cnt < num_returned; cnt++) + s->intervals.desc[desc_index + cnt] = + le32_to_cpu(buf->intervals[cnt]); + + desc_index += num_returned; + + scmi_reset_rx_to_maxsz(handle, ti); + /* + * check for both returned and remaining to avoid infinite + * loop due to buggy firmware + */ + } while (num_returned && num_remaining); + + scmi_xfer_put(handle, ti); + return ret; +} + +static int scmi_sensor_axis_description(const struct scmi_handle *handle, + struct scmi_sensor_info *s) +{ + int ret, cnt; + u32 desc_index = 0; + u16 num_returned, num_remaining; + struct scmi_xfer *te; + struct scmi_msg_resp_sensor_axis_description *buf; + struct scmi_msg_sensor_axis_description_get *msg; + + s->axis = devm_kcalloc(handle->dev, s->num_axis, + sizeof(*s->axis), GFP_KERNEL); + if (!s->axis) + return -ENOMEM; + + ret = scmi_xfer_get_init(handle, SENSOR_AXIS_DESCRIPTION_GET, + SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &te); + if (ret) + return ret; + + buf = te->rx.buf; + do { + u32 flags; + struct scmi_axis_descriptor *adesc; + + msg = te->tx.buf; + /* Set the number of sensors to be skipped/already read */ + msg->id = cpu_to_le32(s->id); + msg->axis_desc_index = cpu_to_le32(desc_index); + + ret = scmi_do_xfer(handle, te); + if (ret) + break; + + flags = le32_to_cpu(buf->num_axis_flags); + num_returned = NUM_AXIS_RETURNED(flags); + num_remaining = NUM_AXIS_REMAINING(flags); + + if (desc_index + num_returned > s->num_axis) { + dev_err(handle->dev, "No. of axis can't exceed %d\n", + s->num_axis); + break; + } + + adesc = &buf->desc[0]; + for (cnt = 0; cnt < num_returned; cnt++) { + u32 attrh, attrl; + struct scmi_sensor_axis_info *a; + size_t dsize = SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ; + + attrl = le32_to_cpu(adesc->attributes_low); + + a = &s->axis[desc_index + cnt]; + + a->id = le32_to_cpu(adesc->id); + a->extended_attrs = SUPPORTS_EXTEND_ATTRS(attrl); + + attrh = le32_to_cpu(adesc->attributes_high); + a->scale = S32_EXT(SENSOR_SCALE(attrh)); + a->type = SENSOR_TYPE(attrh); + strlcpy(a->name, adesc->name, SCMI_MAX_STR_SIZE); + + if (a->extended_attrs) { + unsigned int ares = + le32_to_cpu(adesc->resolution); + + a->resolution = SENSOR_RES(ares); + a->exponent = + S32_EXT(SENSOR_RES_EXP(ares)); + dsize += sizeof(adesc->resolution); + + scmi_parse_range_attrs(&a->attrs, + &adesc->attrs); + dsize += sizeof(adesc->attrs); + } + + adesc = (typeof(adesc))((u8 *)adesc + dsize); + } + + desc_index += num_returned; + + scmi_reset_rx_to_maxsz(handle, te); + /* + * check for both returned and remaining to avoid infinite + * loop due to buggy firmware + */ + } while (num_returned && num_remaining); + + scmi_xfer_put(handle, te); + return ret; +} + static int scmi_sensor_description_get(const struct scmi_handle *handle, struct sensors_info *si) { @@ -131,9 +433,10 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, buf = t->rx.buf; do { + struct scmi_sensor_descriptor *sdesc; + /* Set the number of sensors to be skipped/already read */ put_unaligned_le32(desc_index, t->tx.buf); - ret = scmi_do_xfer(handle, t); if (ret) break; @@ -147,22 +450,97 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, break; } + sdesc = &buf->desc[0]; for (cnt = 0; cnt < num_returned; cnt++) { u32 attrh, attrl; struct scmi_sensor_info *s; + size_t dsize = SCMI_MSG_RESP_SENS_DESCR_BASE_SZ; - attrl = le32_to_cpu(buf->desc[cnt].attributes_low); - attrh = le32_to_cpu(buf->desc[cnt].attributes_high); s = &si->sensors[desc_index + cnt]; - s->id = le32_to_cpu(buf->desc[cnt].id); - s->type = SENSOR_TYPE(attrh); - s->scale = SENSOR_SCALE(attrh); - /* Sign extend to a full s8 */ - if (s->scale & SENSOR_SCALE_SIGN) - s->scale |= SENSOR_SCALE_EXTEND; + s->id = le32_to_cpu(sdesc->id); + + attrl = le32_to_cpu(sdesc->attributes_low); + /* common bitfields parsing */ s->async = SUPPORTS_ASYNC_READ(attrl); s->num_trip_points = NUM_TRIP_POINTS(attrl); - strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE); + /** + * only SCMIv3.0 specific bitfield below. + * Such bitfields are assumed to be zeroed on non + * relevant fw versions...assuming fw not buggy ! + */ + s->update = SUPPORTS_UPDATE_NOTIFY(attrl); + s->timestamped = SUPPORTS_TIMESTAMP(attrl); + if (s->timestamped) + s->tstamp_scale = + S32_EXT(SENSOR_TSTAMP_EXP(attrl)); + s->extended_scalar_attrs = + SUPPORTS_EXTEND_ATTRS(attrl); + + attrh = le32_to_cpu(sdesc->attributes_high); + /* common bitfields parsing */ + s->scale = S32_EXT(SENSOR_SCALE(attrh)); + s->type = SENSOR_TYPE(attrh); + /* Use pre-allocated pool wherever possible */ + s->intervals.desc = s->intervals.prealloc_pool; + if (si->version == SCMIv2_SENSOR_PROTOCOL) { + s->intervals.segmented = false; + s->intervals.count = 1; + /* + * Convert SCMIv2.0 update interval format to + * SCMIv3.0 to be used as the common exposed + * descriptor, accessible via common macros. + */ + s->intervals.desc[0] = + (SENSOR_UPDATE_BASE(attrh) << 5) | + SENSOR_UPDATE_SCALE(attrh); + } else { + /* + * From SCMIv3.0 update intervals are retrieved + * via a dedicated (optional) command. + * Since the command is optional, on error carry + * on without any update interval. + */ + if (scmi_sensor_update_intervals(handle, s)) + dev_dbg(handle->dev, + "Update Intervals not available for sensor ID:%d\n", + s->id); + } + /** + * only > SCMIv2.0 specific bitfield below. + * Such bitfields are assumed to be zeroed on non + * relevant fw versions...assuming fw not buggy ! + */ + s->num_axis = min_t(unsigned int, + SUPPORTS_AXIS(attrh) ? + SENSOR_AXIS_NUMBER(attrh) : 0, + SCMI_MAX_NUM_SENSOR_AXIS); + strlcpy(s->name, sdesc->name, SCMI_MAX_STR_SIZE); + + if (s->extended_scalar_attrs) { + s->sensor_power = le32_to_cpu(sdesc->power); + dsize += sizeof(sdesc->power); + /* Only for sensors reporting scalar values */ + if (s->num_axis == 0) { + unsigned int sres = + le32_to_cpu(sdesc->resolution); + + s->resolution = SENSOR_RES(sres); + s->exponent = + S32_EXT(SENSOR_RES_EXP(sres)); + dsize += sizeof(sdesc->resolution); + + scmi_parse_range_attrs(&s->scalar_attrs, + &sdesc->scalar_attrs); + dsize += sizeof(sdesc->scalar_attrs); + } + } + if (s->num_axis > 0) { + ret = scmi_sensor_axis_description(handle, s); + if (ret) + goto out; + } + + sdesc = (typeof(sdesc))((u8 *)sdesc + dsize); } desc_index += num_returned; @@ -174,19 +552,21 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, */ } while (num_returned && num_remaining); +out: scmi_xfer_put(handle, t); return ret; } -static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle, - u32 sensor_id, bool enable) +static inline int +scmi_sensor_request_notify(const struct scmi_handle *handle, u32 sensor_id, + u8 message_id, bool enable) { int ret; - u32 evt_cntl = enable ? SENSOR_TP_NOTIFY_ALL : 0; + u32 evt_cntl = enable ? SENSOR_NOTIFY_ALL : 0; struct scmi_xfer *t; - struct scmi_msg_sensor_trip_point_notify *cfg; + struct scmi_msg_sensor_request_notify *cfg; - ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_NOTIFY, + ret = scmi_xfer_get_init(handle, message_id, SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t); if (ret) return ret; @@ -201,6 +581,23 @@ static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle, return ret; } +static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle, + u32 sensor_id, bool enable) +{ + return scmi_sensor_request_notify(handle, sensor_id, + SENSOR_TRIP_POINT_NOTIFY, + enable); +} + +static int +scmi_sensor_continuous_update_notify(const struct scmi_handle *handle, + u32 sensor_id, bool enable) +{ + return scmi_sensor_request_notify(handle, sensor_id, + SENSOR_CONTINUOUS_UPDATE_NOTIFY, + enable); +} + static int scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id, u8 trip_id, u64 trip_value) @@ -227,6 +624,75 @@ scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id, return ret; } +static int scmi_sensor_config_get(const struct scmi_handle *handle, + u32 sensor_id, u32 *sensor_config) +{ + int ret; + struct scmi_xfer *t; + + ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_GET, + SCMI_PROTOCOL_SENSOR, sizeof(__le32), + sizeof(__le32), &t); + if (ret) + return ret; + + put_unaligned_le32(cpu_to_le32(sensor_id), t->tx.buf); + ret = scmi_do_xfer(handle, t); + if (!ret) { + struct sensors_info *si = handle->sensor_priv; + struct scmi_sensor_info *s = si->sensors + sensor_id; + + *sensor_config = get_unaligned_le64(t->rx.buf); + s->sensor_config = *sensor_config; + } + + scmi_xfer_put(handle, t); + return ret; +} + +static int scmi_sensor_config_set(const struct scmi_handle *handle, + u32 sensor_id, u32 sensor_config) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_sensor_config_set *msg; + + ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_SET, + SCMI_PROTOCOL_SENSOR, sizeof(*msg), 0, &t); + if (ret) + return ret; + + msg = t->tx.buf; + msg->id = cpu_to_le32(sensor_id); + msg->sensor_config = cpu_to_le32(sensor_config); + + ret = scmi_do_xfer(handle, t); + if (!ret) { + struct sensors_info *si = handle->sensor_priv; + struct scmi_sensor_info *s = si->sensors + sensor_id; + + s->sensor_config = sensor_config; + } + + scmi_xfer_put(handle, t); + return ret; +} + +/** + * scmi_sensor_reading_get - Read scalar sensor value + * @handle: Platform handle + * @sensor_id: Sensor ID + * @value: The 64bit value sensor reading + * + * This function returns a single 64 bit reading value representing the sensor + * value; if the platform SCMI Protocol implementation and the sensor support + * multiple axis and timestamped-reads, this just returns the first axis while + * dropping the timestamp value. + * Use instead the @scmi_sensor_reading_get_timestamped to retrieve the array of + * timestamped multi-axis values. + * + * Return: 0 on Success + */ static int scmi_sensor_reading_get(const struct scmi_handle *handle, u32 sensor_id, u64 *value) { @@ -237,20 +703,24 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle, struct scmi_sensor_info *s = si->sensors + sensor_id; ret = scmi_xfer_get_init(handle, SENSOR_READING_GET, - SCMI_PROTOCOL_SENSOR, sizeof(*sensor), - sizeof(u64), &t); + SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t); if (ret) return ret; sensor = t->tx.buf; sensor->id = cpu_to_le32(sensor_id); - if (s->async) { sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC); ret = scmi_do_xfer_with_response(handle, t); - if (!ret) - *value = get_unaligned_le64((void *) - ((__le32 *)t->rx.buf + 1)); + if (!ret) { + struct scmi_resp_sensor_reading_complete *resp; + + resp = t->rx.buf; + if (le32_to_cpu(resp->id) == sensor_id) + *value = get_unaligned_le64(&resp->readings); + else + ret = -EPROTO; + } } else { sensor->flags = cpu_to_le32(0); ret = scmi_do_xfer(handle, t); @@ -262,6 +732,84 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle, return ret; } +static inline void +scmi_parse_sensor_readings(struct scmi_sensor_reading *out, + const struct scmi_sensor_reading_resp *in) +{ + out->value = get_unaligned_le64((void *)&in->sensor_value_low); + out->timestamp = get_unaligned_le64((void *)&in->timestamp_low); +} + +/** + * scmi_sensor_reading_get_timestamped - Read multiple-axis timestamped values + * @handle: Platform handle + * @sensor_id: Sensor ID + * @count: The length of the provided @readings array + * @readings: An array of elements each representing a timestamped per-axis + * reading of type @struct scmi_sensor_reading. + * Returned readings are ordered as the @axis descriptors array + * included in @struct scmi_sensor_info and the max number of + * returned elements is min(@count, @num_axis); ideally the provided + * array should be of length @count equal to @num_axis. + * + * Return: 0 on Success + */ +static int +scmi_sensor_reading_get_timestamped(const struct scmi_handle *handle, + u32 sensor_id, u8 count, + struct scmi_sensor_reading *readings) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_sensor_reading_get *sensor; + struct sensors_info *si = handle->sensor_priv; + struct scmi_sensor_info *s = si->sensors + sensor_id; + + if (!count || !readings || + (!s->num_axis && count > 1) || (s->num_axis && count > s->num_axis)) + return -EINVAL; + + ret = scmi_xfer_get_init(handle, SENSOR_READING_GET, + SCMI_PROTOCOL_SENSOR, sizeof(*sensor), 0, &t); + if (ret) + return ret; + + sensor = t->tx.buf; + sensor->id = cpu_to_le32(sensor_id); + if (s->async) { + sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC); + ret = scmi_do_xfer_with_response(handle, t); + if (!ret) { + int i; + struct scmi_resp_sensor_reading_complete_v3 *resp; + + resp = t->rx.buf; + /* Retrieve only the number of requested axis anyway */ + if (le32_to_cpu(resp->id) == sensor_id) + for (i = 0; i < count; i++) + scmi_parse_sensor_readings(&readings[i], + &resp->readings[i]); + else + ret = -EPROTO; + } + } else { + sensor->flags = cpu_to_le32(0); + ret = scmi_do_xfer(handle, t); + if (!ret) { + int i; + struct scmi_sensor_reading_resp *resp_readings; + + resp_readings = t->rx.buf; + for (i = 0; i < count; i++) + scmi_parse_sensor_readings(&readings[i], + &resp_readings[i]); + } + } + + scmi_xfer_put(handle, t); + return ret; +} + static const struct scmi_sensor_info * scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id) { @@ -282,6 +830,9 @@ static const struct scmi_sensor_ops sensor_ops = { .info_get = scmi_sensor_info_get, .trip_point_config = scmi_sensor_trip_point_config, .reading_get = scmi_sensor_reading_get, + .reading_get_timestamped = scmi_sensor_reading_get_timestamped, + .config_get = scmi_sensor_config_get, + .config_set = scmi_sensor_config_set, }; static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle, @@ -289,7 +840,19 @@ static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle, { int ret; - ret = scmi_sensor_trip_point_notify(handle, src_id, enable); + switch (evt_id) { + case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT: + ret = scmi_sensor_trip_point_notify(handle, src_id, enable); + break; + case SCMI_EVENT_SENSOR_UPDATE: + ret = scmi_sensor_continuous_update_notify(handle, src_id, + enable); + break; + default: + ret = -EINVAL; + break; + } + if (ret) pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", evt_id, src_id, ret); @@ -302,20 +865,59 @@ static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle, const void *payld, size_t payld_sz, void *report, u32 *src_id) { - const struct scmi_sensor_trip_notify_payld *p = payld; - struct scmi_sensor_trip_point_report *r = report; + void *rep = NULL; + + switch (evt_id) { + case SCMI_EVENT_SENSOR_TRIP_POINT_EVENT: + { + const struct scmi_sensor_trip_notify_payld *p = payld; + struct scmi_sensor_trip_point_report *r = report; - if (evt_id != SCMI_EVENT_SENSOR_TRIP_POINT_EVENT || - sizeof(*p) != payld_sz) - return NULL; + if (sizeof(*p) != payld_sz) + break; - r->timestamp = timestamp; - r->agent_id = le32_to_cpu(p->agent_id); - r->sensor_id = le32_to_cpu(p->sensor_id); - r->trip_point_desc = le32_to_cpu(p->trip_point_desc); - *src_id = r->sensor_id; + r->timestamp = timestamp; + r->agent_id = le32_to_cpu(p->agent_id); + r->sensor_id = le32_to_cpu(p->sensor_id); + r->trip_point_desc = le32_to_cpu(p->trip_point_desc); + *src_id = r->sensor_id; + rep = r; + break; + } + case SCMI_EVENT_SENSOR_UPDATE: + { + int i; + struct scmi_sensor_info *s; + const struct scmi_sensor_update_notify_payld *p = payld; + struct scmi_sensor_update_report *r = report; + struct sensors_info *sinfo = handle->sensor_priv; + + /* payld_sz is variable for this event */ + r->sensor_id = le32_to_cpu(p->sensor_id); + if (r->sensor_id >= sinfo->num_sensors) + break; + r->timestamp = timestamp; + r->agent_id = le32_to_cpu(p->agent_id); + s = &sinfo->sensors[r->sensor_id]; + /* + * The generated report r (@struct scmi_sensor_update_report) + * was pre-allocated to contain up to SCMI_MAX_NUM_SENSOR_AXIS + * readings: here it is filled with the effective @num_axis + * readings defined for this sensor or 1 for scalar sensors. + */ + r->readings_count = s->num_axis ?: 1; + for (i = 0; i < r->readings_count; i++) + scmi_parse_sensor_readings(&r->readings[i], + &p->readings[i]); + *src_id = r->sensor_id; + rep = r; + break; + } + default: + break; + } - return r; + return rep; } static const struct scmi_event sensor_events[] = { @@ -324,6 +926,16 @@ static const struct scmi_event sensor_events[] = { .max_payld_sz = sizeof(struct scmi_sensor_trip_notify_payld), .max_report_sz = sizeof(struct scmi_sensor_trip_point_report), }, + { + .id = SCMI_EVENT_SENSOR_UPDATE, + .max_payld_sz = + sizeof(struct scmi_sensor_update_notify_payld) + + SCMI_MAX_NUM_SENSOR_AXIS * + sizeof(struct scmi_sensor_reading_resp), + .max_report_sz = sizeof(struct scmi_sensor_update_report) + + SCMI_MAX_NUM_SENSOR_AXIS * + sizeof(struct scmi_sensor_reading), + }, }; static const struct scmi_event_ops sensor_event_ops = { @@ -334,6 +946,7 @@ static const struct scmi_event_ops sensor_event_ops = { static int scmi_sensors_protocol_init(struct scmi_handle *handle) { u32 version; + int ret; struct sensors_info *sinfo; scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version); @@ -344,15 +957,19 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle) sinfo = devm_kzalloc(handle->dev, sizeof(*sinfo), GFP_KERNEL); if (!sinfo) return -ENOMEM; + sinfo->version = version; - scmi_sensor_attributes_get(handle, sinfo); - + ret = scmi_sensor_attributes_get(handle, sinfo); + if (ret) + return ret; sinfo->sensors = devm_kcalloc(handle->dev, sinfo->num_sensors, sizeof(*sinfo->sensors), GFP_KERNEL); if (!sinfo->sensors) return -ENOMEM; - scmi_sensor_description_get(handle, sinfo); + ret = scmi_sensor_description_get(handle, sinfo); + if (ret) + return ret; scmi_register_protocol_events(handle, SCMI_PROTOCOL_SENSOR, SCMI_PROTO_QUEUE_SZ, @@ -360,9 +977,8 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle) ARRAY_SIZE(sensor_events), sinfo->num_sensors); - sinfo->version = version; - handle->sensor_ops = &sensor_ops; handle->sensor_priv = sinfo; + handle->sensor_ops = &sensor_ops; return 0; } diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c index 4265e9dbed84..a6c06d7476c3 100644 --- a/drivers/firmware/imx/imx-dsp.c +++ b/drivers/firmware/imx/imx-dsp.c @@ -60,22 +60,40 @@ static void imx_dsp_handle_rx(struct mbox_client *c, void *msg) } } -static int imx_dsp_probe(struct platform_device *pdev) +struct mbox_chan *imx_dsp_request_channel(struct imx_dsp_ipc *dsp_ipc, int idx) { - struct device *dev = &pdev->dev; - struct imx_dsp_ipc *dsp_ipc; + struct imx_dsp_chan *dsp_chan; + + if (idx >= DSP_MU_CHAN_NUM) + return ERR_PTR(-EINVAL); + + dsp_chan = &dsp_ipc->chans[idx]; + dsp_chan->ch = mbox_request_channel_byname(&dsp_chan->cl, dsp_chan->name); + return dsp_chan->ch; +} +EXPORT_SYMBOL(imx_dsp_request_channel); + +void imx_dsp_free_channel(struct imx_dsp_ipc *dsp_ipc, int idx) +{ + struct imx_dsp_chan *dsp_chan; + + if (idx >= DSP_MU_CHAN_NUM) + return; + + dsp_chan = &dsp_ipc->chans[idx]; + mbox_free_channel(dsp_chan->ch); +} +EXPORT_SYMBOL(imx_dsp_free_channel); + +static int imx_dsp_setup_channels(struct imx_dsp_ipc *dsp_ipc) +{ + struct device *dev = dsp_ipc->dev; struct imx_dsp_chan *dsp_chan; struct mbox_client *cl; char *chan_name; int ret; int i, j; - device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); - - dsp_ipc = devm_kzalloc(dev, sizeof(*dsp_ipc), GFP_KERNEL); - if (!dsp_ipc) - return -ENOMEM; - for (i = 0; i < DSP_MU_CHAN_NUM; i++) { if (i < 2) chan_name = kasprintf(GFP_KERNEL, "txdb%d", i); @@ -86,6 +104,7 @@ static int imx_dsp_probe(struct platform_device *pdev) return -ENOMEM; dsp_chan = &dsp_ipc->chans[i]; + dsp_chan->name = chan_name; cl = &dsp_chan->cl; cl->dev = dev; cl->tx_block = false; @@ -104,27 +123,43 @@ static int imx_dsp_probe(struct platform_device *pdev) } dev_dbg(dev, "request mbox chan %s\n", chan_name); - /* chan_name is not used anymore by framework */ - kfree(chan_name); } - dsp_ipc->dev = dev; - - dev_set_drvdata(dev, dsp_ipc); - - dev_info(dev, "NXP i.MX DSP IPC initialized\n"); - return 0; out: - kfree(chan_name); for (j = 0; j < i; j++) { dsp_chan = &dsp_ipc->chans[j]; mbox_free_channel(dsp_chan->ch); + kfree(dsp_chan->name); } return ret; } +static int imx_dsp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct imx_dsp_ipc *dsp_ipc; + int ret; + + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); + + dsp_ipc = devm_kzalloc(dev, sizeof(*dsp_ipc), GFP_KERNEL); + if (!dsp_ipc) + return -ENOMEM; + + dsp_ipc->dev = dev; + dev_set_drvdata(dev, dsp_ipc); + + ret = imx_dsp_setup_channels(dsp_ipc); + if (ret < 0) + return ret; + + dev_info(dev, "NXP i.MX DSP IPC initialized\n"); + + return 0; +} + static int imx_dsp_remove(struct platform_device *pdev) { struct imx_dsp_chan *dsp_chan; @@ -136,6 +171,7 @@ static int imx_dsp_remove(struct platform_device *pdev) for (i = 0; i < DSP_MU_CHAN_NUM; i++) { dsp_chan = &dsp_ipc->chans[i]; mbox_free_channel(dsp_chan->ch); + kfree(dsp_chan->name); } return 0; diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index 946eea292b52..08533ee67626 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -160,12 +160,18 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 }, { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 }, + { "mipi1", IMX_SC_R_MIPI_1, 1, false, 0 }, + { "mipi1-pwm0", IMX_SC_R_MIPI_1_PWM_0, 1, false, 0 }, + { "mipi1-i2c", IMX_SC_R_MIPI_1_I2C_0, 2, true, 0 }, + /* LVDS SS */ { "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 }, + { "lvds1", IMX_SC_R_LVDS_1, 1, false, 0 }, /* DC SS */ { "dc0", IMX_SC_R_DC_0, 1, false, 0 }, { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 }, + { "dc0-video", IMX_SC_R_DC_0_VIDEO0, 2, true, 0 }, /* CM40 SS */ { "cm40-i2c", IMX_SC_R_M4_0_I2C, 1, false, 0 }, @@ -180,6 +186,12 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { { "cm41-pid", IMX_SC_R_M4_1_PID0, 5, true, 0}, { "cm41-mu-a1", IMX_SC_R_M4_1_MU_1A, 1, false, 0}, { "cm41-lpuart", IMX_SC_R_M4_1_UART, 1, false, 0}, + + /* IMAGE SS */ + { "img-jpegdec-mp", IMX_SC_R_MJPEG_DEC_MP, 1, false, 0 }, + { "img-jpegdec-s0", IMX_SC_R_MJPEG_DEC_S0, 4, true, 0 }, + { "img-jpegenc-mp", IMX_SC_R_MJPEG_ENC_MP, 1, false, 0 }, + { "img-jpegenc-s0", IMX_SC_R_MJPEG_ENC_S0, 4, true, 0 }, }; static const struct imx_sc_pd_soc imx8qxp_scu_pd = { diff --git a/drivers/firmware/meson/Kconfig b/drivers/firmware/meson/Kconfig index 2671dcd0ad92..f2fdd3756648 100644 --- a/drivers/firmware/meson/Kconfig +++ b/drivers/firmware/meson/Kconfig @@ -3,8 +3,9 @@ # Amlogic Secure Monitor driver # config MESON_SM - bool - default ARCH_MESON + tristate "Amlogic Secure Monitor driver" + depends on ARCH_MESON || COMPILE_TEST + default y depends on ARM64_4K_PAGES help Say y here to enable the Amlogic secure monitor driver diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index 2854b56f6e0b..77aa5c6398aa 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -331,3 +331,4 @@ static struct platform_driver meson_sm_driver = { }, }; module_platform_driver_probe(meson_sm_driver, meson_sm_probe); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c index c1bbba9ee93a..440d99c63638 100644 --- a/drivers/firmware/tegra/bpmp-debugfs.c +++ b/drivers/firmware/tegra/bpmp-debugfs.c @@ -412,16 +412,12 @@ static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp, goto out; } - len = strlen(ppath) + strlen(name) + 1; + len = snprintf(pathbuf, pathlen, "%s%s/", ppath, name); if (len >= pathlen) { err = -EINVAL; goto out; } - strncpy(pathbuf, ppath, pathlen); - strncat(pathbuf, name, strlen(name)); - strcat(pathbuf, "/"); - err = bpmp_populate_debugfs_inband(bpmp, dentry, pathbuf); if (err < 0) diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 896f53ec7857..235c7e7869aa 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -1703,14 +1703,14 @@ fail: * @subtype: Resource assignment subtype that is being requested * from the given device. * @s_host: Host processor ID to which the resources are allocated - * @range_start: Start index of the resource range - * @range_num: Number of resources in the range + * @desc: Pointer to ti_sci_resource_desc to be updated with the + * resource range start index and number of resources * * Return: 0 if all went fine, else return appropriate error. */ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle, u32 dev_id, u8 subtype, u8 s_host, - u16 *range_start, u16 *range_num) + struct ti_sci_resource_desc *desc) { struct ti_sci_msg_resp_get_resource_range *resp; struct ti_sci_msg_req_get_resource_range *req; @@ -1721,7 +1721,7 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle, if (IS_ERR(handle)) return PTR_ERR(handle); - if (!handle) + if (!handle || !desc) return -EINVAL; info = handle_to_ti_sci_info(handle); @@ -1751,11 +1751,14 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle, if (!ti_sci_is_response_ack(resp)) { ret = -ENODEV; - } else if (!resp->range_start && !resp->range_num) { + } else if (!resp->range_num && !resp->range_num_sec) { + /* Neither of the two resource range is valid */ ret = -ENODEV; } else { - *range_start = resp->range_start; - *range_num = resp->range_num; + desc->start = resp->range_start; + desc->num = resp->range_num; + desc->start_sec = resp->range_start_sec; + desc->num_sec = resp->range_num_sec; }; fail: @@ -1771,18 +1774,18 @@ fail: * @dev_id: TISCI device ID. * @subtype: Resource assignment subtype that is being requested * from the given device. - * @range_start: Start index of the resource range - * @range_num: Number of resources in the range + * @desc: Pointer to ti_sci_resource_desc to be updated with the + * resource range start index and number of resources * * Return: 0 if all went fine, else return appropriate error. */ static int ti_sci_cmd_get_resource_range(const struct ti_sci_handle *handle, u32 dev_id, u8 subtype, - u16 *range_start, u16 *range_num) + struct ti_sci_resource_desc *desc) { return ti_sci_get_resource_range(handle, dev_id, subtype, TI_SCI_IRQ_SECONDARY_HOST_INVALID, - range_start, range_num); + desc); } /** @@ -1793,18 +1796,17 @@ static int ti_sci_cmd_get_resource_range(const struct ti_sci_handle *handle, * @subtype: Resource assignment subtype that is being requested * from the given device. * @s_host: Host processor ID to which the resources are allocated - * @range_start: Start index of the resource range - * @range_num: Number of resources in the range + * @desc: Pointer to ti_sci_resource_desc to be updated with the + * resource range start index and number of resources * * Return: 0 if all went fine, else return appropriate error. */ static int ti_sci_cmd_get_resource_range_from_shost(const struct ti_sci_handle *handle, u32 dev_id, u8 subtype, u8 s_host, - u16 *range_start, u16 *range_num) + struct ti_sci_resource_desc *desc) { - return ti_sci_get_resource_range(handle, dev_id, subtype, s_host, - range_start, range_num); + return ti_sci_get_resource_range(handle, dev_id, subtype, s_host, desc); } /** @@ -2047,28 +2049,17 @@ static int ti_sci_cmd_free_event_map(const struct ti_sci_handle *handle, } /** - * ti_sci_cmd_ring_config() - configure RA ring - * @handle: Pointer to TI SCI handle. - * @valid_params: Bitfield defining validity of ring configuration - * parameters - * @nav_id: Device ID of Navigator Subsystem from which the ring is - * allocated - * @index: Ring index - * @addr_lo: The ring base address lo 32 bits - * @addr_hi: The ring base address hi 32 bits - * @count: Number of ring elements - * @mode: The mode of the ring - * @size: The ring element size. - * @order_id: Specifies the ring's bus order ID + * ti_sci_cmd_rm_ring_cfg() - Configure a NAVSS ring + * @handle: Pointer to TI SCI handle. + * @params: Pointer to ti_sci_msg_rm_ring_cfg ring config structure * * Return: 0 if all went well, else returns appropriate error value. * - * See @ti_sci_msg_rm_ring_cfg_req for more info. + * See @ti_sci_msg_rm_ring_cfg and @ti_sci_msg_rm_ring_cfg_req for + * more info. */ -static int ti_sci_cmd_ring_config(const struct ti_sci_handle *handle, - u32 valid_params, u16 nav_id, u16 index, - u32 addr_lo, u32 addr_hi, u32 count, - u8 mode, u8 size, u8 order_id) +static int ti_sci_cmd_rm_ring_cfg(const struct ti_sci_handle *handle, + const struct ti_sci_msg_rm_ring_cfg *params) { struct ti_sci_msg_rm_ring_cfg_req *req; struct ti_sci_msg_hdr *resp; @@ -2092,15 +2083,17 @@ static int ti_sci_cmd_ring_config(const struct ti_sci_handle *handle, return ret; } req = (struct ti_sci_msg_rm_ring_cfg_req *)xfer->xfer_buf; - req->valid_params = valid_params; - req->nav_id = nav_id; - req->index = index; - req->addr_lo = addr_lo; - req->addr_hi = addr_hi; - req->count = count; - req->mode = mode; - req->size = size; - req->order_id = order_id; + req->valid_params = params->valid_params; + req->nav_id = params->nav_id; + req->index = params->index; + req->addr_lo = params->addr_lo; + req->addr_hi = params->addr_hi; + req->count = params->count; + req->mode = params->mode; + req->size = params->size; + req->order_id = params->order_id; + req->virtid = params->virtid; + req->asel = params->asel; ret = ti_sci_do_xfer(info, xfer); if (ret) { @@ -2109,90 +2102,11 @@ static int ti_sci_cmd_ring_config(const struct ti_sci_handle *handle, } resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; - ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; - -fail: - ti_sci_put_one_xfer(&info->minfo, xfer); - dev_dbg(dev, "RM_RA:config ring %u ret:%d\n", index, ret); - return ret; -} - -/** - * ti_sci_cmd_ring_get_config() - get RA ring configuration - * @handle: Pointer to TI SCI handle. - * @nav_id: Device ID of Navigator Subsystem from which the ring is - * allocated - * @index: Ring index - * @addr_lo: Returns ring's base address lo 32 bits - * @addr_hi: Returns ring's base address hi 32 bits - * @count: Returns number of ring elements - * @mode: Returns mode of the ring - * @size: Returns ring element size - * @order_id: Returns ring's bus order ID - * - * Return: 0 if all went well, else returns appropriate error value. - * - * See @ti_sci_msg_rm_ring_get_cfg_req for more info. - */ -static int ti_sci_cmd_ring_get_config(const struct ti_sci_handle *handle, - u32 nav_id, u32 index, u8 *mode, - u32 *addr_lo, u32 *addr_hi, - u32 *count, u8 *size, u8 *order_id) -{ - struct ti_sci_msg_rm_ring_get_cfg_resp *resp; - struct ti_sci_msg_rm_ring_get_cfg_req *req; - struct ti_sci_xfer *xfer; - struct ti_sci_info *info; - struct device *dev; - int ret = 0; - - if (IS_ERR_OR_NULL(handle)) - return -EINVAL; - - info = handle_to_ti_sci_info(handle); - dev = info->dev; - - xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_RM_RING_GET_CFG, - TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, - sizeof(*req), sizeof(*resp)); - if (IS_ERR(xfer)) { - ret = PTR_ERR(xfer); - dev_err(dev, - "RM_RA:Message get config failed(%d)\n", ret); - return ret; - } - req = (struct ti_sci_msg_rm_ring_get_cfg_req *)xfer->xfer_buf; - req->nav_id = nav_id; - req->index = index; - - ret = ti_sci_do_xfer(info, xfer); - if (ret) { - dev_err(dev, "RM_RA:Mbox get config send fail %d\n", ret); - goto fail; - } - - resp = (struct ti_sci_msg_rm_ring_get_cfg_resp *)xfer->xfer_buf; - - if (!ti_sci_is_response_ack(resp)) { - ret = -ENODEV; - } else { - if (mode) - *mode = resp->mode; - if (addr_lo) - *addr_lo = resp->addr_lo; - if (addr_hi) - *addr_hi = resp->addr_hi; - if (count) - *count = resp->count; - if (size) - *size = resp->size; - if (order_id) - *order_id = resp->order_id; - }; + ret = ti_sci_is_response_ack(resp) ? 0 : -EINVAL; fail: ti_sci_put_one_xfer(&info->minfo, xfer); - dev_dbg(dev, "RM_RA:get config ring %u ret:%d\n", index, ret); + dev_dbg(dev, "RM_RA:config ring %u ret:%d\n", params->index, ret); return ret; } @@ -2362,6 +2276,8 @@ static int ti_sci_cmd_rm_udmap_tx_ch_cfg(const struct ti_sci_handle *handle, req->fdepth = params->fdepth; req->tx_sched_priority = params->tx_sched_priority; req->tx_burst_size = params->tx_burst_size; + req->tx_tdtype = params->tx_tdtype; + req->extended_ch_type = params->extended_ch_type; ret = ti_sci_do_xfer(info, xfer); if (ret) { @@ -2921,8 +2837,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) iops->free_irq = ti_sci_cmd_free_irq; iops->free_event_map = ti_sci_cmd_free_event_map; - rops->config = ti_sci_cmd_ring_config; - rops->get_config = ti_sci_cmd_ring_get_config; + rops->set_cfg = ti_sci_cmd_rm_ring_cfg; psilops->pair = ti_sci_cmd_rm_psil_pair; psilops->unpair = ti_sci_cmd_rm_psil_unpair; @@ -3157,12 +3072,18 @@ u16 ti_sci_get_free_resource(struct ti_sci_resource *res) raw_spin_lock_irqsave(&res->lock, flags); for (set = 0; set < res->sets; set++) { - free_bit = find_first_zero_bit(res->desc[set].res_map, - res->desc[set].num); - if (free_bit != res->desc[set].num) { - set_bit(free_bit, res->desc[set].res_map); + struct ti_sci_resource_desc *desc = &res->desc[set]; + int res_count = desc->num + desc->num_sec; + + free_bit = find_first_zero_bit(desc->res_map, res_count); + if (free_bit != res_count) { + set_bit(free_bit, desc->res_map); raw_spin_unlock_irqrestore(&res->lock, flags); - return res->desc[set].start + free_bit; + + if (desc->num && free_bit < desc->num) + return desc->start + free_bit; + else + return desc->start_sec + free_bit; } } raw_spin_unlock_irqrestore(&res->lock, flags); @@ -3183,10 +3104,14 @@ void ti_sci_release_resource(struct ti_sci_resource *res, u16 id) raw_spin_lock_irqsave(&res->lock, flags); for (set = 0; set < res->sets; set++) { - if (res->desc[set].start <= id && - (res->desc[set].num + res->desc[set].start) > id) - clear_bit(id - res->desc[set].start, - res->desc[set].res_map); + struct ti_sci_resource_desc *desc = &res->desc[set]; + + if (desc->num && desc->start <= id && + (desc->start + desc->num) > id) + clear_bit(id - desc->start, desc->res_map); + else if (desc->num_sec && desc->start_sec <= id && + (desc->start_sec + desc->num_sec) > id) + clear_bit(id - desc->start_sec, desc->res_map); } raw_spin_unlock_irqrestore(&res->lock, flags); } @@ -3203,7 +3128,7 @@ u32 ti_sci_get_num_resources(struct ti_sci_resource *res) u32 set, count = 0; for (set = 0; set < res->sets; set++) - count += res->desc[set].num; + count += res->desc[set].num + res->desc[set].num_sec; return count; } @@ -3227,7 +3152,7 @@ devm_ti_sci_get_resource_sets(const struct ti_sci_handle *handle, { struct ti_sci_resource *res; bool valid_set = false; - int i, ret; + int i, ret, res_count; res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL); if (!res) @@ -3242,23 +3167,23 @@ devm_ti_sci_get_resource_sets(const struct ti_sci_handle *handle, for (i = 0; i < res->sets; i++) { ret = handle->ops.rm_core_ops.get_range(handle, dev_id, sub_types[i], - &res->desc[i].start, - &res->desc[i].num); + &res->desc[i]); if (ret) { dev_dbg(dev, "dev = %d subtype %d not allocated for this host\n", dev_id, sub_types[i]); - res->desc[i].start = 0; - res->desc[i].num = 0; + memset(&res->desc[i], 0, sizeof(res->desc[i])); continue; } - dev_dbg(dev, "dev = %d, subtype = %d, start = %d, num = %d\n", + dev_dbg(dev, "dev/sub_type: %d/%d, start/num: %d/%d | %d/%d\n", dev_id, sub_types[i], res->desc[i].start, - res->desc[i].num); + res->desc[i].num, res->desc[i].start_sec, + res->desc[i].num_sec); valid_set = true; + res_count = res->desc[i].num + res->desc[i].num_sec; res->desc[i].res_map = - devm_kzalloc(dev, BITS_TO_LONGS(res->desc[i].num) * + devm_kzalloc(dev, BITS_TO_LONGS(res_count) * sizeof(*res->desc[i].res_map), GFP_KERNEL); if (!res->desc[i].res_map) return ERR_PTR(-ENOMEM); diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 57cd04062994..ef3a8214d002 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -49,7 +49,6 @@ #define TI_SCI_MSG_RM_RING_RECONFIG 0x1102 #define TI_SCI_MSG_RM_RING_RESET 0x1103 #define TI_SCI_MSG_RM_RING_CFG 0x1110 -#define TI_SCI_MSG_RM_RING_GET_CFG 0x1111 /* PSI-L requests */ #define TI_SCI_MSG_RM_PSIL_PAIR 0x1280 @@ -574,8 +573,10 @@ struct ti_sci_msg_req_get_resource_range { /** * struct ti_sci_msg_resp_get_resource_range - Response to resource get range. * @hdr: Generic Header - * @range_start: Start index of the resource range. - * @range_num: Number of resources in the range. + * @range_start: Start index of the first resource range. + * @range_num: Number of resources in the first range. + * @range_start_sec: Start index of the second resource range. + * @range_num_sec: Number of resources in the second range. * * Response to request TI_SCI_MSG_GET_RESOURCE_RANGE. */ @@ -583,6 +584,8 @@ struct ti_sci_msg_resp_get_resource_range { struct ti_sci_msg_hdr hdr; u16 range_start; u16 range_num; + u16 range_start_sec; + u16 range_num_sec; } __packed; /** @@ -656,6 +659,8 @@ struct ti_sci_msg_req_manage_irq { * 3 - Valid bit for @tisci_msg_rm_ring_cfg_req mode * 4 - Valid bit for @tisci_msg_rm_ring_cfg_req size * 5 - Valid bit for @tisci_msg_rm_ring_cfg_req order_id + * 6 - Valid bit for @tisci_msg_rm_ring_cfg_req virtid + * 7 - Valid bit for @tisci_msg_rm_ring_cfg_req ASEL * @nav_id: Device ID of Navigator Subsystem from which the ring is allocated * @index: ring index to be configured. * @addr_lo: 32 LSBs of ring base address to be programmed into the ring's @@ -669,6 +674,9 @@ struct ti_sci_msg_req_manage_irq { * the formula (log2(size_bytes) - 2), where size_bytes cannot be * greater than 256. * @order_id: Specifies the ring's bus order ID. + * @virtid: Ring virt ID value + * @asel: Ring ASEL (address select) value to be set into the ASEL field of the + * ring's RING_BA_HI register. */ struct ti_sci_msg_rm_ring_cfg_req { struct ti_sci_msg_hdr hdr; @@ -681,49 +689,8 @@ struct ti_sci_msg_rm_ring_cfg_req { u8 mode; u8 size; u8 order_id; -} __packed; - -/** - * struct ti_sci_msg_rm_ring_get_cfg_req - Get RA ring's configuration - * - * Gets the configuration of the non-real-time register fields of a ring. The - * host, or a supervisor of the host, who owns the ring must be the requesting - * host. The values of the non-real-time registers are returned in - * @ti_sci_msg_rm_ring_get_cfg_resp. - * - * @hdr: Generic Header - * @nav_id: Device ID of Navigator Subsystem from which the ring is allocated - * @index: ring index. - */ -struct ti_sci_msg_rm_ring_get_cfg_req { - struct ti_sci_msg_hdr hdr; - u16 nav_id; - u16 index; -} __packed; - -/** - * struct ti_sci_msg_rm_ring_get_cfg_resp - Ring get configuration response - * - * Response received by host processor after RM has handled - * @ti_sci_msg_rm_ring_get_cfg_req. The response contains the ring's - * non-real-time register values. - * - * @hdr: Generic Header - * @addr_lo: Ring 32 LSBs of base address - * @addr_hi: Ring 16 MSBs of base address. - * @count: Ring number of elements. - * @mode: Ring mode. - * @size: encoded Ring element size - * @order_id: ing order ID. - */ -struct ti_sci_msg_rm_ring_get_cfg_resp { - struct ti_sci_msg_hdr hdr; - u32 addr_lo; - u32 addr_hi; - u32 count; - u8 mode; - u8 size; - u8 order_id; + u16 virtid; + u8 asel; } __packed; /** @@ -910,6 +877,8 @@ struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg { * 12 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_credit_count * 13 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::fdepth * 14 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_burst_size + * 15 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::tx_tdtype + * 16 - Valid bit for @ref ti_sci_msg_rm_udmap_tx_ch_cfg::extended_ch_type * * @nav_id: SoC device ID of Navigator Subsystem where tx channel is located * @@ -973,6 +942,15 @@ struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg { * * @tx_burst_size: UDMAP transmit channel burst size configuration to be * programmed into the tx_burst_size field of the TCHAN_TCFG register. + * + * @tx_tdtype: UDMAP transmit channel teardown type configuration to be + * programmed into the tdtype field of the TCHAN_TCFG register: + * 0 - Return immediately + * 1 - Wait for completion message from remote peer + * + * @extended_ch_type: Valid for BCDMA. + * 0 - the channel is split tx channel (tchan) + * 1 - the channel is block copy channel (bchan) */ struct ti_sci_msg_rm_udmap_tx_ch_cfg_req { struct ti_sci_msg_hdr hdr; @@ -994,6 +972,8 @@ struct ti_sci_msg_rm_udmap_tx_ch_cfg_req { u16 fdepth; u8 tx_sched_priority; u8 tx_burst_size; + u8 tx_tdtype; + u8 extended_ch_type; } __packed; /** diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index fd95edeb702b..7eb9958662dd 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -615,13 +615,13 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data); /** * zynqmp_pm_set_sd_tapdelay() - Set tap delay for the SD device * - * @node_id Node ID of the device - * @type Type of tap delay to set (input/output) - * @value Value to set fot the tap delay + * @node_id: Node ID of the device + * @type: Type of tap delay to set (input/output) + * @value: Value to set fot the tap delay * * This function sets input/output tap delay for the SD device. * - * @return Returns status, either success or error+reason + * Return: Returns status, either success or error+reason */ int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value) { @@ -633,12 +633,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay); /** * zynqmp_pm_sd_dll_reset() - Reset DLL logic * - * @node_id Node ID of the device - * @type Reset type + * @node_id: Node ID of the device + * @type: Reset type * * This function resets DLL logic for the SD device. * - * @return Returns status, either success or error+reason + * Return: Returns status, either success or error+reason */ int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type) { @@ -649,12 +649,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset); /** * zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs) - * @index GGS register index - * @value Register value to be written + * @index: GGS register index + * @value: Register value to be written * * This function writes value to GGS register. * - * @return Returns status, either success or error+reason + * Return: Returns status, either success or error+reason */ int zynqmp_pm_write_ggs(u32 index, u32 value) { @@ -665,12 +665,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs); /** * zynqmp_pm_write_ggs() - PM API for reading global general storage (ggs) - * @index GGS register index - * @value Register value to be written + * @index: GGS register index + * @value: Register value to be written * * This function returns GGS register value. * - * @return Returns status, either success or error+reason + * Return: Returns status, either success or error+reason */ int zynqmp_pm_read_ggs(u32 index, u32 *value) { @@ -682,12 +682,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs); /** * zynqmp_pm_write_pggs() - PM API for writing persistent global general * storage (pggs) - * @index PGGS register index - * @value Register value to be written + * @index: PGGS register index + * @value: Register value to be written * * This function writes value to PGGS register. * - * @return Returns status, either success or error+reason + * Return: Returns status, either success or error+reason */ int zynqmp_pm_write_pggs(u32 index, u32 value) { @@ -699,12 +699,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs); /** * zynqmp_pm_write_pggs() - PM API for reading persistent global general * storage (pggs) - * @index PGGS register index - * @value Register value to be written + * @index: PGGS register index + * @value: Register value to be written * * This function returns PGGS register value. * - * @return Returns status, either success or error+reason + * Return: Returns status, either success or error+reason */ int zynqmp_pm_read_pggs(u32 index, u32 *value) { @@ -715,12 +715,12 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs); /** * zynqmp_pm_set_boot_health_status() - PM API for setting healthy boot status - * @value Status value to be written + * @value: Status value to be written * * This function sets healthy bit value to indicate boot health status * to firmware. * - * @return Returns status, either success or error+reason + * Return: Returns status, either success or error+reason */ int zynqmp_pm_set_boot_health_status(u32 value) { @@ -815,10 +815,10 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_status); * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller * master has initialized its own power management * + * Return: Returns status, either success or error+reason + * * This API function is to be used for notify the power management controller * about the completed power management initialization. - * - * Return: Returns status, either success or error+reason */ int zynqmp_pm_init_finalize(void) { |