1 // SPDX-License-Identifier: GPL-2.0+
3 * Inter-Processor Communication with the Platform Management Unit (PMU)
6 * (C) Copyright 2019 Luca Ceresoli
7 * Luca Ceresoli <luca@lucaceresoli.net>
12 #include <asm/arch/sys_proto.h>
14 /* IPI bitmasks, register base and register offsets */
15 #define IPI_BIT_MASK_APU 0x00001
16 #define IPI_BIT_MASK_PMU0 0x10000
17 #define IPI_REG_BASE_APU 0xFF300000
18 #define IPI_REG_BASE_PMU0 0xFF330000
19 #define IPI_REG_OFFSET_TRIG 0x00
20 #define IPI_REG_OFFSET_OBR 0x04
22 /* IPI mailbox buffer offsets */
23 #define IPI_BUF_BASE_APU 0xFF990400
24 #define IPI_BUF_OFFSET_TARGET_PMU 0x1C0
25 #define IPI_BUF_OFFSET_REQ 0x00
26 #define IPI_BUF_OFFSET_RESP 0x20
28 #define PMUFW_PAYLOAD_ARG_CNT 8
31 #define PMUFW_CMD_SET_CONFIGURATION 2
33 static void pmu_ipc_send_request(const u32 *req, size_t req_len)
35 u32 *mbx = (u32 *)(IPI_BUF_BASE_APU +
36 IPI_BUF_OFFSET_TARGET_PMU +
40 for (i = 0; i < req_len; i++)
41 writel(req[i], &mbx[i]);
44 static void pmu_ipc_read_response(unsigned int *value, size_t count)
46 u32 *mbx = (u32 *)(IPI_BUF_BASE_APU +
47 IPI_BUF_OFFSET_TARGET_PMU +
51 for (i = 0; i < count; i++)
52 value[i] = readl(&mbx[i]);
56 * Send request to PMU and get the response.
58 * @req: Request buffer. Byte 0 is the API ID, other bytes are optional
60 * @req_len: Request length in number of 32-bit words.
61 * @res: Response buffer. Byte 0 is the error code, other bytes are
62 * optional parameters. Optional, if @res_maxlen==0 the parameters
64 * @res_maxlen: Space allocated for the response in number of 32-bit words.
66 * @return Error code returned by the PMU (i.e. the first word of the response)
68 static int pmu_ipc_request(const u32 *req, size_t req_len,
69 u32 *res, size_t res_maxlen)
73 if (req_len > PMUFW_PAYLOAD_ARG_CNT ||
74 res_maxlen > PMUFW_PAYLOAD_ARG_CNT)
77 pmu_ipc_send_request(req, req_len);
79 /* Raise Inter-Processor Interrupt to PMU and wait for response */
80 writel(IPI_BIT_MASK_PMU0, IPI_REG_BASE_APU + IPI_REG_OFFSET_TRIG);
82 status = readl(IPI_REG_BASE_APU + IPI_REG_OFFSET_OBR);
83 } while (status & IPI_BIT_MASK_PMU0);
85 pmu_ipc_read_response(res, res_maxlen);
91 * Send a configuration object to the PMU firmware.
93 * @cfg_obj: Pointer to the configuration object
94 * @size: Size of @cfg_obj in bytes
96 void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size)
98 const u32 request[] = {
99 PMUFW_CMD_SET_CONFIGURATION,
105 printf("Loading PMUFW cfg obj (%ld bytes)\n", size);
107 err = pmu_ipc_request(request, ARRAY_SIZE(request), &response, 1);
109 panic("Cannot load PMUFW configuration object (%d)\n", err);
111 panic("PMUFW returned 0x%08x status!\n", response);