Commit 1818c029 authored by Rajan Vaja's avatar Rajan Vaja Committed by Jolly Shah
Browse files

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: default avatarRajan Vaja <rajanv@xilinx.com>
Signed-off-by: default avatarJolly Shah <jollys@xilinx.com>
parent f76918a8
......@@ -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;
}
......
......@@ -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,
......
......@@ -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__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment