From 1818c029252914b7d5c93915789c7cef32ffcfd7 Mon Sep 17 00:00:00 2001 From: Rajan Vaja Date: Wed, 17 Jan 2018 02:39:24 -0800 Subject: [PATCH] zynqmp: pm: Implement IOCTL APIs for device control Implement ioctl APIs which uses MMIO operations to configure devices. Below IOCTLs are supported in this patch: * Set tap delay bypass * Set SGMII mode * SD reset * Set SD/MMC tap delay Signed-off-by: Rajan Vaja Signed-off-by: Jolly Shah --- plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c | 201 +++++++++++++++++++ plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h | 32 +++ plat/xilinx/zynqmp/zynqmp_def.h | 39 ++++ 3 files changed, 272 insertions(+) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c index 6f94f420f..c881d1248 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c @@ -140,6 +140,195 @@ static enum pm_ret_status pm_ioctl_config_tcm_comb(unsigned int value) return PM_RET_SUCCESS; } +/** + * pm_ioctl_set_tapdelay_bypass() - Enable/Disable tap delay bypass + * @type Type of tap delay to enable/disable (e.g. QSPI) + * @value Enable/Disable + * + * This function enable/disable tap delay bypass. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ioctl_set_tapdelay_bypass(unsigned int type, + unsigned int value) +{ + if ((value != PM_TAPDELAY_BYPASS_ENABLE && + value != PM_TAPDELAY_BYPASS_DISABLE) || type >= PM_TAPDELAY_MAX) + return PM_RET_ERROR_ARGS; + + return pm_mmio_write(IOU_TAPDLY_BYPASS, TAP_DELAY_MASK, value << type); +} + +/** + * pm_ioctl_set_sgmii_mode() - Set SGMII mode for the GEM device + * @nid Node ID of the device + * @value Enable/Disable + * + * This function enable/disable SGMII mode for the GEM device. + * While enabling SGMII mode, it also ties the GEM PCS Signal + * Detect to 1 and selects EMIO for RX clock generation. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ioctl_set_sgmii_mode(enum pm_node_id nid, + unsigned int value) +{ + unsigned int val, mask, shift; + int ret; + + if (value != PM_SGMII_DISABLE && value != PM_SGMII_ENABLE) + return PM_RET_ERROR_ARGS; + + switch (nid) { + case NODE_ETH_0: + shift = 0; + break; + case NODE_ETH_1: + shift = 1; + break; + case NODE_ETH_2: + shift = 2; + break; + case NODE_ETH_3: + shift = 3; + break; + default: + return PM_RET_ERROR_ARGS; + } + + if (value == PM_SGMII_DISABLE) { + mask = GEM_SGMII_MASK << GEM_CLK_CTRL_OFFSET * shift; + ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, 0); + } else { + /* Tie the GEM PCS Signal Detect to 1 */ + mask = SGMII_SD_MASK << SGMII_SD_OFFSET * shift; + val = SGMII_PCS_SD_1 << SGMII_SD_OFFSET * shift; + ret = pm_mmio_write(IOU_GEM_CTRL, mask, val); + if (ret) + return ret; + + /* Set the GEM to SGMII mode */ + mask = GEM_CLK_CTRL_MASK << GEM_CLK_CTRL_OFFSET * shift; + val = GEM_RX_SRC_SEL_GTR | GEM_SGMII_MODE; + val <<= GEM_CLK_CTRL_OFFSET * shift; + ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, val); + } + + return ret; +} + +/** + * pm_ioctl_sd_dll_reset() - Reset DLL logic + * @nid Node ID of the device + * @type Reset type + * + * This function resets DLL logic for the SD device. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ioctl_sd_dll_reset(enum pm_node_id nid, + unsigned int type) +{ + unsigned int mask, val; + int ret; + + if (nid == NODE_SD_0) { + mask = ZYNQMP_SD0_DLL_RST_MASK; + val = ZYNQMP_SD0_DLL_RST; + } else if (nid == NODE_SD_1) { + mask = ZYNQMP_SD1_DLL_RST_MASK; + val = ZYNQMP_SD1_DLL_RST; + } else { + return PM_RET_ERROR_ARGS; + } + + switch (type) { + case PM_DLL_RESET_ASSERT: + case PM_DLL_RESET_PULSE: + ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, val); + if (ret) + return ret; + + if (type == PM_DLL_RESET_ASSERT) + break; + mdelay(1); + case PM_DLL_RESET_RELEASE: + ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, 0); + break; + default: + ret = PM_RET_ERROR_ARGS; + } + + return ret; +} + +/** + * pm_ioctl_sd_set_tapdelay() - Set tap delay for the SD device + * @nid Node ID of the device + * @type Type of tap delay to set (input/output) + * @value Value to set fot the tap delay + * + * This function sets input/output tap delay for the SD device. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ioctl_sd_set_tapdelay(enum pm_node_id nid, + enum tap_delay_type type, + unsigned int value) +{ + unsigned int shift; + int ret; + + if (nid == NODE_SD_0) + shift = 0; + else if (nid == NODE_SD_1) + shift = ZYNQMP_SD_TAP_OFFSET; + else + return PM_RET_ERROR_ARGS; + + ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_ASSERT); + if (ret) + return ret; + + if (type == PM_TAPDELAY_INPUT) { + ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY, + ZYNQMP_SD_ITAPCHGWIN_MASK << shift, + ZYNQMP_SD_ITAPCHGWIN << shift); + if (ret) + goto reset_release; + ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY, + ZYNQMP_SD_ITAPDLYENA_MASK << shift, + ZYNQMP_SD_ITAPDLYENA << shift); + if (ret) + goto reset_release; + ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY, + ZYNQMP_SD_ITAPDLYSEL_MASK << shift, + value << shift); + if (ret) + goto reset_release; + ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY, + ZYNQMP_SD_ITAPCHGWIN_MASK << shift, 0); + } else if (type == PM_TAPDELAY_OUTPUT) { + ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY, + ZYNQMP_SD_OTAPDLYENA_MASK << shift, + ZYNQMP_SD_OTAPDLYENA << shift); + if (ret) + goto reset_release; + ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY, + ZYNQMP_SD_OTAPDLYSEL_MASK << shift, + value << shift); + } else { + ret = PM_RET_ERROR_ARGS; + } + +reset_release: + ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_RELEASE); + if (ret) + return ret; + + return ret; +} + /** * pm_api_ioctl() - PM IOCTL API for device control and configs * @node_id Node ID of the device @@ -173,6 +362,18 @@ enum pm_ret_status pm_api_ioctl(enum pm_node_id nid, case IOCTL_TCM_COMB_CONFIG: ret = pm_ioctl_config_tcm_comb(arg1); break; + case IOCTL_SET_TAPDELAY_BYPASS: + ret = pm_ioctl_set_tapdelay_bypass(arg1, arg2); + break; + case IOCTL_SET_SGMII_MODE: + ret = pm_ioctl_set_sgmii_mode(nid, arg1); + break; + case IOCTL_SD_DLL_RESET: + ret = pm_ioctl_sd_dll_reset(nid, arg1); + break; + case IOCTL_SET_SD_TAPDELAY: + ret = pm_ioctl_sd_set_tapdelay(nid, arg1, arg2); + break; default: ret = PM_RET_ERROR_NOTSUPPORTED; } diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h index 9dae69fed..a7f14a477 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h +++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h @@ -18,6 +18,10 @@ enum pm_ioctl_id { IOCTL_SET_RPU_OPER_MODE, IOCTL_RPU_BOOT_ADDR_CONFIG, IOCTL_TCM_COMB_CONFIG, + IOCTL_SET_TAPDELAY_BYPASS, + IOCTL_SET_SGMII_MODE, + IOCTL_SD_DLL_RESET, + IOCTL_SET_SD_TAPDELAY, }; enum rpu_oper_mode { @@ -35,6 +39,34 @@ enum rpu_tcm_comb { PM_RPU_TCM_COMB, }; +enum tap_delay_signal_type { + PM_TAPDELAY_NAND_DQS_IN, + PM_TAPDELAY_NAND_DQS_OUT, + PM_TAPDELAY_QSPI, + PM_TAPDELAY_MAX, +}; + +enum tap_delay_bypass_ctrl { + PM_TAPDELAY_BYPASS_DISABLE, + PM_TAPDELAY_BYPASS_ENABLE, +}; + +enum sgmii_mode { + PM_SGMII_DISABLE, + PM_SGMII_ENABLE, +}; + +enum tap_delay_type { + PM_TAPDELAY_INPUT, + PM_TAPDELAY_OUTPUT, +}; + +enum dll_reset_type { + PM_DLL_RESET_ASSERT, + PM_DLL_RESET_RELEASE, + PM_DLL_RESET_PULSE, +}; + enum pm_ret_status pm_api_ioctl(enum pm_node_id nid, unsigned int ioctl_id, unsigned int arg1, diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h index 54036f99b..f3180e901 100644 --- a/plat/xilinx/zynqmp/zynqmp_def.h +++ b/plat/xilinx/zynqmp/zynqmp_def.h @@ -186,4 +186,43 @@ #define ZYNQMP_SLCLAMP_MASK 0x10 #define ZYNQMP_VINITHI_MASK 0x04 +/* Tap delay bypass */ +#define IOU_TAPDLY_BYPASS 0XFF180390 +#define TAP_DELAY_MASK 0x7 + +/* SGMII mode */ +#define IOU_GEM_CTRL 0xFF180360 +#define IOU_GEM_CLK_CTRL 0xFF180308 +#define SGMII_SD_MASK 0x3 +#define SGMII_SD_OFFSET 2 +#define SGMII_PCS_SD_0 0x0 +#define SGMII_PCS_SD_1 0x1 +#define SGMII_PCS_SD_PHY 0x2 +#define GEM_SGMII_MASK 0x4 +#define GEM_CLK_CTRL_MASK 0xF +#define GEM_CLK_CTRL_OFFSET 5 +#define GEM_RX_SRC_SEL_GTR 0x1 +#define GEM_SGMII_MODE 0x4 + +/* SD DLL reset */ +#define ZYNQMP_SD_DLL_CTRL 0xFF180358 +#define ZYNQMP_SD0_DLL_RST_MASK 0x00000004 +#define ZYNQMP_SD0_DLL_RST 0x00000004 +#define ZYNQMP_SD1_DLL_RST_MASK 0x00040000 +#define ZYNQMP_SD1_DLL_RST 0x00040000 + +/* SD tap delay */ +#define ZYNQMP_SD_DLL_CTRL 0xFF180358 +#define ZYNQMP_SD_ITAP_DLY 0xFF180314 +#define ZYNQMP_SD_OTAP_DLY 0xFF180318 +#define ZYNQMP_SD_TAP_OFFSET 16 +#define ZYNQMP_SD_ITAPCHGWIN_MASK 0x200 +#define ZYNQMP_SD_ITAPCHGWIN 0x200 +#define ZYNQMP_SD_ITAPDLYENA_MASK 0x100 +#define ZYNQMP_SD_ITAPDLYENA 0x100 +#define ZYNQMP_SD_ITAPDLYSEL_MASK 0xFF +#define ZYNQMP_SD_OTAPDLYSEL_MASK 0x3F +#define ZYNQMP_SD_OTAPDLYENA_MASK 0x40 +#define ZYNQMP_SD_OTAPDLYENA 0x40 + #endif /* __ZYNQMP_DEF_H__ */ -- GitLab