From mboxrd@z Thu Jan 1 00:00:00 1970 From: Mike Looijmans Date: Thu, 4 Apr 2019 05:38:34 +0000 Subject: [U-Boot] [RFC v2 2/2] arm64: zynqmp: spl: install a PMU firmware config object at runtime In-Reply-To: <5bbdd18b-1e19-523f-1406-16a7f9d60a03@lucaceresoli.net> References: <20190321154857.29892-1-luca@lucaceresoli.net> <20190321154857.29892-3-luca@lucaceresoli.net> <55a5e990-737e-35e0-8f37-c953c9962d8a@lucaceresoli.net> <5bbdd18b-1e19-523f-1406-16a7f9d60a03@lucaceresoli.net> Message-ID: <47d3c08a-1188-095e-da3e-425e90d6e9aa@topic.nl> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 03-04-19 23:18, Luca Ceresoli wrote: > Hi Mike, > > On 03/04/19 13:24, Mike Looijmans wrote: >> On 29-03-19 13:22, Luca Ceresoli wrote: >>> Hi Michal, >>> >>> thanks for the feedback. >>> >>> On 27/03/19 16:03, Michal Simek wrote: >>>> On 21. 03. 19 16:48, Luca Ceresoli wrote: >>>>> Optionally allow U-Boot to load at the PMU firmware configuration object >>>>> into the Power Management Unit (PMU) on Xilinx ZynqMP. >>>>> >>>>> The configuration object is required by the PMU FW to enable most SoC >>>>> peripherals. So far the only way to boot using U-Boot SPL was to hard-code >>>>> the configuration object in the PMU firmware. Allow a different boot >>>>> process, where the PMU FW is equal for any ZynqMP chip and its >>>>> configuration is passed at runtime by U-Boot SPL. >>>>> >>>>> All the code for Inter-processor communication with the PMU is isolated in >>>>> a new file (pmu_ipc.c). The code is inspired by the same feature as >>>>> implemented in the Xilinx First Stage Bootloader (FSBL) and Arm Trusted >>>>> Firmware: >>>>> >>>>> * https://github.com/Xilinx/embeddedsw/blob/fb647e6b4c00f5154eba52a88b948195b6f1dc2b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_misc_drivers.c#L295 >>>>> * https://github.com/ARM-software/arm-trusted-firmware/blob/c48d02bade88b07fa7f43aa44e5217f68e5d047f/plat/xilinx/zynqmp/pm_service/pm_api_sys.c#L357 >>>>> >>>>> The load is logged on the console during boot: >>>>> >>>>> U-Boot SPL 2018.01 (Mar 20 2019 - 08:12:21) >>>>> Loading PMUFW cfg obj (2008 bytes) >>>>> EL Level: EL3 >>>>> ... >>>>> >>>>> Signed-off-by: Luca Ceresoli >>> [...] >>>>> diff --git a/board/xilinx/zynqmp/pmu_ipc.c b/board/xilinx/zynqmp/pmu_ipc.c >>>>> new file mode 100644 >>>>> index 000000000000..6306d33d6f17 >>>>> --- /dev/null >>>>> +++ b/board/xilinx/zynqmp/pmu_ipc.c >>>>> @@ -0,0 +1,116 @@ >>>>> +// SPDX-License-Identifier: GPL-2.0+ >>>>> +/* >>>>> + * Inter-Processor Communication with the Platform Management Unit (PMU) >>>>> + * firmware. >>> [...] >>>>> +static int pmu_ipc_request(const u32 *req, size_t req_len, >>>>> + u32 *res, size_t res_maxlen) >>>>> +{ >>>>> + u32 status; >>>>> + >>>>> + if (req_len > PMUFW_PAYLOAD_ARG_CNT || >>>>> + res_maxlen > PMUFW_PAYLOAD_ARG_CNT) >>>>> + return -EINVAL; >>>>> + >>>>> + pmu_ipc_send_request(req, req_len); >>>>> + >>>>> + /* Raise Inter-Processor Interrupt to PMU and wait for response */ >>>>> + writel(IPI_BIT_MASK_PMU0, IPI_REG_BASE_APU + IPI_REG_OFFSET_TRIG); >>>>> + do { >>>>> + status = readl(IPI_REG_BASE_APU + IPI_REG_OFFSET_OBR); >>>>> + } while (status & IPI_BIT_MASK_PMU0); >>>>> + >>>>> + pmu_ipc_read_response(res, res_maxlen); >>>>> + >>>>> + return 0; >>>>> +} >>>> >>>> All above should be mailbox driver. It means this should go to >>>> drivers/mailbox and be split to mbox send/recv functions. >>> >>> Oh, wow, there's a mailbox uclass! I'll have a look into it. >>> >>>> But I have no problem to use this configuration in the first patch and >>>> move to mbox driver in separate patch. >>> >>> Good to know, I'll use this option in case it takes too long to make it >>> a proper mailbox driver. >>> >>>>> +/** >>>>> + * Send a configuration object to the PMU firmware. >>>>> + * >>>>> + * @cfg_obj Pointer to the configuration object >>>>> + * @size Size of @cfg_obj in bytes >>>>> + */ >>>>> +void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) >>>>> +{ >>>>> + const u32 *ocm = (u32 *)CONFIG_SPL_TEXT_BASE; >>>>> + const u32 request[] = { >>>>> + PMUFW_CMD_SET_CONFIGURATION, >>>>> + CONFIG_SPL_TEXT_BASE >>>>> + }; >>>>> + u32 response; >>>>> + int err; >>>>> + >>>>> + printf("Loading PMUFW cfg obj (%ld bytes)\n", size); >>>>> + >>>>> + memcpy(ocm, cfg_obj, size); >>>>> + >>>>> + err = pmu_ipc_request(request, ARRAY_SIZE(request), &response, 1); >>>>> + if (err) >>>>> + panic("Cannot load PMUFW configuration object (%d)\n", err); >>>>> + if (response != 0) >>>>> + panic("PMUFW returned 0x%08x status!\n", response); >>>>> +} >>>> >>>> And this can stay here or go to arch/arm/mach-zynq/ >>> >>> Ok, I'll move it to arch/arm/mach-zynq/pmu.c or so. >>> >>> I assume "zynq" here means the whole zynq family, including zynqmp. >>> >>>>> diff --git a/board/xilinx/zynqmp/pmu_ipc.h b/board/xilinx/zynqmp/pmu_ipc.h >>>>> new file mode 100644 >>>>> index 000000000000..37bb72c1b20a >>>>> --- /dev/null >>>>> +++ b/board/xilinx/zynqmp/pmu_ipc.h >>>>> @@ -0,0 +1,14 @@ >>>>> +/* SPDX-License-Identifier: GPL-2.0+ */ >>>>> +/* >>>>> + * (C) Copyright 2019 Luca Ceresoli >>>>> + * Luca Ceresoli >>>>> + */ >>>>> + >>>>> +#ifndef __ZYNQMP_PMU_IPC_H__ >>>>> +#define __ZYNQMP_PMU_IPC_H__ >>>>> + >>>>> +#include >>>>> + >>>>> +void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size); >>>>> + >>>> >>>> >>>> arch/arm/mach-zynqmp/include/mach/sys_proto.h should be fine. >>> >>> Ok, but I guess you mean s/zynqmp/zynq/, as above. >>> >>>>> +#endif /* __ZYNQMP_PMU_IPC_H__ */ >>>>> diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c >>>>> index 5e1d2116bc32..1d5e25961863 100644 >>>>> --- a/board/xilinx/zynqmp/zynqmp.c >>>>> +++ b/board/xilinx/zynqmp/zynqmp.c >>>>> @@ -4,6 +4,8 @@ >>>>> * Michal Simek >>>>> */ >>>>> >>>>> +#include "pmu_ipc.h" >>>>> + >>>>> #include >>>>> #include >>>>> #include >>>>> @@ -302,6 +304,10 @@ static char *zynqmp_get_silicon_idcode_name(void) >>>>> } >>>>> #endif >>>>> >>>>> +#ifdef ZYNQMP_LOAD_PM_CFG_OBJ >>>>> +#include CONFIG_ZYNQMP_LOAD_PM_CFG_OBJ_FILE >>>>> +#endif >>>>> + >>>>> int board_early_init_f(void) >>>>> { >>>>> int ret = 0; >>>>> @@ -332,6 +338,11 @@ int board_early_init_f(void) >>>>> >>>>> int board_init(void) >>>>> { >>>>> +#if defined(CONFIG_SPL_BUILD) && defined(ZYNQMP_LOAD_PM_CFG_OBJ) >>>>> + zynqmp_pmufw_load_config_object(XPm_ConfigObject, >>>>> + sizeof(XPm_ConfigObject)); >>>>> +#endif >>>> >>>> As we discussed over IRC. I think that this should be simply bin >>>> firmware file compare to C built by u-boot. >>> >>> Sure. I have a working prototype that uses a binary blob. It still needs >>> a decent way to produce a blob and to be updated according to your review. >> >> It should be doable to write a Python script to parse the C file and create an >> equivalent binary (using "struct" module) which is just an array of integers >> in the end. That avoids the need for a microblaze C compiler... > > There's no need for a microblaze compiler. pm_cfg_obj.c is simply > declaring a u32 array and some #defines, any C compiler is enough. > > That said, my current solution (a trivial main.c that compiles the u32 > array and outputs it to a binary file) is not nice at all, and it > requires a pm_defs.h file. > > The python script you mention looks way better from a user perspective, > although the parsing might be a bit fragile. I'll consider it, thanks > for the suggestion. > > In the past I even prototyped a python script that parses the Vivado > .xpr project file and produces a pm_cfg_obj.c. It avoided the need to > run the Xilinx XSDK just to generate pm_cfg_obj.c. It might also be > extended to produce a .bin directly, or a self-standing .c file that > doesn't need pm_defs.h, thus removing any licensing issue. But it never > grew complete to handle all cases. Obvious, since *I* don't even know > all of the cases. :) Another approach would be to simply create and include a "god mode" config object that just allows access to all periferals. As far as I can see, such a config object would just work on all boards. There's nothing really board specific in the config object, and it's rather lame anyway to have to go and compile a new bootloader just because you want to use a SPI controller... The config object I compile into the pmu firmware is of that type anyway.