Commit a3e552b53fb85abce33a8e00bc430d014d7ee733
1 parent
b6039aad2d
Exists in
smarc_8mq_lf_v2020.04
and in
9 other branches
arm64: zynqmp: Use mailbox driver for PMUFW config loading
With new mailbox driver PMUFW configuration object can be loaded via the same interface and there is no need to have pmu_ipc.c completely. Signed-off-by: Michal Simek <michal.simek@xilinx.com> Reviewed-by: Luca Ceresoli <luca@lucaceresoli.net>
Showing 5 changed files with 25 additions and 118 deletions Side-by-side Diff
arch/arm/mach-zynqmp/Makefile
arch/arm/mach-zynqmp/include/mach/sys_proto.h
arch/arm/mach-zynqmp/pmu_ipc.c
1 | -// SPDX-License-Identifier: GPL-2.0+ | |
2 | -/* | |
3 | - * Inter-Processor Communication with the Platform Management Unit (PMU) | |
4 | - * firmware. | |
5 | - * | |
6 | - * (C) Copyright 2019 Luca Ceresoli | |
7 | - * Luca Ceresoli <luca@lucaceresoli.net> | |
8 | - */ | |
9 | - | |
10 | -#include <common.h> | |
11 | -#include <asm/io.h> | |
12 | -#include <asm/arch/sys_proto.h> | |
13 | - | |
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 | |
21 | - | |
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 | |
27 | - | |
28 | -#define PMUFW_PAYLOAD_ARG_CNT 8 | |
29 | - | |
30 | -/* PMUFW commands */ | |
31 | -#define PMUFW_CMD_SET_CONFIGURATION 2 | |
32 | - | |
33 | -static void pmu_ipc_send_request(const u32 *req, size_t req_len) | |
34 | -{ | |
35 | - u32 *mbx = (u32 *)(IPI_BUF_BASE_APU + | |
36 | - IPI_BUF_OFFSET_TARGET_PMU + | |
37 | - IPI_BUF_OFFSET_REQ); | |
38 | - size_t i; | |
39 | - | |
40 | - for (i = 0; i < req_len; i++) | |
41 | - writel(req[i], &mbx[i]); | |
42 | -} | |
43 | - | |
44 | -static void pmu_ipc_read_response(unsigned int *value, size_t count) | |
45 | -{ | |
46 | - u32 *mbx = (u32 *)(IPI_BUF_BASE_APU + | |
47 | - IPI_BUF_OFFSET_TARGET_PMU + | |
48 | - IPI_BUF_OFFSET_RESP); | |
49 | - size_t i; | |
50 | - | |
51 | - for (i = 0; i < count; i++) | |
52 | - value[i] = readl(&mbx[i]); | |
53 | -} | |
54 | - | |
55 | -/** | |
56 | - * Send request to PMU and get the response. | |
57 | - * | |
58 | - * @req: Request buffer. Byte 0 is the API ID, other bytes are optional | |
59 | - * parameters. | |
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 | |
63 | - * will not be read. | |
64 | - * @res_maxlen: Space allocated for the response in number of 32-bit words. | |
65 | - * | |
66 | - * @return Error code returned by the PMU (i.e. the first word of the response) | |
67 | - */ | |
68 | -static int pmu_ipc_request(const u32 *req, size_t req_len, | |
69 | - u32 *res, size_t res_maxlen) | |
70 | -{ | |
71 | - u32 status; | |
72 | - | |
73 | - if (req_len > PMUFW_PAYLOAD_ARG_CNT || | |
74 | - res_maxlen > PMUFW_PAYLOAD_ARG_CNT) | |
75 | - return -EINVAL; | |
76 | - | |
77 | - pmu_ipc_send_request(req, req_len); | |
78 | - | |
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); | |
81 | - do { | |
82 | - status = readl(IPI_REG_BASE_APU + IPI_REG_OFFSET_OBR); | |
83 | - } while (status & IPI_BIT_MASK_PMU0); | |
84 | - | |
85 | - pmu_ipc_read_response(res, res_maxlen); | |
86 | - | |
87 | - return 0; | |
88 | -} | |
89 | - | |
90 | -/** | |
91 | - * Send a configuration object to the PMU firmware. | |
92 | - * | |
93 | - * @cfg_obj: Pointer to the configuration object | |
94 | - * @size: Size of @cfg_obj in bytes | |
95 | - */ | |
96 | -void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) | |
97 | -{ | |
98 | - const u32 request[] = { | |
99 | - PMUFW_CMD_SET_CONFIGURATION, | |
100 | - (u32)((u64)cfg_obj) | |
101 | - }; | |
102 | - u32 response; | |
103 | - int err; | |
104 | - | |
105 | - printf("Loading PMUFW cfg obj (%ld bytes)\n", size); | |
106 | - | |
107 | - err = pmu_ipc_request(request, ARRAY_SIZE(request), &response, 1); | |
108 | - if (err) | |
109 | - panic("Cannot load PMUFW configuration object (%d)\n", err); | |
110 | - if (response != 0) | |
111 | - panic("PMUFW returned 0x%08x status!\n", response); | |
112 | -} |
drivers/firmware/firmware-zynqmp.c
... | ... | @@ -84,6 +84,30 @@ |
84 | 84 | return pm_api_version; |
85 | 85 | }; |
86 | 86 | |
87 | +/** | |
88 | + * Send a configuration object to the PMU firmware. | |
89 | + * | |
90 | + * @cfg_obj: Pointer to the configuration object | |
91 | + * @size: Size of @cfg_obj in bytes | |
92 | + */ | |
93 | +void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) | |
94 | +{ | |
95 | + const u32 request[] = { | |
96 | + PM_SET_CONFIGURATION, | |
97 | + (u32)((u64)cfg_obj) | |
98 | + }; | |
99 | + u32 response; | |
100 | + int err; | |
101 | + | |
102 | + printf("Loading new PMUFW cfg obj (%ld bytes)\n", size); | |
103 | + | |
104 | + err = send_req(request, ARRAY_SIZE(request), &response, 1); | |
105 | + if (err) | |
106 | + panic("Cannot load PMUFW configuration object (%d)\n", err); | |
107 | + if (response != 0) | |
108 | + panic("PMUFW returned 0x%08x status!\n", response); | |
109 | +} | |
110 | + | |
87 | 111 | static int zynqmp_power_probe(struct udevice *dev) |
88 | 112 | { |
89 | 113 | int ret = 0; |
include/zynqmp_firmware.h