aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-12-31 20:32:35 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-12-31 20:32:35 -0500
commitd36377c6eb071e3d0751e9e0e3c19198c58d9a5d (patch)
treebf1d28abd5fac5c826079c4b760ca34263f0fab4 /drivers/firmware
parent0922275ef157ba8ac93e7e7857087eb0442d5397 (diff)
parenta6f119a06960ef1dc30570401e43b71f9ebdd2c2 (diff)
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Olof Johansson: "Misc driver updates for platforms, many of them power related. - Rockchip adds power domain support for rk3066 and rk3188 - Amlogic adds a power measurement driver - Allwinner adds SRAM support for three platforms (F1C100, H5, A64 C1) - Wakeup and ti-sysc (platform bus) fixes for OMAP/DRA7 - Broadcom fixes suspend/resume with Thumb2 kernels, and improves stability of a handful of firmware/platform interfaces - PXA completes their conversion to dmaengine framework - Renesas does a bunch of PM cleanups across many platforms - Tegra adds support for suspend/resume on T186/T194, which includes some driver cleanups and addition of wake events - Tegra also adds a driver for memory controller (EMC) on Tegra2 - i.MX tweaks power domain bindings, and adds support for i.MX8MQ in GPC - Atmel adds identifiers and LPDDR2 support for a new SoC, SAM9X60 and misc cleanups across several platforms" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (73 commits) ARM: at91: add support in soc driver for new SAM9X60 ARM: at91: add support in soc driver for LPDDR2 SiP memory: omap-gpmc: Use of_node_name_eq for node name comparisons bus: ti-sysc: Check for no-reset and no-idle flags at the child level ARM: OMAP2+: Check also the first dts child for hwmod flags soc: amlogic: meson-clk-measure: Add missing REGMAP_MMIO dependency soc: imx: gpc: Increase GPC_CLK_MAX to 7 soc: renesas: rcar-sysc: Fix power domain control after system resume soc: renesas: rcar-sysc: Merge PM Domain registration and linking soc: renesas: rcar-sysc: Remove rcar_sysc_power_{down,up}() helpers soc: renesas: r8a77990-sysc: Fix initialization order of 3DG-{A,B} dt-bindings: sram: sunxi: Add compatible for the A64 SRAM C1 dt-bindings: sram: sunxi: Add bindings for the H5 with SRAM C1 dt-bindings: sram: Add Allwinner suniv F1C100s soc: sunxi: sram: Add support for the H5 SoC system control soc: sunxi: sram: Enable EMAC clock access for H3 variant soc: imx: gpcv2: add support for i.MX8MQ SoC soc: imx: gpcv2: move register access table to domain data soc: imx: gpcv2: prefix i.MX7 specific defines dmaengine: pxa: make the filter function internal ...
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/imx/Kconfig6
-rw-r--r--drivers/firmware/imx/Makefile3
-rw-r--r--drivers/firmware/imx/scu-pd.c339
-rw-r--r--drivers/firmware/raspberrypi.c48
-rw-r--r--drivers/firmware/tegra/bpmp-debugfs.c29
-rw-r--r--drivers/firmware/tegra/bpmp.c77
6 files changed, 442 insertions, 60 deletions
diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
index b170c2851e48..6a7a7c2c5b5f 100644
--- a/drivers/firmware/imx/Kconfig
+++ b/drivers/firmware/imx/Kconfig
@@ -9,3 +9,9 @@ config IMX_SCU
9 9
10 This driver manages the IPC interface between host CPU and the 10 This driver manages the IPC interface between host CPU and the
11 SCU firmware running on M4. 11 SCU firmware running on M4.
12
13config IMX_SCU_PD
14 bool "IMX SCU Power Domain driver"
15 depends on IMX_SCU
16 help
17 The System Controller Firmware (SCFW) based power domain driver.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
index 0ac04dfda8d4..1b2e15b3c9ca 100644
--- a/drivers/firmware/imx/Makefile
+++ b/drivers/firmware/imx/Makefile
@@ -1,2 +1,3 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o 2obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o
3obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o
diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c
new file mode 100644
index 000000000000..407245f2efd0
--- /dev/null
+++ b/drivers/firmware/imx/scu-pd.c
@@ -0,0 +1,339 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
4 * Copyright 2017-2018 NXP
5 * Dong Aisheng <aisheng.dong@nxp.com>
6 *
7 * Implementation of the SCU based Power Domains
8 *
9 * NOTE: a better implementation suggested by Ulf Hansson is using a
10 * single global power domain and implement the ->attach|detach_dev()
11 * callback for the genpd and use the regular of_genpd_add_provider_simple().
12 * From within the ->attach_dev(), we could get the OF node for
13 * the device that is being attached and then parse the power-domain
14 * cell containing the "resource id" and store that in the per device
15 * struct generic_pm_domain_data (we have void pointer there for
16 * storing these kind of things).
17 *
18 * Additionally, we need to implement the ->stop() and ->start()
19 * callbacks of genpd, which is where you "power on/off" devices,
20 * rather than using the above ->power_on|off() callbacks.
21 *
22 * However, there're two known issues:
23 * 1. The ->attach_dev() of power domain infrastructure still does
24 * not support multi domains case as the struct device *dev passed
25 * in is a virtual PD device, it does not help for parsing the real
26 * device resource id from device tree, so it's unware of which
27 * real sub power domain of device should be attached.
28 *
29 * The framework needs some proper extension to support multi power
30 * domain cases.
31 *
32 * 2. It also breaks most of current drivers as the driver probe sequence
33 * behavior changed if removing ->power_on|off() callback and use
34 * ->start() and ->stop() instead. genpd_dev_pm_attach will only power
35 * up the domain and attach device, but will not call .start() which
36 * relies on device runtime pm. That means the device power is still
37 * not up before running driver probe function. For SCU enabled
38 * platforms, all device drivers accessing registers/clock without power
39 * domain enabled will trigger a HW access error. That means we need fix
40 * most drivers probe sequence with proper runtime pm.
41 *
42 * In summary, we need fix above two issue before being able to switch to
43 * the "single global power domain" way.
44 *
45 */
46
47#include <dt-bindings/firmware/imx/rsrc.h>
48#include <linux/firmware/imx/sci.h>
49#include <linux/io.h>
50#include <linux/module.h>
51#include <linux/of.h>
52#include <linux/of_address.h>
53#include <linux/of_platform.h>
54#include <linux/platform_device.h>
55#include <linux/pm.h>
56#include <linux/pm_domain.h>
57#include <linux/slab.h>
58
59/* SCU Power Mode Protocol definition */
60struct imx_sc_msg_req_set_resource_power_mode {
61 struct imx_sc_rpc_msg hdr;
62 u16 resource;
63 u8 mode;
64} __packed;
65
66#define IMX_SCU_PD_NAME_SIZE 20
67struct imx_sc_pm_domain {
68 struct generic_pm_domain pd;
69 char name[IMX_SCU_PD_NAME_SIZE];
70 u32 rsrc;
71};
72
73struct imx_sc_pd_range {
74 char *name;
75 u32 rsrc;
76 u8 num;
77 bool postfix;
78};
79
80struct imx_sc_pd_soc {
81 const struct imx_sc_pd_range *pd_ranges;
82 u8 num_ranges;
83};
84
85static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
86 /* LSIO SS */
87 { "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 },
88 { "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 },
89 { "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 },
90 { "lsio-kpp", IMX_SC_R_KPP, 1, 0 },
91 { "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 },
92 { "lsio-mu", IMX_SC_R_MU_0A, 14, 1 },
93
94 /* CONN SS */
95 { "con-usb", IMX_SC_R_USB_0, 2, 1 },
96 { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 },
97 { "con-usb2", IMX_SC_R_USB_2, 1, 0 },
98 { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 },
99 { "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 },
100 { "con-enet", IMX_SC_R_ENET_0, 2, 1 },
101 { "con-nand", IMX_SC_R_NAND, 1, 0 },
102 { "con-mlb", IMX_SC_R_MLB_0, 1, 1 },
103
104 /* Audio DMA SS */
105 { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 },
106 { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 },
107 { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 },
108 { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 },
109 { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 },
110 { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 },
111 { "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 },
112 { "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 },
113 { "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 },
114 { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 },
115 { "adma-sai", IMX_SC_R_SAI_0, 3, 1 },
116 { "adma-amix", IMX_SC_R_AMIX, 1, 0 },
117 { "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 },
118 { "adma-dsp", IMX_SC_R_DSP, 1, 0 },
119 { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 },
120 { "adma-can", IMX_SC_R_CAN_0, 3, 1 },
121 { "adma-ftm", IMX_SC_R_FTM_0, 2, 1 },
122 { "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 },
123 { "adma-adc", IMX_SC_R_ADC_0, 1, 1 },
124 { "adma-lcd", IMX_SC_R_LCD_0, 1, 1 },
125 { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 },
126 { "adma-lpuart", IMX_SC_R_UART_0, 4, 1 },
127 { "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 },
128
129 /* VPU SS */
130 { "vpu", IMX_SC_R_VPU, 1, 0 },
131 { "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 },
132 { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 },
133 { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 },
134
135 /* GPU SS */
136 { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 },
137
138 /* HSIO SS */
139 { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 },
140 { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 },
141 { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 },
142
143 /* MIPI/LVDS SS */
144 { "mipi0", IMX_SC_R_MIPI_0, 1, 0 },
145 { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 },
146 { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 },
147 { "lvds0", IMX_SC_R_LVDS_0, 1, 0 },
148
149 /* DC SS */
150 { "dc0", IMX_SC_R_DC_0, 1, 0 },
151 { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 },
152};
153
154static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
155 .pd_ranges = imx8qxp_scu_pd_ranges,
156 .num_ranges = ARRAY_SIZE(imx8qxp_scu_pd_ranges),
157};
158
159static struct imx_sc_ipc *pm_ipc_handle;
160
161static inline struct imx_sc_pm_domain *
162to_imx_sc_pd(struct generic_pm_domain *genpd)
163{
164 return container_of(genpd, struct imx_sc_pm_domain, pd);
165}
166
167static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on)
168{
169 struct imx_sc_msg_req_set_resource_power_mode msg;
170 struct imx_sc_rpc_msg *hdr = &msg.hdr;
171 struct imx_sc_pm_domain *pd;
172 int ret;
173
174 pd = to_imx_sc_pd(domain);
175
176 hdr->ver = IMX_SC_RPC_VERSION;
177 hdr->svc = IMX_SC_RPC_SVC_PM;
178 hdr->func = IMX_SC_PM_FUNC_SET_RESOURCE_POWER_MODE;
179 hdr->size = 2;
180
181 msg.resource = pd->rsrc;
182 msg.mode = power_on ? IMX_SC_PM_PW_MODE_ON : IMX_SC_PM_PW_MODE_LP;
183
184 ret = imx_scu_call_rpc(pm_ipc_handle, &msg, true);
185 if (ret)
186 dev_err(&domain->dev, "failed to power %s resource %d ret %d\n",
187 power_on ? "up" : "off", pd->rsrc, ret);
188
189 return ret;
190}
191
192static int imx_sc_pd_power_on(struct generic_pm_domain *domain)
193{
194 return imx_sc_pd_power(domain, true);
195}
196
197static int imx_sc_pd_power_off(struct generic_pm_domain *domain)
198{
199 return imx_sc_pd_power(domain, false);
200}
201
202static struct generic_pm_domain *imx_scu_pd_xlate(struct of_phandle_args *spec,
203 void *data)
204{
205 struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
206 struct genpd_onecell_data *pd_data = data;
207 unsigned int i;
208
209 for (i = 0; i < pd_data->num_domains; i++) {
210 struct imx_sc_pm_domain *sc_pd;
211
212 sc_pd = to_imx_sc_pd(pd_data->domains[i]);
213 if (sc_pd->rsrc == spec->args[0]) {
214 domain = &sc_pd->pd;
215 break;
216 }
217 }
218
219 return domain;
220}
221
222static struct imx_sc_pm_domain *
223imx_scu_add_pm_domain(struct device *dev, int idx,
224 const struct imx_sc_pd_range *pd_ranges)
225{
226 struct imx_sc_pm_domain *sc_pd;
227 int ret;
228
229 sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL);
230 if (!sc_pd)
231 return ERR_PTR(-ENOMEM);
232
233 sc_pd->rsrc = pd_ranges->rsrc + idx;
234 sc_pd->pd.power_off = imx_sc_pd_power_off;
235 sc_pd->pd.power_on = imx_sc_pd_power_on;
236
237 if (pd_ranges->postfix)
238 snprintf(sc_pd->name, sizeof(sc_pd->name),
239 "%s%i", pd_ranges->name, idx);
240 else
241 snprintf(sc_pd->name, sizeof(sc_pd->name),
242 "%s", pd_ranges->name);
243
244 sc_pd->pd.name = sc_pd->name;
245
246 if (sc_pd->rsrc >= IMX_SC_R_LAST) {
247 dev_warn(dev, "invalid pd %s rsrc id %d found",
248 sc_pd->name, sc_pd->rsrc);
249
250 devm_kfree(dev, sc_pd);
251 return NULL;
252 }
253
254 ret = pm_genpd_init(&sc_pd->pd, NULL, true);
255 if (ret) {
256 dev_warn(dev, "failed to init pd %s rsrc id %d",
257 sc_pd->name, sc_pd->rsrc);
258 devm_kfree(dev, sc_pd);
259 return NULL;
260 }
261
262 return sc_pd;
263}
264
265static int imx_scu_init_pm_domains(struct device *dev,
266 const struct imx_sc_pd_soc *pd_soc)
267{
268 const struct imx_sc_pd_range *pd_ranges = pd_soc->pd_ranges;
269 struct generic_pm_domain **domains;
270 struct genpd_onecell_data *pd_data;
271 struct imx_sc_pm_domain *sc_pd;
272 u32 count = 0;
273 int i, j;
274
275 for (i = 0; i < pd_soc->num_ranges; i++)
276 count += pd_ranges[i].num;
277
278 domains = devm_kcalloc(dev, count, sizeof(*domains), GFP_KERNEL);
279 if (!domains)
280 return -ENOMEM;
281
282 pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL);
283 if (!pd_data)
284 return -ENOMEM;
285
286 count = 0;
287 for (i = 0; i < pd_soc->num_ranges; i++) {
288 for (j = 0; j < pd_ranges[i].num; j++) {
289 sc_pd = imx_scu_add_pm_domain(dev, j, &pd_ranges[i]);
290 if (IS_ERR_OR_NULL(sc_pd))
291 continue;
292
293 domains[count++] = &sc_pd->pd;
294 dev_dbg(dev, "added power domain %s\n", sc_pd->pd.name);
295 }
296 }
297
298 pd_data->domains = domains;
299 pd_data->num_domains = count;
300 pd_data->xlate = imx_scu_pd_xlate;
301
302 of_genpd_add_provider_onecell(dev->of_node, pd_data);
303
304 return 0;
305}
306
307static int imx_sc_pd_probe(struct platform_device *pdev)
308{
309 const struct imx_sc_pd_soc *pd_soc;
310 int ret;
311
312 ret = imx_scu_get_handle(&pm_ipc_handle);
313 if (ret)
314 return ret;
315
316 pd_soc = of_device_get_match_data(&pdev->dev);
317 if (!pd_soc)
318 return -ENODEV;
319
320 return imx_scu_init_pm_domains(&pdev->dev, pd_soc);
321}
322
323static const struct of_device_id imx_sc_pd_match[] = {
324 { .compatible = "fsl,imx8qxp-scu-pd", &imx8qxp_scu_pd},
325 { /* sentinel */ }
326};
327
328static struct platform_driver imx_sc_pd_driver = {
329 .driver = {
330 .name = "imx-scu-pd",
331 .of_match_table = imx_sc_pd_match,
332 },
333 .probe = imx_sc_pd_probe,
334};
335builtin_platform_driver(imx_sc_pd_driver);
336
337MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
338MODULE_DESCRIPTION("IMX SCU Power Domain driver");
339MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
index a200a2174611..a13558154ac3 100644
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -1,12 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Defines interfaces for interacting wtih the Raspberry Pi firmware's 3 * Defines interfaces for interacting wtih the Raspberry Pi firmware's
3 * property channel. 4 * property channel.
4 * 5 *
5 * Copyright © 2015 Broadcom 6 * Copyright © 2015 Broadcom
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */ 7 */
11 8
12#include <linux/dma-mapping.h> 9#include <linux/dma-mapping.h>
@@ -14,6 +11,7 @@
14#include <linux/module.h> 11#include <linux/module.h>
15#include <linux/of_platform.h> 12#include <linux/of_platform.h>
16#include <linux/platform_device.h> 13#include <linux/platform_device.h>
14#include <linux/slab.h>
17#include <soc/bcm2835/raspberrypi-firmware.h> 15#include <soc/bcm2835/raspberrypi-firmware.h>
18 16
19#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) 17#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf))
@@ -21,8 +19,6 @@
21#define MBOX_DATA28(msg) ((msg) & ~0xf) 19#define MBOX_DATA28(msg) ((msg) & ~0xf)
22#define MBOX_CHAN_PROPERTY 8 20#define MBOX_CHAN_PROPERTY 8
23 21
24#define MAX_RPI_FW_PROP_BUF_SIZE 32
25
26static struct platform_device *rpi_hwmon; 22static struct platform_device *rpi_hwmon;
27 23
28struct rpi_firmware { 24struct rpi_firmware {
@@ -56,8 +52,12 @@ rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data)
56 reinit_completion(&fw->c); 52 reinit_completion(&fw->c);
57 ret = mbox_send_message(fw->chan, &message); 53 ret = mbox_send_message(fw->chan, &message);
58 if (ret >= 0) { 54 if (ret >= 0) {
59 wait_for_completion(&fw->c); 55 if (wait_for_completion_timeout(&fw->c, HZ)) {
60 ret = 0; 56 ret = 0;
57 } else {
58 ret = -ETIMEDOUT;
59 WARN_ONCE(1, "Firmware transaction timeout");
60 }
61 } else { 61 } else {
62 dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret); 62 dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret);
63 } 63 }
@@ -144,28 +144,30 @@ EXPORT_SYMBOL_GPL(rpi_firmware_property_list);
144int rpi_firmware_property(struct rpi_firmware *fw, 144int rpi_firmware_property(struct rpi_firmware *fw,
145 u32 tag, void *tag_data, size_t buf_size) 145 u32 tag, void *tag_data, size_t buf_size)
146{ 146{
147 /* Single tags are very small (generally 8 bytes), so the 147 struct rpi_firmware_property_tag_header *header;
148 * stack should be safe.
149 */
150 u8 data[sizeof(struct rpi_firmware_property_tag_header) +
151 MAX_RPI_FW_PROP_BUF_SIZE];
152 struct rpi_firmware_property_tag_header *header =
153 (struct rpi_firmware_property_tag_header *)data;
154 int ret; 148 int ret;
155 149
156 if (WARN_ON(buf_size > sizeof(data) - sizeof(*header))) 150 /* Some mailboxes can use over 1k bytes. Rather than checking
157 return -EINVAL; 151 * size and using stack or kmalloc depending on requirements,
152 * just use kmalloc. Mailboxes don't get called enough to worry
153 * too much about the time taken in the allocation.
154 */
155 void *data = kmalloc(sizeof(*header) + buf_size, GFP_KERNEL);
158 156
157 if (!data)
158 return -ENOMEM;
159
160 header = data;
159 header->tag = tag; 161 header->tag = tag;
160 header->buf_size = buf_size; 162 header->buf_size = buf_size;
161 header->req_resp_size = 0; 163 header->req_resp_size = 0;
162 memcpy(data + sizeof(struct rpi_firmware_property_tag_header), 164 memcpy(data + sizeof(*header), tag_data, buf_size);
163 tag_data, buf_size); 165
166 ret = rpi_firmware_property_list(fw, data, buf_size + sizeof(*header));
167
168 memcpy(tag_data, data + sizeof(*header), buf_size);
164 169
165 ret = rpi_firmware_property_list(fw, &data, buf_size + sizeof(*header)); 170 kfree(data);
166 memcpy(tag_data,
167 data + sizeof(struct rpi_firmware_property_tag_header),
168 buf_size);
169 171
170 return ret; 172 return ret;
171} 173}
diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c
index f7f6a0a5cb07..a84df1a8ca2b 100644
--- a/drivers/firmware/tegra/bpmp-debugfs.c
+++ b/drivers/firmware/tegra/bpmp-debugfs.c
@@ -379,33 +379,6 @@ static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf,
379 return err; 379 return err;
380} 380}
381 381
382static int mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
383{
384 struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) };
385 struct mrq_query_abi_response resp;
386 struct tegra_bpmp_message msg = {
387 .mrq = MRQ_QUERY_ABI,
388 .tx = {
389 .data = &req,
390 .size = sizeof(req),
391 },
392 .rx = {
393 .data = &resp,
394 .size = sizeof(resp),
395 },
396 };
397 int ret;
398
399 ret = tegra_bpmp_transfer(bpmp, &msg);
400 if (ret < 0) {
401 /* something went wrong; assume not supported */
402 dev_warn(bpmp->dev, "tegra_bpmp_transfer failed (%d)\n", ret);
403 return 0;
404 }
405
406 return resp.status ? 0 : 1;
407}
408
409int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) 382int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
410{ 383{
411 dma_addr_t phys; 384 dma_addr_t phys;
@@ -415,7 +388,7 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
415 int ret; 388 int ret;
416 struct dentry *root; 389 struct dentry *root;
417 390
418 if (!mrq_is_supported(bpmp, MRQ_DEBUGFS)) 391 if (!tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS))
419 return 0; 392 return 0;
420 393
421 root = debugfs_create_dir("bpmp", NULL); 394 root = debugfs_create_dir("bpmp", NULL);
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
index a3d5b518c10e..689478b92bce 100644
--- a/drivers/firmware/tegra/bpmp.c
+++ b/drivers/firmware/tegra/bpmp.c
@@ -28,6 +28,7 @@
28 28
29#define MSG_ACK BIT(0) 29#define MSG_ACK BIT(0)
30#define MSG_RING BIT(1) 30#define MSG_RING BIT(1)
31#define TAG_SZ 32
31 32
32static inline struct tegra_bpmp * 33static inline struct tegra_bpmp *
33mbox_client_to_bpmp(struct mbox_client *client) 34mbox_client_to_bpmp(struct mbox_client *client)
@@ -470,6 +471,31 @@ unlock:
470} 471}
471EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); 472EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq);
472 473
474bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
475{
476 struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) };
477 struct mrq_query_abi_response resp;
478 struct tegra_bpmp_message msg = {
479 .mrq = MRQ_QUERY_ABI,
480 .tx = {
481 .data = &req,
482 .size = sizeof(req),
483 },
484 .rx = {
485 .data = &resp,
486 .size = sizeof(resp),
487 },
488 };
489 int ret;
490
491 ret = tegra_bpmp_transfer(bpmp, &msg);
492 if (ret || msg.rx.ret)
493 return false;
494
495 return resp.status == 0;
496}
497EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_is_supported);
498
473static void tegra_bpmp_mrq_handle_ping(unsigned int mrq, 499static void tegra_bpmp_mrq_handle_ping(unsigned int mrq,
474 struct tegra_bpmp_channel *channel, 500 struct tegra_bpmp_channel *channel,
475 void *data) 501 void *data)
@@ -521,8 +547,9 @@ static int tegra_bpmp_ping(struct tegra_bpmp *bpmp)
521 return err; 547 return err;
522} 548}
523 549
524static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, 550/* deprecated version of tag query */
525 size_t size) 551static int tegra_bpmp_get_firmware_tag_old(struct tegra_bpmp *bpmp, char *tag,
552 size_t size)
526{ 553{
527 struct mrq_query_tag_request request; 554 struct mrq_query_tag_request request;
528 struct tegra_bpmp_message msg; 555 struct tegra_bpmp_message msg;
@@ -531,7 +558,10 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
531 void *virt; 558 void *virt;
532 int err; 559 int err;
533 560
534 virt = dma_alloc_coherent(bpmp->dev, MSG_DATA_MIN_SZ, &phys, 561 if (size != TAG_SZ)
562 return -EINVAL;
563
564 virt = dma_alloc_coherent(bpmp->dev, TAG_SZ, &phys,
535 GFP_KERNEL | GFP_DMA32); 565 GFP_KERNEL | GFP_DMA32);
536 if (!virt) 566 if (!virt)
537 return -ENOMEM; 567 return -ENOMEM;
@@ -549,13 +579,44 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
549 local_irq_restore(flags); 579 local_irq_restore(flags);
550 580
551 if (err == 0) 581 if (err == 0)
552 strlcpy(tag, virt, size); 582 memcpy(tag, virt, TAG_SZ);
553 583
554 dma_free_coherent(bpmp->dev, MSG_DATA_MIN_SZ, virt, phys); 584 dma_free_coherent(bpmp->dev, TAG_SZ, virt, phys);
555 585
556 return err; 586 return err;
557} 587}
558 588
589static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
590 size_t size)
591{
592 if (tegra_bpmp_mrq_is_supported(bpmp, MRQ_QUERY_FW_TAG)) {
593 struct mrq_query_fw_tag_response resp;
594 struct tegra_bpmp_message msg = {
595 .mrq = MRQ_QUERY_FW_TAG,
596 .rx = {
597 .data = &resp,
598 .size = sizeof(resp),
599 },
600 };
601 int err;
602
603 if (size != sizeof(resp.tag))
604 return -EINVAL;
605
606 err = tegra_bpmp_transfer(bpmp, &msg);
607
608 if (err)
609 return err;
610 if (msg.rx.ret < 0)
611 return -EINVAL;
612
613 memcpy(tag, resp.tag, sizeof(resp.tag));
614 return 0;
615 }
616
617 return tegra_bpmp_get_firmware_tag_old(bpmp, tag, size);
618}
619
559static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) 620static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel)
560{ 621{
561 unsigned long flags = channel->ob->flags; 622 unsigned long flags = channel->ob->flags;
@@ -664,7 +725,7 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
664{ 725{
665 struct tegra_bpmp *bpmp; 726 struct tegra_bpmp *bpmp;
666 unsigned int i; 727 unsigned int i;
667 char tag[32]; 728 char tag[TAG_SZ];
668 size_t size; 729 size_t size;
669 int err; 730 int err;
670 731
@@ -792,13 +853,13 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
792 goto free_mrq; 853 goto free_mrq;
793 } 854 }
794 855
795 err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag) - 1); 856 err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag));
796 if (err < 0) { 857 if (err < 0) {
797 dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err); 858 dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err);
798 goto free_mrq; 859 goto free_mrq;
799 } 860 }
800 861
801 dev_info(&pdev->dev, "firmware: %s\n", tag); 862 dev_info(&pdev->dev, "firmware: %.*s\n", (int)sizeof(tag), tag);
802 863
803 platform_set_drvdata(pdev, bpmp); 864 platform_set_drvdata(pdev, bpmp);
804 865