blob: d1fff328e8575ccd119b66f0bbda86efa7774a4a [file] [log] [blame]
Rajan Vaja14723ed2019-02-15 04:45:32 -08001// SPDX-License-Identifier: GPL-2.0
Ibai Erkiaga1327d162019-09-27 12:51:41 +02002/*
3 * Xilinx Zynq MPSoC Firmware driver
4 *
5 * Copyright (C) 2018-2019 Xilinx, Inc.
6 */
Rajan Vaja14723ed2019-02-15 04:45:32 -08007
Ibai Erkiaga1327d162019-09-27 12:51:41 +02008#include <common.h>
Rajan Vaja14723ed2019-02-15 04:45:32 -08009#include <dm.h>
10
Ibai Erkiaga1327d162019-09-27 12:51:41 +020011#if defined(CONFIG_ZYNQMP_IPI)
12#include <mailbox.h>
13#include <asm/arch/sys_proto.h>
14
Ibai Erkiaga490f6272019-09-27 11:37:00 +010015#define PMUFW_PAYLOAD_ARG_CNT 8
16
Ibai Erkiaga1327d162019-09-27 12:51:41 +020017struct zynqmp_power {
18 struct mbox_chan tx_chan;
19 struct mbox_chan rx_chan;
20} zynqmp_power;
21
Ibai Erkiaga490f6272019-09-27 11:37:00 +010022static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
23{
24 struct zynqmp_ipi_msg msg;
25 int ret;
26
27 if (req_len > PMUFW_PAYLOAD_ARG_CNT ||
28 res_maxlen > PMUFW_PAYLOAD_ARG_CNT)
29 return -EINVAL;
30
31 if (!(zynqmp_power.tx_chan.dev) || !(&zynqmp_power.rx_chan.dev))
32 return -EINVAL;
33
34 msg.buf = (u32 *)req;
35 msg.len = req_len;
36 ret = mbox_send(&zynqmp_power.tx_chan, &msg);
37 if (ret) {
38 debug("%s: Sending message failed\n", __func__);
39 return ret;
40 }
41
42 msg.buf = res;
43 msg.len = res_maxlen;
44 ret = mbox_recv(&zynqmp_power.rx_chan, &msg, 100);
45 if (ret)
46 debug("%s: Receiving message failed\n", __func__);
47
48 return ret;
49}
50
51unsigned int zynqmp_firmware_version(void)
52{
53 int ret;
54 u32 ret_payload[PAYLOAD_ARG_CNT];
55 static u32 pm_api_version = ZYNQMP_PM_VERSION_INVALID;
56
57 /*
58 * Get PMU version only once and later
59 * just return stored values instead of
60 * asking PMUFW again.
61 **/
62 if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) {
63 if (IS_ENABLED(CONFIG_SPL_BUILD)) {
64 const u32 request[] = { PM_GET_API_VERSION };
65
66 ret = ipi_req(request, ARRAY_SIZE(request),
67 ret_payload, 2);
68 } else {
69 ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0,
70 0, 0, ret_payload);
71 };
72
73 if (ret)
74 panic("PMUFW is not found - Please load it!\n");
75
76 pm_api_version = ret_payload[1];
77 if (pm_api_version < ZYNQMP_PM_VERSION)
78 panic("PMUFW version error. Expected: v%d.%d\n",
79 ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
80 }
81
82 return pm_api_version;
83};
84
Ibai Erkiaga1327d162019-09-27 12:51:41 +020085static int zynqmp_power_probe(struct udevice *dev)
86{
87 int ret = 0;
88
89 debug("%s, (dev=%p)\n", __func__, dev);
90
91 ret = mbox_get_by_name(dev, "tx", &zynqmp_power.tx_chan);
92 if (ret) {
93 debug("%s, cannot tx mailbox\n", __func__);
94 return ret;
95 }
96
97 ret = mbox_get_by_name(dev, "rx", &zynqmp_power.rx_chan);
Ibai Erkiaga490f6272019-09-27 11:37:00 +010098 if (ret) {
Ibai Erkiaga1327d162019-09-27 12:51:41 +020099 debug("%s, cannot rx mailbox\n", __func__);
Ibai Erkiaga490f6272019-09-27 11:37:00 +0100100 return ret;
101 }
Ibai Erkiaga1327d162019-09-27 12:51:41 +0200102
Ibai Erkiaga490f6272019-09-27 11:37:00 +0100103 ret = zynqmp_firmware_version();
104 printf("PMUFW:\tv%d.%d\n",
105 ret >> ZYNQMP_PM_VERSION_MAJOR_SHIFT,
106 ret & ZYNQMP_PM_VERSION_MINOR_MASK);
107
108 return 0;
Ibai Erkiaga1327d162019-09-27 12:51:41 +0200109};
110
111static const struct udevice_id zynqmp_power_ids[] = {
112 { .compatible = "xlnx,zynqmp-power" },
113 { }
114};
115
116U_BOOT_DRIVER(zynqmp_power) = {
117 .name = "zynqmp_power",
118 .id = UCLASS_FIRMWARE,
119 .of_match = zynqmp_power_ids,
120 .probe = zynqmp_power_probe,
121};
122#endif
123
Rajan Vaja14723ed2019-02-15 04:45:32 -0800124static const struct udevice_id zynqmp_firmware_ids[] = {
125 { .compatible = "xlnx,zynqmp-firmware" },
Siva Durga Prasad Paladugu95105082019-06-23 12:24:57 +0530126 { .compatible = "xlnx,versal-firmware"},
Rajan Vaja14723ed2019-02-15 04:45:32 -0800127 { }
128};
129
130U_BOOT_DRIVER(zynqmp_firmware) = {
131 .id = UCLASS_FIRMWARE,
132 .name = "zynqmp-firmware",
133 .probe = dm_scan_fdt_dev,
134 .of_match = zynqmp_firmware_ids,
135};