};
#endif
+static const char *const pinctrl_functions[] = {
+ "can0",
+ "can1",
+ "ethernet0",
+ "ethernet1",
+ "ethernet2",
+ "ethernet3",
+ "gemtsu0",
+ "gpio0",
+ "i2c0",
+ "i2c1",
+ "mdio0",
+ "mdio1",
+ "mdio2",
+ "mdio3",
+ "qspi0",
+ "qspi_fbclk",
+ "qspi_ss",
+ "spi0",
+ "spi1",
+ "spi0_ss",
+ "spi1_ss",
+ "sdio0",
+ "sdio0_pc",
+ "sdio0_cd",
+ "sdio0_wp",
+ "sdio1",
+ "sdio1_pc",
+ "sdio1_cd",
+ "sdio1_wp",
+ "nand0",
+ "nand0_ce",
+ "nand0_rb",
+ "nand0_dqs",
+ "ttc0_clk",
+ "ttc0_wav",
+ "ttc1_clk",
+ "ttc1_wav",
+ "ttc2_clk",
+ "ttc2_wav",
+ "ttc3_clk",
+ "ttc3_wav",
+ "uart0",
+ "uart1",
+ "usb0",
+ "usb1",
+ "swdt0_clk",
+ "swdt0_rst",
+ "swdt1_clk",
+ "swdt1_rst",
+ "pmu0",
+ "pcie0",
+ "csu0",
+ "dpaux0",
+ "pjtag0",
+ "trace0",
+ "trace0_clk",
+ "testscan0",
+};
+
+/*
+ * PM_QUERY_DATA is implemented by ATF and not the PMU firmware, so we have to
+ * emulate it in SPL. Just implement functions/pins since the groups take up a
+ * lot of rodata and are mostly superfluous.
+ */
+static int zynqmp_pm_query_data(enum pm_query_id qid, u32 arg1, u32 arg2,
+ u32 *ret_payload)
+{
+ switch (qid) {
+ case PM_QID_PINCTRL_GET_NUM_PINS:
+ ret_payload[1] = 78; /* NUM_PINS */
+ ret_payload[0] = 0;
+ return 0;
+ case PM_QID_PINCTRL_GET_NUM_FUNCTIONS:
+ ret_payload[1] = ARRAY_SIZE(pinctrl_functions);
+ ret_payload[0] = 0;
+ return 0;
+ case PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS:
+ ret_payload[1] = 0;
+ ret_payload[0] = 0;
+ return 0;
+ case PM_QID_PINCTRL_GET_FUNCTION_NAME:
+ assert(arg1 < ARRAY_SIZE(pinctrl_functions));
+ memset(ret_payload, 0, MAX_FUNC_NAME_LEN);
+ strcpy((char *)ret_payload, pinctrl_functions[arg1]);
+ return 0;
+ case PM_QID_PINCTRL_GET_FUNCTION_GROUPS:
+ case PM_QID_PINCTRL_GET_PIN_GROUPS:
+ memset(ret_payload + 1, 0xff,
+ sizeof(s16) * NUM_GROUPS_PER_RESP);
+ ret_payload[0] = 0;
+ return 0;
+ default:
+ ret_payload[0] = 1;
+ return 1;
+ }
+}
+
smc_call_handler_t __data smc_call_handler;
static int smc_call_legacy(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
__func__, current_el(), api_id, arg0, arg1, arg2, arg3, arg4, arg5);
if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) {
+ if (CONFIG_IS_ENABLED(PINCTRL_ZYNQMP) &&
+ api_id == PM_QUERY_DATA)
+ return zynqmp_pm_query_data(arg0, arg1, arg2, ret_payload);
#if defined(CONFIG_ZYNQMP_IPI)
/*
* Use fixed payload and arg size as the EL2 call. The firmware
Generic Pinctrl framework and is compatible with the Linux driver,
i.e. it uses the same device tree configuration.
+config SPL_PINCTRL_ZYNQMP
+ bool "Xilinx ZynqMP pin control driver in SPL"
+ depends on SPL_DM && SPL_PINCTRL_GENERIC && ARCH_ZYNQMP
+ default PINCTRL_ZYNQMP
+ help
+ Support pin multiplexing control in SPL on Xilinx ZynqMP. Only "pins"
+ can be muxed; "groups" are not supported.
+
endif
source "drivers/pinctrl/broadcom/Kconfig"
#include <linux/compat.h>
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
-#define PINCTRL_GET_FUNC_GROUPS_RESP_LEN 12
-#define PINCTRL_GET_PIN_GROUPS_RESP_LEN 12
-#define NUM_GROUPS_PER_RESP 6
-#define NA_GROUP -1
-#define RESERVED_GROUP -2
+#define PINCTRL_GET_FUNC_GROUPS_RESP_LEN (sizeof(s16) * NUM_GROUPS_PER_RESP)
+#define PINCTRL_GET_PIN_GROUPS_RESP_LEN (sizeof(s16) * NUM_GROUPS_PER_RESP)
#define MAX_GROUP_PIN 50
#define MAX_PIN_GROUPS 50
#define MAX_GROUP_NAME_LEN 32
-#define MAX_FUNC_NAME_LEN 16
#define DRIVE_STRENGTH_2MA 2
#define DRIVE_STRENGTH_4MA 4
PM_QID_CLOCK_GET_MAX_DIVISOR = 13,
};
+#define NUM_GROUPS_PER_RESP 6
+#define NA_GROUP -1
+#define RESERVED_GROUP -2
+#define MAX_FUNC_NAME_LEN 16
+
enum pm_pinctrl_config_param {
PM_PINCTRL_CONFIG_SLEW_RATE = 0,
PM_PINCTRL_CONFIG_BIAS_STATUS = 1,