From 85a55eeed40db02dfe292712c1789953712f86a4 Mon Sep 17 00:00:00 2001 From: Sudeepgoud Patil Date: Tue, 16 Jul 2024 23:08:34 +0530 Subject: [PATCH 001/212] soc: qcom: smp2p: Introduce tracepoint support Introduce tracepoint support for smp2p to enable communication logging between local and remote processors. Include tracepoints with information about the remote subsystem name, negotiation details, supported features, bit change notifications, and ssr activity. These logs are useful for debugging issues between subsystems. Signed-off-by: Sudeepgoud Patil Link: https://lore.kernel.org/r/20240716173835.997259-3-quic_sudeepgo@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/smp2p.c | 9 ++++ drivers/soc/qcom/trace-smp2p.h | 98 ++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 drivers/soc/qcom/trace-smp2p.h diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index d3560f861085..acbca2ab5cc2 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -25,6 +25,7 @@ qcom_rpmh-y += rpmh.o obj-$(CONFIG_QCOM_SMD_RPM) += rpm-proc.o smd-rpm.o obj-$(CONFIG_QCOM_SMEM) += smem.o obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o +CFLAGS_smp2p.o := -I$(src) obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index 696c2a8387d0..4aa61b0f11ad 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -161,6 +161,9 @@ struct qcom_smp2p { struct list_head outbound; }; +#define CREATE_TRACE_POINTS +#include "trace-smp2p.h" + static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) { /* Make sure any updated data is written before the kick */ @@ -192,6 +195,7 @@ static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) struct smp2p_smem_item *out = smp2p->out; u32 val; + trace_smp2p_ssr_ack(smp2p->dev); smp2p->ssr_ack = !smp2p->ssr_ack; val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT); @@ -214,6 +218,7 @@ static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p) smp2p->ssr_ack_enabled = true; smp2p->negotiation_done = true; + trace_smp2p_negotiate(smp2p->dev, out->features); } } @@ -252,6 +257,8 @@ static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p) status = val ^ entry->last_value; entry->last_value = val; + trace_smp2p_notify_in(entry, status, val); + /* No changes of this entry? */ if (!status) continue; @@ -415,6 +422,8 @@ static int smp2p_update_bits(void *data, u32 mask, u32 value) writel(val, entry->value); spin_unlock_irqrestore(&entry->lock, flags); + trace_smp2p_update_bits(entry, orig, val); + if (val != orig) qcom_smp2p_kick(entry->smp2p); diff --git a/drivers/soc/qcom/trace-smp2p.h b/drivers/soc/qcom/trace-smp2p.h new file mode 100644 index 000000000000..9a6392043f10 --- /dev/null +++ b/drivers/soc/qcom/trace-smp2p.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM qcom_smp2p + +#if !defined(__QCOM_SMP2P_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) +#define __QCOM_SMP2P_TRACE_H__ + +#include +#include + +TRACE_EVENT(smp2p_ssr_ack, + TP_PROTO(const struct device *dev), + TP_ARGS(dev), + TP_STRUCT__entry( + __string(dev_name, dev_name(dev)) + ), + TP_fast_assign( + __assign_str(dev_name); + ), + TP_printk("%s: SSR detected", __get_str(dev_name)) +); + +TRACE_EVENT(smp2p_negotiate, + TP_PROTO(const struct device *dev, unsigned int features), + TP_ARGS(dev, features), + TP_STRUCT__entry( + __string(dev_name, dev_name(dev)) + __field(u32, out_features) + ), + TP_fast_assign( + __assign_str(dev_name); + __entry->out_features = features; + ), + TP_printk("%s: state=open out_features=%s", __get_str(dev_name), + __print_flags(__entry->out_features, "|", + {SMP2P_FEATURE_SSR_ACK, "SMP2P_FEATURE_SSR_ACK"}) + ) +); + +TRACE_EVENT(smp2p_notify_in, + TP_PROTO(struct smp2p_entry *smp2p_entry, unsigned long status, u32 val), + TP_ARGS(smp2p_entry, status, val), + TP_STRUCT__entry( + __string(dev_name, dev_name(smp2p_entry->smp2p->dev)) + __string(client_name, smp2p_entry->name) + __field(unsigned long, status) + __field(u32, val) + ), + TP_fast_assign( + __assign_str(dev_name); + __assign_str(client_name); + __entry->status = status; + __entry->val = val; + ), + TP_printk("%s: %s: status:0x%0lx val:0x%0x", + __get_str(dev_name), + __get_str(client_name), + __entry->status, + __entry->val + ) +); + +TRACE_EVENT(smp2p_update_bits, + TP_PROTO(struct smp2p_entry *smp2p_entry, u32 orig, u32 val), + TP_ARGS(smp2p_entry, orig, val), + TP_STRUCT__entry( + __string(dev_name, dev_name(smp2p_entry->smp2p->dev)) + __string(client_name, smp2p_entry->name) + __field(u32, orig) + __field(u32, val) + ), + TP_fast_assign( + __assign_str(dev_name); + __assign_str(client_name); + __entry->orig = orig; + __entry->val = val; + ), + TP_printk("%s: %s: orig:0x%0x new:0x%0x", + __get_str(dev_name), + __get_str(client_name), + __entry->orig, + __entry->val + ) +); + +#endif /* __QCOM_SMP2P_TRACE_H__ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace-smp2p + +#include From e6b5a4c3ae3b883cb13be2e1cd9fbf364928173e Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 19 Jul 2024 22:16:37 +0200 Subject: [PATCH 002/212] firmware: qcom: scm: Allow QSEECOM on ThinkPad T14s Add the aforementioned machine to the list to get e.g. efivars up. Signed-off-by: Konrad Dybcio Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20240719-topic-t14s_upstream-v1-2-d7d97fdebb28@linaro.org Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 00c379a3cceb..e60bef68401c 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -1724,6 +1724,7 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send); */ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { { .compatible = "lenovo,flex-5g" }, + { .compatible = "lenovo,thinkpad-t14s" }, { .compatible = "lenovo,thinkpad-x13s", }, { .compatible = "qcom,sc8180x-primus" }, { .compatible = "qcom,x1e80100-crd" }, From 99a7b371eef63507c1761e367382d78ebec0a5ab Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 23 Jul 2024 13:45:42 +0530 Subject: [PATCH 003/212] soc: qcom: llcc: Update configuration data for x1e80100 Update the configuration table for x1e80100 with the latest recommendations from the SCT table. Signed-off-by: Rajendra Nayak Tested-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240723081542.1522249-1-quic_rjendra@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 37e11e501728..8fa4ffd3a9b5 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -453,26 +453,24 @@ static const struct llcc_slice_config qdu1000_data_8ch[] = { }; static const struct llcc_slice_config x1e80100_data[] = { - {LLCC_CPUSS, 1, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_VIDSC0, 2, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_AUDIO, 6, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CPUSS, 1, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_VIDSC0, 2, 512, 4, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_AUDIO, 6, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {LLCC_CMPT, 10, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_GPUHTW, 11, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_GPU, 9, 4096, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_MMUHWT, 18, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_GPU, 9, 4608, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_MMUHWT, 18, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CVP, 8, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP1, 7, 3072, 2, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_LCPDARE, 30, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CVP, 8, 512, 4, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_WRCACHE, 31, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP0, 4, 256, 4, 1, 0x3, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP1, 7, 3072, 3, 1, 0xFFC, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_LCPDARE, 30, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, {LLCC_AENPU, 3, 3072, 1, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_ISLAND1, 12, 512, 7, 1, 0x1, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_ISLAND2, 13, 512, 7, 1, 0x2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_ISLAND3, 14, 512, 7, 1, 0x3, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_ISLAND4, 15, 512, 7, 1, 0x4, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP2, 19, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP3, 20, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP4, 21, 3072, 3, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_ISLAND1, 12, 2048, 7, 1, 0x0, 0xF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP2, 19, 3072, 3, 1, 0xFFC, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP3, 20, 3072, 2, 1, 0xFFC, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CAMEXP4, 21, 3072, 2, 1, 0xFFC, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }; static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { From 649f4783dcda7400bbed866140df504d09a3b135 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 4 Jul 2024 12:31:20 +0100 Subject: [PATCH 004/212] memory: tegra: Remove periodic compensation duplicate calls Prior to calling periodic_compensation_handler() the code is doing one extra DRAM delay reading which is unnecessary as this is already done in periodic_compensation_handler(), so remove these extra calls. Signed-off-by: Diogo Ivo Link: https://lore.kernel.org/r/20240704-tegra210_emcfreq-v4-1-3e450503c555@tecnico.ulisboa.pt Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra210-emc-cc-r21021.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index 4cb608c71ead..9ec49ced8f91 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -492,7 +492,6 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc) }; struct tegra210_emc_timing *last = emc->last; unsigned int items = ARRAY_SIZE(list), i; - unsigned long delay; if (last->periodic_training) { emc_dbg(emc, PER_TRAIN, "Periodic training starting\n"); @@ -530,18 +529,9 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc) /* * 2. osc kick off - this assumes training and dvfs have set * correct MR23. - */ - tegra210_emc_start_periodic_compensation(emc); - - /* + * * 3. Let dram capture its clock tree delays. - */ - delay = tegra210_emc_actual_osc_clocks(last->run_clocks); - delay *= 1000; - delay /= last->rate + 1; - udelay(delay); - - /* + * * 4. Check delta wrt previous values (save value if margin * exceeds what is set in table). */ @@ -734,11 +724,6 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc) EMC_EMC_STATUS_DRAM_IN_SELF_REFRESH_MASK, 0); - tegra210_emc_start_periodic_compensation(emc); - - delay = 1000 * tegra210_emc_actual_osc_clocks(last->run_clocks); - udelay((delay / last->rate) + 2); - value = periodic_compensation_handler(emc, DVFS_SEQUENCE, fake, next); value = (value * 128 * next->rate / 1000) / 1000000; From 7b4dcb8888e1660d590ec13463ba71ec5bbf6333 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 4 Jul 2024 12:31:21 +0100 Subject: [PATCH 005/212] memory: tegra: Move DQSOSC measurement to common place Move the calls that instruct the RAM to capture its clock tree delays to update_clock_tree_delay() in order to avoid code duplication. Signed-off-by: Diogo Ivo Link: https://lore.kernel.org/r/20240704-tegra210_emcfreq-v4-2-3e450503c555@tecnico.ulisboa.pt Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra210-emc-cc-r21021.c | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index 9ec49ced8f91..a3525f3b8145 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -123,10 +123,19 @@ static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) bool dvfs_update = type == DVFS_UPDATE; s32 tdel = 0, tmdel = 0, adel = 0; bool dvfs_pt1 = type == DVFS_PT1; + u32 temp[2][2], value, delay_us; unsigned long cval = 0; - u32 temp[2][2], value; unsigned int i; + if (dvfs_pt1 || periodic_training_update) { + delay_us = tegra210_emc_actual_osc_clocks(last->run_clocks); + delay_us *= 1000; + delay_us = 2 + (delay_us / last->rate); + + tegra210_emc_start_periodic_compensation(emc); + udelay(delay_us); + } + /* * Dev0 MSB. */ @@ -409,11 +418,6 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, (nt)->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; }) u32 i, adel = 0, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; - u32 delay; - - delay = tegra210_emc_actual_osc_clocks(last->run_clocks); - delay *= 1000; - delay = 2 + (delay / last->rate); if (!next->periodic_training) return 0; @@ -447,9 +451,6 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, __MOVAVG(next, C1D1U1) = 0; for (i = 0; i < samples; i++) { - tegra210_emc_start_periodic_compensation(emc); - udelay(delay); - /* * Generate next sample of data. */ @@ -465,12 +466,8 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, adel = update_clock_tree_delay(emc, DVFS_UPDATE); } - if (type == PERIODIC_TRAINING_SEQUENCE) { - tegra210_emc_start_periodic_compensation(emc); - udelay(delay); - + if (type == PERIODIC_TRAINING_SEQUENCE) adel = update_clock_tree_delay(emc, PERIODIC_TRAINING_UPDATE); - } return adel; } From c5f83622ccd0158cf16c6be8ba56f178c99776a5 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 4 Jul 2024 12:31:22 +0100 Subject: [PATCH 006/212] memory: tegra: Reword and correct comments Fix incorrect comment on periodic_compensation_handler() as the call update_clock_tree_delay() with DVFS_UPDATE is responsible for dividing the samples accumulated up to that point and comparing the computed values with the currently programmed ones. While at it fix the indentation of a nearby comment. Signed-off-by: Diogo Ivo Link: https://lore.kernel.org/r/20240704-tegra210_emcfreq-v4-3-3e450503c555@tecnico.ulisboa.pt Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra210-emc-cc-r21021.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index a3525f3b8145..a9e19dfa9856 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -451,18 +451,12 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, __MOVAVG(next, C1D1U1) = 0; for (i = 0; i < samples; i++) { - /* - * Generate next sample of data. - */ + /* Generate next sample of data. */ adel = update_clock_tree_delay(emc, DVFS_PT1); } } - /* - * Seems like it should be part of the - * 'if (last_timing->periodic_training)' conditional - * since is already done for the else clause. - */ + /* Do the division part of the moving average */ adel = update_clock_tree_delay(emc, DVFS_UPDATE); } From a238f62b3666558f38d8abf688d0fecf4ccb48ee Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 4 Jul 2024 12:31:23 +0100 Subject: [PATCH 007/212] memory: tegra: Change macros to interpret parameter as integer Convert the macros that manipulate the delay values to interpret their index parameter as an integer to allow the introduction of loops. Signed-off-by: Diogo Ivo Link: https://lore.kernel.org/r/20240704-tegra210_emcfreq-v4-4-3e450503c555@tecnico.ulisboa.pt Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra210-emc-cc-r21021.c | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index a9e19dfa9856..bfb01918270e 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -75,29 +75,29 @@ enum { * The division portion of the average operation. */ #define __AVERAGE_PTFV(dev) \ - ({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] = \ - next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \ + ({ next->ptfv_list[(dev)] = \ + next->ptfv_list[(dev)] / \ next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; }) /* * Convert val to fixed point and add it to the temporary average. */ #define __INCREMENT_PTFV(dev, val) \ - ({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] += \ + ({ next->ptfv_list[(dev)] += \ ((val) * MOVAVG_PRECISION_FACTOR); }) /* * Convert a moving average back to integral form and return the value. */ #define __MOVAVG_AC(timing, dev) \ - ((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \ + ((timing)->ptfv_list[(dev)] / \ MOVAVG_PRECISION_FACTOR) /* Weighted update. */ #define __WEIGHTED_UPDATE_PTFV(dev, nval) \ do { \ int w = PTFV_MOVAVG_WEIGHT_INDEX; \ - int dqs = PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX; \ + int dqs = (dev); \ \ next->ptfv_list[dqs] = \ ((nval * MOVAVG_PRECISION_FACTOR) + \ @@ -111,7 +111,7 @@ enum { /* Access a particular average. */ #define __MOVAVG(timing, dev) \ - ((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX]) + ((timing)->ptfv_list[(dev)]) static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) { @@ -418,6 +418,7 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, (nt)->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; }) u32 i, adel = 0, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; + u32 idx; if (!next->periodic_training) return 0; @@ -431,24 +432,12 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, * calibration then we can reuse the previous * frequencies EMA data. */ - __COPY_EMA(next, last, C0D0U0); - __COPY_EMA(next, last, C0D0U1); - __COPY_EMA(next, last, C1D0U0); - __COPY_EMA(next, last, C1D0U1); - __COPY_EMA(next, last, C0D1U0); - __COPY_EMA(next, last, C0D1U1); - __COPY_EMA(next, last, C1D1U0); - __COPY_EMA(next, last, C1D1U1); + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) + __COPY_EMA(next, last, idx); } else { /* Reset the EMA.*/ - __MOVAVG(next, C0D0U0) = 0; - __MOVAVG(next, C0D0U1) = 0; - __MOVAVG(next, C1D0U0) = 0; - __MOVAVG(next, C1D0U1) = 0; - __MOVAVG(next, C0D1U0) = 0; - __MOVAVG(next, C0D1U1) = 0; - __MOVAVG(next, C1D1U0) = 0; - __MOVAVG(next, C1D1U1) = 0; + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) + __MOVAVG(next, idx) = 0; for (i = 0; i < samples; i++) { /* Generate next sample of data. */ From adc720820f963047210efc4fe1c1ff068b4bd773 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 4 Jul 2024 12:31:24 +0100 Subject: [PATCH 008/212] memory: tegra: Loop update_clock_tree_delay() As the current form of this function in a completely unrolled loop over the RAM channels roll it up two levels to improve readability. Signed-off-by: Diogo Ivo Link: https://lore.kernel.org/r/20240704-tegra210_emcfreq-v4-5-3e450503c555@tecnico.ulisboa.pt Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra210-emc-cc-r21021.c | 324 ++++-------------- 1 file changed, 68 insertions(+), 256 deletions(-) diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index bfb01918270e..9262da658189 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -125,7 +125,7 @@ static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) bool dvfs_pt1 = type == DVFS_PT1; u32 temp[2][2], value, delay_us; unsigned long cval = 0; - unsigned int i; + unsigned int c, d, idx; if (dvfs_pt1 || periodic_training_update) { delay_us = tegra210_emc_actual_osc_clocks(last->run_clocks); @@ -136,276 +136,88 @@ static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) udelay(delay_us); } - /* - * Dev0 MSB. - */ - if (dvfs_pt1 || periodic_training_update) { - value = tegra210_emc_mrr_read(emc, 2, 19); - - for (i = 0; i < emc->num_channels; i++) { - temp[i][0] = (value & 0x00ff) << 8; - temp[i][1] = (value & 0xff00) << 0; - value >>= 16; - } - - /* - * Dev0 LSB. - */ - value = tegra210_emc_mrr_read(emc, 2, 18); - - for (i = 0; i < emc->num_channels; i++) { - temp[i][0] |= (value & 0x00ff) >> 0; - temp[i][1] |= (value & 0xff00) >> 8; - value >>= 16; - } - } - - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[0][0]; - } - - if (dvfs_pt1) - __INCREMENT_PTFV(C0D0U0, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C0D0U0); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C0D0U0, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C0D0U0] - - __MOVAVG_AC(next, C0D0U0); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C0D0U0] = - __MOVAVG_AC(next, C0D0U0); - } - - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[0][1]; - } - - if (dvfs_pt1) - __INCREMENT_PTFV(C0D0U1, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C0D0U1); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C0D0U1, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C0D0U1] - - __MOVAVG_AC(next, C0D0U1); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C0D0U1] = - __MOVAVG_AC(next, C0D0U1); - } - - if (emc->num_channels > 1) { + for (d = 0; d < emc->num_devices; d++) { if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[1][0]; + /* Dev[d] MSB */ + value = tegra210_emc_mrr_read(emc, 2 - d, 19); + + for (c = 0; c < emc->num_channels; c++) { + temp[c][0] = (value & 0x00ff) << 8; + temp[c][1] = (value & 0xff00) << 0; + value >>= 16; + } + + /* Dev[d] LSB */ + value = tegra210_emc_mrr_read(emc, 2 - d, 18); + + for (c = 0; c < emc->num_channels; c++) { + temp[c][0] |= (value & 0x00ff) >> 0; + temp[c][1] |= (value & 0xff00) >> 8; + value >>= 16; + } } - if (dvfs_pt1) - __INCREMENT_PTFV(C1D0U0, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C1D0U0); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C1D0U0, cval); + for (c = 0; c < emc->num_channels; c++) { + /* C[c]D[d]U[0] */ + idx = c * 4 + d * 2; - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C1D0U0] - - __MOVAVG_AC(next, C1D0U0); - tmdel = (tdel < 0) ? -1 * tdel : tdel; + if (dvfs_pt1 || periodic_training_update) { + cval = tegra210_emc_actual_osc_clocks(last->run_clocks); + cval *= 1000000; + cval /= last_timing_rate_mhz * 2 * temp[c][0]; + } - if (tmdel > adel) + if (dvfs_pt1) + __INCREMENT_PTFV(idx, cval); + else if (dvfs_update) + __AVERAGE_PTFV(idx); + else if (periodic_training_update) + __WEIGHTED_UPDATE_PTFV(idx, cval); + + if (dvfs_update || periodic_training_update) { + tdel = next->current_dram_clktree[idx] - + __MOVAVG_AC(next, idx); + tmdel = (tdel < 0) ? -1 * tdel : tdel; adel = tmdel; - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C1D0U0] = - __MOVAVG_AC(next, C1D0U0); - } + if (tmdel * 128 * next_timing_rate_mhz / 1000000 > + next->tree_margin) + next->current_dram_clktree[idx] = + __MOVAVG_AC(next, idx); + } - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[1][1]; - } + /* C[c]D[d]U[1] */ + idx++; - if (dvfs_pt1) - __INCREMENT_PTFV(C1D0U1, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C1D0U1); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C1D0U1, cval); + if (dvfs_pt1 || periodic_training_update) { + cval = tegra210_emc_actual_osc_clocks(last->run_clocks); + cval *= 1000000; + cval /= last_timing_rate_mhz * 2 * temp[c][1]; + } - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C1D0U1] - - __MOVAVG_AC(next, C1D0U1); - tmdel = (tdel < 0) ? -1 * tdel : tdel; + if (dvfs_pt1) + __INCREMENT_PTFV(idx, cval); + else if (dvfs_update) + __AVERAGE_PTFV(idx); + else if (periodic_training_update) + __WEIGHTED_UPDATE_PTFV(idx, cval); - if (tmdel > adel) - adel = tmdel; + if (dvfs_update || periodic_training_update) { + tdel = next->current_dram_clktree[idx] - + __MOVAVG_AC(next, idx); + tmdel = (tdel < 0) ? -1 * tdel : tdel; - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C1D0U1] = - __MOVAVG_AC(next, C1D0U1); + if (tmdel > adel) + adel = tmdel; + + if (tmdel * 128 * next_timing_rate_mhz / 1000000 > + next->tree_margin) + next->current_dram_clktree[idx] = + __MOVAVG_AC(next, idx); + } } } - if (emc->num_devices < 2) - goto done; - - /* - * Dev1 MSB. - */ - if (dvfs_pt1 || periodic_training_update) { - value = tegra210_emc_mrr_read(emc, 1, 19); - - for (i = 0; i < emc->num_channels; i++) { - temp[i][0] = (value & 0x00ff) << 8; - temp[i][1] = (value & 0xff00) << 0; - value >>= 16; - } - - /* - * Dev1 LSB. - */ - value = tegra210_emc_mrr_read(emc, 1, 18); - - for (i = 0; i < emc->num_channels; i++) { - temp[i][0] |= (value & 0x00ff) >> 0; - temp[i][1] |= (value & 0xff00) >> 8; - value >>= 16; - } - } - - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[0][0]; - } - - if (dvfs_pt1) - __INCREMENT_PTFV(C0D1U0, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C0D1U0); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C0D1U0, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C0D1U0] - - __MOVAVG_AC(next, C0D1U0); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C0D1U0] = - __MOVAVG_AC(next, C0D1U0); - } - - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[0][1]; - } - - if (dvfs_pt1) - __INCREMENT_PTFV(C0D1U1, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C0D1U1); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C0D1U1, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C0D1U1] - - __MOVAVG_AC(next, C0D1U1); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C0D1U1] = - __MOVAVG_AC(next, C0D1U1); - } - - if (emc->num_channels > 1) { - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[1][0]; - } - - if (dvfs_pt1) - __INCREMENT_PTFV(C1D1U0, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C1D1U0); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C1D1U0, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C1D1U0] - - __MOVAVG_AC(next, C1D1U0); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C1D1U0] = - __MOVAVG_AC(next, C1D1U0); - } - - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[1][1]; - } - - if (dvfs_pt1) - __INCREMENT_PTFV(C1D1U1, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C1D1U1); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C1D1U1, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C1D1U1] - - __MOVAVG_AC(next, C1D1U1); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C1D1U1] = - __MOVAVG_AC(next, C1D1U1); - } - } - -done: return adel; } From b109656e9ca399d6899152eb40efac2bdd3b4202 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 4 Jul 2024 12:31:25 +0100 Subject: [PATCH 009/212] memory: tegra: Move compare/update current delay values to a function Separate the comparison/updating of the measured delay values with the values currently programmed into a separate function to simplify the code. Signed-off-by: Diogo Ivo Link: https://lore.kernel.org/r/20240704-tegra210_emcfreq-v4-6-3e450503c555@tecnico.ulisboa.pt Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra210-emc-cc-r21021.c | 86 +++++++++---------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index 9262da658189..a8a217502f0c 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -113,19 +113,35 @@ enum { #define __MOVAVG(timing, dev) \ ((timing)->ptfv_list[(dev)]) -static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) +static bool tegra210_emc_compare_update_delay(struct tegra210_emc_timing *timing, + u32 measured, u32 idx) +{ + u32 *curr = &timing->current_dram_clktree[idx]; + u32 rate_mhz = timing->rate / 1000; + u32 tmdel; + + tmdel = abs(*curr - measured); + + if (tmdel * 128 * rate_mhz / 1000000 > timing->tree_margin) { + *curr = measured; + return true; + } + + return false; +} + +static bool update_clock_tree_delay(struct tegra210_emc *emc, int type) { bool periodic_training_update = type == PERIODIC_TRAINING_UPDATE; struct tegra210_emc_timing *last = emc->last; struct tegra210_emc_timing *next = emc->next; u32 last_timing_rate_mhz = last->rate / 1000; - u32 next_timing_rate_mhz = next->rate / 1000; bool dvfs_update = type == DVFS_UPDATE; - s32 tdel = 0, tmdel = 0, adel = 0; bool dvfs_pt1 = type == DVFS_PT1; u32 temp[2][2], value, delay_us; unsigned long cval = 0; unsigned int c, d, idx; + bool over = false; if (dvfs_pt1 || periodic_training_update) { delay_us = tegra210_emc_actual_osc_clocks(last->run_clocks); @@ -174,17 +190,9 @@ static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(idx, cval); - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[idx] - - __MOVAVG_AC(next, idx); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[idx] = - __MOVAVG_AC(next, idx); - } + if (dvfs_update || periodic_training_update) + over |= tegra210_emc_compare_update_delay(next, + __MOVAVG_AC(next, idx), idx); /* C[c]D[d]U[1] */ idx++; @@ -202,34 +210,25 @@ static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) else if (periodic_training_update) __WEIGHTED_UPDATE_PTFV(idx, cval); - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[idx] - - __MOVAVG_AC(next, idx); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[idx] = - __MOVAVG_AC(next, idx); - } + if (dvfs_update || periodic_training_update) + over |= tegra210_emc_compare_update_delay(next, + __MOVAVG_AC(next, idx), idx); } } - return adel; + return over; } -static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, - struct tegra210_emc_timing *last, - struct tegra210_emc_timing *next) +static bool periodic_compensation_handler(struct tegra210_emc *emc, u32 type, + struct tegra210_emc_timing *last, + struct tegra210_emc_timing *next) { #define __COPY_EMA(nt, lt, dev) \ ({ __MOVAVG(nt, dev) = __MOVAVG(lt, dev) * \ (nt)->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; }) - u32 i, adel = 0, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; + u32 i, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; + bool over = false; u32 idx; if (!next->periodic_training) @@ -253,23 +252,23 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, for (i = 0; i < samples; i++) { /* Generate next sample of data. */ - adel = update_clock_tree_delay(emc, DVFS_PT1); + update_clock_tree_delay(emc, DVFS_PT1); } } /* Do the division part of the moving average */ - adel = update_clock_tree_delay(emc, DVFS_UPDATE); + over = update_clock_tree_delay(emc, DVFS_UPDATE); } if (type == PERIODIC_TRAINING_SEQUENCE) - adel = update_clock_tree_delay(emc, PERIODIC_TRAINING_UPDATE); + over = update_clock_tree_delay(emc, PERIODIC_TRAINING_UPDATE); - return adel; + return over; } static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc) { - u32 emc_cfg, emc_cfg_o, emc_cfg_update, del, value; + u32 emc_cfg, emc_cfg_o, emc_cfg_update, value; static const u32 list[] = { EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1, @@ -327,15 +326,12 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc) * 4. Check delta wrt previous values (save value if margin * exceeds what is set in table). */ - del = periodic_compensation_handler(emc, - PERIODIC_TRAINING_SEQUENCE, - last, last); - + if (periodic_compensation_handler(emc, PERIODIC_TRAINING_SEQUENCE, + last, last)) { /* * 5. Apply compensation w.r.t. trained values (if clock tree * has drifted more than the set margin). */ - if (last->tree_margin < ((del * 128 * (last->rate / 1000)) / 1000000)) { for (i = 0; i < items; i++) { value = tegra210_emc_compensate(last, list[i]); emc_dbg(emc, EMA_WRITES, "0x%08x <= 0x%08x\n", @@ -516,11 +512,7 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc) EMC_EMC_STATUS_DRAM_IN_SELF_REFRESH_MASK, 0); - value = periodic_compensation_handler(emc, DVFS_SEQUENCE, fake, - next); - value = (value * 128 * next->rate / 1000) / 1000000; - - if (next->periodic_training && value > next->tree_margin) + if (periodic_compensation_handler(emc, DVFS_SEQUENCE, fake, next)) compensate_trimmer_applicable = true; } From ddb869ea237eb4e1c882c8768675fad53623b062 Mon Sep 17 00:00:00 2001 From: Diogo Ivo Date: Thu, 4 Jul 2024 12:31:26 +0100 Subject: [PATCH 010/212] memory: tegra: Rework update_clock_tree_delay() Further streamline this function by moving the delay post-processing to the callers, leaving it only with the task of returning the measured delay values. Signed-off-by: Diogo Ivo Link: https://lore.kernel.org/r/20240704-tegra210_emcfreq-v4-7-3e450503c555@tecnico.ulisboa.pt Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra210-emc-cc-r21021.c | 122 +++++++----------- 1 file changed, 48 insertions(+), 74 deletions(-) diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index a8a217502f0c..a30a646ec468 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -105,7 +105,7 @@ enum { next->ptfv_list[w])) / \ (next->ptfv_list[w] + 1); \ \ - emc_dbg(emc, EMA_UPDATES, "%s: (s=%lu) EMA: %u\n", \ + emc_dbg(emc, EMA_UPDATES, "%s: (s=%u) EMA: %u\n", \ __stringify(dev), nval, next->ptfv_list[dqs]); \ } while (0) @@ -130,93 +130,53 @@ static bool tegra210_emc_compare_update_delay(struct tegra210_emc_timing *timing return false; } -static bool update_clock_tree_delay(struct tegra210_emc *emc, int type) +static void tegra210_emc_get_clktree_delay(struct tegra210_emc *emc, + u32 delay[DRAM_CLKTREE_NUM]) { - bool periodic_training_update = type == PERIODIC_TRAINING_UPDATE; - struct tegra210_emc_timing *last = emc->last; - struct tegra210_emc_timing *next = emc->next; - u32 last_timing_rate_mhz = last->rate / 1000; - bool dvfs_update = type == DVFS_UPDATE; - bool dvfs_pt1 = type == DVFS_PT1; - u32 temp[2][2], value, delay_us; - unsigned long cval = 0; + struct tegra210_emc_timing *curr = emc->last; + u32 rate_mhz = curr->rate / 1000; + u32 msb, lsb, dqsosc, delay_us; unsigned int c, d, idx; - bool over = false; + unsigned long clocks; - if (dvfs_pt1 || periodic_training_update) { - delay_us = tegra210_emc_actual_osc_clocks(last->run_clocks); - delay_us *= 1000; - delay_us = 2 + (delay_us / last->rate); + clocks = tegra210_emc_actual_osc_clocks(curr->run_clocks); + delay_us = 2 + (clocks / rate_mhz); - tegra210_emc_start_periodic_compensation(emc); - udelay(delay_us); - } + tegra210_emc_start_periodic_compensation(emc); + udelay(delay_us); for (d = 0; d < emc->num_devices; d++) { - if (dvfs_pt1 || periodic_training_update) { - /* Dev[d] MSB */ - value = tegra210_emc_mrr_read(emc, 2 - d, 19); - - for (c = 0; c < emc->num_channels; c++) { - temp[c][0] = (value & 0x00ff) << 8; - temp[c][1] = (value & 0xff00) << 0; - value >>= 16; - } - - /* Dev[d] LSB */ - value = tegra210_emc_mrr_read(emc, 2 - d, 18); - - for (c = 0; c < emc->num_channels; c++) { - temp[c][0] |= (value & 0x00ff) >> 0; - temp[c][1] |= (value & 0xff00) >> 8; - value >>= 16; - } - } + /* Read DQSOSC from MRR18/19 */ + msb = tegra210_emc_mrr_read(emc, 2 - d, 19); + lsb = tegra210_emc_mrr_read(emc, 2 - d, 18); for (c = 0; c < emc->num_channels; c++) { /* C[c]D[d]U[0] */ idx = c * 4 + d * 2; - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[c][0]; - } + dqsosc = (msb & 0x00ff) << 8; + dqsosc |= (lsb & 0x00ff) >> 0; - if (dvfs_pt1) - __INCREMENT_PTFV(idx, cval); - else if (dvfs_update) - __AVERAGE_PTFV(idx); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(idx, cval); - - if (dvfs_update || periodic_training_update) - over |= tegra210_emc_compare_update_delay(next, - __MOVAVG_AC(next, idx), idx); + /* Check for unpopulated channels */ + if (dqsosc) + delay[idx] = (clocks * 1000000) / + (rate_mhz * 2 * dqsosc); /* C[c]D[d]U[1] */ idx++; - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[c][1]; - } + dqsosc = (msb & 0xff00) << 0; + dqsosc |= (lsb & 0xff00) >> 8; - if (dvfs_pt1) - __INCREMENT_PTFV(idx, cval); - else if (dvfs_update) - __AVERAGE_PTFV(idx); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(idx, cval); + /* Check for unpopulated channels */ + if (dqsosc) + delay[idx] = (clocks * 1000000) / + (rate_mhz * 2 * dqsosc); - if (dvfs_update || periodic_training_update) - over |= tegra210_emc_compare_update_delay(next, - __MOVAVG_AC(next, idx), idx); + msb >>= 16; + lsb >>= 16; } } - - return over; } static bool periodic_compensation_handler(struct tegra210_emc *emc, u32 type, @@ -228,8 +188,8 @@ static bool periodic_compensation_handler(struct tegra210_emc *emc, u32 type, (nt)->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; }) u32 i, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; + u32 delay[DRAM_CLKTREE_NUM], idx; bool over = false; - u32 idx; if (!next->periodic_training) return 0; @@ -252,16 +212,30 @@ static bool periodic_compensation_handler(struct tegra210_emc *emc, u32 type, for (i = 0; i < samples; i++) { /* Generate next sample of data. */ - update_clock_tree_delay(emc, DVFS_PT1); + tegra210_emc_get_clktree_delay(emc, delay); + + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) + __INCREMENT_PTFV(idx, delay[idx]); } } - /* Do the division part of the moving average */ - over = update_clock_tree_delay(emc, DVFS_UPDATE); + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) { + /* Do the division part of the moving average */ + __AVERAGE_PTFV(idx); + over |= tegra210_emc_compare_update_delay(next, + __MOVAVG_AC(next, idx), idx); + } } - if (type == PERIODIC_TRAINING_SEQUENCE) - over = update_clock_tree_delay(emc, PERIODIC_TRAINING_UPDATE); + if (type == PERIODIC_TRAINING_SEQUENCE) { + tegra210_emc_get_clktree_delay(emc, delay); + + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) { + __WEIGHTED_UPDATE_PTFV(idx, delay[idx]); + over |= tegra210_emc_compare_update_delay(next, + __MOVAVG_AC(next, idx), idx); + } + } return over; } From ded525f8ac5db53286b0eabb679ecf7edb974eaa Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 7 Jul 2024 07:47:20 +0200 Subject: [PATCH 011/212] soc: mediatek: pwrap: Constify struct pmic_wrapper_type 'struct pmic_wrapper_type' is not modified in this driver. Constifying this structure moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig: Before: ====== text data bss dec hex filename 45336 8724 16 54076 d33c drivers/soc/mediatek/mtk-pmic-wrap.o After: ===== text data bss dec hex filename 45528 8532 16 54076 d33c drivers/soc/mediatek/mtk-pmic-wrap.o Signed-off-by: Christophe JAILLET Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/5b4b60c5dfd6d8fe893b05cfc96c0e2d67705463.1720331018.git.christophe.jaillet@wanadoo.fr Signed-off-by: AngeloGioacchino Del Regno --- drivers/soc/mediatek/mtk-pmic-wrap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index efd9cae212dc..0da0cdec5050 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -2397,7 +2397,7 @@ static const struct pmic_wrapper_type pwrap_mt8183 = { .init_soc_specific = pwrap_mt8183_init_soc_specific, }; -static struct pmic_wrapper_type pwrap_mt8195 = { +static const struct pmic_wrapper_type pwrap_mt8195 = { .regs = mt8195_regs, .type = PWRAP_MT8195, .arb_en_all = 0x777f, /* NEED CONFIRM */ @@ -2423,7 +2423,7 @@ static const struct pmic_wrapper_type pwrap_mt8365 = { .init_soc_specific = NULL, }; -static struct pmic_wrapper_type pwrap_mt8516 = { +static const struct pmic_wrapper_type pwrap_mt8516 = { .regs = mt8516_regs, .type = PWRAP_MT8516, .arb_en_all = 0xff, @@ -2435,7 +2435,7 @@ static struct pmic_wrapper_type pwrap_mt8516 = { .init_soc_specific = NULL, }; -static struct pmic_wrapper_type pwrap_mt8186 = { +static const struct pmic_wrapper_type pwrap_mt8186 = { .regs = mt8186_regs, .type = PWRAP_MT8186, .arb_en_all = 0xfb27f, From 10c1ea1eaf4d107c323321e92237ba67848de291 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 7 Jul 2024 07:47:21 +0200 Subject: [PATCH 012/212] soc: mediatek: pwrap: Constify some struct int[] These arrays are not modified in this driver. Constifying this structure moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig: Before: ====== text data bss dec hex filename 45528 8532 16 54076 d33c drivers/soc/mediatek/mtk-pmic-wrap.o After: ===== text data bss dec hex filename 52664 1384 16 54064 d330 drivers/soc/mediatek/mtk-pmic-wrap.o Signed-off-by: Christophe JAILLET Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/f1fea00fbaa0fea298bf67732e019f9cc5c407ab.1720331018.git.christophe.jaillet@wanadoo.fr Signed-off-by: AngeloGioacchino Del Regno --- drivers/soc/mediatek/mtk-pmic-wrap.c | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 0da0cdec5050..d57553486383 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -483,7 +483,7 @@ enum pwrap_regs { PWRAP_MSB_FIRST, }; -static int mt2701_regs[] = { +static const int mt2701_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -569,7 +569,7 @@ static int mt2701_regs[] = { [PWRAP_ADC_RDATA_ADDR2] = 0x154, }; -static int mt6765_regs[] = { +static const int mt6765_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -601,7 +601,7 @@ static int mt6765_regs[] = { [PWRAP_DCM_DBC_PRD] = 0x1E0, }; -static int mt6779_regs[] = { +static const int mt6779_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -640,7 +640,7 @@ static int mt6779_regs[] = { [PWRAP_WACS2_VLDCLR] = 0xC28, }; -static int mt6795_regs[] = { +static const int mt6795_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -725,7 +725,7 @@ static int mt6795_regs[] = { [PWRAP_EXT_CK] = 0x14c, }; -static int mt6797_regs[] = { +static const int mt6797_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -758,7 +758,7 @@ static int mt6797_regs[] = { [PWRAP_DCM_DBC_PRD] = 0x1D4, }; -static int mt6873_regs[] = { +static const int mt6873_regs[] = { [PWRAP_INIT_DONE2] = 0x0, [PWRAP_TIMER_EN] = 0x3E0, [PWRAP_INT_EN] = 0x448, @@ -769,7 +769,7 @@ static int mt6873_regs[] = { [PWRAP_WACS2_RDATA] = 0xCA8, }; -static int mt7622_regs[] = { +static const int mt7622_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -881,7 +881,7 @@ static int mt7622_regs[] = { [PWRAP_SPI2_CTRL] = 0x244, }; -static int mt8135_regs[] = { +static const int mt8135_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -954,7 +954,7 @@ static int mt8135_regs[] = { [PWRAP_DCM_DBC_PRD] = 0x160, }; -static int mt8173_regs[] = { +static const int mt8173_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -1036,7 +1036,7 @@ static int mt8173_regs[] = { [PWRAP_DCM_DBC_PRD] = 0x148, }; -static int mt8183_regs[] = { +static const int mt8183_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -1087,7 +1087,7 @@ static int mt8183_regs[] = { [PWRAP_WACS2_VLDCLR] = 0xC28, }; -static int mt8195_regs[] = { +static const int mt8195_regs[] = { [PWRAP_INIT_DONE2] = 0x0, [PWRAP_STAUPD_CTRL] = 0x4C, [PWRAP_TIMER_EN] = 0x3E4, @@ -1104,7 +1104,7 @@ static int mt8195_regs[] = { [PWRAP_WACS2_RDATA] = 0x8A8, }; -static int mt8365_regs[] = { +static const int mt8365_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -1166,7 +1166,7 @@ static int mt8365_regs[] = { [PWRAP_WDT_SRC_EN_1] = 0xf8, }; -static int mt8516_regs[] = { +static const int mt8516_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -1251,7 +1251,7 @@ static int mt8516_regs[] = { [PWRAP_MSB_FIRST] = 0x170, }; -static int mt8186_regs[] = { +static const int mt8186_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, [PWRAP_DIO_EN] = 0x8, @@ -1377,7 +1377,7 @@ struct pmic_wrapper { }; struct pmic_wrapper_type { - int *regs; + const int *regs; enum pwrap_type type; u32 arb_en_all; u32 int_en_all; From 1c28c9452d521bf21dc5d2c50a47c2e43002728d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 7 Jul 2024 07:47:22 +0200 Subject: [PATCH 013/212] soc: mediatek: pwrap: Use devm_clk_bulk_get_all_enable() Use devm_clk_bulk_get_all_enable() to simplify the code and to make sure that clk_disable_unprepare() is called if the driver is unloaded. Fixes: 55924157da8c ("soc: mediatek: pwrap: add support for sys & tmr clocks") Fixes: 1f022d84bd19 ("soc: mediatek: Add PMIC wrapper for MT8135 and MT8173 SoCs") Suggested-by: AngeloGioacchino Del Regno Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/5b1114c538dd5230728592855f89942aec8ef83b.1720331018.git.christophe.jaillet@wanadoo.fr Signed-off-by: AngeloGioacchino Del Regno --- drivers/soc/mediatek/mtk-pmic-wrap.c | 82 ++++------------------------ 1 file changed, 12 insertions(+), 70 deletions(-) diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index d57553486383..9fdc0ef79202 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -1366,10 +1366,6 @@ struct pmic_wrapper { struct regmap *regmap; const struct pmic_wrapper_type *master; const struct pwrap_slv_type *slave; - struct clk *clk_spi; - struct clk *clk_wrap; - struct clk *clk_sys; - struct clk *clk_tmr; struct reset_control *rstc; struct reset_control *rstc_bridge; @@ -2472,6 +2468,7 @@ static int pwrap_probe(struct platform_device *pdev) int ret, irq; u32 mask_done; struct pmic_wrapper *wrp; + struct clk_bulk_data *clk; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_slave_id = NULL; @@ -2521,49 +2518,10 @@ static int pwrap_probe(struct platform_device *pdev) } } - wrp->clk_spi = devm_clk_get(wrp->dev, "spi"); - if (IS_ERR(wrp->clk_spi)) { - dev_dbg(wrp->dev, "failed to get clock: %ld\n", - PTR_ERR(wrp->clk_spi)); - return PTR_ERR(wrp->clk_spi); - } - - wrp->clk_wrap = devm_clk_get(wrp->dev, "wrap"); - if (IS_ERR(wrp->clk_wrap)) { - dev_dbg(wrp->dev, "failed to get clock: %ld\n", - PTR_ERR(wrp->clk_wrap)); - return PTR_ERR(wrp->clk_wrap); - } - - wrp->clk_sys = devm_clk_get_optional(wrp->dev, "sys"); - if (IS_ERR(wrp->clk_sys)) { - return dev_err_probe(wrp->dev, PTR_ERR(wrp->clk_sys), - "failed to get clock: %pe\n", - wrp->clk_sys); - } - - wrp->clk_tmr = devm_clk_get_optional(wrp->dev, "tmr"); - if (IS_ERR(wrp->clk_tmr)) { - return dev_err_probe(wrp->dev, PTR_ERR(wrp->clk_tmr), - "failed to get clock: %pe\n", - wrp->clk_tmr); - } - - ret = clk_prepare_enable(wrp->clk_spi); + ret = devm_clk_bulk_get_all_enable(wrp->dev, &clk); if (ret) - return ret; - - ret = clk_prepare_enable(wrp->clk_wrap); - if (ret) - goto err_out1; - - ret = clk_prepare_enable(wrp->clk_sys); - if (ret) - goto err_out2; - - ret = clk_prepare_enable(wrp->clk_tmr); - if (ret) - goto err_out3; + return dev_err_probe(wrp->dev, ret, + "failed to get clocks\n"); /* Enable internal dynamic clock */ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_DCM)) { @@ -2579,7 +2537,7 @@ static int pwrap_probe(struct platform_device *pdev) ret = pwrap_init(wrp); if (ret) { dev_dbg(wrp->dev, "init failed with %d\n", ret); - goto err_out4; + return ret; } } @@ -2592,8 +2550,7 @@ static int pwrap_probe(struct platform_device *pdev) if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & mask_done)) { dev_dbg(wrp->dev, "initialization isn't finished\n"); - ret = -ENODEV; - goto err_out4; + return -ENODEV; } /* Initialize watchdog, may not be done by the bootloader */ @@ -2622,42 +2579,27 @@ static int pwrap_probe(struct platform_device *pdev) pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto err_out2; - } + if (irq < 0) + return irq; ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH, "mt-pmic-pwrap", wrp); if (ret) - goto err_out4; + return ret; wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regops->regmap); - if (IS_ERR(wrp->regmap)) { - ret = PTR_ERR(wrp->regmap); - goto err_out2; - } + if (IS_ERR(wrp->regmap)) + return PTR_ERR(wrp->regmap); ret = of_platform_populate(np, NULL, NULL, wrp->dev); if (ret) { dev_dbg(wrp->dev, "failed to create child devices at %pOF\n", np); - goto err_out4; + return ret; } return 0; - -err_out4: - clk_disable_unprepare(wrp->clk_tmr); -err_out3: - clk_disable_unprepare(wrp->clk_sys); -err_out2: - clk_disable_unprepare(wrp->clk_wrap); -err_out1: - clk_disable_unprepare(wrp->clk_spi); - - return ret; } static struct platform_driver pwrap_drv = { From d1e5d531d20b085bb83d9ab1868ed99fdeb0cc42 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 29 Jul 2024 14:25:38 +0200 Subject: [PATCH 014/212] soc: mediatek: mtk-mutex: Reduce type size for mtk_mutex_data members All of mutex_mod and mutex_table_mod contain an array of bit numbers, which can go from 0 to 63, it is hence not needed to use an unsigned 32-bits integer to store that: change them to unsigned 8-bits instead. As for the mutex_sof table since this directly contains the values to write to the DISP_MUTEXn_CTL register, which has only bits [13:0] (so this register is effectively 14 bits long), change that to use unsigned 16-bits. The type of mutex_{mod,sof}_reg was also changed to 16 bits, as the maximum value that those will ever have is 0x800, because it calculates as 0x30 + (0x20 * n) where n's maximum value is 63. This reduces module size and brings no functional changes. Before: text data bss dec hex filename 9929 512 0 10441 28c9 mtk-mutex.o After: text data bss dec hex filename 7425 512 0 7937 1f01 mtk-mutex.o Link: https://lore.kernel.org/r/20240729122538.989855-1-angelogioacchino.delregno@collabora.com Signed-off-by: AngeloGioacchino Del Regno --- drivers/soc/mediatek/mtk-mutex.c | 52 ++++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c index 01b129caf1eb..5250c1d702eb 100644 --- a/drivers/soc/mediatek/mtk-mutex.c +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -327,11 +327,11 @@ enum mtk_mutex_sof_id { }; struct mtk_mutex_data { - const unsigned int *mutex_mod; - const unsigned int *mutex_sof; - const unsigned int mutex_mod_reg; - const unsigned int mutex_sof_reg; - const unsigned int *mutex_table_mod; + const u8 *mutex_mod; + const u8 *mutex_table_mod; + const u16 *mutex_sof; + const u16 mutex_mod_reg; + const u16 mutex_sof_reg; const bool no_clk; }; @@ -345,7 +345,7 @@ struct mtk_mutex_ctx { struct cmdq_client_reg cmdq_reg; }; -static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS, [DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR, [DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL, @@ -354,7 +354,7 @@ static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA, }; -static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT2712_MUTEX_MOD_DISP_AAL0, [DDP_COMPONENT_AAL1] = MT2712_MUTEX_MOD2_DISP_AAL1, [DDP_COMPONENT_COLOR0] = MT2712_MUTEX_MOD_DISP_COLOR0, @@ -374,7 +374,7 @@ static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_WDMA1] = MT2712_MUTEX_MOD_DISP_WDMA1, }; -static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT8167_MUTEX_MOD_DISP_AAL, [DDP_COMPONENT_CCORR] = MT8167_MUTEX_MOD_DISP_CCORR, [DDP_COMPONENT_COLOR0] = MT8167_MUTEX_MOD_DISP_COLOR, @@ -389,7 +389,7 @@ static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_WDMA0] = MT8167_MUTEX_MOD_DISP_WDMA0, }; -static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL, [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0, [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1, @@ -407,7 +407,7 @@ static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1, }; -static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT8183_MUTEX_MOD_DISP_AAL0, [DDP_COMPONENT_CCORR] = MT8183_MUTEX_MOD_DISP_CCORR0, [DDP_COMPONENT_COLOR0] = MT8183_MUTEX_MOD_DISP_COLOR0, @@ -421,7 +421,7 @@ static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0, }; -static const unsigned int mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { +static const u8 mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_RDMA0] = MT8183_MUTEX_MOD_MDP_RDMA0, [MUTEX_MOD_IDX_MDP_RSZ0] = MT8183_MUTEX_MOD_MDP_RSZ0, [MUTEX_MOD_IDX_MDP_RSZ1] = MT8183_MUTEX_MOD_MDP_RSZ1, @@ -432,7 +432,7 @@ static const unsigned int mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_CCORR0] = MT8183_MUTEX_MOD_MDP_CCORR0, }; -static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT8186_MUTEX_MOD_DISP_AAL0, [DDP_COMPONENT_CCORR] = MT8186_MUTEX_MOD_DISP_CCORR0, [DDP_COMPONENT_COLOR0] = MT8186_MUTEX_MOD_DISP_COLOR0, @@ -445,7 +445,7 @@ static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_RDMA1] = MT8186_MUTEX_MOD_DISP_RDMA1, }; -static const unsigned int mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { +static const u8 mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_RDMA0] = MT8186_MUTEX_MOD_MDP_RDMA0, [MUTEX_MOD_IDX_MDP_RSZ0] = MT8186_MUTEX_MOD_MDP_RSZ0, [MUTEX_MOD_IDX_MDP_RSZ1] = MT8186_MUTEX_MOD_MDP_RSZ1, @@ -456,7 +456,7 @@ static const unsigned int mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_COLOR0] = MT8186_MUTEX_MOD_MDP_COLOR0, }; -static const unsigned int mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_OVL0] = MT8188_MUTEX_MOD_DISP_OVL0, [DDP_COMPONENT_WDMA0] = MT8188_MUTEX_MOD_DISP_WDMA0, [DDP_COMPONENT_RDMA0] = MT8188_MUTEX_MOD_DISP_RDMA0, @@ -496,7 +496,7 @@ static const unsigned int mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_MERGE5] = MT8188_MUTEX_MOD_DISP1_VPP_MERGE4, }; -static const unsigned int mt8188_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { +static const u8 mt8188_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_RDMA0] = MT8195_MUTEX_MOD_MDP_RDMA0, [MUTEX_MOD_IDX_MDP_RDMA2] = MT8195_MUTEX_MOD_MDP_RDMA2, [MUTEX_MOD_IDX_MDP_RDMA3] = MT8195_MUTEX_MOD_MDP_RDMA3, @@ -530,7 +530,7 @@ static const unsigned int mt8188_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_WROT3] = MT8195_MUTEX_MOD_MDP_WROT3, }; -static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT8192_MUTEX_MOD_DISP_AAL0, [DDP_COMPONENT_CCORR] = MT8192_MUTEX_MOD_DISP_CCORR0, [DDP_COMPONENT_COLOR0] = MT8192_MUTEX_MOD_DISP_COLOR0, @@ -544,7 +544,7 @@ static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_RDMA4] = MT8192_MUTEX_MOD_DISP_RDMA4, }; -static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_OVL0] = MT8195_MUTEX_MOD_DISP_OVL0, [DDP_COMPONENT_WDMA0] = MT8195_MUTEX_MOD_DISP_WDMA0, [DDP_COMPONENT_RDMA0] = MT8195_MUTEX_MOD_DISP_RDMA0, @@ -575,7 +575,7 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_DP_INTF1] = MT8195_MUTEX_MOD_DISP1_DP_INTF0, }; -static const unsigned int mt8195_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { +static const u8 mt8195_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_RDMA0] = MT8195_MUTEX_MOD_MDP_RDMA0, [MUTEX_MOD_IDX_MDP_RDMA1] = MT8195_MUTEX_MOD_MDP_RDMA1, [MUTEX_MOD_IDX_MDP_RDMA2] = MT8195_MUTEX_MOD_MDP_RDMA2, @@ -621,7 +621,7 @@ static const unsigned int mt8195_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_WROT3] = MT8195_MUTEX_MOD_MDP_WROT3, }; -static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = { +static const u8 mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT8365_MUTEX_MOD_DISP_AAL, [DDP_COMPONENT_CCORR] = MT8365_MUTEX_MOD_DISP_CCORR, [DDP_COMPONENT_COLOR0] = MT8365_MUTEX_MOD_DISP_COLOR0, @@ -637,7 +637,7 @@ static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_WDMA0] = MT8365_MUTEX_MOD_DISP_WDMA0, }; -static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = { +static const u16 mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = { [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1, @@ -647,14 +647,14 @@ static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = { [MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3, }; -static const unsigned int mt6795_mutex_sof[DDP_MUTEX_SOF_MAX] = { +static const u16 mt6795_mutex_sof[DDP_MUTEX_SOF_MAX] = { [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1, [MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0, }; -static const unsigned int mt8167_mutex_sof[DDP_MUTEX_SOF_MAX] = { +static const u16 mt8167_mutex_sof[DDP_MUTEX_SOF_MAX] = { [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, [MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0, @@ -662,13 +662,13 @@ static const unsigned int mt8167_mutex_sof[DDP_MUTEX_SOF_MAX] = { }; /* Add EOF setting so overlay hardware can receive frame done irq */ -static const unsigned int mt8183_mutex_sof[DDP_MUTEX_SOF_MAX] = { +static const u16 mt8183_mutex_sof[DDP_MUTEX_SOF_MAX] = { [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0 | MT8183_MUTEX_EOF_DSI0, [MUTEX_SOF_DPI0] = MT8183_MUTEX_SOF_DPI0 | MT8183_MUTEX_EOF_DPI0, }; -static const unsigned int mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = { +static const u16 mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = { [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_DSI0] = MT8186_MUTEX_SOF_DSI0 | MT8186_MUTEX_EOF_DSI0, [MUTEX_SOF_DPI0] = MT8186_MUTEX_SOF_DPI0 | MT8186_MUTEX_EOF_DPI0, @@ -682,7 +682,7 @@ static const unsigned int mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = { * but also detect the error at end of frame(EAEOF) when EOF signal * arrives. */ -static const unsigned int mt8188_mutex_sof[DDP_MUTEX_SOF_MAX] = { +static const u16 mt8188_mutex_sof[DDP_MUTEX_SOF_MAX] = { [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_DSI0] = MT8188_MUTEX_SOF_DSI0 | MT8188_MUTEX_EOF_DSI0, @@ -692,7 +692,7 @@ static const unsigned int mt8188_mutex_sof[DDP_MUTEX_SOF_MAX] = { MT8188_MUTEX_SOF_DP_INTF1 | MT8188_MUTEX_EOF_DP_INTF1, }; -static const unsigned int mt8195_mutex_sof[DDP_MUTEX_SOF_MAX] = { +static const u16 mt8195_mutex_sof[DDP_MUTEX_SOF_MAX] = { [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_DSI0] = MT8195_MUTEX_SOF_DSI0 | MT8195_MUTEX_EOF_DSI0, [MUTEX_SOF_DSI1] = MT8195_MUTEX_SOF_DSI1 | MT8195_MUTEX_EOF_DSI1, From dc8c4a8aee49e42cf13e32e123de127122dc516f Mon Sep 17 00:00:00 2001 From: Shivnandan Kumar Date: Mon, 8 Jul 2024 15:47:34 +0530 Subject: [PATCH 015/212] soc: qcom: icc-bwmon: Add tracepoints in bwmon_intr_thread Add tracepoint for tracing the measured traffic in kbps, up_kbps and down_kbps in bwmon. This information is valuable for understanding what bwmon hw measures at the system cache level and at the DDR level which is helpful in debugging bwmon behavior. Signed-off-by: Shivnandan Kumar Reviewed-by: Sibi Sankar Link: https://lore.kernel.org/r/20240708101734.1999795-1-quic_kshivnan@quicinc.com Signed-off-by: Bjorn Andersson --- MAINTAINERS | 1 + drivers/soc/qcom/icc-bwmon.c | 6 +++- drivers/soc/qcom/trace_icc-bwmon.h | 48 ++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 drivers/soc/qcom/trace_icc-bwmon.h diff --git a/MAINTAINERS b/MAINTAINERS index 42decde38320..aff8dc6aaa67 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18855,6 +18855,7 @@ L: linux-arm-msm@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml F: drivers/soc/qcom/icc-bwmon.c +F: drivers/soc/qcom/trace_icc-bwmon.h QUALCOMM IOMMU M: Rob Clark diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index e7851974084b..f9235bc3aa3b 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -17,6 +17,8 @@ #include #include #include +#define CREATE_TRACE_POINTS +#include "trace_icc-bwmon.h" /* * The BWMON samples data throughput within 'sample_ms' time. With three @@ -645,9 +647,10 @@ static irqreturn_t bwmon_intr_thread(int irq, void *dev_id) struct icc_bwmon *bwmon = dev_id; unsigned int irq_enable = 0; struct dev_pm_opp *opp, *target_opp; - unsigned int bw_kbps, up_kbps, down_kbps; + unsigned int bw_kbps, up_kbps, down_kbps, meas_kbps; bw_kbps = bwmon->target_kbps; + meas_kbps = bwmon->target_kbps; target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0); if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE) @@ -679,6 +682,7 @@ static irqreturn_t bwmon_intr_thread(int irq, void *dev_id) bwmon_clear_irq(bwmon); bwmon_enable(bwmon, irq_enable); + trace_qcom_bwmon_update(dev_name(bwmon->dev), meas_kbps, up_kbps, down_kbps); if (bwmon->target_kbps == bwmon->current_kbps) goto out; diff --git a/drivers/soc/qcom/trace_icc-bwmon.h b/drivers/soc/qcom/trace_icc-bwmon.h new file mode 100644 index 000000000000..beb8e6b485a9 --- /dev/null +++ b/drivers/soc/qcom/trace_icc-bwmon.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM icc_bwmon + +#if !defined(_TRACE_ICC_BWMON_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_ICC_BWMON_H +#include + +TRACE_EVENT(qcom_bwmon_update, + TP_PROTO(const char *name, + unsigned int meas_kbps, unsigned int up_kbps, unsigned int down_kbps), + + TP_ARGS(name, meas_kbps, up_kbps, down_kbps), + + TP_STRUCT__entry( + __string(name, name) + __field(unsigned int, meas_kbps) + __field(unsigned int, up_kbps) + __field(unsigned int, down_kbps) + ), + + TP_fast_assign( + __assign_str(name); + __entry->meas_kbps = meas_kbps; + __entry->up_kbps = up_kbps; + __entry->down_kbps = down_kbps; + ), + + TP_printk("name=%s meas_kbps=%u up_kbps=%u down_kbps=%u", + __get_str(name), + __entry->meas_kbps, + __entry->up_kbps, + __entry->down_kbps) +); + +#endif /* _TRACE_ICC_BWMON_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/soc/qcom/ + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace_icc-bwmon + +#include From 23d22b0fe6a12317e9d17bb17720285ac4ba4d54 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 31 Jul 2024 13:12:59 -0600 Subject: [PATCH 016/212] memory: emif: Use of_property_read_bool() Use of_property_read_bool() to read boolean properties rather than of_find_property(). This is part of a larger effort to remove callers of of_find_property() and similar functions. of_find_property() leaks the DT struct property and data pointers which is a problem for dynamically allocated nodes which may be freed. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240731191312.1710417-21-robh@kernel.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/emif.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 8c5ad5c025fa..974ed641473e 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -864,7 +864,7 @@ static void of_get_custom_configs(struct device_node *np_emif, be32_to_cpup(poll_intvl); } - if (of_find_property(np_emif, "extended-temp-part", &len)) + if (of_property_read_bool(np_emif, "extended-temp-part")) cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART; if (!is_custom_config_valid(cust_cfgs, emif->dev)) { @@ -880,13 +880,9 @@ static void of_get_ddr_info(struct device_node *np_emif, struct ddr_device_info *dev_info) { u32 density = 0, io_width = 0; - int len; - if (of_find_property(np_emif, "cs1-used", &len)) - dev_info->cs1_used = true; - - if (of_find_property(np_emif, "cal-resistor-per-cs", &len)) - dev_info->cal_resistors_per_cs = true; + dev_info->cs1_used = of_property_read_bool(np_emif, "cs1-used"); + dev_info->cal_resistors_per_cs = of_property_read_bool(np_emif, "cal-resistor-per-cs"); if (of_device_is_compatible(np_ddr, "jedec,lpddr2-s4")) dev_info->type = DDR_TYPE_LPDDR2_S4; @@ -916,7 +912,6 @@ static struct emif_data *of_get_memory_device_details( struct ddr_device_info *dev_info = NULL; struct emif_platform_data *pd = NULL; struct device_node *np_ddr; - int len; np_ddr = of_parse_phandle(np_emif, "device-handle", 0); if (!np_ddr) @@ -944,7 +939,7 @@ static struct emif_data *of_get_memory_device_details( of_property_read_u32(np_emif, "phy-type", &pd->phy_type); - if (of_find_property(np_emif, "hw-caps-ll-interface", &len)) + if (of_property_read_bool(np_emif, "hw-caps-ll-interface")) pd->hw_caps |= EMIF_HW_CAPS_LL_INTERFACE; of_get_ddr_info(np_emif, np_ddr, dev_info); From 0070dc29c85f0859a6071844b88fca6bce2974e4 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 31 Jul 2024 13:12:39 -0600 Subject: [PATCH 017/212] bus: ti-sysc: Use of_property_present() Use of_property_present() to test for property presence rather than of_get_property(). This is part of a larger effort to remove callers of of_get_property() and similar functions. of_get_property() leaks the DT property data pointer which is a problem for dynamically allocated nodes which may be freed. The code was also incorrectly assigning the return value to a 'struct property' pointer. It didn't matter as "prop" was never dereferenced. Signed-off-by: Rob Herring (Arm) Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20240731191312.1710417-1-robh@kernel.org Signed-off-by: Kevin Hilman --- drivers/bus/ti-sysc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 2b59ef61dda2..7caaf89f3bf2 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -2569,14 +2569,12 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = { static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, bool is_child) { - const struct property *prop; - int i, len; + int i; for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { const char *name = sysc_dts_quirks[i].name; - prop = of_get_property(np, name, &len); - if (!prop) + if (!of_property_present(np, name)) continue; ddata->cfg.quirks |= sysc_dts_quirks[i].mask; From a80a3d92dc600fed760edb8a633ea80712faaf98 Mon Sep 17 00:00:00 2001 From: Dhruva Gole Date: Mon, 5 Aug 2024 15:41:18 +0530 Subject: [PATCH 018/212] bus: ti-sysc: Remove excess struct member 'disable_on_idle' description When built with W=1, the driver throws the following warning: ../drivers/bus/ti-sysc.c:169: warning: Excess struct member 'disable_on_idle' description in 'sysc' Fix it by removing the excess description. Signed-off-by: Dhruva Gole Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20240805101118.427133-1-d-gole@ti.com Signed-off-by: Kevin Hilman --- drivers/bus/ti-sysc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 7caaf89f3bf2..270a94a06e05 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -126,7 +126,6 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = { * @enabled: sysc runtime enabled status * @needs_resume: runtime resume needed on resume from suspend * @child_needs_resume: runtime resume needed for child on resume from suspend - * @disable_on_idle: status flag used for disabling modules with resets * @idle_work: work structure used to perform delayed idle on a module * @pre_reset_quirk: module specific pre-reset quirk * @post_reset_quirk: module specific post-reset quirk From d9483b44c94eba6fa7451caf27cc7e993c8cc568 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 9 Jul 2024 19:41:29 +0200 Subject: [PATCH 019/212] soc: ti: k3-ringacc: Constify struct k3_ring_ops 'struct k3_ring_ops' is not modified in this driver. Constifying this structure moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig: Before: ====== text data bss dec hex filename 17090 3304 32 20426 4fca drivers/soc/ti/k3-ringacc.o After: ===== text data bss dec hex filename 17266 3144 32 20442 4fda drivers/soc/ti/k3-ringacc.o Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/cb9dfc18cdf890afa2c53cd74b0b330d6f1c30ab.1720546863.git.christophe.jaillet@wanadoo.fr Signed-off-by: Nishanth Menon --- drivers/soc/ti/k3-ringacc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c index fd4251d75935..8c0102968351 100644 --- a/drivers/soc/ti/k3-ringacc.c +++ b/drivers/soc/ti/k3-ringacc.c @@ -161,7 +161,7 @@ struct k3_ring { struct k3_ringacc_proxy_target_regs __iomem *proxy; dma_addr_t ring_mem_dma; void *ring_mem_virt; - struct k3_ring_ops *ops; + const struct k3_ring_ops *ops; u32 size; enum k3_ring_size elm_size; enum k3_ring_mode mode; @@ -268,17 +268,17 @@ static int k3_ringacc_ring_pop_mem(struct k3_ring *ring, void *elem); static int k3_dmaring_fwd_pop(struct k3_ring *ring, void *elem); static int k3_dmaring_reverse_pop(struct k3_ring *ring, void *elem); -static struct k3_ring_ops k3_ring_mode_ring_ops = { +static const struct k3_ring_ops k3_ring_mode_ring_ops = { .push_tail = k3_ringacc_ring_push_mem, .pop_head = k3_ringacc_ring_pop_mem, }; -static struct k3_ring_ops k3_dmaring_fwd_ops = { +static const struct k3_ring_ops k3_dmaring_fwd_ops = { .push_tail = k3_ringacc_ring_push_mem, .pop_head = k3_dmaring_fwd_pop, }; -static struct k3_ring_ops k3_dmaring_reverse_ops = { +static const struct k3_ring_ops k3_dmaring_reverse_ops = { /* Reverse side of the DMA ring can only be popped by SW */ .pop_head = k3_dmaring_reverse_pop, }; @@ -288,7 +288,7 @@ static int k3_ringacc_ring_pop_io(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_push_head_io(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_pop_tail_io(struct k3_ring *ring, void *elem); -static struct k3_ring_ops k3_ring_mode_msg_ops = { +static const struct k3_ring_ops k3_ring_mode_msg_ops = { .push_tail = k3_ringacc_ring_push_io, .push_head = k3_ringacc_ring_push_head_io, .pop_tail = k3_ringacc_ring_pop_tail_io, @@ -300,7 +300,7 @@ static int k3_ringacc_ring_push_tail_proxy(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_pop_head_proxy(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_pop_tail_proxy(struct k3_ring *ring, void *elem); -static struct k3_ring_ops k3_ring_mode_proxy_ops = { +static const struct k3_ring_ops k3_ring_mode_proxy_ops = { .push_tail = k3_ringacc_ring_push_tail_proxy, .push_head = k3_ringacc_ring_push_head_proxy, .pop_tail = k3_ringacc_ring_pop_tail_proxy, From 8737e167dc55cc00c5818b408f47ba03b6ddb25b Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 31 Jul 2024 14:13:57 -0600 Subject: [PATCH 020/212] soc: ti: knav: Drop unnecessary check for property presence of_property_read_u32() returns -EINVAL if a property is not present, so the preceding check for presence with of_get_property() can be dropped. This is part of a larger effort to remove callers of of_get_property() and similar functions. of_get_property() leaks the DT struct property and data pointers which is a problem for dynamically allocated nodes which may be freed. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240731201407.1838385-2-robh@kernel.org Signed-off-by: Nishanth Menon --- drivers/soc/ti/knav_qmss_queue.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index f2055a76f84c..a15eaa1900ab 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1104,11 +1104,6 @@ static int knav_queue_setup_regions(struct knav_device *kdev, continue; } - if (!of_get_property(child, "link-index", NULL)) { - dev_err(dev, "No link info for %s\n", region->name); - devm_kfree(dev, region); - continue; - } ret = of_property_read_u32(child, "link-index", ®ion->link_index); if (ret) { From b2a0176620db7aa0aa77109d7a8b894755441079 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 31 Jul 2024 14:13:58 -0600 Subject: [PATCH 021/212] soc: ti: knav: Use of_property_read_variable_u32_array() There's no need to get the length of an DT array property before parsing the array. of_property_read_variable_u32_array() takes a minimum and maximum length and returns the actual length (or error code). This is part of a larger effort to remove callers of of_find_property() and similar functions. of_find_property() leaks the DT struct property and data pointers which is a problem for dynamically allocated nodes which may be freed. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240731201407.1838385-3-robh@kernel.org Signed-off-by: Nishanth Menon --- drivers/soc/ti/knav_dma.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index 6023006685fc..fb0746d8caad 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -602,7 +602,7 @@ static int dma_init(struct device_node *cloud, struct device_node *dma_node) unsigned max_tx_chan, max_rx_chan, max_rx_flow, max_tx_sched; struct device_node *node = dma_node; struct knav_dma_device *dma; - int ret, len, num_chan = 0; + int ret, num_chan = 0; resource_size_t size; u32 timeout; u32 i; @@ -615,25 +615,13 @@ static int dma_init(struct device_node *cloud, struct device_node *dma_node) INIT_LIST_HEAD(&dma->list); INIT_LIST_HEAD(&dma->chan_list); - if (!of_find_property(cloud, "ti,navigator-cloud-address", &len)) { - dev_err(kdev->dev, "unspecified navigator cloud addresses\n"); - return -ENODEV; - } - - dma->logical_queue_managers = len / sizeof(u32); - if (dma->logical_queue_managers > DMA_MAX_QMS) { - dev_warn(kdev->dev, "too many queue mgrs(>%d) rest ignored\n", - dma->logical_queue_managers); - dma->logical_queue_managers = DMA_MAX_QMS; - } - - ret = of_property_read_u32_array(cloud, "ti,navigator-cloud-address", - dma->qm_base_address, - dma->logical_queue_managers); - if (ret) { + ret = of_property_read_variable_u32_array(cloud, "ti,navigator-cloud-address", + dma->qm_base_address, 1, DMA_MAX_QMS); + if (ret < 0) { dev_err(kdev->dev, "invalid navigator cloud addresses\n"); return -ENODEV; } + dma->logical_queue_managers = ret; dma->reg_global = pktdma_get_regs(dma, node, 0, &size); if (IS_ERR(dma->reg_global)) From 1afe599a0a484225bda6098feb22562831d72a4e Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Mon, 29 Jul 2024 12:35:43 +0530 Subject: [PATCH 022/212] dt-bindings: atmel-sysreg: add sam9x7 Add RAM controller & PIT64 DT bindings. Signed-off-by: Varshini Rajendran Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240729070543.1990209-1-varshini.rajendran@microchip.com Signed-off-by: Claudiu Beznea --- Documentation/devicetree/bindings/arm/atmel-sysregs.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt index 7374beb5a613..76e2b7978250 100644 --- a/Documentation/devicetree/bindings/arm/atmel-sysregs.txt +++ b/Documentation/devicetree/bindings/arm/atmel-sysregs.txt @@ -11,7 +11,8 @@ PIT Timer required properties: shared across all System Controller members. PIT64B Timer required properties: -- compatible: Should be "microchip,sam9x60-pit64b" +- compatible: Should be "microchip,sam9x60-pit64b" or + "microchip,sam9x7-pit64b", "microchip,sam9x60-pit64b" - reg: Should contain registers location and length - interrupts: Should contain interrupt for PIT64B timer - clocks: Should contain the available clock sources for PIT64B timer. @@ -31,7 +32,8 @@ RAMC SDRAM/DDR Controller required properties: "atmel,at91sam9g45-ddramc", "atmel,sama5d3-ddramc", "microchip,sam9x60-ddramc", - "microchip,sama7g5-uddrc" + "microchip,sama7g5-uddrc", + "microchip,sam9x7-ddramc", "atmel,sama5d3-ddramc". - reg: Should contain registers location and length Examples: From 67146942efe9077b5d09a43e1aa41f9602d916ef Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Mon, 29 Jul 2024 12:36:59 +0530 Subject: [PATCH 023/212] ARM: at91: pm: add support for sam9x7 SoC family Add support and pm init config for sam9x7 SoC. Signed-off-by: Varshini Rajendran Reviewed-by: Claudiu Beznea Link: https://lore.kernel.org/r/20240729070659.1990506-1-varshini.rajendran@microchip.com Signed-off-by: Claudiu Beznea --- arch/arm/mach-at91/generic.h | 2 ++ arch/arm/mach-at91/pm.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 0c3960a8b3eb..acf0b3c82a30 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -12,6 +12,7 @@ extern void __init at91rm9200_pm_init(void); extern void __init at91sam9_pm_init(void); extern void __init sam9x60_pm_init(void); +extern void __init sam9x7_pm_init(void); extern void __init sama5_pm_init(void); extern void __init sama5d2_pm_init(void); extern void __init sama7_pm_init(void); @@ -19,6 +20,7 @@ extern void __init sama7_pm_init(void); static inline void __init at91rm9200_pm_init(void) { } static inline void __init at91sam9_pm_init(void) { } static inline void __init sam9x60_pm_init(void) { } +static inline void __init sam9x7_pm_init(void) { } static inline void __init sama5_pm_init(void) { } static inline void __init sama5d2_pm_init(void) { } static inline void __init sama7_pm_init(void) { } diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 345b91dc6627..b9b995f8a36e 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -233,6 +233,13 @@ static const struct of_device_id sama7g5_ws_ids[] = { { /* sentinel */ } }; +static const struct of_device_id sam9x7_ws_ids[] = { + { .compatible = "microchip,sam9x7-rtc", .data = &ws_info[1] }, + { .compatible = "microchip,sam9x7-rtt", .data = &ws_info[4] }, + { .compatible = "microchip,sam9x7-gem", .data = &ws_info[5] }, + { /* sentinel */ } +}; + static int at91_pm_config_ws(unsigned int pm_mode, bool set) { const struct wakeup_source_info *wsi; @@ -1361,6 +1368,7 @@ static const struct of_device_id atmel_pmc_ids[] __initconst = { { .compatible = "atmel,sama5d4-pmc", .data = &pmc_infos[1] }, { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] }, { .compatible = "microchip,sam9x60-pmc", .data = &pmc_infos[4] }, + { .compatible = "microchip,sam9x7-pmc", .data = &pmc_infos[4] }, { .compatible = "microchip,sama7g5-pmc", .data = &pmc_infos[5] }, { /* sentinel */ }, }; @@ -1499,6 +1507,27 @@ void __init sam9x60_pm_init(void) soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws; } +void __init sam9x7_pm_init(void) +{ + static const int modes[] __initconst = { + AT91_PM_STANDBY, AT91_PM_ULP0, + }; + int ret; + + if (!IS_ENABLED(CONFIG_SOC_SAM9X7)) + return; + + at91_pm_modes_validate(modes, ARRAY_SIZE(modes)); + ret = at91_dt_ramc(false); + if (ret) + return; + + at91_pm_init(NULL); + + soc_pm.ws_ids = sam9x7_ws_ids; + soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws; +} + void __init at91sam9_pm_init(void) { int ret; From 2488bde930e59cdb148d8574a611fb1825cfc109 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Mon, 29 Jul 2024 12:37:05 +0530 Subject: [PATCH 024/212] ARM: at91: pm: add sam9x7 SoC init config Add SoC init config for sam9x7 family. Signed-off-by: Varshini Rajendran Reviewed-by: Claudiu Beznea Link: https://lore.kernel.org/r/20240729070705.1990557-1-varshini.rajendran@microchip.com Signed-off-by: Claudiu Beznea --- arch/arm/mach-at91/Makefile | 1 + arch/arm/mach-at91/sam9x7.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 arch/arm/mach-at91/sam9x7.c diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 794bd12ab0a8..7d8a7bc44e65 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o +obj-$(CONFIG_SOC_SAM9X7) += sam9x7.o obj-$(CONFIG_SOC_SAMA5) += sama5.o sam_secure.o obj-$(CONFIG_SOC_SAMA7) += sama7.o obj-$(CONFIG_SOC_SAMV7) += samv7.o diff --git a/arch/arm/mach-at91/sam9x7.c b/arch/arm/mach-at91/sam9x7.c new file mode 100644 index 000000000000..e1ff30b5b09b --- /dev/null +++ b/arch/arm/mach-at91/sam9x7.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Setup code for SAM9X7. + * + * Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries + * + * Author: Varshini Rajendran + */ + +#include +#include + +#include + +#include "generic.h" + +static void __init sam9x7_init(void) +{ + of_platform_default_populate(NULL, NULL, NULL); + + sam9x7_pm_init(); +} + +static const char * const sam9x7_dt_board_compat[] __initconst = { + "microchip,sam9x7", + NULL +}; + +DT_MACHINE_START(sam9x7_dt, "Microchip SAM9X7") + /* Maintainer: Microchip */ + .init_machine = sam9x7_init, + .dt_compat = sam9x7_dt_board_compat, +MACHINE_END From 5eb64f2b368f32cb4c31975fc42485c09b693c65 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Mon, 29 Jul 2024 12:37:11 +0530 Subject: [PATCH 025/212] ARM: at91: add support in SoC driver for new sam9x7 Add support for SAM9X7 SoC in the SoC driver. Signed-off-by: Varshini Rajendran Reviewed-by: Claudiu Beznea Link: https://lore.kernel.org/r/20240729070711.1990605-1-varshini.rajendran@microchip.com Signed-off-by: Claudiu Beznea --- drivers/soc/atmel/soc.c | 23 +++++++++++++++++++++++ drivers/soc/atmel/soc.h | 9 +++++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c index cc9a3e107479..2a42b28931c9 100644 --- a/drivers/soc/atmel/soc.c +++ b/drivers/soc/atmel/soc.c @@ -101,6 +101,29 @@ static const struct at91_soc socs[] __initconst = { AT91_CIDR_VERSION_MASK, SAM9X60_D6K_EXID_MATCH, "sam9x60 8MiB SDRAM SiP", "sam9x60"), #endif +#ifdef CONFIG_SOC_SAM9X7 + AT91_SOC(SAM9X7_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAM9X70_EXID_MATCH, + "sam9x70", "sam9x7"), + AT91_SOC(SAM9X7_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAM9X72_EXID_MATCH, + "sam9x72", "sam9x7"), + AT91_SOC(SAM9X7_CIDR_MATCH, AT91_CIDR_MATCH_MASK, + AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH, + "sam9x75", "sam9x7"), + AT91_SOC(SAM9X7_CIDR_MATCH, SAM9X75_D1M_EXID_MATCH, + AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH, + "sam9x75 16MB DDR2 SiP", "sam9x7"), + AT91_SOC(SAM9X7_CIDR_MATCH, SAM9X75_D5M_EXID_MATCH, + AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH, + "sam9x75 64MB DDR2 SiP", "sam9x7"), + AT91_SOC(SAM9X7_CIDR_MATCH, SAM9X75_D1G_EXID_MATCH, + AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH, + "sam9x75 125MB DDR3L SiP ", "sam9x7"), + AT91_SOC(SAM9X7_CIDR_MATCH, SAM9X75_D2G_EXID_MATCH, + AT91_CIDR_VERSION_MASK, SAM9X75_EXID_MATCH, + "sam9x75 250MB DDR3L SiP", "sam9x7"), +#endif #ifdef CONFIG_SOC_SAMA5 AT91_SOC(SAMA5D2_CIDR_MATCH, AT91_CIDR_MATCH_MASK, AT91_CIDR_VERSION_MASK, SAMA5D21CU_EXID_MATCH, diff --git a/drivers/soc/atmel/soc.h b/drivers/soc/atmel/soc.h index 7a9f47ce85fb..2c78e54255f7 100644 --- a/drivers/soc/atmel/soc.h +++ b/drivers/soc/atmel/soc.h @@ -44,6 +44,7 @@ at91_soc_init(const struct at91_soc *socs); #define AT91SAM9X5_CIDR_MATCH 0x019a05a0 #define AT91SAM9N12_CIDR_MATCH 0x019a07a0 #define SAM9X60_CIDR_MATCH 0x019b35a0 +#define SAM9X7_CIDR_MATCH 0x09750020 #define SAMA7G5_CIDR_MATCH 0x00162100 #define AT91SAM9M11_EXID_MATCH 0x00000001 @@ -66,6 +67,14 @@ at91_soc_init(const struct at91_soc *socs); #define SAM9X60_D1G_EXID_MATCH 0x00000010 #define SAM9X60_D6K_EXID_MATCH 0x00000011 +#define SAM9X70_EXID_MATCH 0x00000005 +#define SAM9X72_EXID_MATCH 0x00000004 +#define SAM9X75_D1G_EXID_MATCH 0x00000018 +#define SAM9X75_D2G_EXID_MATCH 0x00000020 +#define SAM9X75_D1M_EXID_MATCH 0x00000003 +#define SAM9X75_D5M_EXID_MATCH 0x00000010 +#define SAM9X75_EXID_MATCH 0x00000000 + #define SAMA7G51_EXID_MATCH 0x3 #define SAMA7G52_EXID_MATCH 0x2 #define SAMA7G53_EXID_MATCH 0x1 From 1a92f0387b17c8cb4548185675fb42de670f9794 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Mon, 29 Jul 2024 12:39:16 +0530 Subject: [PATCH 026/212] ARM: at91: Kconfig: add config flag for SAM9X7 SoC Add config flag for sam9x7 SoC. Signed-off-by: Varshini Rajendran Reviewed-by: Claudiu Beznea Link: https://lore.kernel.org/r/20240729070916.1991370-1-varshini.rajendran@microchip.com Signed-off-by: Claudiu Beznea --- arch/arm/mach-at91/Kconfig | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index a8c022b4c053..344f5305f69a 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -141,11 +141,27 @@ config SOC_SAM9X60 help Select this if you are using Microchip's SAM9X60 SoC +config SOC_SAM9X7 + bool "SAM9X7" + depends on ARCH_MULTI_V5 + select ATMEL_AIC5_IRQ + select ATMEL_PM if PM + select CPU_ARM926T + select HAVE_AT91_USB_CLK + select HAVE_AT91_GENERATED_CLK + select HAVE_AT91_SAM9X60_PLL + select MEMORY + select PINCTRL_AT91 + select SOC_SAM_V4_V5 + select SRAM if PM + help + Select this if you are using Microchip's SAM9X7 SoC + comment "Clocksource driver selection" config ATMEL_CLOCKSOURCE_PIT bool "Periodic Interval Timer (PIT) support" - depends on SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAMA5 + depends on SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAM9X7 || SOC_SAMA5 default SOC_AT91SAM9 || SOC_SAMA5 select ATMEL_PIT help @@ -155,7 +171,7 @@ config ATMEL_CLOCKSOURCE_PIT config ATMEL_CLOCKSOURCE_TCB bool "Timer Counter Blocks (TCB) support" - default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAMA5 + default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAM9X60 || SOC_SAM9X7 || SOC_SAMA5 select ATMEL_TCB_CLKSRC help Select this to get a high precision clocksource based on a @@ -166,7 +182,7 @@ config ATMEL_CLOCKSOURCE_TCB config MICROCHIP_CLOCKSOURCE_PIT64B bool "64-bit Periodic Interval Timer (PIT64B) support" - default SOC_SAM9X60 || SOC_SAMA7 + default SOC_SAM9X60 || SOC_SAM9X7 || SOC_SAMA7 select MICROCHIP_PIT64B help Select this to get a high resolution clockevent (SAM9X60) or From e3e4e77140b4a240865309cc543141a593be4a21 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 7 Aug 2024 16:59:58 -0600 Subject: [PATCH 027/212] dt-bindings: memory-controllers: fsl,imx-weim: Fix "fsl,weim-cs-timing" schema The "fsl,weim-cs-timing" property is an array, but the constraints in the if/then schema are for a matrix. That worked fine when all properties were decoded into a matrix, but now dtschema decodes properties into scalars and arrays based on their type. Signed-off-by: Rob Herring (Arm) Acked-by: Peng Fan Link: https://lore.kernel.org/r/20240807225959.3343093-1-robh@kernel.org Signed-off-by: Krzysztof Kozlowski --- .../memory-controllers/fsl/fsl,imx-weim.yaml | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml b/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml index 3f40ca5b13f6..ce4ec94a561c 100644 --- a/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml @@ -134,9 +134,8 @@ allOf: properties: fsl,weim-cs-timing: items: - items: - - description: CSxU - - description: CSxL + - description: CSxU + - description: CSxL - if: properties: compatible: @@ -151,10 +150,9 @@ allOf: properties: fsl,weim-cs-timing: items: - items: - - description: CSCRxU - - description: CSCRxL - - description: CSCRxA + - description: CSCRxU + - description: CSCRxL + - description: CSCRxA - if: properties: compatible: @@ -171,13 +169,12 @@ allOf: properties: fsl,weim-cs-timing: items: - items: - - description: CSxGCR1 - - description: CSxGCR2 - - description: CSxRCR1 - - description: CSxRCR2 - - description: CSxWCR1 - - description: CSxWCR2 + - description: CSxGCR1 + - description: CSxGCR2 + - description: CSxRCR1 + - description: CSxRCR2 + - description: CSxWCR1 + - description: CSxWCR2 additionalProperties: false From 20c9234d623cc54caed843739c1f89b305eb3bfa Mon Sep 17 00:00:00 2001 From: Luke Parkin Date: Mon, 5 Aug 2024 14:10:08 +0100 Subject: [PATCH 028/212] firmware: arm_scmi: Remove superfluous handle_to_scmi_info Variable info is already defined in the outer code block and there is no need to define the same again in the inner code block. Let us just remove that duplicate definition of the variable info. No functional change. Reviewed-by: Cristian Marussi Tested-by: Cristian Marussi Signed-off-by: Luke Parkin Message-Id: <20240805131013.587016-2-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 6b6957f4743f..56a93d20bf23 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -1261,9 +1261,6 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, xfer->rx.buf, xfer->rx.len); if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { - struct scmi_info *info = - handle_to_scmi_info(cinfo->handle); - scmi_raw_message_report(info->raw, xfer, SCMI_RAW_REPLY_QUEUE, cinfo->id); From 1b18d4295f9d1125bc7a799fc12924cd45fc04b1 Mon Sep 17 00:00:00 2001 From: Luke Parkin Date: Mon, 5 Aug 2024 14:10:09 +0100 Subject: [PATCH 029/212] firmware: arm_scmi: Add support for debug metrics at the interface Since SCMI involves interaction with the entity(software, firmware and/or hardware) providing services or features, it is quite useful to track certain metrics(for pure debugging purposes) like how many messages were sent or received, were there any failures, what kind of failures, ..etc. Add a new optional config option for the above purpose and the initial support for counting such key debug metrics. Signed-off-by: Luke Parkin Reviewed-by: Cristian Marussi Tested-by: Cristian Marussi Message-Id: <20240805131013.587016-3-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Kconfig | 14 ++++++++++++++ drivers/firmware/arm_scmi/common.h | 10 ++++++++++ drivers/firmware/arm_scmi/driver.c | 2 ++ 3 files changed, 26 insertions(+) diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index aa5842be19b2..f35784d0a8dd 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -55,6 +55,20 @@ config ARM_SCMI_RAW_MODE_SUPPORT_COEX operate normally, thing which could make an SCMI test suite using the SCMI Raw mode support unreliable. If unsure, say N. +config ARM_SCMI_DEBUG_COUNTERS + bool "Enable SCMI communication debug metrics tracking" + select ARM_SCMI_NEED_DEBUGFS + depends on DEBUG_FS + default n + help + Enables tracking of some key communication metrics for debug + purposes. It may track metrics like how many messages were sent + or received, were there any failures, what kind of failures, ..etc. + + Enable this option to create a new debugfs directory which contains + such useful debug counters. This can be helpful for debugging and + SCMI monitoring. + config ARM_SCMI_HAVE_TRANSPORT bool help diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 4b8c5250cdb5..d414b0a43b3b 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -301,6 +301,16 @@ extern const struct scmi_desc scmi_optee_desc; void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv); +enum debug_counters { + SCMI_DEBUG_COUNTERS_LAST +}; + +static inline void scmi_inc_count(atomic_t *arr, int stat) +{ + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) + atomic_inc(&arr[stat]); +} + enum scmi_bad_msg { MSG_UNEXPECTED = -1, MSG_INVALID = -2, diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 56a93d20bf23..958b2ac92050 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -117,12 +117,14 @@ struct scmi_protocol_instance { * @name: Name of this SCMI instance * @type: Type of this SCMI instance * @is_atomic: Flag to state if the transport of this instance is atomic + * @counters: An array of atomic_c's used for tracking statistics (if enabled) */ struct scmi_debug_info { struct dentry *top_dentry; const char *name; const char *type; bool is_atomic; + atomic_t counters[SCMI_DEBUG_COUNTERS_LAST]; }; /** From 0b3d48c4726e1b20dffd2ff81a9d94d5d930220b Mon Sep 17 00:00:00 2001 From: Luke Parkin Date: Mon, 5 Aug 2024 14:10:10 +0100 Subject: [PATCH 030/212] firmware: arm_scmi: Track basic SCMI communication debug metrics Add the support for counting some of the SCMI communication debug metrics like how many were sent successfully or with some errors, responses received, notifications and delayed responses, transfer timeouts and errors from the firmware/platform. In many cases, the traces exists. But the traces are not always necessarily enabled and getting such cumulative SCMI communication debug metrics helps in understanding if there are any possible improvements that can be made on either side of SCMI communication. Signed-off-by: Luke Parkin Reviewed-by: Cristian Marussi Tested-by: Cristian Marussi Message-Id: <20240805131013.587016-4-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/common.h | 14 ++++++++++++++ drivers/firmware/arm_scmi/driver.c | 25 ++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index d414b0a43b3b..21c94deaf614 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -302,6 +302,20 @@ extern const struct scmi_desc scmi_optee_desc; void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv); enum debug_counters { + SENT_OK, + SENT_FAIL, + SENT_FAIL_POLLING_UNSUPPORTED, + SENT_FAIL_CHANNEL_NOT_FOUND, + RESPONSE_OK, + NOTIFICATION_OK, + DELAYED_RESPONSE_OK, + XFERS_RESPONSE_TIMEOUT, + XFERS_RESPONSE_POLLED_TIMEOUT, + RESPONSE_POLLED_OK, + ERR_MSG_UNEXPECTED, + ERR_MSG_INVALID, + ERR_MSG_NOMEM, + ERR_PROTOCOL, SCMI_DEBUG_COUNTERS_LAST }; diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 958b2ac92050..943ba03315de 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -990,6 +990,7 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr) spin_unlock_irqrestore(&minfo->xfer_lock, flags); scmi_bad_message_trace(cinfo, msg_hdr, MSG_UNEXPECTED); + scmi_inc_count(info->dbg->counters, ERR_MSG_UNEXPECTED); return xfer; } @@ -1017,6 +1018,8 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr) msg_type, xfer_id, msg_hdr, xfer->state); scmi_bad_message_trace(cinfo, msg_hdr, MSG_INVALID); + scmi_inc_count(info->dbg->counters, ERR_MSG_INVALID); + /* On error the refcount incremented above has to be dropped */ __scmi_xfer_put(minfo, xfer); @@ -1056,6 +1059,7 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, PTR_ERR(xfer)); scmi_bad_message_trace(cinfo, msg_hdr, MSG_NOMEM); + scmi_inc_count(info->dbg->counters, ERR_MSG_NOMEM); scmi_clear_channel(info, cinfo); return; @@ -1071,6 +1075,7 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, xfer->hdr.id, "NOTI", xfer->hdr.seq, xfer->hdr.status, xfer->rx.buf, xfer->rx.len); + scmi_inc_count(info->dbg->counters, NOTIFICATION_OK); scmi_notify(cinfo->handle, xfer->hdr.protocol_id, xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts); @@ -1130,8 +1135,10 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo, if (xfer->hdr.type == MSG_TYPE_DELAYED_RESP) { scmi_clear_channel(info, cinfo); complete(xfer->async_done); + scmi_inc_count(info->dbg->counters, DELAYED_RESPONSE_OK); } else { complete(&xfer->done); + scmi_inc_count(info->dbg->counters, RESPONSE_OK); } if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { @@ -1215,6 +1222,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, struct scmi_xfer *xfer, unsigned int timeout_ms) { int ret = 0; + struct scmi_info *info = handle_to_scmi_info(cinfo->handle); if (xfer->hdr.poll_completion) { /* @@ -1235,13 +1243,12 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, "timed out in resp(caller: %pS) - polling\n", (void *)_RET_IP_); ret = -ETIMEDOUT; + scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_POLLED_TIMEOUT); } } if (!ret) { unsigned long flags; - struct scmi_info *info = - handle_to_scmi_info(cinfo->handle); /* * Do not fetch_response if an out-of-order delayed @@ -1261,6 +1268,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, "RESP" : "resp", xfer->hdr.seq, xfer->hdr.status, xfer->rx.buf, xfer->rx.len); + scmi_inc_count(info->dbg->counters, RESPONSE_POLLED_OK); if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) { scmi_raw_message_report(info->raw, xfer, @@ -1275,6 +1283,7 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc, dev_err(dev, "timed out in resp(caller: %pS)\n", (void *)_RET_IP_); ret = -ETIMEDOUT; + scmi_inc_count(info->dbg->counters, XFERS_RESPONSE_TIMEOUT); } } @@ -1358,13 +1367,15 @@ static int do_xfer(const struct scmi_protocol_handle *ph, !is_transport_polling_capable(info->desc)) { dev_warn_once(dev, "Polling mode is not supported by transport.\n"); + scmi_inc_count(info->dbg->counters, SENT_FAIL_POLLING_UNSUPPORTED); return -EINVAL; } cinfo = idr_find(&info->tx_idr, pi->proto->id); - if (unlikely(!cinfo)) + if (unlikely(!cinfo)) { + scmi_inc_count(info->dbg->counters, SENT_FAIL_CHANNEL_NOT_FOUND); return -EINVAL; - + } /* True ONLY if also supported by transport. */ if (is_polling_enabled(cinfo, info->desc)) xfer->hdr.poll_completion = true; @@ -1396,16 +1407,20 @@ static int do_xfer(const struct scmi_protocol_handle *ph, ret = info->desc->ops->send_message(cinfo, xfer); if (ret < 0) { dev_dbg(dev, "Failed to send message %d\n", ret); + scmi_inc_count(info->dbg->counters, SENT_FAIL); return ret; } trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id, xfer->hdr.id, "CMND", xfer->hdr.seq, xfer->hdr.status, xfer->tx.buf, xfer->tx.len); + scmi_inc_count(info->dbg->counters, SENT_OK); ret = scmi_wait_for_message_response(cinfo, xfer); - if (!ret && xfer->hdr.status) + if (!ret && xfer->hdr.status) { ret = scmi_to_linux_errno(xfer->hdr.status); + scmi_inc_count(info->dbg->counters, ERR_PROTOCOL); + } if (info->desc->ops->mark_txdone) info->desc->ops->mark_txdone(cinfo, ret, xfer); From f6a905eaf6bfcf63d7b83d27bf3046e0e7a6f0a6 Mon Sep 17 00:00:00 2001 From: Luke Parkin Date: Mon, 5 Aug 2024 14:10:11 +0100 Subject: [PATCH 031/212] firmware: arm_scmi: Create debugfs files for SCMI communication debug metrics Now that the basic support to collect the SCMI communication debug metrics is in place, let us create debugfs files for the same so that they are accessible to the users/debuggers. Signed-off-by: Luke Parkin Reviewed-by: Cristian Marussi Tested-by: Cristian Marussi Message-Id: <20240805131013.587016-5-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 943ba03315de..ade32a67ab63 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -2847,6 +2847,36 @@ static int scmi_device_request_notifier(struct notifier_block *nb, return NOTIFY_OK; } +static const char * const dbg_counter_strs[] = { + "sent_ok", + "sent_fail", + "sent_fail_polling_unsupported", + "sent_fail_channel_not_found", + "response_ok", + "notification_ok", + "delayed_response_ok", + "xfers_response_timeout", + "xfers_response_polled_timeout", + "response_polled_ok", + "err_msg_unexpected", + "err_msg_invalid", + "err_msg_nomem", + "err_protocol", +}; + +static void scmi_debugfs_counters_setup(struct scmi_debug_info *dbg, + struct dentry *trans) +{ + struct dentry *counters; + int idx; + + counters = debugfs_create_dir("counters", trans); + + for (idx = 0; idx < SCMI_DEBUG_COUNTERS_LAST; idx++) + debugfs_create_atomic_t(dbg_counter_strs[idx], 0400, counters, + &dbg->counters[idx]); +} + static void scmi_debugfs_common_cleanup(void *d) { struct scmi_debug_info *dbg = d; @@ -2913,6 +2943,9 @@ static struct scmi_debug_info *scmi_debugfs_common_setup(struct scmi_info *info) debugfs_create_u32("rx_max_msg", 0400, trans, (u32 *)&info->rx_minfo.max_msg); + if (IS_ENABLED(CONFIG_ARM_SCMI_DEBUG_COUNTERS)) + scmi_debugfs_counters_setup(dbg, trans); + dbg->top_dentry = top_dentry; if (devm_add_action_or_reset(info->dev, From bd02b0737f3816073e7a37a667190dea3c195e4a Mon Sep 17 00:00:00 2001 From: Luke Parkin Date: Mon, 5 Aug 2024 14:10:12 +0100 Subject: [PATCH 032/212] firmware: arm_scmi: Add support to reset the debug metrics It is sometimes useful to reset all these SCMI communication debug metrics especially when we are interested in analysing these metrics during a particular workload or for a fixed time duration. Let us add the capability to reset all these metrics as once so that they can be counted during the period of interest. Signed-off-by: Luke Parkin Reviewed-by: Cristian Marussi Tested-by: Cristian Marussi Message-Id: <20240805131013.587016-6-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index ade32a67ab63..ca910079d718 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -2864,6 +2864,24 @@ static const char * const dbg_counter_strs[] = { "err_protocol", }; +static ssize_t reset_all_on_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct scmi_debug_info *dbg = filp->private_data; + + for (int i = 0; i < SCMI_DEBUG_COUNTERS_LAST; i++) + atomic_set(&dbg->counters[i], 0); + + return count; +} + +static const struct file_operations fops_reset_counts = { + .owner = THIS_MODULE, + .open = simple_open, + .llseek = no_llseek, + .write = reset_all_on_write, +}; + static void scmi_debugfs_counters_setup(struct scmi_debug_info *dbg, struct dentry *trans) { @@ -2873,8 +2891,10 @@ static void scmi_debugfs_counters_setup(struct scmi_debug_info *dbg, counters = debugfs_create_dir("counters", trans); for (idx = 0; idx < SCMI_DEBUG_COUNTERS_LAST; idx++) - debugfs_create_atomic_t(dbg_counter_strs[idx], 0400, counters, + debugfs_create_atomic_t(dbg_counter_strs[idx], 0600, counters, &dbg->counters[idx]); + + debugfs_create_file("reset", 0200, counters, dbg, &fops_reset_counts); } static void scmi_debugfs_common_cleanup(void *d) From eedc060cff725ff53f284c63d55a42f49e6d2b3c Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Thu, 25 Jul 2024 08:53:17 +0200 Subject: [PATCH 033/212] firmware: arm_scmi: Fix voltage description in failure cases Reset the reception buffer max size when a voltage domain description request fails, for example when the voltage domain returns an access permission error (SCMI_ERR_ACCESS) unless what only a single 32bit word is read back for the remaining voltage description requests responses leading to invalid information. The side effect of this issue is that the voltage regulators registered from those remaining SCMI voltage domain were assigned a wrong regulator name. Signed-off-by: Etienne Carriere Reviewed-by: Cristian Marussi Message-Id: <20240725065317.3758165-1-etienne.carriere@foss.st.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/voltage.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c index 2175ffd6cef5..f1a7c04ae820 100644 --- a/drivers/firmware/arm_scmi/voltage.c +++ b/drivers/firmware/arm_scmi/voltage.c @@ -229,8 +229,10 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph, /* Retrieve domain attributes at first ... */ put_unaligned_le32(dom, td->tx.buf); /* Skip domain on comms error */ - if (ph->xops->do_xfer(ph, td)) + if (ph->xops->do_xfer(ph, td)) { + ph->xops->reset_rx_to_maxsz(ph, td); continue; + } v = vinfo->domains + dom; v->id = dom; From 4d5921a39f67232f5d61440956c552f6e7a892d4 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 28 Jun 2024 11:03:09 +0800 Subject: [PATCH 034/212] dt-bindings: firmware: arm,scmi: Add support for system power protocol Add SCMI System Power Protocol bindings, and the protocol id is 0x12. Signed-off-by: Peng Fan Reviewed-by: Rob Herring (Arm) Message-Id: <20240628030309.1162012-1-peng.fan@oss.nxp.com> Signed-off-by: Sudeep Holla --- Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml index 4d823f3b1f0e..ebf384e76df1 100644 --- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml +++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml @@ -145,6 +145,14 @@ properties: required: - '#power-domain-cells' + protocol@12: + $ref: '#/$defs/protocol-node' + unevaluatedProperties: false + + properties: + reg: + const: 0x12 + protocol@13: $ref: '#/$defs/protocol-node' unevaluatedProperties: false From 8c38617722bdf57a90e6c77ed9ee5ebb60958d2a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 9 Aug 2024 16:15:54 +0200 Subject: [PATCH 035/212] memory: ti-aemif: remove platform data support There are no longer any users of the ti-aemif driver that set up platform data from board files. We can shrink the driver by removing support for it. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20240809-ti-aemif-v1-1-27b1e5001390@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/ti-aemif.c | 25 +------------- include/linux/platform_data/ti-aemif.h | 45 -------------------------- 2 files changed, 1 insertion(+), 69 deletions(-) delete mode 100644 include/linux/platform_data/ti-aemif.h diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index e192db9e0e4b..b92cab455cbb 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -17,7 +17,6 @@ #include #include #include -#include #define TA_SHIFT 2 #define RHOLD_SHIFT 4 @@ -332,16 +331,11 @@ static int aemif_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct device_node *child_np; struct aemif_device *aemif; - struct aemif_platform_data *pdata; - struct of_dev_auxdata *dev_lookup; aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL); if (!aemif) return -ENOMEM; - pdata = dev_get_platdata(&pdev->dev); - dev_lookup = pdata ? pdata->dev_lookup : NULL; - platform_set_drvdata(pdev, aemif); aemif->clk = devm_clk_get(dev, NULL); @@ -358,8 +352,6 @@ static int aemif_probe(struct platform_device *pdev) if (np && of_device_is_compatible(np, "ti,da850-aemif")) aemif->cs_offset = 2; - else if (pdata) - aemif->cs_offset = pdata->cs_offset; aemif->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(aemif->base)) { @@ -381,11 +373,6 @@ static int aemif_probe(struct platform_device *pdev) goto error; } } - } else if (pdata && pdata->num_abus_data > 0) { - for (i = 0; i < pdata->num_abus_data; i++, aemif->num_cs++) { - aemif->cs_data[i].cs = pdata->abus_data[i].cs; - aemif_get_hw_params(pdev, i); - } } for (i = 0; i < aemif->num_cs; i++) { @@ -403,22 +390,12 @@ static int aemif_probe(struct platform_device *pdev) */ if (np) { for_each_available_child_of_node(np, child_np) { - ret = of_platform_populate(child_np, NULL, - dev_lookup, dev); + ret = of_platform_populate(child_np, NULL, NULL, dev); if (ret < 0) { of_node_put(child_np); goto error; } } - } else if (pdata) { - for (i = 0; i < pdata->num_sub_devices; i++) { - pdata->sub_devices[i].dev.parent = dev; - ret = platform_device_register(&pdata->sub_devices[i]); - if (ret) { - dev_warn(dev, "Error register sub device %s\n", - pdata->sub_devices[i].name); - } - } } return 0; diff --git a/include/linux/platform_data/ti-aemif.h b/include/linux/platform_data/ti-aemif.h deleted file mode 100644 index 77625251df07..000000000000 --- a/include/linux/platform_data/ti-aemif.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * TI DaVinci AEMIF platform glue. - * - * Copyright (C) 2017 BayLibre SAS - * - * Author: - * Bartosz Golaszewski - */ - -#ifndef __TI_DAVINCI_AEMIF_DATA_H__ -#define __TI_DAVINCI_AEMIF_DATA_H__ - -#include - -/** - * struct aemif_abus_data - Async bus configuration parameters. - * - * @cs - Chip-select number. - */ -struct aemif_abus_data { - u32 cs; -}; - -/** - * struct aemif_platform_data - Data to set up the TI aemif driver. - * - * @dev_lookup: of_dev_auxdata passed to of_platform_populate() for aemif - * subdevices. - * @cs_offset: Lowest allowed chip-select number. - * @abus_data: Array of async bus configuration entries. - * @num_abus_data: Number of abus entries. - * @sub_devices: Array of platform subdevices. - * @num_sub_devices: Number of subdevices. - */ -struct aemif_platform_data { - struct of_dev_auxdata *dev_lookup; - u32 cs_offset; - struct aemif_abus_data *abus_data; - size_t num_abus_data; - struct platform_device *sub_devices; - size_t num_sub_devices; -}; - -#endif /* __TI_DAVINCI_AEMIF_DATA_H__ */ From f6ae541cc3355fe872d4c942dc47d67877951d17 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 9 Aug 2024 16:15:55 +0200 Subject: [PATCH 036/212] memory: ti-aemif: use devm_clk_get_enabled() and shrink the code Remove several lines of code and a jump label by using the managed variant of clk_get() that also prepares and enables the clock (and disables and unprepares it on driver detach). Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20240809-ti-aemif-v1-2-27b1e5001390@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/ti-aemif.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index b92cab455cbb..fbe0786f5ac4 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -338,26 +338,20 @@ static int aemif_probe(struct platform_device *pdev) platform_set_drvdata(pdev, aemif); - aemif->clk = devm_clk_get(dev, NULL); + aemif->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(aemif->clk)) { dev_err(dev, "cannot get clock 'aemif'\n"); return PTR_ERR(aemif->clk); } - ret = clk_prepare_enable(aemif->clk); - if (ret) - return ret; - aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC; if (np && of_device_is_compatible(np, "ti,da850-aemif")) aemif->cs_offset = 2; aemif->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(aemif->base)) { - ret = PTR_ERR(aemif->base); - goto error; - } + if (IS_ERR(aemif->base)) + return PTR_ERR(aemif->base); if (np) { /* @@ -370,7 +364,7 @@ static int aemif_probe(struct platform_device *pdev) ret = of_aemif_parse_abus_config(pdev, child_np); if (ret < 0) { of_node_put(child_np); - goto error; + return ret; } } } @@ -380,7 +374,7 @@ static int aemif_probe(struct platform_device *pdev) if (ret < 0) { dev_err(dev, "Error configuring chip select %d\n", aemif->cs_data[i].cs); - goto error; + return ret; } } @@ -393,27 +387,16 @@ static int aemif_probe(struct platform_device *pdev) ret = of_platform_populate(child_np, NULL, NULL, dev); if (ret < 0) { of_node_put(child_np); - goto error; + return ret; } } } return 0; -error: - clk_disable_unprepare(aemif->clk); - return ret; -} - -static void aemif_remove(struct platform_device *pdev) -{ - struct aemif_device *aemif = platform_get_drvdata(pdev); - - clk_disable_unprepare(aemif->clk); } static struct platform_driver aemif_driver = { .probe = aemif_probe, - .remove_new = aemif_remove, .driver = { .name = "ti-aemif", .of_match_table = of_match_ptr(aemif_of_match), From 23a641d5c2bce4c723fff9118a5d865ee6b9d05a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 9 Aug 2024 16:15:56 +0200 Subject: [PATCH 037/212] memory: ti-aemif: don't needlessly iterate over child nodes When populating devices from a specific node, we don't need to call of_platform_populate() for every child node manually - the routine will already do it. We can call it directly from the platform device's OF node. While at it: use the managed variant of of_platform_populate(). Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20240809-ti-aemif-v1-3-27b1e5001390@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/ti-aemif.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index fbe0786f5ac4..49e7cbe98fdb 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -383,13 +383,9 @@ static int aemif_probe(struct platform_device *pdev) * child will be probed after the AEMIF timing parameters are set. */ if (np) { - for_each_available_child_of_node(np, child_np) { - ret = of_platform_populate(child_np, NULL, NULL, dev); - if (ret < 0) { - of_node_put(child_np); - return ret; - } - } + ret = devm_of_platform_populate(dev); + if (ret) + return ret; } return 0; From e98dba934b2fc587eafb83f47ad64d9053b18ae0 Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:33:32 +0100 Subject: [PATCH 038/212] firmware: arm_scmi: Fix double free in OPTEE transport Channels can be shared between protocols, avoid freeing the same channel descriptors twice when unloading the stack. Fixes: 5f90f189a052 ("firmware: arm_scmi: Add optee transport") Signed-off-by: Cristian Marussi Tested-by: Peng Fan #i.MX95 19x19 EVK Reviewed-by: Peng Fan Tested-by: Florian Fainelli Message-Id: <20240812173340.3912830-2-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/optee.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c index 4e7944b91e38..0c8908d3b1d6 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/optee.c @@ -473,6 +473,13 @@ static int scmi_optee_chan_free(int id, void *p, void *data) struct scmi_chan_info *cinfo = p; struct scmi_optee_channel *channel = cinfo->transport_info; + /* + * Different protocols might share the same chan info, so a previous + * call might have already freed the structure. + */ + if (!channel) + return 0; + mutex_lock(&scmi_optee_private->mu); list_del(&channel->link); mutex_unlock(&scmi_optee_private->mu); From 1ebc28e9357cc1064c5ae79a4c87c6b424b10b6e Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 12 Aug 2024 18:33:33 +0100 Subject: [PATCH 039/212] firmware: arm_scmi: Introduce setup_shmem_iomap To get the address of shmem could be generalized by introducing setup_shmem_iomap. Then the duplicated code in mailbox.c, optee.c and smc.c could be dropped. Signed-off-by: Peng Fan [ Cristian: use OF __free and make use of the new helper also in smc.c ] Signed-off-by: Cristian Marussi Tested-by: Peng Fan #i.MX95 19x19 EVK Tested-by: Florian Fainelli Message-Id: <20240812173340.3912830-3-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/common.h | 2 ++ drivers/firmware/arm_scmi/mailbox.c | 27 +++---------------- drivers/firmware/arm_scmi/optee.c | 35 +++--------------------- drivers/firmware/arm_scmi/shmem.c | 41 +++++++++++++++++++++++++++++ drivers/firmware/arm_scmi/smc.c | 27 ++++--------------- 5 files changed, 56 insertions(+), 76 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 21c94deaf614..28c963358e01 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -351,6 +351,8 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem); bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem); +void __iomem *setup_shmem_iomap(struct scmi_chan_info *cinfo, struct device *dev, + bool tx, struct resource *res); /* declarations for message passing transports */ struct scmi_msg_payld; diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 0219a12e3209..886fc4eedb4a 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -178,11 +178,8 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, const char *desc = tx ? "Tx" : "Rx"; struct device *cdev = cinfo->dev; struct scmi_mailbox *smbox; - struct device_node *shmem; - int ret, a2p_rx_chan, p2a_chan, p2a_rx_chan, idx = tx ? 0 : 1; + int ret, a2p_rx_chan, p2a_chan, p2a_rx_chan; struct mbox_client *cl; - resource_size_t size; - struct resource res; ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan, &p2a_rx_chan); if (ret) @@ -195,25 +192,9 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!smbox) return -ENOMEM; - shmem = of_parse_phandle(cdev->of_node, "shmem", idx); - if (!of_device_is_compatible(shmem, "arm,scmi-shmem")) { - of_node_put(shmem); - return -ENXIO; - } - - ret = of_address_to_resource(shmem, 0, &res); - of_node_put(shmem); - if (ret) { - dev_err(cdev, "failed to get SCMI %s shared memory\n", desc); - return ret; - } - - size = resource_size(&res); - smbox->shmem = devm_ioremap(dev, res.start, size); - if (!smbox->shmem) { - dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc); - return -EADDRNOTAVAIL; - } + smbox->shmem = setup_shmem_iomap(cinfo, dev, tx, NULL); + if (IS_ERR(smbox->shmem)) + return PTR_ERR(smbox->shmem); cl = &smbox->cl; cl->dev = cdev; diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c index 0c8908d3b1d6..ee9cda1a8211 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/optee.c @@ -368,38 +368,11 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo, struct scmi_optee_channel *channel) { - struct device_node *np; - resource_size_t size; - struct resource res; - int ret; + channel->req.shmem = setup_shmem_iomap(cinfo, dev, true, NULL); + if (IS_ERR(channel->req.shmem)) + return PTR_ERR(channel->req.shmem); - np = of_parse_phandle(cinfo->dev->of_node, "shmem", 0); - if (!of_device_is_compatible(np, "arm,scmi-shmem")) { - ret = -ENXIO; - goto out; - } - - ret = of_address_to_resource(np, 0, &res); - if (ret) { - dev_err(dev, "Failed to get SCMI Tx shared memory\n"); - goto out; - } - - size = resource_size(&res); - - channel->req.shmem = devm_ioremap(dev, res.start, size); - if (!channel->req.shmem) { - dev_err(dev, "Failed to ioremap SCMI Tx shared memory\n"); - ret = -EADDRNOTAVAIL; - goto out; - } - - ret = 0; - -out: - of_node_put(np); - - return ret; + return 0; } static int setup_shmem(struct device *dev, struct scmi_chan_info *cinfo, diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index b74e5a740f2c..a0d6f68172fc 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include @@ -133,3 +135,42 @@ bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem) { return ioread32(&shmem->flags) & SCMI_SHMEM_FLAG_INTR_ENABLED; } + +void __iomem *setup_shmem_iomap(struct scmi_chan_info *cinfo, + struct device *dev, bool tx, + struct resource *res) +{ + struct device_node *shmem __free(device_node); + const char *desc = tx ? "Tx" : "Rx"; + int ret, idx = tx ? 0 : 1; + struct device *cdev = cinfo->dev; + struct resource lres = {}; + resource_size_t size; + void __iomem *addr; + + shmem = of_parse_phandle(cdev->of_node, "shmem", idx); + if (!shmem) + return IOMEM_ERR_PTR(-ENODEV); + + if (!of_device_is_compatible(shmem, "arm,scmi-shmem")) + return IOMEM_ERR_PTR(-ENXIO); + + /* Use a local on-stack as a working area when not provided */ + if (!res) + res = &lres; + + ret = of_address_to_resource(shmem, 0, res); + if (ret) { + dev_err(cdev, "failed to get SCMI %s shared memory\n", desc); + return IOMEM_ERR_PTR(ret); + } + + size = resource_size(res); + addr = devm_ioremap(dev, res->start, size); + if (!addr) { + dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc); + return IOMEM_ERR_PTR(-EADDRNOTAVAIL); + } + + return addr; +} diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index 39936e1dd30e..59b6c04b52bc 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -130,9 +130,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, struct device *cdev = cinfo->dev; unsigned long cap_id = ULONG_MAX; struct scmi_smc *scmi_info; - resource_size_t size; - struct resource res; - struct device_node *np; + struct resource res = {}; u32 func_id; int ret; @@ -143,31 +141,16 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!scmi_info) return -ENOMEM; - np = of_parse_phandle(cdev->of_node, "shmem", 0); - if (!of_device_is_compatible(np, "arm,scmi-shmem")) { - of_node_put(np); - return -ENXIO; - } - - ret = of_address_to_resource(np, 0, &res); - of_node_put(np); - if (ret) { - dev_err(cdev, "failed to get SCMI Tx shared memory\n"); - return ret; - } - - size = resource_size(&res); - scmi_info->shmem = devm_ioremap(dev, res.start, size); - if (!scmi_info->shmem) { - dev_err(dev, "failed to ioremap SCMI Tx shared memory\n"); - return -EADDRNOTAVAIL; - } + scmi_info->shmem = setup_shmem_iomap(cinfo, dev, tx, &res); + if (IS_ERR(scmi_info->shmem)) + return PTR_ERR(scmi_info->shmem); ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id); if (ret < 0) return ret; if (of_device_is_compatible(dev->of_node, "qcom,scmi-smc")) { + resource_size_t size = resource_size(&res); void __iomem *ptr = (void __iomem *)scmi_info->shmem + size - 8; /* The capability-id is kept in last 8 bytes of shmem. * +-------+ <-- 0 From b6b7c77c988a1314b2a3505f9962a6bfc563a8dc Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:33:34 +0100 Subject: [PATCH 040/212] firmware: arm_scmi: Introduce packet handling helpers Introduce a pair of structures initialized to contain all the existing packet handling helpers, both for transports based on shared memory and messages. No functional change. Signed-off-by: Cristian Marussi Tested-by: Peng Fan #i.MX95 19x19 EVK Tested-by: Florian Fainelli Message-Id: <20240812173340.3912830-4-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/common.h | 78 +++++++++++++++++++++-------- drivers/firmware/arm_scmi/mailbox.c | 20 ++++---- drivers/firmware/arm_scmi/msg.c | 27 ++++++---- drivers/firmware/arm_scmi/optee.c | 14 +++--- drivers/firmware/arm_scmi/shmem.c | 45 +++++++++++------ drivers/firmware/arm_scmi/smc.c | 8 +-- drivers/firmware/arm_scmi/virtio.c | 14 +++--- 7 files changed, 131 insertions(+), 75 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 28c963358e01..d5b78681b292 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -4,7 +4,7 @@ * driver common header file containing some definitions, structures * and function prototypes used in all the different SCMI protocols. * - * Copyright (C) 2018-2022 ARM Ltd. + * Copyright (C) 2018-2024 ARM Ltd. */ #ifndef _SCMI_COMMON_H #define _SCMI_COMMON_H @@ -339,20 +339,39 @@ void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, /* shmem related declarations */ struct scmi_shared_mem; -void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, - struct scmi_xfer *xfer, struct scmi_chan_info *cinfo); -u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem); -void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, +/** + * struct scmi_shared_mem_operations - Transport core operations for + * Shared Memory + * + * @tx_prepare: Prepare the @xfer message for transmission on the chosen @shmem + * @read_header: Read header of the message currently hold in @shmem + * @fetch_response: Copy the message response from @shmem into @xfer + * @fetch_notification: Copy the message notification from @shmem into @xfer + * @clear_channel: Clear the @shmem channel busy flag + * @poll_done: Check if poll has completed for @xfer on @shmem + * @channel_free: Check if @shmem channel is marked as free + * @channel_intr_enabled: Check is @shmem channel has requested a completion irq + * @setup_iomap: Setup IO shared memory for channel @cinfo + */ +struct scmi_shared_mem_operations { + void (*tx_prepare)(struct scmi_shared_mem __iomem *shmem, + struct scmi_xfer *xfer, + struct scmi_chan_info *cinfo); + u32 (*read_header)(struct scmi_shared_mem __iomem *shmem); + + void (*fetch_response)(struct scmi_shared_mem __iomem *shmem, + struct scmi_xfer *xfer); + void (*fetch_notification)(struct scmi_shared_mem __iomem *shmem, + size_t max_len, struct scmi_xfer *xfer); + void (*clear_channel)(struct scmi_shared_mem __iomem *shmem); + bool (*poll_done)(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); -void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, - size_t max_len, struct scmi_xfer *xfer); -void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); -bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, - struct scmi_xfer *xfer); -bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem); -bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem); -void __iomem *setup_shmem_iomap(struct scmi_chan_info *cinfo, struct device *dev, - bool tx, struct resource *res); + bool (*channel_free)(struct scmi_shared_mem __iomem *shmem); + bool (*channel_intr_enabled)(struct scmi_shared_mem __iomem *shmem); + void __iomem *(*setup_iomap)(struct scmi_chan_info *cinfo, + struct device *dev, + bool tx, struct resource *res); +}; /* declarations for message passing transports */ struct scmi_msg_payld; @@ -360,14 +379,29 @@ struct scmi_msg_payld; /* Maximum overhead of message w.r.t. struct scmi_desc.max_msg_size */ #define SCMI_MSG_MAX_PROT_OVERHEAD (2 * sizeof(__le32)) -size_t msg_response_size(struct scmi_xfer *xfer); -size_t msg_command_size(struct scmi_xfer *xfer); -void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer); -u32 msg_read_header(struct scmi_msg_payld *msg); -void msg_fetch_response(struct scmi_msg_payld *msg, size_t len, - struct scmi_xfer *xfer); -void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, - size_t max_len, struct scmi_xfer *xfer); +/** + * struct scmi_message_operations - Transport core operations for Message + * + * @response_size: Get calculated response size for @xfer + * @command_size: Get calculated command size for @xfer + * @tx_prepare: Prepare the @xfer message for transmission on the provided @msg + * @read_header: Read header of the message currently hold in @msg + * @fetch_response: Copy the message response from @msg into @xfer + * @fetch_notification: Copy the message notification from @msg into @xfer + */ +struct scmi_message_operations { + size_t (*response_size)(struct scmi_xfer *xfer); + size_t (*command_size)(struct scmi_xfer *xfer); + void (*tx_prepare)(struct scmi_msg_payld *msg, struct scmi_xfer *xfer); + u32 (*read_header)(struct scmi_msg_payld *msg); + void (*fetch_response)(struct scmi_msg_payld *msg, size_t len, + struct scmi_xfer *xfer); + void (*fetch_notification)(struct scmi_msg_payld *msg, size_t len, + size_t max_len, struct scmi_xfer *xfer); +}; + +extern const struct scmi_shared_mem_operations scmi_shmem_ops; +extern const struct scmi_message_operations scmi_msg_ops; void scmi_notification_instance_data_set(const struct scmi_handle *handle, void *priv); diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 886fc4eedb4a..60698efe8442 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -40,7 +40,7 @@ static void tx_prepare(struct mbox_client *cl, void *m) { struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); - shmem_tx_prepare(smbox->shmem, m, smbox->cinfo); + scmi_shmem_ops.tx_prepare(smbox->shmem, m, smbox->cinfo); } static void rx_callback(struct mbox_client *cl, void *m) @@ -56,15 +56,15 @@ static void rx_callback(struct mbox_client *cl, void *m) * a previous timed-out reply which arrived late could be wrongly * associated with the next pending transaction. */ - if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { + if (cl->knows_txdone && !scmi_shmem_ops.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), + scmi_shmem_ops.read_header(smbox->shmem), MSG_MBOX_SPURIOUS); return; } - scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL); + scmi_rx_callback(smbox->cinfo, scmi_shmem_ops.read_header(smbox->shmem), NULL); } static bool mailbox_chan_available(struct device_node *of_node, int idx) @@ -192,7 +192,7 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!smbox) return -ENOMEM; - smbox->shmem = setup_shmem_iomap(cinfo, dev, tx, NULL); + smbox->shmem = scmi_shmem_ops.setup_iomap(cinfo, dev, tx, NULL); if (IS_ERR(smbox->shmem)) return PTR_ERR(smbox->shmem); @@ -293,7 +293,7 @@ static void mailbox_fetch_response(struct scmi_chan_info *cinfo, { struct scmi_mailbox *smbox = cinfo->transport_info; - shmem_fetch_response(smbox->shmem, xfer); + scmi_shmem_ops.fetch_response(smbox->shmem, xfer); } static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, @@ -301,7 +301,7 @@ static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, { struct scmi_mailbox *smbox = cinfo->transport_info; - shmem_fetch_notification(smbox->shmem, max_len, xfer); + scmi_shmem_ops.fetch_notification(smbox->shmem, max_len, xfer); } static void mailbox_clear_channel(struct scmi_chan_info *cinfo) @@ -310,9 +310,9 @@ static void mailbox_clear_channel(struct scmi_chan_info *cinfo) struct mbox_chan *intr_chan; int ret; - shmem_clear_channel(smbox->shmem); + scmi_shmem_ops.clear_channel(smbox->shmem); - if (!shmem_channel_intr_enabled(smbox->shmem)) + if (!scmi_shmem_ops.channel_intr_enabled(smbox->shmem)) return; if (smbox->chan_platform_receiver) @@ -335,7 +335,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) { struct scmi_mailbox *smbox = cinfo->transport_info; - return shmem_poll_done(smbox->shmem, xfer); + return scmi_shmem_ops.poll_done(smbox->shmem, xfer); } static const struct scmi_transport_ops scmi_mailbox_ops = { diff --git a/drivers/firmware/arm_scmi/msg.c b/drivers/firmware/arm_scmi/msg.c index d33a704e5814..f5f6c2c55577 100644 --- a/drivers/firmware/arm_scmi/msg.c +++ b/drivers/firmware/arm_scmi/msg.c @@ -4,7 +4,7 @@ * * Derived from shm.c. * - * Copyright (C) 2019-2021 ARM Ltd. + * Copyright (C) 2019-2024 ARM Ltd. * Copyright (C) 2020-2021 OpenSynergy GmbH */ @@ -30,7 +30,7 @@ struct scmi_msg_payld { * * Return: transport SDU size. */ -size_t msg_command_size(struct scmi_xfer *xfer) +static size_t msg_command_size(struct scmi_xfer *xfer) { return sizeof(struct scmi_msg_payld) + xfer->tx.len; } @@ -42,7 +42,7 @@ size_t msg_command_size(struct scmi_xfer *xfer) * * Return: transport SDU size. */ -size_t msg_response_size(struct scmi_xfer *xfer) +static size_t msg_response_size(struct scmi_xfer *xfer) { return sizeof(struct scmi_msg_payld) + sizeof(__le32) + xfer->rx.len; } @@ -53,7 +53,7 @@ size_t msg_response_size(struct scmi_xfer *xfer) * @msg: transport SDU for command * @xfer: message which is being sent */ -void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer) +static void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer) { msg->msg_header = cpu_to_le32(pack_scmi_header(&xfer->hdr)); if (xfer->tx.buf) @@ -67,7 +67,7 @@ void msg_tx_prepare(struct scmi_msg_payld *msg, struct scmi_xfer *xfer) * * Return: SCMI header */ -u32 msg_read_header(struct scmi_msg_payld *msg) +static u32 msg_read_header(struct scmi_msg_payld *msg) { return le32_to_cpu(msg->msg_header); } @@ -79,8 +79,8 @@ u32 msg_read_header(struct scmi_msg_payld *msg) * @len: transport SDU size * @xfer: message being responded to */ -void msg_fetch_response(struct scmi_msg_payld *msg, size_t len, - struct scmi_xfer *xfer) +static void msg_fetch_response(struct scmi_msg_payld *msg, + size_t len, struct scmi_xfer *xfer) { size_t prefix_len = sizeof(*msg) + sizeof(msg->msg_payload[0]); @@ -100,8 +100,8 @@ void msg_fetch_response(struct scmi_msg_payld *msg, size_t len, * @max_len: maximum SCMI payload size to fetch * @xfer: notification message */ -void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, - size_t max_len, struct scmi_xfer *xfer) +static void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, + size_t max_len, struct scmi_xfer *xfer) { xfer->rx.len = min_t(size_t, max_len, len >= sizeof(*msg) ? len - sizeof(*msg) : 0); @@ -109,3 +109,12 @@ void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, /* Take a copy to the rx buffer.. */ memcpy(xfer->rx.buf, msg->msg_payload, xfer->rx.len); } + +const struct scmi_message_operations scmi_msg_ops = { + .tx_prepare = msg_tx_prepare, + .command_size = msg_command_size, + .response_size = msg_response_size, + .read_header = msg_read_header, + .fetch_response = msg_fetch_response, + .fetch_notification = msg_fetch_notification, +}; diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c index ee9cda1a8211..dae68adf6f9e 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/optee.c @@ -343,7 +343,7 @@ static void scmi_optee_clear_channel(struct scmi_chan_info *cinfo) struct scmi_optee_channel *channel = cinfo->transport_info; if (!channel->tee_shm) - shmem_clear_channel(channel->req.shmem); + scmi_shmem_ops.clear_channel(channel->req.shmem); } static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *channel) @@ -368,7 +368,7 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo, struct scmi_optee_channel *channel) { - channel->req.shmem = setup_shmem_iomap(cinfo, dev, true, NULL); + channel->req.shmem = scmi_shmem_ops.setup_iomap(cinfo, dev, true, NULL); if (IS_ERR(channel->req.shmem)) return PTR_ERR(channel->req.shmem); @@ -479,10 +479,10 @@ static int scmi_optee_send_message(struct scmi_chan_info *cinfo, mutex_lock(&channel->mu); if (channel->tee_shm) { - msg_tx_prepare(channel->req.msg, xfer); - ret = invoke_process_msg_channel(channel, msg_command_size(xfer)); + scmi_msg_ops.tx_prepare(channel->req.msg, xfer); + ret = invoke_process_msg_channel(channel, scmi_msg_ops.command_size(xfer)); } else { - shmem_tx_prepare(channel->req.shmem, xfer, cinfo); + scmi_shmem_ops.tx_prepare(channel->req.shmem, xfer, cinfo); ret = invoke_process_smt_channel(channel); } @@ -498,9 +498,9 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo, struct scmi_optee_channel *channel = cinfo->transport_info; if (channel->tee_shm) - msg_fetch_response(channel->req.msg, channel->rx_len, xfer); + scmi_msg_ops.fetch_response(channel->req.msg, channel->rx_len, xfer); else - shmem_fetch_response(channel->req.shmem, xfer); + scmi_shmem_ops.fetch_response(channel->req.shmem, xfer); } static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret, diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index a0d6f68172fc..477d391968c6 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -2,7 +2,7 @@ /* * For transport using shared mem structure. * - * Copyright (C) 2019 ARM Ltd. + * Copyright (C) 2019-2024 ARM Ltd. */ #include @@ -34,8 +34,9 @@ struct scmi_shared_mem { u8 msg_payload[]; }; -void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, - struct scmi_xfer *xfer, struct scmi_chan_info *cinfo) +static void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, + struct scmi_xfer *xfer, + struct scmi_chan_info *cinfo) { ktime_t stop; @@ -75,13 +76,13 @@ void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len); } -u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) +static u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) { return ioread32(&shmem->msg_header); } -void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, - struct scmi_xfer *xfer) +static void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, + struct scmi_xfer *xfer) { size_t len = ioread32(&shmem->length); @@ -93,8 +94,8 @@ void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); } -void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, - size_t max_len, struct scmi_xfer *xfer) +static void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, + size_t max_len, struct scmi_xfer *xfer) { size_t len = ioread32(&shmem->length); @@ -105,13 +106,13 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len); } -void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem) +static void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem) { iowrite32(SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE, &shmem->channel_status); } -bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, - struct scmi_xfer *xfer) +static bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, + struct scmi_xfer *xfer) { u16 xfer_id; @@ -125,20 +126,20 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); } -bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) +static bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) { return (ioread32(&shmem->channel_status) & SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); } -bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem) +static bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem) { return ioread32(&shmem->flags) & SCMI_SHMEM_FLAG_INTR_ENABLED; } -void __iomem *setup_shmem_iomap(struct scmi_chan_info *cinfo, - struct device *dev, bool tx, - struct resource *res) +static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo, + struct device *dev, bool tx, + struct resource *res) { struct device_node *shmem __free(device_node); const char *desc = tx ? "Tx" : "Rx"; @@ -174,3 +175,15 @@ void __iomem *setup_shmem_iomap(struct scmi_chan_info *cinfo, return addr; } + +const struct scmi_shared_mem_operations scmi_shmem_ops = { + .tx_prepare = shmem_tx_prepare, + .read_header = shmem_read_header, + .fetch_response = shmem_fetch_response, + .fetch_notification = shmem_fetch_notification, + .clear_channel = shmem_clear_channel, + .poll_done = shmem_poll_done, + .channel_free = shmem_channel_free, + .channel_intr_enabled = shmem_channel_intr_enabled, + .setup_iomap = shmem_setup_iomap, +}; diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index 59b6c04b52bc..4cb86386c490 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -74,7 +74,7 @@ static irqreturn_t smc_msg_done_isr(int irq, void *data) struct scmi_smc *scmi_info = data; scmi_rx_callback(scmi_info->cinfo, - shmem_read_header(scmi_info->shmem), NULL); + scmi_shmem_ops.read_header(scmi_info->shmem), NULL); return IRQ_HANDLED; } @@ -141,7 +141,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!scmi_info) return -ENOMEM; - scmi_info->shmem = setup_shmem_iomap(cinfo, dev, tx, &res); + scmi_info->shmem = scmi_shmem_ops.setup_iomap(cinfo, dev, tx, &res); if (IS_ERR(scmi_info->shmem)) return PTR_ERR(scmi_info->shmem); @@ -226,7 +226,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo, */ smc_channel_lock_acquire(scmi_info, xfer); - shmem_tx_prepare(scmi_info->shmem, xfer, cinfo); + scmi_shmem_ops.tx_prepare(scmi_info->shmem, xfer, cinfo); if (scmi_info->cap_id != ULONG_MAX) arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0, @@ -250,7 +250,7 @@ static void smc_fetch_response(struct scmi_chan_info *cinfo, { struct scmi_smc *scmi_info = cinfo->transport_info; - shmem_fetch_response(scmi_info->shmem, xfer); + scmi_shmem_ops.fetch_response(scmi_info->shmem, xfer); } static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret, diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi/virtio.c index dd3459bdb9cb..e8d38e822c7e 100644 --- a/drivers/firmware/arm_scmi/virtio.c +++ b/drivers/firmware/arm_scmi/virtio.c @@ -295,7 +295,7 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue) if (msg) { msg->rx_len = length; scmi_rx_callback(vioch->cinfo, - msg_read_header(msg->input), msg); + scmi_msg_ops.read_header(msg->input), msg); scmi_finalize_message(vioch, msg); } @@ -340,7 +340,7 @@ static void scmi_vio_deferred_tx_worker(struct work_struct *work) */ if (msg->poll_status == VIO_MSG_NOT_POLLED) scmi_rx_callback(vioch->cinfo, - msg_read_header(msg->input), msg); + scmi_msg_ops.read_header(msg->input), msg); /* Free the processed message once done */ scmi_vio_msg_release(vioch, msg); @@ -510,10 +510,10 @@ static int virtio_send_message(struct scmi_chan_info *cinfo, return -EBUSY; } - msg_tx_prepare(msg->request, xfer); + scmi_msg_ops.tx_prepare(msg->request, xfer); - sg_init_one(&sg_out, msg->request, msg_command_size(xfer)); - sg_init_one(&sg_in, msg->input, msg_response_size(xfer)); + sg_init_one(&sg_out, msg->request, scmi_msg_ops.command_size(xfer)); + sg_init_one(&sg_in, msg->input, scmi_msg_ops.response_size(xfer)); spin_lock_irqsave(&vioch->lock, flags); @@ -560,7 +560,7 @@ static void virtio_fetch_response(struct scmi_chan_info *cinfo, struct scmi_vio_msg *msg = xfer->priv; if (msg) - msg_fetch_response(msg->input, msg->rx_len, xfer); + scmi_msg_ops.fetch_response(msg->input, msg->rx_len, xfer); } static void virtio_fetch_notification(struct scmi_chan_info *cinfo, @@ -569,7 +569,7 @@ static void virtio_fetch_notification(struct scmi_chan_info *cinfo, struct scmi_vio_msg *msg = xfer->priv; if (msg) - msg_fetch_notification(msg->input, msg->rx_len, max_len, xfer); + scmi_msg_ops.fetch_notification(msg->input, msg->rx_len, max_len, xfer); } /** From 8b76a8c95930a36389e2301b306747ff6f06cb16 Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:33:35 +0100 Subject: [PATCH 041/212] firmware: arm_scmi: Add support for standalone transport drivers Extend the core SCMI stack with structures and methods to allow for transports to be split out as standalone drivers, while still supporting old style transports, defined as built into the SCMI core stack. No functional change. Signed-off-by: Cristian Marussi Tested-by: Peng Fan #i.MX95 19x19 EVK Tested-by: Florian Fainelli Message-Id: <20240812173340.3912830-5-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/common.h | 84 ++++++++++++++++++++++++++++++ drivers/firmware/arm_scmi/driver.c | 44 +++++++++++++++- drivers/firmware/arm_scmi/msg.c | 5 ++ drivers/firmware/arm_scmi/shmem.c | 5 ++ 4 files changed, 136 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index d5b78681b292..90404ac0629f 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -373,6 +373,8 @@ struct scmi_shared_mem_operations { bool tx, struct resource *res); }; +const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void); + /* declarations for message passing transports */ struct scmi_msg_payld; @@ -400,6 +402,88 @@ struct scmi_message_operations { size_t max_len, struct scmi_xfer *xfer); }; +const struct scmi_message_operations *scmi_message_operations_get(void); + +/** + * struct scmi_transport_core_operations - Transpoert core operations + * + * @bad_message_trace: An helper to report a malformed/unexpected message + * @rx_callback: Callback to report received messages + * @shmem: Datagram operations for shared memory based transports + * @msg: Datagram operations for message based transports + */ +struct scmi_transport_core_operations { + void (*bad_message_trace)(struct scmi_chan_info *cinfo, + u32 msg_hdr, enum scmi_bad_msg err); + void (*rx_callback)(struct scmi_chan_info *cinfo, u32 msg_hdr, + void *priv); + const struct scmi_shared_mem_operations *shmem; + const struct scmi_message_operations *msg; +}; + +/** + * struct scmi_transport - A structure representing a configured transport + * + * @supplier: Device representing the transport and acting as a supplier for + * the core SCMI stack + * @desc: Transport descriptor + * @core_ops: A pointer to a pointer used by the core SCMI stack to make the + * core transport operations accessible to the transports. + */ +struct scmi_transport { + struct device *supplier; + const struct scmi_desc *desc; + struct scmi_transport_core_operations **core_ops; +}; + +#define DEFINE_SCMI_TRANSPORT_DRIVER(__tag, __drv, __desc, __match, __core_ops)\ +static void __tag##_dev_free(void *data) \ +{ \ + struct platform_device *spdev = data; \ + \ + platform_device_unregister(spdev); \ +} \ + \ +static int __tag##_probe(struct platform_device *pdev) \ +{ \ + struct device *dev = &pdev->dev; \ + struct platform_device *spdev; \ + struct scmi_transport strans; \ + int ret; \ + \ + spdev = platform_device_alloc("arm-scmi", PLATFORM_DEVID_AUTO); \ + if (!spdev) \ + return -ENOMEM; \ + \ + device_set_of_node_from_dev(&spdev->dev, dev); \ + \ + strans.supplier = dev; \ + strans.desc = &(__desc); \ + strans.core_ops = &(__core_ops); \ + \ + ret = platform_device_add_data(spdev, &strans, sizeof(strans)); \ + if (ret) \ + goto err; \ + \ + ret = platform_device_add(spdev); \ + if (ret) \ + goto err; \ + \ + return devm_add_action_or_reset(dev, __tag##_dev_free, spdev); \ + \ +err: \ + platform_device_put(spdev); \ + return ret; \ +} \ + \ +static struct platform_driver __drv = { \ + .driver = { \ + .name = #__tag "_transport", \ + .of_match_table = __match, \ + }, \ + .probe = __tag##_probe, \ +} + extern const struct scmi_shared_mem_operations scmi_shmem_ops; extern const struct scmi_message_operations scmi_msg_ops; diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index ca910079d718..708efe6f9be6 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -196,6 +196,11 @@ struct scmi_info { #define bus_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, bus_nb) #define req_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, dev_req_nb) +static struct scmi_transport_core_operations scmi_trans_core_ops = { + .bad_message_trace = scmi_bad_message_trace, + .rx_callback = scmi_rx_callback, +}; + static unsigned long scmi_vendor_protocol_signature(unsigned int protocol_id, char *vendor_id, char *sub_vendor_id, u32 impl_ver) @@ -3017,6 +3022,28 @@ static int scmi_debugfs_raw_mode_setup(struct scmi_info *info) return ret; } +static const struct scmi_desc *scmi_transport_setup(struct device *dev) +{ + struct scmi_transport *trans; + + trans = dev_get_platdata(dev); + if (!trans || !trans->desc || !trans->supplier || !trans->core_ops) + return NULL; + + if (!device_link_add(dev, trans->supplier, DL_FLAG_AUTOREMOVE_CONSUMER)) { + dev_err(dev, + "Adding link to supplier transport device failed\n"); + return NULL; + } + + /* Provide core transport ops */ + *trans->core_ops = &scmi_trans_core_ops; + + dev_info(dev, "Using %s\n", dev_driver_string(trans->supplier)); + + return trans->desc; +} + static int scmi_probe(struct platform_device *pdev) { int ret; @@ -3029,8 +3056,14 @@ static int scmi_probe(struct platform_device *pdev) struct device_node *child, *np = dev->of_node; desc = of_device_get_match_data(dev); - if (!desc) - return -EINVAL; + if (!desc) { + desc = scmi_transport_setup(dev); + if (!desc) { + err_str = "transport invalid\n"; + ret = -EINVAL; + goto out_err; + } + } info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -3197,6 +3230,7 @@ static int scmi_probe(struct platform_device *pdev) clear_ida: ida_free(&scmi_id, info->id); +out_err: return dev_err_probe(dev, ret, "%s", err_str); } @@ -3388,6 +3422,12 @@ static int __init scmi_driver_init(void) if (ret) return ret; + if (IS_ENABLED(CONFIG_ARM_SCMI_HAVE_SHMEM)) + scmi_trans_core_ops.shmem = scmi_shared_mem_operations_get(); + + if (IS_ENABLED(CONFIG_ARM_SCMI_HAVE_MSG)) + scmi_trans_core_ops.msg = scmi_message_operations_get(); + if (IS_ENABLED(CONFIG_ARM_SCMI_NEED_DEBUGFS)) scmi_top_dentry = scmi_debugfs_init(); diff --git a/drivers/firmware/arm_scmi/msg.c b/drivers/firmware/arm_scmi/msg.c index f5f6c2c55577..18337f9191d0 100644 --- a/drivers/firmware/arm_scmi/msg.c +++ b/drivers/firmware/arm_scmi/msg.c @@ -118,3 +118,8 @@ const struct scmi_message_operations scmi_msg_ops = { .fetch_response = msg_fetch_response, .fetch_notification = msg_fetch_notification, }; + +const struct scmi_message_operations *scmi_message_operations_get(void) +{ + return &scmi_msg_ops; +} diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index 477d391968c6..3fba05e1560c 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -187,3 +187,8 @@ const struct scmi_shared_mem_operations scmi_shmem_ops = { .channel_intr_enabled = shmem_channel_intr_enabled, .setup_iomap = shmem_setup_iomap, }; + +const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void) +{ + return &scmi_shmem_ops; +} From b53515fa177ca7cf0793f573d5885bcb25a62b1b Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:33:36 +0100 Subject: [PATCH 042/212] firmware: arm_scmi: Make MBOX transport a standalone driver Make SCMI mailbox transport a standalone driver that can be optionally loaded as a module; while at it, create a dedicated subdirectory and submenu for SCMI Transports. Signed-off-by: Cristian Marussi Message-Id: <20240812173340.3912830-6-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Kconfig | 31 +----------- drivers/firmware/arm_scmi/Makefile | 3 +- drivers/firmware/arm_scmi/common.h | 3 -- drivers/firmware/arm_scmi/driver.c | 3 -- drivers/firmware/arm_scmi/transports/Kconfig | 37 ++++++++++++++ drivers/firmware/arm_scmi/transports/Makefile | 4 ++ .../arm_scmi/{ => transports}/mailbox.c | 48 +++++++++++++------ 7 files changed, 77 insertions(+), 52 deletions(-) create mode 100644 drivers/firmware/arm_scmi/transports/Kconfig create mode 100644 drivers/firmware/arm_scmi/transports/Makefile rename drivers/firmware/arm_scmi/{ => transports}/mailbox.c (87%) diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index f35784d0a8dd..e9a7c9aaa956 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -69,36 +69,7 @@ config ARM_SCMI_DEBUG_COUNTERS such useful debug counters. This can be helpful for debugging and SCMI monitoring. -config ARM_SCMI_HAVE_TRANSPORT - bool - help - This declares whether at least one SCMI transport has been configured. - Used to trigger a build bug when trying to build SCMI without any - configured transport. - -config ARM_SCMI_HAVE_SHMEM - bool - help - This declares whether a shared memory based transport for SCMI is - available. - -config ARM_SCMI_HAVE_MSG - bool - help - This declares whether a message passing based transport for SCMI is - available. - -config ARM_SCMI_TRANSPORT_MAILBOX - bool "SCMI transport based on Mailbox" - depends on MAILBOX - select ARM_SCMI_HAVE_TRANSPORT - select ARM_SCMI_HAVE_SHMEM - default y - help - Enable mailbox based transport for SCMI. - - If you want the ARM SCMI PROTOCOL stack to include support for a - transport based on mailboxes, answer Y. +source "drivers/firmware/arm_scmi/transports/Kconfig" config ARM_SCMI_TRANSPORT_OPTEE bool "SCMI transport based on OP-TEE service" diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index fd59f58ce8a2..beaa55c146b8 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -5,7 +5,6 @@ scmi-core-objs := $(scmi-bus-y) scmi-driver-y = driver.o notify.o scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o -scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o 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 @@ -14,6 +13,8 @@ scmi-protocols-y := base.o clock.o perf.o power.o reset.o sensors.o system.o vol scmi-protocols-y += pinctrl.o scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y) +obj-$(CONFIG_ARM_SCMI_PROTOCOL) += transports/ + obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 90404ac0629f..2bca62a8ecde 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -286,9 +286,6 @@ int scmi_xfer_raw_inflight_register(const struct scmi_handle *handle, int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer, unsigned int timeout_ms); -#ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX -extern const struct scmi_desc scmi_mailbox_desc; -#endif #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC extern const struct scmi_desc scmi_smc_desc; #endif diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 708efe6f9be6..c13bef8a1796 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -3318,9 +3318,6 @@ ATTRIBUTE_GROUPS(versions); /* Each compatible listed below must have descriptor associated with it */ static const struct of_device_id scmi_of_match[] = { -#ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX - { .compatible = "arm,scmi", .data = &scmi_mailbox_desc }, -#endif #ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE { .compatible = "linaro,scmi-optee", .data = &scmi_optee_desc }, #endif diff --git a/drivers/firmware/arm_scmi/transports/Kconfig b/drivers/firmware/arm_scmi/transports/Kconfig new file mode 100644 index 000000000000..96c0d76b3042 --- /dev/null +++ b/drivers/firmware/arm_scmi/transports/Kconfig @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-only +menu "SCMI Transport Drivers" + +config ARM_SCMI_HAVE_TRANSPORT + bool + help + This declares whether at least one SCMI transport has been configured. + Used to trigger a build bug when trying to build SCMI without any + configured transport. + +config ARM_SCMI_HAVE_SHMEM + bool + help + This declares whether a shared memory based transport for SCMI is + available. + +config ARM_SCMI_HAVE_MSG + bool + help + This declares whether a message passing based transport for SCMI is + available. + +config ARM_SCMI_TRANSPORT_MAILBOX + tristate "SCMI transport based on Mailbox" + depends on MAILBOX + select ARM_SCMI_HAVE_TRANSPORT + select ARM_SCMI_HAVE_SHMEM + default y + help + Enable mailbox based transport for SCMI. + + If you want the ARM SCMI PROTOCOL stack to include support for a + transport based on mailboxes, answer Y. + This driver can also be built as a module. If so, the module + will be called scmi_transport_mailbox. + +endmenu diff --git a/drivers/firmware/arm_scmi/transports/Makefile b/drivers/firmware/arm_scmi/transports/Makefile new file mode 100644 index 000000000000..cb40be8955be --- /dev/null +++ b/drivers/firmware/arm_scmi/transports/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +scmi_transport_mailbox-objs := mailbox.o +obj-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += scmi_transport_mailbox.o + diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/transports/mailbox.c similarity index 87% rename from drivers/firmware/arm_scmi/mailbox.c rename to drivers/firmware/arm_scmi/transports/mailbox.c index 60698efe8442..917f9b8918d6 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/transports/mailbox.c @@ -3,7 +3,7 @@ * System Control and Management Interface (SCMI) Message Mailbox Transport * driver. * - * Copyright (C) 2019 ARM Ltd. + * Copyright (C) 2019-2024 ARM Ltd. */ #include @@ -11,9 +11,10 @@ #include #include #include +#include #include -#include "common.h" +#include "../common.h" /** * struct scmi_mailbox - Structure representing a SCMI mailbox transport @@ -36,11 +37,13 @@ struct scmi_mailbox { #define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl) +static struct scmi_transport_core_operations *core; + static void tx_prepare(struct mbox_client *cl, void *m) { struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); - scmi_shmem_ops.tx_prepare(smbox->shmem, m, smbox->cinfo); + core->shmem->tx_prepare(smbox->shmem, m, smbox->cinfo); } static void rx_callback(struct mbox_client *cl, void *m) @@ -56,15 +59,17 @@ static void rx_callback(struct mbox_client *cl, void *m) * a previous timed-out reply which arrived late could be wrongly * associated with the next pending transaction. */ - if (cl->knows_txdone && !scmi_shmem_ops.channel_free(smbox->shmem)) { + if (cl->knows_txdone && + !core->shmem->channel_free(smbox->shmem)) { dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); - scmi_bad_message_trace(smbox->cinfo, - scmi_shmem_ops.read_header(smbox->shmem), - MSG_MBOX_SPURIOUS); + core->bad_message_trace(smbox->cinfo, + core->shmem->read_header(smbox->shmem), + MSG_MBOX_SPURIOUS); return; } - scmi_rx_callback(smbox->cinfo, scmi_shmem_ops.read_header(smbox->shmem), NULL); + core->rx_callback(smbox->cinfo, + core->shmem->read_header(smbox->shmem), NULL); } static bool mailbox_chan_available(struct device_node *of_node, int idx) @@ -192,7 +197,7 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!smbox) return -ENOMEM; - smbox->shmem = scmi_shmem_ops.setup_iomap(cinfo, dev, tx, NULL); + smbox->shmem = core->shmem->setup_iomap(cinfo, dev, tx, NULL); if (IS_ERR(smbox->shmem)) return PTR_ERR(smbox->shmem); @@ -293,7 +298,7 @@ static void mailbox_fetch_response(struct scmi_chan_info *cinfo, { struct scmi_mailbox *smbox = cinfo->transport_info; - scmi_shmem_ops.fetch_response(smbox->shmem, xfer); + core->shmem->fetch_response(smbox->shmem, xfer); } static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, @@ -301,7 +306,7 @@ static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, { struct scmi_mailbox *smbox = cinfo->transport_info; - scmi_shmem_ops.fetch_notification(smbox->shmem, max_len, xfer); + core->shmem->fetch_notification(smbox->shmem, max_len, xfer); } static void mailbox_clear_channel(struct scmi_chan_info *cinfo) @@ -310,9 +315,9 @@ static void mailbox_clear_channel(struct scmi_chan_info *cinfo) struct mbox_chan *intr_chan; int ret; - scmi_shmem_ops.clear_channel(smbox->shmem); + core->shmem->clear_channel(smbox->shmem); - if (!scmi_shmem_ops.channel_intr_enabled(smbox->shmem)) + if (!core->shmem->channel_intr_enabled(smbox->shmem)) return; if (smbox->chan_platform_receiver) @@ -335,7 +340,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) { struct scmi_mailbox *smbox = cinfo->transport_info; - return scmi_shmem_ops.poll_done(smbox->shmem, xfer); + return core->shmem->poll_done(smbox->shmem, xfer); } static const struct scmi_transport_ops scmi_mailbox_ops = { @@ -350,9 +355,22 @@ static const struct scmi_transport_ops scmi_mailbox_ops = { .poll_done = mailbox_poll_done, }; -const struct scmi_desc scmi_mailbox_desc = { +static const struct scmi_desc scmi_mailbox_desc = { .ops = &scmi_mailbox_ops, .max_rx_timeout_ms = 30, /* We may increase this if required */ .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ .max_msg_size = 128, }; + +static const struct of_device_id scmi_of_match[] = { + { .compatible = "arm,scmi" }, + { /* Sentinel */ }, +}; + +DEFINE_SCMI_TRANSPORT_DRIVER(scmi_mailbox, scmi_mailbox_driver, + scmi_mailbox_desc, scmi_of_match, core); +module_platform_driver(scmi_mailbox_driver); + +MODULE_AUTHOR("Sudeep Holla "); +MODULE_DESCRIPTION("SCMI Mailbox Transport driver"); +MODULE_LICENSE("GPL"); From 70c2cf283c2ff475e3a07d62ead91a11b18376b1 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 28 Jul 2024 13:41:45 +0200 Subject: [PATCH 043/212] firmware: raspberrypi: Improve timeout warning Recent work on raspberry-power driver showed that even the stacktrace on firmware property timeout doesn't provide enough information. So add the first tag name to the warning to be in line with a status error. Signed-off-by: Stefan Wahren Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20240728114200.75559-2-wahrenst@gmx.net Signed-off-by: Florian Fainelli --- drivers/firmware/raspberrypi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index ac34876a97f8..18cc34987108 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -62,7 +62,6 @@ rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data) ret = 0; } else { ret = -ETIMEDOUT; - WARN_ONCE(1, "Firmware transaction timeout"); } } else { dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret); @@ -125,6 +124,8 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, dev_err(fw->cl.dev, "Request 0x%08x returned status 0x%08x\n", buf[2], buf[1]); ret = -EINVAL; + } else if (ret == -ETIMEDOUT) { + WARN_ONCE(1, "Firmware transaction 0x%08x timeout", buf[2]); } dma_free_coherent(fw->chan->mbox->dev, PAGE_ALIGN(size), buf, bus_addr); From 67dd9e861add38755a7c5d29e25dd0f6cb4116ab Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 12 Aug 2024 14:30:55 +0200 Subject: [PATCH 044/212] memory: tegra186-emc: drop unused to_tegra186_emc() to_tegra186_emc() is not used, W=1 builds: tegra186-emc.c:38:36: error: unused function 'to_tegra186_emc' [-Werror,-Wunused-function] Fixes: 9a38cb27668e ("memory: tegra: Add interconnect support for DRAM scaling in Tegra234") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240812123055.124123-1-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra186-emc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c index 57d9ae12fcfe..33d67d251719 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -35,11 +35,6 @@ struct tegra186_emc { struct icc_provider provider; }; -static inline struct tegra186_emc *to_tegra186_emc(struct icc_provider *provider) -{ - return container_of(provider, struct tegra186_emc, provider); -} - /* * debugfs interface * From 79cb2cb8d89b7eca87e8dac031dadea4aeafeaa7 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 8 Jul 2024 21:23:32 +0530 Subject: [PATCH 045/212] firmware: qcom: scm: Disable SDI and write no dump to dump mode SDI is enabled for most of the Qualcomm SoCs and as per commit ff4aa3bc9825 ("firmware: qcom_scm: disable SDI if required") it was recommended to disable SDI by mentioning it in device tree to avoid hang during watchdog or during reboot. However, for some cases if download mode tcsr register already configured from boot firmware to collect dumps and if SDI is disabled via means of mentioning it in device tree we could still end up with dump collection. Disabling SDI alone is not completely enough to disable dump mode and we also need to zero out the bits download bits from tcsr register. Current commit now, unconditionally call qcom_scm_set_download_mode() based on download_mode flag, at max if TCSR register is not mentioned or available for a SoC it will fallback to legacy way of setting download mode through command which may be no-ops or return error in case current firmware does not implements QCOM_SCM_INFO_IS_CALL_AVAIL so, at worst it does nothing if it fails. It also does to call SDI disable call if dload mode is disabled, which looks fine to do as intention is to disable dump collection even if system crashes. Fixes: ff4aa3bc9825 ("firmware: qcom_scm: disable SDI if required") Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20240708155332.4056479-1-quic_mojha@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index e60bef68401c..b1f3258835b1 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -1955,14 +1955,12 @@ static int qcom_scm_probe(struct platform_device *pdev) * will cause the boot stages to enter download mode, unless * disabled below by a clean shutdown/reboot. */ - if (download_mode) - qcom_scm_set_download_mode(true); - + qcom_scm_set_download_mode(download_mode); /* * Disable SDI if indicated by DT that it is enabled by default. */ - if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled")) + if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled") || !download_mode) qcom_scm_disable_sdi(); ret = of_reserved_mem_device_init(__scm->dev); From bd6db1f1486eedb8460647b3fbe9b5ae8fd09207 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 8 Jul 2024 18:22:09 +0200 Subject: [PATCH 046/212] soc: qcom: pd_mapper: Add X1E80100 X1E80100 has the same protection domains as SM8550, except that MPSS is missing. Add it to the in-kernel pd-mapper to avoid having to run the daemon in userspace for charging and audio functionality. Signed-off-by: Stephan Gerhold Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240708-x1e80100-pd-mapper-v1-1-854386af4cf5@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_pd_mapper.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c index 9afa09c3920e..d3d853ceb6e8 100644 --- a/drivers/soc/qcom/qcom_pd_mapper.c +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -517,6 +517,15 @@ static const struct qcom_pdm_domain_data *sm8550_domains[] = { NULL, }; +static const struct qcom_pdm_domain_data *x1e80100_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_charger_pd, + &adsp_sensor_pd, + &cdsp_root_pd, + NULL, +}; + static const struct of_device_id qcom_pdm_domains[] __maybe_unused = { { .compatible = "qcom,apq8064", .data = NULL, }, { .compatible = "qcom,apq8074", .data = NULL, }, @@ -545,6 +554,7 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = { { .compatible = "qcom,sm8450", .data = sm8350_domains, }, { .compatible = "qcom,sm8550", .data = sm8550_domains, }, { .compatible = "qcom,sm8650", .data = sm8550_domains, }, + { .compatible = "qcom,x1e80100", .data = x1e80100_domains, }, {}, }; From ed2c37520893427dfb8b615fcc6263af796a0ab1 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 8 Jul 2024 18:22:10 +0200 Subject: [PATCH 047/212] soc: qcom: pd_mapper: Add more older platforms without domains MSM8909, MSM8916 and MSM8939 all do not make use of pd-mapper, add them to the list similar to the other older platforms to avoid the following message in dmesg when booting: "PDM: no support for the platform, userspace daemon might be required." Signed-off-by: Stephan Gerhold Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240708-x1e80100-pd-mapper-v1-2-854386af4cf5@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_pd_mapper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c index d3d853ceb6e8..63db04f2bf67 100644 --- a/drivers/soc/qcom/qcom_pd_mapper.c +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -527,11 +527,15 @@ static const struct qcom_pdm_domain_data *x1e80100_domains[] = { }; static const struct of_device_id qcom_pdm_domains[] __maybe_unused = { + { .compatible = "qcom,apq8016", .data = NULL, }, { .compatible = "qcom,apq8064", .data = NULL, }, { .compatible = "qcom,apq8074", .data = NULL, }, { .compatible = "qcom,apq8084", .data = NULL, }, { .compatible = "qcom,apq8096", .data = msm8996_domains, }, { .compatible = "qcom,msm8226", .data = NULL, }, + { .compatible = "qcom,msm8909", .data = NULL, }, + { .compatible = "qcom,msm8916", .data = NULL, }, + { .compatible = "qcom,msm8939", .data = NULL, }, { .compatible = "qcom,msm8974", .data = NULL, }, { .compatible = "qcom,msm8996", .data = msm8996_domains, }, { .compatible = "qcom,msm8998", .data = msm8998_domains, }, From c802b0a2ed0f67fcec8cc0cac685c8fd0dd0aa6f Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 15 Jul 2024 21:26:54 +0530 Subject: [PATCH 048/212] firmware: qcom: scm: Refactor code to support multiple dload mode Currently on Qualcomm SoC, download_mode is enabled if CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is selected or passed a boolean value from command line. Refactor the code such that it supports multiple download modes and drop CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT config instead, give interface to set the download mode from module parameter while being backword compatible at the same time. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20240715155655.1811178-1-quic_mojha@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/Kconfig | 11 ------ drivers/firmware/qcom/qcom_scm.c | 60 +++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index 73a1a41bf92d..b477d54b495a 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -41,17 +41,6 @@ config QCOM_TZMEM_MODE_SHMBRIDGE endchoice -config QCOM_SCM_DOWNLOAD_MODE_DEFAULT - bool "Qualcomm download mode enabled by default" - depends on QCOM_SCM - help - A device with "download mode" enabled will upon an unexpected - warm-restart enter a special debug mode that allows the user to - "download" memory content over USB for offline postmortem analysis. - The feature can be enabled/disabled on the kernel command line. - - Say Y here to enable "download mode" by default. - config QCOM_QSEECOM bool "Qualcomm QSEECOM interface driver" depends on QCOM_SCM=y diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index b1f3258835b1..ca75d1c7006f 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -32,8 +33,7 @@ #include "qcom_scm.h" #include "qcom_tzmem.h" -static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT); -module_param(download_mode, bool, 0); +static u32 download_mode; struct qcom_scm { struct device *dev; @@ -134,6 +134,11 @@ static const char * const qcom_scm_convention_names[] = { [SMC_CONVENTION_LEGACY] = "smc legacy", }; +static const char * const download_mode_name[] = { + [QCOM_DLOAD_NODUMP] = "off", + [QCOM_DLOAD_FULLDUMP] = "full", +}; + static struct qcom_scm *__scm; static int qcom_scm_clk_enable(void) @@ -526,17 +531,16 @@ static int qcom_scm_io_rmw(phys_addr_t addr, unsigned int mask, unsigned int val return qcom_scm_io_writel(addr, new); } -static void qcom_scm_set_download_mode(bool enable) +static void qcom_scm_set_download_mode(u32 dload_mode) { - u32 val = enable ? QCOM_DLOAD_FULLDUMP : QCOM_DLOAD_NODUMP; int ret = 0; if (__scm->dload_mode_addr) { ret = qcom_scm_io_rmw(__scm->dload_mode_addr, QCOM_DLOAD_MASK, - FIELD_PREP(QCOM_DLOAD_MASK, val)); + FIELD_PREP(QCOM_DLOAD_MASK, dload_mode)); } else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE)) { - ret = __qcom_scm_set_dload_mode(__scm->dev, enable); + ret = __qcom_scm_set_dload_mode(__scm->dev, !!dload_mode); } else { dev_err(__scm->dev, "No available mechanism for setting download mode\n"); @@ -1887,6 +1891,46 @@ static irqreturn_t qcom_scm_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static int get_download_mode(char *buffer, const struct kernel_param *kp) +{ + if (download_mode >= ARRAY_SIZE(download_mode_name)) + return sysfs_emit(buffer, "unknown mode\n"); + + return sysfs_emit(buffer, "%s\n", download_mode_name[download_mode]); +} + +static int set_download_mode(const char *val, const struct kernel_param *kp) +{ + bool tmp; + int ret; + + ret = sysfs_match_string(download_mode_name, val); + if (ret < 0) { + ret = kstrtobool(val, &tmp); + if (ret < 0) { + pr_err("qcom_scm: err: %d\n", ret); + return ret; + } + + ret = tmp ? 1 : 0; + } + + download_mode = ret; + if (__scm) + qcom_scm_set_download_mode(download_mode); + + return 0; +} + +static const struct kernel_param_ops download_mode_param_ops = { + .get = get_download_mode, + .set = set_download_mode, +}; + +module_param_cb(download_mode, &download_mode_param_ops, NULL, 0644); +MODULE_PARM_DESC(download_mode, + "download mode: off/0/N for no dump mode, full/on/1/Y for full dump mode"); + static int qcom_scm_probe(struct platform_device *pdev) { struct qcom_tzmem_pool_config pool_config; @@ -1951,7 +1995,7 @@ static int qcom_scm_probe(struct platform_device *pdev) __get_convention(); /* - * If requested enable "download mode", from this point on warmboot + * If "download mode" is requested, from this point on warmboot * will cause the boot stages to enter download mode, unless * disabled below by a clean shutdown/reboot. */ @@ -2002,7 +2046,7 @@ static int qcom_scm_probe(struct platform_device *pdev) static void qcom_scm_shutdown(struct platform_device *pdev) { /* Clean shutdown, disable download mode to allow normal restart */ - qcom_scm_set_download_mode(false); + qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP); } static const struct of_device_id qcom_scm_dt_match[] = { From d4d4049e411b246cdfc2df60d8d5a4474019c689 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Mon, 15 Jul 2024 21:26:55 +0530 Subject: [PATCH 049/212] firmware: qcom: scm: Add multiple download mode support Currently, scm driver only supports full dump when download mode is selected. Add support to enable minidump as well as enable it along with fulldump. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/20240715155655.1811178-2-quic_mojha@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index ca75d1c7006f..bdb5e98b82ef 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -126,6 +126,8 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = { #define QCOM_DLOAD_MASK GENMASK(5, 4) #define QCOM_DLOAD_NODUMP 0 #define QCOM_DLOAD_FULLDUMP 1 +#define QCOM_DLOAD_MINIDUMP 2 +#define QCOM_DLOAD_BOTHDUMP 3 static const char * const qcom_scm_convention_names[] = { [SMC_CONVENTION_UNKNOWN] = "unknown", @@ -137,6 +139,8 @@ static const char * const qcom_scm_convention_names[] = { static const char * const download_mode_name[] = { [QCOM_DLOAD_NODUMP] = "off", [QCOM_DLOAD_FULLDUMP] = "full", + [QCOM_DLOAD_MINIDUMP] = "mini", + [QCOM_DLOAD_BOTHDUMP] = "full,mini", }; static struct qcom_scm *__scm; @@ -1928,8 +1932,7 @@ static const struct kernel_param_ops download_mode_param_ops = { }; module_param_cb(download_mode, &download_mode_param_ops, NULL, 0644); -MODULE_PARM_DESC(download_mode, - "download mode: off/0/N for no dump mode, full/on/1/Y for full dump mode"); +MODULE_PARM_DESC(download_mode, "download mode: off/0/N for no dump mode, full/on/1/Y for full dump mode, mini for minidump mode and full,mini for both full and minidump mode together are acceptable values"); static int qcom_scm_probe(struct platform_device *pdev) { From b17155133391d7f6dd18d3fb94a7d492fdec18fa Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 29 Jul 2024 22:52:14 +0300 Subject: [PATCH 050/212] Revert "soc: qcom: smd-rpm: Match rpmsg channel instead of compatible" The rpm_requests device nodes have the compatible node. As such the rpmsg core uses OF modalias instead of a native rpmsg modalias. Thus if smd-rpm is built as a module, it doesn't get autoloaded for the device. Revert the commit bcabe1e09135 ("soc: qcom: smd-rpm: Match rpmsg channel instead of compatible") Fixes: bcabe1e09135 ("soc: qcom: smd-rpm: Match rpmsg channel instead of compatible") Cc: stable@vger.kernel.org Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240729-fix-smd-rpm-v2-1-0776408a94c5@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smd-rpm.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index b7056aed4c7d..9d64283d2125 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -196,9 +196,6 @@ static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev) { struct qcom_smd_rpm *rpm; - if (!rpdev->dev.of_node) - return -EINVAL; - rpm = devm_kzalloc(&rpdev->dev, sizeof(*rpm), GFP_KERNEL); if (!rpm) return -ENOMEM; @@ -218,18 +215,38 @@ static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev) of_platform_depopulate(&rpdev->dev); } -static const struct rpmsg_device_id qcom_smd_rpm_id_table[] = { - { .name = "rpm_requests", }, - { /* sentinel */ } +static const struct of_device_id qcom_smd_rpm_of_match[] = { + { .compatible = "qcom,rpm-apq8084" }, + { .compatible = "qcom,rpm-ipq6018" }, + { .compatible = "qcom,rpm-ipq9574" }, + { .compatible = "qcom,rpm-msm8226" }, + { .compatible = "qcom,rpm-msm8909" }, + { .compatible = "qcom,rpm-msm8916" }, + { .compatible = "qcom,rpm-msm8936" }, + { .compatible = "qcom,rpm-msm8953" }, + { .compatible = "qcom,rpm-msm8974" }, + { .compatible = "qcom,rpm-msm8976" }, + { .compatible = "qcom,rpm-msm8994" }, + { .compatible = "qcom,rpm-msm8996" }, + { .compatible = "qcom,rpm-msm8998" }, + { .compatible = "qcom,rpm-sdm660" }, + { .compatible = "qcom,rpm-sm6115" }, + { .compatible = "qcom,rpm-sm6125" }, + { .compatible = "qcom,rpm-sm6375" }, + { .compatible = "qcom,rpm-qcm2290" }, + { .compatible = "qcom,rpm-qcs404" }, + {} }; -MODULE_DEVICE_TABLE(rpmsg, qcom_smd_rpm_id_table); +MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match); static struct rpmsg_driver qcom_smd_rpm_driver = { .probe = qcom_smd_rpm_probe, .remove = qcom_smd_rpm_remove, .callback = qcom_smd_rpm_callback, - .id_table = qcom_smd_rpm_id_table, - .drv.name = "qcom_smd_rpm", + .drv = { + .name = "qcom_smd_rpm", + .of_match_table = qcom_smd_rpm_of_match, + }, }; static int __init qcom_smd_rpm_init(void) From 9d5f3cc5024df5ad3ee4bce14226a44ee78d22ae Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 29 Jul 2024 22:52:15 +0300 Subject: [PATCH 051/212] dt-bindings: soc: qcom: smd-rpm: add generic compatibles Add two generic compatibles to all smd-rpm devices, they follow the same RPMSG protocol and are either accessed through the smd-edge or through the glink-edge. Signed-off-by: Dmitry Baryshkov Reviewed-by: Rob Herring (Arm) Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20240729-fix-smd-rpm-v2-2-0776408a94c5@linaro.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/clock/qcom,rpmcc.yaml | 2 +- .../remoteproc/qcom,glink-rpm-edge.yaml | 2 +- .../bindings/remoteproc/qcom,rpm-proc.yaml | 4 +- .../bindings/soc/qcom/qcom,smd-rpm.yaml | 74 +++++++++---------- .../bindings/soc/qcom/qcom,smd.yaml | 2 +- 5 files changed, 38 insertions(+), 46 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml index 3665dd30604a..02fcffe93f1a 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.yaml @@ -139,7 +139,7 @@ examples: - | rpm { rpm-requests { - compatible = "qcom,rpm-msm8916"; + compatible = "qcom,rpm-msm8916", "qcom,smd-rpm"; qcom,smd-channels = "rpm_requests"; clock-controller { diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml index 3766d4513b37..c54234247ab3 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml @@ -90,7 +90,7 @@ examples: qcom,rpm-msg-ram = <&rpm_msg_ram>; rpm-requests { - compatible = "qcom,rpm-msm8996"; + compatible = "qcom,rpm-msm8996", "qcom,glink-smd-rpm"; qcom,glink-channels = "rpm_requests"; /* ... */ diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml index 7afafde17a38..0c3e668b5d31 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml @@ -142,7 +142,7 @@ examples: qcom,smd-edge = <15>; rpm-requests { - compatible = "qcom,rpm-msm8916"; + compatible = "qcom,rpm-msm8916", "qcom,smd-rpm"; qcom,smd-channels = "rpm_requests"; /* ... */ }; @@ -163,7 +163,7 @@ examples: mboxes = <&apcs_glb 0>; rpm-requests { - compatible = "qcom,rpm-qcm2290"; + compatible = "qcom,rpm-qcm2290", "qcom,glink-smd-rpm"; qcom,glink-channels = "rpm_requests"; /* ... */ }; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml index 2fa725b8af5d..270bcd079f88 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml @@ -30,31 +30,37 @@ maintainers: properties: compatible: - enum: - - qcom,rpm-apq8084 - - qcom,rpm-ipq6018 - - qcom,rpm-ipq9574 - - qcom,rpm-mdm9607 - - qcom,rpm-msm8226 - - qcom,rpm-msm8610 - - qcom,rpm-msm8909 - - qcom,rpm-msm8916 - - qcom,rpm-msm8917 - - qcom,rpm-msm8936 - - qcom,rpm-msm8937 - - qcom,rpm-msm8952 - - qcom,rpm-msm8953 - - qcom,rpm-msm8974 - - qcom,rpm-msm8976 - - qcom,rpm-msm8994 - - qcom,rpm-msm8996 - - qcom,rpm-msm8998 - - qcom,rpm-qcm2290 - - qcom,rpm-qcs404 - - qcom,rpm-sdm660 - - qcom,rpm-sm6115 - - qcom,rpm-sm6125 - - qcom,rpm-sm6375 + oneOf: + - items: + - enum: + - qcom,rpm-apq8084 + - qcom,rpm-mdm9607 + - qcom,rpm-msm8226 + - qcom,rpm-msm8610 + - qcom,rpm-msm8909 + - qcom,rpm-msm8916 + - qcom,rpm-msm8917 + - qcom,rpm-msm8936 + - qcom,rpm-msm8937 + - qcom,rpm-msm8952 + - qcom,rpm-msm8953 + - qcom,rpm-msm8974 + - qcom,rpm-msm8976 + - qcom,rpm-msm8994 + - const: qcom,smd-rpm + - items: + - enum: + - qcom,rpm-ipq6018 + - qcom,rpm-ipq9574 + - qcom,rpm-msm8996 + - qcom,rpm-msm8998 + - qcom,rpm-qcm2290 + - qcom,rpm-qcs404 + - qcom,rpm-sdm660 + - qcom,rpm-sm6115 + - qcom,rpm-sm6125 + - qcom,rpm-sm6375 + - const: qcom,glink-smd-rpm clock-controller: $ref: /schemas/clock/qcom,rpmcc.yaml# @@ -84,21 +90,7 @@ if: properties: compatible: contains: - enum: - - qcom,rpm-apq8084 - - qcom,rpm-mdm9607 - - qcom,rpm-msm8226 - - qcom,rpm-msm8610 - - qcom,rpm-msm8909 - - qcom,rpm-msm8916 - - qcom,rpm-msm8917 - - qcom,rpm-msm8936 - - qcom,rpm-msm8937 - - qcom,rpm-msm8952 - - qcom,rpm-msm8953 - - qcom,rpm-msm8974 - - qcom,rpm-msm8976 - - qcom,rpm-msm8994 + const: qcom,smd-rpm then: properties: qcom,glink-channels: false @@ -129,7 +121,7 @@ examples: qcom,smd-edge = <15>; rpm-requests { - compatible = "qcom,rpm-msm8916"; + compatible = "qcom,rpm-msm8916", "qcom,smd-rpm"; qcom,smd-channels = "rpm_requests"; clock-controller { diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml index 4819ce90d206..d9fabefc8147 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml @@ -56,7 +56,7 @@ examples: qcom,smd-edge = <15>; rpm-requests { - compatible = "qcom,rpm-msm8974"; + compatible = "qcom,rpm-msm8974", "qcom,smd-rpm"; qcom,smd-channels = "rpm_requests"; clock-controller { From b14c150d195b8ae07deb391741a1efb8c302f176 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 29 Jul 2024 22:52:16 +0300 Subject: [PATCH 052/212] soc: qcom: smd-rpm: add qcom,smd-rpm compatible Add the generic qcom,smd-rpm and qcom,glink-smd-rpm compatibles so that there is no need to add further compat strings to the list. Existing strings are intact to keep compatibility with existing DTS. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240729-fix-smd-rpm-v2-3-0776408a94c5@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smd-rpm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index 9d64283d2125..f2b3e02abdf1 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -216,6 +216,12 @@ static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev) } static const struct of_device_id qcom_smd_rpm_of_match[] = { + { .compatible = "qcom,glink-smd-rpm" }, + { .compatible = "qcom,smd-rpm" }, + /* + * Don't add any more compatibles to the list, two previous entryes + * should match all defined devices. + */ { .compatible = "qcom,rpm-apq8084" }, { .compatible = "qcom,rpm-ipq6018" }, { .compatible = "qcom,rpm-ipq9574" }, From 6c26d9c764c62343722d6ea6c9e4c7e65989f634 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 Aug 2024 15:09:47 +0200 Subject: [PATCH 053/212] soc: qcom: apr: simplify with scoped for each OF child loop Use scoped for_each_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-1-cfb67323a95c@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/apr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 4fbff3a890e2..a956c407ce03 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -485,11 +485,10 @@ static int of_apr_add_pd_lookups(struct device *dev) { const char *service_name, *service_path; struct packet_router *apr = dev_get_drvdata(dev); - struct device_node *node; struct pdr_service *pds; int ret; - for_each_child_of_node(dev->of_node, node) { + for_each_child_of_node_scoped(dev->of_node, node) { ret = of_property_read_string_index(node, "qcom,protection-domain", 0, &service_name); if (ret < 0) @@ -499,14 +498,12 @@ static int of_apr_add_pd_lookups(struct device *dev) 1, &service_path); if (ret < 0) { dev_err(dev, "pdr service path missing: %d\n", ret); - of_node_put(node); return ret; } pds = pdr_add_lookup(apr->pdr, service_name, service_path); if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds)); - of_node_put(node); return PTR_ERR(pds); } } From c50203cbba1573546f115330530d24382fc53f09 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 Aug 2024 15:09:48 +0200 Subject: [PATCH 054/212] soc: qcom: aoss: simplify with scoped for each OF child loop Use scoped for_each_available_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-2-cfb67323a95c@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_aoss.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index ca2f6b7629ce..60af26667bce 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -394,7 +394,7 @@ static int qmp_cooling_device_add(struct qmp *qmp, static int qmp_cooling_devices_register(struct qmp *qmp) { - struct device_node *np, *child; + struct device_node *np; int count = 0; int ret; @@ -407,15 +407,13 @@ static int qmp_cooling_devices_register(struct qmp *qmp) if (!qmp->cooling_devs) return -ENOMEM; - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { if (!of_property_present(child, "#cooling-cells")) continue; ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++], child); - if (ret) { - of_node_put(child); + if (ret) goto unroll; - } } if (!count) From 877840f13bcc96e05aca2e1e6cc0f957afb788a4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 Aug 2024 15:09:49 +0200 Subject: [PATCH 055/212] soc: qcom: ice: use scoped device node handling to simplify error paths Obtain the device node reference with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-3-cfb67323a95c@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/ice.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c index fbab7fe5c652..50be7a9274a1 100644 --- a/drivers/soc/qcom/ice.c +++ b/drivers/soc/qcom/ice.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -265,7 +266,6 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct qcom_ice *ice; - struct device_node *node; struct resource *res; void __iomem *base; @@ -292,15 +292,15 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) * (legacy DT binding), then it must at least provide a phandle * to the ICE devicetree node, otherwise ICE is not supported. */ - node = of_parse_phandle(dev->of_node, "qcom,ice", 0); + struct device_node *node __free(device_node) = of_parse_phandle(dev->of_node, + "qcom,ice", 0); if (!node) return NULL; pdev = of_find_device_by_node(node); if (!pdev) { dev_err(dev, "Cannot find device node %s\n", node->name); - ice = ERR_PTR(-EPROBE_DEFER); - goto out; + return ERR_PTR(-EPROBE_DEFER); } ice = platform_get_drvdata(pdev); @@ -308,8 +308,7 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) dev_err(dev, "Cannot get ice instance from %s\n", dev_name(&pdev->dev)); platform_device_put(pdev); - ice = ERR_PTR(-EPROBE_DEFER); - goto out; + return ERR_PTR(-EPROBE_DEFER); } ice->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER); @@ -321,9 +320,6 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) ice = ERR_PTR(-EINVAL); } -out: - of_node_put(node); - return ice; } EXPORT_SYMBOL_GPL(of_qcom_ice_get); From f4c1c19f5c0e5cf2870df91dedc6b40400fd9c8a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 Aug 2024 15:09:50 +0200 Subject: [PATCH 056/212] soc: qcom: ocmem: use scoped device node handling to simplify error paths Obtain the device node reference with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-4-cfb67323a95c@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/ocmem.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index 6b6dd80cbc0f..ff8df7d75d6b 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -186,23 +186,20 @@ static void update_range(struct ocmem *ocmem, struct ocmem_buf *buf, struct ocmem *of_get_ocmem(struct device *dev) { struct platform_device *pdev; - struct device_node *devnode; struct ocmem *ocmem; - devnode = of_parse_phandle(dev->of_node, "sram", 0); + struct device_node *devnode __free(device_node) = of_parse_phandle(dev->of_node, + "sram", 0); if (!devnode || !devnode->parent) { dev_err(dev, "Cannot look up sram phandle\n"); - of_node_put(devnode); return ERR_PTR(-ENODEV); } pdev = of_find_device_by_node(devnode->parent); if (!pdev) { dev_err(dev, "Cannot find device node %s\n", devnode->name); - of_node_put(devnode); return ERR_PTR(-EPROBE_DEFER); } - of_node_put(devnode); ocmem = platform_get_drvdata(pdev); if (!ocmem) { From a29e97bdc160aaa27187c7be3bcd052af66c027a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 Aug 2024 15:09:51 +0200 Subject: [PATCH 057/212] soc: qcom: pbs: use scoped device node handling to simplify error paths Obtain the device node reference with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-5-cfb67323a95c@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom-pbs.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/soc/qcom/qcom-pbs.c b/drivers/soc/qcom/qcom-pbs.c index 6af49b5060e5..77a70d3d0d0b 100644 --- a/drivers/soc/qcom/qcom-pbs.c +++ b/drivers/soc/qcom/qcom-pbs.c @@ -3,6 +3,7 @@ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include #include @@ -148,11 +149,11 @@ EXPORT_SYMBOL_GPL(qcom_pbs_trigger_event); */ struct pbs_dev *get_pbs_client_device(struct device *dev) { - struct device_node *pbs_dev_node; struct platform_device *pdev; struct pbs_dev *pbs; - pbs_dev_node = of_parse_phandle(dev->of_node, "qcom,pbs", 0); + struct device_node *pbs_dev_node __free(device_node) = of_parse_phandle(dev->of_node, + "qcom,pbs", 0); if (!pbs_dev_node) { dev_err(dev, "Missing qcom,pbs property\n"); return ERR_PTR(-ENODEV); @@ -161,28 +162,23 @@ struct pbs_dev *get_pbs_client_device(struct device *dev) pdev = of_find_device_by_node(pbs_dev_node); if (!pdev) { dev_err(dev, "Unable to find PBS dev_node\n"); - pbs = ERR_PTR(-EPROBE_DEFER); - goto out; + return ERR_PTR(-EPROBE_DEFER); } pbs = platform_get_drvdata(pdev); if (!pbs) { dev_err(dev, "Cannot get pbs instance from %s\n", dev_name(&pdev->dev)); platform_device_put(pdev); - pbs = ERR_PTR(-EPROBE_DEFER); - goto out; + return ERR_PTR(-EPROBE_DEFER); } pbs->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER); if (!pbs->link) { dev_err(&pdev->dev, "Failed to create device link to consumer %s\n", dev_name(dev)); platform_device_put(pdev); - pbs = ERR_PTR(-EINVAL); - goto out; + return ERR_PTR(-EINVAL); } -out: - of_node_put(pbs_dev_node); return pbs; } EXPORT_SYMBOL_GPL(get_pbs_client_device); From f728778272242c84d36682c0aabbb845195e745d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 Aug 2024 15:09:52 +0200 Subject: [PATCH 058/212] soc: qcom: smp2p: use scoped device node handling to simplify error paths Obtain the device node reference with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-6-cfb67323a95c@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smp2p.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index 4aa61b0f11ad..cefcbd61c628 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -539,7 +539,6 @@ static int smp2p_parse_ipc(struct qcom_smp2p *smp2p) static int qcom_smp2p_probe(struct platform_device *pdev) { struct smp2p_entry *entry; - struct device_node *node; struct qcom_smp2p *smp2p; const char *key; int irq; @@ -593,11 +592,10 @@ static int qcom_smp2p_probe(struct platform_device *pdev) if (ret < 0) goto release_mbox; - for_each_available_child_of_node(pdev->dev.of_node, node) { + for_each_available_child_of_node_scoped(pdev->dev.of_node, node) { entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); if (!entry) { ret = -ENOMEM; - of_node_put(node); goto unwind_interfaces; } @@ -605,25 +603,19 @@ static int qcom_smp2p_probe(struct platform_device *pdev) spin_lock_init(&entry->lock); ret = of_property_read_string(node, "qcom,entry-name", &entry->name); - if (ret < 0) { - of_node_put(node); + if (ret < 0) goto unwind_interfaces; - } if (of_property_read_bool(node, "interrupt-controller")) { ret = qcom_smp2p_inbound_entry(smp2p, entry, node); - if (ret < 0) { - of_node_put(node); + if (ret < 0) goto unwind_interfaces; - } list_add(&entry->node, &smp2p->inbound); } else { ret = qcom_smp2p_outbound_entry(smp2p, entry, node); - if (ret < 0) { - of_node_put(node); + if (ret < 0) goto unwind_interfaces; - } list_add(&entry->node, &smp2p->outbound); } From 6b34e75c48bb913f3431e66353cad9782e7225c7 Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 14 Aug 2024 15:28:05 +0800 Subject: [PATCH 059/212] dt-bindings: arm: qcom,ids: add SoC ID for QCS8275/QCS8300 Add the ID for Qualcomm QCS8275/QCS8300 SoC. Signed-off-by: Jingyi Wang Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240814072806.4107079-3-quic_jingyw@quicinc.com Signed-off-by: Bjorn Andersson --- include/dt-bindings/arm/qcom,ids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h index d6c9e9472121..a213f6244c5d 100644 --- a/include/dt-bindings/arm/qcom,ids.h +++ b/include/dt-bindings/arm/qcom,ids.h @@ -274,6 +274,8 @@ #define QCOM_ID_QCM8550 604 #define QCOM_ID_IPQ5300 624 #define QCOM_ID_IPQ5321 650 +#define QCOM_ID_QCS8300 674 +#define QCOM_ID_QCS8275 675 /* * The board type and revision information, used by Qualcomm bootloaders and From dff75ec5763eb9c7ad64be952cc6930b410beb2d Mon Sep 17 00:00:00 2001 From: Jingyi Wang Date: Wed, 14 Aug 2024 15:28:06 +0800 Subject: [PATCH 060/212] soc: qcom: socinfo: add QCS8275/QCS8300 SoC ID Add SoC ID for Qualcomm QCS8275/QCS8300. Signed-off-by: Jingyi Wang Link: https://lore.kernel.org/r/20240814072806.4107079-4-quic_jingyw@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index d7359a235e3c..3ba29412b9ba 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -441,6 +441,8 @@ static const struct soc_id soc_id[] = { { qcom_board_id(QCM8550) }, { qcom_board_id(IPQ5300) }, { qcom_board_id(IPQ5321) }, + { qcom_board_id(QCS8300) }, + { qcom_board_id(QCS8275) }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) From c580e7bfc0cd140b8d3cf73183e08ca8b23326db Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Thu, 8 Aug 2024 21:40:15 +0300 Subject: [PATCH 061/212] dt-bindings: arm: qcom,ids: Add IDs for SM7325 family Add Qualcomm SM7325/SM7325P (yupik) SoC IDs. Signed-off-by: Danila Tikhonov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240808184048.63030-2-danila@jiaxyga.com Signed-off-by: Bjorn Andersson --- include/dt-bindings/arm/qcom,ids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h index a213f6244c5d..8332f8d82f96 100644 --- a/include/dt-bindings/arm/qcom,ids.h +++ b/include/dt-bindings/arm/qcom,ids.h @@ -234,11 +234,13 @@ #define QCOM_ID_SA8540P 461 #define QCOM_ID_QCM4290 469 #define QCOM_ID_QCS4290 470 +#define QCOM_ID_SM7325 475 #define QCOM_ID_SM8450_2 480 #define QCOM_ID_SM8450_3 482 #define QCOM_ID_SC7280 487 #define QCOM_ID_SC7180P 495 #define QCOM_ID_QCM6490 497 +#define QCOM_ID_SM7325P 499 #define QCOM_ID_IPQ5000 503 #define QCOM_ID_IPQ0509 504 #define QCOM_ID_IPQ0518 505 From 31150c9e87b4a8fe8e726a6f50ac0933f5075532 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Thu, 8 Aug 2024 21:40:16 +0300 Subject: [PATCH 062/212] soc: qcom: socinfo: Add Soc IDs for SM7325 family Add Soc ID table entries for Qualcomm SM7325 family. Signed-off-by: Danila Tikhonov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240808184048.63030-3-danila@jiaxyga.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 3ba29412b9ba..24c3971f2ef1 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -401,11 +401,13 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SA8540P) }, { qcom_board_id(QCM4290) }, { qcom_board_id(QCS4290) }, + { qcom_board_id(SM7325) }, { qcom_board_id_named(SM8450_2, "SM8450") }, { qcom_board_id_named(SM8450_3, "SM8450") }, { qcom_board_id(SC7280) }, { qcom_board_id(SC7180P) }, { qcom_board_id(QCM6490) }, + { qcom_board_id(SM7325P) }, { qcom_board_id(IPQ5000) }, { qcom_board_id(IPQ0509) }, { qcom_board_id(IPQ0518) }, From 79b26c110545530fa2945050a2ffbb3c4e270228 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Thu, 8 Aug 2024 21:40:18 +0300 Subject: [PATCH 063/212] soc: qcom: pd_mapper: Add SM7325 compatible The Qualcomm SM7325 platform is identical to SC7280, so add compatibility leading to SC7280. Signed-off-by: Danila Tikhonov Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240808184048.63030-5-danila@jiaxyga.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_pd_mapper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c index 63db04f2bf67..ef5171a6860e 100644 --- a/drivers/soc/qcom/qcom_pd_mapper.c +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -552,6 +552,7 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = { { .compatible = "qcom,sm4250", .data = sm6115_domains, }, { .compatible = "qcom,sm6115", .data = sm6115_domains, }, { .compatible = "qcom,sm6350", .data = sm6350_domains, }, + { .compatible = "qcom,sm7325", .data = sc7280_domains, }, { .compatible = "qcom,sm8150", .data = sm8150_domains, }, { .compatible = "qcom,sm8250", .data = sm8250_domains, }, { .compatible = "qcom,sm8350", .data = sm8350_domains, }, From e6b666de995e993bcda883ff045164f090e5506d Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Thu, 8 Aug 2024 21:40:19 +0300 Subject: [PATCH 064/212] dt-bindings: soc: qcom: qcom,pmic-glink: Document SM7325 compatible The SM7325 is the closest SoC to the QCM6490 and is also identical to the SC7280. The SM7325 also requires both UCSI_NO_PARTNER_PDOS & UCSI_DELAY_DEVICE_PDOS quirks. Document the PMIC GLINK firmware interface on the SM7325 Platform by using the QCM6490 bindings as fallback. Signed-off-by: Danila Tikhonov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240808184048.63030-6-danila@jiaxyga.com Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml index 4512390f90f0..2d3fe0b54243 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml @@ -30,6 +30,11 @@ properties: - qcom,sm8450-pmic-glink - qcom,sm8550-pmic-glink - const: qcom,pmic-glink + - items: + - enum: + - qcom,sm7325-pmic-glink + - const: qcom,qcm6490-pmic-glink + - const: qcom,pmic-glink - items: - enum: - qcom,sm8650-pmic-glink From a41759500b7164abfe509e432b3da1619bc62763 Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:33:37 +0100 Subject: [PATCH 065/212] firmware: arm_scmi: Make SMC transport a standalone driver Make SCMI SMC transport a standalone driver that can be optionally loaded as a module. CC: Peng Fan CC: Nikunj Kela Signed-off-by: Cristian Marussi Message-Id: <20240812173340.3912830-7-cristian.marussi@arm.com> [sudeep.holla: moved Clang Thumb2 build fix to the new makefile] Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Kconfig | 26 --------------- drivers/firmware/arm_scmi/Makefile | 8 ----- drivers/firmware/arm_scmi/common.h | 3 -- drivers/firmware/arm_scmi/driver.c | 5 --- drivers/firmware/arm_scmi/transports/Kconfig | 28 ++++++++++++++++ drivers/firmware/arm_scmi/transports/Makefile | 8 +++++ .../firmware/arm_scmi/{ => transports}/smc.c | 33 +++++++++++++++---- 7 files changed, 62 insertions(+), 49 deletions(-) rename drivers/firmware/arm_scmi/{ => transports}/smc.c (89%) diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index e9a7c9aaa956..27de15ad6444 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -84,32 +84,6 @@ config ARM_SCMI_TRANSPORT_OPTEE If you want the ARM SCMI PROTOCOL stack to include support for a transport based on OP-TEE SCMI service, answer Y. -config ARM_SCMI_TRANSPORT_SMC - bool "SCMI transport based on SMC" - depends on HAVE_ARM_SMCCC_DISCOVERY - select ARM_SCMI_HAVE_TRANSPORT - select ARM_SCMI_HAVE_SHMEM - default y - help - Enable SMC based transport for SCMI. - - If you want the ARM SCMI PROTOCOL stack to include support for a - transport based on SMC, answer Y. - -config ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE - bool "Enable atomic mode support for SCMI SMC transport" - depends on ARM_SCMI_TRANSPORT_SMC - help - Enable support of atomic operation for SCMI SMC based transport. - - If you want the SCMI SMC based transport to operate in atomic - mode, avoiding any kind of sleeping behaviour for selected - transactions on the TX path, answer Y. - Enabling atomic mode operations allows any SCMI driver using this - transport to optionally ask for atomic SCMI transactions and operate - in atomic context too, at the price of using a number of busy-waiting - primitives all over instead. If unsure say N. - config ARM_SCMI_TRANSPORT_VIRTIO bool "SCMI transport based on VirtIO" depends on VIRTIO=y || VIRTIO=ARM_SCMI_PROTOCOL diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index beaa55c146b8..4c58c668ecc4 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -5,7 +5,6 @@ scmi-core-objs := $(scmi-bus-y) scmi-driver-y = driver.o notify.o scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o -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 @@ -19,10 +18,3 @@ obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o - -ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) -# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame -# pointer in Thumb2 mode, which is forcibly enabled by Clang when profiling -# hooks are inserted via the -pg switch. -CFLAGS_REMOVE_smc.o += $(CC_FLAGS_FTRACE) -endif diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 2bca62a8ecde..231b061dadb9 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -286,9 +286,6 @@ int scmi_xfer_raw_inflight_register(const struct scmi_handle *handle, int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer, unsigned int timeout_ms); -#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC -extern const struct scmi_desc scmi_smc_desc; -#endif #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO extern const struct scmi_desc scmi_virtio_desc; #endif diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index c13bef8a1796..bdb952c385d2 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -3321,11 +3321,6 @@ static const struct of_device_id scmi_of_match[] = { #ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE { .compatible = "linaro,scmi-optee", .data = &scmi_optee_desc }, #endif -#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC - { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, - { .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc}, - { .compatible = "qcom,scmi-smc", .data = &scmi_smc_desc}, -#endif #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO { .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc}, #endif diff --git a/drivers/firmware/arm_scmi/transports/Kconfig b/drivers/firmware/arm_scmi/transports/Kconfig index 96c0d76b3042..85d693811a1c 100644 --- a/drivers/firmware/arm_scmi/transports/Kconfig +++ b/drivers/firmware/arm_scmi/transports/Kconfig @@ -34,4 +34,32 @@ config ARM_SCMI_TRANSPORT_MAILBOX This driver can also be built as a module. If so, the module will be called scmi_transport_mailbox. +config ARM_SCMI_TRANSPORT_SMC + tristate "SCMI transport based on SMC" + depends on HAVE_ARM_SMCCC_DISCOVERY + select ARM_SCMI_HAVE_TRANSPORT + select ARM_SCMI_HAVE_SHMEM + default y + help + Enable SMC based transport for SCMI. + + If you want the ARM SCMI PROTOCOL stack to include support for a + transport based on SMC, answer Y. + This driver can also be built as a module. If so, the module + will be called scmi_transport_smc. + +config ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE + bool "Enable atomic mode support for SCMI SMC transport" + depends on ARM_SCMI_TRANSPORT_SMC + help + Enable support of atomic operation for SCMI SMC based transport. + + If you want the SCMI SMC based transport to operate in atomic + mode, avoiding any kind of sleeping behaviour for selected + transactions on the TX path, answer Y. + Enabling atomic mode operations allows any SCMI driver using this + transport to optionally ask for atomic SCMI transactions and operate + in atomic context too, at the price of using a number of busy-waiting + primitives all over instead. If unsure say N. + endmenu diff --git a/drivers/firmware/arm_scmi/transports/Makefile b/drivers/firmware/arm_scmi/transports/Makefile index cb40be8955be..080bd76d9dbd 100644 --- a/drivers/firmware/arm_scmi/transports/Makefile +++ b/drivers/firmware/arm_scmi/transports/Makefile @@ -1,4 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only scmi_transport_mailbox-objs := mailbox.o obj-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += scmi_transport_mailbox.o +scmi_transport_smc-objs := smc.o +obj-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += scmi_transport_smc.o +ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) +# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame +# pointer in Thumb2 mode, which is forcibly enabled by Clang when profiling +# hooks are inserted via the -pg switch. +CFLAGS_REMOVE_smc.o += $(CC_FLAGS_FTRACE) +endif diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/transports/smc.c similarity index 89% rename from drivers/firmware/arm_scmi/smc.c rename to drivers/firmware/arm_scmi/transports/smc.c index 4cb86386c490..6fc3e1973c58 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/transports/smc.c @@ -16,10 +16,11 @@ #include #include #include +#include #include #include -#include "common.h" +#include "../common.h" /* * The shmem address is split into 4K page and offset. @@ -69,12 +70,14 @@ struct scmi_smc { unsigned long cap_id; }; +static struct scmi_transport_core_operations *core; + static irqreturn_t smc_msg_done_isr(int irq, void *data) { struct scmi_smc *scmi_info = data; - scmi_rx_callback(scmi_info->cinfo, - scmi_shmem_ops.read_header(scmi_info->shmem), NULL); + core->rx_callback(scmi_info->cinfo, + core->shmem->read_header(scmi_info->shmem), NULL); return IRQ_HANDLED; } @@ -141,7 +144,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!scmi_info) return -ENOMEM; - scmi_info->shmem = scmi_shmem_ops.setup_iomap(cinfo, dev, tx, &res); + scmi_info->shmem = core->shmem->setup_iomap(cinfo, dev, tx, &res); if (IS_ERR(scmi_info->shmem)) return PTR_ERR(scmi_info->shmem); @@ -226,7 +229,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo, */ smc_channel_lock_acquire(scmi_info, xfer); - scmi_shmem_ops.tx_prepare(scmi_info->shmem, xfer, cinfo); + core->shmem->tx_prepare(scmi_info->shmem, xfer, cinfo); if (scmi_info->cap_id != ULONG_MAX) arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0, @@ -250,7 +253,7 @@ static void smc_fetch_response(struct scmi_chan_info *cinfo, { struct scmi_smc *scmi_info = cinfo->transport_info; - scmi_shmem_ops.fetch_response(scmi_info->shmem, xfer); + core->shmem->fetch_response(scmi_info->shmem, xfer); } static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret, @@ -270,7 +273,7 @@ static const struct scmi_transport_ops scmi_smc_ops = { .fetch_response = smc_fetch_response, }; -const struct scmi_desc scmi_smc_desc = { +static const struct scmi_desc scmi_smc_desc = { .ops = &scmi_smc_ops, .max_rx_timeout_ms = 30, .max_msg = 20, @@ -286,3 +289,19 @@ const struct scmi_desc scmi_smc_desc = { .sync_cmds_completed_on_ret = true, .atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE), }; + +static const struct of_device_id scmi_of_match[] = { + { .compatible = "arm,scmi-smc" }, + { .compatible = "arm,scmi-smc-param" }, + { .compatible = "qcom,scmi-smc" }, + { /* Sentinel */ }, +}; + +DEFINE_SCMI_TRANSPORT_DRIVER(scmi_smc, scmi_smc_driver, scmi_smc_desc, + scmi_of_match, core); +module_platform_driver(scmi_smc_driver); + +MODULE_AUTHOR("Peng Fan "); +MODULE_AUTHOR("Nikunj Kela "); +MODULE_DESCRIPTION("SCMI SMC Transport driver"); +MODULE_LICENSE("GPL"); From db9cc5e677783a8a9157804f4a61bb81d83049ac Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:33:38 +0100 Subject: [PATCH 066/212] firmware: arm_scmi: Make OPTEE transport a standalone driver Make SCMI OPTEE transport a standalone driver that can be optionally loaded as a module. CC: Etienne Carriere Signed-off-by: Cristian Marussi Message-Id: <20240812173340.3912830-8-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Kconfig | 13 --- drivers/firmware/arm_scmi/Makefile | 1 - drivers/firmware/arm_scmi/common.h | 3 - drivers/firmware/arm_scmi/driver.c | 3 - drivers/firmware/arm_scmi/transports/Kconfig | 15 +++ drivers/firmware/arm_scmi/transports/Makefile | 2 + .../arm_scmi/{ => transports}/optee.c | 91 ++++++++++--------- 7 files changed, 64 insertions(+), 64 deletions(-) rename drivers/firmware/arm_scmi/{ => transports}/optee.c (91%) diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index 27de15ad6444..b5e3634a8399 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -71,19 +71,6 @@ config ARM_SCMI_DEBUG_COUNTERS source "drivers/firmware/arm_scmi/transports/Kconfig" -config ARM_SCMI_TRANSPORT_OPTEE - bool "SCMI transport based on OP-TEE service" - depends on OPTEE=y || OPTEE=ARM_SCMI_PROTOCOL - select ARM_SCMI_HAVE_TRANSPORT - select ARM_SCMI_HAVE_SHMEM - select ARM_SCMI_HAVE_MSG - default y - help - This enables the OP-TEE service based transport for SCMI. - - If you want the ARM SCMI PROTOCOL stack to include support for a - transport based on OP-TEE SCMI service, answer Y. - config ARM_SCMI_TRANSPORT_VIRTIO bool "SCMI transport based on VirtIO" depends on VIRTIO=y || VIRTIO=ARM_SCMI_PROTOCOL diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 4c58c668ecc4..4b6dcf241ce1 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -7,7 +7,6 @@ scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.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 += pinctrl.o scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 231b061dadb9..18026d446b59 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -289,9 +289,6 @@ int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo, #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO extern const struct scmi_desc scmi_virtio_desc; #endif -#ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE -extern const struct scmi_desc scmi_optee_desc; -#endif void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index bdb952c385d2..084936e9575d 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -3318,9 +3318,6 @@ ATTRIBUTE_GROUPS(versions); /* Each compatible listed below must have descriptor associated with it */ static const struct of_device_id scmi_of_match[] = { -#ifdef CONFIG_ARM_SCMI_TRANSPORT_OPTEE - { .compatible = "linaro,scmi-optee", .data = &scmi_optee_desc }, -#endif #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO { .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc}, #endif diff --git a/drivers/firmware/arm_scmi/transports/Kconfig b/drivers/firmware/arm_scmi/transports/Kconfig index 85d693811a1c..7d478a4f69df 100644 --- a/drivers/firmware/arm_scmi/transports/Kconfig +++ b/drivers/firmware/arm_scmi/transports/Kconfig @@ -62,4 +62,19 @@ config ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE in atomic context too, at the price of using a number of busy-waiting primitives all over instead. If unsure say N. +config ARM_SCMI_TRANSPORT_OPTEE + tristate "SCMI transport based on OP-TEE service" + depends on OPTEE + select ARM_SCMI_HAVE_TRANSPORT + select ARM_SCMI_HAVE_SHMEM + select ARM_SCMI_HAVE_MSG + default y + help + This enables the OP-TEE service based transport for SCMI. + + If you want the ARM SCMI PROTOCOL stack to include support for a + transport based on OP-TEE SCMI service, answer Y. + This driver can also be built as a module. If so, the module + will be called scmi_transport_optee. + endmenu diff --git a/drivers/firmware/arm_scmi/transports/Makefile b/drivers/firmware/arm_scmi/transports/Makefile index 080bd76d9dbd..efc002e7efcd 100644 --- a/drivers/firmware/arm_scmi/transports/Makefile +++ b/drivers/firmware/arm_scmi/transports/Makefile @@ -3,6 +3,8 @@ scmi_transport_mailbox-objs := mailbox.o obj-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += scmi_transport_mailbox.o scmi_transport_smc-objs := smc.o obj-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += scmi_transport_smc.o +scmi_transport_optee-objs := optee.o +obj-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += scmi_transport_optee.o ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) # The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/transports/optee.c similarity index 91% rename from drivers/firmware/arm_scmi/optee.c rename to drivers/firmware/arm_scmi/transports/optee.c index dae68adf6f9e..978750aaf6b7 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/transports/optee.c @@ -9,12 +9,13 @@ #include #include #include +#include #include #include #include #include -#include "common.h" +#include "../common.h" #define SCMI_OPTEE_MAX_MSG_SIZE 128 @@ -148,12 +149,11 @@ struct scmi_optee_agent { struct list_head channel_list; }; +static struct scmi_transport_core_operations *core; + /* There can be only 1 SCMI service in OP-TEE we connect to */ static struct scmi_optee_agent *scmi_optee_private; -/* Forward reference to scmi_optee transport initialization */ -static int scmi_optee_init(void); - /* Open a session toward SCMI OP-TEE service with REE_KERNEL identity */ static int open_session(struct scmi_optee_agent *agent, u32 *tee_session) { @@ -312,24 +312,6 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t return 0; } -static int scmi_optee_link_supplier(struct device *dev) -{ - if (!scmi_optee_private) { - if (scmi_optee_init()) - dev_dbg(dev, "Optee bus not yet ready\n"); - - /* Wait for optee bus */ - return -EPROBE_DEFER; - } - - if (!device_link_add(dev, scmi_optee_private->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) { - dev_err(dev, "Adding link to supplier optee device failed\n"); - return -ECANCELED; - } - - return 0; -} - static bool scmi_optee_chan_available(struct device_node *of_node, int idx) { u32 channel_id; @@ -343,7 +325,7 @@ static void scmi_optee_clear_channel(struct scmi_chan_info *cinfo) struct scmi_optee_channel *channel = cinfo->transport_info; if (!channel->tee_shm) - scmi_shmem_ops.clear_channel(channel->req.shmem); + core->shmem->clear_channel(channel->req.shmem); } static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *channel) @@ -368,7 +350,7 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo, struct scmi_optee_channel *channel) { - channel->req.shmem = scmi_shmem_ops.setup_iomap(cinfo, dev, true, NULL); + channel->req.shmem = core->shmem->setup_iomap(cinfo, dev, true, NULL); if (IS_ERR(channel->req.shmem)) return PTR_ERR(channel->req.shmem); @@ -479,10 +461,11 @@ static int scmi_optee_send_message(struct scmi_chan_info *cinfo, mutex_lock(&channel->mu); if (channel->tee_shm) { - scmi_msg_ops.tx_prepare(channel->req.msg, xfer); - ret = invoke_process_msg_channel(channel, scmi_msg_ops.command_size(xfer)); + core->msg->tx_prepare(channel->req.msg, xfer); + ret = invoke_process_msg_channel(channel, + core->msg->command_size(xfer)); } else { - scmi_shmem_ops.tx_prepare(channel->req.shmem, xfer, cinfo); + core->shmem->tx_prepare(channel->req.shmem, xfer, cinfo); ret = invoke_process_smt_channel(channel); } @@ -498,9 +481,10 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo, struct scmi_optee_channel *channel = cinfo->transport_info; if (channel->tee_shm) - scmi_msg_ops.fetch_response(channel->req.msg, channel->rx_len, xfer); + core->msg->fetch_response(channel->req.msg, + channel->rx_len, xfer); else - scmi_shmem_ops.fetch_response(channel->req.shmem, xfer); + core->shmem->fetch_response(channel->req.shmem, xfer); } static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret, @@ -512,7 +496,6 @@ static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret, } static struct scmi_transport_ops scmi_optee_ops = { - .link_supplier = scmi_optee_link_supplier, .chan_available = scmi_optee_chan_available, .chan_setup = scmi_optee_chan_setup, .chan_free = scmi_optee_chan_free, @@ -527,6 +510,22 @@ static int scmi_optee_ctx_match(struct tee_ioctl_version_data *ver, const void * return ver->impl_id == TEE_IMPL_ID_OPTEE; } +static const struct scmi_desc scmi_optee_desc = { + .ops = &scmi_optee_ops, + .max_rx_timeout_ms = 30, + .max_msg = 20, + .max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE, + .sync_cmds_completed_on_ret = true, +}; + +static const struct of_device_id scmi_of_match[] = { + { .compatible = "linaro,scmi-optee" }, + { /* Sentinel */ }, +}; + +DEFINE_SCMI_TRANSPORT_DRIVER(scmi_optee, scmi_optee_driver, scmi_optee_desc, + scmi_of_match, core); + static int scmi_optee_service_probe(struct device *dev) { struct scmi_optee_agent *agent; @@ -562,6 +561,12 @@ static int scmi_optee_service_probe(struct device *dev) smp_mb(); scmi_optee_private = agent; + ret = platform_driver_register(&scmi_optee_driver); + if (ret) { + scmi_optee_private = NULL; + goto err; + } + return 0; err: @@ -577,6 +582,8 @@ static int scmi_optee_service_remove(struct device *dev) if (!scmi_optee_private) return -EINVAL; + platform_driver_unregister(&scmi_optee_driver); + if (!list_empty(&scmi_optee_private->channel_list)) return -EBUSY; @@ -598,7 +605,7 @@ static const struct tee_client_device_id scmi_optee_service_id[] = { MODULE_DEVICE_TABLE(tee, scmi_optee_service_id); -static struct tee_client_driver scmi_optee_driver = { +static struct tee_client_driver scmi_optee_service_driver = { .id_table = scmi_optee_service_id, .driver = { .name = "scmi-optee", @@ -608,22 +615,18 @@ static struct tee_client_driver scmi_optee_driver = { }, }; -static int scmi_optee_init(void) +static int __init scmi_transport_optee_init(void) { - return driver_register(&scmi_optee_driver.driver); + return driver_register(&scmi_optee_service_driver.driver); } +module_init(scmi_transport_optee_init); -static void scmi_optee_exit(void) +static void __exit scmi_transport_optee_exit(void) { - if (scmi_optee_private) - driver_unregister(&scmi_optee_driver.driver); + driver_unregister(&scmi_optee_service_driver.driver); } +module_exit(scmi_transport_optee_exit); -const struct scmi_desc scmi_optee_desc = { - .transport_exit = scmi_optee_exit, - .ops = &scmi_optee_ops, - .max_rx_timeout_ms = 30, - .max_msg = 20, - .max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE, - .sync_cmds_completed_on_ret = true, -}; +MODULE_AUTHOR("Etienne Carriere "); +MODULE_DESCRIPTION("SCMI OPTEE Transport driver"); +MODULE_LICENSE("GPL"); From 20bda12a0ea086c35a4cf7465f8014a248e59080 Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:33:39 +0100 Subject: [PATCH 067/212] firmware: arm_scmi: Make VirtIO transport a standalone driver Make SCMI VirtIO transport a standalone driver that can be optionally loaded as a module. CC: Michael S. Tsirkin CC: Igor Skalkin CC: Peter Hilber Signed-off-by: Cristian Marussi Message-Id: <20240812173340.3912830-9-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Kconfig | 41 ------- drivers/firmware/arm_scmi/Makefile | 1 - drivers/firmware/arm_scmi/common.h | 3 - drivers/firmware/arm_scmi/driver.c | 3 - drivers/firmware/arm_scmi/transports/Kconfig | 43 ++++++++ drivers/firmware/arm_scmi/transports/Makefile | 2 + .../arm_scmi/{ => transports}/virtio.c | 103 +++++++++--------- 7 files changed, 99 insertions(+), 97 deletions(-) rename drivers/firmware/arm_scmi/{ => transports}/virtio.c (94%) diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index b5e3634a8399..67053c1862d1 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -71,47 +71,6 @@ config ARM_SCMI_DEBUG_COUNTERS source "drivers/firmware/arm_scmi/transports/Kconfig" -config ARM_SCMI_TRANSPORT_VIRTIO - bool "SCMI transport based on VirtIO" - depends on VIRTIO=y || VIRTIO=ARM_SCMI_PROTOCOL - select ARM_SCMI_HAVE_TRANSPORT - select ARM_SCMI_HAVE_MSG - help - This enables the virtio based transport for SCMI. - - If you want the ARM SCMI PROTOCOL stack to include support for a - transport based on VirtIO, answer Y. - -config ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE - bool "SCMI VirtIO transport Version 1 compliance" - depends on ARM_SCMI_TRANSPORT_VIRTIO - default y - help - This enforces strict compliance with VirtIO Version 1 specification. - - If you want the ARM SCMI VirtIO transport layer to refuse to work - with Legacy VirtIO backends and instead support only VirtIO Version 1 - devices (or above), answer Y. - - If you want instead to support also old Legacy VirtIO backends (like - the ones implemented by kvmtool) and let the core Kernel VirtIO layer - take care of the needed conversions, say N. - -config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE - bool "Enable atomic mode for SCMI VirtIO transport" - depends on ARM_SCMI_TRANSPORT_VIRTIO - help - Enable support of atomic operation for SCMI VirtIO based transport. - - If you want the SCMI VirtIO based transport to operate in atomic - mode, avoiding any kind of sleeping behaviour for selected - transactions on the TX path, answer Y. - - Enabling atomic mode operations allows any SCMI driver using this - transport to optionally ask for atomic SCMI transactions and operate - in atomic context too, at the price of using a number of busy-waiting - primitives all over instead. If unsure say N. - endif #ARM_SCMI_PROTOCOL config ARM_SCMI_POWER_CONTROL diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 4b6dcf241ce1..9659b7d1b963 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -6,7 +6,6 @@ scmi-driver-y = driver.o notify.o scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o -scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.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) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 18026d446b59..7a53412fc41c 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -286,9 +286,6 @@ int scmi_xfer_raw_inflight_register(const struct scmi_handle *handle, int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer, unsigned int timeout_ms); -#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO -extern const struct scmi_desc scmi_virtio_desc; -#endif void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 084936e9575d..12643b4c0db3 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -3318,9 +3318,6 @@ ATTRIBUTE_GROUPS(versions); /* Each compatible listed below must have descriptor associated with it */ static const struct of_device_id scmi_of_match[] = { -#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO - { .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc}, -#endif { /* Sentinel */ }, }; diff --git a/drivers/firmware/arm_scmi/transports/Kconfig b/drivers/firmware/arm_scmi/transports/Kconfig index 7d478a4f69df..57eccf316e26 100644 --- a/drivers/firmware/arm_scmi/transports/Kconfig +++ b/drivers/firmware/arm_scmi/transports/Kconfig @@ -77,4 +77,47 @@ config ARM_SCMI_TRANSPORT_OPTEE This driver can also be built as a module. If so, the module will be called scmi_transport_optee. +config ARM_SCMI_TRANSPORT_VIRTIO + tristate "SCMI transport based on VirtIO" + depends on VIRTIO + select ARM_SCMI_HAVE_TRANSPORT + select ARM_SCMI_HAVE_MSG + help + This enables the virtio based transport for SCMI. + + If you want the ARM SCMI PROTOCOL stack to include support for a + transport based on VirtIO, answer Y. + This driver can also be built as a module. If so, the module + will be called scmi_transport_virtio. + +config ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE + bool "SCMI VirtIO transport Version 1 compliance" + depends on ARM_SCMI_TRANSPORT_VIRTIO + default y + help + This enforces strict compliance with VirtIO Version 1 specification. + + If you want the ARM SCMI VirtIO transport layer to refuse to work + with Legacy VirtIO backends and instead support only VirtIO Version 1 + devices (or above), answer Y. + + If you want instead to support also old Legacy VirtIO backends (like + the ones implemented by kvmtool) and let the core Kernel VirtIO layer + take care of the needed conversions, say N. + +config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE + bool "Enable atomic mode for SCMI VirtIO transport" + depends on ARM_SCMI_TRANSPORT_VIRTIO + help + Enable support of atomic operation for SCMI VirtIO based transport. + + If you want the SCMI VirtIO based transport to operate in atomic + mode, avoiding any kind of sleeping behaviour for selected + transactions on the TX path, answer Y. + + Enabling atomic mode operations allows any SCMI driver using this + transport to optionally ask for atomic SCMI transactions and operate + in atomic context too, at the price of using a number of busy-waiting + primitives all over instead. If unsure say N. + endmenu diff --git a/drivers/firmware/arm_scmi/transports/Makefile b/drivers/firmware/arm_scmi/transports/Makefile index efc002e7efcd..362a406f08e6 100644 --- a/drivers/firmware/arm_scmi/transports/Makefile +++ b/drivers/firmware/arm_scmi/transports/Makefile @@ -5,6 +5,8 @@ scmi_transport_smc-objs := smc.o obj-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += scmi_transport_smc.o scmi_transport_optee-objs := optee.o obj-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += scmi_transport_optee.o +scmi_transport_virtio-objs := virtio.o +obj-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += scmi_transport_virtio.o ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) # The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi/transports/virtio.c similarity index 94% rename from drivers/firmware/arm_scmi/virtio.c rename to drivers/firmware/arm_scmi/transports/virtio.c index e8d38e822c7e..c107579e7fe7 100644 --- a/drivers/firmware/arm_scmi/virtio.c +++ b/drivers/firmware/arm_scmi/transports/virtio.c @@ -4,7 +4,7 @@ * (SCMI). * * Copyright (C) 2020-2022 OpenSynergy. - * Copyright (C) 2021-2022 ARM Ltd. + * Copyright (C) 2021-2024 ARM Ltd. */ /** @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -27,7 +28,7 @@ #include #include -#include "common.h" +#include "../common.h" #define VIRTIO_MAX_RX_TIMEOUT_MS 60000 #define VIRTIO_SCMI_MAX_MSG_SIZE 128 /* Value may be increased. */ @@ -108,6 +109,8 @@ struct scmi_vio_msg { refcount_t users; }; +static struct scmi_transport_core_operations *core; + /* Only one SCMI VirtIO device can possibly exist */ static struct virtio_device *scmi_vdev; @@ -294,8 +297,9 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue) if (msg) { msg->rx_len = length; - scmi_rx_callback(vioch->cinfo, - scmi_msg_ops.read_header(msg->input), msg); + core->rx_callback(vioch->cinfo, + core->msg->read_header(msg->input), + msg); scmi_finalize_message(vioch, msg); } @@ -339,8 +343,9 @@ static void scmi_vio_deferred_tx_worker(struct work_struct *work) * is no more processed elsewhere so no poll_lock needed. */ if (msg->poll_status == VIO_MSG_NOT_POLLED) - scmi_rx_callback(vioch->cinfo, - scmi_msg_ops.read_header(msg->input), msg); + core->rx_callback(vioch->cinfo, + core->msg->read_header(msg->input), + msg); /* Free the processed message once done */ scmi_vio_msg_release(vioch, msg); @@ -366,23 +371,6 @@ static unsigned int virtio_get_max_msg(struct scmi_chan_info *base_cinfo) return vioch->max_msg; } -static int virtio_link_supplier(struct device *dev) -{ - if (!scmi_vdev) { - dev_notice(dev, - "Deferring probe after not finding a bound scmi-virtio device\n"); - return -EPROBE_DEFER; - } - - if (!device_link_add(dev, &scmi_vdev->dev, - DL_FLAG_AUTOREMOVE_CONSUMER)) { - dev_err(dev, "Adding link to supplier virtio device failed\n"); - return -ECANCELED; - } - - return 0; -} - static bool virtio_chan_available(struct device_node *of_node, int idx) { struct scmi_vio_channel *channels, *vioch = NULL; @@ -510,10 +498,10 @@ static int virtio_send_message(struct scmi_chan_info *cinfo, return -EBUSY; } - scmi_msg_ops.tx_prepare(msg->request, xfer); + core->msg->tx_prepare(msg->request, xfer); - sg_init_one(&sg_out, msg->request, scmi_msg_ops.command_size(xfer)); - sg_init_one(&sg_in, msg->input, scmi_msg_ops.response_size(xfer)); + sg_init_one(&sg_out, msg->request, core->msg->command_size(xfer)); + sg_init_one(&sg_in, msg->input, core->msg->response_size(xfer)); spin_lock_irqsave(&vioch->lock, flags); @@ -560,7 +548,7 @@ static void virtio_fetch_response(struct scmi_chan_info *cinfo, struct scmi_vio_msg *msg = xfer->priv; if (msg) - scmi_msg_ops.fetch_response(msg->input, msg->rx_len, xfer); + core->msg->fetch_response(msg->input, msg->rx_len, xfer); } static void virtio_fetch_notification(struct scmi_chan_info *cinfo, @@ -569,7 +557,8 @@ static void virtio_fetch_notification(struct scmi_chan_info *cinfo, struct scmi_vio_msg *msg = xfer->priv; if (msg) - scmi_msg_ops.fetch_notification(msg->input, msg->rx_len, max_len, xfer); + core->msg->fetch_notification(msg->input, msg->rx_len, + max_len, xfer); } /** @@ -669,7 +658,7 @@ static void virtio_mark_txdone(struct scmi_chan_info *cinfo, int ret, * the message we are polling for could be alternatively delivered via usual * IRQs callbacks on another core which happened to have IRQs enabled while we * are actively polling for it here: in such a case it will be handled as such - * by scmi_rx_callback() and the polling loop in the SCMI Core TX path will be + * by rx_callback() and the polling loop in the SCMI Core TX path will be * transparently terminated anyway. * * Return: True once polling has successfully completed. @@ -790,7 +779,6 @@ static bool virtio_poll_done(struct scmi_chan_info *cinfo, } static const struct scmi_transport_ops scmi_virtio_ops = { - .link_supplier = virtio_link_supplier, .chan_available = virtio_chan_available, .chan_setup = virtio_chan_setup, .chan_free = virtio_chan_free, @@ -802,6 +790,23 @@ static const struct scmi_transport_ops scmi_virtio_ops = { .poll_done = virtio_poll_done, }; +static const struct scmi_desc scmi_virtio_desc = { + .ops = &scmi_virtio_ops, + /* for non-realtime virtio devices */ + .max_rx_timeout_ms = VIRTIO_MAX_RX_TIMEOUT_MS, + .max_msg = 0, /* overridden by virtio_get_max_msg() */ + .max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE, + .atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE), +}; + +static const struct of_device_id scmi_of_match[] = { + { .compatible = "arm,scmi-virtio" }, + { /* Sentinel */ }, +}; + +DEFINE_SCMI_TRANSPORT_DRIVER(scmi_virtio, scmi_virtio_driver, scmi_virtio_desc, + scmi_of_match, core); + static int scmi_vio_probe(struct virtio_device *vdev) { struct device *dev = &vdev->dev; @@ -861,14 +866,27 @@ static int scmi_vio_probe(struct virtio_device *vdev) } vdev->priv = channels; + /* Ensure initialized scmi_vdev is visible */ smp_store_mb(scmi_vdev, vdev); + ret = platform_driver_register(&scmi_virtio_driver); + if (ret) { + vdev->priv = NULL; + vdev->config->del_vqs(vdev); + /* Ensure NULLified scmi_vdev is visible */ + smp_store_mb(scmi_vdev, NULL); + + return ret; + } + return 0; } static void scmi_vio_remove(struct virtio_device *vdev) { + platform_driver_unregister(&scmi_virtio_driver); + /* * Once we get here, virtio_chan_free() will have already been called by * the SCMI core for any existing channel and, as a consequence, all the @@ -913,23 +931,10 @@ static struct virtio_driver virtio_scmi_driver = { .validate = scmi_vio_validate, }; -static int __init virtio_scmi_init(void) -{ - return register_virtio_driver(&virtio_scmi_driver); -} +module_virtio_driver(virtio_scmi_driver); -static void virtio_scmi_exit(void) -{ - unregister_virtio_driver(&virtio_scmi_driver); -} - -const struct scmi_desc scmi_virtio_desc = { - .transport_init = virtio_scmi_init, - .transport_exit = virtio_scmi_exit, - .ops = &scmi_virtio_ops, - /* for non-realtime virtio devices */ - .max_rx_timeout_ms = VIRTIO_MAX_RX_TIMEOUT_MS, - .max_msg = 0, /* overridden by virtio_get_max_msg() */ - .max_msg_size = VIRTIO_SCMI_MAX_MSG_SIZE, - .atomic_enabled = IS_ENABLED(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE), -}; +MODULE_AUTHOR("Igor Skalkin "); +MODULE_AUTHOR("Peter Hilber "); +MODULE_AUTHOR("Cristian Marussi "); +MODULE_DESCRIPTION("SCMI VirtIO Transport driver"); +MODULE_LICENSE("GPL"); From fc789363c9f095eda0ccbb57b179dba398a4b5b9 Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:33:40 +0100 Subject: [PATCH 068/212] firmware: arm_scmi: Remove legacy transport-layer code Since all SCMI transports have been made standalone drivers, remove all the core SCMI stack legacy support that was needed to run transports as built into the stack. Signed-off-by: Cristian Marussi Message-Id: <20240812173340.3912830-10-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/common.h | 18 ------ drivers/firmware/arm_scmi/driver.c | 98 +++++------------------------- drivers/firmware/arm_scmi/msg.c | 2 +- drivers/firmware/arm_scmi/shmem.c | 2 +- 4 files changed, 16 insertions(+), 104 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 7a53412fc41c..e44f7d1b4417 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -183,7 +183,6 @@ struct scmi_chan_info { /** * struct scmi_transport_ops - Structure representing a SCMI transport ops * - * @link_supplier: Optional callback to add link to a supplier device * @chan_available: Callback to check if channel is available or not * @chan_setup: Callback to allocate and setup a channel * @chan_free: Callback to free a channel @@ -198,7 +197,6 @@ struct scmi_chan_info { * @poll_done: Callback to poll transfer status */ struct scmi_transport_ops { - int (*link_supplier)(struct device *dev); bool (*chan_available)(struct device_node *of_node, int idx); int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev, bool tx); @@ -219,12 +217,6 @@ struct scmi_transport_ops { /** * struct scmi_desc - Description of SoC integration * - * @transport_init: An optional function that a transport can provide to - * initialize some transport-specific setup during SCMI core - * initialization, so ahead of SCMI core probing. - * @transport_exit: An optional function that a transport can provide to - * de-initialize some transport-specific setup during SCMI core - * de-initialization, so after SCMI core removal. * @ops: Pointer to the transport specific ops structure * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds) * @max_msg: Maximum number of messages for a channel type (tx or rx) that can @@ -245,8 +237,6 @@ struct scmi_transport_ops { * when requested. */ struct scmi_desc { - int (*transport_init)(void); - void (*transport_exit)(void); const struct scmi_transport_ops *ops; int max_rx_timeout_ms; int max_msg; @@ -287,8 +277,6 @@ int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer, unsigned int timeout_ms); -void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv); - enum debug_counters { SENT_OK, SENT_FAIL, @@ -321,9 +309,6 @@ enum scmi_bad_msg { 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; @@ -472,9 +457,6 @@ static struct platform_driver __drv = { \ .probe = __tag##_probe, \ } -extern const struct scmi_shared_mem_operations scmi_shmem_ops; -extern const struct scmi_message_operations scmi_msg_ops; - void scmi_notification_instance_data_set(const struct scmi_handle *handle, void *priv); void *scmi_notification_instance_data_get(const struct scmi_handle *handle); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 12643b4c0db3..119c9b6ae3c1 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -11,7 +11,7 @@ * various power domain DVFS including the core/cluster, certain system * clocks configuration, thermal sensors and many others. * - * Copyright (C) 2018-2021 ARM Ltd. + * Copyright (C) 2018-2024 ARM Ltd. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -196,6 +196,11 @@ struct scmi_info { #define bus_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, bus_nb) #define req_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, dev_req_nb) +static void scmi_rx_callback(struct scmi_chan_info *cinfo, + u32 msg_hdr, void *priv); +static void scmi_bad_message_trace(struct scmi_chan_info *cinfo, + u32 msg_hdr, enum scmi_bad_msg err); + static struct scmi_transport_core_operations scmi_trans_core_ops = { .bad_message_trace = scmi_bad_message_trace, .rx_callback = scmi_rx_callback, @@ -840,8 +845,8 @@ scmi_xfer_lookup_unlocked(struct scmi_xfers_info *minfo, u16 xfer_id) * timed-out message that arrives and as such, can be traced only referring to * the header content, since the payload is missing/unreliable. */ -void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, - enum scmi_bad_msg err) +static void scmi_bad_message_trace(struct scmi_chan_info *cinfo, u32 msg_hdr, + enum scmi_bad_msg err) { char *tag; struct scmi_info *info = handle_to_scmi_info(cinfo->handle); @@ -1174,7 +1179,8 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo, * NOTE: This function will be invoked in IRQ context, hence should be * as optimal as possible. */ -void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv) +static void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, + void *priv) { u8 msg_type = MSG_XTRACT_TYPE(msg_hdr); @@ -3055,14 +3061,11 @@ static int scmi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *child, *np = dev->of_node; - desc = of_device_get_match_data(dev); + desc = scmi_transport_setup(dev); if (!desc) { - desc = scmi_transport_setup(dev); - if (!desc) { - err_str = "transport invalid\n"; - ret = -EINVAL; - goto out_err; - } + err_str = "transport invalid\n"; + ret = -EINVAL; + goto out_err; } info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); @@ -3102,14 +3105,6 @@ static int scmi_probe(struct platform_device *pdev) info->atomic_threshold); handle->is_transport_atomic = scmi_is_transport_atomic; - if (desc->ops->link_supplier) { - ret = desc->ops->link_supplier(dev); - if (ret) { - err_str = "transport not ready\n"; - goto clear_ida; - } - } - /* Setup all channels described in the DT at first */ ret = scmi_channels_setup(info); if (ret) { @@ -3316,72 +3311,16 @@ static struct attribute *versions_attrs[] = { }; ATTRIBUTE_GROUPS(versions); -/* Each compatible listed below must have descriptor associated with it */ -static const struct of_device_id scmi_of_match[] = { - { /* Sentinel */ }, -}; - -MODULE_DEVICE_TABLE(of, scmi_of_match); - static struct platform_driver scmi_driver = { .driver = { .name = "arm-scmi", .suppress_bind_attrs = true, - .of_match_table = scmi_of_match, .dev_groups = versions_groups, }, .probe = scmi_probe, .remove_new = scmi_remove, }; -/** - * __scmi_transports_setup - Common helper to call transport-specific - * .init/.exit code if provided. - * - * @init: A flag to distinguish between init and exit. - * - * Note that, if provided, we invoke .init/.exit functions for all the - * transports currently compiled in. - * - * Return: 0 on Success. - */ -static inline int __scmi_transports_setup(bool init) -{ - int ret = 0; - const struct of_device_id *trans; - - for (trans = scmi_of_match; trans->data; trans++) { - const struct scmi_desc *tdesc = trans->data; - - if ((init && !tdesc->transport_init) || - (!init && !tdesc->transport_exit)) - continue; - - if (init) - ret = tdesc->transport_init(); - else - tdesc->transport_exit(); - - if (ret) { - pr_err("SCMI transport %s FAILED initialization!\n", - trans->compatible); - break; - } - } - - return ret; -} - -static int __init scmi_transports_init(void) -{ - return __scmi_transports_setup(true); -} - -static void __exit scmi_transports_exit(void) -{ - __scmi_transports_setup(false); -} - static struct dentry *scmi_debugfs_init(void) { struct dentry *d; @@ -3397,17 +3336,10 @@ static struct dentry *scmi_debugfs_init(void) static int __init scmi_driver_init(void) { - int ret; - /* Bail out if no SCMI transport was configured */ if (WARN_ON(!IS_ENABLED(CONFIG_ARM_SCMI_HAVE_TRANSPORT))) return -EINVAL; - /* Initialize any compiled-in transport which provided an init/exit */ - ret = scmi_transports_init(); - if (ret) - return ret; - if (IS_ENABLED(CONFIG_ARM_SCMI_HAVE_SHMEM)) scmi_trans_core_ops.shmem = scmi_shared_mem_operations_get(); @@ -3447,8 +3379,6 @@ static void __exit scmi_driver_exit(void) scmi_powercap_unregister(); scmi_pinctrl_unregister(); - scmi_transports_exit(); - platform_driver_unregister(&scmi_driver); debugfs_remove_recursive(scmi_top_dentry); diff --git a/drivers/firmware/arm_scmi/msg.c b/drivers/firmware/arm_scmi/msg.c index 18337f9191d0..2cc74e6bbd72 100644 --- a/drivers/firmware/arm_scmi/msg.c +++ b/drivers/firmware/arm_scmi/msg.c @@ -110,7 +110,7 @@ static void msg_fetch_notification(struct scmi_msg_payld *msg, size_t len, memcpy(xfer->rx.buf, msg->msg_payload, xfer->rx.len); } -const struct scmi_message_operations scmi_msg_ops = { +static const struct scmi_message_operations scmi_msg_ops = { .tx_prepare = msg_tx_prepare, .command_size = msg_command_size, .response_size = msg_response_size, diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index 3fba05e1560c..01d8a9398fe8 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -176,7 +176,7 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo, return addr; } -const struct scmi_shared_mem_operations scmi_shmem_ops = { +static const struct scmi_shared_mem_operations scmi_shmem_ops = { .tx_prepare = shmem_tx_prepare, .read_header = shmem_read_header, .fetch_response = shmem_fetch_response, From be9f086524b3ea17c27fb4cd57115bf873354791 Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Mon, 12 Aug 2024 18:40:27 +0100 Subject: [PATCH 069/212] firmware: arm_scmi: Update various protocols versions A few protocol versions had been increased with SCMI v3.2. Update accordingly the supported version define in the kernel stack, since all the mandatory base commands are indeed already supported. Signed-off-by: Cristian Marussi Message-Id: <20240812174027.3931160-1-cristian.marussi@arm.com> Reviewed-by: Dhruva Gole Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/base.c | 2 +- drivers/firmware/arm_scmi/power.c | 2 +- drivers/firmware/arm_scmi/reset.c | 2 +- drivers/firmware/arm_scmi/sensors.c | 2 +- drivers/firmware/arm_scmi/system.c | 2 +- drivers/firmware/arm_scmi/voltage.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index 97254de35ab0..9939b1d84b7a 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -14,7 +14,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 0x20001 #define SCMI_BASE_NUM_SOURCES 1 #define SCMI_BASE_MAX_CMD_ERR_COUNT 1024 diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 49666bd1d8ac..59aa16444c64 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -14,7 +14,7 @@ #include "notify.h" /* Updated only after ALL the mandatory features for that version are merged */ -#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001 enum scmi_power_protocol_cmd { POWER_DOMAIN_ATTRIBUTES = 0x3, diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index 1b318316535e..0aa82b96f41b 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -14,7 +14,7 @@ #include "notify.h" /* Updated only after ALL the mandatory features for that version are merged */ -#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001 enum scmi_reset_protocol_cmd { RESET_DOMAIN_ATTRIBUTES = 0x3, diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index 7fc5535ca34c..791efd0f82d7 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -15,7 +15,7 @@ #include "notify.h" /* Updated only after ALL the mandatory features for that version are merged */ -#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30001 #define SCMI_MAX_NUM_SENSOR_AXIS 63 #define SCMIv2_SENSOR_PROTOCOL 0x10000 diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c index b6358c155f7f..ec3d355d1772 100644 --- a/drivers/firmware/arm_scmi/system.c +++ b/drivers/firmware/arm_scmi/system.c @@ -14,7 +14,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 0x20001 #define SCMI_SYSTEM_NUM_SOURCES 1 diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c index f1a7c04ae820..fda6a1573609 100644 --- a/drivers/firmware/arm_scmi/voltage.c +++ b/drivers/firmware/arm_scmi/voltage.c @@ -11,7 +11,7 @@ #include "protocols.h" /* Updated only after ALL the mandatory features for that version are merged */ -#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001 #define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0) #define REMAINING_LEVELS_MASK GENMASK(31, 16) From a8bd37e645602afcafc9d5f428c10aeda606b279 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 17:14:07 +0200 Subject: [PATCH 070/212] firmware: arm_scmi: Simplify with scoped for each OF child loop Use scoped for_each_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Cristian Marussi Message-Id: <20240816151407.155034-1-krzysztof.kozlowski@linaro.org> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 119c9b6ae3c1..918d7287ecf4 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -2733,14 +2733,14 @@ scmi_txrx_setup(struct scmi_info *info, struct device_node *of_node, static int scmi_channels_setup(struct scmi_info *info) { int ret; - struct device_node *child, *top_np = info->dev->of_node; + struct device_node *top_np = info->dev->of_node; /* Initialize a common generic channel at first */ ret = scmi_txrx_setup(info, top_np, SCMI_PROTOCOL_BASE); if (ret) return ret; - for_each_available_child_of_node(top_np, child) { + for_each_available_child_of_node_scoped(top_np, child) { u32 prot_id; if (of_property_read_u32(child, "reg", &prot_id)) @@ -2751,10 +2751,8 @@ static int scmi_channels_setup(struct scmi_info *info) "Out of range protocol %d\n", prot_id); ret = scmi_txrx_setup(info, child, prot_id); - if (ret) { - of_node_put(child); + if (ret) return ret; - } } return 0; From 668f0cb2337f9fc5536a0880a8e13cc735efa00d Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Tue, 30 Jul 2024 15:47:02 +0100 Subject: [PATCH 071/212] firmware: arm_scmi: Remove const from transport descriptors The descriptor structure scmi_desc contains a variety of fields related to the transport functionalities and it is defined by the transport drivers themselves; such elements, though, serve varied purposes and have different lifetime. In particular, while there are some of those elements that provide a description of transport features that are supposed to be immutable, on the other side there are present also some other characteristics that are instead supposed to be configurable on a per-platform base since they represent configuration features tied to the specific hardware/firmware system. The immutable fields are already qualified as const on the their own; get rid of the structure-level const qualifier which is not needed, so as to enable possible runtime customization of the mutable configuration features. No functional change. Signed-off-by: Cristian Marussi Tested-by: Peng Fan #i.MX95 19x19 EVK Message-Id: <20240730144707.1647025-2-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/common.h | 2 +- drivers/firmware/arm_scmi/transports/mailbox.c | 2 +- drivers/firmware/arm_scmi/transports/optee.c | 2 +- drivers/firmware/arm_scmi/transports/smc.c | 2 +- drivers/firmware/arm_scmi/transports/virtio.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index e44f7d1b4417..6d9227db473f 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -405,7 +405,7 @@ struct scmi_transport_core_operations { */ struct scmi_transport { struct device *supplier; - const struct scmi_desc *desc; + struct scmi_desc *desc; struct scmi_transport_core_operations **core_ops; }; diff --git a/drivers/firmware/arm_scmi/transports/mailbox.c b/drivers/firmware/arm_scmi/transports/mailbox.c index 917f9b8918d6..a481a2866062 100644 --- a/drivers/firmware/arm_scmi/transports/mailbox.c +++ b/drivers/firmware/arm_scmi/transports/mailbox.c @@ -355,7 +355,7 @@ static const struct scmi_transport_ops scmi_mailbox_ops = { .poll_done = mailbox_poll_done, }; -static const struct scmi_desc scmi_mailbox_desc = { +static struct scmi_desc scmi_mailbox_desc = { .ops = &scmi_mailbox_ops, .max_rx_timeout_ms = 30, /* We may increase this if required */ .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c index 978750aaf6b7..56fc63edf51e 100644 --- a/drivers/firmware/arm_scmi/transports/optee.c +++ b/drivers/firmware/arm_scmi/transports/optee.c @@ -510,7 +510,7 @@ static int scmi_optee_ctx_match(struct tee_ioctl_version_data *ver, const void * return ver->impl_id == TEE_IMPL_ID_OPTEE; } -static const struct scmi_desc scmi_optee_desc = { +static struct scmi_desc scmi_optee_desc = { .ops = &scmi_optee_ops, .max_rx_timeout_ms = 30, .max_msg = 20, diff --git a/drivers/firmware/arm_scmi/transports/smc.c b/drivers/firmware/arm_scmi/transports/smc.c index 6fc3e1973c58..b7243939f161 100644 --- a/drivers/firmware/arm_scmi/transports/smc.c +++ b/drivers/firmware/arm_scmi/transports/smc.c @@ -273,7 +273,7 @@ static const struct scmi_transport_ops scmi_smc_ops = { .fetch_response = smc_fetch_response, }; -static const struct scmi_desc scmi_smc_desc = { +static struct scmi_desc scmi_smc_desc = { .ops = &scmi_smc_ops, .max_rx_timeout_ms = 30, .max_msg = 20, diff --git a/drivers/firmware/arm_scmi/transports/virtio.c b/drivers/firmware/arm_scmi/transports/virtio.c index c107579e7fe7..d349766bc0b2 100644 --- a/drivers/firmware/arm_scmi/transports/virtio.c +++ b/drivers/firmware/arm_scmi/transports/virtio.c @@ -790,7 +790,7 @@ static const struct scmi_transport_ops scmi_virtio_ops = { .poll_done = virtio_poll_done, }; -static const struct scmi_desc scmi_virtio_desc = { +static struct scmi_desc scmi_virtio_desc = { .ops = &scmi_virtio_ops, /* for non-realtime virtio devices */ .max_rx_timeout_ms = VIRTIO_MAX_RX_TIMEOUT_MS, From 3a5e6ab06eabcf105a83199be09453ff1475e77e Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 30 Jul 2024 15:47:03 +0100 Subject: [PATCH 072/212] dt-bindings: firmware: arm,scmi: Introduce property max-rx-timeout-ms System Controller Management Interface(SCMI) firmwares might have different designs depending on the platform: the maximum receive channel timeout value might vary depending on the specific underlying hardware and firmware design choices. Introduce the general property max-rx-timeout-ms property to describe the transport needs of a specific platform design. Reviewed-by: Rob Herring (Arm) Signed-off-by: Peng Fan [Cristian: reworded commit message, s/mailbox/transport in description] Signed-off-by: Cristian Marussi Tested-by: Peng Fan #i.MX95 19x19 EVK Message-Id: <20240730144707.1647025-3-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml index ebf384e76df1..211f5254adf2 100644 --- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml +++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml @@ -121,6 +121,13 @@ properties: atomic mode of operation, even if requested. default: 0 + max-rx-timeout-ms: + description: + An optional time value, expressed in milliseconds, representing the + transport maximum timeout value for the receive channel. The value should + be a non-zero value if set. + minimum: 1 + arm,smc-id: $ref: /schemas/types.yaml#/definitions/uint32 description: From 1780e411ef940db314578b511518e5872d4a13b4 Mon Sep 17 00:00:00 2001 From: Cristian Marussi Date: Tue, 30 Jul 2024 15:47:04 +0100 Subject: [PATCH 073/212] firmware: arm_scmi: Use max-rx-timeout-ms from devicetree Override default maximum RX timeout with the value picked from the devicetree, when provided. Suggested-by: Peng Fan Signed-off-by: Cristian Marussi Tested-by: Peng Fan #i.MX95 19x19 EVK Message-Id: <20240730144707.1647025-4-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 918d7287ecf4..66806578df5a 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -3029,6 +3029,7 @@ static int scmi_debugfs_raw_mode_setup(struct scmi_info *info) static const struct scmi_desc *scmi_transport_setup(struct device *dev) { struct scmi_transport *trans; + int ret; trans = dev_get_platdata(dev); if (!trans || !trans->desc || !trans->supplier || !trans->core_ops) @@ -3045,6 +3046,14 @@ static const struct scmi_desc *scmi_transport_setup(struct device *dev) dev_info(dev, "Using %s\n", dev_driver_string(trans->supplier)); + ret = of_property_read_u32(dev->of_node, "max-rx-timeout-ms", + &trans->desc->max_rx_timeout_ms); + if (ret && ret != -EINVAL) + dev_err(dev, "Malformed max-rx-timeout-ms DT property.\n"); + + dev_info(dev, "SCMI max-rx-timeout: %dms\n", + trans->desc->max_rx_timeout_ms); + return trans->desc; } From 84236ed0a2b1d40a0b72e8dde4b18d641263f5f9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 18 Aug 2024 19:28:04 +0200 Subject: [PATCH 074/212] dt-bindings: samsung: exynos-usi: add missing constraints Properties with variable number of items per each device are expected to have widest constraints in top-level "properties:" block and further customized (narrowed) in "if:then:". Add missing top-level constraints for reg, clocks and clock-names. Reviewed-by: Sam Protsenko Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240818172804.121666-1-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/soc/samsung/exynos-usi.yaml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml index 8b478d6cdc30..f80fcbc3128b 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml @@ -32,11 +32,16 @@ properties: - enum: - samsung,exynos850-usi - reg: true + reg: + maxItems: 1 - clocks: true + clocks: + maxItems: 2 - clock-names: true + clock-names: + items: + - const: pclk + - const: ipclk ranges: true @@ -113,9 +118,7 @@ then: - description: Operating clock for UART/SPI/I2C protocol clock-names: - items: - - const: pclk - - const: ipclk + maxItems: 2 required: - reg From fbbb0e5fd260dbc54df519b6d8e5b970274e9582 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 20 Aug 2024 15:27:54 +0100 Subject: [PATCH 075/212] firmware: arm_ffa: Some coding style fixes These changes fixes a set of below coding style issues: 1. spaces required around that '=' (ctx:VxW) 2. possible unnecessary 'out of memory' message 3. unnecessary for single statement blocks Message-Id: <20240820-ffa_v1-2-v2-1-18c0c5f3c65e@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 7ba98c7af2e9..b4b3ecc9824e 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1242,7 +1242,7 @@ ffa_bus_notifier(struct notifier_block *nb, unsigned long action, void *data) if (action == BUS_NOTIFY_BIND_DRIVER) { struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver); - const struct ffa_device_id *id_table= ffa_drv->id_table; + const struct ffa_device_id *id_table = ffa_drv->id_table; /* * FF-A v1.1 provides UUID for each partition as part of the @@ -1327,8 +1327,6 @@ static int ffa_setup_partitions(void) /* Allocate for the host */ info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { - pr_err("%s: failed to alloc Host partition ID 0x%x. Abort.\n", - __func__, drv_info->vm_id); /* Already registered devices are freed on bus_exit */ ffa_partitions_cleanup(); return -ENOMEM; @@ -1609,9 +1607,8 @@ static int __init ffa_init(void) return ret; drv_info = kzalloc(sizeof(*drv_info), GFP_KERNEL); - if (!drv_info) { + if (!drv_info) return -ENOMEM; - } ret = ffa_version_check(&drv_info->version); if (ret) From 7c432a18ad216b4f7b08e93287586d60e12a3b7b Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 20 Aug 2024 15:27:55 +0100 Subject: [PATCH 076/212] firmware: arm_ffa: Update the FF-A command list with v1.2 additions Arm Firmware Framework for A-profile(FFA) v1.2 introduces register based discovery mechanism and direct messaging extensions that enables to target specific UUID within a partition. Let us add all the newly supported FF-A function IDs in the spec. Also update to the error values and associated handling. Message-Id: <20240820-ffa_v1-2-v2-2-18c0c5f3c65e@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 1 + include/linux/arm_ffa.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index b4b3ecc9824e..be77e03578cc 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -75,6 +75,7 @@ static const int ffa_linux_errmap[] = { -EAGAIN, /* FFA_RET_RETRY */ -ECANCELED, /* FFA_RET_ABORTED */ -ENODATA, /* FFA_RET_NO_DATA */ + -EAGAIN, /* FFA_RET_NOT_READY */ }; static inline int ffa_to_linux_errno(int errno) diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index 89683f31ae12..b34f0c0dc2c5 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -73,6 +73,11 @@ #define FFA_FN64_MEM_PERM_GET FFA_SMC_64(0x88) #define FFA_MEM_PERM_SET FFA_SMC_32(0x89) #define FFA_FN64_MEM_PERM_SET FFA_SMC_64(0x89) +#define FFA_CONSOLE_LOG FFA_SMC_32(0x8A) +#define FFA_PARTITION_INFO_GET_REGS FFA_SMC_64(0x8B) +#define FFA_EL3_INTR_HANDLE FFA_SMC_32(0x8C) +#define FFA_MSG_SEND_DIRECT_REQ2 FFA_SMC_64(0x8D) +#define FFA_MSG_SEND_DIRECT_RESP2 FFA_SMC_64(0x8E) /* * For some calls it is necessary to use SMC64 to pass or return 64-bit values. From d37fff98262ddca6b6ef3b63f378136c04067c64 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 20 Aug 2024 15:27:56 +0100 Subject: [PATCH 077/212] firmware: arm_ffa: Move the function ffa_features() earlier We need to use ffa_features() in ffa_partition_probe() to detect if the newer FFA_PARTITION_INFO_GET_REGS API is supported in the platform or not. To avoid unnecessary forward declaration within the file, let us just move this ffa_features() earlier. No funtional change. Message-Id: <20240820-ffa_v1-2-v2-3-18c0c5f3c65e@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 52 +++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index be77e03578cc..91681933ece9 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -212,6 +212,32 @@ static int ffa_rxtx_unmap(u16 vm_id) return 0; } +static int ffa_features(u32 func_feat_id, u32 input_props, + u32 *if_props_1, u32 *if_props_2) +{ + ffa_value_t id; + + if (!ARM_SMCCC_IS_FAST_CALL(func_feat_id) && input_props) { + pr_err("%s: Invalid Parameters: %x, %x", __func__, + func_feat_id, input_props); + return ffa_to_linux_errno(FFA_RET_INVALID_PARAMETERS); + } + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_FEATURES, .a1 = func_feat_id, .a2 = input_props, + }, &id); + + if (id.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)id.a2); + + if (if_props_1) + *if_props_1 = id.a2; + if (if_props_2) + *if_props_2 = id.a3; + + return 0; +} + #define PARTITION_INFO_GET_RETURN_COUNT_ONLY BIT(0) /* buffer must be sizeof(struct ffa_partition_info) * num_partitions */ @@ -598,32 +624,6 @@ static int ffa_memory_reclaim(u64 g_handle, u32 flags) return 0; } -static int ffa_features(u32 func_feat_id, u32 input_props, - u32 *if_props_1, u32 *if_props_2) -{ - ffa_value_t id; - - if (!ARM_SMCCC_IS_FAST_CALL(func_feat_id) && input_props) { - pr_err("%s: Invalid Parameters: %x, %x", __func__, - func_feat_id, input_props); - return ffa_to_linux_errno(FFA_RET_INVALID_PARAMETERS); - } - - invoke_ffa_fn((ffa_value_t){ - .a0 = FFA_FEATURES, .a1 = func_feat_id, .a2 = input_props, - }, &id); - - if (id.a0 == FFA_ERROR) - return ffa_to_linux_errno((int)id.a2); - - if (if_props_1) - *if_props_1 = id.a2; - if (if_props_2) - *if_props_2 = id.a3; - - return 0; -} - static int ffa_notification_bitmap_create(void) { ffa_value_t ret; From ba85c644ac8dc37d9b01a3332c2f142cb4d46954 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 20 Aug 2024 15:27:57 +0100 Subject: [PATCH 078/212] firmware: arm_ffa: Add support for FFA_PARTITION_INFO_GET_REGS FF-A v1.2 introduced FFA_PARTITION_INFO_GET_REGS which is similar to FFA_PARTITION_INFO_GET except that the former uses the registers to get the required information instead of the Rx buffer which the latter uses. We need to first check if the platform supports this new API using FFA_FEATURES so that we can fallback to the FFA_PARTITION_INFO_GET (which is mandatory) if FFA_PARTITION_INFO_GET_REGS is not implemented. Message-Id: <20240820-ffa_v1-2-v2-4-18c0c5f3c65e@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 72 +++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 91681933ece9..e28cbfe9a801 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -287,17 +287,75 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, return count; } +#define LAST_INDEX_MASK GENMASK(15, 0) +#define CURRENT_INDEX_MASK GENMASK(31, 16) +#define UUID_INFO_TAG_MASK GENMASK(47, 32) +#define PARTITION_INFO_SZ_MASK GENMASK(63, 48) +#define PARTITION_COUNT(x) ((u16)(FIELD_GET(LAST_INDEX_MASK, (x))) + 1) +#define CURRENT_INDEX(x) ((u16)(FIELD_GET(CURRENT_INDEX_MASK, (x)))) +#define UUID_INFO_TAG(x) ((u16)(FIELD_GET(UUID_INFO_TAG_MASK, (x)))) +#define PARTITION_INFO_SZ(x) ((u16)(FIELD_GET(PARTITION_INFO_SZ_MASK, (x)))) +static int +__ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3, + struct ffa_partition_info *buffer, int num_parts) +{ + u16 buf_sz, start_idx, cur_idx, count = 0, prev_idx = 0, tag = 0; + ffa_value_t partition_info; + + do { + start_idx = prev_idx ? prev_idx + 1 : 0; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_PARTITION_INFO_GET_REGS, + .a1 = (u64)uuid1 << 32 | uuid0, + .a2 = (u64)uuid3 << 32 | uuid2, + .a3 = start_idx | tag << 16, + }, &partition_info); + + if (partition_info.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)partition_info.a2); + + if (!count) + count = PARTITION_COUNT(partition_info.a2); + if (!buffer || !num_parts) /* count only */ + return count; + + cur_idx = CURRENT_INDEX(partition_info.a2); + tag = UUID_INFO_TAG(partition_info.a2); + buf_sz = PARTITION_INFO_SZ(partition_info.a2); + if (buf_sz > sizeof(*buffer)) + buf_sz = sizeof(*buffer); + + memcpy(buffer + prev_idx * buf_sz, &partition_info.a3, + (cur_idx - start_idx + 1) * buf_sz); + prev_idx = cur_idx; + + } while (cur_idx < (count - 1)); + + return count; +} + /* buffer is allocated and caller must free the same if returned count > 0 */ static int ffa_partition_probe(const uuid_t *uuid, struct ffa_partition_info **buffer) { int count; u32 uuid0_4[4]; + bool reg_mode = false; struct ffa_partition_info *pbuf; + if (!ffa_features(FFA_PARTITION_INFO_GET_REGS, 0, NULL, NULL)) + reg_mode = true; + export_uuid((u8 *)uuid0_4, uuid); - count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2], - uuid0_4[3], NULL, 0); + if (reg_mode) + count = __ffa_partition_info_get_regs(uuid0_4[0], uuid0_4[1], + uuid0_4[2], uuid0_4[3], + NULL, 0); + else + count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], + uuid0_4[2], uuid0_4[3], + NULL, 0); if (count <= 0) return count; @@ -305,8 +363,14 @@ ffa_partition_probe(const uuid_t *uuid, struct ffa_partition_info **buffer) if (!pbuf) return -ENOMEM; - count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], uuid0_4[2], - uuid0_4[3], pbuf, count); + if (reg_mode) + count = __ffa_partition_info_get_regs(uuid0_4[0], uuid0_4[1], + uuid0_4[2], uuid0_4[3], + pbuf, count); + else + count = __ffa_partition_info_get(uuid0_4[0], uuid0_4[1], + uuid0_4[2], uuid0_4[3], + pbuf, count); if (count <= 0) kfree(pbuf); else From aaef3bc98129c86078b336f16788dd733b0728a4 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 20 Aug 2024 15:27:58 +0100 Subject: [PATCH 079/212] firmware: arm_ffa: Add support for FFA_MSG_SEND_DIRECT_{REQ,RESP}2 FFA_MSG_SEND_DIRECT_{REQ,RESP} supported only x3-x7 to pass implementation defined values as part of the message. This may not be sufficient sometimes and also it would be good to use all the registers supported by SMCCC v1.2 (x0-x17) for such register based communication. Also another limitation with the FFA_MSG_SEND_DIRECT_{REQ,RESP} is the ability to target a specific service within the partition based on it's UUID. In order to address both of the above limitation, FF-A v1.2 introduced FFA_MSG_SEND_DIRECT_{REQ,RESP}2 which has the ability to target the message to a specific service based on its UUID within a partition as well as utilise all the available registers(x4-x17 specifically) for the communication. This change adds support for FFA_MSG_SEND_DIRECT_REQ2 and FFA_MSG_SEND_DIRECT_RESP2. Message-Id: <20240820-ffa_v1-2-v2-5-18c0c5f3c65e@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 49 +++++++++++++++++++++++++++++-- include/linux/arm_ffa.h | 7 +++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index e28cbfe9a801..ec99fed5715d 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -99,6 +99,7 @@ struct ffa_drv_info { void *rx_buffer; void *tx_buffer; bool mem_ops_native; + bool msg_direct_req2_supp; bool bitmap_created; bool notif_enabled; unsigned int sched_recv_irq; @@ -468,6 +469,35 @@ static int ffa_msg_send2(u16 src_id, u16 dst_id, void *buf, size_t sz) return retval; } +static int ffa_msg_send_direct_req2(u16 src_id, u16 dst_id, const uuid_t *uuid, + struct ffa_send_direct_data2 *data) +{ + u32 src_dst_ids = PACK_TARGET_INFO(src_id, dst_id); + ffa_value_t ret, args = { + .a0 = FFA_MSG_SEND_DIRECT_REQ2, .a1 = src_dst_ids, + }; + + export_uuid((u8 *)&args.a2, uuid); + memcpy((void *)&args + offsetof(ffa_value_t, a4), data, sizeof(*data)); + + invoke_ffa_fn(args, &ret); + + while (ret.a0 == FFA_INTERRUPT) + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_RUN, .a1 = ret.a1, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + if (ret.a0 == FFA_MSG_SEND_DIRECT_RESP2) { + memcpy(data, &ret.a4, sizeof(*data)); + return 0; + } + + return -EINVAL; +} + static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz, u32 frag_len, u32 len, u64 *handle) { @@ -923,11 +953,15 @@ static int ffa_run(struct ffa_device *dev, u16 vcpu) return 0; } -static void ffa_set_up_mem_ops_native_flag(void) +static void ffa_drvinfo_flags_init(void) { if (!ffa_features(FFA_FN_NATIVE(MEM_LEND), 0, NULL, NULL) || !ffa_features(FFA_FN_NATIVE(MEM_SHARE), 0, NULL, NULL)) drv_info->mem_ops_native = true; + + if (!ffa_features(FFA_MSG_SEND_DIRECT_REQ2, 0, NULL, NULL) || + !ffa_features(FFA_MSG_SEND_DIRECT_RESP2, 0, NULL, NULL)) + drv_info->msg_direct_req2_supp = true; } static u32 ffa_api_version_get(void) @@ -973,6 +1007,16 @@ static int ffa_indirect_msg_send(struct ffa_device *dev, void *buf, size_t sz) return ffa_msg_send2(drv_info->vm_id, dev->vm_id, buf, sz); } +static int ffa_sync_send_receive2(struct ffa_device *dev, const uuid_t *uuid, + struct ffa_send_direct_data2 *data) +{ + if (!drv_info->msg_direct_req2_supp) + return -EOPNOTSUPP; + + return ffa_msg_send_direct_req2(drv_info->vm_id, dev->vm_id, + uuid, data); +} + static int ffa_memory_share(struct ffa_mem_ops_args *args) { if (drv_info->mem_ops_native) @@ -1256,6 +1300,7 @@ static const struct ffa_msg_ops ffa_drv_msg_ops = { .mode_32bit_set = ffa_mode_32bit_set, .sync_send_receive = ffa_sync_send_receive, .indirect_send = ffa_indirect_msg_send, + .sync_send_receive2 = ffa_sync_send_receive2, }; static const struct ffa_mem_ops ffa_drv_mem_ops = { @@ -1708,7 +1753,7 @@ static int __init ffa_init(void) mutex_init(&drv_info->rx_lock); mutex_init(&drv_info->tx_lock); - ffa_set_up_mem_ops_native_flag(); + ffa_drvinfo_flags_init(); ffa_notifications_setup(); diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h index b34f0c0dc2c5..a28e2a6a13d0 100644 --- a/include/linux/arm_ffa.h +++ b/include/linux/arm_ffa.h @@ -270,6 +270,11 @@ struct ffa_indirect_msg_hdr { u32 size; }; +/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP}2 which pass data via registers */ +struct ffa_send_direct_data2 { + unsigned long data[14]; /* x4-x17 */ +}; + struct ffa_mem_region_addr_range { /* The base IPA of the constituent memory region, aligned to 4 kiB */ u64 address; @@ -431,6 +436,8 @@ struct ffa_msg_ops { int (*sync_send_receive)(struct ffa_device *dev, struct ffa_send_direct_data *data); int (*indirect_send)(struct ffa_device *dev, void *buf, size_t sz); + int (*sync_send_receive2)(struct ffa_device *dev, const uuid_t *uuid, + struct ffa_send_direct_data2 *data); }; struct ffa_mem_ops { From eaca7ef8f31a9040021683d381ddb83eb6fd7774 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 20 Aug 2024 15:27:59 +0100 Subject: [PATCH 080/212] firmware: arm_ffa: Add support for FFA_YIELD in direct messaging Successful completion of both direct messaging function can be indicated through an invocation of FFA_YIELD or GGA_INTERRUPT by the callee. FFA_INTERRUPT indicates that the direct request was interrupted and must be resumed through the FFA_RUN interface which is already done in the driver. FFA_YIELD indicates that the receiver endpoint has transitioned to the blocked runtime state and must be resumed through the FFA_RUN interface. However, the way receiver endpoint gets unblocked is implementation defined. So, the driver just sleeps for 1 - 2ms and issues FFA_RUN. It can return to the caller with FFA_YIELD is the receiver endpoint is still blocked. Message-Id: <20240820-ffa_v1-2-v2-6-18c0c5f3c65e@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index ec99fed5715d..d47272859190 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -397,6 +398,18 @@ static int ffa_id_get(u16 *vm_id) return 0; } +static inline void ffa_msg_send_wait_for_completion(ffa_value_t *ret) +{ + while (ret->a0 == FFA_INTERRUPT || ret->a0 == FFA_YIELD) { + if (ret->a0 == FFA_YIELD) + fsleep(1000); + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_RUN, .a1 = ret->a1, + }, ret); + } +} + static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit, struct ffa_send_direct_data *data) { @@ -417,10 +430,7 @@ static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit, .a6 = data->data3, .a7 = data->data4, }, &ret); - while (ret.a0 == FFA_INTERRUPT) - invoke_ffa_fn((ffa_value_t){ - .a0 = FFA_RUN, .a1 = ret.a1, - }, &ret); + ffa_msg_send_wait_for_completion(&ret); if (ret.a0 == FFA_ERROR) return ffa_to_linux_errno((int)ret.a2); @@ -482,10 +492,7 @@ static int ffa_msg_send_direct_req2(u16 src_id, u16 dst_id, const uuid_t *uuid, invoke_ffa_fn(args, &ret); - while (ret.a0 == FFA_INTERRUPT) - invoke_ffa_fn((ffa_value_t){ - .a0 = FFA_RUN, .a1 = ret.a1, - }, &ret); + ffa_msg_send_wait_for_completion(&ret); if (ret.a0 == FFA_ERROR) return ffa_to_linux_errno((int)ret.a2); From 61824feae5c07987f70519b1235e50baa138b3c2 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 20 Aug 2024 15:28:00 +0100 Subject: [PATCH 081/212] firmware: arm_ffa: Fetch the Rx/Tx buffer size using ffa_features() An endpoint can discover the minimum size, maximum size and alignment boundary for the Rx/Tx buffers by passing the function ID of the FFA_RXTX_MAP ABI as input in the FFA_FEATURES interface. The maximum size is an optional field and a value of 0 means that the partition manager or the hypervisor does not enforce a maximum size. Use the discovery mechanism and remove the hardcoded 4kB buffer size. If the discovery fails, it still defaults to 4kB. Message-Id: <20240820-ffa_v1-2-v2-7-18c0c5f3c65e@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_ffa/driver.c | 44 ++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index d47272859190..4d231bc375e0 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -54,11 +54,8 @@ #define PACK_TARGET_INFO(s, r) \ (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r))) -/* - * Keeping RX TX buffer size as 4K for now - * 64K may be preferred to keep it min a page in 64K PAGE_SIZE config - */ -#define RXTX_BUFFER_SIZE SZ_4K +#define RXTX_MAP_MIN_BUFSZ_MASK GENMASK(1, 0) +#define RXTX_MAP_MIN_BUFSZ(x) ((x) & RXTX_MAP_MIN_BUFSZ_MASK) #define FFA_MAX_NOTIFICATIONS 64 @@ -99,6 +96,7 @@ struct ffa_drv_info { struct mutex tx_lock; /* lock to protect Tx buffer */ void *rx_buffer; void *tx_buffer; + size_t rxtx_bufsz; bool mem_ops_native; bool msg_direct_req2_supp; bool bitmap_created; @@ -454,7 +452,7 @@ static int ffa_msg_send2(u16 src_id, u16 dst_id, void *buf, size_t sz) ffa_value_t ret; int retval = 0; - if (sz > (RXTX_BUFFER_SIZE - sizeof(*msg))) + if (sz > (drv_info->rxtx_bufsz - sizeof(*msg))) return -ERANGE; mutex_lock(&drv_info->tx_lock); @@ -689,9 +687,10 @@ static int ffa_memory_ops(u32 func_id, struct ffa_mem_ops_args *args) { int ret; void *buffer; + size_t rxtx_bufsz = drv_info->rxtx_bufsz; if (!args->use_txbuf) { - buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); + buffer = alloc_pages_exact(rxtx_bufsz, GFP_KERNEL); if (!buffer) return -ENOMEM; } else { @@ -699,12 +698,12 @@ static int ffa_memory_ops(u32 func_id, struct ffa_mem_ops_args *args) mutex_lock(&drv_info->tx_lock); } - ret = ffa_setup_and_transmit(func_id, buffer, RXTX_BUFFER_SIZE, args); + ret = ffa_setup_and_transmit(func_id, buffer, rxtx_bufsz, args); if (args->use_txbuf) mutex_unlock(&drv_info->tx_lock); else - free_pages_exact(buffer, RXTX_BUFFER_SIZE); + free_pages_exact(buffer, rxtx_bufsz); return ret < 0 ? ret : 0; } @@ -1718,6 +1717,8 @@ static void ffa_notifications_setup(void) static int __init ffa_init(void) { int ret; + u32 buf_sz; + size_t rxtx_bufsz = SZ_4K; ret = ffa_transport_init(&invoke_ffa_fn); if (ret) @@ -1737,13 +1738,24 @@ static int __init ffa_init(void) goto free_drv_info; } - drv_info->rx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); + ret = ffa_features(FFA_FN_NATIVE(RXTX_MAP), 0, &buf_sz, NULL); + if (!ret) { + if (RXTX_MAP_MIN_BUFSZ(buf_sz) == 1) + rxtx_bufsz = SZ_64K; + else if (RXTX_MAP_MIN_BUFSZ(buf_sz) == 2) + rxtx_bufsz = SZ_16K; + else + rxtx_bufsz = SZ_4K; + } + + drv_info->rxtx_bufsz = rxtx_bufsz; + drv_info->rx_buffer = alloc_pages_exact(rxtx_bufsz, GFP_KERNEL); if (!drv_info->rx_buffer) { ret = -ENOMEM; goto free_pages; } - drv_info->tx_buffer = alloc_pages_exact(RXTX_BUFFER_SIZE, GFP_KERNEL); + drv_info->tx_buffer = alloc_pages_exact(rxtx_bufsz, GFP_KERNEL); if (!drv_info->tx_buffer) { ret = -ENOMEM; goto free_pages; @@ -1751,7 +1763,7 @@ static int __init ffa_init(void) ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), virt_to_phys(drv_info->rx_buffer), - RXTX_BUFFER_SIZE / FFA_PAGE_SIZE); + rxtx_bufsz / FFA_PAGE_SIZE); if (ret) { pr_err("failed to register FFA RxTx buffers\n"); goto free_pages; @@ -1781,8 +1793,8 @@ static int __init ffa_init(void) ffa_notifications_cleanup(); free_pages: if (drv_info->tx_buffer) - free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); - free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); + free_pages_exact(drv_info->tx_buffer, rxtx_bufsz); + free_pages_exact(drv_info->rx_buffer, rxtx_bufsz); free_drv_info: kfree(drv_info); return ret; @@ -1794,8 +1806,8 @@ static void __exit ffa_exit(void) ffa_notifications_cleanup(); ffa_partitions_cleanup(); ffa_rxtx_unmap(drv_info->vm_id); - free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); - free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); + free_pages_exact(drv_info->tx_buffer, drv_info->rxtx_bufsz); + free_pages_exact(drv_info->rx_buffer, drv_info->rxtx_bufsz); kfree(drv_info); } module_exit(ffa_exit); From dde3c64013035c9d6f0a5d0fd894a7a7e03c79ea Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Fri, 19 Jul 2024 16:08:09 +0800 Subject: [PATCH 082/212] dt-bindings: arm: amlogic: meson-gx-ao-secure: support more SoCs Add new compatible for ao-secure of Amlogic SoCs(S4,C3,T7,A4). Acked-by: Conor Dooley Signed-off-by: Xianwei Zhao Link: https://lore.kernel.org/r/20240719-soc_info-v3-1-020a3b687c0c@amlogic.com Signed-off-by: Neil Armstrong --- .../arm/amlogic/amlogic,meson-gx-ao-secure.yaml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/amlogic/amlogic,meson-gx-ao-secure.yaml b/Documentation/devicetree/bindings/arm/amlogic/amlogic,meson-gx-ao-secure.yaml index 7dff32f373cb..b4f6695a6015 100644 --- a/Documentation/devicetree/bindings/arm/amlogic/amlogic,meson-gx-ao-secure.yaml +++ b/Documentation/devicetree/bindings/arm/amlogic/amlogic,meson-gx-ao-secure.yaml @@ -25,10 +25,18 @@ select: properties: compatible: - items: - - const: amlogic,meson-gx-ao-secure - - const: syscon - + oneOf: + - items: + - const: amlogic,meson-gx-ao-secure + - const: syscon + - items: + - enum: + - amlogic,a4-ao-secure + - amlogic,c3-ao-secure + - amlogic,s4-ao-secure + - amlogic,t7-ao-secure + - const: amlogic,meson-gx-ao-secure + - const: syscon reg: maxItems: 1 From 009ff80bfaec1aa3fa48bbe5e2903c95931a6f37 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Fri, 19 Jul 2024 16:08:10 +0800 Subject: [PATCH 083/212] soc: amlogic: meson-gx-socinfo: add new SoCs id Add new definition for Amlogi SoCs, include S4, C3, T7, A4, A5. Reviewed-by: Neil Armstrong Signed-off-by: Xianwei Zhao Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240719-soc_info-v3-2-020a3b687c0c@amlogic.com Signed-off-by: Neil Armstrong --- drivers/soc/amlogic/meson-gx-socinfo.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c index 8809a948201a..7549f1644e5e 100644 --- a/drivers/soc/amlogic/meson-gx-socinfo.c +++ b/drivers/soc/amlogic/meson-gx-socinfo.c @@ -41,6 +41,11 @@ static const struct meson_gx_soc_id { { "G12B", 0x29 }, { "SM1", 0x2b }, { "A1", 0x2c }, + { "T7", 0x36 }, + { "S4", 0x37 }, + { "A5", 0x3c }, + { "C3", 0x3d }, + { "A4", 0x40 }, }; static const struct meson_gx_package_id { @@ -76,6 +81,11 @@ static const struct meson_gx_package_id { { "S905X3", 0x2b, 0x10, 0x3f }, { "S905D3", 0x2b, 0x30, 0x3f }, { "A113L", 0x2c, 0x0, 0xf8 }, + { "S805X2", 0x37, 0x2, 0xf }, + { "C308L", 0x3d, 0x1, 0xf }, + { "A311D2", 0x36, 0x1, 0xf }, + { "A113X2", 0x3c, 0x1, 0xf }, + { "A113L2", 0x40, 0x1, 0xf }, }; static inline unsigned int socinfo_to_major(u32 socinfo) From eba8a7b05e21ab1baa0394eb7e915312303492fe Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 18 Aug 2024 19:29:30 +0200 Subject: [PATCH 084/212] dt-bindings: memory-controllers: renesas,rpc-if: add top-level constraints Properties with variable number of items per each device are expected to have widest constraints in top-level "properties:" block and further customized (narrowed) in "if:then:". Add missing top-level constraints for clocks. Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240818172930.121898-1-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- .../bindings/memory-controllers/renesas,rpc-if.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml b/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml index d7745dd53b51..4f4bc953e31a 100644 --- a/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml @@ -67,7 +67,9 @@ properties: - const: dirmap - const: wbuf - clocks: true + clocks: + minItems: 1 + maxItems: 2 interrupts: maxItems: 1 From d47d52554d0233120ee74ab874cea979147f00e3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:25 +0200 Subject: [PATCH 085/212] memory: atmel-ebi: use scoped device node handling to simplify error paths Obtain the device node reference with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-1-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/atmel-ebi.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index e8bb5f37f5cb..8f5b3302ee30 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -6,6 +6,7 @@ * Copyright (C) 2013 Jean-Jacques Hiblot */ +#include #include #include #include @@ -517,7 +518,7 @@ static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np) static int atmel_ebi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *child, *np = dev->of_node, *smc_np; + struct device_node *child, *np = dev->of_node; struct atmel_ebi *ebi; int ret, reg_cells; struct clk *clk; @@ -541,30 +542,24 @@ static int atmel_ebi_probe(struct platform_device *pdev) ebi->clk = clk; - smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0); + struct device_node *smc_np __free(device_node) = + of_parse_phandle(dev->of_node, "atmel,smc", 0); ebi->smc.regmap = syscon_node_to_regmap(smc_np); - if (IS_ERR(ebi->smc.regmap)) { - ret = PTR_ERR(ebi->smc.regmap); - goto put_node; - } + if (IS_ERR(ebi->smc.regmap)) + return PTR_ERR(ebi->smc.regmap); ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np); - if (IS_ERR(ebi->smc.layout)) { - ret = PTR_ERR(ebi->smc.layout); - goto put_node; - } + if (IS_ERR(ebi->smc.layout)) + return PTR_ERR(ebi->smc.layout); ebi->smc.clk = of_clk_get(smc_np, 0); if (IS_ERR(ebi->smc.clk)) { - if (PTR_ERR(ebi->smc.clk) != -ENOENT) { - ret = PTR_ERR(ebi->smc.clk); - goto put_node; - } + if (PTR_ERR(ebi->smc.clk) != -ENOENT) + return PTR_ERR(ebi->smc.clk); ebi->smc.clk = NULL; } - of_node_put(smc_np); ret = clk_prepare_enable(ebi->smc.clk); if (ret) return ret; @@ -615,10 +610,6 @@ static int atmel_ebi_probe(struct platform_device *pdev) } return of_platform_populate(np, NULL, NULL, dev); - -put_node: - of_node_put(smc_np); - return ret; } static __maybe_unused int atmel_ebi_resume(struct device *dev) From 50e40b71598cd19d59683c989bc5b89140e70d28 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:26 +0200 Subject: [PATCH 086/212] memory: atmel-ebi: simplify with scoped for each OF child loop Use scoped for_each_available_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-2-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/atmel-ebi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index 8f5b3302ee30..8db970da9af9 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -518,7 +518,7 @@ static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np) static int atmel_ebi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *child, *np = dev->of_node; + struct device_node *np = dev->of_node; struct atmel_ebi *ebi; int ret, reg_cells; struct clk *clk; @@ -592,7 +592,7 @@ static int atmel_ebi_probe(struct platform_device *pdev) reg_cells += val; - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { if (!of_property_present(child, "reg")) continue; @@ -602,10 +602,8 @@ static int atmel_ebi_probe(struct platform_device *pdev) child); ret = atmel_ebi_dev_disable(ebi, child); - if (ret) { - of_node_put(child); + if (ret) return ret; - } } } From 2af13f97fc67979701a240ebe397811491ad575c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:27 +0200 Subject: [PATCH 087/212] memory: samsung: exynos5422-dmc: simplify dmc->dev usage Store 'dmc->dev' in local 'dev' variable, to make several pieces of code using it shorter and easier to read. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-3-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/samsung/exynos5422-dmc.c | 61 +++++++++++++------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c index da7ecd921c72..48ef41b8eaa0 100644 --- a/drivers/memory/samsung/exynos5422-dmc.c +++ b/drivers/memory/samsung/exynos5422-dmc.c @@ -339,19 +339,20 @@ static int exynos5_switch_timing_regs(struct exynos5_dmc *dmc, bool set) static int exynos5_init_freq_table(struct exynos5_dmc *dmc, struct devfreq_dev_profile *profile) { + struct device *dev = dmc->dev; int i, ret; int idx; unsigned long freq; - ret = devm_pm_opp_of_add_table(dmc->dev); + ret = devm_pm_opp_of_add_table(dev); if (ret < 0) { - dev_err(dmc->dev, "Failed to get OPP table\n"); + dev_err(dev, "Failed to get OPP table\n"); return ret; } - dmc->opp_count = dev_pm_opp_get_opp_count(dmc->dev); + dmc->opp_count = dev_pm_opp_get_opp_count(dev); - dmc->opp = devm_kmalloc_array(dmc->dev, dmc->opp_count, + dmc->opp = devm_kmalloc_array(dev, dmc->opp_count, sizeof(struct dmc_opp_table), GFP_KERNEL); if (!dmc->opp) return -ENOMEM; @@ -360,7 +361,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc, for (i = 0, freq = ULONG_MAX; i < dmc->opp_count; i++, freq--) { struct dev_pm_opp *opp; - opp = dev_pm_opp_find_freq_floor(dmc->dev, &freq); + opp = dev_pm_opp_find_freq_floor(dev, &freq); if (IS_ERR(opp)) return PTR_ERR(opp); @@ -1175,49 +1176,50 @@ static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row, static int of_get_dram_timings(struct exynos5_dmc *dmc) { int ret = 0; + struct device *dev = dmc->dev; int idx; struct device_node *np_ddr; u32 freq_mhz, clk_period_ps; - np_ddr = of_parse_phandle(dmc->dev->of_node, "device-handle", 0); + np_ddr = of_parse_phandle(dev->of_node, "device-handle", 0); if (!np_ddr) { - dev_warn(dmc->dev, "could not find 'device-handle' in DT\n"); + dev_warn(dev, "could not find 'device-handle' in DT\n"); return -EINVAL; } - dmc->timing_row = devm_kmalloc_array(dmc->dev, TIMING_COUNT, + dmc->timing_row = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); if (!dmc->timing_row) { ret = -ENOMEM; goto put_node; } - dmc->timing_data = devm_kmalloc_array(dmc->dev, TIMING_COUNT, + dmc->timing_data = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); if (!dmc->timing_data) { ret = -ENOMEM; goto put_node; } - dmc->timing_power = devm_kmalloc_array(dmc->dev, TIMING_COUNT, + dmc->timing_power = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); if (!dmc->timing_power) { ret = -ENOMEM; goto put_node; } - dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dmc->dev, + dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dev, DDR_TYPE_LPDDR3, &dmc->timings_arr_size); if (!dmc->timings) { - dev_warn(dmc->dev, "could not get timings from DT\n"); + dev_warn(dev, "could not get timings from DT\n"); ret = -EINVAL; goto put_node; } - dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dmc->dev); + dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dev); if (!dmc->min_tck) { - dev_warn(dmc->dev, "could not get tck from DT\n"); + dev_warn(dev, "could not get tck from DT\n"); ret = -EINVAL; goto put_node; } @@ -1254,34 +1256,34 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc) static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc) { int ret; + struct device *dev = dmc->dev; unsigned long target_volt = 0; unsigned long target_rate = 0; unsigned int tmp; - dmc->fout_spll = devm_clk_get(dmc->dev, "fout_spll"); + dmc->fout_spll = devm_clk_get(dev, "fout_spll"); if (IS_ERR(dmc->fout_spll)) return PTR_ERR(dmc->fout_spll); - dmc->fout_bpll = devm_clk_get(dmc->dev, "fout_bpll"); + dmc->fout_bpll = devm_clk_get(dev, "fout_bpll"); if (IS_ERR(dmc->fout_bpll)) return PTR_ERR(dmc->fout_bpll); - dmc->mout_mclk_cdrex = devm_clk_get(dmc->dev, "mout_mclk_cdrex"); + dmc->mout_mclk_cdrex = devm_clk_get(dev, "mout_mclk_cdrex"); if (IS_ERR(dmc->mout_mclk_cdrex)) return PTR_ERR(dmc->mout_mclk_cdrex); - dmc->mout_bpll = devm_clk_get(dmc->dev, "mout_bpll"); + dmc->mout_bpll = devm_clk_get(dev, "mout_bpll"); if (IS_ERR(dmc->mout_bpll)) return PTR_ERR(dmc->mout_bpll); - dmc->mout_mx_mspll_ccore = devm_clk_get(dmc->dev, - "mout_mx_mspll_ccore"); + dmc->mout_mx_mspll_ccore = devm_clk_get(dev, "mout_mx_mspll_ccore"); if (IS_ERR(dmc->mout_mx_mspll_ccore)) return PTR_ERR(dmc->mout_mx_mspll_ccore); - dmc->mout_spll = devm_clk_get(dmc->dev, "ff_dout_spll2"); + dmc->mout_spll = devm_clk_get(dev, "ff_dout_spll2"); if (IS_ERR(dmc->mout_spll)) { - dmc->mout_spll = devm_clk_get(dmc->dev, "mout_sclk_spll"); + dmc->mout_spll = devm_clk_get(dev, "mout_sclk_spll"); if (IS_ERR(dmc->mout_spll)) return PTR_ERR(dmc->mout_spll); } @@ -1329,38 +1331,37 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc) */ static int exynos5_performance_counters_init(struct exynos5_dmc *dmc) { + struct device *dev = dmc->dev; int ret, i; - dmc->num_counters = devfreq_event_get_edev_count(dmc->dev, - "devfreq-events"); + dmc->num_counters = devfreq_event_get_edev_count(dev, "devfreq-events"); if (dmc->num_counters < 0) { - dev_err(dmc->dev, "could not get devfreq-event counters\n"); + dev_err(dev, "could not get devfreq-event counters\n"); return dmc->num_counters; } - dmc->counter = devm_kcalloc(dmc->dev, dmc->num_counters, + dmc->counter = devm_kcalloc(dev, dmc->num_counters, sizeof(*dmc->counter), GFP_KERNEL); if (!dmc->counter) return -ENOMEM; for (i = 0; i < dmc->num_counters; i++) { dmc->counter[i] = - devfreq_event_get_edev_by_phandle(dmc->dev, - "devfreq-events", i); + devfreq_event_get_edev_by_phandle(dev, "devfreq-events", i); if (IS_ERR_OR_NULL(dmc->counter[i])) return -EPROBE_DEFER; } ret = exynos5_counters_enable_edev(dmc); if (ret < 0) { - dev_err(dmc->dev, "could not enable event counter\n"); + dev_err(dev, "could not enable event counter\n"); return ret; } ret = exynos5_counters_set_event(dmc); if (ret < 0) { exynos5_counters_disable_edev(dmc); - dev_err(dmc->dev, "could not set event counter\n"); + dev_err(dev, "could not set event counter\n"); return ret; } From e2cc3ddaec0218f227cc53e3f784144640cd1765 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:28 +0200 Subject: [PATCH 088/212] memory: samsung: exynos5422-dmc: use scoped device node handling to simplify error paths Obtain the device node reference with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-4-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/samsung/exynos5422-dmc.c | 31 +++++++++---------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c index 48ef41b8eaa0..7d80322754fa 100644 --- a/drivers/memory/samsung/exynos5422-dmc.c +++ b/drivers/memory/samsung/exynos5422-dmc.c @@ -4,6 +4,7 @@ * Author: Lukasz Luba */ +#include #include #include #include @@ -1178,10 +1179,10 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc) int ret = 0; struct device *dev = dmc->dev; int idx; - struct device_node *np_ddr; u32 freq_mhz, clk_period_ps; - np_ddr = of_parse_phandle(dev->of_node, "device-handle", 0); + struct device_node *np_ddr __free(device_node) = + of_parse_phandle(dev->of_node, "device-handle", 0); if (!np_ddr) { dev_warn(dev, "could not find 'device-handle' in DT\n"); return -EINVAL; @@ -1189,39 +1190,31 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc) dmc->timing_row = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); - if (!dmc->timing_row) { - ret = -ENOMEM; - goto put_node; - } + if (!dmc->timing_row) + return -ENOMEM; dmc->timing_data = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); - if (!dmc->timing_data) { - ret = -ENOMEM; - goto put_node; - } + if (!dmc->timing_data) + return -ENOMEM; dmc->timing_power = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); - if (!dmc->timing_power) { - ret = -ENOMEM; - goto put_node; - } + if (!dmc->timing_power) + return -ENOMEM; dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dev, DDR_TYPE_LPDDR3, &dmc->timings_arr_size); if (!dmc->timings) { dev_warn(dev, "could not get timings from DT\n"); - ret = -EINVAL; - goto put_node; + return -EINVAL; } dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dev); if (!dmc->min_tck) { dev_warn(dev, "could not get tck from DT\n"); - ret = -EINVAL; - goto put_node; + return -EINVAL; } /* Sorted array of OPPs with frequency ascending */ @@ -1241,8 +1234,6 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc) dmc->bypass_timing_data = dmc->timing_data[idx - 1]; dmc->bypass_timing_power = dmc->timing_power[idx - 1]; -put_node: - of_node_put(np_ddr); return ret; } From 48ec68281d40ee566c2f38d36357ee7d493000c8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:29 +0200 Subject: [PATCH 089/212] memory: stm32-fmc2-ebi: simplify with scoped for each OF child loop Use scoped for_each_available_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-5-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/stm32-fmc2-ebi.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c index 1c63eeacd071..7167e1da56d3 100644 --- a/drivers/memory/stm32-fmc2-ebi.c +++ b/drivers/memory/stm32-fmc2-ebi.c @@ -1573,29 +1573,25 @@ static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi, static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) { struct device *dev = ebi->dev; - struct device_node *child; bool child_found = false; u32 bank; int ret; - for_each_available_child_of_node(dev->of_node, child) { + for_each_available_child_of_node_scoped(dev->of_node, child) { ret = of_property_read_u32(child, "reg", &bank); if (ret) { dev_err(dev, "could not retrieve reg property: %d\n", ret); - of_node_put(child); return ret; } if (bank >= FMC2_MAX_BANKS) { dev_err(dev, "invalid reg value: %d\n", bank); - of_node_put(child); return -EINVAL; } if (ebi->bank_assigned & BIT(bank)) { dev_err(dev, "bank already assigned: %d\n", bank); - of_node_put(child); return -EINVAL; } @@ -1603,7 +1599,6 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) ret = ebi->data->check_rif(ebi, bank + 1); if (ret) { dev_err(dev, "bank access failed: %d\n", bank); - of_node_put(child); return ret; } } @@ -1613,7 +1608,6 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) if (ret) { dev_err(dev, "setup chip select %d failed: %d\n", bank, ret); - of_node_put(child); return ret; } } From 4c1a381a9eb775f96eb64b1a63a4147fb265bb6f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:30 +0200 Subject: [PATCH 090/212] memory: stm32-fmc2-ebi: simplify with dev_err_probe() dev_err_probe() combines 'return' and error code printing, thus code is a bit simpler, even if it cannot actually defer. Suggested-by: Jonathan Cameron Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-6-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/stm32-fmc2-ebi.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c index 7167e1da56d3..566c225f71c0 100644 --- a/drivers/memory/stm32-fmc2-ebi.c +++ b/drivers/memory/stm32-fmc2-ebi.c @@ -1579,11 +1579,8 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) for_each_available_child_of_node_scoped(dev->of_node, child) { ret = of_property_read_u32(child, "reg", &bank); - if (ret) { - dev_err(dev, "could not retrieve reg property: %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "could not retrieve reg property\n"); if (bank >= FMC2_MAX_BANKS) { dev_err(dev, "invalid reg value: %d\n", bank); @@ -1605,11 +1602,9 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) if (bank < FMC2_MAX_EBI_CE) { ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank); - if (ret) { - dev_err(dev, "setup chip select %d failed: %d\n", - bank, ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "setup chip select %d failed\n", bank); } ebi->bank_assigned |= BIT(bank); From 210059143b6f51819ecc9a00a15aeef80b45beee Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:31 +0200 Subject: [PATCH 091/212] memory: tegra-mc: simplify with scoped for each OF child loop Use scoped for_each_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-7-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/mc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 224b488794e5..bd5b58f1fd42 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -450,7 +450,6 @@ static int load_one_timing(struct tegra_mc *mc, static int load_timings(struct tegra_mc *mc, struct device_node *node) { - struct device_node *child; struct tegra_mc_timing *timing; int child_count = of_get_child_count(node); int i = 0, err; @@ -462,14 +461,12 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node) mc->num_timings = child_count; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { timing = &mc->timings[i++]; err = load_one_timing(mc, timing, child); - if (err) { - of_node_put(child); + if (err) return err; - } } return 0; @@ -477,7 +474,6 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node) static int tegra_mc_setup_timings(struct tegra_mc *mc) { - struct device_node *node; u32 ram_code, node_ram_code; int err; @@ -485,14 +481,13 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc) mc->num_timings = 0; - for_each_child_of_node(mc->dev->of_node, node) { + for_each_child_of_node_scoped(mc->dev->of_node, node) { err = of_property_read_u32(node, "nvidia,ram-code", &node_ram_code); if (err || (node_ram_code != ram_code)) continue; err = load_timings(mc, node); - of_node_put(node); if (err) return err; break; From 2bc48f69717485e28ff9a300a928cc742ddd39b0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:32 +0200 Subject: [PATCH 092/212] memory: tegra124-emc: simplify with scoped for each OF child loop Use scoped for_each_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-8-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra124-emc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index 47c0c19e13fd..03f1daa2d132 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -992,7 +992,6 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, struct device_node *node) { int child_count = of_get_child_count(node); - struct device_node *child; struct emc_timing *timing; unsigned int i = 0; int err; @@ -1004,14 +1003,12 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, emc->num_timings = child_count; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { timing = &emc->timings[i++]; err = load_one_timing_from_dt(emc, timing, child); - if (err) { - of_node_put(child); + if (err) return err; - } } sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, From 818902cb74c377ade67ce933f3bbd8305615a459 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:33 +0200 Subject: [PATCH 093/212] memory: tegra20-emc: simplify with scoped for each OF child loop Use scoped for_each_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-9-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra20-emc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c index 97cf59523b0b..7193f848d17e 100644 --- a/drivers/memory/tegra/tegra20-emc.c +++ b/drivers/memory/tegra/tegra20-emc.c @@ -410,7 +410,6 @@ static int cmp_timings(const void *_a, const void *_b) static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, struct device_node *node) { - struct device_node *child; struct emc_timing *timing; int child_count; int err; @@ -428,15 +427,13 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, timing = emc->timings; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { if (of_node_name_eq(child, "lpddr2")) continue; err = load_one_timing_from_dt(emc, timing++, child); - if (err) { - of_node_put(child); + if (err) return err; - } emc->num_timings++; } From c7f67fec177484fd4f7836e832e66e77fa25700f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:34 +0200 Subject: [PATCH 094/212] memory: tegra30-emc: simplify with scoped for each OF child loop Use scoped for_each_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-10-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/tegra/tegra30-emc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c index d7b0a23c2d7d..921dce1b8bc6 100644 --- a/drivers/memory/tegra/tegra30-emc.c +++ b/drivers/memory/tegra/tegra30-emc.c @@ -979,7 +979,6 @@ static int emc_check_mc_timings(struct tegra_emc *emc) static int emc_load_timings_from_dt(struct tegra_emc *emc, struct device_node *node) { - struct device_node *child; struct emc_timing *timing; int child_count; int err; @@ -998,12 +997,10 @@ static int emc_load_timings_from_dt(struct tegra_emc *emc, emc->num_timings = child_count; timing = emc->timings; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { err = load_one_timing_from_dt(emc, timing++, child); - if (err) { - of_node_put(child); + if (err) return err; - } } sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, From 82986f5cdd23756e7e0c4fa9e4f590f7516772e9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:35 +0200 Subject: [PATCH 095/212] memory: ti-aemif: simplify with dev_err_probe() Use dev_err_probe() to avoid dmesg flood on actual defer. This makes the code also simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-11-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/ti-aemif.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 49e7cbe98fdb..a1f1922ea291 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -339,10 +339,9 @@ static int aemif_probe(struct platform_device *pdev) platform_set_drvdata(pdev, aemif); aemif->clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(aemif->clk)) { - dev_err(dev, "cannot get clock 'aemif'\n"); - return PTR_ERR(aemif->clk); - } + if (IS_ERR(aemif->clk)) + return dev_err_probe(dev, PTR_ERR(aemif->clk), + "cannot get clock 'aemif'\n"); aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC; From 5e8431f722d95bf58276a3051240c1ebe3cc238d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 12:54:37 +0200 Subject: [PATCH 096/212] memory: ti-aemif: simplify with scoped for each OF child loop Use scoped for_each_available_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240816-cleanup-h-of-node-put-memory-v2-13-9eed0ee16b78@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/ti-aemif.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index a1f1922ea291..3b546eddf5fe 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -329,7 +329,6 @@ static int aemif_probe(struct platform_device *pdev) int ret = -ENODEV; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *child_np; struct aemif_device *aemif; aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL); @@ -359,12 +358,10 @@ static int aemif_probe(struct platform_device *pdev) * functions iterate over these nodes and update the cs data * array. */ - for_each_available_child_of_node(np, child_np) { + for_each_available_child_of_node_scoped(np, child_np) { ret = of_aemif_parse_abus_config(pdev, child_np); - if (ret < 0) { - of_node_put(child_np); + if (ret < 0) return ret; - } } } From ff2bed591a820d98288c49aca692eab2f39acaf8 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Tue, 21 May 2024 21:10:12 +0000 Subject: [PATCH 097/212] dt-bindings: power: rockchip: Document RK3308 IO voltage domains Document dt-bindings for RK3308 IO voltage domains. Signed-off-by: Jonas Karlman Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240521211029.1236094-10-jonas@kwiboo.se Signed-off-by: Heiko Stuebner --- .../bindings/power/rockchip-io-domain.yaml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Documentation/devicetree/bindings/power/rockchip-io-domain.yaml b/Documentation/devicetree/bindings/power/rockchip-io-domain.yaml index d71fc72d4464..c434277218ea 100644 --- a/Documentation/devicetree/bindings/power/rockchip-io-domain.yaml +++ b/Documentation/devicetree/bindings/power/rockchip-io-domain.yaml @@ -50,6 +50,7 @@ properties: - rockchip,rk3188-io-voltage-domain - rockchip,rk3228-io-voltage-domain - rockchip,rk3288-io-voltage-domain + - rockchip,rk3308-io-voltage-domain - rockchip,rk3328-io-voltage-domain - rockchip,rk3368-io-voltage-domain - rockchip,rk3368-pmu-io-voltage-domain @@ -71,6 +72,7 @@ allOf: - $ref: "#/$defs/rk3188" - $ref: "#/$defs/rk3228" - $ref: "#/$defs/rk3288" + - $ref: "#/$defs/rk3308" - $ref: "#/$defs/rk3328" - $ref: "#/$defs/rk3368" - $ref: "#/$defs/rk3368-pmu" @@ -194,6 +196,28 @@ $defs: wifi-supply: description: The supply connected to APIO3_VDD. Also known as SDIO0. + rk3308: + if: + properties: + compatible: + contains: + const: rockchip,rk3308-io-voltage-domain + + then: + properties: + vccio0-supply: + description: The supply connected to VCCIO0. + vccio1-supply: + description: The supply connected to VCCIO1. + vccio2-supply: + description: The supply connected to VCCIO2. + vccio3-supply: + description: The supply connected to VCCIO3. + vccio4-supply: + description: The supply connected to VCCIO4. + vccio5-supply: + description: The supply connected to VCCIO5. + rk3328: if: properties: From f0d7047889589a4affe7a04d38a408ef45ec58e6 Mon Sep 17 00:00:00 2001 From: David Wu Date: Tue, 21 May 2024 21:10:13 +0000 Subject: [PATCH 098/212] soc: rockchip: io-domain: Add RK3308 IO voltage domains Add IO voltage domains support for the RK3308 SoC. Signed-off-by: David Wu Signed-off-by: Jianqun Xu Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20240521211029.1236094-11-jonas@kwiboo.se Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/io-domain.c | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/soc/rockchip/io-domain.c b/drivers/soc/rockchip/io-domain.c index 18f809c160a7..fd9fd31f71c2 100644 --- a/drivers/soc/rockchip/io-domain.c +++ b/drivers/soc/rockchip/io-domain.c @@ -39,6 +39,10 @@ #define RK3288_SOC_CON2_FLASH0 BIT(7) #define RK3288_SOC_FLASH_SUPPLY_NUM 2 +#define RK3308_SOC_CON0 0x300 +#define RK3308_SOC_CON0_VCCIO3 BIT(8) +#define RK3308_SOC_VCCIO3_SUPPLY_NUM 3 + #define RK3328_SOC_CON4 0x410 #define RK3328_SOC_CON4_VCCIO2 BIT(7) #define RK3328_SOC_VCCIO2_SUPPLY_NUM 1 @@ -229,6 +233,25 @@ static void rk3288_iodomain_init(struct rockchip_iodomain *iod) dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); } +static void rk3308_iodomain_init(struct rockchip_iodomain *iod) +{ + int ret; + u32 val; + + /* if no vccio3 supply we should leave things alone */ + if (!iod->supplies[RK3308_SOC_VCCIO3_SUPPLY_NUM].reg) + return; + + /* + * set vccio3 iodomain to also use this framework + * instead of a special gpio. + */ + val = RK3308_SOC_CON0_VCCIO3 | (RK3308_SOC_CON0_VCCIO3 << 16); + ret = regmap_write(iod->grf, RK3308_SOC_CON0, val); + if (ret < 0) + dev_warn(iod->dev, "couldn't update vccio3 vsel ctrl\n"); +} + static void rk3328_iodomain_init(struct rockchip_iodomain *iod) { int ret; @@ -376,6 +399,19 @@ static const struct rockchip_iodomain_soc_data soc_data_rk3288 = { .init = rk3288_iodomain_init, }; +static const struct rockchip_iodomain_soc_data soc_data_rk3308 = { + .grf_offset = 0x300, + .supply_names = { + "vccio0", + "vccio1", + "vccio2", + "vccio3", + "vccio4", + "vccio5", + }, + .init = rk3308_iodomain_init, +}; + static const struct rockchip_iodomain_soc_data soc_data_rk3328 = { .grf_offset = 0x410, .supply_names = { @@ -528,6 +564,10 @@ static const struct of_device_id rockchip_iodomain_match[] = { .compatible = "rockchip,rk3288-io-voltage-domain", .data = &soc_data_rk3288 }, + { + .compatible = "rockchip,rk3308-io-voltage-domain", + .data = &soc_data_rk3308 + }, { .compatible = "rockchip,rk3328-io-voltage-domain", .data = &soc_data_rk3328 From 7bd76f405d329c2c361703cc45317a4a55d8a68e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Thu, 23 May 2024 20:56:32 +0200 Subject: [PATCH 099/212] soc: rockchip: grf: Set RK3128's vpu main clock RK3128 has a setting in GRF which selects whether the vpu attached iommu uses the AXI clock of the decoder (vdpu) or the encoder (vepu). The default is vepu but some part of the vendor firmware sets it to vdpu. In order to be independent on whether any of those vendor firmware blobs is used to boot the SoC reset "vpu main clock" setting to it's default value. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20240523185633.71355-3-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/grf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c index 5fd62046b28a..df64de3d3040 100644 --- a/drivers/soc/rockchip/grf.c +++ b/drivers/soc/rockchip/grf.c @@ -41,9 +41,11 @@ static const struct rockchip_grf_info rk3036_grf __initconst = { }; #define RK3128_GRF_SOC_CON0 0x140 +#define RK3128_GRF_SOC_CON1 0x144 static const struct rockchip_grf_value rk3128_defaults[] __initconst = { { "jtag switching", RK3128_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 8) }, + { "vpu main clock", RK3128_GRF_SOC_CON1, HIWORD_UPDATE(0, 1, 10) }, }; static const struct rockchip_grf_info rk3128_grf __initconst = { From 4261b5804661f75408a8e2b63038308d2aae1f31 Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Thu, 22 Aug 2024 15:53:36 -0400 Subject: [PATCH 100/212] dt-bindings: soc: rockchip: Add rk3576 syscon compatibles Add all syscon compatibles for RK3576. Signed-off-by: Detlev Casanova Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240822195706.920567-2-detlev.casanova@collabora.com Signed-off-by: Heiko Stuebner --- .../devicetree/bindings/soc/rockchip/grf.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml index 78c6d5b64138..9735063e6aa5 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml @@ -20,6 +20,20 @@ properties: - rockchip,rk3568-pipe-grf - rockchip,rk3568-pipe-phy-grf - rockchip,rk3568-usb2phy-grf + - rockchip,rk3576-bigcore-grf + - rockchip,rk3576-cci-grf + - rockchip,rk3576-gpu-grf + - rockchip,rk3576-litcore-grf + - rockchip,rk3576-npu-grf + - rockchip,rk3576-php-grf + - rockchip,rk3576-pipe-phy-grf + - rockchip,rk3576-pmu1-grf + - rockchip,rk3576-sdgmac-grf + - rockchip,rk3576-sys-grf + - rockchip,rk3576-usb-grf + - rockchip,rk3576-usbdpphy-grf + - rockchip,rk3576-vo0-grf + - rockchip,rk3576-vop-grf - rockchip,rk3588-bigcore0-grf - rockchip,rk3588-bigcore1-grf - rockchip,rk3588-hdptxphy-grf @@ -58,6 +72,8 @@ properties: - rockchip,rk3399-pmugrf - rockchip,rk3568-grf - rockchip,rk3568-pmugrf + - rockchip,rk3576-ioc-grf + - rockchip,rk3576-pmu0-grf - rockchip,rk3588-usb2phy-grf - rockchip,rv1108-grf - rockchip,rv1108-pmugrf From e1aaecacfa135cd264a0db331d3ab8b2a04a54a3 Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Thu, 22 Aug 2024 15:53:37 -0400 Subject: [PATCH 101/212] soc: rockchip: grf: Add rk3576 default GRF values Set SW controlled i3c weak pull up and disable JTAG function on SDMMC IO. The i3c weak pull up is activated to let all gpio banks be controlled by the pinctrl driver. Disabling the JTAG function lets the SDMMC core use its full IO width. Signed-off-by: Detlev Casanova Acked-by: Dragan Simic Link: https://lore.kernel.org/r/20240822195706.920567-3-detlev.casanova@collabora.com Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/grf.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c index df64de3d3040..1eab4bb0eacf 100644 --- a/drivers/soc/rockchip/grf.c +++ b/drivers/soc/rockchip/grf.c @@ -123,6 +123,29 @@ static const struct rockchip_grf_info rk3566_pipegrf __initconst = { .num_values = ARRAY_SIZE(rk3566_defaults), }; +#define RK3576_SYSGRF_SOC_CON1 0x0004 + +static const struct rockchip_grf_value rk3576_defaults_sys_grf[] __initconst = { + { "i3c0 weakpull", RK3576_SYSGRF_SOC_CON1, HIWORD_UPDATE(3, 3, 6) }, + { "i3c1 weakpull", RK3576_SYSGRF_SOC_CON1, HIWORD_UPDATE(3, 3, 8) }, +}; + +static const struct rockchip_grf_info rk3576_sysgrf __initconst = { + .values = rk3576_defaults_sys_grf, + .num_values = ARRAY_SIZE(rk3576_defaults_sys_grf), +}; + +#define RK3576_IOCGRF_MISC_CON 0x04F0 + +static const struct rockchip_grf_value rk3576_defaults_ioc_grf[] __initconst = { + { "jtag switching", RK3576_IOCGRF_MISC_CON, HIWORD_UPDATE(0, 1, 1) }, +}; + +static const struct rockchip_grf_info rk3576_iocgrf __initconst = { + .values = rk3576_defaults_ioc_grf, + .num_values = ARRAY_SIZE(rk3576_defaults_ioc_grf), +}; + #define RK3588_GRF_SOC_CON6 0x0318 static const struct rockchip_grf_value rk3588_defaults[] __initconst = { @@ -134,7 +157,6 @@ static const struct rockchip_grf_info rk3588_sysgrf __initconst = { .num_values = ARRAY_SIZE(rk3588_defaults), }; - static const struct of_device_id rockchip_grf_dt_match[] __initconst = { { .compatible = "rockchip,rk3036-grf", @@ -160,6 +182,12 @@ static const struct of_device_id rockchip_grf_dt_match[] __initconst = { }, { .compatible = "rockchip,rk3566-pipe-grf", .data = (void *)&rk3566_pipegrf, + }, { + .compatible = "rockchip,rk3576-sys-grf", + .data = (void *)&rk3576_sysgrf, + }, { + .compatible = "rockchip,rk3576-ioc-grf", + .data = (void *)&rk3576_iocgrf, }, { .compatible = "rockchip,rk3588-sys-grf", .data = (void *)&rk3588_sysgrf, From c7d2f3fbdf59b206414ddc306b0fb74cd174c0ed Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sat, 24 Aug 2024 10:02:35 +0200 Subject: [PATCH 102/212] memory: ti-aemif: Revert "memory: ti-aemif: don't needlessly iterate over child nodes" This reverts commit 23a641d5c2bce4c723fff9118a5d865ee6b9d05a. The first-level children of the aemif node are not the device nodes (ones containing the 'compatible' property) but the chip-select nodes which instead have their own children. of_platform_populate() will skip such nodes so we must indeed iterate over the direct children of the aemif node. The problem here is that we never call of_platform_depopulate() as it takes the root device as argument. We only have an unpopulated chip-select nodes so we will leak these devices if any of the calls to of_platform_populate() fails. I don't have a batter idea right now but my patch was not correct so we need to revert it. While at it: at least use the scoped variant of the OF node iterator. Down the line, we should find a better solution to fix this potential resource leak in error path. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20240824080235.56472-1-brgl@bgdev.pl Fixes: 23a641d5c2bc ("memory: ti-aemif: don't needlessly iterate over child nodes") Signed-off-by: Krzysztof Kozlowski --- drivers/memory/ti-aemif.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 3b546eddf5fe..d54dc3cfff73 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -379,9 +379,11 @@ static int aemif_probe(struct platform_device *pdev) * child will be probed after the AEMIF timing parameters are set. */ if (np) { - ret = devm_of_platform_populate(dev); - if (ret) - return ret; + for_each_available_child_of_node_scoped(np, child_np) { + ret = of_platform_populate(child_np, NULL, NULL, dev); + if (ret < 0) + return ret; + } } return 0; From 99602b4d30359f971247f8438afac57cbd1832f0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 Aug 2024 12:15:56 +0200 Subject: [PATCH 103/212] memory: emif: drop unused 'irq_state' member Driver does not use 'emif_data.irq_state'. Link: https://lore.kernel.org/r/20240823-b4-cleanup-h-guard-v1-1-01668915bd55@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/emif.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 974ed641473e..b32f3a8f9d71 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -57,7 +57,6 @@ struct emif_data { u8 temperature_level; u8 lpmode; struct list_head node; - unsigned long irq_state; void __iomem *base; struct device *dev; struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES]; From f1619986d7e996eb6e53c7fe8ab32e66b17e1cf1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 Aug 2024 12:15:57 +0200 Subject: [PATCH 104/212] memory: emif: simplify locking with guard() Simplify error handling (less gotos) over locks with guard(). The driver used file-scope variable 'irq_state' for storing IRQ state with spin_lock_irqsave, so move it into respective local scopes. This should be equivalent, but more readable (less global variables). Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240823-b4-cleanup-h-guard-v1-2-01668915bd55@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/emif.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index b32f3a8f9d71..99eb7d1baa5f 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -7,6 +7,7 @@ * Aneesh V * Santosh Shilimkar */ +#include #include #include #include @@ -68,7 +69,6 @@ struct emif_data { static struct emif_data *emif1; static DEFINE_SPINLOCK(emif_lock); -static unsigned long irq_state; static LIST_HEAD(device_list); static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif, @@ -522,18 +522,18 @@ static void setup_temperature_sensitive_regs(struct emif_data *emif, static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) { u32 old_temp_level; - irqreturn_t ret = IRQ_HANDLED; + irqreturn_t ret; struct emif_custom_configs *custom_configs; - spin_lock_irqsave(&emif_lock, irq_state); + guard(spinlock_irqsave)(&emif_lock); old_temp_level = emif->temperature_level; get_temperature_level(emif); if (unlikely(emif->temperature_level == old_temp_level)) { - goto out; + return IRQ_HANDLED; } else if (!emif->curr_regs) { dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n"); - goto out; + return IRQ_HANDLED; } custom_configs = emif->plat_data->custom_configs; @@ -553,8 +553,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) * from thread context */ emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN; - ret = IRQ_WAKE_THREAD; - goto out; + return IRQ_WAKE_THREAD; } } @@ -570,10 +569,9 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) /* Temperature is going up - handle immediately */ setup_temperature_sensitive_regs(emif, emif->curr_regs); do_freq_update(); + ret = IRQ_HANDLED; } -out: - spin_unlock_irqrestore(&emif_lock, irq_state); return ret; } @@ -616,6 +614,7 @@ static irqreturn_t emif_interrupt_handler(int irq, void *dev_id) static irqreturn_t emif_threaded_isr(int irq, void *dev_id) { struct emif_data *emif = dev_id; + unsigned long irq_state; if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n"); From c93ad423edd8a42a6666241595043f9193469f9e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 Aug 2024 12:15:58 +0200 Subject: [PATCH 105/212] memory: omap-gpmc: simplify locking with guard() Simplify error handling (less gotos) over locks with guard(). Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240823-b4-cleanup-h-guard-v1-3-01668915bd55@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/omap-gpmc.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index 80d038884207..c8a0d82f9c27 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -9,6 +9,7 @@ * Copyright (C) 2009 Texas Instruments * Added OMAP4 support - Santosh Shilimkar */ +#include #include #include #include @@ -989,18 +990,18 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) if (size > (1 << GPMC_SECTION_SHIFT)) return -ENOMEM; - spin_lock(&gpmc_mem_lock); - if (gpmc_cs_reserved(cs)) { - r = -EBUSY; - goto out; - } + guard(spinlock)(&gpmc_mem_lock); + + if (gpmc_cs_reserved(cs)) + return -EBUSY; + if (gpmc_cs_mem_enabled(cs)) r = adjust_resource(res, res->start & ~(size - 1), size); if (r < 0) r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0, size, NULL, NULL); if (r < 0) - goto out; + return r; /* Disable CS while changing base address and size mask */ gpmc_cs_disable_mem(cs); @@ -1008,16 +1009,15 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) r = gpmc_cs_set_memconf(cs, res->start, resource_size(res)); if (r < 0) { release_resource(res); - goto out; + return r; } /* Enable CS */ gpmc_cs_enable_mem(cs); *base = res->start; gpmc_cs_set_reserved(cs, 1); -out: - spin_unlock(&gpmc_mem_lock); - return r; + + return 0; } EXPORT_SYMBOL(gpmc_cs_request); @@ -1026,10 +1026,9 @@ void gpmc_cs_free(int cs) struct gpmc_cs_data *gpmc; struct resource *res; - spin_lock(&gpmc_mem_lock); + guard(spinlock)(&gpmc_mem_lock); if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) { WARN(1, "Trying to free non-reserved GPMC CS%d\n", cs); - spin_unlock(&gpmc_mem_lock); return; } gpmc = &gpmc_cs[cs]; @@ -1039,7 +1038,6 @@ void gpmc_cs_free(int cs) if (res->flags) release_resource(res); gpmc_cs_set_reserved(cs, 0); - spin_unlock(&gpmc_mem_lock); } EXPORT_SYMBOL(gpmc_cs_free); From 8f3cb397cbc1e3b18081738af87171f960bd112e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 Aug 2024 12:15:59 +0200 Subject: [PATCH 106/212] memory: pl172: simplify with dev_err_probe() Use dev_err_probe() to avoid dmesg flood on actual defer. This makes the code also simpler. Reviewed-by: Jonathan Cameron Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20240823-b4-cleanup-h-guard-v1-4-01668915bd55@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/pl172.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/memory/pl172.c b/drivers/memory/pl172.c index 9eb8cc7de494..390012401f64 100644 --- a/drivers/memory/pl172.c +++ b/drivers/memory/pl172.c @@ -217,10 +217,9 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id) return -ENOMEM; pl172->clk = devm_clk_get(dev, "mpmcclk"); - if (IS_ERR(pl172->clk)) { - dev_err(dev, "no mpmcclk provided clock\n"); - return PTR_ERR(pl172->clk); - } + if (IS_ERR(pl172->clk)) + return dev_err_probe(dev, PTR_ERR(pl172->clk), + "no mpmcclk provided clock\n"); ret = clk_prepare_enable(pl172->clk); if (ret) { From 610395de8496c34919f827dd194bf41af20c2bca Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 Aug 2024 12:16:00 +0200 Subject: [PATCH 107/212] memory: pl172: simplify with devm_clk_get_enabled() Use devm_clk_get_enabled() to drop clock prepare/unprepare parts and make code simpler. Change to dev_err_probe() in handling clk_get_rate() error to make it even simpler. Reviewed-by: Jonathan Cameron Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20240823-b4-cleanup-h-guard-v1-5-01668915bd55@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/pl172.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/drivers/memory/pl172.c b/drivers/memory/pl172.c index 390012401f64..db5fbee34077 100644 --- a/drivers/memory/pl172.c +++ b/drivers/memory/pl172.c @@ -216,28 +216,20 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id) if (!pl172) return -ENOMEM; - pl172->clk = devm_clk_get(dev, "mpmcclk"); + pl172->clk = devm_clk_get_enabled(dev, "mpmcclk"); if (IS_ERR(pl172->clk)) return dev_err_probe(dev, PTR_ERR(pl172->clk), "no mpmcclk provided clock\n"); - ret = clk_prepare_enable(pl172->clk); - if (ret) { - dev_err(dev, "unable to mpmcclk enable clock\n"); - return ret; - } - pl172->rate = clk_get_rate(pl172->clk) / MSEC_PER_SEC; - if (!pl172->rate) { - dev_err(dev, "unable to get mpmcclk clock rate\n"); - ret = -EINVAL; - goto err_clk_enable; - } + if (!pl172->rate) + return dev_err_probe(dev, -EINVAL, + "unable to get mpmcclk clock rate\n"); ret = amba_request_regions(adev, NULL); if (ret) { dev_err(dev, "unable to request AMBA regions\n"); - goto err_clk_enable; + return ret; } pl172->base = devm_ioremap(dev, adev->res.start, @@ -267,16 +259,11 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id) err_no_ioremap: amba_release_regions(adev); -err_clk_enable: - clk_disable_unprepare(pl172->clk); return ret; } static void pl172_remove(struct amba_device *adev) { - struct pl172_data *pl172 = amba_get_drvdata(adev); - - clk_disable_unprepare(pl172->clk); amba_release_regions(adev); } From 49ee2e842a40dec16ed4933bf2cd993c709f12a3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 Aug 2024 12:16:01 +0200 Subject: [PATCH 108/212] memory: pl353-smc: simplify with dev_err_probe() Use dev_err_probe() to avoid dmesg flood on actual defer. This makes the code also simpler. Reviewed-by: Miquel Raynal Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240823-b4-cleanup-h-guard-v1-6-01668915bd55@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/pl353-smc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c index 56e51737c81f..c75b99e49970 100644 --- a/drivers/memory/pl353-smc.c +++ b/drivers/memory/pl353-smc.c @@ -82,16 +82,14 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) return -ENOMEM; pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk"); - if (IS_ERR(pl353_smc->aclk)) { - dev_err(&adev->dev, "aclk clock not found.\n"); - return PTR_ERR(pl353_smc->aclk); - } + if (IS_ERR(pl353_smc->aclk)) + return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->aclk), + "aclk clock not found.\n"); pl353_smc->memclk = devm_clk_get(&adev->dev, "memclk"); - if (IS_ERR(pl353_smc->memclk)) { - dev_err(&adev->dev, "memclk clock not found.\n"); - return PTR_ERR(pl353_smc->memclk); - } + if (IS_ERR(pl353_smc->memclk)) + return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->memclk), + "memclk clock not found.\n"); err = clk_prepare_enable(pl353_smc->aclk); if (err) { From ce536578e5652ec4da10ec69436d2ae2548bd619 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 23 Aug 2024 12:16:02 +0200 Subject: [PATCH 109/212] memory: pl353-smc: simplify with devm_clk_get_enabled() Use devm_clk_get_enabled() to drop clock prepare/unprepare parts and make code simpler. Reviewed-by: Miquel Raynal Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20240823-b4-cleanup-h-guard-v1-7-01668915bd55@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/pl353-smc.c | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c index c75b99e49970..994c7a792e34 100644 --- a/drivers/memory/pl353-smc.c +++ b/drivers/memory/pl353-smc.c @@ -75,34 +75,21 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) const struct of_device_id *match = NULL; struct pl353_smc_data *pl353_smc; struct device_node *child; - int err; pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL); if (!pl353_smc) return -ENOMEM; - pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk"); + pl353_smc->aclk = devm_clk_get_enabled(&adev->dev, "apb_pclk"); if (IS_ERR(pl353_smc->aclk)) return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->aclk), "aclk clock not found.\n"); - pl353_smc->memclk = devm_clk_get(&adev->dev, "memclk"); + pl353_smc->memclk = devm_clk_get_enabled(&adev->dev, "memclk"); if (IS_ERR(pl353_smc->memclk)) return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->memclk), "memclk clock not found.\n"); - err = clk_prepare_enable(pl353_smc->aclk); - if (err) { - dev_err(&adev->dev, "Unable to enable AXI clock.\n"); - return err; - } - - err = clk_prepare_enable(pl353_smc->memclk); - if (err) { - dev_err(&adev->dev, "Unable to enable memory clock.\n"); - goto disable_axi_clk; - } - amba_set_drvdata(adev, pl353_smc); /* Find compatible children. Only a single child is supported */ @@ -115,30 +102,14 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) break; } if (!match) { - err = -ENODEV; dev_err(&adev->dev, "no matching children\n"); - goto disable_mem_clk; + return -ENODEV; } of_platform_device_create(child, NULL, &adev->dev); of_node_put(child); return 0; - -disable_mem_clk: - clk_disable_unprepare(pl353_smc->memclk); -disable_axi_clk: - clk_disable_unprepare(pl353_smc->aclk); - - return err; -} - -static void pl353_smc_remove(struct amba_device *adev) -{ - struct pl353_smc_data *pl353_smc = amba_get_drvdata(adev); - - clk_disable_unprepare(pl353_smc->memclk); - clk_disable_unprepare(pl353_smc->aclk); } static const struct amba_id pl353_ids[] = { @@ -157,7 +128,6 @@ static struct amba_driver pl353_smc_driver = { }, .id_table = pl353_ids, .probe = pl353_smc_probe, - .remove = pl353_smc_remove, }; module_amba_driver(pl353_smc_driver); From ff390189b7f2cfa20c644bc58b4462b5e2621838 Mon Sep 17 00:00:00 2001 From: Rong Qianfeng Date: Wed, 21 Aug 2024 11:25:57 +0800 Subject: [PATCH 110/212] memory: mtk-smi: Use devm_clk_get_enabled() Replace devm_clk_get() and clk_prepare_enable() with devm_clk_get_enabled() in .probe(). Fix the bug of missing clk_disable_unprepare() in .remove() by using devm_clk_get_enabled() that can disables and unprepares it automatically on driver detach. Fixes: 3c8f4ad85c4b ("memory/mediatek: add support for mt2701") Cc: honghui.zhang@mediatek.com Signed-off-by: Rong Qianfeng Reviewed-by: Yong Wu Link: https://lore.kernel.org/r/20240821032558.43052-1-rongqianfeng@vivo.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/mtk-smi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c index fbe52ecc0eca..2bc034dff691 100644 --- a/drivers/memory/mtk-smi.c +++ b/drivers/memory/mtk-smi.c @@ -771,13 +771,9 @@ static int mtk_smi_common_probe(struct platform_device *pdev) if (IS_ERR(common->smi_ao_base)) return PTR_ERR(common->smi_ao_base); - common->clk_async = devm_clk_get(dev, "async"); + common->clk_async = devm_clk_get_enabled(dev, "async"); if (IS_ERR(common->clk_async)) return PTR_ERR(common->clk_async); - - ret = clk_prepare_enable(common->clk_async); - if (ret) - return ret; } else { common->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(common->base)) From 259f5082721f1d17b4e5b9dc2bb430821afd95aa Mon Sep 17 00:00:00 2001 From: Aakarsh Jain Date: Thu, 8 Aug 2024 19:14:32 +0530 Subject: [PATCH 111/212] dt-bindings: media: s5p-mfc: Remove s5p-mfc.txt binding s5p-mfc bindings to json-schema is already merged with this commit 538af6e5856b ("dt-bindings: media: s5p-mfc: convert bindings to json-schema"). Remove s5p-mfc.txt file. Fixes: 538af6e5856b ("dt-bindings: media: s5p-mfc: convert bindings to json-schema") Signed-off-by: Aakarsh Jain Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240808134432.50073-1-aakarsh.jain@samsung.com Signed-off-by: Krzysztof Kozlowski --- Documentation/devicetree/bindings/media/s5p-mfc.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/s5p-mfc.txt diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt deleted file mode 100644 index e69de29bb2d1..000000000000 From 6614be05358869f1642964b650977018ac528a14 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 26 Aug 2024 16:37:51 +0200 Subject: [PATCH 112/212] firmware: qcom: scm: Allow QSEECOM on Surface Laptop 7 models Add the aforementioned machines to the list to get e.g. efivars up. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240826-topic-sl7-v2-2-c32ebae78789@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/firmware/qcom/qcom_scm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index bdb5e98b82ef..10986cb11ec0 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -1734,6 +1734,8 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { { .compatible = "lenovo,flex-5g" }, { .compatible = "lenovo,thinkpad-t14s" }, { .compatible = "lenovo,thinkpad-x13s", }, + { .compatible = "microsoft,romulus13", }, + { .compatible = "microsoft,romulus15", }, { .compatible = "qcom,sc8180x-primus" }, { .compatible = "qcom,x1e80100-crd" }, { .compatible = "qcom,x1e80100-qcp" }, From 9c3a62c20f7fb00294a4237e287254456ba8a48b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 15:57:21 +0200 Subject: [PATCH 113/212] firmware: tegra: bpmp: Drop unused mbox_client_to_bpmp() mbox_client_to_bpmp() is not used, W=1 builds: drivers/firmware/tegra/bpmp.c:28:1: error: unused function 'mbox_client_to_bpmp' [-Werror,-Wunused-function] Fixes: cdfa358b248e ("firmware: tegra: Refactor BPMP driver") Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Signed-off-by: Thierry Reding --- drivers/firmware/tegra/bpmp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index c1590d3aa9cb..c3a1dc344961 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -24,12 +24,6 @@ #define MSG_RING BIT(1) #define TAG_SZ 32 -static inline struct tegra_bpmp * -mbox_client_to_bpmp(struct mbox_client *client) -{ - return container_of(client, struct tegra_bpmp, mbox.client); -} - static inline const struct tegra_bpmp_ops * channel_to_ops(struct tegra_bpmp_channel *channel) { From 8812b8689ee652ee7f7e958473a9de56d7c184b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 16 Aug 2024 15:57:22 +0200 Subject: [PATCH 114/212] firmware: tegra: bpmp: Use scoped device node handling to simplify error paths Obtain the device node reference with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Thierry Reding --- drivers/firmware/tegra/bpmp.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index c3a1dc344961..2bee6e918f81 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -3,6 +3,7 @@ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. */ +#include #include #include #include @@ -34,29 +35,24 @@ channel_to_ops(struct tegra_bpmp_channel *channel) struct tegra_bpmp *tegra_bpmp_get(struct device *dev) { + struct device_node *np __free(device_node); struct platform_device *pdev; struct tegra_bpmp *bpmp; - struct device_node *np; np = of_parse_phandle(dev->of_node, "nvidia,bpmp", 0); if (!np) return ERR_PTR(-ENOENT); pdev = of_find_device_by_node(np); - if (!pdev) { - bpmp = ERR_PTR(-ENODEV); - goto put; - } + if (!pdev) + return ERR_PTR(-ENODEV); bpmp = platform_get_drvdata(pdev); if (!bpmp) { - bpmp = ERR_PTR(-EPROBE_DEFER); put_device(&pdev->dev); - goto put; + return ERR_PTR(-EPROBE_DEFER); } -put: - of_node_put(np); return bpmp; } EXPORT_SYMBOL_GPL(tegra_bpmp_get); From 50db2ef5c719c90ef30cbc05dd80ac91688fd966 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 27 Aug 2024 15:38:36 +0100 Subject: [PATCH 115/212] firmware: arm_scmi: Fix trivial whitespace/coding style issues Fix couple of unnecessary multiple blank lines and spaces instead of tabs. No functional change. Message-Id: <20240827143838.1465913-2-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/base.c | 2 -- drivers/firmware/arm_scmi/clock.c | 1 + drivers/firmware/arm_scmi/driver.c | 1 - drivers/firmware/arm_scmi/perf.c | 2 +- drivers/firmware/arm_scmi/pinctrl.c | 1 + drivers/firmware/arm_scmi/transports/mailbox.c | 1 - drivers/firmware/arm_scmi/transports/smc.c | 1 + 7 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index 9939b1d84b7a..d52873523cd2 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -42,7 +42,6 @@ struct scmi_msg_resp_base_discover_agent { u8 name[SCMI_SHORT_NAME_MAX_SIZE]; }; - struct scmi_msg_base_error_notify { __le32 event_control; #define BASE_TP_NOTIFY_ALL BIT(0) @@ -105,7 +104,6 @@ scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor) struct scmi_xfer *t; struct scmi_revision_info *rev = ph->get_priv(ph); - if (sub_vendor) { cmd = BASE_DISCOVER_SUB_VENDOR; vendor_id = rev->sub_vendor_id; diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 134019297d08..2ed2279388f0 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -365,6 +365,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, ret = ph->xops->do_xfer(ph, t); if (!ret) { u32 latency = 0; + attributes = le32_to_cpu(attr->attributes); strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE); /* clock_enable_latency field is present only since SCMI v3.1 */ diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 66806578df5a..69c15135371c 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -1030,7 +1030,6 @@ scmi_xfer_command_acquire(struct scmi_chan_info *cinfo, u32 msg_hdr) scmi_bad_message_trace(cinfo, msg_hdr, MSG_INVALID); scmi_inc_count(info->dbg->counters, ERR_MSG_INVALID); - /* On error the refcount incremented above has to be dropped */ __scmi_xfer_put(minfo, xfer); xfer = ERR_PTR(-EINVAL); diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 4b7f1cbb9b04..2d77b5f40ca7 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -310,7 +310,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, } if (!dom_info->mult_factor) dev_warn(ph->dev, - "Wrong sustained perf/frequency(domain %d)\n", + "Wrong sustained perf/frequency(domain %d)\n", dom_info->id); strscpy(dom_info->info.name, attr->name, diff --git a/drivers/firmware/arm_scmi/pinctrl.c b/drivers/firmware/arm_scmi/pinctrl.c index a2a7f880d6a3..3855c98caf06 100644 --- a/drivers/firmware/arm_scmi/pinctrl.c +++ b/drivers/firmware/arm_scmi/pinctrl.c @@ -913,4 +913,5 @@ static const struct scmi_protocol scmi_pinctrl = { .ops = &pinctrl_proto_ops, .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; + DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(pinctrl, scmi_pinctrl) diff --git a/drivers/firmware/arm_scmi/transports/mailbox.c b/drivers/firmware/arm_scmi/transports/mailbox.c index a481a2866062..9d258f5d5da8 100644 --- a/drivers/firmware/arm_scmi/transports/mailbox.c +++ b/drivers/firmware/arm_scmi/transports/mailbox.c @@ -238,7 +238,6 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, } } - cinfo->transport_info = smbox; smbox->cinfo = cinfo; diff --git a/drivers/firmware/arm_scmi/transports/smc.c b/drivers/firmware/arm_scmi/transports/smc.c index b7243939f161..2ffed5280eab 100644 --- a/drivers/firmware/arm_scmi/transports/smc.c +++ b/drivers/firmware/arm_scmi/transports/smc.c @@ -85,6 +85,7 @@ static irqreturn_t smc_msg_done_isr(int irq, void *data) static bool smc_chan_available(struct device_node *of_node, int idx) { struct device_node *np = of_parse_phandle(of_node, "shmem", 0); + if (!np) return false; From ccf502193126e168cfca08ec3d8a2460057a0da5 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 27 Aug 2024 15:38:37 +0100 Subject: [PATCH 116/212] firmware: arm_scmi: Replace the use of of_node_put() to __free(device_node) Use __free for device_node values, and thus drop calls to of_node_put. The goal is simplify of_node reference cleanup by using this scope-based of_node_put() cleanup to simplify function exit handling. When using __free a resource is allocated within a block, it is automatically freed at the end of the block. This cleanup aligns well with the recent change in shmem.c to use __free instead of explicit of_node_put() calls. Message-Id: <20240827143838.1465913-3-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/transports/mailbox.c | 10 ++++------ drivers/firmware/arm_scmi/transports/smc.c | 5 ++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/firmware/arm_scmi/transports/mailbox.c b/drivers/firmware/arm_scmi/transports/mailbox.c index 9d258f5d5da8..1a754dee24f7 100644 --- a/drivers/firmware/arm_scmi/transports/mailbox.c +++ b/drivers/firmware/arm_scmi/transports/mailbox.c @@ -129,18 +129,16 @@ static int mailbox_chan_validate(struct device *cdev, int *a2p_rx_chan, /* Bail out if provided shmem descriptors do not refer distinct areas */ if (num_sh > 1) { - struct device_node *np_tx, *np_rx; + struct device_node *np_tx __free(device_node) = + of_parse_phandle(np, "shmem", 0); + struct device_node *np_rx __free(device_node) = + of_parse_phandle(np, "shmem", 1); - np_tx = of_parse_phandle(np, "shmem", 0); - np_rx = of_parse_phandle(np, "shmem", 1); if (!np_tx || !np_rx || np_tx == np_rx) { dev_warn(cdev, "Invalid shmem descriptor for '%s'\n", of_node_full_name(np)); ret = -EINVAL; } - - of_node_put(np_tx); - of_node_put(np_rx); } /* Calculate channels IDs to use depending on mboxes/shmem layout */ diff --git a/drivers/firmware/arm_scmi/transports/smc.c b/drivers/firmware/arm_scmi/transports/smc.c index 2ffed5280eab..f8dd108777f9 100644 --- a/drivers/firmware/arm_scmi/transports/smc.c +++ b/drivers/firmware/arm_scmi/transports/smc.c @@ -84,12 +84,11 @@ static irqreturn_t smc_msg_done_isr(int irq, void *data) static bool smc_chan_available(struct device_node *of_node, int idx) { - struct device_node *np = of_parse_phandle(of_node, "shmem", 0); - + struct device_node *np __free(device_node) = + of_parse_phandle(of_node, "shmem", 0); if (!np) return false; - of_node_put(np); return true; } From c4b908a23fab2653cb844b77cbe576358c021053 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 27 Aug 2024 15:38:38 +0100 Subject: [PATCH 117/212] firmware: arm_scmi: Replace comma with the semicolon Replace the typo comma with the semicolon. No functional change. Message-Id: <20240827143838.1465913-4-sudeep.holla@arm.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index d52873523cd2..86b376c50a13 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -384,7 +384,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph) if (ret) return ret; - rev->major_ver = PROTOCOL_REV_MAJOR(version), + rev->major_ver = PROTOCOL_REV_MAJOR(version); rev->minor_ver = PROTOCOL_REV_MINOR(version); ph->set_priv(ph, rev, version); From 952ceb03787dde88fc713c7453824e25bf12cb3a Mon Sep 17 00:00:00 2001 From: Kousik Sanagavarapu Date: Sun, 25 Aug 2024 14:18:42 +0530 Subject: [PATCH 118/212] soc: ti: pruss: factor out memories setup Factor out memories setup code from probe() into a new function pruss_of_setup_memories(). This sets the stage for introducing auto cleanup of the device node (done in the subsequent patch), since the clean up depends on the scope of the pointer and factoring out code into a separate function obviously limits the scope of the various variables used in that function. Apart from the above, this change also has the advantage of making the code look more neat. While at it, use dev_err_probe() instead of plain dev_err() as this new function is called by the probe(). Signed-off-by: Kousik Sanagavarapu Link: https://lore.kernel.org/r/20240825085714.10736-2-five231003@gmail.com Signed-off-by: Nishanth Menon --- drivers/soc/ti/pruss.c | 111 ++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 50 deletions(-) diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index 24a42e0b645c..83d7d8d5ef22 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -415,6 +415,63 @@ static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node) return ret; } +static int pruss_of_setup_memories(struct device *dev, struct pruss *pruss) +{ + struct device_node *np = dev_of_node(dev); + struct device_node *child; + const struct pruss_private_data *data = of_device_get_match_data(dev); + const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" }; + int i; + + child = of_get_child_by_name(np, "memories"); + if (!child) + return dev_err_probe(dev, -ENODEV, + "%pOF is missing its 'memories' node\n", + child); + + for (i = 0; i < PRUSS_MEM_MAX; i++) { + struct resource res; + int index; + + /* + * On AM437x one of two PRUSS units don't contain Shared RAM, + * skip it + */ + if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2) + continue; + + index = of_property_match_string(child, "reg-names", + mem_names[i]); + if (index < 0) { + of_node_put(child); + return index; + } + + if (of_address_to_resource(child, index, &res)) { + of_node_put(child); + return -EINVAL; + } + + pruss->mem_regions[i].va = devm_ioremap(dev, res.start, + resource_size(&res)); + if (!pruss->mem_regions[i].va) { + of_node_put(child); + return dev_err_probe(dev, -ENOMEM, + "failed to parse and map memory resource %d %s\n", + i, mem_names[i]); + } + pruss->mem_regions[i].pa = res.start; + pruss->mem_regions[i].size = resource_size(&res); + + dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n", + mem_names[i], &pruss->mem_regions[i].pa, + pruss->mem_regions[i].size, pruss->mem_regions[i].va); + } + of_node_put(child); + + return 0; +} + static struct regmap_config regmap_conf = { .reg_bits = 32, .val_bits = 32, @@ -471,15 +528,8 @@ static int pruss_cfg_of_init(struct device *dev, struct pruss *pruss) static int pruss_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev_of_node(dev); - struct device_node *child; struct pruss *pruss; - struct resource res; - int ret, i, index; - const struct pruss_private_data *data; - const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" }; - - data = of_device_get_match_data(&pdev->dev); + int ret; ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); if (ret) { @@ -494,48 +544,9 @@ static int pruss_probe(struct platform_device *pdev) pruss->dev = dev; mutex_init(&pruss->lock); - child = of_get_child_by_name(np, "memories"); - if (!child) { - dev_err(dev, "%pOF is missing its 'memories' node\n", child); - return -ENODEV; - } - - for (i = 0; i < PRUSS_MEM_MAX; i++) { - /* - * On AM437x one of two PRUSS units don't contain Shared RAM, - * skip it - */ - if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2) - continue; - - index = of_property_match_string(child, "reg-names", - mem_names[i]); - if (index < 0) { - of_node_put(child); - return index; - } - - if (of_address_to_resource(child, index, &res)) { - of_node_put(child); - return -EINVAL; - } - - pruss->mem_regions[i].va = devm_ioremap(dev, res.start, - resource_size(&res)); - if (!pruss->mem_regions[i].va) { - dev_err(dev, "failed to parse and map memory resource %d %s\n", - i, mem_names[i]); - of_node_put(child); - return -ENOMEM; - } - pruss->mem_regions[i].pa = res.start; - pruss->mem_regions[i].size = resource_size(&res); - - dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n", - mem_names[i], &pruss->mem_regions[i].pa, - pruss->mem_regions[i].size, pruss->mem_regions[i].va); - } - of_node_put(child); + ret = pruss_of_setup_memories(dev, pruss); + if (ret < 0) + return ret; platform_set_drvdata(pdev, pruss); From df70c0b4828bb85f1370453288a0a63d7618decf Mon Sep 17 00:00:00 2001 From: Kousik Sanagavarapu Date: Sun, 25 Aug 2024 14:18:43 +0530 Subject: [PATCH 119/212] soc: ti: pruss: do device_node auto cleanup Use scope based cleanup instead of manual of_node_put() calls, hence simplifying the handling of error paths at various places. While at it, use dev_err_probe() instead of dev_err() in all the code paths touched. Suggested-by: Julia Lawall Signed-off-by: Kousik Sanagavarapu Link: https://lore.kernel.org/r/20240825085714.10736-3-five231003@gmail.com Signed-off-by: Nishanth Menon --- drivers/soc/ti/pruss.c | 91 +++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 58 deletions(-) diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index 83d7d8d5ef22..3ec758f50e24 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -380,50 +380,42 @@ static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux, static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node) { - const struct pruss_private_data *data; - struct device_node *clks_np; struct device *dev = pruss->dev; - int ret = 0; + struct device_node *clks_np __free(device_node) = + of_get_child_by_name(cfg_node, "clocks"); + const struct pruss_private_data *data = of_device_get_match_data(dev); + int ret; - data = of_device_get_match_data(dev); - - clks_np = of_get_child_by_name(cfg_node, "clocks"); - if (!clks_np) { - dev_err(dev, "%pOF is missing its 'clocks' node\n", cfg_node); - return -ENODEV; - } + if (!clks_np) + return dev_err_probe(dev, -ENODEV, + "%pOF is missing its 'clocks' node\n", + cfg_node); if (data && data->has_core_mux_clock) { ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux, "coreclk-mux", clks_np); - if (ret) { - dev_err(dev, "failed to setup coreclk-mux\n"); - goto put_clks_node; - } + if (ret) + return dev_err_probe(dev, ret, + "failed to setup coreclk-mux\n"); } ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux", clks_np); - if (ret) { - dev_err(dev, "failed to setup iepclk-mux\n"); - goto put_clks_node; - } + if (ret) + return dev_err_probe(dev, ret, "failed to setup iepclk-mux\n"); -put_clks_node: - of_node_put(clks_np); - - return ret; + return 0; } static int pruss_of_setup_memories(struct device *dev, struct pruss *pruss) { struct device_node *np = dev_of_node(dev); - struct device_node *child; + struct device_node *child __free(device_node) = + of_get_child_by_name(np, "memories"); const struct pruss_private_data *data = of_device_get_match_data(dev); const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" }; int i; - child = of_get_child_by_name(np, "memories"); if (!child) return dev_err_probe(dev, -ENODEV, "%pOF is missing its 'memories' node\n", @@ -442,24 +434,18 @@ static int pruss_of_setup_memories(struct device *dev, struct pruss *pruss) index = of_property_match_string(child, "reg-names", mem_names[i]); - if (index < 0) { - of_node_put(child); + if (index < 0) return index; - } - if (of_address_to_resource(child, index, &res)) { - of_node_put(child); + if (of_address_to_resource(child, index, &res)) return -EINVAL; - } pruss->mem_regions[i].va = devm_ioremap(dev, res.start, resource_size(&res)); - if (!pruss->mem_regions[i].va) { - of_node_put(child); + if (!pruss->mem_regions[i].va) return dev_err_probe(dev, -ENOMEM, "failed to parse and map memory resource %d %s\n", i, mem_names[i]); - } pruss->mem_regions[i].pa = res.start; pruss->mem_regions[i].size = resource_size(&res); @@ -467,7 +453,6 @@ static int pruss_of_setup_memories(struct device *dev, struct pruss *pruss) mem_names[i], &pruss->mem_regions[i].pa, pruss->mem_regions[i].size, pruss->mem_regions[i].va); } - of_node_put(child); return 0; } @@ -481,26 +466,21 @@ static struct regmap_config regmap_conf = { static int pruss_cfg_of_init(struct device *dev, struct pruss *pruss) { struct device_node *np = dev_of_node(dev); - struct device_node *child; + struct device_node *child __free(device_node) = + of_get_child_by_name(np, "cfg"); struct resource res; int ret; - child = of_get_child_by_name(np, "cfg"); - if (!child) { - dev_err(dev, "%pOF is missing its 'cfg' node\n", child); - return -ENODEV; - } + if (!child) + return dev_err_probe(dev, -ENODEV, + "%pOF is missing its 'cfg' node\n", child); - if (of_address_to_resource(child, 0, &res)) { - ret = -ENOMEM; - goto node_put; - } + if (of_address_to_resource(child, 0, &res)) + return -ENOMEM; pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res)); - if (!pruss->cfg_base) { - ret = -ENOMEM; - goto node_put; - } + if (!pruss->cfg_base) + return -ENOMEM; regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child, (u64)res.start); @@ -509,20 +489,15 @@ static int pruss_cfg_of_init(struct device *dev, struct pruss *pruss) pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base, ®map_conf); kfree(regmap_conf.name); - if (IS_ERR(pruss->cfg_regmap)) { - dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n", - PTR_ERR(pruss->cfg_regmap)); - ret = PTR_ERR(pruss->cfg_regmap); - goto node_put; - } + if (IS_ERR(pruss->cfg_regmap)) + return dev_err_probe(dev, PTR_ERR(pruss->cfg_regmap), + "regmap_init_mmio failed for cfg\n"); ret = pruss_clk_init(pruss, child); if (ret) - dev_err(dev, "pruss_clk_init failed, ret = %d\n", ret); + return dev_err_probe(dev, ret, "pruss_clk_init failed\n"); -node_put: - of_node_put(child); - return ret; + return 0; } static int pruss_probe(struct platform_device *pdev) From b0289dbf1c952c04ba48b05cc6345381999ef055 Mon Sep 17 00:00:00 2001 From: Kousik Sanagavarapu Date: Sun, 25 Aug 2024 14:18:44 +0530 Subject: [PATCH 120/212] soc: ti: knav_qmss_queue: do device_node auto cleanup Use scope based cleanup, instead of manual of_node_put() calls, which automatically free()s "struct device_node". While at it, refactor the code from knav_queue_probe() into the separate functions to make auto cleanup look more neat. Doing the cleanup this way has the advantage of reducing the chance of memory leaks in case we need to read from new OF nodes in the future when we probe. Suggested-by: Julia Lawall Reviewed-by: Jonathan Cameron Signed-off-by: Kousik Sanagavarapu Link: https://lore.kernel.org/r/20240825085714.10736-4-five231003@gmail.com Signed-off-by: Nishanth Menon --- drivers/soc/ti/knav_qmss_queue.c | 100 ++++++++++++++++--------------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index a15eaa1900ab..6c98738e548a 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1076,14 +1076,20 @@ static const char *knav_queue_find_name(struct device_node *node) } static int knav_queue_setup_regions(struct knav_device *kdev, - struct device_node *regions) + struct device_node *node) { struct device *dev = kdev->dev; + struct device_node *regions __free(device_node) = + of_get_child_by_name(node, "descriptor-regions"); struct knav_region *region; struct device_node *child; u32 temp[2]; int ret; + if (!regions) + return dev_err_probe(dev, -ENODEV, + "descriptor-regions not specified\n"); + for_each_child_of_node(regions, child) { region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL); if (!region) { @@ -1116,10 +1122,9 @@ static int knav_queue_setup_regions(struct knav_device *kdev, INIT_LIST_HEAD(®ion->pools); list_add_tail(®ion->list, &kdev->regions); } - if (list_empty(&kdev->regions)) { - dev_err(dev, "no valid region information found\n"); - return -ENODEV; - } + if (list_empty(&kdev->regions)) + return dev_err_probe(dev, -ENODEV, + "no valid region information found\n"); /* Next, we run through the regions and set things up */ for_each_region(kdev, region) @@ -1301,10 +1306,16 @@ static int knav_setup_queue_range(struct knav_device *kdev, } static int knav_setup_queue_pools(struct knav_device *kdev, - struct device_node *queue_pools) + struct device_node *node) { + struct device_node *queue_pools __free(device_node) = + of_get_child_by_name(node, "queue-pools"); struct device_node *type, *range; + if (!queue_pools) + return dev_err_probe(kdev->dev, -ENODEV, + "queue-pools not specified\n"); + for_each_child_of_node(queue_pools, type) { for_each_child_of_node(type, range) { /* return value ignored, we init the rest... */ @@ -1313,10 +1324,9 @@ static int knav_setup_queue_pools(struct knav_device *kdev, } /* ... and barf if they all failed! */ - if (list_empty(&kdev->queue_ranges)) { - dev_err(kdev->dev, "no valid queue range found\n"); - return -ENODEV; - } + if (list_empty(&kdev->queue_ranges)) + return dev_err_probe(kdev->dev, -ENODEV, + "no valid queue range found\n"); return 0; } @@ -1384,14 +1394,20 @@ static void __iomem *knav_queue_map_reg(struct knav_device *kdev, } static int knav_queue_init_qmgrs(struct knav_device *kdev, - struct device_node *qmgrs) + struct device_node *node) { struct device *dev = kdev->dev; + struct device_node *qmgrs __free(device_node) = + of_get_child_by_name(node, "qmgrs"); struct knav_qmgr_info *qmgr; struct device_node *child; u32 temp[2]; int ret; + if (!qmgrs) + return dev_err_probe(dev, -ENODEV, + "queue manager info not specified\n"); + for_each_child_of_node(qmgrs, child) { qmgr = devm_kzalloc(dev, sizeof(*qmgr), GFP_KERNEL); if (!qmgr) { @@ -1663,6 +1679,26 @@ static int knav_queue_start_pdsps(struct knav_device *kdev) return 0; } +static int knav_queue_setup_pdsps(struct knav_device *kdev, + struct device_node *node) +{ + struct device_node *pdsps __free(device_node) = + of_get_child_by_name(node, "pdsps"); + + if (pdsps) { + int ret; + + ret = knav_queue_init_pdsps(kdev, pdsps); + if (ret) + return ret; + + ret = knav_queue_start_pdsps(kdev); + if (ret) + return ret; + } + return 0; +} + static inline struct knav_qmgr_info *knav_find_qmgr(unsigned id) { struct knav_qmgr_info *qmgr; @@ -1750,7 +1786,6 @@ MODULE_DEVICE_TABLE(of, keystone_qmss_of_match); static int knav_queue_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; - struct device_node *qmgrs, *queue_pools, *regions, *pdsps; struct device *dev = &pdev->dev; u32 temp[2]; int ret; @@ -1794,39 +1829,17 @@ static int knav_queue_probe(struct platform_device *pdev) kdev->num_queues = temp[1]; /* Initialize queue managers using device tree configuration */ - qmgrs = of_get_child_by_name(node, "qmgrs"); - if (!qmgrs) { - dev_err(dev, "queue manager info not specified\n"); - ret = -ENODEV; - goto err; - } - ret = knav_queue_init_qmgrs(kdev, qmgrs); - of_node_put(qmgrs); + ret = knav_queue_init_qmgrs(kdev, node); if (ret) goto err; /* get pdsp configuration values from device tree */ - pdsps = of_get_child_by_name(node, "pdsps"); - if (pdsps) { - ret = knav_queue_init_pdsps(kdev, pdsps); - if (ret) - goto err; - - ret = knav_queue_start_pdsps(kdev); - if (ret) - goto err; - } - of_node_put(pdsps); + ret = knav_queue_setup_pdsps(kdev, node); + if (ret) + goto err; /* get usable queue range values from device tree */ - queue_pools = of_get_child_by_name(node, "queue-pools"); - if (!queue_pools) { - dev_err(dev, "queue-pools not specified\n"); - ret = -ENODEV; - goto err; - } - ret = knav_setup_queue_pools(kdev, queue_pools); - of_node_put(queue_pools); + ret = knav_setup_queue_pools(kdev, node); if (ret) goto err; @@ -1848,14 +1861,7 @@ static int knav_queue_probe(struct platform_device *pdev) if (ret) goto err; - regions = of_get_child_by_name(node, "descriptor-regions"); - if (!regions) { - dev_err(dev, "descriptor-regions not specified\n"); - ret = -ENODEV; - goto err; - } - ret = knav_queue_setup_regions(kdev, regions); - of_node_put(regions); + ret = knav_queue_setup_regions(kdev, node); if (ret) goto err; From 68123510b7c1c610387dd306f92ff539c3c546b5 Mon Sep 17 00:00:00 2001 From: Kousik Sanagavarapu Date: Sun, 25 Aug 2024 14:18:45 +0530 Subject: [PATCH 121/212] soc: ti: pm33xx: do device_node auto cleanup Use scope based cleanup instead of manual of_node_put() calls, hence simplifying the handling of error paths. Suggested-by: Julia Lawall Signed-off-by: Kousik Sanagavarapu Link: https://lore.kernel.org/r/20240825085714.10736-5-five231003@gmail.com Signed-off-by: Nishanth Menon --- drivers/soc/ti/pm33xx.c | 52 +++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 3a56bbf3268a..8169885ab1e0 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -383,54 +383,44 @@ static void am33xx_pm_free_sram(void) */ static int am33xx_pm_alloc_sram(void) { - struct device_node *np; - int ret = 0; + struct device_node *np __free(device_node) = + of_find_compatible_node(NULL, NULL, "ti,omap3-mpu"); - np = of_find_compatible_node(NULL, NULL, "ti,omap3-mpu"); if (!np) { np = of_find_compatible_node(NULL, NULL, "ti,omap4-mpu"); - if (!np) { - dev_err(pm33xx_dev, "PM: %s: Unable to find device node for mpu\n", - __func__); - return -ENODEV; - } + if (!np) + return dev_err_probe(pm33xx_dev, -ENODEV, + "PM: %s: Unable to find device node for mpu\n", + __func__); } sram_pool = of_gen_pool_get(np, "pm-sram", 0); - if (!sram_pool) { - dev_err(pm33xx_dev, "PM: %s: Unable to get sram pool for ocmcram\n", - __func__); - ret = -ENODEV; - goto mpu_put_node; - } + if (!sram_pool) + return dev_err_probe(pm33xx_dev, -ENODEV, + "PM: %s: Unable to get sram pool for ocmcram\n", + __func__); sram_pool_data = of_gen_pool_get(np, "pm-sram", 1); - if (!sram_pool_data) { - dev_err(pm33xx_dev, "PM: %s: Unable to get sram data pool for ocmcram\n", - __func__); - ret = -ENODEV; - goto mpu_put_node; - } + if (!sram_pool_data) + return dev_err_probe(pm33xx_dev, -ENODEV, + "PM: %s: Unable to get sram data pool for ocmcram\n", + __func__); ocmcram_location = gen_pool_alloc(sram_pool, *pm_sram->do_wfi_sz); - if (!ocmcram_location) { - dev_err(pm33xx_dev, "PM: %s: Unable to allocate memory from ocmcram\n", - __func__); - ret = -ENOMEM; - goto mpu_put_node; - } + if (!ocmcram_location) + return dev_err_probe(pm33xx_dev, -ENOMEM, + "PM: %s: Unable to allocate memory from ocmcram\n", + __func__); ocmcram_location_data = gen_pool_alloc(sram_pool_data, sizeof(struct emif_regs_amx3)); if (!ocmcram_location_data) { - dev_err(pm33xx_dev, "PM: Unable to allocate memory from ocmcram\n"); gen_pool_free(sram_pool, ocmcram_location, *pm_sram->do_wfi_sz); - ret = -ENOMEM; + return dev_err_probe(pm33xx_dev, -ENOMEM, + "PM: Unable to allocate memory from ocmcram\n"); } -mpu_put_node: - of_node_put(np); - return ret; + return 0; } static int am33xx_pm_rtc_setup(void) From 7d2b23fda9961e7bfdd063a1708445b101a831c5 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 23 Aug 2024 17:05:17 +0800 Subject: [PATCH 122/212] dt-bindings: firmware: Add i.MX95 SCMI Extension protocol Add i.MX SCMI Extension protocols bindings for: - Battery Backed Module(BBM) Protocol This contains persistent storage (GPR), an RTC, and the ON/OFF button. The protocol can also provide access to similar functions implemented via external board components. - MISC Protocol. This includes controls that are misc settings/actions that must be exposed from the SM to agents. They are device specific and are usually define to access bit fields in various mix block control modules, IOMUX_GPR, and other GPR/CSR owned by the SM. Reviewed-by: Rob Herring (Arm) Reviewed-by: Cristian Marussi Signed-off-by: Peng Fan Message-Id: <20240823-imx95-bbm-misc-v2-v8-1-e600ed9e9271@nxp.com> Signed-off-by: Sudeep Holla --- .../bindings/firmware/arm,scmi.yaml | 5 ++- .../bindings/firmware/nxp,imx95-scmi.yaml | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/firmware/nxp,imx95-scmi.yaml diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml index 211f5254adf2..54d7d11bfed4 100644 --- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml +++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml @@ -22,6 +22,9 @@ description: | [0] https://developer.arm.com/documentation/den0056/latest +anyOf: + - $ref: /schemas/firmware/nxp,imx95-scmi.yaml + properties: $nodename: const: scmi @@ -299,7 +302,7 @@ properties: required: - reg -additionalProperties: false +unevaluatedProperties: false $defs: protocol-node: diff --git a/Documentation/devicetree/bindings/firmware/nxp,imx95-scmi.yaml b/Documentation/devicetree/bindings/firmware/nxp,imx95-scmi.yaml new file mode 100644 index 000000000000..1a95010a546b --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/nxp,imx95-scmi.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2024 NXP +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/firmware/nxp,imx95-scmi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: i.MX95 System Control and Management Interface(SCMI) Vendor Protocols Extension + +maintainers: + - Peng Fan + +properties: + protocol@81: + $ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node' + unevaluatedProperties: false + + properties: + reg: + const: 0x81 + + protocol@84: + $ref: '/schemas/firmware/arm,scmi.yaml#/$defs/protocol-node' + unevaluatedProperties: false + + properties: + reg: + const: 0x84 + + nxp,ctrl-ids: + description: + Each entry consists of 2 integers, represents the ctrl id and the value + items: + items: + - description: the ctrl id index + enum: [0, 1, 2, 3, 4, 5, 6, 7, 0x8000, 0x8001, 0x8002, 0x8003, + 0x8004, 0x8005, 0x8006, 0x8007] + - description: the value assigned to the ctrl id + minItems: 1 + maxItems: 16 + $ref: /schemas/types.yaml#/definitions/uint32-matrix + +additionalProperties: true From c66beeab7436de419b6f3281479d702c1b0eb915 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 23 Aug 2024 17:05:20 +0800 Subject: [PATCH 123/212] firmware: arm_scmi: Add NXP i.MX95 SCMI documentation Add NXP i.MX95 System Control Management Interface(SCMI) vendor extensions protocol documentation. Reviewed-by: Cristian Marussi Signed-off-by: Peng Fan Message-Id: <20240823-imx95-bbm-misc-v2-v8-4-e600ed9e9271@nxp.com> Signed-off-by: Sudeep Holla --- .../firmware/arm_scmi/vendors/imx/imx95.rst | 886 ++++++++++++++++++ 1 file changed, 886 insertions(+) create mode 100644 drivers/firmware/arm_scmi/vendors/imx/imx95.rst diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx95.rst b/drivers/firmware/arm_scmi/vendors/imx/imx95.rst new file mode 100644 index 000000000000..b2dfd6c46ca2 --- /dev/null +++ b/drivers/firmware/arm_scmi/vendors/imx/imx95.rst @@ -0,0 +1,886 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: + +=============================================================================== +i.MX95 System Control and Management Interface(SCMI) Vendor Protocols Extension +=============================================================================== + +:Copyright: |copy| 2024 NXP + +:Author: Peng Fan + +The System Manager (SM) is a low-level system function which runs on a System +Control Processor (SCP) to support isolation and management of power domains, +clocks, resets, sensors, pins, etc. on complex application processors. It often +runs on a Cortex-M processor and provides an abstraction to many of the +underlying features of the hardware. The primary purpose of the SM is to allow +isolation between software running on different cores in the SoC. It does this +by having exclusive access to critical resources such as those controlling +power, clocks, reset, PMIC, etc. and then providing an RPC interface to those +clients. This allows the SM to provide access control, arbitration, and +aggregation policies for those shared critical resources. + +SM introduces a concept Logic Machine(LM) which is analogous to VM and each has +its own instance of SCMI. All normal SCMI calls only apply to that LM. That +includes boot, shutdown, reset, suspend, wake, etc. Each LM (e.g. A55 and M7) +are completely isolated from the others and each LM has its own communication +channels talking to the same SCMI server. + +This document covers all the information necessary to understand, maintain, +port, and deploy the SM on supported processors. + +The SM implements an interface compliant with the Arm SCMI Specification +with additional vendor specific extensions. + +SCMI_BBM: System Control and Management BBM Vendor Protocol +============================================================== + +This protocol is intended provide access to the battery-backed module. This +contains persistent storage (GPR), an RTC, and the ON/OFF button. The protocol +can also provide access to similar functions implemented via external board +components. The BBM protocol provides functions to: + +- Describe the protocol version. +- Discover implementation attributes. +- Read/write GPR +- Discover the RTCs available in the system. +- Read/write the RTC time in seconds and ticks +- Set an alarm (per LM) in seconds +- Get notifications on RTC update, alarm, or rollover. +- Get notification on ON/OFF button activity. + +For most SoC, there is one on-chip RTC (e.g. in BBNSM) and this is RTC ID 0. +Board code can add additional GPR and RTC. + +GPR are not aggregated. The RTC time is also not aggregated. Setting these +sets for all so normally exclusive access would be granted to one agent for +each. However, RTC alarms are maintained for each LM and the hardware is +programmed with the next nearest alarm time. So only one agent in an LM should +be given access rights to set an RTC alarm. + +Commands: +_________ + +PROTOCOL_VERSION +~~~~~~~~~~~~~~~~ + +message_id: 0x0 +protocol_id: 0x81 + ++---------------+--------------------------------------------------------------+ +|Return values | ++---------------+--------------------------------------------------------------+ +|Name |Description | ++---------------+--------------------------------------------------------------+ +|int32 status | See ARM SCMI Specification for status code definitions. | ++---------------+--------------------------------------------------------------+ +|uint32 version | For this revision of the specification, this value must be | +| | 0x10000. | ++---------------+--------------------------------------------------------------+ + +PROTOCOL_ATTRIBUTES +~~~~~~~~~~~~~~~~~~~ + +message_id: 0x1 +protocol_id: 0x81 + ++---------------+--------------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status | See ARM SCMI Specification for status code definitions. | ++------------------+-----------------------------------------------------------+ +|uint32 attributes | Bits[31:8] Number of RTCs. | +| | Bits[15:0] Number of persistent storage (GPR) words. | ++------------------+-----------------------------------------------------------+ + +PROTOCOL_MESSAGE_ATTRIBUTES +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +message_id: 0x2 +protocol_id: 0x81 + ++---------------+--------------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: in case the message is implemented and available | +| |to use. | +| |NOT_FOUND: if the message identified by message_id is | +| |invalid or not implemented | ++------------------+-----------------------------------------------------------+ +|uint32 attributes |Flags that are associated with a specific function in the | +| |protocol. For all functions in this protocol, this | +| |parameter has a value of 0 | ++------------------+-----------------------------------------------------------+ + +BBM_GPR_SET +~~~~~~~~~~~ + +message_id: 0x3 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of GPR to write | ++------------------+-----------------------------------------------------------+ +|uint32 value |32-bit value to write to the GPR | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if the GPR was successfully written. | +| |NOT_FOUND: if the index is not valid. | +| |DENIED: if the agent does not have permission to write | +| |the specified GPR | ++------------------+-----------------------------------------------------------+ + +BBM_GPR_GET +~~~~~~~~~~~ + +message_id: 0x4 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of GPR to read | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if the GPR was successfully read. | +| |NOT_FOUND: if the index is not valid. | +| |DENIED: if the agent does not have permission to read | +| |the specified GPR. | ++------------------+-----------------------------------------------------------+ +|uint32 value |32-bit value read from the GPR | ++------------------+-----------------------------------------------------------+ + +BBM_RTC_ATTRIBUTES +~~~~~~~~~~~~~~~~~~ + +message_id: 0x5 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of RTC | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: returned the attributes. | +| |NOT_FOUND: Index is invalid. | ++------------------+-----------------------------------------------------------+ +|uint32 attributes |Bit[31:24] Bit width of RTC seconds. | +| |Bit[23:16] Bit width of RTC ticks. | +| |Bits[15:0] RTC ticks per second | ++------------------+-----------------------------------------------------------+ +|uint8 name[16] |Null-terminated ASCII string of up to 16 bytes in length | +| |describing the RTC name | ++------------------+-----------------------------------------------------------+ + +BBM_RTC_TIME_SET +~~~~~~~~~~~~~~~~ + +message_id: 0x6 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of RTC | ++------------------+-----------------------------------------------------------+ +|uint32 flags |Bits[31:1] Reserved, must be zero. | +| |Bit[0] RTC time format: | +| |Set to 1 if the time is in ticks. | +| |Set to 0 if the time is in seconds | ++------------------+-----------------------------------------------------------+ +|uint32 time[2] |Lower word: Lower 32 bits of the time in seconds/ticks. | +| |Upper word: Upper 32 bits of the time in seconds/ticks. | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: RTC time was successfully set. | +| |NOT_FOUND: rtcId pertains to a non-existent RTC. | +| |INVALID_PARAMETERS: time is not valid | +| |(beyond the range of the RTC). | +| |DENIED: the agent does not have permission to set the RTC. | ++------------------+-----------------------------------------------------------+ + +BBM_RTC_TIME_GET +~~~~~~~~~~~~~~~~ + +message_id: 0x7 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of RTC | ++------------------+-----------------------------------------------------------+ +|uint32 flags |Bits[31:1] Reserved, must be zero. | +| |Bit[0] RTC time format: | +| |Set to 1 if the time is in ticks. | +| |Set to 0 if the time is in seconds | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: RTC time was successfully get. | +| |NOT_FOUND: rtcId pertains to a non-existent RTC. | ++------------------+-----------------------------------------------------------+ +|uint32 time[2] |Lower word: Lower 32 bits of the time in seconds/ticks. | +| |Upper word: Upper 32 bits of the time in seconds/ticks. | ++------------------+-----------------------------------------------------------+ + +BBM_RTC_ALARM_SET +~~~~~~~~~~~~~~~~~ + +message_id: 0x8 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of RTC | ++------------------+-----------------------------------------------------------+ +|uint32 flags |Bits[31:1] Reserved, must be zero. | +| |Bit[0] RTC enable flag: | +| |Set to 1 if the RTC alarm should be enabled. | +| |Set to 0 if the RTC alarm should be disabled | ++------------------+-----------------------------------------------------------+ +|uint32 time[2] |Lower word: Lower 32 bits of the time in seconds. | +| |Upper word: Upper 32 bits of the time in seconds. | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: RTC time was successfully set. | +| |NOT_FOUND: rtcId pertains to a non-existent RTC. | +| |INVALID_PARAMETERS: time is not valid | +| |(beyond the range of the RTC). | +| |DENIED: the agent does not have permission to set the RTC | +| |alarm | ++------------------+-----------------------------------------------------------+ + +BBM_BUTTON_GET +~~~~~~~~~~~~~~ + +message_id: 0x9 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if the button status was read. | +| |Other value: ARM SCMI Specification status code definitions| ++------------------+-----------------------------------------------------------+ +|uint32 state |State of the ON/OFF button. 1: ON, 0: OFF | ++------------------+-----------------------------------------------------------+ + +BBM_RTC_NOTIFY +~~~~~~~~~~~~~~ + +message_id: 0xA +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of RTC | ++------------------+-----------------------------------------------------------+ +|uint32 flags |Notification flags | +| |Bits[31:3] Reserved, must be zero. | +| |Bit[2] Update enable: | +| |Set to 1 to send notification. | +| |Set to 0 if no notification. | +| |Bit[1] Rollover enable: | +| |Set to 1 to send notification. | +| |Set to 0 if no notification. | +| |Bit[0] Alarm enable: | +| |Set to 1 to send notification. | +| |Set to 0 if no notification | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: notification configuration was successfully | +| |updated. | +| |NOT_FOUND: rtcId pertains to a non-existent RTC. | +| |DENIED: the agent does not have permission to request RTC | +| |notifications. | ++------------------+-----------------------------------------------------------+ + +BBM_BUTTON_NOTIFY +~~~~~~~~~~~~~~~~~ + +message_id: 0xB +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 flags |Notification flags | +| |Bits[31:1] Reserved, must be zero. | +| |Bit[0] Enable button: | +| |Set to 1 to send notification. | +| |Set to 0 if no notification | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: notification configuration was successfully | +| |updated. | +| |DENIED: the agent does not have permission to request | +| |button notifications. | ++------------------+-----------------------------------------------------------+ + +NEGOTIATE_PROTOCOL_VERSION +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +message_id: 0x10 +protocol_id: 0x81 + ++--------------------+---------------------------------------------------------+ +|Parameters | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|uint32 version |The negotiated protocol version the agent intends to use | ++--------------------+---------------------------------------------------------+ +|Return values | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|int32 status |SUCCESS: if the negotiated protocol version is supported | +| |by the platform. All commands, responses, and | +| |notifications post successful return of this command must| +| |comply with the negotiated version. | +| |NOT_SUPPORTED: if the protocol version is not supported. | ++--------------------+---------------------------------------------------------+ + +Notifications +_____________ + +BBM_RTC_EVENT +~~~~~~~~~~~~~ + +message_id: 0x0 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 flags |RTC events: | +| |Bits[31:2] Reserved, must be zero. | +| |Bit[1] RTC rollover notification: | +| |1 RTC rollover detected. | +| |0 no RTC rollover detected. | +| |Bit[0] RTC alarm notification: | +| |1 RTC alarm generated. | +| |0 no RTC alarm generated. | ++------------------+-----------------------------------------------------------+ + +BBM_BUTTON_EVENT +~~~~~~~~~~~~~~~~ + +message_id: 0x1 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 flags |RTC events: | ++------------------+-----------------------------------------------------------+ +| |Button events: | +| |Bits[31:1] Reserved, must be zero. | +| |Bit[0] Button notification: | +| |1 button change detected. | +| |0 no button change detected. | ++------------------+-----------------------------------------------------------+ + +SCMI_MISC: System Control and Management MISC Vendor Protocol +================================================================ + +Provides miscellaneous functions. This includes controls that are miscellaneous +settings/actions that must be exposed from the SM to agents. They are device +specific and are usually define to access bit fields in various mix block +control modules, IOMUX_GPR, and other GPR/CSR owned by the SM. This protocol +supports the following functions: + +- Describe the protocol version. +- Discover implementation attributes. +- Set/Get a control. +- Initiate an action on a control. +- Obtain platform (i.e. SM) build information. +- Obtain ROM passover data. +- Read boot/shutdown/reset information for the LM or the system. + +Commands: +_________ + +PROTOCOL_VERSION +~~~~~~~~~~~~~~~~ + +message_id: 0x0 +protocol_id: 0x84 + ++---------------+--------------------------------------------------------------+ +|Return values | ++---------------+--------------------------------------------------------------+ +|Name |Description | ++---------------+--------------------------------------------------------------+ +|int32 status | See ARM SCMI Specification for status code definitions. | ++---------------+--------------------------------------------------------------+ +|uint32 version | For this revision of the specification, this value must be | +| | 0x10000. | ++---------------+--------------------------------------------------------------+ + +PROTOCOL_ATTRIBUTES +~~~~~~~~~~~~~~~~~~~ + +message_id: 0x1 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status | See ARM SCMI Specification for status code definitions. | ++------------------+-----------------------------------------------------------+ +|uint32 attributes |Protocol attributes: | +| |Bits[31:24] Reserved, must be zero. | +| |Bits[23:16] Number of reset reasons. | +| |Bits[15:0] Number of controls | ++------------------+-----------------------------------------------------------+ + +PROTOCOL_MESSAGE_ATTRIBUTES +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +message_id: 0x2 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: in case the message is implemented and available | +| |to use. | +| |NOT_FOUND: if the message identified by message_id is | +| |invalid or not implemented | ++------------------+-----------------------------------------------------------+ +|uint32 attributes |Flags that are associated with a specific function in the | +| |protocol. For all functions in this protocol, this | +| |parameter has a value of 0 | ++------------------+-----------------------------------------------------------+ + +MISC_CONTROL_SET +~~~~~~~~~~~~~~~~ + +message_id: 0x3 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of the control | ++------------------+-----------------------------------------------------------+ +|uint32 num |Size of the value data in words | ++------------------+-----------------------------------------------------------+ +|uint32 val[8] |value data array | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if the control was set successfully. | +| |NOT_FOUND: if the index is not valid. | +| |DENIED: if the agent does not have permission to set the | +| |control | ++------------------+-----------------------------------------------------------+ + +MISC_CONTROL_GET +~~~~~~~~~~~~~~~~ + +message_id: 0x4 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of the control | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if the control was get successfully. | +| |NOT_FOUND: if the index is not valid. | +| |DENIED: if the agent does not have permission to get the | +| |control | ++------------------+-----------------------------------------------------------+ +|uint32 num |Size of the return data in words, max 8 | ++------------------+-----------------------------------------------------------+ +|uint32 | | +|val[0, num - 1] |value data array | ++------------------+-----------------------------------------------------------+ + +MISC_CONTROL_ACTION +~~~~~~~~~~~~~~~~~~~ + +message_id: 0x5 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of the control | ++------------------+-----------------------------------------------------------+ +|uint32 action |Action for the control | ++------------------+-----------------------------------------------------------+ +|uint32 numarg |Size of the argument data, max 8 | ++------------------+-----------------------------------------------------------+ +|uint32 | | +|arg[0, numarg -1] |Argument data array | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if the action was set successfully. | +| |NOT_FOUND: if the index is not valid. | +| |DENIED: if the agent does not have permission to get the | +| |control | ++------------------+-----------------------------------------------------------+ +|uint32 num |Size of the return data in words, max 8 | ++------------------+-----------------------------------------------------------+ +|uint32 | | +|val[0, num - 1] |value data array | ++------------------+-----------------------------------------------------------+ + +MISC_DISCOVER_BUILD_INFO +~~~~~~~~~~~~~~~~~~~~~~~~ + +This function is used to obtain the build commit, data, time, number. + +message_id: 0x6 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if the build info was got successfully. | +| |NOT_SUPPORTED: if the data is not available. | ++------------------+-----------------------------------------------------------+ +|uint32 buildnum |Build number | ++------------------+-----------------------------------------------------------+ +|uint32 buildcommit|Most significant 32 bits of the git commit hash | ++------------------+-----------------------------------------------------------+ +|uint8 date[16] |Date of build. Null terminated ASCII string of up to 16 | +| |bytes in length | ++------------------+-----------------------------------------------------------+ +|uint8 time[16] |Time of build. Null terminated ASCII string of up to 16 | +| |bytes in length | ++------------------+-----------------------------------------------------------+ + +MISC_ROM_PASSOVER_GET +~~~~~~~~~~~~~~~~~~~~~ + +ROM passover data is information exported by ROM and could be used by others. +It includes boot device, instance, type, mode and etc. This function is used +to obtain the ROM passover data. The returned block of words is structured as +defined in the ROM passover section in the SoC RM. + +message_id: 0x7 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if the data was got successfully. | +| |NOT_SUPPORTED: if the data is not available. | ++------------------+-----------------------------------------------------------+ +|uint32 num |Size of the passover data in words, max 13 | ++------------------+-----------------------------------------------------------+ +|uint32 | | +|data[0, num - 1] |Passover data array | ++------------------+-----------------------------------------------------------+ + +MISC_CONTROL_NOTIFY +~~~~~~~~~~~~~~~~~~~ + +message_id: 0x8 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 index |Index of control | ++------------------+-----------------------------------------------------------+ +|uint32 flags |Notification flags, varies by control | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: notification configuration was successfully | +| |updated. | +| |NOT_FOUND: control id not exists. | +| |INVALID_PARAMETERS: if the input attributes flag specifies | +| |unsupported or invalid configurations.. | +| |DENIED: if the calling agent is not permitted to request | +| |the notification. | ++------------------+-----------------------------------------------------------+ + +MISC_RESET_REASON_ATTRIBUTES +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +message_id: 0x9 +protocol_id: 0x84 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 reasonid |Identifier for the reason | ++------------------+-----------------------------------------------------------+ +|Return values | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|int32 status |SUCCESS: if valid reason attributes are returned | +| |NOT_FOUND: if reasonId pertains to a non-existent reason. | ++------------------+-----------------------------------------------------------+ +|uint32 attributes |Reason attributes. This parameter has the following | +| |format: Bits[31:0] Reserved, must be zero | +| |Bits[15:0] Number of persistent storage (GPR) words. | ++------------------+-----------------------------------------------------------+ +|uint8 name[16] |Null-terminated ASCII string of up to 16 bytes in length | +| |describing the reason | ++------------------+-----------------------------------------------------------+ + +MISC_RESET_REASON_GET +~~~~~~~~~~~~~~~~~~~~~ + +message_id: 0xA +protocol_id: 0x84 + ++--------------------+---------------------------------------------------------+ +|Parameters | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|uint32 flags |Reason flags. This parameter has the following format: | +| |Bits[31:1] Reserved, must be zero. | +| |Bit[0] System: | +| |Set to 1 to return the system reason. | +| |Set to 0 to return the LM reason | ++--------------------+---------------------------------------------------------+ +|Return values | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|int32 status |SUCCESS: reset reason return | ++--------------------+---------------------------------------------------------+ +|uint32 bootflags |Boot reason flags. This parameter has the format: | +| |Bits[31] Valid. | +| |Set to 1 if the entire reason is valid. | +| |Set to 0 if the entire reason is not valid. | +| |Bits[30:29] Reserved, must be zero. | +| |Bit[28] Valid origin: | +| |Set to 1 if the origin field is valid. | +| |Set to 0 if the origin field is not valid. | +| |Bits[27:24] Origin. | +| |Bit[23] Valid err ID: | +| |Set to 1 if the error ID field is valid. | +| |Set to 0 if the error ID field is not valid. | +| |Bits[22:8] Error ID. | +| |Bit[7:0] Reason | ++--------------------+---------------------------------------------------------+ +|uint32 shutdownflags|Shutdown reason flags. This parameter has the format: | +| |Bits[31] Valid. | +| |Set to 1 if the entire reason is valid. | +| |Set to 0 if the entire reason is not valid. | +| |Bits[30:29] Number of valid extended info words. | +| |Bit[28] Valid origin: | +| |Set to 1 if the origin field is valid. | +| |Set to 0 if the origin field is not valid. | +| |Bits[27:24] Origin. | +| |Bit[23] Valid err ID: | +| |Set to 1 if the error ID field is valid. | +| |Set to 0 if the error ID field is not valid. | +| |Bits[22:8] Error ID. | +| |Bit[7:0] Reason | ++--------------------+---------------------------------------------------------+ +|uint32 extinfo[8] |Array of extended info words | ++--------------------+---------------------------------------------------------+ + +MISC_SI_INFO_GET +~~~~~~~~~~~~~~~~ + +message_id: 0xB +protocol_id: 0x84 + ++--------------------+---------------------------------------------------------+ +|Return values | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|int32 status |SUCCESS: silicon info return | ++--------------------+---------------------------------------------------------+ +|uint32 deviceid |Silicon specific device ID | ++--------------------+---------------------------------------------------------+ +|uint32 sirev |Silicon specific revision | ++--------------------+---------------------------------------------------------+ +|uint32 partnum |Silicon specific part number | ++--------------------+---------------------------------------------------------+ +|uint8 siname[16] |Silicon name/revision. Null terminated ASCII string of up| +| |to 16 bytes in length | ++--------------------+---------------------------------------------------------+ + +MISC_CFG_INFO_GET +~~~~~~~~~~~~~~~~~ + +message_id: 0xC +protocol_id: 0x84 + ++--------------------+---------------------------------------------------------+ +|Return values | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|int32 status |SUCCESS: config name return | +| |NOT_SUPPORTED: name not available | ++--------------------+---------------------------------------------------------+ +|uint32 msel |Mode selector value | ++--------------------+---------------------------------------------------------+ +|uint8 cfgname[16] |config file basename. Null terminated ASCII string of up | +| |to 16 bytes in length | ++--------------------+---------------------------------------------------------+ + +MISC_SYSLOG_GET +~~~~~~~~~~~~~~~ + +message_id: 0xD +protocol_id: 0x84 + ++--------------------+---------------------------------------------------------+ +|Parameters | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|uint32 flags |Device specific flags that might impact the data returned| +| |or clearing of the data | ++--------------------+---------------------------------------------------------+ +|uint32 logindex |Index to the first log word. Will be the first element in| +| |the return array | ++--------------------+---------------------------------------------------------+ +|Return values | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|int32 status |SUCCESS: system log return | ++--------------------+---------------------------------------------------------+ +|uint32 numLogflags |Descriptor for the log data returned by this call. | +| |Bits[31:20] Number of remaining log words. | +| |Bits[15:12] Reserved, must be zero. | +| |Bits[11:0] Number of log words that are returned by this | +| |call | ++--------------------+---------------------------------------------------------+ +|uint32 syslog[N] |Log data array, N is defined in bits[11:0] of numLogflags| ++--------------------+---------------------------------------------------------+ + +NEGOTIATE_PROTOCOL_VERSION +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +message_id: 0x10 +protocol_id: 0x84 + ++--------------------+---------------------------------------------------------+ +|Parameters | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|uint32 version |The negotiated protocol version the agent intends to use | ++--------------------+---------------------------------------------------------+ +|Return values | ++--------------------+---------------------------------------------------------+ +|Name |Description | ++--------------------+---------------------------------------------------------+ +|int32 status |SUCCESS: if the negotiated protocol version is supported | +| |by the platform. All commands, responses, and | +| |notifications post successful return of this command must| +| |comply with the negotiated version. | +| |NOT_SUPPORTED: if the protocol version is not supported. | ++--------------------+---------------------------------------------------------+ + +Notifications +_____________ + +MISC_CONTROL_EVENT +~~~~~~~~~~~~~~~~~~ + +message_id: 0x0 +protocol_id: 0x81 + ++------------------+-----------------------------------------------------------+ +|Parameters | ++------------------+-----------------------------------------------------------+ +|Name |Description | ++------------------+-----------------------------------------------------------+ +|uint32 ctrlid |Identifier for the control that caused the event. | ++------------------+-----------------------------------------------------------+ +|uint32 flags |Event flags, varies by control. | ++------------------+-----------------------------------------------------------+ From 41845541adebc503b8574943c92670016d5e566b Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 23 Aug 2024 17:05:18 +0800 Subject: [PATCH 124/212] firmware: arm_scmi: Add initial support for i.MX BBM protocol i.MX95 has a battery-backed module(BBM), which has persistent storage (GPR), an RTC, and the ON/OFF button. The System Manager(SM) firmware use SCMI vendor protocol(SCMI BBM) to let agent be able to use GPR, RTC and ON/OFF button. Reviewed-by: Cristian Marussi Signed-off-by: Peng Fan Message-Id: <20240823-imx95-bbm-misc-v2-v8-2-e600ed9e9271@nxp.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/Kconfig | 1 + drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/vendors/imx/Kconfig | 15 + .../firmware/arm_scmi/vendors/imx/Makefile | 2 + .../arm_scmi/vendors/imx/imx-sm-bbm.c | 383 ++++++++++++++++++ include/linux/scmi_imx_protocol.h | 42 ++ 6 files changed, 444 insertions(+) create mode 100644 drivers/firmware/arm_scmi/vendors/imx/Kconfig create mode 100644 drivers/firmware/arm_scmi/vendors/imx/Makefile create mode 100644 drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c create mode 100644 include/linux/scmi_imx_protocol.h diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index 67053c1862d1..dabd874641d0 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -70,6 +70,7 @@ config ARM_SCMI_DEBUG_COUNTERS SCMI monitoring. source "drivers/firmware/arm_scmi/transports/Kconfig" +source "drivers/firmware/arm_scmi/vendors/imx/Kconfig" endif #ARM_SCMI_PROTOCOL diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 9659b7d1b963..9ac81adff567 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -11,6 +11,7 @@ scmi-protocols-y += pinctrl.o scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y) obj-$(CONFIG_ARM_SCMI_PROTOCOL) += transports/ +obj-$(CONFIG_ARM_SCMI_PROTOCOL) += vendors/imx/ obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o diff --git a/drivers/firmware/arm_scmi/vendors/imx/Kconfig b/drivers/firmware/arm_scmi/vendors/imx/Kconfig new file mode 100644 index 000000000000..95d0dec2ca94 --- /dev/null +++ b/drivers/firmware/arm_scmi/vendors/imx/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +menu "ARM SCMI NXP i.MX Vendor Protocols" + +config IMX_SCMI_BBM_EXT + tristate "i.MX SCMI BBM EXTENSION" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default y if ARCH_MXC + help + This enables i.MX System BBM control logic which supports RTC + and BUTTON. + + To compile this driver as a module, choose M here: the + module will be called imx-sm-bbm. + +endmenu diff --git a/drivers/firmware/arm_scmi/vendors/imx/Makefile b/drivers/firmware/arm_scmi/vendors/imx/Makefile new file mode 100644 index 000000000000..a7dbdd20dbb9 --- /dev/null +++ b/drivers/firmware/arm_scmi/vendors/imx/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c new file mode 100644 index 000000000000..17799eacf06c --- /dev/null +++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Management Interface (SCMI) NXP BBM Protocol + * + * Copyright 2024 NXP + */ + +#define pr_fmt(fmt) "SCMI Notifications BBM - " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "../../protocols.h" +#include "../../notify.h" + +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000 + +enum scmi_imx_bbm_protocol_cmd { + IMX_BBM_GPR_SET = 0x3, + IMX_BBM_GPR_GET = 0x4, + IMX_BBM_RTC_ATTRIBUTES = 0x5, + IMX_BBM_RTC_TIME_SET = 0x6, + IMX_BBM_RTC_TIME_GET = 0x7, + IMX_BBM_RTC_ALARM_SET = 0x8, + IMX_BBM_BUTTON_GET = 0x9, + IMX_BBM_RTC_NOTIFY = 0xA, + IMX_BBM_BUTTON_NOTIFY = 0xB, +}; + +#define GET_RTCS_NR(x) le32_get_bits((x), GENMASK(23, 16)) +#define GET_GPRS_NR(x) le32_get_bits((x), GENMASK(15, 0)) + +#define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED BIT(2) +#define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER BIT(1) +#define SCMI_IMX_BBM_NOTIFY_RTC_ALARM BIT(0) + +#define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG BIT(0) + +#define SCMI_IMX_BBM_NOTIFY_RTC_FLAG \ + (SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \ + SCMI_IMX_BBM_NOTIFY_RTC_ALARM) + +#define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24) + +struct scmi_imx_bbm_info { + u32 version; + int nr_rtc; + int nr_gpr; +}; + +struct scmi_msg_imx_bbm_protocol_attributes { + __le32 attributes; +}; + +struct scmi_imx_bbm_set_time { + __le32 id; + __le32 flags; + __le32 value_low; + __le32 value_high; +}; + +struct scmi_imx_bbm_get_time { + __le32 id; + __le32 flags; +}; + +struct scmi_imx_bbm_alarm_time { + __le32 id; + __le32 flags; + __le32 value_low; + __le32 value_high; +}; + +struct scmi_msg_imx_bbm_rtc_notify { + __le32 rtc_id; + __le32 flags; +}; + +struct scmi_msg_imx_bbm_button_notify { + __le32 flags; +}; + +struct scmi_imx_bbm_notify_payld { + __le32 flags; +}; + +static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle *ph, + struct scmi_imx_bbm_info *pi) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_imx_bbm_protocol_attributes *attr; + + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = ph->xops->do_xfer(ph, t); + if (!ret) { + pi->nr_rtc = GET_RTCS_NR(attr->attributes); + pi->nr_gpr = GET_GPRS_NR(attr->attributes); + } + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_imx_bbm_notify(const struct scmi_protocol_handle *ph, + u32 src_id, int message_id, bool enable) +{ + int ret; + struct scmi_xfer *t; + + if (message_id == IMX_BBM_RTC_NOTIFY) { + struct scmi_msg_imx_bbm_rtc_notify *rtc_notify; + + ret = ph->xops->xfer_get_init(ph, message_id, + sizeof(*rtc_notify), 0, &t); + if (ret) + return ret; + + rtc_notify = t->tx.buf; + rtc_notify->rtc_id = cpu_to_le32(0); + rtc_notify->flags = + cpu_to_le32(enable ? SCMI_IMX_BBM_NOTIFY_RTC_FLAG : 0); + } else if (message_id == IMX_BBM_BUTTON_NOTIFY) { + struct scmi_msg_imx_bbm_button_notify *button_notify; + + ret = ph->xops->xfer_get_init(ph, message_id, + sizeof(*button_notify), 0, &t); + if (ret) + return ret; + + button_notify = t->tx.buf; + button_notify->flags = cpu_to_le32(enable ? 1 : 0); + } else { + return -EINVAL; + } + + ret = ph->xops->do_xfer(ph, t); + + ph->xops->xfer_put(ph, t); + return ret; +} + +static enum scmi_imx_bbm_protocol_cmd evt_2_cmd[] = { + IMX_BBM_RTC_NOTIFY, + IMX_BBM_BUTTON_NOTIFY +}; + +static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle *ph, + u8 evt_id, u32 src_id, bool enable) +{ + int ret, cmd_id; + + if (evt_id >= ARRAY_SIZE(evt_2_cmd)) + return -EINVAL; + + cmd_id = evt_2_cmd[evt_id]; + ret = scmi_imx_bbm_notify(ph, src_id, cmd_id, enable); + if (ret) + pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", + evt_id, src_id, ret); + + return ret; +} + +static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle *ph, + u8 evt_id, ktime_t timestamp, + const void *payld, size_t payld_sz, + void *report, u32 *src_id) +{ + const struct scmi_imx_bbm_notify_payld *p = payld; + struct scmi_imx_bbm_notif_report *r = report; + + if (sizeof(*p) != payld_sz) + return NULL; + + if (evt_id == SCMI_EVENT_IMX_BBM_RTC) { + r->is_rtc = true; + r->is_button = false; + r->timestamp = timestamp; + r->rtc_id = le32_get_bits(p->flags, SCMI_IMX_BBM_EVENT_RTC_MASK); + r->rtc_evt = le32_get_bits(p->flags, SCMI_IMX_BBM_NOTIFY_RTC_FLAG); + dev_dbg(ph->dev, "RTC: %d evt: %x\n", r->rtc_id, r->rtc_evt); + *src_id = r->rtc_evt; + } else if (evt_id == SCMI_EVENT_IMX_BBM_BUTTON) { + r->is_rtc = false; + r->is_button = true; + r->timestamp = timestamp; + dev_dbg(ph->dev, "BBM Button\n"); + *src_id = 0; + } else { + WARN_ON_ONCE(1); + return NULL; + } + + return r; +} + +static const struct scmi_event scmi_imx_bbm_events[] = { + { + .id = SCMI_EVENT_IMX_BBM_RTC, + .max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld), + .max_report_sz = sizeof(struct scmi_imx_bbm_notif_report), + }, + { + .id = SCMI_EVENT_IMX_BBM_BUTTON, + .max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld), + .max_report_sz = sizeof(struct scmi_imx_bbm_notif_report), + }, +}; + +static const struct scmi_event_ops scmi_imx_bbm_event_ops = { + .set_notify_enabled = scmi_imx_bbm_set_notify_enabled, + .fill_custom_report = scmi_imx_bbm_fill_custom_report, +}; + +static const struct scmi_protocol_events scmi_imx_bbm_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &scmi_imx_bbm_event_ops, + .evts = scmi_imx_bbm_events, + .num_events = ARRAY_SIZE(scmi_imx_bbm_events), + .num_sources = 1, +}; + +static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle *ph, + u32 rtc_id, u64 sec) +{ + struct scmi_imx_bbm_info *pi = ph->get_priv(ph); + struct scmi_imx_bbm_set_time *cfg; + struct scmi_xfer *t; + int ret; + + if (rtc_id >= pi->nr_rtc) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_SET, sizeof(*cfg), 0, &t); + if (ret) + return ret; + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(rtc_id); + cfg->flags = 0; + cfg->value_low = cpu_to_le32(lower_32_bits(sec)); + cfg->value_high = cpu_to_le32(upper_32_bits(sec)); + + ret = ph->xops->do_xfer(ph, t); + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle *ph, + u32 rtc_id, u64 *value) +{ + struct scmi_imx_bbm_info *pi = ph->get_priv(ph); + struct scmi_imx_bbm_get_time *cfg; + struct scmi_xfer *t; + int ret; + + if (rtc_id >= pi->nr_rtc) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_GET, sizeof(*cfg), + sizeof(u64), &t); + if (ret) + return ret; + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(rtc_id); + cfg->flags = 0; + + ret = ph->xops->do_xfer(ph, t); + if (!ret) + *value = get_unaligned_le64(t->rx.buf); + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle *ph, + u32 rtc_id, bool enable, u64 sec) +{ + struct scmi_imx_bbm_info *pi = ph->get_priv(ph); + struct scmi_imx_bbm_alarm_time *cfg; + struct scmi_xfer *t; + int ret; + + if (rtc_id >= pi->nr_rtc) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_ALARM_SET, sizeof(*cfg), 0, &t); + if (ret) + return ret; + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(rtc_id); + cfg->flags = enable ? + cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG) : 0; + cfg->value_low = cpu_to_le32(lower_32_bits(sec)); + cfg->value_high = cpu_to_le32(upper_32_bits(sec)); + + ret = ph->xops->do_xfer(ph, t); + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle *ph, u32 *state) +{ + struct scmi_xfer *t; + int ret; + + ret = ph->xops->xfer_get_init(ph, IMX_BBM_BUTTON_GET, 0, sizeof(u32), &t); + if (ret) + return ret; + + ret = ph->xops->do_xfer(ph, t); + if (!ret) + *state = get_unaligned_le32(t->rx.buf); + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = { + .rtc_time_get = scmi_imx_bbm_rtc_time_get, + .rtc_time_set = scmi_imx_bbm_rtc_time_set, + .rtc_alarm_set = scmi_imx_bbm_rtc_alarm_set, + .button_get = scmi_imx_bbm_button_get, +}; + +static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph) +{ + u32 version; + int ret; + struct scmi_imx_bbm_info *binfo; + + ret = ph->xops->version_get(ph, &version); + if (ret) + return ret; + + dev_info(ph->dev, "NXP SM BBM Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL); + if (!binfo) + return -ENOMEM; + + ret = scmi_imx_bbm_attributes_get(ph, binfo); + if (ret) + return ret; + + return ph->set_priv(ph, binfo, version); +} + +static const struct scmi_protocol scmi_imx_bbm = { + .id = SCMI_PROTOCOL_IMX_BBM, + .owner = THIS_MODULE, + .instance_init = &scmi_imx_bbm_protocol_init, + .ops = &scmi_imx_bbm_proto_ops, + .events = &scmi_imx_bbm_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, + .vendor_id = "NXP", + .sub_vendor_id = "IMX", +}; +module_scmi_protocol(scmi_imx_bbm); + +MODULE_DESCRIPTION("i.MX SCMI BBM driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/scmi_imx_protocol.h b/include/linux/scmi_imx_protocol.h new file mode 100644 index 000000000000..2df2ea0f1809 --- /dev/null +++ b/include/linux/scmi_imx_protocol.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * SCMI Message Protocol driver NXP extension header + * + * Copyright 2024 NXP. + */ + +#ifndef _LINUX_SCMI_NXP_PROTOCOL_H +#define _LINUX_SCMI_NXP_PROTOCOL_H + +#include +#include +#include +#include + +enum scmi_nxp_protocol { + SCMI_PROTOCOL_IMX_BBM = 0x81, +}; + +struct scmi_imx_bbm_proto_ops { + int (*rtc_time_set)(const struct scmi_protocol_handle *ph, u32 id, + uint64_t sec); + int (*rtc_time_get)(const struct scmi_protocol_handle *ph, u32 id, + u64 *val); + int (*rtc_alarm_set)(const struct scmi_protocol_handle *ph, u32 id, + bool enable, u64 sec); + int (*button_get)(const struct scmi_protocol_handle *ph, u32 *state); +}; + +enum scmi_nxp_notification_events { + SCMI_EVENT_IMX_BBM_RTC = 0x0, + SCMI_EVENT_IMX_BBM_BUTTON = 0x1, +}; + +struct scmi_imx_bbm_notif_report { + bool is_rtc; + bool is_button; + ktime_t timestamp; + unsigned int rtc_id; + unsigned int rtc_evt; +}; +#endif From 61c9f03e22fc57fe61726c513b1f92c0ed1ef00f Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 23 Aug 2024 17:05:19 +0800 Subject: [PATCH 125/212] firmware: arm_scmi: Add initial support for i.MX MISC protocol i.MX95 System Manager(SM) firmware includes a SCMI vendor protocol, SCMI MISC protocol which includes controls that are misc settings/actions that must be exposed from the SM to agents. They are device specific and are usually define to access bit fields in various mix block control modules, IOMUX_GPR, and other General Purpose registers, Control Status Registers owned by the SM. Reviewed-by: Cristian Marussi Signed-off-by: Peng Fan Message-Id: <20240823-imx95-bbm-misc-v2-v8-3-e600ed9e9271@nxp.com> Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/vendors/imx/Kconfig | 10 + .../firmware/arm_scmi/vendors/imx/Makefile | 1 + .../arm_scmi/vendors/imx/imx-sm-misc.c | 318 ++++++++++++++++++ include/linux/scmi_imx_protocol.h | 17 + 4 files changed, 346 insertions(+) create mode 100644 drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c diff --git a/drivers/firmware/arm_scmi/vendors/imx/Kconfig b/drivers/firmware/arm_scmi/vendors/imx/Kconfig index 95d0dec2ca94..2883ed24a84d 100644 --- a/drivers/firmware/arm_scmi/vendors/imx/Kconfig +++ b/drivers/firmware/arm_scmi/vendors/imx/Kconfig @@ -12,4 +12,14 @@ config IMX_SCMI_BBM_EXT To compile this driver as a module, choose M here: the module will be called imx-sm-bbm. +config IMX_SCMI_MISC_EXT + tristate "i.MX SCMI MISC EXTENSION" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default y if ARCH_MXC + help + This enables i.MX System MISC control logic such as gpio expander + wakeup + + To compile this driver as a module, choose M here: the + module will be called imx-sm-misc. endmenu diff --git a/drivers/firmware/arm_scmi/vendors/imx/Makefile b/drivers/firmware/arm_scmi/vendors/imx/Makefile index a7dbdd20dbb9..d3ee6d544924 100644 --- a/drivers/firmware/arm_scmi/vendors/imx/Makefile +++ b/drivers/firmware/arm_scmi/vendors/imx/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o +obj-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c new file mode 100644 index 000000000000..a86ab9b35953 --- /dev/null +++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System control and Management Interface (SCMI) NXP MISC Protocol + * + * Copyright 2024 NXP + */ + +#define pr_fmt(fmt) "SCMI Notifications MISC - " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "../../protocols.h" +#include "../../notify.h" + +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000 + +#define MAX_MISC_CTRL_SOURCES GENMASK(15, 0) + +enum scmi_imx_misc_protocol_cmd { + SCMI_IMX_MISC_CTRL_SET = 0x3, + SCMI_IMX_MISC_CTRL_GET = 0x4, + SCMI_IMX_MISC_CTRL_NOTIFY = 0x8, +}; + +struct scmi_imx_misc_info { + u32 version; + u32 nr_dev_ctrl; + u32 nr_brd_ctrl; + u32 nr_reason; +}; + +struct scmi_msg_imx_misc_protocol_attributes { + __le32 attributes; +}; + +#define GET_BRD_CTRLS_NR(x) le32_get_bits((x), GENMASK(31, 24)) +#define GET_REASONS_NR(x) le32_get_bits((x), GENMASK(23, 16)) +#define GET_DEV_CTRLS_NR(x) le32_get_bits((x), GENMASK(15, 0)) +#define BRD_CTRL_START_ID BIT(15) + +struct scmi_imx_misc_ctrl_set_in { + __le32 id; + __le32 num; + __le32 value[]; +}; + +struct scmi_imx_misc_ctrl_notify_in { + __le32 ctrl_id; + __le32 flags; +}; + +struct scmi_imx_misc_ctrl_notify_payld { + __le32 ctrl_id; + __le32 flags; +}; + +struct scmi_imx_misc_ctrl_get_out { + __le32 num; + __le32 val[]; +}; + +static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph, + struct scmi_imx_misc_info *mi) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_imx_misc_protocol_attributes *attr; + + ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, + sizeof(*attr), &t); + if (ret) + return ret; + + attr = t->rx.buf; + + ret = ph->xops->do_xfer(ph, t); + if (!ret) { + mi->nr_dev_ctrl = GET_DEV_CTRLS_NR(attr->attributes); + mi->nr_brd_ctrl = GET_BRD_CTRLS_NR(attr->attributes); + mi->nr_reason = GET_REASONS_NR(attr->attributes); + dev_info(ph->dev, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n", + mi->nr_dev_ctrl, mi->nr_brd_ctrl, mi->nr_reason); + } + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle *ph, + u32 ctrl_id) +{ + struct scmi_imx_misc_info *mi = ph->get_priv(ph); + + /* + * [0, BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related + * [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related + */ + if (ctrl_id < BRD_CTRL_START_ID && ctrl_id > mi->nr_dev_ctrl) + return -EINVAL; + if (ctrl_id >= BRD_CTRL_START_ID + mi->nr_brd_ctrl) + return -EINVAL; + + return 0; +} + +static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle *ph, + u32 ctrl_id, u32 evt_id, u32 flags) +{ + struct scmi_imx_misc_ctrl_notify_in *in; + struct scmi_xfer *t; + int ret; + + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); + if (ret) + return ret; + + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_NOTIFY, + sizeof(*in), 0, &t); + if (ret) + return ret; + + in = t->tx.buf; + in->ctrl_id = cpu_to_le32(ctrl_id); + in->flags = cpu_to_le32(flags); + + ret = ph->xops->do_xfer(ph, t); + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int +scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle *ph, + u8 evt_id, u32 src_id, bool enable) +{ + int ret; + + /* misc_ctrl_req_notify is for enablement */ + if (enable) + return 0; + + ret = scmi_imx_misc_ctrl_notify(ph, src_id, evt_id, 0); + if (ret) + dev_err(ph->dev, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n", + evt_id, src_id, ret); + + return ret; +} + +static void * +scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle *ph, + u8 evt_id, ktime_t timestamp, + const void *payld, size_t payld_sz, + void *report, u32 *src_id) +{ + const struct scmi_imx_misc_ctrl_notify_payld *p = payld; + struct scmi_imx_misc_ctrl_notify_report *r = report; + + if (sizeof(*p) != payld_sz) + return NULL; + + r->timestamp = timestamp; + r->ctrl_id = le32_to_cpu(p->ctrl_id); + r->flags = le32_to_cpu(p->flags); + if (src_id) + *src_id = r->ctrl_id; + dev_dbg(ph->dev, "%s: ctrl_id: %d flags: %d\n", __func__, + r->ctrl_id, r->flags); + + return r; +} + +static const struct scmi_event_ops scmi_imx_misc_event_ops = { + .set_notify_enabled = scmi_imx_misc_ctrl_set_notify_enabled, + .fill_custom_report = scmi_imx_misc_ctrl_fill_custom_report, +}; + +static const struct scmi_event scmi_imx_misc_events[] = { + { + .id = SCMI_EVENT_IMX_MISC_CONTROL, + .max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld), + .max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report), + }, +}; + +static struct scmi_protocol_events scmi_imx_misc_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &scmi_imx_misc_event_ops, + .evts = scmi_imx_misc_events, + .num_events = ARRAY_SIZE(scmi_imx_misc_events), + .num_sources = MAX_MISC_CTRL_SOURCES, +}; + +static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle *ph, + u32 ctrl_id, u32 *num, u32 *val) +{ + struct scmi_imx_misc_ctrl_get_out *out; + struct scmi_xfer *t; + int ret, i; + int max_msg_size = ph->hops->get_max_msg_size(ph); + int max_num = (max_msg_size - sizeof(*out)) / sizeof(__le32); + + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); + if (ret) + return ret; + + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_GET, sizeof(u32), + 0, &t); + if (ret) + return ret; + + put_unaligned_le32(ctrl_id, t->tx.buf); + ret = ph->xops->do_xfer(ph, t); + if (!ret) { + out = t->rx.buf; + *num = le32_to_cpu(out->num); + + if (*num >= max_num || + *num * sizeof(__le32) > t->rx.len - sizeof(__le32)) { + ph->xops->xfer_put(ph, t); + return -EINVAL; + } + + for (i = 0; i < *num; i++) + val[i] = le32_to_cpu(out->val[i]); + } + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle *ph, + u32 ctrl_id, u32 num, u32 *val) +{ + struct scmi_imx_misc_ctrl_set_in *in; + struct scmi_xfer *t; + int ret, i; + int max_msg_size = ph->hops->get_max_msg_size(ph); + int max_num = (max_msg_size - sizeof(*in)) / sizeof(__le32); + + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); + if (ret) + return ret; + + if (num > max_num) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, sizeof(*in), + 0, &t); + if (ret) + return ret; + + in = t->tx.buf; + in->id = cpu_to_le32(ctrl_id); + in->num = cpu_to_le32(num); + for (i = 0; i < num; i++) + in->value[i] = cpu_to_le32(val[i]); + + ret = ph->xops->do_xfer(ph, t); + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = { + .misc_ctrl_set = scmi_imx_misc_ctrl_set, + .misc_ctrl_get = scmi_imx_misc_ctrl_get, + .misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify, +}; + +static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph) +{ + struct scmi_imx_misc_info *minfo; + u32 version; + int ret; + + ret = ph->xops->version_get(ph, &version); + if (ret) + return ret; + + dev_info(ph->dev, "NXP SM MISC Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL); + if (!minfo) + return -ENOMEM; + + ret = scmi_imx_misc_attributes_get(ph, minfo); + if (ret) + return ret; + + return ph->set_priv(ph, minfo, version); +} + +static const struct scmi_protocol scmi_imx_misc = { + .id = SCMI_PROTOCOL_IMX_MISC, + .owner = THIS_MODULE, + .instance_init = &scmi_imx_misc_protocol_init, + .ops = &scmi_imx_misc_proto_ops, + .events = &scmi_imx_misc_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, + .vendor_id = "NXP", + .sub_vendor_id = "IMX", +}; +module_scmi_protocol(scmi_imx_misc); + +MODULE_DESCRIPTION("i.MX SCMI MISC driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/scmi_imx_protocol.h b/include/linux/scmi_imx_protocol.h index 2df2ea0f1809..066216f1357a 100644 --- a/include/linux/scmi_imx_protocol.h +++ b/include/linux/scmi_imx_protocol.h @@ -15,6 +15,7 @@ enum scmi_nxp_protocol { SCMI_PROTOCOL_IMX_BBM = 0x81, + SCMI_PROTOCOL_IMX_MISC = 0x84, }; struct scmi_imx_bbm_proto_ops { @@ -30,6 +31,7 @@ struct scmi_imx_bbm_proto_ops { enum scmi_nxp_notification_events { SCMI_EVENT_IMX_BBM_RTC = 0x0, SCMI_EVENT_IMX_BBM_BUTTON = 0x1, + SCMI_EVENT_IMX_MISC_CONTROL = 0x0, }; struct scmi_imx_bbm_notif_report { @@ -39,4 +41,19 @@ struct scmi_imx_bbm_notif_report { unsigned int rtc_id; unsigned int rtc_evt; }; + +struct scmi_imx_misc_ctrl_notify_report { + ktime_t timestamp; + unsigned int ctrl_id; + unsigned int flags; +}; + +struct scmi_imx_misc_proto_ops { + int (*misc_ctrl_set)(const struct scmi_protocol_handle *ph, u32 id, + u32 num, u32 *val); + int (*misc_ctrl_get)(const struct scmi_protocol_handle *ph, u32 id, + u32 *num, u32 *val); + int (*misc_ctrl_req_notify)(const struct scmi_protocol_handle *ph, + u32 ctrl_id, u32 evt_id, u32 flags); +}; #endif From 0b4f8a68b292e7ee82107b1ce15c3aad31c864b1 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 23 Aug 2024 17:05:21 +0800 Subject: [PATCH 126/212] firmware: imx: Add i.MX95 MISC driver The i.MX95 System manager exports SCMI MISC protocol for linux to do various settings, such as set board gpio expander as wakeup source. The driver is to add the support. Reviewed-by: Cristian Marussi Signed-off-by: Peng Fan Message-Id: <20240823-imx95-bbm-misc-v2-v8-5-e600ed9e9271@nxp.com> Signed-off-by: Sudeep Holla --- drivers/firmware/imx/Kconfig | 11 +++ drivers/firmware/imx/Makefile | 1 + drivers/firmware/imx/sm-misc.c | 119 ++++++++++++++++++++++++++++++++ include/linux/firmware/imx/sm.h | 34 +++++++++ 4 files changed, 165 insertions(+) create mode 100644 drivers/firmware/imx/sm-misc.c create mode 100644 include/linux/firmware/imx/sm.h diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig index 183613f82a11..477d3f32d99a 100644 --- a/drivers/firmware/imx/Kconfig +++ b/drivers/firmware/imx/Kconfig @@ -22,3 +22,14 @@ config IMX_SCU This driver manages the IPC interface between host CPU and the SCU firmware running on M4. + +config IMX_SCMI_MISC_DRV + tristate "IMX SCMI MISC Protocol driver" + depends on IMX_SCMI_MISC_EXT || COMPILE_TEST + default y if ARCH_MXC + help + The System Controller Management Interface firmware (SCMI FW) is + a low-level system function which runs on a dedicated Cortex-M + core that could provide misc functions such as board control. + + This driver can also be built as a module. diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 8f9f04a513a8..8d046c341be8 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_IMX_DSP) += imx-dsp.o obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o +obj-${CONFIG_IMX_SCMI_MISC_DRV} += sm-misc.o diff --git a/drivers/firmware/imx/sm-misc.c b/drivers/firmware/imx/sm-misc.c new file mode 100644 index 000000000000..fc3ee12c2be8 --- /dev/null +++ b/drivers/firmware/imx/sm-misc.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP + */ + +#include +#include +#include +#include +#include +#include + +static const struct scmi_imx_misc_proto_ops *imx_misc_ctrl_ops; +static struct scmi_protocol_handle *ph; +struct notifier_block scmi_imx_misc_ctrl_nb; + +int scmi_imx_misc_ctrl_set(u32 id, u32 val) +{ + if (!ph) + return -EPROBE_DEFER; + + return imx_misc_ctrl_ops->misc_ctrl_set(ph, id, 1, &val); +}; +EXPORT_SYMBOL(scmi_imx_misc_ctrl_set); + +int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val) +{ + if (!ph) + return -EPROBE_DEFER; + + return imx_misc_ctrl_ops->misc_ctrl_get(ph, id, num, val); +} +EXPORT_SYMBOL(scmi_imx_misc_ctrl_get); + +static int scmi_imx_misc_ctrl_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + /* + * notifier_chain_register requires a valid notifier_block and + * valid notifier_call. SCMI_EVENT_IMX_MISC_CONTROL is needed + * to let SCMI firmware enable control events, but the hook here + * is just a dummy function to avoid kernel panic as of now. + */ + return 0; +} + +static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev) +{ + const struct scmi_handle *handle = sdev->handle; + struct device_node *np = sdev->dev.of_node; + u32 src_id, flags; + int ret, i, num; + + if (!handle) + return -ENODEV; + + if (imx_misc_ctrl_ops) { + dev_err(&sdev->dev, "misc ctrl already initialized\n"); + return -EEXIST; + } + + imx_misc_ctrl_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_MISC, &ph); + if (IS_ERR(imx_misc_ctrl_ops)) + return PTR_ERR(imx_misc_ctrl_ops); + + num = of_property_count_u32_elems(np, "nxp,ctrl-ids"); + if (num % 2) { + dev_err(&sdev->dev, "Invalid wakeup-sources\n"); + return -EINVAL; + } + + scmi_imx_misc_ctrl_nb.notifier_call = &scmi_imx_misc_ctrl_notifier; + for (i = 0; i < num; i += 2) { + ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i, &src_id); + if (ret) { + dev_err(&sdev->dev, "Failed to read ctrl-id: %i\n", i); + continue; + } + + ret = of_property_read_u32_index(np, "nxp,ctrl-ids", i + 1, &flags); + if (ret) { + dev_err(&sdev->dev, "Failed to read ctrl-id value: %d\n", i + 1); + continue; + } + + ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_MISC, + SCMI_EVENT_IMX_MISC_CONTROL, + &src_id, + &scmi_imx_misc_ctrl_nb); + if (ret) { + dev_err(&sdev->dev, "Failed to register scmi misc event: %d\n", src_id); + } else { + ret = imx_misc_ctrl_ops->misc_ctrl_req_notify(ph, src_id, + SCMI_EVENT_IMX_MISC_CONTROL, + flags); + if (ret) + dev_err(&sdev->dev, "Failed to req notify: %d\n", src_id); + } + } + + return 0; +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_IMX_MISC, "imx-misc-ctrl" }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_imx_misc_ctrl_driver = { + .name = "scmi-imx-misc-ctrl", + .probe = scmi_imx_misc_ctrl_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_imx_misc_ctrl_driver); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("IMX SM MISC driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/firmware/imx/sm.h b/include/linux/firmware/imx/sm.h new file mode 100644 index 000000000000..62a2690e2abd --- /dev/null +++ b/include/linux/firmware/imx/sm.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2024 NXP + */ + +#ifndef _SCMI_IMX_H +#define _SCMI_IMX_H + +#include +#include +#include + +#define SCMI_IMX_CTRL_PDM_CLK_SEL 0 /* AON PDM clock sel */ +#define SCMI_IMX_CTRL_MQS1_SETTINGS 1 /* AON MQS settings */ +#define SCMI_IMX_CTRL_SAI1_MCLK 2 /* AON SAI1 MCLK */ +#define SCMI_IMX_CTRL_SAI3_MCLK 3 /* WAKE SAI3 MCLK */ +#define SCMI_IMX_CTRL_SAI4_MCLK 4 /* WAKE SAI4 MCLK */ +#define SCMI_IMX_CTRL_SAI5_MCLK 5 /* WAKE SAI5 MCLK */ + +#if IS_ENABLED(CONFIG_IMX_SCMI_MISC_EXT) +int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val); +int scmi_imx_misc_ctrl_set(u32 id, u32 val); +#else +static inline int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val) +{ + return -EOPNOTSUPP; +} + +static inline int scmi_imx_misc_ctrl_set(u32 id, u32 val); +{ + return -EOPNOTSUPP; +} +#endif +#endif From d17baf052cbbd793784bc0f4fc613459afa4b883 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 23 Aug 2024 17:05:23 +0800 Subject: [PATCH 127/212] input: keyboard: support i.MX95 BBM module The BBM module provides BUTTON feature. To i.MX95, this module is managed by System Manager and exported using System Management Control Interface(SCMI). Linux could use i.MX SCMI BBM Extension protocol to use BUTTON feature. This driver is to use SCMI interface to enable pwrkey. Acked-by: Dmitry Torokhov Signed-off-by: Peng Fan Message-Id: <20240823-imx95-bbm-misc-v2-v8-7-e600ed9e9271@nxp.com> Signed-off-by: Sudeep Holla --- drivers/input/keyboard/Kconfig | 11 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/imx-sm-bbm-key.c | 225 ++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 drivers/input/keyboard/imx-sm-bbm-key.c diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 1d0c5f4c0f99..1c3fef7d34af 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -466,6 +466,17 @@ config KEYBOARD_IMX To compile this driver as a module, choose M here: the module will be called imx_keypad. +config KEYBOARD_IMX_BBM_SCMI + tristate "IMX BBM SCMI Key Driver" + depends on IMX_SCMI_BBM_EXT || COMPILE_TEST + default y if ARCH_MXC + help + This is the BBM key driver for NXP i.MX SoCs managed through + SCMI protocol. + + To compile this driver as a module, choose M here: the + module will be called scmi-imx-bbm-key. + config KEYBOARD_IMX_SC_KEY tristate "IMX SCU Key Driver" depends on IMX_SCU diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index aecef00c5d09..624c90adde89 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_KEYBOARD_IPAQ_MICRO) += ipaq-micro-keys.o obj-$(CONFIG_KEYBOARD_IQS62X) += iqs62x-keys.o obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o obj-$(CONFIG_KEYBOARD_IMX_SC_KEY) += imx_sc_key.o +obj-$(CONFIG_KEYBOARD_IMX_BBM_SCMI) += imx-sm-bbm-key.o obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o diff --git a/drivers/input/keyboard/imx-sm-bbm-key.c b/drivers/input/keyboard/imx-sm-bbm-key.c new file mode 100644 index 000000000000..96486bd23d60 --- /dev/null +++ b/drivers/input/keyboard/imx-sm-bbm-key.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBOUNCE_TIME 30 +#define REPEAT_INTERVAL 60 + +struct scmi_imx_bbm { + struct scmi_protocol_handle *ph; + const struct scmi_imx_bbm_proto_ops *ops; + struct notifier_block nb; + int keycode; + int keystate; /* 1:pressed */ + bool suspended; + struct delayed_work check_work; + struct input_dev *input; +}; + +static void scmi_imx_bbm_pwrkey_check_for_events(struct work_struct *work) +{ + struct scmi_imx_bbm *bbnsm = container_of(to_delayed_work(work), + struct scmi_imx_bbm, check_work); + struct scmi_protocol_handle *ph = bbnsm->ph; + struct input_dev *input = bbnsm->input; + u32 state = 0; + int ret; + + ret = bbnsm->ops->button_get(ph, &state); + if (ret) { + pr_err("%s: %d\n", __func__, ret); + return; + } + + pr_debug("%s: state: %d, keystate %d\n", __func__, state, bbnsm->keystate); + + /* only report new event if status changed */ + if (state ^ bbnsm->keystate) { + bbnsm->keystate = state; + input_event(input, EV_KEY, bbnsm->keycode, state); + input_sync(input); + pm_relax(bbnsm->input->dev.parent); + pr_debug("EV_KEY: %x\n", bbnsm->keycode); + } + + /* repeat check if pressed long */ + if (state) + schedule_delayed_work(&bbnsm->check_work, msecs_to_jiffies(REPEAT_INTERVAL)); +} + +static int scmi_imx_bbm_pwrkey_event(struct scmi_imx_bbm *bbnsm) +{ + struct input_dev *input = bbnsm->input; + + pm_wakeup_event(input->dev.parent, 0); + + /* + * Directly report key event after resume to make no key press + * event is missed. + */ + if (READ_ONCE(bbnsm->suspended)) { + bbnsm->keystate = 1; + input_event(input, EV_KEY, bbnsm->keycode, 1); + input_sync(input); + WRITE_ONCE(bbnsm->suspended, false); + } + + schedule_delayed_work(&bbnsm->check_work, msecs_to_jiffies(DEBOUNCE_TIME)); + + return 0; +} + +static void scmi_imx_bbm_pwrkey_act(void *pdata) +{ + struct scmi_imx_bbm *bbnsm = pdata; + + cancel_delayed_work_sync(&bbnsm->check_work); +} + +static int scmi_imx_bbm_key_notifier(struct notifier_block *nb, unsigned long event, void *data) +{ + struct scmi_imx_bbm *bbnsm = container_of(nb, struct scmi_imx_bbm, nb); + struct scmi_imx_bbm_notif_report *r = data; + + if (r->is_button) { + pr_debug("BBM Button Power key pressed\n"); + scmi_imx_bbm_pwrkey_event(bbnsm); + } else { + /* Should never reach here */ + pr_err("Unexpected BBM event: %s\n", __func__); + } + + return 0; +} + +static int scmi_imx_bbm_pwrkey_init(struct scmi_device *sdev) +{ + const struct scmi_handle *handle = sdev->handle; + struct device *dev = &sdev->dev; + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); + struct input_dev *input; + int ret; + + if (device_property_read_u32(dev, "linux,code", &bbnsm->keycode)) { + bbnsm->keycode = KEY_POWER; + dev_warn(dev, "key code is not specified, using default KEY_POWER\n"); + } + + INIT_DELAYED_WORK(&bbnsm->check_work, scmi_imx_bbm_pwrkey_check_for_events); + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(dev, "failed to allocate the input device for SCMI IMX BBM\n"); + return -ENOMEM; + } + + input->name = dev_name(dev); + input->phys = "bbnsm-pwrkey/input0"; + input->id.bustype = BUS_HOST; + + input_set_capability(input, EV_KEY, bbnsm->keycode); + + ret = devm_add_action_or_reset(dev, scmi_imx_bbm_pwrkey_act, bbnsm); + if (ret) { + dev_err(dev, "failed to register remove action\n"); + return ret; + } + + bbnsm->input = input; + + bbnsm->nb.notifier_call = &scmi_imx_bbm_key_notifier; + ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_BBM, + SCMI_EVENT_IMX_BBM_BUTTON, + NULL, &bbnsm->nb); + + if (ret) + dev_err(dev, "Failed to register BBM Button Events %d:", ret); + + ret = input_register_device(input); + if (ret) { + dev_err(dev, "failed to register input device\n"); + return ret; + } + + return 0; +} + +static int scmi_imx_bbm_key_probe(struct scmi_device *sdev) +{ + const struct scmi_handle *handle = sdev->handle; + struct device *dev = &sdev->dev; + struct scmi_protocol_handle *ph; + struct scmi_imx_bbm *bbnsm; + int ret; + + if (!handle) + return -ENODEV; + + bbnsm = devm_kzalloc(dev, sizeof(*bbnsm), GFP_KERNEL); + if (!bbnsm) + return -ENOMEM; + + bbnsm->ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_BBM, &ph); + if (IS_ERR(bbnsm->ops)) + return PTR_ERR(bbnsm->ops); + + bbnsm->ph = ph; + + device_init_wakeup(dev, true); + + dev_set_drvdata(dev, bbnsm); + + ret = scmi_imx_bbm_pwrkey_init(sdev); + if (ret) + device_init_wakeup(dev, false); + + return ret; +} + +static int __maybe_unused scmi_imx_bbm_key_suspend(struct device *dev) +{ + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); + + WRITE_ONCE(bbnsm->suspended, true); + + return 0; +} + +static int __maybe_unused scmi_imx_bbm_key_resume(struct device *dev) +{ + return 0; +} + +static SIMPLE_DEV_PM_OPS(scmi_imx_bbm_pm_key_ops, scmi_imx_bbm_key_suspend, + scmi_imx_bbm_key_resume); + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_IMX_BBM, "imx-bbm-key" }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_imx_bbm_key_driver = { + .driver = { + .pm = &scmi_imx_bbm_pm_key_ops, + }, + .name = "scmi-imx-bbm-key", + .probe = scmi_imx_bbm_key_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_imx_bbm_key_driver); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("IMX SM BBM Key driver"); +MODULE_LICENSE("GPL"); From 3008598ef3b009252aaf2f5967df0b11d14258a6 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 23 Aug 2024 17:05:22 +0800 Subject: [PATCH 128/212] rtc: support i.MX95 BBM RTC The BBM module provides RTC feature. To i.MX95, this module is managed by System Manager and exported System Control Management Interface(SCMI). Linux could use i.MX SCMI BBM Extension protocol to use RTC feature. This driver is to use SCMI interface to get/set RTC. Reviewed-by: Cristian Marussi Signed-off-by: Peng Fan Message-Id: <20240823-imx95-bbm-misc-v2-v8-6-e600ed9e9271@nxp.com> Acked-by: Alexandre Belloni Signed-off-by: Sudeep Holla --- drivers/rtc/Kconfig | 11 +++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-imx-sm-bbm.c | 162 +++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 drivers/rtc/rtc-imx-sm-bbm.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2a95b05982ad..e87c3d74565c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1827,6 +1827,17 @@ config RTC_DRV_BBNSM This driver can also be built as a module, if so, the module will be called "rtc-bbnsm". +config RTC_DRV_IMX_BBM_SCMI + depends on IMX_SCMI_BBM_EXT || COMPILE_TEST + default y if ARCH_MXC + tristate "NXP i.MX BBM SCMI RTC support" + help + If you say yes here you get support for the NXP i.MX BBSM SCMI + RTC module. + + To compile this driver as a module, choose M here: the + module will be called rtc-imx-sm-bbm. + config RTC_DRV_IMX_SC depends on IMX_SCU depends on HAVE_ARM_SMCCC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 3004e372f25f..8ee79cb18322 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o obj-$(CONFIG_RTC_DRV_IMX_SC) += rtc-imx-sc.o +obj-$(CONFIG_RTC_DRV_IMX_BBM_SCMI) += rtc-imx-sm-bbm.o obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o diff --git a/drivers/rtc/rtc-imx-sm-bbm.c b/drivers/rtc/rtc-imx-sm-bbm.c new file mode 100644 index 000000000000..daa472be7c80 --- /dev/null +++ b/drivers/rtc/rtc-imx-sm-bbm.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP. + */ + +#include +#include +#include +#include +#include +#include + +struct scmi_imx_bbm { + const struct scmi_imx_bbm_proto_ops *ops; + struct rtc_device *rtc_dev; + struct scmi_protocol_handle *ph; + struct notifier_block nb; +}; + +static int scmi_imx_bbm_read_time(struct device *dev, struct rtc_time *tm) +{ + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); + struct scmi_protocol_handle *ph = bbnsm->ph; + u64 val; + int ret; + + ret = bbnsm->ops->rtc_time_get(ph, 0, &val); + if (ret) + return ret; + + rtc_time64_to_tm(val, tm); + + return 0; +} + +static int scmi_imx_bbm_set_time(struct device *dev, struct rtc_time *tm) +{ + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); + struct scmi_protocol_handle *ph = bbnsm->ph; + u64 val; + + val = rtc_tm_to_time64(tm); + + return bbnsm->ops->rtc_time_set(ph, 0, val); +} + +static int scmi_imx_bbm_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); + struct scmi_protocol_handle *ph = bbnsm->ph; + + /* scmi_imx_bbm_set_alarm enables the irq, just handle disable here */ + if (!enable) + return bbnsm->ops->rtc_alarm_set(ph, 0, false, 0); + + return 0; +} + +static int scmi_imx_bbm_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); + struct scmi_protocol_handle *ph = bbnsm->ph; + struct rtc_time *alrm_tm = &alrm->time; + u64 val; + + val = rtc_tm_to_time64(alrm_tm); + + return bbnsm->ops->rtc_alarm_set(ph, 0, true, val); +} + +static const struct rtc_class_ops smci_imx_bbm_rtc_ops = { + .read_time = scmi_imx_bbm_read_time, + .set_time = scmi_imx_bbm_set_time, + .set_alarm = scmi_imx_bbm_set_alarm, + .alarm_irq_enable = scmi_imx_bbm_alarm_irq_enable, +}; + +static int scmi_imx_bbm_rtc_notifier(struct notifier_block *nb, unsigned long event, void *data) +{ + struct scmi_imx_bbm *bbnsm = container_of(nb, struct scmi_imx_bbm, nb); + struct scmi_imx_bbm_notif_report *r = data; + + if (r->is_rtc) + rtc_update_irq(bbnsm->rtc_dev, 1, RTC_AF | RTC_IRQF); + else + pr_err("Unexpected bbm event: %s\n", __func__); + + return 0; +} + +static int scmi_imx_bbm_rtc_init(struct scmi_device *sdev) +{ + const struct scmi_handle *handle = sdev->handle; + struct device *dev = &sdev->dev; + struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev); + int ret; + + bbnsm->rtc_dev = devm_rtc_allocate_device(dev); + if (IS_ERR(bbnsm->rtc_dev)) + return PTR_ERR(bbnsm->rtc_dev); + + bbnsm->rtc_dev->ops = &smci_imx_bbm_rtc_ops; + bbnsm->rtc_dev->range_max = U32_MAX; + + bbnsm->nb.notifier_call = &scmi_imx_bbm_rtc_notifier; + ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_BBM, + SCMI_EVENT_IMX_BBM_RTC, + NULL, &bbnsm->nb); + if (ret) + return ret; + + return devm_rtc_register_device(bbnsm->rtc_dev); +} + +static int scmi_imx_bbm_rtc_probe(struct scmi_device *sdev) +{ + const struct scmi_handle *handle = sdev->handle; + struct device *dev = &sdev->dev; + struct scmi_protocol_handle *ph; + struct scmi_imx_bbm *bbnsm; + int ret; + + if (!handle) + return -ENODEV; + + bbnsm = devm_kzalloc(dev, sizeof(*bbnsm), GFP_KERNEL); + if (!bbnsm) + return -ENOMEM; + + bbnsm->ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_BBM, &ph); + if (IS_ERR(bbnsm->ops)) + return PTR_ERR(bbnsm->ops); + + bbnsm->ph = ph; + + device_init_wakeup(dev, true); + + dev_set_drvdata(dev, bbnsm); + + ret = scmi_imx_bbm_rtc_init(sdev); + if (ret) + device_init_wakeup(dev, false); + + return ret; +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_IMX_BBM, "imx-bbm-rtc" }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_imx_bbm_rtc_driver = { + .name = "scmi-imx-bbm-rtc", + .probe = scmi_imx_bbm_rtc_probe, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_imx_bbm_rtc_driver); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("IMX SM BBM RTC driver"); +MODULE_LICENSE("GPL"); From 4d57a840560c3ff04fed07a06b3aec7cbac4bff0 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Tue, 27 Aug 2024 19:46:04 +0800 Subject: [PATCH 129/212] soc/tegra: pmc: Simplify with scoped for each OF child loop Use scoped for_each_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Signed-off-by: Jinjie Ruan Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 6c37d6eb8b49..a08c377933c5 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1438,7 +1438,7 @@ static int tegra_powergate_init(struct tegra_pmc *pmc, struct device_node *parent) { struct of_phandle_args child_args, parent_args; - struct device_node *np, *child; + struct device_node *np; int err = 0; /* @@ -1457,12 +1457,10 @@ static int tegra_powergate_init(struct tegra_pmc *pmc, if (!np) return 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { err = tegra_powergate_add(pmc, child); - if (err < 0) { - of_node_put(child); + if (err < 0) break; - } if (of_parse_phandle_with_args(child, "power-domains", "#power-domain-cells", @@ -1474,10 +1472,8 @@ static int tegra_powergate_init(struct tegra_pmc *pmc, err = of_genpd_add_subdomain(&parent_args, &child_args); of_node_put(parent_args.np); - if (err) { - of_node_put(child); + if (err) break; - } } of_node_put(np); From 874c5b601856adbfda10846b9770a6c66c41e229 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 20:05:22 +0200 Subject: [PATCH 130/212] soc: versatile: integrator: fix OF node leak in probe() error path Driver is leaking OF node reference obtained from of_find_matching_node(). Fixes: f956a785a282 ("soc: move SoC driver for the ARM Integrator") Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-1-ff4b35abed83@linaro.org Signed-off-by: Linus Walleij --- drivers/soc/versatile/soc-integrator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c index bab4ad87aa75..d5099a3386b4 100644 --- a/drivers/soc/versatile/soc-integrator.c +++ b/drivers/soc/versatile/soc-integrator.c @@ -113,6 +113,7 @@ static int __init integrator_soc_init(void) return -ENODEV; syscon_regmap = syscon_node_to_regmap(np); + of_node_put(np); if (IS_ERR(syscon_regmap)) return PTR_ERR(syscon_regmap); From 1c4f26a41f9d052f334f6ae629e01f598ed93508 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 20:05:23 +0200 Subject: [PATCH 131/212] soc: versatile: realview: fix memory leak during device remove If device is unbound, the memory allocated for soc_dev_attr should be freed to prevent leaks. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-2-ff4b35abed83@linaro.org Signed-off-by: Linus Walleij --- drivers/soc/versatile/soc-realview.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c index c6876d232d8f..d304ee69287a 100644 --- a/drivers/soc/versatile/soc-realview.c +++ b/drivers/soc/versatile/soc-realview.c @@ -93,7 +93,7 @@ static int realview_soc_probe(struct platform_device *pdev) if (IS_ERR(syscon_regmap)) return PTR_ERR(syscon_regmap); - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), GFP_KERNEL); if (!soc_dev_attr) return -ENOMEM; @@ -106,10 +106,9 @@ static int realview_soc_probe(struct platform_device *pdev) soc_dev_attr->family = "Versatile"; soc_dev_attr->custom_attr_group = realview_groups[0]; soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - kfree(soc_dev_attr); + if (IS_ERR(soc_dev)) return -ENODEV; - } + ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET, &realview_coreid); if (ret) From c774f2564c0086c23f5269fd4691f233756bf075 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 20:05:24 +0200 Subject: [PATCH 132/212] soc: versatile: realview: fix soc_dev leak during device remove If device is unbound, the soc_dev should be unregistered to prevent memory leak. Fixes: a2974c9c1f83 ("soc: add driver for the ARM RealView") Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-3-ff4b35abed83@linaro.org Signed-off-by: Linus Walleij --- drivers/soc/versatile/soc-realview.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c index d304ee69287a..cf91abe07d38 100644 --- a/drivers/soc/versatile/soc-realview.c +++ b/drivers/soc/versatile/soc-realview.c @@ -4,6 +4,7 @@ * * Author: Linus Walleij */ +#include #include #include #include @@ -81,6 +82,13 @@ static struct attribute *realview_attrs[] = { ATTRIBUTE_GROUPS(realview); +static void realview_soc_socdev_release(void *data) +{ + struct soc_device *soc_dev = data; + + soc_device_unregister(soc_dev); +} + static int realview_soc_probe(struct platform_device *pdev) { struct regmap *syscon_regmap; @@ -109,6 +117,11 @@ static int realview_soc_probe(struct platform_device *pdev) if (IS_ERR(soc_dev)) return -ENODEV; + ret = devm_add_action_or_reset(&pdev->dev, realview_soc_socdev_release, + soc_dev); + if (ret) + return ret; + ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET, &realview_coreid); if (ret) From 2f05726171f8d03eef58bc26b49e4994a66c0c5f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 20:05:25 +0200 Subject: [PATCH 133/212] soc: versatile: enable compile testing Enable compile testing for broader build coverage. None of the drivers use anything from "asm", so code should build everywhere. CONFIG_PLAT_VERSATILE is being selected by driver dependencies (CONFIG_ARCH_INTEGRATOR and CONFIG_ARCH_REALVIEW), so directory can be always added to Makefile targets without impacting other configurations. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-4-ff4b35abed83@linaro.org Signed-off-by: Linus Walleij --- drivers/soc/Makefile | 2 +- drivers/soc/versatile/Kconfig | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index fb2bd31387d0..56f476a12847 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -32,5 +32,5 @@ obj-y += sunxi/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/ -obj-$(CONFIG_PLAT_VERSATILE) += versatile/ +obj-y += versatile/ obj-y += xilinx/ diff --git a/drivers/soc/versatile/Kconfig b/drivers/soc/versatile/Kconfig index c3792c0a84ac..7bbf54a8d879 100644 --- a/drivers/soc/versatile/Kconfig +++ b/drivers/soc/versatile/Kconfig @@ -4,7 +4,7 @@ # config SOC_INTEGRATOR_CM bool "SoC bus device for the ARM Integrator platform core modules" - depends on ARCH_INTEGRATOR + depends on ARCH_INTEGRATOR || COMPILE_TEST select SOC_BUS help Include support for the SoC bus on the ARM Integrator platform @@ -13,7 +13,7 @@ config SOC_INTEGRATOR_CM config SOC_REALVIEW bool "SoC bus device for the ARM RealView platforms" - depends on ARCH_REALVIEW + depends on ARCH_REALVIEW || COMPILE_TEST select SOC_BUS help Include support for the SoC bus on the ARM RealView platforms From 9aee8262445d185960431e972e2d997e6aba3de0 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Mon, 26 Aug 2024 11:58:23 +0800 Subject: [PATCH 134/212] ARM: OMAP2+: Remove obsoleted declaration for gpmc_onenand_init The gpmc_onenand_init() have been removed since commit 2514830b8b8c ("ARM: OMAP2+: Remove gpmc-onenand"), and now it is useless, so remove it. Signed-off-by: Gaosheng Cui Link: https://lore.kernel.org/r/20240826035823.4043171-1-cuigaosheng1@huawei.com Signed-off-by: Kevin Hilman --- include/linux/omap-gpmc.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h index 082841908fe7..c9e3843d2dd5 100644 --- a/include/linux/omap-gpmc.h +++ b/include/linux/omap-gpmc.h @@ -84,13 +84,3 @@ extern void gpmc_read_settings_dt(struct device_node *np, struct gpmc_timings; struct omap_nand_platform_data; struct omap_onenand_platform_data; - -#if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2) -extern int gpmc_onenand_init(struct omap_onenand_platform_data *d); -#else -#define board_onenand_data NULL -static inline int gpmc_onenand_init(struct omap_onenand_platform_data *d) -{ - return 0; -} -#endif From 84d1078af52f6a099267fccfb1dda602ac8b66d0 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Fri, 30 Aug 2024 21:30:03 +0100 Subject: [PATCH 135/212] memory: renesas-rpc-if: Use Hi-Z state as the default setting for IOVF pins The RZ/{G2L,G2LC,V2L} SMARC EVK uses Micron MT25QU412A flash and RZ/G2UL SMARC EVK uses Renesas AT25QL128A flash. With current pin setting for IOVF pin, 4-bit flash write fails for AT25QL128A flash. Use Hi-Z state as the default for IOVF pin, so that spi controller driver in linux will be independent of flash type. To support this, during board production, the bit 4 of the NV config register must be cleared by the bootloader for Micron flash. Output from u-boot after clearing bit4 of NVCR register. => renesas_micron_flash_nvcr SF: Detected mt25qu512a with page size 256 Bytes, erase size 64 KiB, total 64 MiB NVCR=0xef Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20240830203014.199326-2-biju.das.jz@bp.renesas.com Signed-off-by: Krzysztof Kozlowski --- drivers/memory/renesas-rpc-if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 3167826b236a..7fbd36fa1a1b 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -367,7 +367,7 @@ int rpcif_hw_init(struct device *dev, bool hyperflash) regmap_update_bits(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_IOFV(3) | RPCIF_CMNCR_BSZ(3), - RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(2) | + RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(3) | RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0)); else regmap_update_bits(rpc->regmap, RPCIF_CMNCR, From 331b8a963137d182248599d500edd9b4a3783db5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 15:50:00 +0200 Subject: [PATCH 136/212] memory: pl172: simplify releasing AMBA regions with devm Use devm_add_action_or_reset() and dev_err_probe() to make the probe() error handling simpler around amba_release_regions() cleanup. This allows to drop the remove() callback entirely. Suggested-by: Jonathan Cameron Acked-by: Vladimir Zapolskiy Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20240825135001.48963-1-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/pl172.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/memory/pl172.c b/drivers/memory/pl172.c index db5fbee34077..be7ba599cccf 100644 --- a/drivers/memory/pl172.c +++ b/drivers/memory/pl172.c @@ -187,6 +187,13 @@ static int pl172_parse_cs_config(struct amba_device *adev, return -EINVAL; } +static void pl172_amba_release_regions(void *data) +{ + struct amba_device *adev = data; + + amba_release_regions(adev); +} + static const char * const pl172_revisions[] = {"r1", "r2", "r2p3", "r2p4"}; static const char * const pl175_revisions[] = {"r1"}; static const char * const pl176_revisions[] = {"r0"}; @@ -232,13 +239,14 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id) return ret; } + ret = devm_add_action_or_reset(dev, pl172_amba_release_regions, adev); + if (ret) + return ret; + pl172->base = devm_ioremap(dev, adev->res.start, resource_size(&adev->res)); - if (!pl172->base) { - dev_err(dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_no_ioremap; - } + if (!pl172->base) + return dev_err_probe(dev, -ENOMEM, "ioremap failed\n"); amba_set_drvdata(adev, pl172); @@ -256,15 +264,6 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id) } return 0; - -err_no_ioremap: - amba_release_regions(adev); - return ret; -} - -static void pl172_remove(struct amba_device *adev) -{ - amba_release_regions(adev); } static const struct amba_id pl172_ids[] = { @@ -292,7 +291,6 @@ static struct amba_driver pl172_driver = { .name = "memory-pl172", }, .probe = pl172_probe, - .remove = pl172_remove, .id_table = pl172_ids, }; module_amba_driver(pl172_driver); From 32960b4f25c248f13758b8bbe6cc4260828442a1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 15:50:01 +0200 Subject: [PATCH 137/212] memory: pl353-smc: simplify with scoped for each OF child loop Use scoped for_each_available_child_of_node_scoped() when iterating over device nodes to make code a bit simpler. Suggested-by: Jonathan Cameron Reviewed-by: Miquel Raynal Link: https://lore.kernel.org/r/20240825135001.48963-2-krzysztof.kozlowski@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/memory/pl353-smc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c index 994c7a792e34..28a8cc56003c 100644 --- a/drivers/memory/pl353-smc.c +++ b/drivers/memory/pl353-smc.c @@ -74,7 +74,6 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) struct device_node *of_node = adev->dev.of_node; const struct of_device_id *match = NULL; struct pl353_smc_data *pl353_smc; - struct device_node *child; pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL); if (!pl353_smc) @@ -93,12 +92,13 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) amba_set_drvdata(adev, pl353_smc); /* Find compatible children. Only a single child is supported */ - for_each_available_child_of_node(of_node, child) { + for_each_available_child_of_node_scoped(of_node, child) { match = of_match_node(pl353_smc_supported_children, child); if (!match) { dev_warn(&adev->dev, "unsupported child node\n"); continue; } + of_platform_device_create(child, NULL, &adev->dev); break; } if (!match) { @@ -106,9 +106,6 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) return -ENODEV; } - of_platform_device_create(child, NULL, &adev->dev); - of_node_put(child); - return 0; } From ce6697a613c523b4e2e1d4228c0a81facc080076 Mon Sep 17 00:00:00 2001 From: Wu Bo Date: Mon, 26 Aug 2024 21:23:47 -0600 Subject: [PATCH 138/212] bus: imx-weim: support compile test Add COMPILE_TEST to support code compile test Signed-off-by: Wu Bo Signed-off-by: Shawn Guo --- drivers/bus/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 64cd2ee03aa3..ff669a8ccad9 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -89,7 +89,7 @@ config HISILICON_LPC config IMX_WEIM bool "Freescale EIM DRIVER" - depends on ARCH_MXC + depends on ARCH_MXC || COMPILE_TEST help Driver for i.MX WEIM controller. The WEIM(Wireless External Interface Module) works like a bus. From 2ea2113b3dacf9cf616488f875f32584dad53ff8 Mon Sep 17 00:00:00 2001 From: Wu Bo Date: Mon, 26 Aug 2024 21:23:48 -0600 Subject: [PATCH 139/212] bus: imx-weim: change to use devm_clk_get_enabled() helper Make the code cleaner and avoid call clk_disable_unprepare() Signed-off-by: Wu Bo Signed-off-by: Shawn Guo --- drivers/bus/imx-weim.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index 837bf9d51c6e..83d623d97f5f 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -282,22 +282,18 @@ static int weim_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, priv); /* get the clock */ - clk = devm_clk_get(&pdev->dev, NULL); + clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk); - ret = clk_prepare_enable(clk); - if (ret) - return ret; - /* parse the device node */ ret = weim_parse_dt(pdev); if (ret) - clk_disable_unprepare(clk); - else - dev_info(&pdev->dev, "Driver registered.\n"); + return ret; - return ret; + dev_info(&pdev->dev, "Driver registered.\n"); + + return 0; } #if IS_ENABLED(CONFIG_OF_DYNAMIC) From f2642d97f2105ed17b2ece0c597450f2ff95d704 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 Aug 2024 07:49:33 +0200 Subject: [PATCH 140/212] ARM: versatile: fix OF node leak in CPUs prepare Machine code is leaking OF node reference from of_find_matching_node() in realview_smp_prepare_cpus(). Fixes: 5420b4b15617 ("ARM: realview: add an DT SMP boot method") Signed-off-by: Krzysztof Kozlowski Acked-by: Liviu Dudau Link: https://lore.kernel.org/20240826054934.10724-1-krzysztof.kozlowski@linaro.org Signed-off-by: Linus Walleij --- arch/arm/mach-versatile/platsmp-realview.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-versatile/platsmp-realview.c b/arch/arm/mach-versatile/platsmp-realview.c index 6965a1de727b..d38b2e174257 100644 --- a/arch/arm/mach-versatile/platsmp-realview.c +++ b/arch/arm/mach-versatile/platsmp-realview.c @@ -70,6 +70,7 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus) return; } map = syscon_node_to_regmap(np); + of_node_put(np); if (IS_ERR(map)) { pr_err("PLATSMP: No syscon regmap\n"); return; From 15a62b81175885b5adfcaf49870466e3603f06c7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 Aug 2024 07:49:34 +0200 Subject: [PATCH 141/212] bus: integrator-lm: fix OF node leak in probe() Driver code is leaking OF node reference from of_find_matching_node() in probe(). Fixes: ccea5e8a5918 ("bus: Add driver for Integrator/AP logic modules") Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Kozlowski Acked-by: Liviu Dudau Link: https://lore.kernel.org/20240826054934.10724-2-krzysztof.kozlowski@linaro.org Signed-off-by: Linus Walleij --- drivers/bus/arm-integrator-lm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bus/arm-integrator-lm.c b/drivers/bus/arm-integrator-lm.c index b715c8ab36e8..a65c79b08804 100644 --- a/drivers/bus/arm-integrator-lm.c +++ b/drivers/bus/arm-integrator-lm.c @@ -85,6 +85,7 @@ static int integrator_ap_lm_probe(struct platform_device *pdev) return -ENODEV; } map = syscon_node_to_regmap(syscon); + of_node_put(syscon); if (IS_ERR(map)) { dev_err(dev, "could not find Integrator/AP system controller\n"); From 6bbc0fa234a2ec144a469bd35d8f68e21e69af5a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 18 Aug 2024 19:28:19 +0200 Subject: [PATCH 142/212] dt-bindings: reset: socionext,uniphier-glue-reset: add top-level constraints Properties with variable number of items per each device are expected to have widest constraints in top-level "properties:" block and further customized (narrowed) in "if:then:". Add missing top-level constraints for clock-names and reset-names. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Kunihiko Hayashi Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20240818172819.121697-1-krzysztof.kozlowski@linaro.org Signed-off-by: Philipp Zabel --- .../bindings/reset/socionext,uniphier-glue-reset.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/reset/socionext,uniphier-glue-reset.yaml b/Documentation/devicetree/bindings/reset/socionext,uniphier-glue-reset.yaml index fa253c518d79..babc563ae61e 100644 --- a/Documentation/devicetree/bindings/reset/socionext,uniphier-glue-reset.yaml +++ b/Documentation/devicetree/bindings/reset/socionext,uniphier-glue-reset.yaml @@ -38,13 +38,17 @@ properties: minItems: 1 maxItems: 2 - clock-names: true + clock-names: + minItems: 1 + maxItems: 2 resets: minItems: 1 maxItems: 2 - reset-names: true + reset-names: + minItems: 1 + maxItems: 2 allOf: - if: From 29d258542f900a55791ec2ca8b15e4f9da083a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:35 +0200 Subject: [PATCH 143/212] firmware: turris-mox-rwtm: Use macro constant instead of hardcoded 4096 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 4096 bytes limit in mox_hwrng_read() is due to the DMA buffer being allocated to one PAGE_SIZE bytes. Use new local macro constant RWTM_DMA_BUFFER_SIZE at allocation time and when used in mox_hwrng_read(). Use SZ_4K instead of PAGE_SIZE. Although PAGE_SIZE is never set to a larger value on Armada 3720, it theoretically could, and this would be a waste of space. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-2-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 3e7f186d239a..67d7b65da174 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -11,14 +11,18 @@ #include #include #include +#include #include #include #include #include +#include #include #define DRIVER_NAME "turris-mox-rwtm" +#define RWTM_DMA_BUFFER_SIZE SZ_4K + /* * The macros and constants below come from Turris Mox's rWTM firmware code. * This firmware is open source and it's sources can be found at @@ -287,8 +291,7 @@ static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) struct armada_37xx_rwtm_tx_msg msg; int ret; - if (max > 4096) - max = 4096; + max = min(max, RWTM_DMA_BUFFER_SIZE); msg.command = MBOX_CMD_GET_RANDOM; msg.args[0] = 1; @@ -479,8 +482,8 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) return -ENOMEM; rwtm->dev = dev; - rwtm->buf = dmam_alloc_coherent(dev, PAGE_SIZE, &rwtm->buf_phys, - GFP_KERNEL); + rwtm->buf = dmam_alloc_coherent(dev, RWTM_DMA_BUFFER_SIZE, + &rwtm->buf_phys, GFP_KERNEL); if (!rwtm->buf) return -ENOMEM; From c3358e1017411fae7d379fbb88f8265b11e9597d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:36 +0200 Subject: [PATCH 144/212] firmware: turris-mox-rwtm: Use ETH_ALEN instead of hardcoded 6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the ETH_ALEN macro instead of hardcoded 6 for MAC address length. Signed-off-by: Marek BehĂșn Reviewed-by: Ilpo JĂ€rvinen Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-3-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 67d7b65da174..d3ce093d4835 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,7 @@ struct mox_rwtm { int has_board_info; u64 serial_number; int board_version, ram_size; - u8 mac_address1[6], mac_address2[6]; + u8 mac_address1[ETH_ALEN], mac_address2[ETH_ALEN]; /* public key burned in eFuse */ int has_pubkey; From b787a6b89284949f3204fdc737b7e867f067720b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:37 +0200 Subject: [PATCH 145/212] firmware: turris-mox-rwtm: Use the boolean type where appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the boolean type for has_board_info, has_pubkey and last_sig_done members of the driver's private structure. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-4-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index d3ce093d4835..8875c35f9b19 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -19,6 +19,7 @@ #include #include #include +#include #define DRIVER_NAME "turris-mox-rwtm" @@ -67,13 +68,13 @@ struct mox_rwtm { struct completion cmd_done; /* board information */ - int has_board_info; + bool has_board_info; u64 serial_number; int board_version, ram_size; u8 mac_address1[ETH_ALEN], mac_address2[ETH_ALEN]; /* public key burned in eFuse */ - int has_pubkey; + bool has_pubkey; u8 pubkey[135]; #ifdef CONFIG_DEBUG_FS @@ -85,7 +86,7 @@ struct mox_rwtm { */ struct dentry *debugfs_root; u32 last_sig[34]; - int last_sig_done; + bool last_sig_done; #endif }; @@ -229,7 +230,7 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) reply->status[5]); reply_to_mac_addr(rwtm->mac_address2, reply->status[6], reply->status[7]); - rwtm->has_board_info = 1; + rwtm->has_board_info = true; pr_info("Turris Mox serial number %016llX\n", rwtm->serial_number); @@ -256,7 +257,7 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) } else { u32 *s = reply->status; - rwtm->has_pubkey = 1; + rwtm->has_pubkey = true; sprintf(rwtm->pubkey, "%06x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", ret, s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], @@ -352,7 +353,7 @@ static ssize_t do_sign_read(struct file *file, char __user *buf, size_t len, /* 2 arrays of 17 32-bit words are 136 bytes */ ret = simple_read_from_buffer(buf, len, ppos, rwtm->last_sig, 136); - rwtm->last_sig_done = 0; + rwtm->last_sig_done = false; return ret; } @@ -418,7 +419,7 @@ static ssize_t do_sign_write(struct file *file, const char __user *buf, */ memcpy(rwtm->last_sig, rwtm->buf + 68, 136); cpu_to_be32_array(rwtm->last_sig, rwtm->last_sig, 34); - rwtm->last_sig_done = 1; + rwtm->last_sig_done = true; mutex_unlock(&rwtm->busy); return len; From 99ed7980b5b03ad70d8965f300e1b9b8a21e0295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:38 +0200 Subject: [PATCH 146/212] firmware: turris-mox-rwtm: Hide signature related constants behind macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hide signature generation related constants behind macros instead of hardcoding the values. Use SHA512_DIGEST_SIZE from crypto/sha2.h instead of hardcoded 64 as the message size. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-5-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 36 ++++++++++++++++++------------ 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 8875c35f9b19..cf8c605d99ef 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -5,6 +5,7 @@ * Copyright (C) 2019, 2024 Marek BehĂșn */ +#include #include #include #include @@ -31,6 +32,11 @@ * https://gitlab.labs.nic.cz/turris/mox-boot-builder/tree/master/wtmi. */ +#define MOX_ECC_NUMBER_WORDS 17 +#define MOX_ECC_NUMBER_LEN (MOX_ECC_NUMBER_WORDS * sizeof(u32)) + +#define MOX_ECC_SIGNATURE_WORDS (2 * MOX_ECC_NUMBER_WORDS) + #define MBOX_STS_SUCCESS (0 << 30) #define MBOX_STS_FAIL (1 << 30) #define MBOX_STS_BADCMD (2 << 30) @@ -85,7 +91,7 @@ struct mox_rwtm { * from userspace. */ struct dentry *debugfs_root; - u32 last_sig[34]; + u32 last_sig[MOX_ECC_SIGNATURE_WORDS]; bool last_sig_done; #endif }; @@ -341,18 +347,18 @@ static ssize_t do_sign_read(struct file *file, char __user *buf, size_t len, struct mox_rwtm *rwtm = file->private_data; ssize_t ret; - /* only allow one read, of 136 bytes, from position 0 */ + /* only allow one read, of whole signature, from position 0 */ if (*ppos != 0) return 0; - if (len < 136) + if (len < sizeof(rwtm->last_sig)) return -EINVAL; if (!rwtm->last_sig_done) return -ENODATA; - /* 2 arrays of 17 32-bit words are 136 bytes */ - ret = simple_read_from_buffer(buf, len, ppos, rwtm->last_sig, 136); + ret = simple_read_from_buffer(buf, len, ppos, rwtm->last_sig, + sizeof(rwtm->last_sig)); rwtm->last_sig_done = false; return ret; @@ -367,8 +373,7 @@ static ssize_t do_sign_write(struct file *file, const char __user *buf, loff_t dummy = 0; ssize_t ret; - /* the input is a SHA-512 hash, so exactly 64 bytes have to be read */ - if (len != 64) + if (len != SHA512_DIGEST_SIZE) return -EINVAL; /* if last result is not zero user has not read that information yet */ @@ -389,17 +394,18 @@ static ssize_t do_sign_write(struct file *file, const char __user *buf, * 3. Address of the buffer where ECDSA signature value S shall be * stored by the rWTM firmware. */ - memset(rwtm->buf, 0, 4); - ret = simple_write_to_buffer(rwtm->buf + 4, 64, &dummy, buf, len); + memset(rwtm->buf, 0, sizeof(u32)); + ret = simple_write_to_buffer(rwtm->buf + sizeof(u32), + SHA512_DIGEST_SIZE, &dummy, buf, len); if (ret < 0) goto unlock_mutex; - be32_to_cpu_array(rwtm->buf, rwtm->buf, 17); + be32_to_cpu_array(rwtm->buf, rwtm->buf, MOX_ECC_NUMBER_WORDS); msg.command = MBOX_CMD_SIGN; msg.args[0] = 1; msg.args[1] = rwtm->buf_phys; - msg.args[2] = rwtm->buf_phys + 68; - msg.args[3] = rwtm->buf_phys + 2 * 68; + msg.args[2] = rwtm->buf_phys + MOX_ECC_NUMBER_LEN; + msg.args[3] = rwtm->buf_phys + 2 * MOX_ECC_NUMBER_LEN; ret = mbox_send_message(rwtm->mbox, &msg); if (ret < 0) goto unlock_mutex; @@ -417,8 +423,10 @@ static ssize_t do_sign_write(struct file *file, const char __user *buf, * computed by the rWTM firmware and convert their words from * LE to BE. */ - memcpy(rwtm->last_sig, rwtm->buf + 68, 136); - cpu_to_be32_array(rwtm->last_sig, rwtm->last_sig, 34); + memcpy(rwtm->last_sig, rwtm->buf + MOX_ECC_NUMBER_LEN, + sizeof(rwtm->last_sig)); + cpu_to_be32_array(rwtm->last_sig, rwtm->last_sig, + MOX_ECC_SIGNATURE_WORDS); rwtm->last_sig_done = true; mutex_unlock(&rwtm->busy); From 671d5f68698b5e516c23048e5bfd4bcd9d90cc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:39 +0200 Subject: [PATCH 147/212] firmware: turris-mox-rwtm: Fix driver includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop including of.h, include several other headers that are used but not included directly. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-6-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index cf8c605d99ef..ca1eb1687d44 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -8,18 +8,23 @@ #include #include #include +#include #include +#include #include +#include +#include #include #include +#include #include #include #include #include -#include #include #include #include +#include #include #define DRIVER_NAME "turris-mox-rwtm" From 97a9c5b3e0a4791cd4aa9d9ebbbfb2c0e83e2ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:40 +0200 Subject: [PATCH 148/212] firmware: turris-mox-rwtm: Use sysfs_emit() instead of sprintf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use sysfs_emit() instead of sprintf() in sysfs attribute .show() method. Signed-off-by: Marek BehĂșn Link: https://lore.kernel.org/r/20240831092050.23093-7-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index ca1eb1687d44..8923c4cabcd0 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -151,7 +151,7 @@ name##_show(struct kobject *kobj, struct kobj_attribute *a, \ struct mox_rwtm *rwtm = to_rwtm(kobj); \ if (!rwtm->has_##cat) \ return -ENODATA; \ - return sprintf(buf, format, rwtm->name); \ + return sysfs_emit(buf, format, rwtm->name); \ } \ static struct kobj_attribute mox_attr_##name = __ATTR_RO(name) From 579e05ee1bfbc76bd270074916882471e88c7af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:41 +0200 Subject: [PATCH 149/212] firmware: turris-mox-rwtm: Don't create own kobject type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to create attribute files in /sys/firmware/turris-mox-rwtm, this driver creates it's own kobject type. Simplify this by dropping this own kobject creation, and instead creating standard device attribute files. For backwards compatibility with sysfs ABI, create a symlink /sys/firmware/turris-mox-rwtm, pointing to this device's sysfs directory. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-8-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 108 ++++++++--------------------- 1 file changed, 30 insertions(+), 78 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 8923c4cabcd0..97b40982a3e7 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -61,13 +60,10 @@ enum mbox_cmd { MBOX_CMD_OTP_WRITE = 8, }; -struct mox_kobject; - struct mox_rwtm { struct device *dev; struct mbox_client mbox_client; struct mbox_chan *mbox; - struct mox_kobject *kobj; struct hwrng hwrng; struct armada_37xx_rwtm_rx_msg reply; @@ -101,59 +97,17 @@ struct mox_rwtm { #endif }; -struct mox_kobject { - struct kobject kobj; - struct mox_rwtm *rwtm; -}; - -static inline struct kobject *rwtm_to_kobj(struct mox_rwtm *rwtm) -{ - return &rwtm->kobj->kobj; -} - -static inline struct mox_rwtm *to_rwtm(struct kobject *kobj) -{ - return container_of(kobj, struct mox_kobject, kobj)->rwtm; -} - -static void mox_kobj_release(struct kobject *kobj) -{ - kfree(to_rwtm(kobj)->kobj); -} - -static const struct kobj_type mox_kobj_ktype = { - .release = mox_kobj_release, - .sysfs_ops = &kobj_sysfs_ops, -}; - -static int mox_kobj_create(struct mox_rwtm *rwtm) -{ - rwtm->kobj = kzalloc(sizeof(*rwtm->kobj), GFP_KERNEL); - if (!rwtm->kobj) - return -ENOMEM; - - kobject_init(rwtm_to_kobj(rwtm), &mox_kobj_ktype); - if (kobject_add(rwtm_to_kobj(rwtm), firmware_kobj, "turris-mox-rwtm")) { - kobject_put(rwtm_to_kobj(rwtm)); - return -ENXIO; - } - - rwtm->kobj->rwtm = rwtm; - - return 0; -} - #define MOX_ATTR_RO(name, format, cat) \ static ssize_t \ -name##_show(struct kobject *kobj, struct kobj_attribute *a, \ +name##_show(struct device *dev, struct device_attribute *a, \ char *buf) \ { \ - struct mox_rwtm *rwtm = to_rwtm(kobj); \ + struct mox_rwtm *rwtm = dev_get_drvdata(dev); \ if (!rwtm->has_##cat) \ return -ENODATA; \ return sysfs_emit(buf, format, rwtm->name); \ } \ -static struct kobj_attribute mox_attr_##name = __ATTR_RO(name) +static DEVICE_ATTR_RO(name) MOX_ATTR_RO(serial_number, "%016llX\n", board_info); MOX_ATTR_RO(board_version, "%i\n", board_info); @@ -162,6 +116,17 @@ MOX_ATTR_RO(mac_address1, "%pM\n", board_info); MOX_ATTR_RO(mac_address2, "%pM\n", board_info); MOX_ATTR_RO(pubkey, "%s\n", pubkey); +static struct attribute *turris_mox_rwtm_attrs[] = { + &dev_attr_serial_number.attr, + &dev_attr_board_version.attr, + &dev_attr_ram_size.attr, + &dev_attr_mac_address1.attr, + &dev_attr_mac_address2.attr, + &dev_attr_pubkey.attr, + NULL +}; +ATTRIBUTE_GROUPS(turris_mox_rwtm); + static int mox_get_status(enum mbox_cmd cmd, u32 retval) { if (MBOX_STS_CMD(retval) != cmd) @@ -176,16 +141,6 @@ static int mox_get_status(enum mbox_cmd cmd, u32 retval) return MBOX_STS_VALUE(retval); } -static const struct attribute *mox_rwtm_attrs[] = { - &mox_attr_serial_number.attr, - &mox_attr_board_version.attr, - &mox_attr_ram_size.attr, - &mox_attr_mac_address1.attr, - &mox_attr_mac_address2.attr, - &mox_attr_pubkey.attr, - NULL -}; - static void mox_rwtm_rx_callback(struct mbox_client *cl, void *data) { struct mox_rwtm *rwtm = dev_get_drvdata(cl->dev); @@ -486,6 +441,11 @@ static inline void rwtm_unregister_debugfs(struct mox_rwtm *rwtm) } #endif +static void rwtm_firmware_symlink_drop(void *parent) +{ + sysfs_remove_link(parent, DRIVER_NAME); +} + static int turris_mox_rwtm_probe(struct platform_device *pdev) { struct mox_rwtm *rwtm; @@ -502,18 +462,6 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) if (!rwtm->buf) return -ENOMEM; - ret = mox_kobj_create(rwtm); - if (ret < 0) { - dev_err(dev, "Cannot create turris-mox-rwtm kobject!\n"); - return ret; - } - - ret = sysfs_create_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs); - if (ret < 0) { - dev_err(dev, "Cannot create sysfs files!\n"); - goto put_kobj; - } - platform_set_drvdata(pdev, rwtm); mutex_init(&rwtm->busy); @@ -528,7 +476,7 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) if (ret != -EPROBE_DEFER) dev_err(dev, "Cannot request mailbox channel: %i\n", ret); - goto remove_files; + return ret; } ret = mox_get_board_info(rwtm); @@ -560,14 +508,19 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) dev_info(dev, "HWRNG successfully registered\n"); + /* + * For sysfs ABI compatibility, create symlink + * /sys/firmware/turris-mox-rwtm to this device's sysfs directory. + */ + ret = sysfs_create_link(firmware_kobj, &dev->kobj, DRIVER_NAME); + if (!ret) + devm_add_action_or_reset(dev, rwtm_firmware_symlink_drop, + firmware_kobj); + return 0; free_channel: mbox_free_channel(rwtm->mbox); -remove_files: - sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs); -put_kobj: - kobject_put(rwtm_to_kobj(rwtm)); return ret; } @@ -576,8 +529,6 @@ static void turris_mox_rwtm_remove(struct platform_device *pdev) struct mox_rwtm *rwtm = platform_get_drvdata(pdev); rwtm_unregister_debugfs(rwtm); - sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs); - kobject_put(rwtm_to_kobj(rwtm)); mbox_free_channel(rwtm->mbox); } @@ -595,6 +546,7 @@ static struct platform_driver turris_mox_rwtm_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = turris_mox_rwtm_match, + .dev_groups = turris_mox_rwtm_groups, }, }; module_platform_driver(turris_mox_rwtm_driver); From 1b649ec180d41dbcdcd6d38a49cbab885661514b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:42 +0200 Subject: [PATCH 150/212] firmware: turris-mox-rwtm: Simplify debugfs code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify debugfs code: do not check for errors, as debugfs errors should be ignored, and use devm action for dropping the debugfs directory. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-9-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 44 ++++++++---------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 97b40982a3e7..0462c345778c 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -91,7 +91,6 @@ struct mox_rwtm { * It should be rewritten via crypto API once akcipher API is available * from userspace. */ - struct dentry *debugfs_root; u32 last_sig[MOX_ECC_SIGNATURE_WORDS]; bool last_sig_done; #endif @@ -404,39 +403,23 @@ static const struct file_operations do_sign_fops = { .llseek = no_llseek, }; -static int rwtm_register_debugfs(struct mox_rwtm *rwtm) +static void rwtm_debugfs_release(void *root) { - struct dentry *root, *entry; + debugfs_remove_recursive(root); +} + +static void rwtm_register_debugfs(struct mox_rwtm *rwtm) +{ + struct dentry *root; root = debugfs_create_dir("turris-mox-rwtm", NULL); - if (IS_ERR(root)) - return PTR_ERR(root); + debugfs_create_file_unsafe("do_sign", 0600, root, rwtm, &do_sign_fops); - entry = debugfs_create_file_unsafe("do_sign", 0600, root, rwtm, - &do_sign_fops); - if (IS_ERR(entry)) - goto err_remove; - - rwtm->debugfs_root = root; - - return 0; -err_remove: - debugfs_remove_recursive(root); - return PTR_ERR(entry); -} - -static void rwtm_unregister_debugfs(struct mox_rwtm *rwtm) -{ - debugfs_remove_recursive(rwtm->debugfs_root); + devm_add_action_or_reset(rwtm->dev, rwtm_debugfs_release, root); } #else -static inline int rwtm_register_debugfs(struct mox_rwtm *rwtm) -{ - return 0; -} - -static inline void rwtm_unregister_debugfs(struct mox_rwtm *rwtm) +static inline void rwtm_register_debugfs(struct mox_rwtm *rwtm) { } #endif @@ -500,11 +483,7 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) goto free_channel; } - ret = rwtm_register_debugfs(rwtm); - if (ret < 0) { - dev_err(dev, "Failed creating debugfs entries: %i\n", ret); - goto free_channel; - } + rwtm_register_debugfs(rwtm); dev_info(dev, "HWRNG successfully registered\n"); @@ -528,7 +507,6 @@ static void turris_mox_rwtm_remove(struct platform_device *pdev) { struct mox_rwtm *rwtm = platform_get_drvdata(pdev); - rwtm_unregister_debugfs(rwtm); mbox_free_channel(rwtm->mbox); } From fbd48bd8cf0c4063465e2713bfaedfa71709a116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:43 +0200 Subject: [PATCH 151/212] firmware: turris-mox-rwtm: Convert rest to devm_* and get rid of driver .remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm resource management for driver's mailbox. This allows us to get rid of the driver's .remove() method and the gotos in .probe(). Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-10-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 0462c345778c..dd0dbaa9de72 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -424,6 +424,11 @@ static inline void rwtm_register_debugfs(struct mox_rwtm *rwtm) } #endif +static void rwtm_devm_mbox_release(void *mbox) +{ + mbox_free_channel(mbox); +} + static void rwtm_firmware_symlink_drop(void *parent) { sysfs_remove_link(parent, DRIVER_NAME); @@ -462,6 +467,10 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) return ret; } + ret = devm_add_action_or_reset(dev, rwtm_devm_mbox_release, rwtm->mbox); + if (ret) + return ret; + ret = mox_get_board_info(rwtm); if (ret < 0) dev_warn(dev, "Cannot read board information: %i\n", ret); @@ -470,7 +479,7 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) if (ret < 0) { dev_notice(dev, "Firmware does not support the GET_RANDOM command\n"); - goto free_channel; + return ret; } rwtm->hwrng.name = DRIVER_NAME "_hwrng"; @@ -480,7 +489,7 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) ret = devm_hwrng_register(dev, &rwtm->hwrng); if (ret < 0) { dev_err(dev, "Cannot register HWRNG: %i\n", ret); - goto free_channel; + return ret; } rwtm_register_debugfs(rwtm); @@ -497,17 +506,6 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) firmware_kobj); return 0; - -free_channel: - mbox_free_channel(rwtm->mbox); - return ret; -} - -static void turris_mox_rwtm_remove(struct platform_device *pdev) -{ - struct mox_rwtm *rwtm = platform_get_drvdata(pdev); - - mbox_free_channel(rwtm->mbox); } static const struct of_device_id turris_mox_rwtm_match[] = { @@ -520,7 +518,6 @@ MODULE_DEVICE_TABLE(of, turris_mox_rwtm_match); static struct platform_driver turris_mox_rwtm_driver = { .probe = turris_mox_rwtm_probe, - .remove_new = turris_mox_rwtm_remove, .driver = { .name = DRIVER_NAME, .of_match_table = turris_mox_rwtm_match, From 869b1fc0435699aec568101c1b4279d5bc03bf3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:44 +0200 Subject: [PATCH 152/212] firmware: turris-mox-rwtm: Use dev_err_probe() where possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use dev_err_probe() where possible in the driver's .probe() method. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-11-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index dd0dbaa9de72..f291df9a72ff 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -459,13 +459,9 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) rwtm->mbox_client.rx_callback = mox_rwtm_rx_callback; rwtm->mbox = mbox_request_channel(&rwtm->mbox_client, 0); - if (IS_ERR(rwtm->mbox)) { - ret = PTR_ERR(rwtm->mbox); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Cannot request mailbox channel: %i\n", - ret); - return ret; - } + if (IS_ERR(rwtm->mbox)) + return dev_err_probe(dev, PTR_ERR(rwtm->mbox), + "Cannot request mailbox channel!\n"); ret = devm_add_action_or_reset(dev, rwtm_devm_mbox_release, rwtm->mbox); if (ret) @@ -487,10 +483,8 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) rwtm->hwrng.priv = (unsigned long) rwtm; ret = devm_hwrng_register(dev, &rwtm->hwrng); - if (ret < 0) { - dev_err(dev, "Cannot register HWRNG: %i\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Cannot register HWRNG!\n"); rwtm_register_debugfs(rwtm); From ed09d6d4f5938626823af3d2a04ff3a395bd348a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:45 +0200 Subject: [PATCH 153/212] firmware: turris-mox-rwtm: Drop redundant device pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop redundant device pointer from driver's private structure. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-12-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index f291df9a72ff..d12e29625022 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -61,7 +61,6 @@ enum mbox_cmd { }; struct mox_rwtm { - struct device *dev; struct mbox_client mbox_client; struct mbox_chan *mbox; struct hwrng hwrng; @@ -96,6 +95,11 @@ struct mox_rwtm { #endif }; +static inline struct device *rwtm_dev(struct mox_rwtm *rwtm) +{ + return rwtm->mbox_client.dev; +} + #define MOX_ATTR_RO(name, format, cat) \ static ssize_t \ name##_show(struct device *dev, struct device_attribute *a, \ @@ -164,6 +168,7 @@ static void reply_to_mac_addr(u8 *mac, u32 t1, u32 t2) static int mox_get_board_info(struct mox_rwtm *rwtm) { + struct device *dev = rwtm_dev(rwtm); struct armada_37xx_rwtm_tx_msg msg; struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply; int ret; @@ -178,10 +183,10 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval); if (ret == -ENODATA) { - dev_warn(rwtm->dev, + dev_warn(dev, "Board does not have manufacturing information burned!\n"); } else if (ret == -ENOSYS) { - dev_notice(rwtm->dev, + dev_notice(dev, "Firmware does not support the BOARD_INFO command\n"); } else if (ret < 0) { return ret; @@ -213,9 +218,9 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval); if (ret == -ENODATA) { - dev_warn(rwtm->dev, "Board has no public key burned!\n"); + dev_warn(dev, "Board has no public key burned!\n"); } else if (ret == -ENOSYS) { - dev_notice(rwtm->dev, + dev_notice(dev, "Firmware does not support the ECDSA_PUB_KEY command\n"); } else if (ret < 0) { return ret; @@ -416,7 +421,7 @@ static void rwtm_register_debugfs(struct mox_rwtm *rwtm) debugfs_create_file_unsafe("do_sign", 0600, root, rwtm, &do_sign_fops); - devm_add_action_or_reset(rwtm->dev, rwtm_debugfs_release, root); + devm_add_action_or_reset(rwtm_dev(rwtm), rwtm_debugfs_release, root); } #else static inline void rwtm_register_debugfs(struct mox_rwtm *rwtm) @@ -444,7 +449,6 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) if (!rwtm) return -ENOMEM; - rwtm->dev = dev; rwtm->buf = dmam_alloc_coherent(dev, RWTM_DMA_BUFFER_SIZE, &rwtm->buf_phys, GFP_KERNEL); if (!rwtm->buf) From db955e0847484c64c6e749659527b5f45b2b5749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:46 +0200 Subject: [PATCH 154/212] firmware: turris-mox-rwtm: Use devm_mutex_init() instead of mutex_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_mutex_init() instead of mutex_init(), to properly call mutex_destroy() on probe failure / driver unbind. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-13-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index d12e29625022..9f6bda969943 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -456,7 +456,10 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rwtm); - mutex_init(&rwtm->busy); + ret = devm_mutex_init(dev, &rwtm->busy); + if (ret) + return ret; + init_completion(&rwtm->cmd_done); rwtm->mbox_client.dev = dev; From 21733f5902bee79357dad9994865df5229b538a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:47 +0200 Subject: [PATCH 155/212] firmware: turris-mox-rwtm: Use container_of() instead of hwrng .priv member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use container_of() to get driver private structure from hwnrg structure, instead of the hwrng's .priv member, as suggested by Herbert for another driver. Link: https://lore.kernel.org/soc/ZmLhQBdmg613KdET@gondor.apana.org.au/ Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-14-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 9f6bda969943..52f97235c3a6 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -259,7 +259,7 @@ static int check_get_random_support(struct mox_rwtm *rwtm) static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) { - struct mox_rwtm *rwtm = (struct mox_rwtm *) rng->priv; + struct mox_rwtm *rwtm = container_of(rng, struct mox_rwtm, hwrng); struct armada_37xx_rwtm_tx_msg msg; int ret; @@ -487,7 +487,6 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev) rwtm->hwrng.name = DRIVER_NAME "_hwrng"; rwtm->hwrng.read = mox_hwrng_read; - rwtm->hwrng.priv = (unsigned long) rwtm; ret = devm_hwrng_register(dev, &rwtm->hwrng); if (ret) From 8a4853a65b88240dc778b5d4360a2921ec6b22c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:48 +0200 Subject: [PATCH 156/212] firmware: turris-mox-rwtm: Use EOPNOTSUPP instead of ENOSYS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checkpatch warns agains -ENOSYS: WARNING: ENOSYS means 'invalid syscall nr' and nothing else Use EOPNOTSUPP instead. Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-15-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 52f97235c3a6..a9391705f5b4 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -137,7 +137,7 @@ static int mox_get_status(enum mbox_cmd cmd, u32 retval) else if (MBOX_STS_ERROR(retval) == MBOX_STS_FAIL) return -(int)MBOX_STS_VALUE(retval); else if (MBOX_STS_ERROR(retval) == MBOX_STS_BADCMD) - return -ENOSYS; + return -EOPNOTSUPP; else if (MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS) return -EIO; else @@ -185,7 +185,7 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) if (ret == -ENODATA) { dev_warn(dev, "Board does not have manufacturing information burned!\n"); - } else if (ret == -ENOSYS) { + } else if (ret == -EOPNOTSUPP) { dev_notice(dev, "Firmware does not support the BOARD_INFO command\n"); } else if (ret < 0) { @@ -219,7 +219,7 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval); if (ret == -ENODATA) { dev_warn(dev, "Board has no public key burned!\n"); - } else if (ret == -ENOSYS) { + } else if (ret == -EOPNOTSUPP) { dev_notice(dev, "Firmware does not support the ECDSA_PUB_KEY command\n"); } else if (ret < 0) { From 82944f65a0a59a44c397e3e22d592afdfb9b3074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:49 +0200 Subject: [PATCH 157/212] firmware: turris-mox-rwtm: Use ALIGN() instead of hardcoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use ALIGN(max, 4) instead of hardcoding ((max + 3) & ~3). Signed-off-by: Marek BehĂșn Link: https://lore.kernel.org/r/20240831092050.23093-16-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index a9391705f5b4..0c7d8c96ea17 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -268,7 +269,7 @@ static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) msg.command = MBOX_CMD_GET_RANDOM; msg.args[0] = 1; msg.args[1] = rwtm->buf_phys; - msg.args[2] = (max + 3) & ~3; + msg.args[2] = ALIGN(max, 4); if (!wait) { if (!mutex_trylock(&rwtm->busy)) From a79f256fc99d6d7aa4a8c738c28cc876e5ef1435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 31 Aug 2024 11:20:50 +0200 Subject: [PATCH 158/212] firmware: turris-mox-rwtm: Deduplicate command execution code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deduplicate rWTM command execution calls mbox_send_message() wait_for_completion() mox_get_status() to one function mox_rwtm_exec() Signed-off-by: Marek BehĂșn Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20240831092050.23093-17-kabel@kernel.org Signed-off-by: Arnd Bergmann --- drivers/firmware/turris-mox-rwtm.c | 98 ++++++++++++------------------ 1 file changed, 39 insertions(+), 59 deletions(-) diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 0c7d8c96ea17..525ebdc7ded5 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -157,6 +157,34 @@ static void mox_rwtm_rx_callback(struct mbox_client *cl, void *data) complete(&rwtm->cmd_done); } +static int mox_rwtm_exec(struct mox_rwtm *rwtm, enum mbox_cmd cmd, + struct armada_37xx_rwtm_tx_msg *msg, + bool interruptible) +{ + struct armada_37xx_rwtm_tx_msg _msg = {}; + int ret; + + if (!msg) + msg = &_msg; + + msg->command = cmd; + + ret = mbox_send_message(rwtm->mbox, msg); + if (ret < 0) + return ret; + + if (interruptible) { + ret = wait_for_completion_interruptible(&rwtm->cmd_done); + if (ret < 0) + return ret; + } else { + if (!wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2)) + return -ETIMEDOUT; + } + + return mox_get_status(cmd, rwtm->reply.retval); +} + static void reply_to_mac_addr(u8 *mac, u32 t1, u32 t2) { mac[0] = t1 >> 8; @@ -170,19 +198,10 @@ static void reply_to_mac_addr(u8 *mac, u32 t1, u32 t2) static int mox_get_board_info(struct mox_rwtm *rwtm) { struct device *dev = rwtm_dev(rwtm); - struct armada_37xx_rwtm_tx_msg msg; struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply; int ret; - msg.command = MBOX_CMD_BOARD_INFO; - ret = mbox_send_message(rwtm->mbox, &msg); - if (ret < 0) - return ret; - - if (!wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2)) - return -ETIMEDOUT; - - ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval); + ret = mox_rwtm_exec(rwtm, MBOX_CMD_BOARD_INFO, NULL, false); if (ret == -ENODATA) { dev_warn(dev, "Board does not have manufacturing information burned!\n"); @@ -209,15 +228,7 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) pr_info(" burned RAM size %i MiB\n", rwtm->ram_size); } - msg.command = MBOX_CMD_ECDSA_PUB_KEY; - ret = mbox_send_message(rwtm->mbox, &msg); - if (ret < 0) - return ret; - - if (!wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2)) - return -ETIMEDOUT; - - ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval); + ret = mox_rwtm_exec(rwtm, MBOX_CMD_ECDSA_PUB_KEY, NULL, false); if (ret == -ENODATA) { dev_warn(dev, "Board has no public key burned!\n"); } else if (ret == -EOPNOTSUPP) { @@ -240,37 +251,23 @@ static int mox_get_board_info(struct mox_rwtm *rwtm) static int check_get_random_support(struct mox_rwtm *rwtm) { - struct armada_37xx_rwtm_tx_msg msg; - int ret; + struct armada_37xx_rwtm_tx_msg msg = { + .args = { 1, rwtm->buf_phys, 4 }, + }; - msg.command = MBOX_CMD_GET_RANDOM; - msg.args[0] = 1; - msg.args[1] = rwtm->buf_phys; - msg.args[2] = 4; - - ret = mbox_send_message(rwtm->mbox, &msg); - if (ret < 0) - return ret; - - if (!wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2)) - return -ETIMEDOUT; - - return mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval); + return mox_rwtm_exec(rwtm, MBOX_CMD_GET_RANDOM, &msg, false); } static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) { struct mox_rwtm *rwtm = container_of(rng, struct mox_rwtm, hwrng); - struct armada_37xx_rwtm_tx_msg msg; + struct armada_37xx_rwtm_tx_msg msg = { + .args = { 1, rwtm->buf_phys, ALIGN(max, 4) }, + }; int ret; max = min(max, RWTM_DMA_BUFFER_SIZE); - msg.command = MBOX_CMD_GET_RANDOM; - msg.args[0] = 1; - msg.args[1] = rwtm->buf_phys; - msg.args[2] = ALIGN(max, 4); - if (!wait) { if (!mutex_trylock(&rwtm->busy)) return -EBUSY; @@ -278,15 +275,7 @@ static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) mutex_lock(&rwtm->busy); } - ret = mbox_send_message(rwtm->mbox, &msg); - if (ret < 0) - goto unlock_mutex; - - ret = wait_for_completion_interruptible(&rwtm->cmd_done); - if (ret < 0) - goto unlock_mutex; - - ret = mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval); + ret = mox_rwtm_exec(rwtm, MBOX_CMD_GET_RANDOM, &msg, true); if (ret < 0) goto unlock_mutex; @@ -333,7 +322,6 @@ static ssize_t do_sign_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct mox_rwtm *rwtm = file->private_data; - struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply; struct armada_37xx_rwtm_tx_msg msg; loff_t dummy = 0; ssize_t ret; @@ -366,23 +354,15 @@ static ssize_t do_sign_write(struct file *file, const char __user *buf, goto unlock_mutex; be32_to_cpu_array(rwtm->buf, rwtm->buf, MOX_ECC_NUMBER_WORDS); - msg.command = MBOX_CMD_SIGN; msg.args[0] = 1; msg.args[1] = rwtm->buf_phys; msg.args[2] = rwtm->buf_phys + MOX_ECC_NUMBER_LEN; msg.args[3] = rwtm->buf_phys + 2 * MOX_ECC_NUMBER_LEN; - ret = mbox_send_message(rwtm->mbox, &msg); - if (ret < 0) - goto unlock_mutex; - ret = wait_for_completion_interruptible(&rwtm->cmd_done); + ret = mox_rwtm_exec(rwtm, MBOX_CMD_SIGN, &msg, true); if (ret < 0) goto unlock_mutex; - ret = MBOX_STS_VALUE(reply->retval); - if (MBOX_STS_ERROR(reply->retval) != MBOX_STS_SUCCESS) - goto unlock_mutex; - /* * Here we read the R and S values of the ECDSA signature * computed by the rWTM firmware and convert their words from From 5f58a88cc91075be38cec69b7cb70aaa4ba69e8b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 16:14:24 +0200 Subject: [PATCH 159/212] reset: berlin: fix OF node leak in probe() error path Driver is leaking OF node reference on memory allocation failure. Acquire the OF node reference after memory allocation to fix this and keep it simple. Fixes: aed6f3cadc86 ("reset: berlin: convert to a platform driver") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Damien Le Moal Link: https://lore.kernel.org/r/20240825-reset-cleanup-scoped-v1-1-03f6d834f8c0@linaro.org Signed-off-by: Philipp Zabel --- drivers/reset/reset-berlin.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/reset/reset-berlin.c b/drivers/reset/reset-berlin.c index 2537ec05ecee..578fe867080c 100644 --- a/drivers/reset/reset-berlin.c +++ b/drivers/reset/reset-berlin.c @@ -68,13 +68,14 @@ static int berlin_reset_xlate(struct reset_controller_dev *rcdev, static int berlin2_reset_probe(struct platform_device *pdev) { - struct device_node *parent_np = of_get_parent(pdev->dev.of_node); + struct device_node *parent_np; struct berlin_reset_priv *priv; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + parent_np = of_get_parent(pdev->dev.of_node); priv->regmap = syscon_node_to_regmap(parent_np); of_node_put(parent_np); if (IS_ERR(priv->regmap)) From b14e40f5dc7cd0dd7e958010e6ca9ad32ff2ddad Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 16:14:25 +0200 Subject: [PATCH 160/212] reset: k210: fix OF node leak in probe() error path Driver is leaking OF node reference on memory allocation failure. Acquire the OF node reference after memory allocation to fix this and keep it simple. Fixes: 5a2308da9f60 ("riscv: Add Canaan Kendryte K210 reset controller") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Damien Le Moal Link: https://lore.kernel.org/r/20240825-reset-cleanup-scoped-v1-2-03f6d834f8c0@linaro.org Signed-off-by: Philipp Zabel --- drivers/reset/reset-k210.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c index b62a2fd44e4e..e77e4cca377d 100644 --- a/drivers/reset/reset-k210.c +++ b/drivers/reset/reset-k210.c @@ -90,7 +90,7 @@ static const struct reset_control_ops k210_rst_ops = { static int k210_rst_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *parent_np = of_get_parent(dev->of_node); + struct device_node *parent_np; struct k210_rst *ksr; dev_info(dev, "K210 reset controller\n"); @@ -99,6 +99,7 @@ static int k210_rst_probe(struct platform_device *pdev) if (!ksr) return -ENOMEM; + parent_np = of_get_parent(dev->of_node); ksr->map = syscon_node_to_regmap(parent_np); of_node_put(parent_np); if (IS_ERR(ksr->map)) From 3ec21e7fa854b0b9dfefacd185c486e580479bb9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 16:14:26 +0200 Subject: [PATCH 161/212] reset: simplify locking with guard() Simplify error handling (less gotos) over locks with guard(). Signed-off-by: Krzysztof Kozlowski Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240825-reset-cleanup-scoped-v1-3-03f6d834f8c0@linaro.org Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index dba74e857be6..c9074810306c 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -916,20 +916,18 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) */ lockdep_assert_not_held(&reset_list_mutex); - mutex_lock(&reset_gpio_lookup_mutex); + guard(mutex)(&reset_gpio_lookup_mutex); list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) { if (args->np == rgpio_dev->of_args.np) { if (of_phandle_args_equal(args, &rgpio_dev->of_args)) - goto out; /* Already on the list, done */ + return 0; /* Already on the list, done */ } } id = ida_alloc(&reset_gpio_ida, GFP_KERNEL); - if (id < 0) { - ret = id; - goto err_unlock; - } + if (id < 0) + return id; /* Not freed on success, because it is persisent subsystem data. */ rgpio_dev = kzalloc(sizeof(*rgpio_dev), GFP_KERNEL); @@ -959,9 +957,6 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) list_add(&rgpio_dev->list, &reset_gpio_lookup_list); -out: - mutex_unlock(&reset_gpio_lookup_mutex); - return 0; err_put: @@ -970,8 +965,6 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) kfree(rgpio_dev); err_ida_free: ida_free(&reset_gpio_ida, id); -err_unlock: - mutex_unlock(&reset_gpio_lookup_mutex); return ret; } From ece222e91f2fb818fd01ff2754cf3b1d6f2bf411 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 16:14:27 +0200 Subject: [PATCH 162/212] reset: lpc18xx: simplify with dev_err_probe() Use dev_err_probe() to avoid dmesg flood on actual defer. This makes the code also simpler. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Damien Le Moal Acked-by: Vladimir Zapolskiy Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20240825-reset-cleanup-scoped-v1-4-03f6d834f8c0@linaro.org Signed-off-by: Philipp Zabel --- drivers/reset/reset-lpc18xx.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c index 28fb85772b3e..e7896e3f1851 100644 --- a/drivers/reset/reset-lpc18xx.c +++ b/drivers/reset/reset-lpc18xx.c @@ -151,16 +151,14 @@ static int lpc18xx_rgu_probe(struct platform_device *pdev) return PTR_ERR(rc->base); rc->clk_reg = devm_clk_get(&pdev->dev, "reg"); - if (IS_ERR(rc->clk_reg)) { - dev_err(&pdev->dev, "reg clock not found\n"); - return PTR_ERR(rc->clk_reg); - } + if (IS_ERR(rc->clk_reg)) + return dev_err_probe(&pdev->dev, PTR_ERR(rc->clk_reg), + "reg clock not found\n"); rc->clk_delay = devm_clk_get(&pdev->dev, "delay"); - if (IS_ERR(rc->clk_delay)) { - dev_err(&pdev->dev, "delay clock not found\n"); - return PTR_ERR(rc->clk_delay); - } + if (IS_ERR(rc->clk_delay)) + return dev_err_probe(&pdev->dev, PTR_ERR(rc->clk_delay), + "delay clock not found\n"); ret = clk_prepare_enable(rc->clk_reg); if (ret) { From 0fa8ce76b713a31f6aef2f88d08eee74d7d3d8a7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Aug 2024 16:14:28 +0200 Subject: [PATCH 163/212] reset: lpc18xx: simplify with devm_clk_get_enabled() Use devm_clk_get_enabled() to drop clock prepare/unprepare parts and make the code simpler. Change to dev_err_probe() in handling reset_controller_register() error to make it even simpler. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Damien Le Moal Acked-by: Vladimir Zapolskiy Reviewed-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20240825-reset-cleanup-scoped-v1-5-03f6d834f8c0@linaro.org Signed-off-by: Philipp Zabel --- drivers/reset/reset-lpc18xx.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c index e7896e3f1851..e42b2f24a93d 100644 --- a/drivers/reset/reset-lpc18xx.c +++ b/drivers/reset/reset-lpc18xx.c @@ -150,28 +150,16 @@ static int lpc18xx_rgu_probe(struct platform_device *pdev) if (IS_ERR(rc->base)) return PTR_ERR(rc->base); - rc->clk_reg = devm_clk_get(&pdev->dev, "reg"); + rc->clk_reg = devm_clk_get_enabled(&pdev->dev, "reg"); if (IS_ERR(rc->clk_reg)) return dev_err_probe(&pdev->dev, PTR_ERR(rc->clk_reg), "reg clock not found\n"); - rc->clk_delay = devm_clk_get(&pdev->dev, "delay"); + rc->clk_delay = devm_clk_get_enabled(&pdev->dev, "delay"); if (IS_ERR(rc->clk_delay)) return dev_err_probe(&pdev->dev, PTR_ERR(rc->clk_delay), "delay clock not found\n"); - ret = clk_prepare_enable(rc->clk_reg); - if (ret) { - dev_err(&pdev->dev, "unable to enable reg clock\n"); - return ret; - } - - ret = clk_prepare_enable(rc->clk_delay); - if (ret) { - dev_err(&pdev->dev, "unable to enable delay clock\n"); - goto dis_clk_reg; - } - fcclk = clk_get_rate(rc->clk_reg) / USEC_PER_SEC; firc = clk_get_rate(rc->clk_delay) / USEC_PER_SEC; if (fcclk == 0 || firc == 0) @@ -187,10 +175,8 @@ static int lpc18xx_rgu_probe(struct platform_device *pdev) rc->rcdev.of_node = pdev->dev.of_node; ret = reset_controller_register(&rc->rcdev); - if (ret) { - dev_err(&pdev->dev, "unable to register device\n"); - goto dis_clks; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "unable to register device\n"); rc->restart_nb.priority = 192, rc->restart_nb.notifier_call = lpc18xx_rgu_restart, @@ -199,13 +185,6 @@ static int lpc18xx_rgu_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to register restart handler\n"); return 0; - -dis_clks: - clk_disable_unprepare(rc->clk_delay); -dis_clk_reg: - clk_disable_unprepare(rc->clk_reg); - - return ret; } static const struct of_device_id lpc18xx_rgu_match[] = { From a05f87270e9013bf8ce37efe70c8cc3e243931cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 8 Aug 2024 17:46:56 +0200 Subject: [PATCH 164/212] reset: core: add get_device()/put_device on rcdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the rcdev structure is allocated by the reset controller drivers themselves, they need to exists as long as there is a consumer. A call to module_get() is already existing but that does not work when using device-tree overlays. In order to guarantee that the underlying reset controller device does not vanish while using it, add a get_device() call when retrieving a reset control from a reset controller device and a put_device() when releasing that control. Signed-off-by: ClĂ©ment LĂ©ger Signed-off-by: Herve Codina Reviewed-by: Philipp Zabel Reviewed-by: Rob Herring (Arm) Reviewed-by: Andrew Lunn Reviewed-by: Steen Hegelund Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240808154658.247873-8-herve.codina@bootlin.com Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index c9074810306c..4d509d41456a 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -812,6 +812,7 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev, kref_init(&rstc->refcnt); rstc->acquired = acquired; rstc->shared = shared; + get_device(rcdev->dev); return rstc; } @@ -826,6 +827,7 @@ static void __reset_control_release(struct kref *kref) module_put(rstc->rcdev->owner); list_del(&rstc->list); + put_device(rstc->rcdev->dev); kfree(rstc); } From 47c270a9bf2188c3797e9791e2d59c411f7c9549 Mon Sep 17 00:00:00 2001 From: Zelong Dong Date: Mon, 22 Apr 2024 19:11:43 +0800 Subject: [PATCH 165/212] dt-bindings: reset: Add Amlogic T7 reset controller Add a new compatible for Amlogic T7 reset controller. Signed-off-by: Zelong Dong Signed-off-by: Kelvin Zhang Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20240422-t7-reset-v2-1-cb82271d3296@amlogic.com Signed-off-by: Philipp Zabel --- Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml index f0c6c0df0ce3..695ef38a7bb3 100644 --- a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml +++ b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml @@ -19,6 +19,7 @@ properties: - amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs - amlogic,meson-s4-reset # Reset Controller on S4 and compatible SoCs - amlogic,c3-reset # Reset Controller on C3 and compatible SoCs + - amlogic,t7-reset reg: maxItems: 1 From b062ef2907a2f2054d7b3f84712e12ace42ee3f1 Mon Sep 17 00:00:00 2001 From: Zelong Dong Date: Mon, 22 Apr 2024 19:11:44 +0800 Subject: [PATCH 166/212] reset: reset-meson: Add support for Amlogic T7 SoC reset controller There are 7 sets of Reset Source in Amlogic T7 SoC reset controller, and the offset between base and level registers is 0x40. Add a new compatible string and struct meson_reset_param to support the reset controller on T7 SoC. Signed-off-by: Zelong Dong Signed-off-by: Kelvin Zhang Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240422-t7-reset-v2-2-cb82271d3296@amlogic.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index f78be97898bc..1e9fca3e30e8 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -102,6 +102,11 @@ static const struct meson_reset_param meson_s4_param = { .level_offset = 0x40, }; +static const struct meson_reset_param t7_param = { + .reg_count = 7, + .level_offset = 0x40, +}; + static const struct of_device_id meson_reset_dt_ids[] = { { .compatible = "amlogic,meson8b-reset", .data = &meson8b_param}, { .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param}, @@ -109,6 +114,7 @@ static const struct of_device_id meson_reset_dt_ids[] = { { .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param}, { .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param}, { .compatible = "amlogic,c3-reset", .data = &meson_s4_param}, + { .compatible = "amlogic,t7-reset", .data = &t7_param}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, meson_reset_dt_ids); From ce50a775bd2ef31846df201804d920bbfc99c93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Tue, 30 Jul 2024 18:06:22 +0200 Subject: [PATCH 167/212] Revert "dt-bindings: reset: mobileye,eyeq5-reset: add bindings" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from one sub-node per functionality in the system-controller to a single node representing the entire OLB instance. This is the recommended approach for controllers handling many different functionalities; it is a single controller and should be represented by a single devicetree node. The reset bindings is removed and all properties will be described by: soc/mobileye/mobileye,eyeq5-olb.yaml Reviewed-by: Rob Herring (Arm) Signed-off-by: ThĂ©o Lebrun Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20240730-mbly-reset-v2-1-00b870a6a2ff@bootlin.com Signed-off-by: Philipp Zabel --- .../bindings/reset/mobileye,eyeq5-reset.yaml | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 Documentation/devicetree/bindings/reset/mobileye,eyeq5-reset.yaml diff --git a/Documentation/devicetree/bindings/reset/mobileye,eyeq5-reset.yaml b/Documentation/devicetree/bindings/reset/mobileye,eyeq5-reset.yaml deleted file mode 100644 index 062b4518347b..000000000000 --- a/Documentation/devicetree/bindings/reset/mobileye,eyeq5-reset.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/reset/mobileye,eyeq5-reset.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Mobileye EyeQ5 reset controller - -description: - The EyeQ5 reset driver handles three reset domains. Its registers live in a - shared region called OLB. - -maintainers: - - GrĂ©gory Clement - - ThĂ©o Lebrun - - Vladimir Kondratiev - -properties: - compatible: - const: mobileye,eyeq5-reset - - reg: - maxItems: 3 - - reg-names: - items: - - const: d0 - - const: d1 - - const: d2 - - "#reset-cells": - const: 2 - description: - The first cell is the domain (0 to 2 inclusive) and the second one is the - reset index inside that domain. - -required: - - compatible - - reg - - reg-names - - "#reset-cells" - -additionalProperties: false From 487b1b32e317b85c2948eb4013f3e089a0433d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Tue, 30 Jul 2024 18:06:23 +0200 Subject: [PATCH 168/212] reset: eyeq: add platform driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Mobileye EyeQ reset controller driver, for EyeQ5, EyeQ6L and EyeQ6H SoCs. Instances belong to a shared register region called OLB and gets spawned as auxiliary device to the platform driver for clock. There is one OLB instance for EyeQ5 and EyeQ6L. There are seven OLB instances on EyeQ6H; three have a reset controller embedded: - West and east get handled by the same compatible. - Acc (accelerator) is another one. Each instance vary in the number and types of reset domains. Instances with single domain expect a single cell, others two. Signed-off-by: ThĂ©o Lebrun Link: https://lore.kernel.org/r/20240730-mbly-reset-v2-2-00b870a6a2ff@bootlin.com Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 13 + drivers/reset/Makefile | 1 + drivers/reset/reset-eyeq.c | 570 +++++++++++++++++++++++++++++++++++++ 3 files changed, 584 insertions(+) create mode 100644 drivers/reset/reset-eyeq.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 67bce340a87e..5484a65f66b9 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -66,6 +66,19 @@ config RESET_BRCMSTB_RESCAL This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on BCM7216. +config RESET_EYEQ + bool "Mobileye EyeQ reset controller" + depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST + select AUXILIARY_BUS + default MACH_EYEQ5 || MACH_EYEQ6H + help + This enables the Mobileye EyeQ reset controller, used in EyeQ5, EyeQ6L + and EyeQ6H SoCs. + + It has one or more domains, with a varying number of resets in each. + Registers are located in a shared register region called OLB. EyeQ6H + has multiple reset instances. + config RESET_GPIO tristate "GPIO reset controller" depends on GPIOLIB diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 27b0bbdfcc04..4411a2a124d7 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o +obj-$(CONFIG_RESET_EYEQ) += reset-eyeq.o obj-$(CONFIG_RESET_GPIO) += reset-gpio.o obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o diff --git a/drivers/reset/reset-eyeq.c b/drivers/reset/reset-eyeq.c new file mode 100644 index 000000000000..02d50041048b --- /dev/null +++ b/drivers/reset/reset-eyeq.c @@ -0,0 +1,570 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Reset driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms. + * + * Controllers live in a shared register region called OLB. EyeQ5 and EyeQ6L + * have a single OLB instance for a single reset controller. EyeQ6H has seven + * OLB instances; three host reset controllers. + * + * Each reset controller has one or more domain. Domains are of a given type + * (see enum eqr_domain_type), with a valid offset mask (up to 32 resets per + * domain). + * + * Domain types define expected behavior: one-register-per-reset, + * one-bit-per-reset, status detection method, busywait duration, etc. + * + * We use eqr_ as prefix, as-in "EyeQ Reset", but way shorter. + * + * Known resets in EyeQ5 domain 0 (type EQR_EYEQ5_SARCR): + * 3. CAN0 4. CAN1 5. CAN2 6. SPI0 + * 7. SPI1 8. SPI2 9. SPI3 10. UART0 + * 11. UART1 12. UART2 13. I2C0 14. I2C1 + * 15. I2C2 16. I2C3 17. I2C4 18. TIMER0 + * 19. TIMER1 20. TIMER2 21. TIMER3 22. TIMER4 + * 23. WD0 24. EXT0 25. EXT1 26. GPIO + * 27. WD1 + * + * Known resets in EyeQ5 domain 1 (type EQR_EYEQ5_ACRP): + * 0. VMP0 1. VMP1 2. VMP2 3. VMP3 + * 4. PMA0 5. PMA1 6. PMAC0 7. PMAC1 + * 8. MPC0 9. MPC1 10. MPC2 11. MPC3 + * 12. MPC4 + * + * Known resets in EyeQ5 domain 2 (type EQR_EYEQ5_PCIE): + * 0. PCIE0_CORE 1. PCIE0_APB 2. PCIE0_LINK_AXI 3. PCIE0_LINK_MGMT + * 4. PCIE0_LINK_HOT 5. PCIE0_LINK_PIPE 6. PCIE1_CORE 7. PCIE1_APB + * 8. PCIE1_LINK_AXI 9. PCIE1_LINK_MGMT 10. PCIE1_LINK_HOT 11. PCIE1_LINK_PIPE + * 12. MULTIPHY 13. MULTIPHY_APB 15. PCIE0_LINK_MGMT 16. PCIE1_LINK_MGMT + * 17. PCIE0_LINK_PM 18. PCIE1_LINK_PM + * + * Known resets in EyeQ6L domain 0 (type EQR_EYEQ5_SARCR): + * 0. SPI0 1. SPI1 2. UART0 3. I2C0 + * 4. I2C1 5. TIMER0 6. TIMER1 7. TIMER2 + * 8. TIMER3 9. WD0 10. WD1 11. EXT0 + * 12. EXT1 13. GPIO + * + * Known resets in EyeQ6L domain 1 (type EQR_EYEQ5_ACRP): + * 0. VMP0 1. VMP1 2. VMP2 3. VMP3 + * 4. PMA0 5. PMA1 6. PMAC0 7. PMAC1 + * 8. MPC0 9. MPC1 10. MPC2 11. MPC3 + * 12. MPC4 + * + * Known resets in EyeQ6H west/east (type EQR_EYEQ6H_SARCR): + * 0. CAN 1. SPI0 2. SPI1 3. UART0 + * 4. UART1 5. I2C0 6. I2C1 7. -hole- + * 8. TIMER0 9. TIMER1 10. WD 11. EXT TIMER + * 12. GPIO + * + * Known resets in EyeQ6H acc (type EQR_EYEQ5_ACRP): + * 1. XNN0 2. XNN1 3. XNN2 4. XNN3 + * 5. VMP0 6. VMP1 7. VMP2 8. VMP3 + * 9. PMA0 10. PMA1 11. MPC0 12. MPC1 + * 13. MPC2 14. MPC3 15. PERIPH + * + * Abbreviations: + * - PMA: Programmable Macro Array + * - MPC: Multi-threaded Processing Clusters + * - VMP: Vector Microcode Processors + * + * Copyright (C) 2024 Mobileye Vision Technologies Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * A reset ID, as returned by eqr_of_xlate_*(), is a (domain, offset) pair. + * Low byte is domain, rest is offset. + */ +#define ID_DOMAIN_MASK GENMASK(7, 0) +#define ID_OFFSET_MASK GENMASK(31, 8) + +enum eqr_domain_type { + EQR_EYEQ5_SARCR, + EQR_EYEQ5_ACRP, + EQR_EYEQ5_PCIE, + EQR_EYEQ6H_SARCR, +}; + +/* + * Domain type EQR_EYEQ5_SARCR register offsets. + */ +#define EQR_EYEQ5_SARCR_REQUEST (0x000) +#define EQR_EYEQ5_SARCR_STATUS (0x004) + +/* + * Domain type EQR_EYEQ5_ACRP register masks. + * Registers are: base + 4 * offset. + */ +#define EQR_EYEQ5_ACRP_PD_REQ BIT(0) +#define EQR_EYEQ5_ACRP_ST_POWER_DOWN BIT(27) +#define EQR_EYEQ5_ACRP_ST_ACTIVE BIT(29) + +/* + * Domain type EQR_EYEQ6H_SARCR register offsets. + */ +#define EQR_EYEQ6H_SARCR_RST_REQUEST (0x000) +#define EQR_EYEQ6H_SARCR_CLK_STATUS (0x004) +#define EQR_EYEQ6H_SARCR_RST_STATUS (0x008) +#define EQR_EYEQ6H_SARCR_CLK_REQUEST (0x00C) + +struct eqr_busy_wait_timings { + unsigned long sleep_us; + unsigned long timeout_us; +}; + +static const struct eqr_busy_wait_timings eqr_timings[] = { + [EQR_EYEQ5_SARCR] = {1, 10}, + [EQR_EYEQ5_ACRP] = {1, 40 * USEC_PER_MSEC}, /* LBIST implies long timeout. */ + /* EQR_EYEQ5_PCIE does no busy waiting. */ + [EQR_EYEQ6H_SARCR] = {1, 400}, +}; + +#define EQR_MAX_DOMAIN_COUNT 3 + +struct eqr_domain_descriptor { + enum eqr_domain_type type; + u32 valid_mask; + unsigned int offset; +}; + +struct eqr_match_data { + unsigned int domain_count; + const struct eqr_domain_descriptor *domains; +}; + +struct eqr_private { + /* + * One mutex per domain for read-modify-write operations on registers. + * Some domains can be involved in LBIST which implies long critical + * sections; we wouldn't want other domains to be impacted by that. + */ + struct mutex mutexes[EQR_MAX_DOMAIN_COUNT]; + void __iomem *base; + const struct eqr_match_data *data; + struct reset_controller_dev rcdev; +}; + +static inline struct eqr_private *eqr_rcdev_to_priv(struct reset_controller_dev *x) +{ + return container_of(x, struct eqr_private, rcdev); +} + +static u32 eqr_double_readl(void __iomem *addr_a, void __iomem *addr_b, + u32 *dest_a, u32 *dest_b) +{ + *dest_a = readl(addr_a); + *dest_b = readl(addr_b); + return 0; /* read_poll_timeout() op argument must return something. */ +} + +static int eqr_busy_wait_locked(struct eqr_private *priv, struct device *dev, + u32 domain, u32 offset, bool assert) +{ + void __iomem *base = priv->base + priv->data->domains[domain].offset; + enum eqr_domain_type domain_type = priv->data->domains[domain].type; + unsigned long timeout_us = eqr_timings[domain_type].timeout_us; + unsigned long sleep_us = eqr_timings[domain_type].sleep_us; + u32 val, mask, rst_status, clk_status; + void __iomem *reg; + int ret; + + lockdep_assert_held(&priv->mutexes[domain]); + + switch (domain_type) { + case EQR_EYEQ5_SARCR: + reg = base + EQR_EYEQ5_SARCR_STATUS; + mask = BIT(offset); + + ret = readl_poll_timeout(reg, val, !(val & mask) == assert, + sleep_us, timeout_us); + break; + + case EQR_EYEQ5_ACRP: + reg = base + 4 * offset; + if (assert) + mask = EQR_EYEQ5_ACRP_ST_POWER_DOWN; + else + mask = EQR_EYEQ5_ACRP_ST_ACTIVE; + + ret = readl_poll_timeout(reg, val, !!(val & mask), + sleep_us, timeout_us); + break; + + case EQR_EYEQ5_PCIE: + ret = 0; /* No busy waiting. */ + break; + + case EQR_EYEQ6H_SARCR: + /* + * Wait until both bits change: + * readl(base + EQR_EYEQ6H_SARCR_RST_STATUS) & BIT(offset) + * readl(base + EQR_EYEQ6H_SARCR_CLK_STATUS) & BIT(offset) + */ + mask = BIT(offset); + ret = read_poll_timeout(eqr_double_readl, val, + (!(rst_status & mask) == assert) && + (!(clk_status & mask) == assert), + sleep_us, timeout_us, false, + base + EQR_EYEQ6H_SARCR_RST_STATUS, + base + EQR_EYEQ6H_SARCR_CLK_STATUS, + &rst_status, &clk_status); + break; + + default: + WARN_ON(1); + ret = -EINVAL; + break; + } + + if (ret == -ETIMEDOUT) + dev_dbg(dev, "%u-%u: timeout\n", domain, offset); + return ret; +} + +static void eqr_assert_locked(struct eqr_private *priv, u32 domain, u32 offset) +{ + enum eqr_domain_type domain_type = priv->data->domains[domain].type; + void __iomem *base, *reg; + u32 val; + + lockdep_assert_held(&priv->mutexes[domain]); + + base = priv->base + priv->data->domains[domain].offset; + + switch (domain_type) { + case EQR_EYEQ5_SARCR: + reg = base + EQR_EYEQ5_SARCR_REQUEST; + writel(readl(reg) & ~BIT(offset), reg); + break; + + case EQR_EYEQ5_ACRP: + reg = base + 4 * offset; + writel(readl(reg) | EQR_EYEQ5_ACRP_PD_REQ, reg); + break; + + case EQR_EYEQ5_PCIE: + writel(readl(base) & ~BIT(offset), base); + break; + + case EQR_EYEQ6H_SARCR: + /* RST_REQUEST and CLK_REQUEST must be kept in sync. */ + val = readl(base + EQR_EYEQ6H_SARCR_RST_REQUEST); + val &= ~BIT(offset); + writel(val, base + EQR_EYEQ6H_SARCR_RST_REQUEST); + writel(val, base + EQR_EYEQ6H_SARCR_CLK_REQUEST); + break; + + default: + WARN_ON(1); + break; + } +} + +static int eqr_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct eqr_private *priv = eqr_rcdev_to_priv(rcdev); + u32 domain = FIELD_GET(ID_DOMAIN_MASK, id); + u32 offset = FIELD_GET(ID_OFFSET_MASK, id); + + dev_dbg(rcdev->dev, "%u-%u: assert request\n", domain, offset); + + guard(mutex)(&priv->mutexes[domain]); + + eqr_assert_locked(priv, domain, offset); + return eqr_busy_wait_locked(priv, rcdev->dev, domain, offset, true); +} + +static void eqr_deassert_locked(struct eqr_private *priv, u32 domain, + u32 offset) +{ + enum eqr_domain_type domain_type = priv->data->domains[domain].type; + void __iomem *base, *reg; + u32 val; + + lockdep_assert_held(&priv->mutexes[domain]); + + base = priv->base + priv->data->domains[domain].offset; + + switch (domain_type) { + case EQR_EYEQ5_SARCR: + reg = base + EQR_EYEQ5_SARCR_REQUEST; + writel(readl(reg) | BIT(offset), reg); + break; + + case EQR_EYEQ5_ACRP: + reg = base + 4 * offset; + writel(readl(reg) & ~EQR_EYEQ5_ACRP_PD_REQ, reg); + break; + + case EQR_EYEQ5_PCIE: + writel(readl(base) | BIT(offset), base); + break; + + case EQR_EYEQ6H_SARCR: + /* RST_REQUEST and CLK_REQUEST must be kept in sync. */ + val = readl(base + EQR_EYEQ6H_SARCR_RST_REQUEST); + val |= BIT(offset); + writel(val, base + EQR_EYEQ6H_SARCR_RST_REQUEST); + writel(val, base + EQR_EYEQ6H_SARCR_CLK_REQUEST); + break; + + default: + WARN_ON(1); + break; + } +} + +static int eqr_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct eqr_private *priv = eqr_rcdev_to_priv(rcdev); + u32 domain = FIELD_GET(ID_DOMAIN_MASK, id); + u32 offset = FIELD_GET(ID_OFFSET_MASK, id); + + dev_dbg(rcdev->dev, "%u-%u: deassert request\n", domain, offset); + + guard(mutex)(&priv->mutexes[domain]); + + eqr_deassert_locked(priv, domain, offset); + return eqr_busy_wait_locked(priv, rcdev->dev, domain, offset, false); +} + +static int eqr_status(struct reset_controller_dev *rcdev, unsigned long id) +{ + u32 domain = FIELD_GET(ID_DOMAIN_MASK, id); + u32 offset = FIELD_GET(ID_OFFSET_MASK, id); + struct eqr_private *priv = eqr_rcdev_to_priv(rcdev); + enum eqr_domain_type domain_type = priv->data->domains[domain].type; + void __iomem *base, *reg; + + dev_dbg(rcdev->dev, "%u-%u: status request\n", domain, offset); + + guard(mutex)(&priv->mutexes[domain]); + + base = priv->base + priv->data->domains[domain].offset; + + switch (domain_type) { + case EQR_EYEQ5_SARCR: + reg = base + EQR_EYEQ5_SARCR_STATUS; + return !(readl(reg) & BIT(offset)); + case EQR_EYEQ5_ACRP: + reg = base + 4 * offset; + return !(readl(reg) & EQR_EYEQ5_ACRP_ST_ACTIVE); + case EQR_EYEQ5_PCIE: + return !(readl(base) & BIT(offset)); + case EQR_EYEQ6H_SARCR: + reg = base + EQR_EYEQ6H_SARCR_RST_STATUS; + return !(readl(reg) & BIT(offset)); + default: + return -EINVAL; + } +} + +static const struct reset_control_ops eqr_ops = { + .assert = eqr_assert, + .deassert = eqr_deassert, + .status = eqr_status, +}; + +static int eqr_of_xlate_internal(struct reset_controller_dev *rcdev, + u32 domain, u32 offset) +{ + struct eqr_private *priv = eqr_rcdev_to_priv(rcdev); + + if (domain >= priv->data->domain_count || offset > 31 || + !(priv->data->domains[domain].valid_mask & BIT(offset))) { + dev_err(rcdev->dev, "%u-%u: invalid reset\n", domain, offset); + return -EINVAL; + } + + return FIELD_PREP(ID_DOMAIN_MASK, domain) | FIELD_PREP(ID_OFFSET_MASK, offset); +} + +static int eqr_of_xlate_onecell(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + return eqr_of_xlate_internal(rcdev, 0, reset_spec->args[0]); +} + +static int eqr_of_xlate_twocells(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + return eqr_of_xlate_internal(rcdev, reset_spec->args[0], reset_spec->args[1]); +} + +static int eqr_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + const struct of_device_id *match; + struct device *dev = &adev->dev; + struct eqr_private *priv; + unsigned int i; + int ret; + + /* + * We are an auxiliary device of clk-eyeq. We do not have an OF node by + * default; let's reuse our parent's OF node. + */ + WARN_ON(dev->of_node); + device_set_of_node_from_dev(dev, dev->parent); + if (!dev->of_node) + return -ENODEV; + + /* + * Using our newfound OF node, we can get match data. We cannot use + * device_get_match_data() because it does not match reused OF nodes. + */ + match = of_match_node(dev->driver->of_match_table, dev->of_node); + if (!match || !match->data) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = match->data; + priv->base = (void __iomem *)dev_get_platdata(dev); + priv->rcdev.ops = &eqr_ops; + priv->rcdev.owner = THIS_MODULE; + priv->rcdev.dev = dev; + priv->rcdev.of_node = dev->of_node; + + if (priv->data->domain_count == 1) { + priv->rcdev.of_reset_n_cells = 1; + priv->rcdev.of_xlate = eqr_of_xlate_onecell; + } else { + priv->rcdev.of_reset_n_cells = 2; + priv->rcdev.of_xlate = eqr_of_xlate_twocells; + } + + for (i = 0; i < priv->data->domain_count; i++) + mutex_init(&priv->mutexes[i]); + + priv->rcdev.nr_resets = 0; + for (i = 0; i < priv->data->domain_count; i++) + priv->rcdev.nr_resets += hweight32(priv->data->domains[i].valid_mask); + + ret = devm_reset_controller_register(dev, &priv->rcdev); + if (ret) + return dev_err_probe(dev, ret, "failed registering reset controller\n"); + + return 0; +} + +static const struct eqr_domain_descriptor eqr_eyeq5_domains[] = { + { + .type = EQR_EYEQ5_SARCR, + .valid_mask = 0xFFFFFF8, + .offset = 0x004, + }, + { + .type = EQR_EYEQ5_ACRP, + .valid_mask = 0x0001FFF, + .offset = 0x200, + }, + { + .type = EQR_EYEQ5_PCIE, + .valid_mask = 0x007BFFF, + .offset = 0x120, + }, +}; + +static const struct eqr_match_data eqr_eyeq5_data = { + .domain_count = ARRAY_SIZE(eqr_eyeq5_domains), + .domains = eqr_eyeq5_domains, +}; + +static const struct eqr_domain_descriptor eqr_eyeq6l_domains[] = { + { + .type = EQR_EYEQ5_SARCR, + .valid_mask = 0x3FFF, + .offset = 0x004, + }, + { + .type = EQR_EYEQ5_ACRP, + .valid_mask = 0x00FF, + .offset = 0x200, + }, +}; + +static const struct eqr_match_data eqr_eyeq6l_data = { + .domain_count = ARRAY_SIZE(eqr_eyeq6l_domains), + .domains = eqr_eyeq6l_domains, +}; + +/* West and east OLBs each have an instance. */ +static const struct eqr_domain_descriptor eqr_eyeq6h_we_domains[] = { + { + .type = EQR_EYEQ6H_SARCR, + .valid_mask = 0x1F7F, + .offset = 0x004, + }, +}; + +static const struct eqr_match_data eqr_eyeq6h_we_data = { + .domain_count = ARRAY_SIZE(eqr_eyeq6h_we_domains), + .domains = eqr_eyeq6h_we_domains, +}; + +static const struct eqr_domain_descriptor eqr_eyeq6h_acc_domains[] = { + { + .type = EQR_EYEQ5_ACRP, + .valid_mask = 0x7FFF, + .offset = 0x000, + }, +}; + +static const struct eqr_match_data eqr_eyeq6h_acc_data = { + .domain_count = ARRAY_SIZE(eqr_eyeq6h_acc_domains), + .domains = eqr_eyeq6h_acc_domains, +}; + +/* + * Table describes OLB system-controller compatibles. + * It does not get used to match against devicetree node. + */ +static const struct of_device_id eqr_match_table[] = { + { .compatible = "mobileye,eyeq5-olb", .data = &eqr_eyeq5_data }, + { .compatible = "mobileye,eyeq6l-olb", .data = &eqr_eyeq6l_data }, + { .compatible = "mobileye,eyeq6h-west-olb", .data = &eqr_eyeq6h_we_data }, + { .compatible = "mobileye,eyeq6h-east-olb", .data = &eqr_eyeq6h_we_data }, + { .compatible = "mobileye,eyeq6h-acc-olb", .data = &eqr_eyeq6h_acc_data }, + {} +}; +MODULE_DEVICE_TABLE(of, eqr_match_table); + +static const struct auxiliary_device_id eqr_id_table[] = { + { .name = "clk_eyeq.reset" }, + { .name = "clk_eyeq.reset_west" }, + { .name = "clk_eyeq.reset_east" }, + { .name = "clk_eyeq.reset_acc" }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, eqr_id_table); + +static struct auxiliary_driver eqr_driver = { + .probe = eqr_probe, + .id_table = eqr_id_table, + .driver = { + .of_match_table = eqr_match_table, + } +}; +module_auxiliary_driver(eqr_driver); From c3cc3e69b33fee3d276895e0e2d1a8fb37ea5d0e Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:54 +0200 Subject: [PATCH 169/212] soc: fsl: cpm1: qmc: Update TRNSYNC only in transparent mode The TRNSYNC feature is available (and enabled) only in transparent mode. Since commit 7cc9bda9c163 ("soc: fsl: cpm1: qmc: Handle timeslot entries at channel start() and stop()") TRNSYNC register is updated in transparent and hdlc mode. In hdlc mode, the address of the TRNSYNC register is used by the QMC for other internal purpose. Even if no weird results were observed in hdlc mode, touching this register in this mode is wrong. Update TRNSYNC only in transparent mode. Fixes: 7cc9bda9c163 ("soc: fsl: cpm1: qmc: Handle timeslot entries at channel start() and stop()") Cc: stable@vger.kernel.org Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-2-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 76bb496305a0..bacabf731dcb 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -940,11 +940,13 @@ static int qmc_chan_start_rx(struct qmc_chan *chan) goto end; } - ret = qmc_setup_chan_trnsync(chan->qmc, chan); - if (ret) { - dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n", - chan->id, ret); - goto end; + if (chan->mode == QMC_TRANSPARENT) { + ret = qmc_setup_chan_trnsync(chan->qmc, chan); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n", + chan->id, ret); + goto end; + } } /* Restart the receiver */ @@ -982,11 +984,13 @@ static int qmc_chan_start_tx(struct qmc_chan *chan) goto end; } - ret = qmc_setup_chan_trnsync(chan->qmc, chan); - if (ret) { - dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n", - chan->id, ret); - goto end; + if (chan->mode == QMC_TRANSPARENT) { + ret = qmc_setup_chan_trnsync(chan->qmc, chan); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n", + chan->id, ret); + goto end; + } } /* From d285cf22f8c0347fc3df80e84f31e9179de4e6c6 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:55 +0200 Subject: [PATCH 170/212] soc: fsl: cpm1: qmc: Enable TRNSYNC only when needed The TRNSYNC feature is enabled whatever the number of time-slots used. The feature is needed only when more than one time-slot is used. Improve the driver enabling TRNSYNC only when it is needed. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-3-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index bacabf731dcb..916395745850 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -889,6 +889,7 @@ EXPORT_SYMBOL(qmc_chan_stop); static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan) { struct tsa_serial_info info; + unsigned int w_rx, w_tx; u16 first_rx, last_tx; u16 trnsync; int ret; @@ -898,6 +899,14 @@ static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan) if (ret) return ret; + w_rx = hweight64(chan->rx_ts_mask); + w_tx = hweight64(chan->tx_ts_mask); + if (w_rx <= 1 && w_tx <= 1) { + dev_dbg(qmc->dev, "only one or zero ts -> disable trnsync\n"); + qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_TRANSP_SYNC); + return 0; + } + /* Find the first Rx TS allocated to the channel */ first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0; @@ -911,6 +920,7 @@ static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan) trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2); qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync); + qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_TRANSP_SYNC); dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n", chan->id, trnsync, @@ -1378,7 +1388,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) if (chan->mode == QMC_TRANSPARENT) { qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60); - val = QMC_SPE_CHAMR_MODE_TRANSP | QMC_SPE_CHAMR_TRANSP_SYNC; + val = QMC_SPE_CHAMR_MODE_TRANSP; if (chan->is_reverse_data) val |= QMC_SPE_CHAMR_TRANSP_RD; qmc_write16(chan->s_param + QMC_SPE_CHAMR, val); From 47a347bae9a491b467ab3543e4725a3e4fbe30f5 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:56 +0200 Subject: [PATCH 171/212] soc: fsl: cpm1: tsa: Fix tsa_write8() The tsa_write8() parameter is an u32 value. This is not consistent with the function itself. Indeed, tsa_write8() writes an 8bits value. Be consistent and use an u8 parameter value. Fixes: 1d4ba0b81c1c ("soc: fsl: cpm1: Add support for TSA") Cc: stable@vger.kernel.org Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-4-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 6c5741cf5e9d..53968ea84c88 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -140,7 +140,7 @@ static inline void tsa_write32(void __iomem *addr, u32 val) iowrite32be(val, addr); } -static inline void tsa_write8(void __iomem *addr, u32 val) +static inline void tsa_write8(void __iomem *addr, u8 val) { iowrite8(val, addr); } From 37dbcd596f9056c5bc6f196873599dca01bc3774 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:57 +0200 Subject: [PATCH 172/212] soc: fsl: cpm1: tsa: Use BIT(), GENMASK() and FIELD_PREP() macros checkpatch.pl signals the following improvement for tsa.c CHECK: Prefer using the BIT macro Follow its suggestion and convert the code to BIT() and related macros. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-5-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 127 +++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 59 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 53968ea84c88..dc4dda17dab8 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -9,6 +9,7 @@ #include "tsa.h" #include +#include #include #include #include @@ -19,47 +20,52 @@ /* TSA SI RAM routing tables entry */ -#define TSA_SIRAM_ENTRY_LAST (1 << 16) -#define TSA_SIRAM_ENTRY_BYTE (1 << 17) -#define TSA_SIRAM_ENTRY_CNT(x) (((x) & 0x0f) << 18) -#define TSA_SIRAM_ENTRY_CSEL_MASK (0x7 << 22) -#define TSA_SIRAM_ENTRY_CSEL_NU (0x0 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SCC2 (0x2 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SCC3 (0x3 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SCC4 (0x4 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SMC1 (0x5 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SMC2 (0x6 << 22) +#define TSA_SIRAM_ENTRY_LAST BIT(16) +#define TSA_SIRAM_ENTRY_BYTE BIT(17) +#define TSA_SIRAM_ENTRY_CNT_MASK GENMASK(21, 18) +#define TSA_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_SIRAM_ENTRY_CNT_MASK, x) +#define TSA_SIRAM_ENTRY_CSEL_MASK GENMASK(24, 22) +#define TSA_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x0) +#define TSA_SIRAM_ENTRY_CSEL_SCC2 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x2) +#define TSA_SIRAM_ENTRY_CSEL_SCC3 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x3) +#define TSA_SIRAM_ENTRY_CSEL_SCC4 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x4) +#define TSA_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x5) +#define TSA_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x6) /* SI mode register (32 bits) */ #define TSA_SIMODE 0x00 -#define TSA_SIMODE_SMC2 0x80000000 -#define TSA_SIMODE_SMC1 0x00008000 -#define TSA_SIMODE_TDMA(x) ((x) << 0) -#define TSA_SIMODE_TDMB(x) ((x) << 16) -#define TSA_SIMODE_TDM_MASK 0x0fff -#define TSA_SIMODE_TDM_SDM_MASK 0x0c00 -#define TSA_SIMODE_TDM_SDM_NORM 0x0000 -#define TSA_SIMODE_TDM_SDM_ECHO 0x0400 -#define TSA_SIMODE_TDM_SDM_INTL_LOOP 0x0800 -#define TSA_SIMODE_TDM_SDM_LOOP_CTRL 0x0c00 -#define TSA_SIMODE_TDM_RFSD(x) ((x) << 8) -#define TSA_SIMODE_TDM_DSC 0x0080 -#define TSA_SIMODE_TDM_CRT 0x0040 -#define TSA_SIMODE_TDM_STZ 0x0020 -#define TSA_SIMODE_TDM_CE 0x0010 -#define TSA_SIMODE_TDM_FE 0x0008 -#define TSA_SIMODE_TDM_GM 0x0004 -#define TSA_SIMODE_TDM_TFSD(x) ((x) << 0) +#define TSA_SIMODE_SMC2 BIT(31) +#define TSA_SIMODE_SMC1 BIT(15) +#define TSA_SIMODE_TDMA_MASK GENMASK(11, 0) +#define TSA_SIMODE_TDMA(x) FIELD_PREP(TSA_SIMODE_TDMA_MASK, x) +#define TSA_SIMODE_TDMB_MASK GENMASK(27, 16) +#define TSA_SIMODE_TDMB(x) FIELD_PREP(TSA_SIMODE_TDMB_MASK, x) +#define TSA_SIMODE_TDM_MASK GENMASK(11, 0) +#define TSA_SIMODE_TDM_SDM_MASK GENMASK(11, 10) +#define TSA_SIMODE_TDM_SDM_NORM FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x0) +#define TSA_SIMODE_TDM_SDM_ECHO FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x1) +#define TSA_SIMODE_TDM_SDM_INTL_LOOP FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x2) +#define TSA_SIMODE_TDM_SDM_LOOP_CTRL FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x3) +#define TSA_SIMODE_TDM_RFSD_MASK GENMASK(9, 8) +#define TSA_SIMODE_TDM_RFSD(x) FIELD_PREP(TSA_SIMODE_TDM_RFSD_MASK, x) +#define TSA_SIMODE_TDM_DSC BIT(7) +#define TSA_SIMODE_TDM_CRT BIT(6) +#define TSA_SIMODE_TDM_STZ BIT(5) +#define TSA_SIMODE_TDM_CE BIT(4) +#define TSA_SIMODE_TDM_FE BIT(3) +#define TSA_SIMODE_TDM_GM BIT(2) +#define TSA_SIMODE_TDM_TFSD_MASK GENMASK(1, 0) +#define TSA_SIMODE_TDM_TFSD(x) FIELD_PREP(TSA_SIMODE_TDM_TFSD_MASK, x) /* SI global mode register (8 bits) */ #define TSA_SIGMR 0x04 -#define TSA_SIGMR_ENB (1<<3) -#define TSA_SIGMR_ENA (1<<2) -#define TSA_SIGMR_RDM_MASK 0x03 -#define TSA_SIGMR_RDM_STATIC_TDMA 0x00 -#define TSA_SIGMR_RDM_DYN_TDMA 0x01 -#define TSA_SIGMR_RDM_STATIC_TDMAB 0x02 -#define TSA_SIGMR_RDM_DYN_TDMAB 0x03 +#define TSA_SIGMR_ENB BIT(3) +#define TSA_SIGMR_ENA BIT(2) +#define TSA_SIGMR_RDM_MASK GENMASK(1, 0) +#define TSA_SIGMR_RDM_STATIC_TDMA FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x0) +#define TSA_SIGMR_RDM_DYN_TDMA FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x1) +#define TSA_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x2) +#define TSA_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x3) /* SI status register (8 bits) */ #define TSA_SISTR 0x06 @@ -69,30 +75,33 @@ /* SI clock route register (32 bits) */ #define TSA_SICR 0x0C -#define TSA_SICR_SCC2(x) ((x) << 8) -#define TSA_SICR_SCC3(x) ((x) << 16) -#define TSA_SICR_SCC4(x) ((x) << 24) -#define TSA_SICR_SCC_MASK 0x0ff -#define TSA_SICR_SCC_GRX (1 << 7) -#define TSA_SICR_SCC_SCX_TSA (1 << 6) -#define TSA_SICR_SCC_RXCS_MASK (0x7 << 3) -#define TSA_SICR_SCC_RXCS_BRG1 (0x0 << 3) -#define TSA_SICR_SCC_RXCS_BRG2 (0x1 << 3) -#define TSA_SICR_SCC_RXCS_BRG3 (0x2 << 3) -#define TSA_SICR_SCC_RXCS_BRG4 (0x3 << 3) -#define TSA_SICR_SCC_RXCS_CLK15 (0x4 << 3) -#define TSA_SICR_SCC_RXCS_CLK26 (0x5 << 3) -#define TSA_SICR_SCC_RXCS_CLK37 (0x6 << 3) -#define TSA_SICR_SCC_RXCS_CLK48 (0x7 << 3) -#define TSA_SICR_SCC_TXCS_MASK (0x7 << 0) -#define TSA_SICR_SCC_TXCS_BRG1 (0x0 << 0) -#define TSA_SICR_SCC_TXCS_BRG2 (0x1 << 0) -#define TSA_SICR_SCC_TXCS_BRG3 (0x2 << 0) -#define TSA_SICR_SCC_TXCS_BRG4 (0x3 << 0) -#define TSA_SICR_SCC_TXCS_CLK15 (0x4 << 0) -#define TSA_SICR_SCC_TXCS_CLK26 (0x5 << 0) -#define TSA_SICR_SCC_TXCS_CLK37 (0x6 << 0) -#define TSA_SICR_SCC_TXCS_CLK48 (0x7 << 0) +#define TSA_SICR_SCC2_MASK GENMASK(15, 8) +#define TSA_SICR_SCC2(x) FIELD_PREP(TSA_SICR_SCC2_MASK, x) +#define TSA_SICR_SCC3_MASK GENMASK(23, 16) +#define TSA_SICR_SCC3(x) FIELD_PREP(TSA_SICR_SCC3_MASK, x) +#define TSA_SICR_SCC4_MASK GENMASK(31, 24) +#define TSA_SICR_SCC4(x) FIELD_PREP(TSA_SICR_SCC4_MASK, x) +#define TSA_SICR_SCC_MASK GENMASK(7, 0) +#define TSA_SICR_SCC_GRX BIT(7) +#define TSA_SICR_SCC_SCX_TSA BIT(6) +#define TSA_SICR_SCC_RXCS_MASK GENMASK(5, 3) +#define TSA_SICR_SCC_RXCS_BRG1 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x0) +#define TSA_SICR_SCC_RXCS_BRG2 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x1) +#define TSA_SICR_SCC_RXCS_BRG3 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x2) +#define TSA_SICR_SCC_RXCS_BRG4 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x3) +#define TSA_SICR_SCC_RXCS_CLK15 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x4) +#define TSA_SICR_SCC_RXCS_CLK26 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x5) +#define TSA_SICR_SCC_RXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x6) +#define TSA_SICR_SCC_RXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x7) +#define TSA_SICR_SCC_TXCS_MASK GENMASK(2, 0) +#define TSA_SICR_SCC_TXCS_BRG1 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x0) +#define TSA_SICR_SCC_TXCS_BRG2 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x1) +#define TSA_SICR_SCC_TXCS_BRG3 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x2) +#define TSA_SICR_SCC_TXCS_BRG4 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x3) +#define TSA_SICR_SCC_TXCS_CLK15 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x4) +#define TSA_SICR_SCC_TXCS_CLK26 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x5) +#define TSA_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x6) +#define TSA_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x7) /* Serial interface RAM pointer register (32 bits) */ #define TSA_SIRP 0x10 From bfd4f092c49fe20a802f703e79df4926b70f3564 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:58 +0200 Subject: [PATCH 173/212] soc: fsl: cpm1: tsa: Fix blank line and spaces checkpatch.pl raises the following issues CHECK: Please don't use multiple blank lines CHECK: spaces preferred around that '/' (ctx:VxV) CHECK: spaces preferred around that '+' (ctx:VxV) CHECK: spaces preferred around that '-' (ctx:VxV) Fix them. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-6-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index dc4dda17dab8..7b1032fb1572 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -18,7 +18,6 @@ #include #include - /* TSA SI RAM routing tables entry */ #define TSA_SIRAM_ENTRY_LAST BIT(16) #define TSA_SIRAM_ENTRY_BYTE BIT(17) @@ -244,8 +243,8 @@ static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area resource_size_t quarter; resource_size_t half; - quarter = tsa->si_ram_sz/4; - half = tsa->si_ram_sz/2; + quarter = tsa->si_ram_sz / 4; + half = tsa->si_ram_sz / 2; if (tdms == BIT(TSA_TDMA)) { /* Only TDMA */ @@ -408,7 +407,7 @@ static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np, } dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n", - tdm_id, route_name, ts, ts+count-1, serial_name); + tdm_id, route_name, ts, ts + count - 1, serial_name); ts += count; ret = tsa_add_entry(tsa, &area, count, serial_id); From a68757abc0d5df7142720d030276f9693e4958af Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:59 +0200 Subject: [PATCH 174/212] soc: fsl: cpm1: tsa: Add missing spinlock comment checkpatch.pl raises the following issue CHECK: spinlock_t definition without comment Add the missing comment. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-7-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 7b1032fb1572..a9d35b44489d 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -128,7 +128,7 @@ struct tsa { void __iomem *si_regs; void __iomem *si_ram; resource_size_t si_ram_sz; - spinlock_t lock; + spinlock_t lock; /* Lock for read/modify/write sequence */ int tdms; /* TSA_TDMx ORed */ struct tsa_tdm tdm[2]; /* TDMa and TDMb */ struct tsa_serial { From a0bbe77fafbc7e5eb41fbf3dc5cdb3608d8778a3 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:00 +0200 Subject: [PATCH 175/212] dt-bindings: soc: fsl: cpm_qe: Add QUICC Engine (QE) TSA controller Add support for the time slot assigner (TSA) available in some PowerQUICC SoC that uses a QUICC Engine (QE) block such as MPC8321. This QE TSA is similar to the CPM TSA except that it uses UCCs (Unified Communication Controllers) instead of SCCs (Serial Communication Controllers). Also, compared against the CPM TSA, this QE TSA can handle up to 4 TDMs instead of 2 and allows to configure the logic level of sync signals. Signed-off-by: Herve Codina Reviewed-by: Rob Herring (Arm) Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-8-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- .../bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml | 210 ++++++++++++++++++ include/dt-bindings/soc/qe-fsl,tsa.h | 13 ++ 2 files changed, 223 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml create mode 100644 include/dt-bindings/soc/qe-fsl,tsa.h diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml new file mode 100644 index 000000000000..3b50e0a003ca --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml @@ -0,0 +1,210 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qe-tsa.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PowerQUICC QE Time-slot assigner (TSA) controller + +maintainers: + - Herve Codina + +description: + The TSA is the time-slot assigner that can be found on some PowerQUICC SoC. + Its purpose is to route some TDM time-slots to other internal serial + controllers. + +properties: + compatible: + items: + - enum: + - fsl,mpc8321-tsa + - const: fsl,qe-tsa + + reg: + items: + - description: SI (Serial Interface) register base + - description: SI RAM base + + reg-names: + items: + - const: si_regs + - const: si_ram + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + '^tdm@[0-3]$': + description: + The TDM managed by this controller + type: object + + additionalProperties: false + + properties: + reg: + minimum: 0 + maximum: 3 + description: + The TDM number for this TDM, 0 for TDMa, 1 for TDMb, 2 for TDMc and 3 + for TDMd. + + fsl,common-rxtx-pins: + $ref: /schemas/types.yaml#/definitions/flag + description: + The hardware can use four dedicated pins for Tx clock, Tx sync, Rx + clock and Rx sync or use only two pins, Tx/Rx clock and Tx/Rx sync. + Without the 'fsl,common-rxtx-pins' property, the four pins are used. + With the 'fsl,common-rxtx-pins' property, two pins are used. + + clocks: + minItems: 2 + items: + - description: Receive sync clock + - description: Receive data clock + - description: Transmit sync clock + - description: Transmit data clock + + clock-names: + minItems: 2 + items: + - const: rsync + - const: rclk + - const: tsync + - const: tclk + + fsl,rx-frame-sync-delay-bits: + enum: [0, 1, 2, 3] + default: 0 + description: | + Receive frame sync delay in number of bits. + Indicates the delay between the Rx sync and the first bit of the Rx + frame. + + fsl,tx-frame-sync-delay-bits: + enum: [0, 1, 2, 3] + default: 0 + description: | + Transmit frame sync delay in number of bits. + Indicates the delay between the Tx sync and the first bit of the Tx + frame. + + fsl,clock-falling-edge: + $ref: /schemas/types.yaml#/definitions/flag + description: + Data is sent on falling edge of the clock (and received on the rising + edge). If not present, data is sent on the rising edge (and received + on the falling edge). + + fsl,fsync-rising-edge: + $ref: /schemas/types.yaml#/definitions/flag + description: + Frame sync pulses are sampled with the rising edge of the channel + clock. If not present, pulses are sampled with the falling edge. + + fsl,fsync-active-low: + $ref: /schemas/types.yaml#/definitions/flag + description: + Frame sync signals are active on low logic level. + If not present, sync signals are active on high level. + + fsl,double-speed-clock: + $ref: /schemas/types.yaml#/definitions/flag + description: + The channel clock is twice the data rate. + + patternProperties: + '^fsl,[rt]x-ts-routes$': + $ref: /schemas/types.yaml#/definitions/uint32-matrix + description: | + A list of tuple that indicates the Tx or Rx time-slots routes. + items: + items: + - description: + The number of time-slots + minimum: 1 + maximum: 64 + - description: | + The source (Tx) or destination (Rx) serial interface + (dt-bindings/soc/qe-fsl,tsa.h defines these values) + - 0: No destination + - 1: UCC1 + - 2: UCC2 + - 3: UCC3 + - 4: UCC4 + - 5: UCC5 + enum: [0, 1, 2, 3, 4, 5] + minItems: 1 + maxItems: 64 + + allOf: + # If fsl,common-rxtx-pins is present, only 2 clocks are needed. + # Else, the 4 clocks must be present. + - if: + required: + - fsl,common-rxtx-pins + then: + properties: + clocks: + maxItems: 2 + clock-names: + maxItems: 2 + else: + properties: + clocks: + minItems: 4 + clock-names: + minItems: 4 + + required: + - reg + - clocks + - clock-names + +required: + - compatible + - reg + - reg-names + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + #include + + tsa@ae0 { + compatible = "fsl,mpc8321-tsa", "fsl,qe-tsa"; + reg = <0xae0 0x10>, + <0xc00 0x200>; + reg-names = "si_regs", "si_ram"; + + #address-cells = <1>; + #size-cells = <0>; + + tdm@0 { + /* TDMa */ + reg = <0>; + + clocks = <&clk_l1rsynca>, <&clk_l1rclka>; + clock-names = "rsync", "rclk"; + + fsl,common-rxtx-pins; + fsl,fsync-rising-edge; + + fsl,tx-ts-routes = <2 0>, /* TS 0..1 */ + <24 FSL_QE_TSA_UCC4>, /* TS 2..25 */ + <1 0>, /* TS 26 */ + <5 FSL_QE_TSA_UCC3>; /* TS 27..31 */ + + fsl,rx-ts-routes = <2 0>, /* TS 0..1 */ + <24 FSL_QE_TSA_UCC4>, /* 2..25 */ + <1 0>, /* TS 26 */ + <5 FSL_QE_TSA_UCC3>; /* TS 27..31 */ + }; + }; diff --git a/include/dt-bindings/soc/qe-fsl,tsa.h b/include/dt-bindings/soc/qe-fsl,tsa.h new file mode 100644 index 000000000000..3cf3df9c0968 --- /dev/null +++ b/include/dt-bindings/soc/qe-fsl,tsa.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef __DT_BINDINGS_SOC_FSL_QE_TSA_H +#define __DT_BINDINGS_SOC_FSL_QE_TSA_H + +#define FSL_QE_TSA_NU 0 +#define FSL_QE_TSA_UCC1 1 +#define FSL_QE_TSA_UCC2 2 +#define FSL_QE_TSA_UCC3 3 +#define FSL_QE_TSA_UCC4 4 +#define FSL_QE_TSA_UCC5 5 + +#endif From 442f3799fa387ab4c0c9b2d20490d582b96532d1 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:01 +0200 Subject: [PATCH 176/212] soc: fsl: cpm1: tsa: Remove unused registers offset definition SISTR, SICMR and SIRP registers offset definitions are not used. In order to avoid unneeded code, remove them. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-9-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index a9d35b44489d..244d521d8780 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -66,12 +66,6 @@ #define TSA_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x2) #define TSA_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x3) -/* SI status register (8 bits) */ -#define TSA_SISTR 0x06 - -/* SI command register (8 bits) */ -#define TSA_SICMR 0x07 - /* SI clock route register (32 bits) */ #define TSA_SICR 0x0C #define TSA_SICR_SCC2_MASK GENMASK(15, 8) @@ -102,9 +96,6 @@ #define TSA_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x6) #define TSA_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x7) -/* Serial interface RAM pointer register (32 bits) */ -#define TSA_SIRP 0x10 - struct tsa_entries_area { void __iomem *entries_start; void __iomem *entries_next; From 58edcace87b0f5d210b171803988ff7602b2410b Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:02 +0200 Subject: [PATCH 177/212] soc: fsl: cpm1: tsa: Use ARRAY_SIZE() instead of hardcoded integer values Loops handling the tdm array use hardcoded size and the initialization part uses hardcoded indexes to initialize the array. Use ARRAY_SIZE() to avoid the hardcoded size and initialize the array using a loop. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-10-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 244d521d8780..3d0c31a62dbb 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -448,8 +448,8 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) int i; tsa->tdms = 0; - tsa->tdm[0].is_enable = false; - tsa->tdm[1].is_enable = false; + for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) + tsa->tdm[i].is_enable = false; for_each_available_child_of_node(np, tdm_np) { ret = of_property_read_u32(tdm_np, "reg", &tdm_id); @@ -609,7 +609,7 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) return 0; err: - for (i = 0; i < 2; i++) { + for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) { if (tsa->tdm[i].l1rsync_clk) { clk_disable_unprepare(tsa->tdm[i].l1rsync_clk); clk_put(tsa->tdm[i].l1rsync_clk); @@ -710,7 +710,7 @@ static void tsa_remove(struct platform_device *pdev) struct tsa *tsa = platform_get_drvdata(pdev); int i; - for (i = 0; i < 2; i++) { + for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) { if (tsa->tdm[i].l1rsync_clk) { clk_disable_unprepare(tsa->tdm[i].l1rsync_clk); clk_put(tsa->tdm[i].l1rsync_clk); From 8c8e1ba3e98c29e3bee1c7c0f19ff1ecd89f197f Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:03 +0200 Subject: [PATCH 178/212] soc: fsl: cpm1: tsa: Make SIRAM entries specific to CPM1 Current code handles the CPM1 version of TSA. Compared against QUICC Engine (QE) version of TSA, CPM1 SIRAM entries are slightly different. In order to prepare the support for the QE version, clearly identify these entries and functions handling them as CPM1 compatible. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-11-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 75 ++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 3d0c31a62dbb..bf7354ebaca4 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -18,18 +18,18 @@ #include #include -/* TSA SI RAM routing tables entry */ -#define TSA_SIRAM_ENTRY_LAST BIT(16) -#define TSA_SIRAM_ENTRY_BYTE BIT(17) -#define TSA_SIRAM_ENTRY_CNT_MASK GENMASK(21, 18) -#define TSA_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_SIRAM_ENTRY_CNT_MASK, x) -#define TSA_SIRAM_ENTRY_CSEL_MASK GENMASK(24, 22) -#define TSA_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x0) -#define TSA_SIRAM_ENTRY_CSEL_SCC2 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x2) -#define TSA_SIRAM_ENTRY_CSEL_SCC3 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x3) -#define TSA_SIRAM_ENTRY_CSEL_SCC4 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x4) -#define TSA_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x5) -#define TSA_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x6) +/* TSA SI RAM routing tables entry (CPM1) */ +#define TSA_CPM1_SIRAM_ENTRY_LAST BIT(16) +#define TSA_CPM1_SIRAM_ENTRY_BYTE BIT(17) +#define TSA_CPM1_SIRAM_ENTRY_CNT_MASK GENMASK(21, 18) +#define TSA_CPM1_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_CPM1_SIRAM_ENTRY_CNT_MASK, x) +#define TSA_CPM1_SIRAM_ENTRY_CSEL_MASK GENMASK(24, 22) +#define TSA_CPM1_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x0) +#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x2) +#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC3 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x3) +#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC4 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x4) +#define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x5) +#define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x6) /* SI mode register (32 bits) */ #define TSA_SIMODE 0x00 @@ -228,8 +228,8 @@ int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *i } EXPORT_SYMBOL(tsa_serial_get_info); -static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area, - u32 tdms, u32 tdm_id, bool is_rx) +static void tsa_cpm1_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area, + u32 tdms, u32 tdm_id, bool is_rx) { resource_size_t quarter; resource_size_t half; @@ -280,7 +280,13 @@ static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area } } -static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id) +static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area, + u32 tdms, u32 tdm_id, bool is_rx) +{ + tsa_cpm1_init_entries_area(tsa, area, tdms, tdm_id, is_rx); +} + +static const char *tsa_cpm1_serial_id2name(struct tsa *tsa, u32 serial_id) { switch (serial_id) { case FSL_CPM_TSA_NU: return "Not used"; @@ -295,22 +301,27 @@ static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id) return NULL; } -static u32 tsa_serial_id2csel(struct tsa *tsa, u32 serial_id) +static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id) +{ + return tsa_cpm1_serial_id2name(tsa, serial_id); +} + +static u32 tsa_cpm1_serial_id2csel(struct tsa *tsa, u32 serial_id) { switch (serial_id) { - case FSL_CPM_TSA_SCC2: return TSA_SIRAM_ENTRY_CSEL_SCC2; - case FSL_CPM_TSA_SCC3: return TSA_SIRAM_ENTRY_CSEL_SCC3; - case FSL_CPM_TSA_SCC4: return TSA_SIRAM_ENTRY_CSEL_SCC4; - case FSL_CPM_TSA_SMC1: return TSA_SIRAM_ENTRY_CSEL_SMC1; - case FSL_CPM_TSA_SMC2: return TSA_SIRAM_ENTRY_CSEL_SMC2; + case FSL_CPM_TSA_SCC2: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC2; + case FSL_CPM_TSA_SCC3: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC3; + case FSL_CPM_TSA_SCC4: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC4; + case FSL_CPM_TSA_SMC1: return TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1; + case FSL_CPM_TSA_SMC2: return TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2; default: break; } - return TSA_SIRAM_ENTRY_CSEL_NU; + return TSA_CPM1_SIRAM_ENTRY_CSEL_NU; } -static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, - u32 count, u32 serial_id) +static int tsa_cpm1_add_entry(struct tsa *tsa, struct tsa_entries_area *area, + u32 count, u32 serial_id) { void __iomem *addr; u32 left; @@ -328,21 +339,21 @@ static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, if (area->last_entry) { /* Clear last flag */ - tsa_clrbits32(area->last_entry, TSA_SIRAM_ENTRY_LAST); + tsa_clrbits32(area->last_entry, TSA_CPM1_SIRAM_ENTRY_LAST); } left = count; while (left) { - val = TSA_SIRAM_ENTRY_BYTE | tsa_serial_id2csel(tsa, serial_id); + val = TSA_CPM1_SIRAM_ENTRY_BYTE | tsa_cpm1_serial_id2csel(tsa, serial_id); if (left > 16) { cnt = 16; } else { cnt = left; - val |= TSA_SIRAM_ENTRY_LAST; + val |= TSA_CPM1_SIRAM_ENTRY_LAST; area->last_entry = addr; } - val |= TSA_SIRAM_ENTRY_CNT(cnt - 1); + val |= TSA_CPM1_SIRAM_ENTRY_CNT(cnt - 1); tsa_write32(addr, val); addr += 4; @@ -352,6 +363,12 @@ static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, return 0; } +static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, + u32 count, u32 serial_id) +{ + return tsa_cpm1_add_entry(tsa, area, count, serial_id); +} + static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np, u32 tdms, u32 tdm_id, bool is_rx) { @@ -636,7 +653,7 @@ static void tsa_init_si_ram(struct tsa *tsa) /* Fill all entries as the last one */ for (i = 0; i < tsa->si_ram_sz; i += 4) - tsa_write32(tsa->si_ram + i, TSA_SIRAM_ENTRY_LAST); + tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST); } static int tsa_probe(struct platform_device *pdev) From 8d600cc337adb0573f2e6622568104ef8e1d1034 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:04 +0200 Subject: [PATCH 179/212] soc: fsl: cpm1: tsa: Introduce tsa_setup() and its CPM1 compatible version Current code handles the CPM1 version of TSA. Setting up TSA consists in handling SIMODE and SIGMR registers. These registers are CPM1 specific. Setting up the QUICC Engine (QE) version of TSA is slightly different. In order to prepare the support for QE version, clearly identify these registers as CPM1 compatible and isolate their handling in a CPM1 specific function. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-12-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 93 +++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index bf7354ebaca4..239b71187e07 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -32,14 +32,14 @@ #define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x6) /* SI mode register (32 bits) */ -#define TSA_SIMODE 0x00 -#define TSA_SIMODE_SMC2 BIT(31) -#define TSA_SIMODE_SMC1 BIT(15) -#define TSA_SIMODE_TDMA_MASK GENMASK(11, 0) -#define TSA_SIMODE_TDMA(x) FIELD_PREP(TSA_SIMODE_TDMA_MASK, x) -#define TSA_SIMODE_TDMB_MASK GENMASK(27, 16) -#define TSA_SIMODE_TDMB(x) FIELD_PREP(TSA_SIMODE_TDMB_MASK, x) -#define TSA_SIMODE_TDM_MASK GENMASK(11, 0) +#define TSA_CPM1_SIMODE 0x00 +#define TSA_CPM1_SIMODE_SMC2 BIT(31) +#define TSA_CPM1_SIMODE_SMC1 BIT(15) +#define TSA_CPM1_SIMODE_TDMA_MASK GENMASK(11, 0) +#define TSA_CPM1_SIMODE_TDMA(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMA_MASK, x) +#define TSA_CPM1_SIMODE_TDMB_MASK GENMASK(27, 16) +#define TSA_CPM1_SIMODE_TDMB(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMB_MASK, x) +#define TSA_CPM1_SIMODE_TDM_MASK GENMASK(11, 0) #define TSA_SIMODE_TDM_SDM_MASK GENMASK(11, 10) #define TSA_SIMODE_TDM_SDM_NORM FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x0) #define TSA_SIMODE_TDM_SDM_ECHO FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x1) @@ -49,22 +49,22 @@ #define TSA_SIMODE_TDM_RFSD(x) FIELD_PREP(TSA_SIMODE_TDM_RFSD_MASK, x) #define TSA_SIMODE_TDM_DSC BIT(7) #define TSA_SIMODE_TDM_CRT BIT(6) -#define TSA_SIMODE_TDM_STZ BIT(5) +#define TSA_CPM1_SIMODE_TDM_STZ BIT(5) #define TSA_SIMODE_TDM_CE BIT(4) #define TSA_SIMODE_TDM_FE BIT(3) #define TSA_SIMODE_TDM_GM BIT(2) #define TSA_SIMODE_TDM_TFSD_MASK GENMASK(1, 0) #define TSA_SIMODE_TDM_TFSD(x) FIELD_PREP(TSA_SIMODE_TDM_TFSD_MASK, x) -/* SI global mode register (8 bits) */ -#define TSA_SIGMR 0x04 -#define TSA_SIGMR_ENB BIT(3) -#define TSA_SIGMR_ENA BIT(2) -#define TSA_SIGMR_RDM_MASK GENMASK(1, 0) -#define TSA_SIGMR_RDM_STATIC_TDMA FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x0) -#define TSA_SIGMR_RDM_DYN_TDMA FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x1) -#define TSA_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x2) -#define TSA_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x3) +/* CPM SI global mode register (8 bits) */ +#define TSA_CPM1_SIGMR 0x04 +#define TSA_CPM1_SIGMR_ENB BIT(3) +#define TSA_CPM1_SIGMR_ENA BIT(2) +#define TSA_CPM1_SIGMR_RDM_MASK GENMASK(1, 0) +#define TSA_CPM1_SIGMR_RDM_STATIC_TDMA FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x0) +#define TSA_CPM1_SIGMR_RDM_DYN_TDMA FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x1) +#define TSA_CPM1_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x2) +#define TSA_CPM1_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x3) /* SI clock route register (32 bits) */ #define TSA_SICR 0x0C @@ -656,13 +656,45 @@ static void tsa_init_si_ram(struct tsa *tsa) tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST); } +static int tsa_cpm1_setup(struct tsa *tsa) +{ + u32 val; + + /* Set SIMODE */ + val = 0; + if (tsa->tdm[0].is_enable) + val |= TSA_CPM1_SIMODE_TDMA(tsa->tdm[0].simode_tdm); + if (tsa->tdm[1].is_enable) + val |= TSA_CPM1_SIMODE_TDMB(tsa->tdm[1].simode_tdm); + + tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SIMODE, + TSA_CPM1_SIMODE_TDMA(TSA_CPM1_SIMODE_TDM_MASK) | + TSA_CPM1_SIMODE_TDMB(TSA_CPM1_SIMODE_TDM_MASK), + val); + + /* Set SIGMR */ + val = (tsa->tdms == BIT(TSA_TDMA)) ? + TSA_CPM1_SIGMR_RDM_STATIC_TDMA : TSA_CPM1_SIGMR_RDM_STATIC_TDMAB; + if (tsa->tdms & BIT(TSA_TDMA)) + val |= TSA_CPM1_SIGMR_ENA; + if (tsa->tdms & BIT(TSA_TDMB)) + val |= TSA_CPM1_SIGMR_ENB; + tsa_write8(tsa->si_regs + TSA_CPM1_SIGMR, val); + + return 0; +} + +static int tsa_setup(struct tsa *tsa) +{ + return tsa_cpm1_setup(tsa); +} + static int tsa_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct resource *res; struct tsa *tsa; unsigned int i; - u32 val; int ret; tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL); @@ -696,26 +728,9 @@ static int tsa_probe(struct platform_device *pdev) if (ret) return ret; - /* Set SIMODE */ - val = 0; - if (tsa->tdm[0].is_enable) - val |= TSA_SIMODE_TDMA(tsa->tdm[0].simode_tdm); - if (tsa->tdm[1].is_enable) - val |= TSA_SIMODE_TDMB(tsa->tdm[1].simode_tdm); - - tsa_clrsetbits32(tsa->si_regs + TSA_SIMODE, - TSA_SIMODE_TDMA(TSA_SIMODE_TDM_MASK) | - TSA_SIMODE_TDMB(TSA_SIMODE_TDM_MASK), - val); - - /* Set SIGMR */ - val = (tsa->tdms == BIT(TSA_TDMA)) ? - TSA_SIGMR_RDM_STATIC_TDMA : TSA_SIGMR_RDM_STATIC_TDMAB; - if (tsa->tdms & BIT(TSA_TDMA)) - val |= TSA_SIGMR_ENA; - if (tsa->tdms & BIT(TSA_TDMB)) - val |= TSA_SIGMR_ENB; - tsa_write8(tsa->si_regs + TSA_SIGMR, val); + ret = tsa_setup(tsa); + if (ret) + return ret; platform_set_drvdata(pdev, tsa); From 9c6c022d1c3ce6e343722b0b7569a00f5b75f0bc Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:05 +0200 Subject: [PATCH 180/212] soc: fsl: cpm1: tsa: Isolate specific CPM1 part from tsa_serial_{dis}connect() Current code handles the CPM1 version of TSA. Connecting and disconnecting the SCC to/from the TSA consists in handling SICR register which is CPM1 specific. The connection and disconnection operation in the QUICC Engine (QE) version are slightly different. In order to prepare the support for the QE version, clearly identify SICR register as specific to CPM1 and isolate its handling done in connect and disconnect functions. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-13-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 103 ++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 239b71187e07..48a176cece86 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -67,34 +67,34 @@ #define TSA_CPM1_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x3) /* SI clock route register (32 bits) */ -#define TSA_SICR 0x0C -#define TSA_SICR_SCC2_MASK GENMASK(15, 8) -#define TSA_SICR_SCC2(x) FIELD_PREP(TSA_SICR_SCC2_MASK, x) -#define TSA_SICR_SCC3_MASK GENMASK(23, 16) -#define TSA_SICR_SCC3(x) FIELD_PREP(TSA_SICR_SCC3_MASK, x) -#define TSA_SICR_SCC4_MASK GENMASK(31, 24) -#define TSA_SICR_SCC4(x) FIELD_PREP(TSA_SICR_SCC4_MASK, x) -#define TSA_SICR_SCC_MASK GENMASK(7, 0) -#define TSA_SICR_SCC_GRX BIT(7) -#define TSA_SICR_SCC_SCX_TSA BIT(6) -#define TSA_SICR_SCC_RXCS_MASK GENMASK(5, 3) -#define TSA_SICR_SCC_RXCS_BRG1 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x0) -#define TSA_SICR_SCC_RXCS_BRG2 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x1) -#define TSA_SICR_SCC_RXCS_BRG3 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x2) -#define TSA_SICR_SCC_RXCS_BRG4 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x3) -#define TSA_SICR_SCC_RXCS_CLK15 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x4) -#define TSA_SICR_SCC_RXCS_CLK26 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x5) -#define TSA_SICR_SCC_RXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x6) -#define TSA_SICR_SCC_RXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x7) -#define TSA_SICR_SCC_TXCS_MASK GENMASK(2, 0) -#define TSA_SICR_SCC_TXCS_BRG1 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x0) -#define TSA_SICR_SCC_TXCS_BRG2 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x1) -#define TSA_SICR_SCC_TXCS_BRG3 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x2) -#define TSA_SICR_SCC_TXCS_BRG4 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x3) -#define TSA_SICR_SCC_TXCS_CLK15 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x4) -#define TSA_SICR_SCC_TXCS_CLK26 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x5) -#define TSA_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x6) -#define TSA_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x7) +#define TSA_CPM1_SICR 0x0C +#define TSA_CPM1_SICR_SCC2_MASK GENMASK(15, 8) +#define TSA_CPM1_SICR_SCC2(x) FIELD_PREP(TSA_CPM1_SICR_SCC2_MASK, x) +#define TSA_CPM1_SICR_SCC3_MASK GENMASK(23, 16) +#define TSA_CPM1_SICR_SCC3(x) FIELD_PREP(TSA_CPM1_SICR_SCC3_MASK, x) +#define TSA_CPM1_SICR_SCC4_MASK GENMASK(31, 24) +#define TSA_CPM1_SICR_SCC4(x) FIELD_PREP(TSA_CPM1_SICR_SCC4_MASK, x) +#define TSA_CPM1_SICR_SCC_MASK GENMASK(7, 0) +#define TSA_CPM1_SICR_SCC_GRX BIT(7) +#define TSA_CPM1_SICR_SCC_SCX_TSA BIT(6) +#define TSA_CPM1_SICR_SCC_RXCS_MASK GENMASK(5, 3) +#define TSA_CPM1_SICR_SCC_RXCS_BRG1 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x0) +#define TSA_CPM1_SICR_SCC_RXCS_BRG2 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x1) +#define TSA_CPM1_SICR_SCC_RXCS_BRG3 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x2) +#define TSA_CPM1_SICR_SCC_RXCS_BRG4 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x3) +#define TSA_CPM1_SICR_SCC_RXCS_CLK15 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x4) +#define TSA_CPM1_SICR_SCC_RXCS_CLK26 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x5) +#define TSA_CPM1_SICR_SCC_RXCS_CLK37 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x6) +#define TSA_CPM1_SICR_SCC_RXCS_CLK48 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x7) +#define TSA_CPM1_SICR_SCC_TXCS_MASK GENMASK(2, 0) +#define TSA_CPM1_SICR_SCC_TXCS_BRG1 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x0) +#define TSA_CPM1_SICR_SCC_TXCS_BRG2 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x1) +#define TSA_CPM1_SICR_SCC_TXCS_BRG3 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x2) +#define TSA_CPM1_SICR_SCC_TXCS_BRG4 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x3) +#define TSA_CPM1_SICR_SCC_TXCS_CLK15 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x4) +#define TSA_CPM1_SICR_SCC_TXCS_CLK26 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x5) +#define TSA_CPM1_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x6) +#define TSA_CPM1_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x7) struct tsa_entries_area { void __iomem *entries_start; @@ -159,7 +159,7 @@ static inline void tsa_clrsetbits32(void __iomem *addr, u32 clr, u32 set) tsa_write32(addr, (tsa_read32(addr) & ~clr) | set); } -int tsa_serial_connect(struct tsa_serial *tsa_serial) +static int tsa_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect) { struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); unsigned long flags; @@ -168,16 +168,16 @@ int tsa_serial_connect(struct tsa_serial *tsa_serial) switch (tsa_serial->id) { case FSL_CPM_TSA_SCC2: - clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK); - set = TSA_SICR_SCC2(TSA_SICR_SCC_SCX_TSA); + clear = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_MASK); + set = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_SCX_TSA); break; case FSL_CPM_TSA_SCC3: - clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK); - set = TSA_SICR_SCC3(TSA_SICR_SCC_SCX_TSA); + clear = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_MASK); + set = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_SCX_TSA); break; case FSL_CPM_TSA_SCC4: - clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK); - set = TSA_SICR_SCC4(TSA_SICR_SCC_SCX_TSA); + clear = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_MASK); + set = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_SCX_TSA); break; default: dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); @@ -185,39 +185,22 @@ int tsa_serial_connect(struct tsa_serial *tsa_serial) } spin_lock_irqsave(&tsa->lock, flags); - tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, set); + tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SICR, clear, + connect ? set : 0); spin_unlock_irqrestore(&tsa->lock, flags); return 0; } + +int tsa_serial_connect(struct tsa_serial *tsa_serial) +{ + return tsa_cpm1_serial_connect(tsa_serial, true); +} EXPORT_SYMBOL(tsa_serial_connect); int tsa_serial_disconnect(struct tsa_serial *tsa_serial) { - struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); - unsigned long flags; - u32 clear; - - switch (tsa_serial->id) { - case FSL_CPM_TSA_SCC2: - clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK); - break; - case FSL_CPM_TSA_SCC3: - clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK); - break; - case FSL_CPM_TSA_SCC4: - clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK); - break; - default: - dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); - return -EINVAL; - } - - spin_lock_irqsave(&tsa->lock, flags); - tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, 0); - spin_unlock_irqrestore(&tsa->lock, flags); - - return 0; + return tsa_cpm1_serial_connect(tsa_serial, false); } EXPORT_SYMBOL(tsa_serial_disconnect); From 572312a5bb49885a6bda4652810bab0319ba89c3 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:06 +0200 Subject: [PATCH 181/212] soc: fsl: cpm1: tsa: Introduce tsa_version Current code handles CPM1 version of TSA. In order to prepare the support for the QUICC Engine (QE) version of TSA, introduce tsa_version to identify versions. This will enable the code to make the distinction between several TSA implementations. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-14-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 48a176cece86..297721a0d2b6 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -114,12 +114,17 @@ struct tsa_tdm { #define TSA_TDMA 0 #define TSA_TDMB 1 +enum tsa_version { + TSA_CPM1 = 1, /* Avoid 0 value */ +}; + struct tsa { struct device *dev; void __iomem *si_regs; void __iomem *si_ram; resource_size_t si_ram_sz; spinlock_t lock; /* Lock for read/modify/write sequence */ + enum tsa_version version; int tdms; /* TSA_TDMx ORed */ struct tsa_tdm tdm[2]; /* TDMa and TDMb */ struct tsa_serial { @@ -685,6 +690,15 @@ static int tsa_probe(struct platform_device *pdev) return -ENOMEM; tsa->dev = &pdev->dev; + tsa->version = (enum tsa_version)(uintptr_t)of_device_get_match_data(&pdev->dev); + switch (tsa->version) { + case TSA_CPM1: + dev_info(tsa->dev, "CPM1 version\n"); + break; + default: + dev_err(tsa->dev, "Unknown version (%d)\n", tsa->version); + return -EINVAL; + } for (i = 0; i < ARRAY_SIZE(tsa->serials); i++) tsa->serials[i].id = i; @@ -746,7 +760,7 @@ static void tsa_remove(struct platform_device *pdev) } static const struct of_device_id tsa_id_table[] = { - { .compatible = "fsl,cpm1-tsa" }, + { .compatible = "fsl,cpm1-tsa", .data = (void *)TSA_CPM1 }, {} /* sentinel */ }; MODULE_DEVICE_TABLE(of, tsa_id_table); From 7ac947021d9d002d207ba9c376b4fe498926ea8d Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:07 +0200 Subject: [PATCH 182/212] soc: fsl: cpm1: tsa: Add support for QUICC Engine (QE) implementation Add support for the time slot assigner (TSA) available in some PowerQUICC SoC that uses a QUICC Engine (QE) block such as MPC8321. The QE TSA is similar to the CPM1 TSA except that it uses UCCs (Unified Communication Controllers) instead of SCCs (Serial Communication Controllers). Also, compared against the CPM1 TSA, this QE TSA can handle up to 4 TDMs instead of 2 and allows to configure the logic level of sync signals. At a lower level, compared against CPM TSA implementation, some registers are slightly different even if same features are present. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-15-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/Kconfig | 9 +- drivers/soc/fsl/qe/tsa.c | 329 +++++++++++++++++++++++++++++++++++-- 2 files changed, 319 insertions(+), 19 deletions(-) diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index fa9ffbed0e92..734744874730 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -31,14 +31,15 @@ config UCC_FAST config UCC bool - default y if UCC_FAST || UCC_SLOW + default y if UCC_FAST || UCC_SLOW || (CPM_TSA && QUICC_ENGINE) config CPM_TSA - tristate "CPM TSA support" + tristate "CPM/QE TSA support" depends on OF && HAS_IOMEM - depends on CPM1 || (CPM && COMPILE_TEST) + depends on CPM1 || QUICC_ENGINE || \ + ((CPM || QUICC_ENGINE) && COMPILE_TEST) help - Freescale CPM Time Slot Assigner (TSA) + Freescale CPM/QE Time Slot Assigner (TSA) controller. This option enables support for this diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 297721a0d2b6..c540cf9144c0 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -9,6 +9,7 @@ #include "tsa.h" #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include /* TSA SI RAM routing tables entry (CPM1) */ #define TSA_CPM1_SIRAM_ENTRY_LAST BIT(16) @@ -31,14 +33,37 @@ #define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x5) #define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x6) -/* SI mode register (32 bits) */ +/* TSA SI RAM routing tables entry (QE) */ +#define TSA_QE_SIRAM_ENTRY_LAST BIT(0) +#define TSA_QE_SIRAM_ENTRY_BYTE BIT(1) +#define TSA_QE_SIRAM_ENTRY_CNT_MASK GENMASK(4, 2) +#define TSA_QE_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_QE_SIRAM_ENTRY_CNT_MASK, x) +#define TSA_QE_SIRAM_ENTRY_CSEL_MASK GENMASK(8, 5) +#define TSA_QE_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x0) +#define TSA_QE_SIRAM_ENTRY_CSEL_UCC5 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x1) +#define TSA_QE_SIRAM_ENTRY_CSEL_UCC1 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x9) +#define TSA_QE_SIRAM_ENTRY_CSEL_UCC2 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xa) +#define TSA_QE_SIRAM_ENTRY_CSEL_UCC3 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xb) +#define TSA_QE_SIRAM_ENTRY_CSEL_UCC4 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xc) + +/* + * SI mode register : + * - CPM1: 32bit register split in 2*16bit (16bit TDM) + * - QE: 4x16bit registers, one per TDM + */ #define TSA_CPM1_SIMODE 0x00 +#define TSA_QE_SIAMR 0x00 +#define TSA_QE_SIBMR 0x02 +#define TSA_QE_SICMR 0x04 +#define TSA_QE_SIDMR 0x06 #define TSA_CPM1_SIMODE_SMC2 BIT(31) #define TSA_CPM1_SIMODE_SMC1 BIT(15) #define TSA_CPM1_SIMODE_TDMA_MASK GENMASK(11, 0) #define TSA_CPM1_SIMODE_TDMA(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMA_MASK, x) #define TSA_CPM1_SIMODE_TDMB_MASK GENMASK(27, 16) #define TSA_CPM1_SIMODE_TDMB(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMB_MASK, x) +#define TSA_QE_SIMODE_TDM_SAD_MASK GENMASK(15, 12) +#define TSA_QE_SIMODE_TDM_SAD(x) FIELD_PREP(TSA_QE_SIMODE_TDM_SAD_MASK, x) #define TSA_CPM1_SIMODE_TDM_MASK GENMASK(11, 0) #define TSA_SIMODE_TDM_SDM_MASK GENMASK(11, 10) #define TSA_SIMODE_TDM_SDM_NORM FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x0) @@ -49,7 +74,8 @@ #define TSA_SIMODE_TDM_RFSD(x) FIELD_PREP(TSA_SIMODE_TDM_RFSD_MASK, x) #define TSA_SIMODE_TDM_DSC BIT(7) #define TSA_SIMODE_TDM_CRT BIT(6) -#define TSA_CPM1_SIMODE_TDM_STZ BIT(5) +#define TSA_CPM1_SIMODE_TDM_STZ BIT(5) /* bit 5: STZ in CPM1 */ +#define TSA_QE_SIMODE_TDM_SL BIT(5) /* bit 5: SL in QE */ #define TSA_SIMODE_TDM_CE BIT(4) #define TSA_SIMODE_TDM_FE BIT(3) #define TSA_SIMODE_TDM_GM BIT(2) @@ -66,6 +92,13 @@ #define TSA_CPM1_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x2) #define TSA_CPM1_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x3) +/* QE SI global mode register high (8 bits) */ +#define TSA_QE_SIGLMRH 0x08 +#define TSA_QE_SIGLMRH_END BIT(3) +#define TSA_QE_SIGLMRH_ENC BIT(2) +#define TSA_QE_SIGLMRH_ENB BIT(1) +#define TSA_QE_SIGLMRH_ENA BIT(0) + /* SI clock route register (32 bits) */ #define TSA_CPM1_SICR 0x0C #define TSA_CPM1_SICR_SCC2_MASK GENMASK(15, 8) @@ -113,9 +146,12 @@ struct tsa_tdm { #define TSA_TDMA 0 #define TSA_TDMB 1 +#define TSA_TDMC 2 /* QE implementation only */ +#define TSA_TDMD 3 /* QE implementation only */ enum tsa_version { TSA_CPM1 = 1, /* Avoid 0 value */ + TSA_QE, }; struct tsa { @@ -126,7 +162,15 @@ struct tsa { spinlock_t lock; /* Lock for read/modify/write sequence */ enum tsa_version version; int tdms; /* TSA_TDMx ORed */ +#if IS_ENABLED(CONFIG_QUICC_ENGINE) + struct tsa_tdm tdm[4]; /* TDMa, TDMb, TDMc and TDMd */ +#else struct tsa_tdm tdm[2]; /* TDMa and TDMb */ +#endif + /* Same number of serials for CPM1 and QE: + * CPM1: NU, 3 SCCs and 2 SMCs + * QE: NU and 5 UCCs + */ struct tsa_serial { unsigned int id; struct tsa_serial_info info; @@ -144,6 +188,11 @@ static inline void tsa_write32(void __iomem *addr, u32 val) iowrite32be(val, addr); } +static inline void tsa_write16(void __iomem *addr, u16 val) +{ + iowrite16be(val, addr); +} + static inline void tsa_write8(void __iomem *addr, u8 val) { iowrite8(val, addr); @@ -154,16 +203,34 @@ static inline u32 tsa_read32(void __iomem *addr) return ioread32be(addr); } +static inline u16 tsa_read16(void __iomem *addr) +{ + return ioread16be(addr); +} + static inline void tsa_clrbits32(void __iomem *addr, u32 clr) { tsa_write32(addr, tsa_read32(addr) & ~clr); } +static inline void tsa_clrbits16(void __iomem *addr, u16 clr) +{ + tsa_write16(addr, tsa_read16(addr) & ~clr); +} + static inline void tsa_clrsetbits32(void __iomem *addr, u32 clr, u32 set) { tsa_write32(addr, (tsa_read32(addr) & ~clr) | set); } +static bool tsa_is_qe(const struct tsa *tsa) +{ + if (IS_ENABLED(CONFIG_QUICC_ENGINE) && IS_ENABLED(CONFIG_CPM)) + return tsa->version == TSA_QE; + + return IS_ENABLED(CONFIG_QUICC_ENGINE); +} + static int tsa_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect) { struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); @@ -197,15 +264,62 @@ static int tsa_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect) return 0; } +static int tsa_qe_serial_connect(struct tsa_serial *tsa_serial, bool connect) +{ + struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); + unsigned long flags; + int ucc_num; + int ret; + + switch (tsa_serial->id) { + case FSL_QE_TSA_UCC1: + ucc_num = 0; + break; + case FSL_QE_TSA_UCC2: + ucc_num = 1; + break; + case FSL_QE_TSA_UCC3: + ucc_num = 2; + break; + case FSL_QE_TSA_UCC4: + ucc_num = 3; + break; + case FSL_QE_TSA_UCC5: + ucc_num = 4; + break; + default: + dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); + return -EINVAL; + } + + spin_lock_irqsave(&tsa->lock, flags); + ret = ucc_set_qe_mux_tsa(ucc_num, connect); + spin_unlock_irqrestore(&tsa->lock, flags); + if (ret) { + dev_err(tsa->dev, "Connect serial id %u to TSA failed (%d)\n", + tsa_serial->id, ret); + return ret; + } + return 0; +} + int tsa_serial_connect(struct tsa_serial *tsa_serial) { - return tsa_cpm1_serial_connect(tsa_serial, true); + struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); + + return tsa_is_qe(tsa) ? + tsa_qe_serial_connect(tsa_serial, true) : + tsa_cpm1_serial_connect(tsa_serial, true); } EXPORT_SYMBOL(tsa_serial_connect); int tsa_serial_disconnect(struct tsa_serial *tsa_serial) { - return tsa_cpm1_serial_connect(tsa_serial, false); + struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); + + return tsa_is_qe(tsa) ? + tsa_qe_serial_connect(tsa_serial, false) : + tsa_cpm1_serial_connect(tsa_serial, false); } EXPORT_SYMBOL(tsa_serial_disconnect); @@ -268,10 +382,39 @@ static void tsa_cpm1_init_entries_area(struct tsa *tsa, struct tsa_entries_area } } +static void tsa_qe_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area, + u32 tdms, u32 tdm_id, bool is_rx) +{ + resource_size_t eighth; + resource_size_t half; + + eighth = tsa->si_ram_sz / 8; + half = tsa->si_ram_sz / 2; + + /* + * One half of the SI RAM used for Tx, the other one for Rx. + * In each half, 1/4 of the area is assigned to each TDM. + */ + if (is_rx) { + /* Rx: Second half of si_ram */ + area->entries_start = tsa->si_ram + half + (eighth * tdm_id); + area->entries_next = area->entries_start + eighth; + area->last_entry = NULL; + } else { + /* Tx: First half of si_ram */ + area->entries_start = tsa->si_ram + (eighth * tdm_id); + area->entries_next = area->entries_start + eighth; + area->last_entry = NULL; + } +} + static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area, u32 tdms, u32 tdm_id, bool is_rx) { - tsa_cpm1_init_entries_area(tsa, area, tdms, tdm_id, is_rx); + if (tsa_is_qe(tsa)) + tsa_qe_init_entries_area(tsa, area, tdms, tdm_id, is_rx); + else + tsa_cpm1_init_entries_area(tsa, area, tdms, tdm_id, is_rx); } static const char *tsa_cpm1_serial_id2name(struct tsa *tsa, u32 serial_id) @@ -289,9 +432,26 @@ static const char *tsa_cpm1_serial_id2name(struct tsa *tsa, u32 serial_id) return NULL; } +static const char *tsa_qe_serial_id2name(struct tsa *tsa, u32 serial_id) +{ + switch (serial_id) { + case FSL_QE_TSA_NU: return "Not used"; + case FSL_QE_TSA_UCC1: return "UCC1"; + case FSL_QE_TSA_UCC2: return "UCC2"; + case FSL_QE_TSA_UCC3: return "UCC3"; + case FSL_QE_TSA_UCC4: return "UCC4"; + case FSL_QE_TSA_UCC5: return "UCC5"; + default: + break; + } + return NULL; +} + static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id) { - return tsa_cpm1_serial_id2name(tsa, serial_id); + return tsa_is_qe(tsa) ? + tsa_qe_serial_id2name(tsa, serial_id) : + tsa_cpm1_serial_id2name(tsa, serial_id); } static u32 tsa_cpm1_serial_id2csel(struct tsa *tsa, u32 serial_id) @@ -351,10 +511,69 @@ static int tsa_cpm1_add_entry(struct tsa *tsa, struct tsa_entries_area *area, return 0; } +static u32 tsa_qe_serial_id2csel(struct tsa *tsa, u32 serial_id) +{ + switch (serial_id) { + case FSL_QE_TSA_UCC1: return TSA_QE_SIRAM_ENTRY_CSEL_UCC1; + case FSL_QE_TSA_UCC2: return TSA_QE_SIRAM_ENTRY_CSEL_UCC2; + case FSL_QE_TSA_UCC3: return TSA_QE_SIRAM_ENTRY_CSEL_UCC3; + case FSL_QE_TSA_UCC4: return TSA_QE_SIRAM_ENTRY_CSEL_UCC4; + case FSL_QE_TSA_UCC5: return TSA_QE_SIRAM_ENTRY_CSEL_UCC5; + default: + break; + } + return TSA_QE_SIRAM_ENTRY_CSEL_NU; +} + +static int tsa_qe_add_entry(struct tsa *tsa, struct tsa_entries_area *area, + u32 count, u32 serial_id) +{ + void __iomem *addr; + u32 left; + u32 val; + u32 cnt; + u32 nb; + + addr = area->last_entry ? area->last_entry + 2 : area->entries_start; + + nb = DIV_ROUND_UP(count, 8); + if ((addr + (nb * 2)) > area->entries_next) { + dev_err(tsa->dev, "si ram area full\n"); + return -ENOSPC; + } + + if (area->last_entry) { + /* Clear last flag */ + tsa_clrbits16(area->last_entry, TSA_QE_SIRAM_ENTRY_LAST); + } + + left = count; + while (left) { + val = TSA_QE_SIRAM_ENTRY_BYTE | tsa_qe_serial_id2csel(tsa, serial_id); + + if (left > 8) { + cnt = 8; + } else { + cnt = left; + val |= TSA_QE_SIRAM_ENTRY_LAST; + area->last_entry = addr; + } + val |= TSA_QE_SIRAM_ENTRY_CNT(cnt - 1); + + tsa_write16(addr, val); + addr += 2; + left -= cnt; + } + + return 0; +} + static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, u32 count, u32 serial_id) { - return tsa_cpm1_add_entry(tsa, area, count, serial_id); + return tsa_is_qe(tsa) ? + tsa_qe_add_entry(tsa, area, count, serial_id) : + tsa_cpm1_add_entry(tsa, area, count, serial_id); } static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np, @@ -470,7 +689,18 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) case 1: tsa->tdms |= BIT(TSA_TDMB); break; + case 2: + if (!tsa_is_qe(tsa)) + goto invalid_tdm; /* Not available on CPM1 */ + tsa->tdms |= BIT(TSA_TDMC); + break; + case 3: + if (!tsa_is_qe(tsa)) + goto invalid_tdm; /* Not available on CPM1 */ + tsa->tdms |= BIT(TSA_TDMD); + break; default: +invalid_tdm: dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np, tdm_id); of_node_put(tdm_np); @@ -536,10 +766,14 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge")) tdm->simode_tdm |= TSA_SIMODE_TDM_FE; + if (tsa_is_qe(tsa) && + of_property_read_bool(tdm_np, "fsl,fsync-active-low")) + tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SL; + if (of_property_read_bool(tdm_np, "fsl,double-speed-clock")) tdm->simode_tdm |= TSA_SIMODE_TDM_DSC; - clk = of_clk_get_by_name(tdm_np, "l1rsync"); + clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rsync" : "l1rsync"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); of_node_put(tdm_np); @@ -553,7 +787,7 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) } tdm->l1rsync_clk = clk; - clk = of_clk_get_by_name(tdm_np, "l1rclk"); + clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rclk" : "l1rclk"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); of_node_put(tdm_np); @@ -568,7 +802,7 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) tdm->l1rclk_clk = clk; if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) { - clk = of_clk_get_by_name(tdm_np, "l1tsync"); + clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tsync" : "l1tsync"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); of_node_put(tdm_np); @@ -582,7 +816,7 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) } tdm->l1tsync_clk = clk; - clk = of_clk_get_by_name(tdm_np, "l1tclk"); + clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tclk" : "l1tclk"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); of_node_put(tdm_np); @@ -597,6 +831,17 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) tdm->l1tclk_clk = clk; } + if (tsa_is_qe(tsa)) { + /* + * The starting address for TSA table must be set. + * 512 entries for Tx and 512 entries for Rx are + * available for 4 TDMs. + * We assign entries equally -> 128 Rx/Tx entries per + * TDM. In other words, 4 blocks of 32 entries per TDM. + */ + tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SAD(4 * tdm_id); + } + ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id); if (ret) { of_node_put(tdm_np); @@ -640,8 +885,13 @@ static void tsa_init_si_ram(struct tsa *tsa) resource_size_t i; /* Fill all entries as the last one */ - for (i = 0; i < tsa->si_ram_sz; i += 4) - tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST); + if (tsa_is_qe(tsa)) { + for (i = 0; i < tsa->si_ram_sz; i += 2) + tsa_write16(tsa->si_ram + i, TSA_QE_SIRAM_ENTRY_LAST); + } else { + for (i = 0; i < tsa->si_ram_sz; i += 4) + tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST); + } } static int tsa_cpm1_setup(struct tsa *tsa) @@ -672,9 +922,50 @@ static int tsa_cpm1_setup(struct tsa *tsa) return 0; } +static int tsa_qe_setup(struct tsa *tsa) +{ + unsigned int sixmr; + u8 siglmrh = 0; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) { + if (!tsa->tdm[i].is_enable) + continue; + + switch (i) { + case 0: + sixmr = TSA_QE_SIAMR; + siglmrh |= TSA_QE_SIGLMRH_ENA; + break; + case 1: + sixmr = TSA_QE_SIBMR; + siglmrh |= TSA_QE_SIGLMRH_ENB; + break; + case 2: + sixmr = TSA_QE_SICMR; + siglmrh |= TSA_QE_SIGLMRH_ENC; + break; + case 3: + sixmr = TSA_QE_SIDMR; + siglmrh |= TSA_QE_SIGLMRH_END; + break; + default: + return -EINVAL; + } + + /* Set SI mode register */ + tsa_write16(tsa->si_regs + sixmr, tsa->tdm[i].simode_tdm); + } + + /* Enable TDMs */ + tsa_write8(tsa->si_regs + TSA_QE_SIGLMRH, siglmrh); + + return 0; +} + static int tsa_setup(struct tsa *tsa) { - return tsa_cpm1_setup(tsa); + return tsa_is_qe(tsa) ? tsa_qe_setup(tsa) : tsa_cpm1_setup(tsa); } static int tsa_probe(struct platform_device *pdev) @@ -695,6 +986,9 @@ static int tsa_probe(struct platform_device *pdev) case TSA_CPM1: dev_info(tsa->dev, "CPM1 version\n"); break; + case TSA_QE: + dev_info(tsa->dev, "QE version\n"); + break; default: dev_err(tsa->dev, "Unknown version (%d)\n", tsa->version); return -EINVAL; @@ -760,7 +1054,12 @@ static void tsa_remove(struct platform_device *pdev) } static const struct of_device_id tsa_id_table[] = { +#if IS_ENABLED(CONFIG_CPM1) { .compatible = "fsl,cpm1-tsa", .data = (void *)TSA_CPM1 }, +#endif +#if IS_ENABLED(CONFIG_QUICC_ENGINE) + { .compatible = "fsl,qe-tsa", .data = (void *)TSA_QE }, +#endif {} /* sentinel */ }; MODULE_DEVICE_TABLE(of, tsa_id_table); @@ -869,5 +1168,5 @@ struct tsa_serial *devm_tsa_serial_get_byphandle(struct device *dev, EXPORT_SYMBOL(devm_tsa_serial_get_byphandle); MODULE_AUTHOR("Herve Codina "); -MODULE_DESCRIPTION("CPM TSA driver"); +MODULE_DESCRIPTION("CPM/QE TSA driver"); MODULE_LICENSE("GPL"); From 2a2b83aca0839a904699fdcb3557037681239708 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:08 +0200 Subject: [PATCH 183/212] MAINTAINERS: Add QE files related to the Freescale TSA controller The Freescale TSA controller driver supports both QE and CPM1. Add the newly introduced QE files to the existing entry. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-16-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 42decde38320..1d32d38f2247 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9011,9 +9011,11 @@ M: Herve Codina L: linuxppc-dev@lists.ozlabs.org S: Maintained F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-tsa.yaml +F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml F: drivers/soc/fsl/qe/tsa.c F: drivers/soc/fsl/qe/tsa.h F: include/dt-bindings/soc/cpm1-fsl,tsa.h +F: include/dt-bindings/soc/qe-fsl,tsa.h FREESCALE QUICC ENGINE UCC ETHERNET DRIVER L: netdev@vger.kernel.org From 3825890981e615bf6a69310390490c099443c324 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:09 +0200 Subject: [PATCH 184/212] soc: fsl: cpm1: tsa: Introduce tsa_serial_get_num() TSA consumers in CPM1 implementation don't need to know about the serial device number used by the TSA component. In QUICC Engine implementation, this information is needed. Improve the TSA API with tsa_serial_get_num() in order to provide this information. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-17-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 56 ++++++++++++++++++++++++++-------------- drivers/soc/fsl/qe/tsa.h | 3 +++ 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index c540cf9144c0..f0889b3fcaf2 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -231,6 +231,39 @@ static bool tsa_is_qe(const struct tsa *tsa) return IS_ENABLED(CONFIG_QUICC_ENGINE); } +static int tsa_qe_serial_get_num(struct tsa_serial *tsa_serial) +{ + struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); + + switch (tsa_serial->id) { + case FSL_QE_TSA_UCC1: return 0; + case FSL_QE_TSA_UCC2: return 1; + case FSL_QE_TSA_UCC3: return 2; + case FSL_QE_TSA_UCC4: return 3; + case FSL_QE_TSA_UCC5: return 4; + default: + break; + } + + dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); + return -EINVAL; +} + +int tsa_serial_get_num(struct tsa_serial *tsa_serial) +{ + struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); + + /* + * There is no need to get the serial num out of the TSA driver in the + * CPM case. + * Further more, in CPM, we can have 2 types of serial SCCs and FCCs. + * What kind of numbering to use that can be global to both SCCs and + * FCCs ? + */ + return tsa_is_qe(tsa) ? tsa_qe_serial_get_num(tsa_serial) : -EOPNOTSUPP; +} +EXPORT_SYMBOL(tsa_serial_get_num); + static int tsa_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect) { struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); @@ -271,26 +304,9 @@ static int tsa_qe_serial_connect(struct tsa_serial *tsa_serial, bool connect) int ucc_num; int ret; - switch (tsa_serial->id) { - case FSL_QE_TSA_UCC1: - ucc_num = 0; - break; - case FSL_QE_TSA_UCC2: - ucc_num = 1; - break; - case FSL_QE_TSA_UCC3: - ucc_num = 2; - break; - case FSL_QE_TSA_UCC4: - ucc_num = 3; - break; - case FSL_QE_TSA_UCC5: - ucc_num = 4; - break; - default: - dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); - return -EINVAL; - } + ucc_num = tsa_qe_serial_get_num(tsa_serial); + if (ucc_num < 0) + return ucc_num; spin_lock_irqsave(&tsa->lock, flags); ret = ucc_set_qe_mux_tsa(ucc_num, connect); diff --git a/drivers/soc/fsl/qe/tsa.h b/drivers/soc/fsl/qe/tsa.h index d9df89b6da3e..da137bc0f49b 100644 --- a/drivers/soc/fsl/qe/tsa.h +++ b/drivers/soc/fsl/qe/tsa.h @@ -39,4 +39,7 @@ struct tsa_serial_info { /* Get information */ int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *info); +/* Get serial number */ +int tsa_serial_get_num(struct tsa_serial *tsa_serial); + #endif /* __SOC_FSL_TSA_H__ */ From e8344905b3415207617ac44f11adfb909cf9adb3 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:10 +0200 Subject: [PATCH 185/212] soc: fsl: cpm1: qmc: Rename QMC_TSA_MASK QMC_TSA_MASK is a bitfield. The value defined is a specific value of this bitfield and correspond to the use of 8bit resolution for the routing entry. Be accurate and rename the defined constant to reflect this point. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-18-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 916395745850..721e0770510c 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -77,7 +77,7 @@ /* TSA entry (16bit entry in TSATRX and TSATTX) */ #define QMC_TSA_VALID (1 << 15) #define QMC_TSA_WRAP (1 << 14) -#define QMC_TSA_MASK (0x303F) +#define QMC_TSA_MASK_8BIT (0x303F) #define QMC_TSA_CHANNEL(x) ((x) << 6) /* Tx buffer descriptor base address (16 bits, offset from MCBASE) */ @@ -641,7 +641,7 @@ static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_ser return -EINVAL; } - val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id); /* Check entries based on Rx stuff*/ for (i = 0; i < info->nb_rx_ts; i++) { @@ -677,7 +677,7 @@ static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_seria /* Use a Rx 32 entries table */ - val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id); /* Check entries based on Rx stuff */ for (i = 0; i < info->nb_rx_ts; i++) { @@ -713,7 +713,7 @@ static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_seria /* Use a Tx 32 entries table */ - val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id); /* Check entries based on Tx stuff */ for (i = 0; i < info->nb_tx_ts; i++) { From 44beb343d8932588eebc4e8813adb5074f383b11 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:11 +0200 Subject: [PATCH 186/212] soc: fsl: cpm1: qmc: Use BIT(), GENMASK() and FIELD_PREP() macros checkpatch.pl signals the following improvement for qmc.c CHECK: Prefer using the BIT macro Follow its suggestion and convert the code to BIT() and related macros. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-19-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 130 +++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 59 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 721e0770510c..e2ac3e59bb79 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -23,23 +24,24 @@ /* SCC general mode register high (32 bits) */ #define SCC_GSMRL 0x00 -#define SCC_GSMRL_ENR (1 << 5) -#define SCC_GSMRL_ENT (1 << 4) -#define SCC_GSMRL_MODE_QMC (0x0A << 0) +#define SCC_GSMRL_ENR BIT(5) +#define SCC_GSMRL_ENT BIT(4) +#define SCC_GSMRL_MODE_MASK GENMASK(3, 0) +#define SCC_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A) /* SCC general mode register low (32 bits) */ #define SCC_GSMRH 0x04 -#define SCC_GSMRH_CTSS (1 << 7) -#define SCC_GSMRH_CDS (1 << 8) -#define SCC_GSMRH_CTSP (1 << 9) -#define SCC_GSMRH_CDP (1 << 10) +#define SCC_GSMRH_CTSS BIT(7) +#define SCC_GSMRH_CDS BIT(8) +#define SCC_GSMRH_CTSP BIT(9) +#define SCC_GSMRH_CDP BIT(10) /* SCC event register (16 bits) */ #define SCC_SCCE 0x10 -#define SCC_SCCE_IQOV (1 << 3) -#define SCC_SCCE_GINT (1 << 2) -#define SCC_SCCE_GUN (1 << 1) -#define SCC_SCCE_GOV (1 << 0) +#define SCC_SCCE_IQOV BIT(3) +#define SCC_SCCE_GINT BIT(2) +#define SCC_SCCE_GUN BIT(1) +#define SCC_SCCE_GOV BIT(0) /* SCC mask register (16 bits) */ #define SCC_SCCM 0x14 @@ -75,25 +77,31 @@ #define QMC_GBL_C_MASK16 0xA0 /* TSA entry (16bit entry in TSATRX and TSATTX) */ -#define QMC_TSA_VALID (1 << 15) -#define QMC_TSA_WRAP (1 << 14) -#define QMC_TSA_MASK_8BIT (0x303F) -#define QMC_TSA_CHANNEL(x) ((x) << 6) +#define QMC_TSA_VALID BIT(15) +#define QMC_TSA_WRAP BIT(14) +#define QMC_TSA_MASK_MASKH GENMASK(13, 12) +#define QMC_TSA_MASK_MASKL GENMASK(5, 0) +#define QMC_TSA_MASK_8BIT (FIELD_PREP_CONST(QMC_TSA_MASK_MASKH, 0x3) | \ + FIELD_PREP_CONST(QMC_TSA_MASK_MASKL, 0x3F)) +#define QMC_TSA_CHANNEL_MASK GENMASK(11, 6) +#define QMC_TSA_CHANNEL(x) FIELD_PREP(QMC_TSA_CHANNEL_MASK, x) /* Tx buffer descriptor base address (16 bits, offset from MCBASE) */ #define QMC_SPE_TBASE 0x00 /* Channel mode register (16 bits) */ #define QMC_SPE_CHAMR 0x02 -#define QMC_SPE_CHAMR_MODE_HDLC (1 << 15) -#define QMC_SPE_CHAMR_MODE_TRANSP ((0 << 15) | (1 << 13)) -#define QMC_SPE_CHAMR_ENT (1 << 12) -#define QMC_SPE_CHAMR_POL (1 << 8) -#define QMC_SPE_CHAMR_HDLC_IDLM (1 << 13) -#define QMC_SPE_CHAMR_HDLC_CRC (1 << 7) -#define QMC_SPE_CHAMR_HDLC_NOF (0x0f << 0) -#define QMC_SPE_CHAMR_TRANSP_RD (1 << 14) -#define QMC_SPE_CHAMR_TRANSP_SYNC (1 << 10) +#define QMC_SPE_CHAMR_MODE_MASK GENMASK(15, 15) +#define QMC_SPE_CHAMR_MODE_HDLC FIELD_PREP_CONST(QMC_SPE_CHAMR_MODE_MASK, 1) +#define QMC_SPE_CHAMR_MODE_TRANSP (FIELD_PREP_CONST(QMC_SPE_CHAMR_MODE_MASK, 0) | BIT(13)) +#define QMC_SPE_CHAMR_ENT BIT(12) +#define QMC_SPE_CHAMR_POL BIT(8) +#define QMC_SPE_CHAMR_HDLC_IDLM BIT(13) +#define QMC_SPE_CHAMR_HDLC_CRC BIT(7) +#define QMC_SPE_CHAMR_HDLC_NOF_MASK GENMASK(3, 0) +#define QMC_SPE_CHAMR_HDLC_NOF(x) FIELD_PREP(QMC_SPE_CHAMR_HDLC_NOF_MASK, x) +#define QMC_SPE_CHAMR_TRANSP_RD BIT(14) +#define QMC_SPE_CHAMR_TRANSP_SYNC BIT(10) /* Tx internal state (32 bits) */ #define QMC_SPE_TSTATE 0x04 @@ -120,43 +128,47 @@ /* Transparent synchronization (16 bits) */ #define QMC_SPE_TRNSYNC 0x3C -#define QMC_SPE_TRNSYNC_RX(x) ((x) << 8) -#define QMC_SPE_TRNSYNC_TX(x) ((x) << 0) +#define QMC_SPE_TRNSYNC_RX_MASK GENMASK(15, 8) +#define QMC_SPE_TRNSYNC_RX(x) FIELD_PREP(QMC_SPE_TRNSYNC_RX_MASK, x) +#define QMC_SPE_TRNSYNC_TX_MASK GENMASK(7, 0) +#define QMC_SPE_TRNSYNC_TX(x) FIELD_PREP(QMC_SPE_TRNSYNC_TX_MASK, x) /* Interrupt related registers bits */ -#define QMC_INT_V (1 << 15) -#define QMC_INT_W (1 << 14) -#define QMC_INT_NID (1 << 13) -#define QMC_INT_IDL (1 << 12) -#define QMC_INT_GET_CHANNEL(x) (((x) & 0x0FC0) >> 6) -#define QMC_INT_MRF (1 << 5) -#define QMC_INT_UN (1 << 4) -#define QMC_INT_RXF (1 << 3) -#define QMC_INT_BSY (1 << 2) -#define QMC_INT_TXB (1 << 1) -#define QMC_INT_RXB (1 << 0) +#define QMC_INT_V BIT(15) +#define QMC_INT_W BIT(14) +#define QMC_INT_NID BIT(13) +#define QMC_INT_IDL BIT(12) +#define QMC_INT_CHANNEL_MASK GENMASK(11, 6) +#define QMC_INT_GET_CHANNEL(x) FIELD_GET(QMC_INT_CHANNEL_MASK, x) +#define QMC_INT_MRF BIT(5) +#define QMC_INT_UN BIT(4) +#define QMC_INT_RXF BIT(3) +#define QMC_INT_BSY BIT(2) +#define QMC_INT_TXB BIT(1) +#define QMC_INT_RXB BIT(0) /* BD related registers bits */ -#define QMC_BD_RX_E (1 << 15) -#define QMC_BD_RX_W (1 << 13) -#define QMC_BD_RX_I (1 << 12) -#define QMC_BD_RX_L (1 << 11) -#define QMC_BD_RX_F (1 << 10) -#define QMC_BD_RX_CM (1 << 9) -#define QMC_BD_RX_UB (1 << 7) -#define QMC_BD_RX_LG (1 << 5) -#define QMC_BD_RX_NO (1 << 4) -#define QMC_BD_RX_AB (1 << 3) -#define QMC_BD_RX_CR (1 << 2) +#define QMC_BD_RX_E BIT(15) +#define QMC_BD_RX_W BIT(13) +#define QMC_BD_RX_I BIT(12) +#define QMC_BD_RX_L BIT(11) +#define QMC_BD_RX_F BIT(10) +#define QMC_BD_RX_CM BIT(9) +#define QMC_BD_RX_UB BIT(7) +#define QMC_BD_RX_LG BIT(5) +#define QMC_BD_RX_NO BIT(4) +#define QMC_BD_RX_AB BIT(3) +#define QMC_BD_RX_CR BIT(2) -#define QMC_BD_TX_R (1 << 15) -#define QMC_BD_TX_W (1 << 13) -#define QMC_BD_TX_I (1 << 12) -#define QMC_BD_TX_L (1 << 11) -#define QMC_BD_TX_TC (1 << 10) -#define QMC_BD_TX_CM (1 << 9) -#define QMC_BD_TX_UB (1 << 7) -#define QMC_BD_TX_PAD (0x0f << 0) +#define QMC_BD_TX_R BIT(15) +#define QMC_BD_TX_W BIT(13) +#define QMC_BD_TX_I BIT(12) +#define QMC_BD_TX_L BIT(11) +#define QMC_BD_TX_TC BIT(10) +#define QMC_BD_TX_CM BIT(9) +#define QMC_BD_TX_UB BIT(7) +#define QMC_BD_TX_PAD_MASK GENMASK(3, 0) +#define QMC_BD_TX_PAD(x) FIELD_PREP(QMC_BD_TX_PAD_MASK, x) /* Numbers of BDs and interrupt items */ #define QMC_NB_TXBDS 8 @@ -662,7 +674,7 @@ static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_ser continue; qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), - ~QMC_TSA_WRAP, enable ? val : 0x0000); + (u16)~QMC_TSA_WRAP, enable ? val : 0x0000); } return 0; @@ -698,7 +710,7 @@ static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_seria continue; qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), - ~QMC_TSA_WRAP, enable ? val : 0x0000); + (u16)~QMC_TSA_WRAP, enable ? val : 0x0000); } return 0; @@ -734,7 +746,7 @@ static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_seria continue; qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), - ~QMC_TSA_WRAP, enable ? val : 0x0000); + (u16)~QMC_TSA_WRAP, enable ? val : 0x0000); } return 0; From f06ab938bcddcb3c3a0b458b03a827c701919c9e Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:12 +0200 Subject: [PATCH 187/212] soc: fsl: cpm1: qmc: Fix blank line and spaces checkpatch.pl raises the following issues CHECK: Please don't use multiple blank lines CHECK: Alignment should match open parenthesis Fix them. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-20-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index e2ac3e59bb79..44bd9b949770 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -274,7 +274,6 @@ static void qmc_setbits32(void __iomem *addr, u32 set) qmc_write32(addr, qmc_read32(addr) | set); } - int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) { struct tsa_serial_info tsa_info; @@ -1411,7 +1410,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); qmc_write16(chan->s_param + QMC_SPE_MFLR, 60); qmc_write16(chan->s_param + QMC_SPE_CHAMR, - QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM); + QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM); } /* Do not enable interrupts now. They will be enabled later */ @@ -1604,7 +1603,6 @@ static int qmc_probe(struct platform_device *pdev) if (IS_ERR(qmc->scc_regs)) return PTR_ERR(qmc->scc_regs); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram"); if (!res) return -EINVAL; @@ -1650,7 +1648,7 @@ static int qmc_probe(struct platform_device *pdev) */ qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t); qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size, - &qmc->bd_dma_addr, GFP_KERNEL); + &qmc->bd_dma_addr, GFP_KERNEL); if (!qmc->bd_table) { dev_err(qmc->dev, "Failed to allocate bd table\n"); ret = -ENOMEM; @@ -1663,7 +1661,7 @@ static int qmc_probe(struct platform_device *pdev) /* Allocate the interrupt table */ qmc->int_size = QMC_NB_INTS * sizeof(u16); qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size, - &qmc->int_dma_addr, GFP_KERNEL); + &qmc->int_dma_addr, GFP_KERNEL); if (!qmc->int_table) { dev_err(qmc->dev, "Failed to allocate interrupt table\n"); ret = -ENOMEM; @@ -1711,7 +1709,7 @@ static int qmc_probe(struct platform_device *pdev) /* Enable interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, - SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV); + SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV); ret = qmc_finalize_chans(qmc); if (ret < 0) From 1934f6aa5e30de0ff8fee64aec947c2578792acd Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:13 +0200 Subject: [PATCH 188/212] soc: fsl: cpm1: qmc: Remove unneeded parenthesis checkpatch.pl raises the following issue in several places CHECK: Unnecessary parenthesis around ... Remove them. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-21-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 44bd9b949770..04466e735302 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -359,8 +359,8 @@ int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param switch (param->mode) { case QMC_HDLC: - if ((param->hdlc.max_rx_buf_size % 4) || - (param->hdlc.max_rx_buf_size < 8)) + if (param->hdlc.max_rx_buf_size % 4 || + param->hdlc.max_rx_buf_size < 8) return -EINVAL; qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR, @@ -1152,7 +1152,7 @@ static int qmc_check_chans(struct qmc *qmc) if (ret) return ret; - if ((info.nb_tx_ts > 64) || (info.nb_rx_ts > 64)) { + if (info.nb_tx_ts > 64 || info.nb_rx_ts > 64) { dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned not supported\n"); return -EINVAL; } @@ -1161,7 +1161,7 @@ static int qmc_check_chans(struct qmc *qmc) * If more than 32 TS are assigned to this serial, one common table is * used for Tx and Rx and so masks must be equal for all channels. */ - if ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) { + if (info.nb_tx_ts > 32 || info.nb_rx_ts > 32) { if (info.nb_tx_ts != info.nb_rx_ts) { dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n"); return -EINVAL; From e49dd637e02589bd9bf096c250963fb2da9cc9d6 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:14 +0200 Subject: [PATCH 189/212] soc: fsl: cpm1: qmc: Fix 'transmiter' typo checkpatch.pl raises the following issue CHECK: 'transmiter' may be misspelled - perhaps 'transmitter'? Indeed, fix it. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-22-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 04466e735302..2d54d7400d2d 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1715,7 +1715,7 @@ static int qmc_probe(struct platform_device *pdev) if (ret < 0) goto err_disable_intr; - /* Enable transmiter and receiver */ + /* Enable transmitter and receiver */ qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT); platform_set_drvdata(pdev, qmc); @@ -1742,7 +1742,7 @@ static void qmc_remove(struct platform_device *pdev) { struct qmc *qmc = platform_get_drvdata(pdev); - /* Disable transmiter and receiver */ + /* Disable transmitter and receiver */ qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0); /* Disable interrupts */ From 211ddf7cc331191eb86e66050584bbe851bf6479 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:15 +0200 Subject: [PATCH 190/212] soc: fsl: cpm1: qmc: Add missing spinlock comment checkpatch.pl raises the following issue CHECK: spinlock_t definition without comment Add the missing comments. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-23-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 2d54d7400d2d..3736a8e4575e 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -196,7 +196,7 @@ struct qmc_chan { u64 rx_ts_mask; bool is_reverse_data; - spinlock_t tx_lock; + spinlock_t tx_lock; /* Protect Tx related data */ cbd_t __iomem *txbds; cbd_t __iomem *txbd_free; cbd_t __iomem *txbd_done; @@ -204,7 +204,7 @@ struct qmc_chan { u64 nb_tx_underrun; bool is_tx_stopped; - spinlock_t rx_lock; + spinlock_t rx_lock; /* Protect Rx related data */ cbd_t __iomem *rxbds; cbd_t __iomem *rxbd_free; cbd_t __iomem *rxbd_done; From 41725760d2cef69360d354ba6136d666cb87bda3 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:16 +0200 Subject: [PATCH 191/212] dt-bindings: soc: fsl: cpm_qe: Add QUICC Engine (QE) QMC controller Add support for the QMC (QUICC Multichannel Controller) available in some PowerQUICC SoC that uses a QUICC Engine (QE) block such as MPC8321. This QE QMC is similar to the CPM QMC except that it uses UCCs (Unified Communication Controllers) instead of SCCs (Serial Communication Controllers). Also, compared against the CPM QMC, this QE QMC does not use a fixed area for the UCC/SCC parameters area but it uses a dynamic area allocated and provided to the hardware at runtime. Last point, the QE QMC can use a firmware to have the QMC working in 'soft-qmc' mode. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-24-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- .../soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml | 197 ++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml new file mode 100644 index 000000000000..71ae64cb8a4f --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml @@ -0,0 +1,197 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PowerQUICC QE QUICC Multichannel Controller (QMC) + +maintainers: + - Herve Codina + +description: + The QMC (QUICC Multichannel Controller) emulates up to 64 channels within one + serial controller using the same TDM physical interface routed from TSA. + +properties: + compatible: + items: + - enum: + - fsl,mpc8321-ucc-qmc + - const: fsl,qe-ucc-qmc + + reg: + items: + - description: UCC (Unified communication controller) register base + - description: Dual port ram base + + reg-names: + items: + - const: ucc_regs + - const: dpram + + interrupts: + maxItems: 1 + description: UCC interrupt line in the QE interrupt controller + + fsl,tsa-serial: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to TSA node + - enum: [1, 2, 3, 4, 5] + description: | + TSA serial interface (dt-bindings/soc/qe-fsl,tsa.h defines these + values) + - 1: UCC1 + - 2: UCC2 + - 3: UCC3 + - 4: UCC4 + - 5: UCC5 + description: + Should be a phandle/number pair. The phandle to TSA node and the TSA + serial interface to use. + + fsl,soft-qmc: + $ref: /schemas/types.yaml#/definitions/string + description: + Soft QMC firmware name to load. If this property is omitted, no firmware + are used. + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + '^channel@([0-9]|[1-5][0-9]|6[0-3])$': + description: + A channel managed by this controller + type: object + additionalProperties: false + + properties: + compatible: + items: + - enum: + - fsl,mpc8321-ucc-qmc-hdlc + - const: fsl,qe-ucc-qmc-hdlc + - const: fsl,qmc-hdlc + + reg: + minimum: 0 + maximum: 63 + description: + The channel number + + fsl,operational-mode: + $ref: /schemas/types.yaml#/definitions/string + enum: [transparent, hdlc] + default: transparent + description: | + The channel operational mode + - hdlc: The channel handles HDLC frames + - transparent: The channel handles raw data without any processing + + fsl,reverse-data: + $ref: /schemas/types.yaml#/definitions/flag + description: + The bit order as seen on the channels is reversed, + transmitting/receiving the MSB of each octet first. + This flag is used only in 'transparent' mode. + + fsl,tx-ts-mask: + $ref: /schemas/types.yaml#/definitions/uint64 + description: + Channel assigned Tx time-slots within the Tx time-slots routed by the + TSA to this cell. + + fsl,rx-ts-mask: + $ref: /schemas/types.yaml#/definitions/uint64 + description: + Channel assigned Rx time-slots within the Rx time-slots routed by the + TSA to this cell. + + fsl,framer: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the framer node. The framer is in charge of an E1/T1 line + interface connected to the TDM bus. It can be used to get the E1/T1 line + status such as link up/down. + + allOf: + - if: + properties: + compatible: + not: + contains: + const: fsl,qmc-hdlc + then: + properties: + fsl,framer: false + + required: + - reg + - fsl,tx-ts-mask + - fsl,rx-ts-mask + +required: + - compatible + - reg + - reg-names + - interrupts + - fsl,tsa-serial + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + #include + + qmc@a60 { + compatible = "fsl,mpc8321-ucc-qmc", "fsl,qe-ucc-qmc"; + reg = <0x3200 0x200>, + <0x10000 0x1000>; + reg-names = "ucc_regs", "dpram"; + interrupts = <35>; + interrupt-parent = <&qeic>; + fsl,soft-qmc = "fsl_qe_ucode_qmc_8321_11.bin"; + + #address-cells = <1>; + #size-cells = <0>; + + fsl,tsa-serial = <&tsa FSL_QE_TSA_UCC4>; + + channel@16 { + /* Ch16 : First 4 even TS from all routed from TSA */ + reg = <16>; + fsl,operational-mode = "transparent"; + fsl,reverse-data; + fsl,tx-ts-mask = <0x00000000 0x000000aa>; + fsl,rx-ts-mask = <0x00000000 0x000000aa>; + }; + + channel@17 { + /* Ch17 : First 4 odd TS from all routed from TSA */ + reg = <17>; + fsl,operational-mode = "transparent"; + fsl,reverse-data; + fsl,tx-ts-mask = <0x00000000 0x00000055>; + fsl,rx-ts-mask = <0x00000000 0x00000055>; + }; + + channel@19 { + /* Ch19 : 8 TS (TS 8..15) from all routed from TSA */ + compatible = "fsl,mpc8321-ucc-qmc-hdlc", + "fsl,qe-ucc-qmc-hdlc", + "fsl,qmc-hdlc"; + reg = <19>; + fsl,operational-mode = "hdlc"; + fsl,tx-ts-mask = <0x00000000 0x0000ff00>; + fsl,rx-ts-mask = <0x00000000 0x0000ff00>; + fsl,framer = <&framer>; + }; + }; From d23ae9f1815e89a0397cea85182ca0305be0056a Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:17 +0200 Subject: [PATCH 192/212] soc: fsl: cpm1: qmc: Introduce qmc_data structure Current code handles CPM1 version of QMC. Some hardcoded values are used several times to initialize the QMC state machine. In the QUICC Engine (QE) version of QMC, these values are different. In order to prepare the support for the QE version of QMC and avoid the copy of the hardcoded values, introduce the qmc_data structure to define these version specific values. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-25-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 69 ++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 3736a8e4575e..85fc86f91806 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -215,8 +215,17 @@ struct qmc_chan { bool is_rx_stopped; }; +struct qmc_data { + u32 tstate; /* Initial TSTATE value */ + u32 rstate; /* Initial RSTATE value */ + u32 zistate; /* Initial ZISTATE value */ + u32 zdstate_hdlc; /* Initial ZDSTATE value (HDLC mode) */ + u32 zdstate_transp; /* Initial ZDSTATE value (Transparent mode) */ +}; + struct qmc { struct device *dev; + const struct qmc_data *data; struct tsa_serial *tsa_serial; void __iomem *scc_regs; void __iomem *scc_pram; @@ -543,11 +552,11 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, /* Restart receiver if needed */ if (chan->is_rx_halted && !chan->is_rx_stopped) { /* Restart receiver */ - if (chan->mode == QMC_TRANSPARENT) - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); - else - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); - qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); + qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, + chan->mode == QMC_TRANSPARENT ? + chan->qmc->data->zdstate_transp : + chan->qmc->data->zdstate_hdlc); + qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate); chan->is_rx_halted = false; } chan->rx_pending++; @@ -971,11 +980,11 @@ static int qmc_chan_start_rx(struct qmc_chan *chan) } /* Restart the receiver */ - if (chan->mode == QMC_TRANSPARENT) - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); - else - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); - qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); + qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, + chan->mode == QMC_TRANSPARENT ? + chan->qmc->data->zdstate_transp : + chan->qmc->data->zdstate_hdlc); + qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate); chan->is_rx_halted = false; chan->is_rx_stopped = false; @@ -1121,8 +1130,8 @@ static void qmc_chan_reset_tx(struct qmc_chan *chan) qmc_read16(chan->s_param + QMC_SPE_TBASE)); /* Reset TSTATE and ZISTATE to their initial value */ - qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000); - qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100); + qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate); + qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate); spin_unlock_irqrestore(&chan->tx_lock, flags); } @@ -1393,11 +1402,11 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t); qmc_write16(chan->s_param + QMC_SPE_RBASE, val); qmc_write16(chan->s_param + QMC_SPE_RBPTR, val); - qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000); - qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); - qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100); + qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate); + qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate); + qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate); if (chan->mode == QMC_TRANSPARENT) { - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); + qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_transp); qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60); val = QMC_SPE_CHAMR_MODE_TRANSP; if (chan->is_reverse_data) @@ -1407,7 +1416,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) if (ret) return ret; } else { - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); + qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_hdlc); qmc_write16(chan->s_param + QMC_SPE_MFLR, 60); qmc_write16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM); @@ -1535,11 +1544,12 @@ static void qmc_irq_gint(struct qmc *qmc) /* Restart the receiver if needed */ spin_lock_irqsave(&chan->rx_lock, flags); if (chan->rx_pending && !chan->is_rx_stopped) { - if (chan->mode == QMC_TRANSPARENT) - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); - else - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); - qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); + qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, + chan->mode == QMC_TRANSPARENT ? + chan->qmc->data->zdstate_transp : + chan->qmc->data->zdstate_hdlc); + qmc_write32(chan->s_param + QMC_SPE_RSTATE, + chan->qmc->data->rstate); chan->is_rx_halted = false; } else { chan->is_rx_halted = true; @@ -1597,6 +1607,11 @@ static int qmc_probe(struct platform_device *pdev) return -ENOMEM; qmc->dev = &pdev->dev; + qmc->data = of_device_get_match_data(&pdev->dev); + if (!qmc->data) { + dev_err(qmc->dev, "Missing match data\n"); + return -EINVAL; + } INIT_LIST_HEAD(&qmc->chan_head); qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); @@ -1752,8 +1767,16 @@ static void qmc_remove(struct platform_device *pdev) tsa_serial_disconnect(qmc->tsa_serial); } +static const struct qmc_data qmc_data_cpm1 = { + .tstate = 0x30000000, + .rstate = 0x31000000, + .zistate = 0x00000100, + .zdstate_hdlc = 0x00000080, + .zdstate_transp = 0x18000080, +}; + static const struct of_device_id qmc_id_table[] = { - { .compatible = "fsl,cpm1-scc-qmc" }, + { .compatible = "fsl,cpm1-scc-qmc", .data = &qmc_data_cpm1 }, {} /* sentinel */ }; MODULE_DEVICE_TABLE(of, qmc_id_table); From a13bf605342ea9df492b8159cadaa41862b53e15 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:18 +0200 Subject: [PATCH 193/212] soc: fsl: cpm1: qmc: Re-order probe() operations Current code handles CPM1 version of QMC. In the QUICC Engine (QE) version, some operations done at probe() need to be done in a different order. In order to prepare the support for the QE version, changed the sequence of operation done at probe(): - Retrieve the tsa_serial earlier, before initializing resources. - Group SCC initialisation and do this initialization when it is really needed in the probe() sequence. Having the QE compatible sequence in the CPM1 version does not lead to any issue and works correctly without any regressions. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-26-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 54 +++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 85fc86f91806..8dd0f8fc7b08 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1614,6 +1614,12 @@ static int qmc_probe(struct platform_device *pdev) } INIT_LIST_HEAD(&qmc->chan_head); + qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial"); + if (IS_ERR(qmc->tsa_serial)) { + return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial), + "Failed to get TSA serial\n"); + } + qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); if (IS_ERR(qmc->scc_regs)) return PTR_ERR(qmc->scc_regs); @@ -1630,33 +1636,13 @@ static int qmc_probe(struct platform_device *pdev) if (IS_ERR(qmc->dpram)) return PTR_ERR(qmc->dpram); - qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial"); - if (IS_ERR(qmc->tsa_serial)) { - return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial), - "Failed to get TSA serial\n"); - } - - /* Connect the serial (SCC) to TSA */ - ret = tsa_serial_connect(qmc->tsa_serial); - if (ret) { - dev_err(qmc->dev, "Failed to connect TSA serial\n"); - return ret; - } - /* Parse channels informationss */ ret = qmc_of_parse_chans(qmc, np); if (ret) - goto err_tsa_serial_disconnect; + return ret; nb_chans = qmc_nb_chans(qmc); - /* Init GMSR_H and GMSR_L registers */ - qmc_write32(qmc->scc_regs + SCC_GSMRH, - SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); - - /* enable QMC mode */ - qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); - /* * Allocate the buffer descriptor table * 8 rx and 8 tx descriptors per channel @@ -1666,8 +1652,7 @@ static int qmc_probe(struct platform_device *pdev) &qmc->bd_dma_addr, GFP_KERNEL); if (!qmc->bd_table) { dev_err(qmc->dev, "Failed to allocate bd table\n"); - ret = -ENOMEM; - goto err_tsa_serial_disconnect; + return -ENOMEM; } memset(qmc->bd_table, 0, qmc->bd_size); @@ -1679,8 +1664,7 @@ static int qmc_probe(struct platform_device *pdev) &qmc->int_dma_addr, GFP_KERNEL); if (!qmc->int_table) { dev_err(qmc->dev, "Failed to allocate interrupt table\n"); - ret = -ENOMEM; - goto err_tsa_serial_disconnect; + return -ENOMEM; } memset(qmc->int_table, 0, qmc->int_size); @@ -1699,18 +1683,32 @@ static int qmc_probe(struct platform_device *pdev) ret = qmc_init_tsa(qmc); if (ret) - goto err_tsa_serial_disconnect; + return ret; qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000); ret = qmc_setup_chans(qmc); if (ret) - goto err_tsa_serial_disconnect; + return ret; /* Init interrupts table */ ret = qmc_setup_ints(qmc); if (ret) - goto err_tsa_serial_disconnect; + return ret; + + /* Connect the serial (SCC) to TSA */ + ret = tsa_serial_connect(qmc->tsa_serial); + if (ret) { + dev_err(qmc->dev, "Failed to connect TSA serial\n"); + return ret; + } + + /* Init GMSR_H and GMSR_L registers */ + qmc_write32(qmc->scc_regs + SCC_GSMRH, + SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); + + /* enable QMC mode */ + qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); /* Disable and clear interrupts, set the irq handler */ qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); From 727b3ab490a5f5e74fb3f246c9fdfb339d309950 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:19 +0200 Subject: [PATCH 194/212] soc: fsl: cpm1: qmc: Introduce qmc_init_resource() and its CPM1 version Current code handles the CPM1 version of QMC. Resources initialisations (i.e. retrieving base addresses and offsets of different parts) will be slightly different in the QUICC Engine (QE) version. Indeed, in QE version, some resources need to be allocated and are no more "staticaly" defined. In order to prepare the support for QE version, introduce qmc_init_resource() to initialize those resources and isolate the CPM1 specific operations in a specific function. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-27-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 47 ++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 8dd0f8fc7b08..eacc7dd2be53 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1593,11 +1593,38 @@ static irqreturn_t qmc_irq_handler(int irq, void *priv) return IRQ_HANDLED; } +static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev) +{ + struct resource *res; + + qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); + if (IS_ERR(qmc->scc_regs)) + return PTR_ERR(qmc->scc_regs); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram"); + if (!res) + return -EINVAL; + qmc->scc_pram_offset = res->start - get_immrbase(); + qmc->scc_pram = devm_ioremap_resource(qmc->dev, res); + if (IS_ERR(qmc->scc_pram)) + return PTR_ERR(qmc->scc_pram); + + qmc->dpram = devm_platform_ioremap_resource_byname(pdev, "dpram"); + if (IS_ERR(qmc->dpram)) + return PTR_ERR(qmc->dpram); + + return 0; +} + +static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev) +{ + return qmc_cpm1_init_resources(qmc, pdev); +} + static int qmc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; unsigned int nb_chans; - struct resource *res; struct qmc *qmc; int irq; int ret; @@ -1620,21 +1647,9 @@ static int qmc_probe(struct platform_device *pdev) "Failed to get TSA serial\n"); } - qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); - if (IS_ERR(qmc->scc_regs)) - return PTR_ERR(qmc->scc_regs); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram"); - if (!res) - return -EINVAL; - qmc->scc_pram_offset = res->start - get_immrbase(); - qmc->scc_pram = devm_ioremap_resource(qmc->dev, res); - if (IS_ERR(qmc->scc_pram)) - return PTR_ERR(qmc->scc_pram); - - qmc->dpram = devm_platform_ioremap_resource_byname(pdev, "dpram"); - if (IS_ERR(qmc->dpram)) - return PTR_ERR(qmc->dpram); + ret = qmc_init_resources(qmc, pdev); + if (ret) + return ret; /* Parse channels informationss */ ret = qmc_of_parse_chans(qmc, np); From de5fdb7d14b34f7fea930f2d72cf0241ec679e72 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:20 +0200 Subject: [PATCH 195/212] soc: fsl: cpm1: qmc: Introduce qmc_{init,exit}_xcc() and their CPM1 version Current code handles the CPM1 version of QMC and initialize the QMC used SCC. The QUICC Engine (QE) version uses an UCC (Unified Communication Controllers) instead of the SCC (Serial Communication Controllers) used in the CPM1 version. These controllers serve the same purpose and are used in the same way but their inializations are slightly different. In order to prepare the support for QE version of QMC, introduce qmc_init_xcc() to initialize theses controllers (UCC in QE and SCC in CPM1) and isolate the CPM1 specific SCC initialization in a specific function. Also introduce qmc_exit_xcc() for consistency to revert operations done in qmc_init_xcc(). Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-28-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 66 +++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index eacc7dd2be53..b95227378f97 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1621,6 +1621,41 @@ static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev) return qmc_cpm1_init_resources(qmc, pdev); } +static int qmc_cpm1_init_scc(struct qmc *qmc) +{ + u32 val; + int ret; + + /* Connect the serial (SCC) to TSA */ + ret = tsa_serial_connect(qmc->tsa_serial); + if (ret) + return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n"); + + /* Init GMSR_H and GMSR_L registers */ + val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP; + qmc_write32(qmc->scc_regs + SCC_GSMRH, val); + + /* enable QMC mode */ + qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); + + /* Disable and clear interrupts */ + qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); + qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F); + + return 0; +} + +static int qmc_init_xcc(struct qmc *qmc) +{ + return qmc_cpm1_init_scc(qmc); +} + +static void qmc_exit_xcc(struct qmc *qmc) +{ + /* Disconnect the serial from TSA */ + tsa_serial_disconnect(qmc->tsa_serial); +} + static int qmc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1711,29 +1746,18 @@ static int qmc_probe(struct platform_device *pdev) if (ret) return ret; - /* Connect the serial (SCC) to TSA */ - ret = tsa_serial_connect(qmc->tsa_serial); - if (ret) { - dev_err(qmc->dev, "Failed to connect TSA serial\n"); + /* Init SCC */ + ret = qmc_init_xcc(qmc); + if (ret) return ret; - } - /* Init GMSR_H and GMSR_L registers */ - qmc_write32(qmc->scc_regs + SCC_GSMRH, - SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); - - /* enable QMC mode */ - qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); - - /* Disable and clear interrupts, set the irq handler */ - qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); - qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F); + /* Set the irq handler */ irq = platform_get_irq(pdev, 0); if (irq < 0) - goto err_tsa_serial_disconnect; + goto err_exit_xcc; ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc); if (ret < 0) - goto err_tsa_serial_disconnect; + goto err_exit_xcc; /* Enable interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, @@ -1761,8 +1785,8 @@ static int qmc_probe(struct platform_device *pdev) err_disable_intr: qmc_write16(qmc->scc_regs + SCC_SCCM, 0); -err_tsa_serial_disconnect: - tsa_serial_disconnect(qmc->tsa_serial); +err_exit_xcc: + qmc_exit_xcc(qmc); return ret; } @@ -1776,8 +1800,8 @@ static void qmc_remove(struct platform_device *pdev) /* Disable interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, 0); - /* Disconnect the serial from TSA */ - tsa_serial_disconnect(qmc->tsa_serial); + /* Exit SCC */ + qmc_exit_xcc(qmc); } static const struct qmc_data qmc_data_cpm1 = { From ef0878a5ba1cc4f5b4716991a02c6f44db48e2ca Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:21 +0200 Subject: [PATCH 196/212] soc: fsl: cpm1: qmc: Rename qmc_chan_command() Current code handles CPM1 version of QMC and qmc_chan_command() is clearly CPM1 specific. In order to prepare the support for the QUICC Engine (QE) version, rename qmc_chan_command() to reflect that point. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-29-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index b95227378f97..272da250a763 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -794,7 +794,7 @@ static int qmc_chan_setup_tsa_rx(struct qmc_chan *chan, bool enable) return qmc_chan_setup_tsa_32rx(chan, &info, enable); } -static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode) +static int qmc_chan_cpm1_command(struct qmc_chan *chan, u8 qmc_opcode) { return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E); } @@ -813,7 +813,7 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan) } /* Send STOP RECEIVE command */ - ret = qmc_chan_command(chan, 0x0); + ret = qmc_chan_cpm1_command(chan, 0x0); if (ret) { dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n", chan->id, ret); @@ -850,7 +850,7 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan) } /* Send STOP TRANSMIT command */ - ret = qmc_chan_command(chan, 0x1); + ret = qmc_chan_cpm1_command(chan, 0x1); if (ret) { dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n", chan->id, ret); From 278d799caa2e89fcb0a1b729954345eb3576b6ec Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:22 +0200 Subject: [PATCH 197/212] soc: fsl: cpm1: qmc: Handle RPACK initialization Current code handles the CPM1 version of QMC, RPACK does not need to be initialized. This is not the case in the QUICC Engine (QE) version. In preparation of the support for QE, initialize the RPACK register when the receiver is initialized and each time it is restarted. This additional RPACK initialization has no impact in the CPM1 version of QMC. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-30-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 272da250a763..63af2608c3cd 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -221,6 +221,7 @@ struct qmc_data { u32 zistate; /* Initial ZISTATE value */ u32 zdstate_hdlc; /* Initial ZDSTATE value (HDLC mode) */ u32 zdstate_transp; /* Initial ZDSTATE value (Transparent mode) */ + u32 rpack; /* Initial RPACK value */ }; struct qmc { @@ -552,6 +553,7 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, /* Restart receiver if needed */ if (chan->is_rx_halted && !chan->is_rx_stopped) { /* Restart receiver */ + qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack); qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->mode == QMC_TRANSPARENT ? chan->qmc->data->zdstate_transp : @@ -980,6 +982,7 @@ static int qmc_chan_start_rx(struct qmc_chan *chan) } /* Restart the receiver */ + qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack); qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->mode == QMC_TRANSPARENT ? chan->qmc->data->zdstate_transp : @@ -1405,6 +1408,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate); qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate); qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate); + qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack); if (chan->mode == QMC_TRANSPARENT) { qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_transp); qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60); @@ -1544,6 +1548,8 @@ static void qmc_irq_gint(struct qmc *qmc) /* Restart the receiver if needed */ spin_lock_irqsave(&chan->rx_lock, flags); if (chan->rx_pending && !chan->is_rx_stopped) { + qmc_write32(chan->s_param + QMC_SPE_RPACK, + chan->qmc->data->rpack); qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->mode == QMC_TRANSPARENT ? chan->qmc->data->zdstate_transp : @@ -1810,6 +1816,7 @@ static const struct qmc_data qmc_data_cpm1 = { .zistate = 0x00000100, .zdstate_hdlc = 0x00000080, .zdstate_transp = 0x18000080, + .rpack = 0x00000000, }; static const struct of_device_id qmc_id_table[] = { From 8f55d06b4c49a8bf1a911bce89b6ee9460b8b052 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:23 +0200 Subject: [PATCH 198/212] soc: fsl: cpm1: qmc: Rename SCC_GSMRL_MODE_QMC Current code handles CPM1 version of QMC. Even if GSMRL is specific to the CPM1 version, the exact same purpose and format register (GUMRL) is present in the QUICC Engine (QE) version of QMC. Compared to the QE version, the values defined for the mode bitfield are different and the 0x0A value defined for the QMC mode is CPM1 specific. In order to prepare the support for the QE version, rename this bitfield value to clearly identify it as CPM1 specific. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-31-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 63af2608c3cd..062477b7426e 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -27,7 +27,7 @@ #define SCC_GSMRL_ENR BIT(5) #define SCC_GSMRL_ENT BIT(4) #define SCC_GSMRL_MODE_MASK GENMASK(3, 0) -#define SCC_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A) +#define SCC_CPM1_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A) /* SCC general mode register low (32 bits) */ #define SCC_GSMRH 0x04 @@ -1642,7 +1642,7 @@ static int qmc_cpm1_init_scc(struct qmc *qmc) qmc_write32(qmc->scc_regs + SCC_GSMRH, val); /* enable QMC mode */ - qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); + qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_CPM1_GSMRL_MODE_QMC); /* Disable and clear interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); From b741b66f1cc83105fdea9ac5503c5ac106a37494 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:24 +0200 Subject: [PATCH 199/212] soc: fsl: cpm1: qmc: Introduce qmc_version Current code handles the CPM1 version of QMC. In order to prepare the support for the QUICC Engine (QE) version of QMC, introduce qmc_version to identify versions. This will enable the code to make the distinction between several QMC implementations. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-32-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 062477b7426e..8ff7eaaa4c50 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -215,7 +215,12 @@ struct qmc_chan { bool is_rx_stopped; }; +enum qmc_version { + QMC_CPM1, +}; + struct qmc_data { + enum qmc_version version; u32 tstate; /* Initial TSTATE value */ u32 rstate; /* Initial RSTATE value */ u32 zistate; /* Initial ZISTATE value */ @@ -1811,6 +1816,7 @@ static void qmc_remove(struct platform_device *pdev) } static const struct qmc_data qmc_data_cpm1 = { + .version = QMC_CPM1, .tstate = 0x30000000, .rstate = 0x31000000, .zistate = 0x00000100, From c6f39c7c165fce8fe1a41327da02dcca0a3cac25 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:25 +0200 Subject: [PATCH 200/212] soc: fsl: qe: Add resource-managed muram allocators Introduce devm_cpm_muram_alloc() and devm_cpm_muram_alloc_fixed(), the resource-managed version of cpm_muram_alloc and cpm_muram_alloc_fixed(). These resource-managed versions simplify the user avoiding the need to call cpm_muram_free(). Indeed, the allocated area returned by these functions will be automatically freed on driver detach. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-33-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qe_common.c | 80 ++++++++++++++++++++++++++++++++++ include/soc/fsl/qe/qe.h | 22 +++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/qe_common.c b/drivers/soc/fsl/qe/qe_common.c index a877347d37d3..02c29f5f86d3 100644 --- a/drivers/soc/fsl/qe/qe_common.c +++ b/drivers/soc/fsl/qe/qe_common.c @@ -13,6 +13,7 @@ * 2006 (c) MontaVista Software, Inc. * Vitaly Bordug */ +#include #include #include #include @@ -187,6 +188,49 @@ void cpm_muram_free(s32 offset) } EXPORT_SYMBOL(cpm_muram_free); +static void devm_cpm_muram_release(struct device *dev, void *res) +{ + s32 *info = res; + + cpm_muram_free(*info); +} + +/** + * devm_cpm_muram_alloc - Resource-managed cpm_muram_alloc + * @dev: Device to allocate memory for + * @size: number of bytes to allocate + * @align: requested alignment, in bytes + * + * This function returns a non-negative offset into the muram area, or + * a negative errno on failure as cpm_muram_alloc() does. + * Use cpm_muram_addr() to get the virtual address of the area. + * + * Compare against cpm_muram_alloc(), the memory allocated by this + * resource-managed version is automatically freed on driver detach and so, + * cpm_muram_free() must not be called to release the allocated memory. + */ +s32 devm_cpm_muram_alloc(struct device *dev, unsigned long size, + unsigned long align) +{ + s32 info; + s32 *dr; + + dr = devres_alloc(devm_cpm_muram_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + info = cpm_muram_alloc(size, align); + if (info >= 0) { + *dr = info; + devres_add(dev, dr); + } else { + devres_free(dr); + } + + return info; +} +EXPORT_SYMBOL(devm_cpm_muram_alloc); + /* * cpm_muram_alloc_fixed - reserve a specific region of multi-user ram * @offset: offset of allocation start address @@ -211,6 +255,42 @@ s32 cpm_muram_alloc_fixed(unsigned long offset, unsigned long size) } EXPORT_SYMBOL(cpm_muram_alloc_fixed); +/** + * devm_cpm_muram_alloc_fixed - Resource-managed cpm_muram_alloc_fixed + * @dev: Device to allocate memory for + * @offset: offset of allocation start address + * @size: number of bytes to allocate + * + * This function returns a non-negative offset into the muram area, or + * a negative errno on failure as cpm_muram_alloc_fixed() does. + * Use cpm_muram_addr() to get the virtual address of the area. + * + * Compare against cpm_muram_alloc_fixed(), the memory allocated by this + * resource-managed version is automatically freed on driver detach and so, + * cpm_muram_free() must not be called to release the allocated memory. + */ +s32 devm_cpm_muram_alloc_fixed(struct device *dev, unsigned long offset, + unsigned long size) +{ + s32 info; + s32 *dr; + + dr = devres_alloc(devm_cpm_muram_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + info = cpm_muram_alloc_fixed(offset, size); + if (info >= 0) { + *dr = info; + devres_add(dev, dr); + } else { + devres_free(dr); + } + + return info; +} +EXPORT_SYMBOL(devm_cpm_muram_alloc_fixed); + /** * cpm_muram_addr - turn a muram offset into a virtual address * @offset: muram offset to convert diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h index af793f2a0ec4..629835b6c71d 100644 --- a/include/soc/fsl/qe/qe.h +++ b/include/soc/fsl/qe/qe.h @@ -23,6 +23,8 @@ #include #include +struct device; + #define QE_NUM_OF_SNUM 256 /* There are 256 serial number in QE */ #define QE_NUM_OF_BRGS 16 #define QE_NUM_OF_PORTS 1024 @@ -93,8 +95,12 @@ int cpm_muram_init(void); #if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE) s32 cpm_muram_alloc(unsigned long size, unsigned long align); +s32 devm_cpm_muram_alloc(struct device *dev, unsigned long size, + unsigned long align); void cpm_muram_free(s32 offset); s32 cpm_muram_alloc_fixed(unsigned long offset, unsigned long size); +s32 devm_cpm_muram_alloc_fixed(struct device *dev, unsigned long offset, + unsigned long size); void __iomem *cpm_muram_addr(unsigned long offset); unsigned long cpm_muram_offset(const void __iomem *addr); dma_addr_t cpm_muram_dma(void __iomem *addr); @@ -106,6 +112,12 @@ static inline s32 cpm_muram_alloc(unsigned long size, return -ENOSYS; } +static inline s32 devm_cpm_muram_alloc(struct device *dev, unsigned long size, + unsigned long align) +{ + return -ENOSYS; +} + static inline void cpm_muram_free(s32 offset) { } @@ -116,6 +128,13 @@ static inline s32 cpm_muram_alloc_fixed(unsigned long offset, return -ENOSYS; } +static inline s32 devm_cpm_muram_alloc_fixed(struct device *dev, + unsigned long offset, + unsigned long size) +{ + return -ENOSYS; +} + static inline void __iomem *cpm_muram_addr(unsigned long offset) { return NULL; @@ -172,7 +191,6 @@ static inline int par_io_data_set(u8 port, u8 pin, u8 val) { return -ENOSYS; } /* * Pin multiplexing functions. */ -struct device; struct qe_pin; #ifdef CONFIG_QE_GPIO extern struct qe_pin *qe_pin_request(struct device *dev, int index); @@ -233,7 +251,9 @@ static inline int qe_alive_during_sleep(void) /* we actually use cpm_muram implementation, define this for convenience */ #define qe_muram_init cpm_muram_init #define qe_muram_alloc cpm_muram_alloc +#define devm_qe_muram_alloc devm_cpm_muram_alloc #define qe_muram_alloc_fixed cpm_muram_alloc_fixed +#define devm_qe_muram_alloc_fixed devm_cpm_muram_alloc_fixed #define qe_muram_free cpm_muram_free #define qe_muram_addr cpm_muram_addr #define qe_muram_offset cpm_muram_offset From f68cd02d51a65594341168f03f7962e9d9540726 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:26 +0200 Subject: [PATCH 201/212] soc: fsl: qe: Add missing PUSHSCHED command The PUSHSCHED command is missing in the QE header file. This command is supported on MPC8321 and is used to modify the start address for the task running on a given peripheral. It is needed for the QMC in order to perform the re-initialization procedure and so, ensure the correct UCC setup in that case. Simply add the missing command in the commands list available in the QE header file. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-34-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- include/soc/fsl/qe/qe.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h index 629835b6c71d..8f967d15e479 100644 --- a/include/soc/fsl/qe/qe.h +++ b/include/soc/fsl/qe/qe.h @@ -469,6 +469,7 @@ enum comm_dir { #define QE_QMC_STOP_TX 0x0000000c #define QE_QMC_STOP_RX 0x0000000d #define QE_SS7_SU_FIL_RESET 0x0000000e +#define QE_PUSHSCHED 0x0000000f /* jonathbr added from here down for 83xx */ #define QE_RESET_BCS 0x0000000a #define QE_MCC_INIT_TX_RX_16 0x00000003 From eb680d563089e55b20cb7730ed881638fe4425b7 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:27 +0200 Subject: [PATCH 202/212] soc: fsl: cpm1: qmc: Add support for QUICC Engine (QE) implementation Add support for the QMC (QUICC Multichannel Controller) available in some PowerQUICC SoC that uses a QUICC Engine (QE) block such as MPC8321. This QE QMC is similar to the CPM QMC except that it uses UCCs (Unified Communication Controllers) instead of SCCs (Serial Communication Controllers). Also, compared against the CPM QMC, this QE QMC does not use a fixed area for the UCC/SCC parameters area but it uses a dynamic area allocated and provided to the hardware at runtime. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-35-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/Kconfig | 9 +- drivers/soc/fsl/qe/qmc.c | 209 +++++++++++++++++++++++++++++++++++-- 2 files changed, 204 insertions(+), 14 deletions(-) diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index 734744874730..5e3c996eb19e 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -17,7 +17,7 @@ config QUICC_ENGINE config UCC_SLOW bool - default y if SERIAL_QE + default y if SERIAL_QE || (CPM_QMC && QUICC_ENGINE) help This option provides qe_lib support to UCC slow protocols: UART, BISYNC, QMC @@ -46,12 +46,13 @@ config CPM_TSA controller config CPM_QMC - tristate "CPM QMC support" + tristate "CPM/QE QMC support" depends on OF && HAS_IOMEM - depends on CPM1 || (FSL_SOC && CPM && COMPILE_TEST) + depends on CPM1 || QUICC_ENGINE || \ + (FSL_SOC && (CPM || QUICC_ENGINE) && COMPILE_TEST) depends on CPM_TSA help - Freescale CPM QUICC Multichannel Controller + Freescale CPM/QE QUICC Multichannel Controller (QMC) This option enables support for this diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 8ff7eaaa4c50..b3a9534441ee 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -19,24 +19,29 @@ #include #include #include +#include +#include #include #include "tsa.h" -/* SCC general mode register high (32 bits) */ +/* SCC general mode register low (32 bits) (GUMR_L in QE) */ #define SCC_GSMRL 0x00 #define SCC_GSMRL_ENR BIT(5) #define SCC_GSMRL_ENT BIT(4) #define SCC_GSMRL_MODE_MASK GENMASK(3, 0) #define SCC_CPM1_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A) +#define SCC_QE_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x02) -/* SCC general mode register low (32 bits) */ +/* SCC general mode register high (32 bits) (identical to GUMR_H in QE) */ #define SCC_GSMRH 0x04 #define SCC_GSMRH_CTSS BIT(7) #define SCC_GSMRH_CDS BIT(8) #define SCC_GSMRH_CTSP BIT(9) #define SCC_GSMRH_CDP BIT(10) +#define SCC_GSMRH_TTX BIT(11) +#define SCC_GSMRH_TRX BIT(12) -/* SCC event register (16 bits) */ +/* SCC event register (16 bits) (identical to UCCE in QE) */ #define SCC_SCCE 0x10 #define SCC_SCCE_IQOV BIT(3) #define SCC_SCCE_GINT BIT(2) @@ -45,6 +50,10 @@ /* SCC mask register (16 bits) */ #define SCC_SCCM 0x14 + +/* UCC Extended Mode Register (8 bits, QE only) */ +#define SCC_QE_UCC_GUEMR 0x90 + /* Multichannel base pointer (32 bits) */ #define QMC_GBL_MCBASE 0x00 /* Multichannel controller state (16 bits) */ @@ -75,6 +84,15 @@ #define QMC_GBL_TSATTX 0x60 /* CRC constant (16 bits) */ #define QMC_GBL_C_MASK16 0xA0 +/* Rx framer base pointer (16 bits, QE only) */ +#define QMC_QE_GBL_RX_FRM_BASE 0xAC +/* Tx framer base pointer (16 bits, QE only) */ +#define QMC_QE_GBL_TX_FRM_BASE 0xAE +/* A reserved area (0xB0 -> 0xC3) that must be initialized to 0 (QE only) */ +#define QMC_QE_GBL_RSV_B0_START 0xB0 +#define QMC_QE_GBL_RSV_B0_SIZE 0x14 +/* QMC Global Channel specific base (32 bits, QE only) */ +#define QMC_QE_GBL_GCSBASE 0xC4 /* TSA entry (16bit entry in TSATRX and TSATTX) */ #define QMC_TSA_VALID BIT(15) @@ -217,6 +235,7 @@ struct qmc_chan { enum qmc_version { QMC_CPM1, + QMC_QE, }; struct qmc_data { @@ -237,6 +256,8 @@ struct qmc { void __iomem *scc_pram; void __iomem *dpram; u16 scc_pram_offset; + u32 dpram_offset; + u32 qe_subblock; cbd_t __iomem *bd_table; dma_addr_t bd_dma_addr; size_t bd_size; @@ -249,6 +270,11 @@ struct qmc { struct qmc_chan *chans[64]; }; +static void qmc_write8(void __iomem *addr, u8 val) +{ + iowrite8(val, addr); +} + static void qmc_write16(void __iomem *addr, u16 val) { iowrite16be(val, addr); @@ -289,6 +315,14 @@ static void qmc_setbits32(void __iomem *addr, u32 set) qmc_write32(addr, qmc_read32(addr) | set); } +static bool qmc_is_qe(const struct qmc *qmc) +{ + if (IS_ENABLED(CONFIG_QUICC_ENGINE) && IS_ENABLED(CONFIG_CPM)) + return qmc->data->version == QMC_QE; + + return IS_ENABLED(CONFIG_QUICC_ENGINE); +} + int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) { struct tsa_serial_info tsa_info; @@ -806,6 +840,13 @@ static int qmc_chan_cpm1_command(struct qmc_chan *chan, u8 qmc_opcode) return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E); } +static int qmc_chan_qe_command(struct qmc_chan *chan, u32 cmd) +{ + if (!qe_issue_cmd(cmd, chan->qmc->qe_subblock, chan->id, 0)) + return -EIO; + return 0; +} + static int qmc_chan_stop_rx(struct qmc_chan *chan) { unsigned long flags; @@ -820,7 +861,9 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan) } /* Send STOP RECEIVE command */ - ret = qmc_chan_cpm1_command(chan, 0x0); + ret = qmc_is_qe(chan->qmc) ? + qmc_chan_qe_command(chan, QE_QMC_STOP_RX) : + qmc_chan_cpm1_command(chan, 0x0); if (ret) { dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n", chan->id, ret); @@ -857,7 +900,9 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan) } /* Send STOP TRANSMIT command */ - ret = qmc_chan_cpm1_command(chan, 0x1); + ret = qmc_is_qe(chan->qmc) ? + qmc_chan_qe_command(chan, QE_QMC_STOP_TX) : + qmc_chan_cpm1_command(chan, 0x1); if (ret) { dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n", chan->id, ret); @@ -1627,9 +1672,62 @@ static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev return 0; } +static int qmc_qe_init_resources(struct qmc *qmc, struct platform_device *pdev) +{ + struct resource *res; + int ucc_num; + s32 info; + + qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "ucc_regs"); + if (IS_ERR(qmc->scc_regs)) + return PTR_ERR(qmc->scc_regs); + + ucc_num = tsa_serial_get_num(qmc->tsa_serial); + if (ucc_num < 0) + return dev_err_probe(qmc->dev, ucc_num, "Failed to get UCC num\n"); + + qmc->qe_subblock = ucc_slow_get_qe_cr_subblock(ucc_num); + if (qmc->qe_subblock == QE_CR_SUBBLOCK_INVALID) { + dev_err(qmc->dev, "Unsupported ucc num %u\n", ucc_num); + return -EINVAL; + } + /* Allocate the 'Global Multichannel Parameters' and the + * 'Framer parameters' areas. The 'Framer parameters' area + * is located right after the 'Global Multichannel Parameters'. + * The 'Framer parameters' need 1 byte per receive and transmit + * channel. The maximum number of receive or transmit channel + * is 64. So reserve 2 * 64 bytes for the 'Framer parameters'. + */ + info = devm_qe_muram_alloc(qmc->dev, UCC_SLOW_PRAM_SIZE + 2 * 64, + ALIGNMENT_OF_UCC_SLOW_PRAM); + if (IS_ERR_VALUE(info)) { + dev_err(qmc->dev, "cannot allocate MURAM for PRAM"); + return -ENOMEM; + } + if (!qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, qmc->qe_subblock, + QE_CR_PROTOCOL_UNSPECIFIED, info)) { + dev_err(qmc->dev, "QE_ASSIGN_PAGE_TO_DEVICE cmd failed"); + return -EIO; + } + qmc->scc_pram = qe_muram_addr(info); + qmc->scc_pram_offset = info; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpram"); + if (!res) + return -EINVAL; + qmc->dpram_offset = res->start - qe_muram_dma(qe_muram_addr(0)); + qmc->dpram = devm_ioremap_resource(qmc->dev, res); + if (IS_ERR(qmc->scc_pram)) + return PTR_ERR(qmc->scc_pram); + + return 0; +} + static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev) { - return qmc_cpm1_init_resources(qmc, pdev); + return qmc_is_qe(qmc) ? + qmc_qe_init_resources(qmc, pdev) : + qmc_cpm1_init_resources(qmc, pdev); } static int qmc_cpm1_init_scc(struct qmc *qmc) @@ -1656,9 +1754,69 @@ static int qmc_cpm1_init_scc(struct qmc *qmc) return 0; } +static int qmc_qe_init_ucc(struct qmc *qmc) +{ + u32 val; + int ret; + + /* Set the UCC in slow mode */ + qmc_write8(qmc->scc_regs + SCC_QE_UCC_GUEMR, + UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX); + + /* Connect the serial (UCC) to TSA */ + ret = tsa_serial_connect(qmc->tsa_serial); + if (ret) + return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n"); + + /* Initialize the QMC tx startup addresses */ + if (!qe_issue_cmd(QE_PUSHSCHED, qmc->qe_subblock, + QE_CR_PROTOCOL_UNSPECIFIED, 0x80)) { + dev_err(qmc->dev, "QE_CMD_PUSH_SCHED tx cmd failed"); + ret = -EIO; + goto err_tsa_serial_disconnect; + } + + /* Initialize the QMC rx startup addresses */ + if (!qe_issue_cmd(QE_PUSHSCHED, qmc->qe_subblock | 0x00020000, + QE_CR_PROTOCOL_UNSPECIFIED, 0x82)) { + dev_err(qmc->dev, "QE_CMD_PUSH_SCHED rx cmd failed"); + ret = -EIO; + goto err_tsa_serial_disconnect; + } + + /* Re-init RXPTR and TXPTR with the content of RX_S_PTR and + * TX_S_PTR (RX_S_PTR and TX_S_PTR are initialized during + * qmc_setup_tsa() call + */ + val = qmc_read16(qmc->scc_pram + QMC_GBL_RX_S_PTR); + qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val); + val = qmc_read16(qmc->scc_pram + QMC_GBL_TX_S_PTR); + qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val); + + /* Init GUMR_H and GUMR_L registers (SCC GSMR_H and GSMR_L) */ + val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP | + SCC_GSMRH_TRX | SCC_GSMRH_TTX; + qmc_write32(qmc->scc_regs + SCC_GSMRH, val); + + /* enable QMC mode */ + qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_QE_GSMRL_MODE_QMC); + + /* Disable and clear interrupts */ + qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); + qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F); + + return 0; + +err_tsa_serial_disconnect: + tsa_serial_disconnect(qmc->tsa_serial); + return ret; +} + static int qmc_init_xcc(struct qmc *qmc) { - return qmc_cpm1_init_scc(qmc); + return qmc_is_qe(qmc) ? + qmc_qe_init_ucc(qmc) : + qmc_cpm1_init_scc(qmc); } static void qmc_exit_xcc(struct qmc *qmc) @@ -1742,6 +1900,22 @@ static int qmc_probe(struct platform_device *pdev) qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3); qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8); + if (qmc_is_qe(qmc)) { + /* Zeroed the reserved area */ + memset_io(qmc->scc_pram + QMC_QE_GBL_RSV_B0_START, 0, + QMC_QE_GBL_RSV_B0_SIZE); + + qmc_write32(qmc->scc_pram + QMC_QE_GBL_GCSBASE, qmc->dpram_offset); + + /* Init 'framer parameters' area and set the base addresses */ + memset_io(qmc->scc_pram + UCC_SLOW_PRAM_SIZE, 0x01, 64); + memset_io(qmc->scc_pram + UCC_SLOW_PRAM_SIZE + 64, 0x01, 64); + qmc_write16(qmc->scc_pram + QMC_QE_GBL_RX_FRM_BASE, + qmc->scc_pram_offset + UCC_SLOW_PRAM_SIZE); + qmc_write16(qmc->scc_pram + QMC_QE_GBL_TX_FRM_BASE, + qmc->scc_pram_offset + UCC_SLOW_PRAM_SIZE + 64); + } + ret = qmc_init_tsa(qmc); if (ret) return ret; @@ -1757,7 +1931,7 @@ static int qmc_probe(struct platform_device *pdev) if (ret) return ret; - /* Init SCC */ + /* Init SCC (CPM1) or UCC (QE) */ ret = qmc_init_xcc(qmc); if (ret) return ret; @@ -1811,7 +1985,7 @@ static void qmc_remove(struct platform_device *pdev) /* Disable interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, 0); - /* Exit SCC */ + /* Exit SCC (CPM1) or UCC (QE) */ qmc_exit_xcc(qmc); } @@ -1825,8 +1999,23 @@ static const struct qmc_data qmc_data_cpm1 = { .rpack = 0x00000000, }; +static const struct qmc_data qmc_data_qe = { + .version = QMC_QE, + .tstate = 0x30000000, + .rstate = 0x30000000, + .zistate = 0x00000200, + .zdstate_hdlc = 0x80FFFFE0, + .zdstate_transp = 0x003FFFE2, + .rpack = 0x80000000, +}; + static const struct of_device_id qmc_id_table[] = { +#if IS_ENABLED(CONFIG_CPM1) { .compatible = "fsl,cpm1-scc-qmc", .data = &qmc_data_cpm1 }, +#endif +#if IS_ENABLED(CONFIG_QUICC_ENGINE) + { .compatible = "fsl,qe-ucc-qmc", .data = &qmc_data_qe }, +#endif {} /* sentinel */ }; MODULE_DEVICE_TABLE(of, qmc_id_table); @@ -1986,5 +2175,5 @@ struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, EXPORT_SYMBOL(devm_qmc_chan_get_bychild); MODULE_AUTHOR("Herve Codina "); -MODULE_DESCRIPTION("CPM QMC driver"); +MODULE_DESCRIPTION("CPM/QE QMC driver"); MODULE_LICENSE("GPL"); From 8655b76b7004d53bfa3c921ad9c4bf03dc952dc7 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:28 +0200 Subject: [PATCH 203/212] soc: fsl: cpm1: qmc: Handle QUICC Engine (QE) soft-qmc firmware The QUICC Engine (QE) QMC can use a firmware to have the QMC working in 'soft-qmc' mode. Handle this optional 'soft-qmc' firmware. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-36-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 67 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index b3a9534441ee..3dffebb48b0d 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1649,6 +1650,66 @@ static irqreturn_t qmc_irq_handler(int irq, void *priv) return IRQ_HANDLED; } +static int qmc_qe_soft_qmc_init(struct qmc *qmc, struct device_node *np) +{ + struct qe_firmware_info *qe_fw_info; + const struct qe_firmware *qe_fw; + const struct firmware *fw; + const char *filename; + int ret; + + ret = of_property_read_string(np, "fsl,soft-qmc", &filename); + switch (ret) { + case 0: + break; + case -EINVAL: + /* fsl,soft-qmc property not set -> Simply do nothing */ + return 0; + default: + dev_err(qmc->dev, "%pOF: failed to read fsl,soft-qmc\n", + np); + return ret; + } + + qe_fw_info = qe_get_firmware_info(); + if (qe_fw_info) { + if (!strstr(qe_fw_info->id, "Soft-QMC")) { + dev_err(qmc->dev, "Another Firmware is already loaded\n"); + return -EALREADY; + } + dev_info(qmc->dev, "Firmware already loaded\n"); + return 0; + } + + dev_info(qmc->dev, "Using firmware %s\n", filename); + + ret = request_firmware(&fw, filename, qmc->dev); + if (ret) { + dev_err(qmc->dev, "Failed to request firmware %s\n", filename); + return ret; + } + + qe_fw = (const struct qe_firmware *)fw->data; + + if (fw->size < sizeof(qe_fw->header) || + be32_to_cpu(qe_fw->header.length) != fw->size) { + dev_err(qmc->dev, "Invalid firmware %s\n", filename); + ret = -EINVAL; + goto end; + } + + ret = qe_upload_firmware(qe_fw); + if (ret) { + dev_err(qmc->dev, "Failed to load firmware %s\n", filename); + goto end; + } + + ret = 0; +end: + release_firmware(fw); + return ret; +} + static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev) { struct resource *res; @@ -1855,6 +1916,12 @@ static int qmc_probe(struct platform_device *pdev) if (ret) return ret; + if (qmc_is_qe(qmc)) { + ret = qmc_qe_soft_qmc_init(qmc, np); + if (ret) + return ret; + } + /* Parse channels informationss */ ret = qmc_of_parse_chans(qmc, np); if (ret) From 3969d8d958021cf3b9dac5787c7daec72036cc1f Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:29 +0200 Subject: [PATCH 204/212] MAINTAINERS: Add QE files related to the Freescale QMC controller The Freescale QMC controller driver supports both QE and CPM1. Add the newly introduced QE files to the existing entry. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-37-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1d32d38f2247..1331bdeb7386 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8996,6 +8996,7 @@ M: Herve Codina L: linuxppc-dev@lists.ozlabs.org S: Maintained F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml +F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml F: drivers/soc/fsl/qe/qmc.c F: include/soc/fsl/qe/qmc.h From 77a1a513083188f12361c45f08bdcfa508749b76 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Mon, 12 Aug 2024 15:25:27 +0800 Subject: [PATCH 205/212] soc: fsl: qbman: Use iommu_paging_domain_alloc() An iommu domain is allocated in portal_set_cpu() and is attached to pcfg->dev in the same function. Use iommu_paging_domain_alloc() to make it explicit. Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20240610085555.88197-14-baolu.lu@linux.intel.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qbman/qman_portal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c index e23b60618c1a..456ef5d5c199 100644 --- a/drivers/soc/fsl/qbman/qman_portal.c +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -48,9 +48,10 @@ static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu) struct device *dev = pcfg->dev; int ret; - pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type); - if (!pcfg->iommu_domain) { + pcfg->iommu_domain = iommu_paging_domain_alloc(dev); + if (IS_ERR(pcfg->iommu_domain)) { dev_err(dev, "%s(): iommu_domain_alloc() failed", __func__); + pcfg->iommu_domain = NULL; goto no_iommu; } ret = fsl_pamu_configure_l1_stash(pcfg->iommu_domain, cpu); From e266aa8b3598c81ea30898a8da20a41f76faa09a Mon Sep 17 00:00:00 2001 From: Xiaolei Wang Date: Fri, 2 Aug 2024 10:16:51 +0800 Subject: [PATCH 206/212] soc: fsl: qbman: Remove redundant warnings This warning was added by commit 07f86917a450 ("soc/fsl/qbman: Use shared-dma-pool for QMan private memory allocations") but RESERVEDMEM_OF_DECLARE usage was removed by commit 3e62273ac63a ("soc: fsl: qbman: Remove RESERVEDMEM_OF_DECLARE usage") . For non-popwerpc platforms, such as ls1043, this warning is redundant. ls1043 itself uses shared-dma-mem. Fixes: 3e62273ac63a ("soc: fsl: qbman: Remove RESERVEDMEM_OF_DECLARE usage") Signed-off-by: Xiaolei Wang Link: https://lore.kernel.org/r/20240802021651.3854295-1-xiaolei.wang@windriver.com [chleroy: Added more details in commit message] Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qbman/qman_ccsr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c index 392e54f14dbe..aa5348f4902f 100644 --- a/drivers/soc/fsl/qbman/qman_ccsr.c +++ b/drivers/soc/fsl/qbman/qman_ccsr.c @@ -791,8 +791,6 @@ static int fsl_qman_probe(struct platform_device *pdev) * FQD memory MUST be zero'd by software */ zero_priv_mem(fqd_a, fqd_sz); -#else - WARN(1, "Unexpected architecture using non shared-dma-mem reservations"); #endif dev_dbg(dev, "Allocated FQD 0x%llx 0x%zx\n", fqd_a, fqd_sz); From 59420d8ad7809827524824a3891d6a081e735449 Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Tue, 3 Sep 2024 11:22:32 -0400 Subject: [PATCH 207/212] dt-bindings: arm: rockchip: Add rk3576 compatible string to pmu.yaml Add the compatible for the pmu mfd on rk3576. Signed-off-by: Detlev Casanova Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240903152308.13565-3-detlev.casanova@collabora.com Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/rockchip/pmu.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml b/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml index b79c81cd9f0e..932f981265cc 100644 --- a/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml @@ -26,6 +26,7 @@ select: - rockchip,rk3368-pmu - rockchip,rk3399-pmu - rockchip,rk3568-pmu + - rockchip,rk3576-pmu - rockchip,rk3588-pmu - rockchip,rv1126-pmu @@ -43,6 +44,7 @@ properties: - rockchip,rk3368-pmu - rockchip,rk3399-pmu - rockchip,rk3568-pmu + - rockchip,rk3576-pmu - rockchip,rk3588-pmu - rockchip,rv1126-pmu - const: syscon From d205c06a326e435057c807bf1e962327de53bb52 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 4 Sep 2024 09:51:09 +0200 Subject: [PATCH 208/212] soc: fsl: cpm1: qmc: Fix dependency on fsl_soc.h QMC driver requires fsl_soc.h to use function get_immrbase(). This header is provided by powerpc architecture and the functions it declares are defined only when FSL_SOC is selected. Today the dependency is the following: depends on CPM1 || QUICC_ENGINE || \ (FSL_SOC && (CPM || QUICC_ENGINE) && COMPILE_TEST) This dependency tentatively ensure that FSL_SOC is there when doing a COMPILE_TEST. CPM1 is only selected by PPC_8xx and cannot be selected manually. CPM1 selects FSL_SOC QUICC_ENGINE on the other hand can be selected by ARM or ARM64 which doesn't select FSL_SOC. QUICC_ENGINE can also be selected with just COMPILE_TEST. It is therefore possible to end up with CPM_QMC selected without FSL_SOC. So fix it by making it depend on FSL_SOC at all time. The rest of the above dependency is the same as the one for CPM_TSA on which CPM_QMC also depends, so it can go away, leaving only a simple dependency on FSL_SOC. Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/lkml/20240904104859.020fe3a9@canb.auug.org.au/ Fixes: 8655b76b7004 ("soc: fsl: cpm1: qmc: Handle QUICC Engine (QE) soft-qmc firmware") Signed-off-by: Christophe Leroy Acked-by: Herve Codina Signed-off-by: Arnd Bergmann --- drivers/soc/fsl/qe/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index 5e3c996eb19e..eb03f42ab978 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -48,8 +48,7 @@ config CPM_TSA config CPM_QMC tristate "CPM/QE QMC support" depends on OF && HAS_IOMEM - depends on CPM1 || QUICC_ENGINE || \ - (FSL_SOC && (CPM || QUICC_ENGINE) && COMPILE_TEST) + depends on FSL_SOC depends on CPM_TSA help Freescale CPM/QE QUICC Multichannel Controller From dc2b17fbd599caa6079d619e1ff2c3d980ff6603 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 5 Sep 2024 09:22:15 +0200 Subject: [PATCH 209/212] soc: fsl: qe: ucc: Export ucc_mux_set_grant_tsa_bkpt When TSA is compiled as module the following error is reported: "ucc_mux_set_grant_tsa_bkpt" [drivers/soc/fsl/qe/tsa.ko] undefined! Indeed, the ucc_mux_set_grant_tsa_bkpt symbol is not exported. Simply export ucc_mux_set_grant_tsa_bkpt. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202409051409.fszn8rEo-lkp@intel.com/ Signed-off-by: Herve Codina Acked-by: Christophe Leroy Signed-off-by: Arnd Bergmann --- drivers/soc/fsl/qe/ucc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/fsl/qe/ucc.c b/drivers/soc/fsl/qe/ucc.c index 21dbcd787cd5..892aa5931d5b 100644 --- a/drivers/soc/fsl/qe/ucc.c +++ b/drivers/soc/fsl/qe/ucc.c @@ -114,6 +114,7 @@ int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask) return 0; } +EXPORT_SYMBOL(ucc_mux_set_grant_tsa_bkpt); int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock, enum comm_dir mode) From 7ad250e13ff8a275ba846fd223288f01f5d3857c Mon Sep 17 00:00:00 2001 From: Zhang Zekun Date: Thu, 5 Sep 2024 19:41:34 +0800 Subject: [PATCH 210/212] bus: sunxi-rsb: Simplify code with dev_err_probe() Use dev_err_probe() directly in the driver probe phase. This can simplify the code a bit. Signed-off-by: Zhang Zekun Link: https://lore.kernel.org/r/20240905114134.80310-1-zhangzekun11@huawei.com Signed-off-by: Chen-Yu Tsai --- drivers/bus/sunxi-rsb.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index eee41fb798a1..a89d78925637 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -751,12 +751,10 @@ static int sunxi_rsb_probe(struct platform_device *pdev) int irq, ret; of_property_read_u32(np, "clock-frequency", &clk_freq); - if (clk_freq > RSB_MAX_FREQ) { - dev_err(dev, - "clock-frequency (%u Hz) is too high (max = 20MHz)\n", - clk_freq); - return -EINVAL; - } + if (clk_freq > RSB_MAX_FREQ) + return dev_err_probe(dev, -EINVAL, + "clock-frequency (%u Hz) is too high (max = 20MHz)\n", + clk_freq); rsb = devm_kzalloc(dev, sizeof(*rsb), GFP_KERNEL); if (!rsb) @@ -774,28 +772,22 @@ static int sunxi_rsb_probe(struct platform_device *pdev) return irq; rsb->clk = devm_clk_get(dev, NULL); - if (IS_ERR(rsb->clk)) { - ret = PTR_ERR(rsb->clk); - dev_err(dev, "failed to retrieve clk: %d\n", ret); - return ret; - } + if (IS_ERR(rsb->clk)) + return dev_err_probe(dev, PTR_ERR(rsb->clk), + "failed to retrieve clk\n"); rsb->rstc = devm_reset_control_get(dev, NULL); - if (IS_ERR(rsb->rstc)) { - ret = PTR_ERR(rsb->rstc); - dev_err(dev, "failed to retrieve reset controller: %d\n", ret); - return ret; - } + if (IS_ERR(rsb->rstc)) + return dev_err_probe(dev, PTR_ERR(rsb->rstc), + "failed to retrieve reset controller\n"); init_completion(&rsb->complete); mutex_init(&rsb->lock); ret = devm_request_irq(dev, irq, sunxi_rsb_irq, 0, RSB_CTRL_NAME, rsb); - if (ret) { - dev_err(dev, "can't register interrupt handler irq %d: %d\n", - irq, ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "can't register interrupt handler irq %d\n", irq); ret = sunxi_rsb_hw_init(rsb); if (ret) From 2d516b8fc0f18ce9c0347a1aea6edb3d8ca1d692 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Sep 2024 16:16:53 +0300 Subject: [PATCH 211/212] platform: cznic: turris-omnia-mcu: Fix error check in omnia_mcu_register_trng() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gpiod_to_irq() function never returns zero. It returns negative error codes or a positive IRQ number. Update the checking to check for negatives. Fixes: 41bb142a4028 ("platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG") Signed-off-by: Dan Carpenter Reviewed-by: Marek BehĂșn Signed-off-by: Arnd Bergmann --- drivers/platform/cznic/turris-omnia-mcu-trng.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/cznic/turris-omnia-mcu-trng.c b/drivers/platform/cznic/turris-omnia-mcu-trng.c index ad953fb3c37a..9a1d9292dc9a 100644 --- a/drivers/platform/cznic/turris-omnia-mcu-trng.c +++ b/drivers/platform/cznic/turris-omnia-mcu-trng.c @@ -70,8 +70,8 @@ int omnia_mcu_register_trng(struct omnia_mcu *mcu) irq_idx = omnia_int_to_gpio_idx[__bf_shf(OMNIA_INT_TRNG)]; irq = gpiod_to_irq(gpio_device_get_desc(mcu->gc.gpiodev, irq_idx)); - if (!irq) - return dev_err_probe(dev, -ENXIO, "Cannot get TRNG IRQ\n"); + if (irq < 0) + return dev_err_probe(dev, irq, "Cannot get TRNG IRQ\n"); /* * If someone else cleared the TRNG interrupt but did not read the From 540c830212edc908361c39d40df21772a8bda308 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 9 Sep 2024 20:30:18 +0000 Subject: [PATCH 212/212] firmware: imx: remove duplicate scmi_imx_misc_ctrl_get() These two functions have a stub definition when CONFIG_IMX_SCMI_MISC_EXT is not set, which conflict with the global definition: In file included from drivers/firmware/imx/sm-misc.c:6: include/linux/firmware/imx/sm.h:30:1: error: expected identifier or '(' before '{' token 30 | { | ^ drivers/firmware/imx/sm-misc.c:26:5: error: redefinition of 'scmi_imx_misc_ctrl_get' 26 | int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val) | ^~~~~~~~~~~~~~~~~~~~~~ include/linux/firmware/imx/sm.h:24:19: note: previous definition of 'scmi_imx_misc_ctrl_get' with type 'int(u32, u32 *, u32 *)' {aka 'int(unsigned int, unsigned int *, unsigned int *)'} 24 | static inline int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val) | ^~~~~~~~~~~~~~~~~~~~~~ There is no real need for the #ifdef, and removing this avoids the build failure. Fixes: 0b4f8a68b292 ("firmware: imx: Add i.MX95 MISC driver") Link: https://lore.kernel.org/r/20240909203023.1275232-1-arnd@kernel.org Signed-off-by: Arnd Bergmann --- include/linux/firmware/imx/sm.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/include/linux/firmware/imx/sm.h b/include/linux/firmware/imx/sm.h index 62a2690e2abd..9b85a3f028d1 100644 --- a/include/linux/firmware/imx/sm.h +++ b/include/linux/firmware/imx/sm.h @@ -17,18 +17,7 @@ #define SCMI_IMX_CTRL_SAI4_MCLK 4 /* WAKE SAI4 MCLK */ #define SCMI_IMX_CTRL_SAI5_MCLK 5 /* WAKE SAI5 MCLK */ -#if IS_ENABLED(CONFIG_IMX_SCMI_MISC_EXT) int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val); int scmi_imx_misc_ctrl_set(u32 id, u32 val); -#else -static inline int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val) -{ - return -EOPNOTSUPP; -} -static inline int scmi_imx_misc_ctrl_set(u32 id, u32 val); -{ - return -EOPNOTSUPP; -} -#endif #endif