X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Ffirmware%2Ffirmware-zynqmp.c;h=903a8f5878203a5e7216929ab527a40dc471edbd;hb=7a1a01c6029039e4fa6aa185cdbbf9a357eecba7;hp=d11740ac772d3f04b70dea9ac12764694257b924;hpb=6596270ecb5d74d5f997da0daa728e06d1f47029;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index d11740a..903a8f5 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -7,7 +7,10 @@ #include #include +#include #include +#include +#include #if defined(CONFIG_ZYNQMP_IPI) #include @@ -15,6 +18,8 @@ #define PMUFW_PAYLOAD_ARG_CNT 8 +#define XST_PM_NO_ACCESS 2002L + struct zynqmp_power { struct mbox_chan tx_chan; struct mbox_chan rx_chan; @@ -32,6 +37,7 @@ static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen) if (!(zynqmp_power.tx_chan.dev) || !(&zynqmp_power.rx_chan.dev)) return -EINVAL; + debug("%s, Sending IPI message with ID: 0x%0x\n", __func__, req[0]); msg.buf = (u32 *)req; msg.len = req_len; ret = mbox_send(&zynqmp_power.tx_chan, &msg); @@ -49,14 +55,6 @@ static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen) return ret; } -static int send_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen) -{ - if (IS_ENABLED(CONFIG_SPL_BUILD)) - return ipi_req(req, req_len, res, res_maxlen); - - return invoke_smc(req[0] + PM_SIP_SVC, 0, 0, 0, 0, res); -} - unsigned int zynqmp_firmware_version(void) { int ret; @@ -69,9 +67,9 @@ unsigned int zynqmp_firmware_version(void) * asking PMUFW again. **/ if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) { - const u32 request[] = { PM_GET_API_VERSION }; - ret = send_req(request, ARRAY_SIZE(request), ret_payload, 2); + ret = xilinx_pm_request(PM_GET_API_VERSION, 0, 0, 0, 0, + ret_payload); if (ret) panic("PMUFW is not found - Please load it!\n"); @@ -92,37 +90,43 @@ unsigned int zynqmp_firmware_version(void) */ void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) { - const u32 request[] = { - PM_SET_CONFIGURATION, - (u32)((u64)cfg_obj) - }; - u32 response; int err; + u32 ret_payload[PAYLOAD_ARG_CNT]; printf("Loading new PMUFW cfg obj (%ld bytes)\n", size); - err = send_req(request, ARRAY_SIZE(request), &response, 1); + err = xilinx_pm_request(PM_SET_CONFIGURATION, (u32)(u64)cfg_obj, 0, 0, + 0, ret_payload); + if (err == XST_PM_NO_ACCESS) { + printf("PMUFW no permission to change config object\n"); + return; + } + if (err) - panic("Cannot load PMUFW configuration object (%d)\n", err); - if (response != 0) - panic("PMUFW returned 0x%08x status!\n", response); + printf("Cannot load PMUFW configuration object (%d)\n", err); + + if (ret_payload[0]) + printf("PMUFW returned 0x%08x status!\n", ret_payload[0]); + + if ((err || ret_payload[0]) && IS_ENABLED(CONFIG_SPL_BUILD)) + panic("PMUFW config object loading failed in EL3\n"); } static int zynqmp_power_probe(struct udevice *dev) { - int ret = 0; + int ret; debug("%s, (dev=%p)\n", __func__, dev); ret = mbox_get_by_name(dev, "tx", &zynqmp_power.tx_chan); if (ret) { - debug("%s, cannot tx mailbox\n", __func__); + debug("%s: Cannot find tx mailbox\n", __func__); return ret; } ret = mbox_get_by_name(dev, "rx", &zynqmp_power.rx_chan); if (ret) { - debug("%s, cannot rx mailbox\n", __func__); + debug("%s: Cannot find rx mailbox\n", __func__); return ret; } @@ -147,40 +151,47 @@ U_BOOT_DRIVER(zynqmp_power) = { }; #endif -int __maybe_unused invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, - u32 arg3, u32 *ret_payload) -{ - /* - * Added SIP service call Function Identifier - * Make sure to stay in x0 register - */ - struct pt_regs regs; - - if (current_el() == 3) - return 0; - - regs.regs[0] = pm_api_id; - regs.regs[1] = ((u64)arg1 << 32) | arg0; - regs.regs[2] = ((u64)arg3 << 32) | arg2; - - smc_call(®s); - - if (ret_payload) { - ret_payload[0] = (u32)regs.regs[0]; - ret_payload[1] = upper_32_bits(regs.regs[0]); - ret_payload[2] = (u32)regs.regs[1]; - ret_payload[3] = upper_32_bits(regs.regs[1]); - ret_payload[4] = (u32)regs.regs[2]; - } - - return regs.regs[0]; -} - int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 *ret_payload) { - return invoke_smc(PM_SIP_SVC | api_id, arg0, arg1, arg2, arg3, - ret_payload); + debug("%s at EL%d, API ID: 0x%0x\n", __func__, current_el(), api_id); + + if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { +#if defined(CONFIG_ZYNQMP_IPI) + /* + * Use fixed payload and arg size as the EL2 call. The firmware + * is capable to handle PMUFW_PAYLOAD_ARG_CNT bytes but the + * firmware API is limited by the SMC call size + */ + u32 regs[] = {api_id, arg0, arg1, arg2, arg3}; + + ipi_req(regs, PAYLOAD_ARG_CNT, ret_payload, PAYLOAD_ARG_CNT); +#else + return -EPERM; +#endif + } else { + /* + * Added SIP service call Function Identifier + * Make sure to stay in x0 register + */ + struct pt_regs regs; + + regs.regs[0] = PM_SIP_SVC | api_id; + regs.regs[1] = ((u64)arg1 << 32) | arg0; + regs.regs[2] = ((u64)arg3 << 32) | arg2; + + smc_call(®s); + + if (ret_payload) { + ret_payload[0] = (u32)regs.regs[0]; + ret_payload[1] = upper_32_bits(regs.regs[0]); + ret_payload[2] = (u32)regs.regs[1]; + ret_payload[3] = upper_32_bits(regs.regs[1]); + ret_payload[4] = (u32)regs.regs[2]; + } + + } + return (ret_payload) ? ret_payload[0] : 0; } static const struct udevice_id zynqmp_firmware_ids[] = { @@ -192,6 +203,5 @@ static const struct udevice_id zynqmp_firmware_ids[] = { U_BOOT_DRIVER(zynqmp_firmware) = { .id = UCLASS_FIRMWARE, .name = "zynqmp-firmware", - .probe = dm_scan_fdt_dev, .of_match = zynqmp_firmware_ids, };