On 08.03.24 12:17, Steffen Trumtrar wrote: > Add a function to set the tap delay for the clk phase of the sd host > controller. > > Signed-off-by: Steffen Trumtrar <s.trumtrar@xxxxxxxxxxxxxx> Reviewed-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> > --- > arch/arm/mach-zynqmp/firmware-zynqmp.c | 42 ++++++++++++++++++++++++++++++++++ > include/mach/zynqmp/firmware-zynqmp.h | 23 +++++++++++++++++++ > 2 files changed, 65 insertions(+) > > diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c > index b383ed6f00..039a46e767 100644 > --- a/arch/arm/mach-zynqmp/firmware-zynqmp.c > +++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c > @@ -48,6 +48,7 @@ enum pm_ret_status { > > enum pm_api_id { > PM_GET_API_VERSION = 1, > + PM_MMIO_WRITE = 19, > PM_FPGA_LOAD = 22, > PM_FPGA_GET_STATUS, > PM_IOCTL = 34, > @@ -511,6 +512,47 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, > arg1, arg2, out); > } > > +/** > + * zynqmp_pm_set_sd_tapdelay() - Set tap delay for the SD device > + * > + * @node_id: 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 > + */ > +int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value) > +{ > + u32 reg = (type == PM_TAPDELAY_INPUT) ? SD_ITAPDLY : SD_OTAPDLYSEL; > + u32 mask = (node_id == NODE_SD_0) ? GENMASK(15, 0) : GENMASK(31, 16); > + > + if (value) { > + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, > + IOCTL_SET_SD_TAPDELAY, > + type, value, NULL); > + } > + > + /* > + * Work around completely misdesigned firmware API on Xilinx ZynqMP. > + * The IOCTL_SET_SD_TAPDELAY firmware call allows the caller to only > + * ever set IOU_SLCR SD_ITAPDLY Register SD0_ITAPDLYENA/SD1_ITAPDLYENA > + * bits, but there is no matching call to clear those bits. If those > + * bits are not cleared, SDMMC tuning may fail. > + * > + * Luckily, there are PM_MMIO_READ/PM_MMIO_WRITE calls which seem to > + * allow complete unrestricted access to all address space, including > + * IOU_SLCR SD_ITAPDLY Register and all the other registers, access > + * to which was supposed to be protected by the current firmware API. > + * > + * Use PM_MMIO_READ/PM_MMIO_WRITE to re-implement the missing counter > + * part of IOCTL_SET_SD_TAPDELAY which clears SDx_ITAPDLYENA bits. > + */ > + return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, reg, mask, 0, 0, NULL); > +} > +EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay); > + > /** > * zynqmp_pm_sd_dll_reset() - Reset DLL logic > * > diff --git a/include/mach/zynqmp/firmware-zynqmp.h b/include/mach/zynqmp/firmware-zynqmp.h > index 630677285f..00c63058f4 100644 > --- a/include/mach/zynqmp/firmware-zynqmp.h > +++ b/include/mach/zynqmp/firmware-zynqmp.h > @@ -27,6 +27,10 @@ > > #define ZYNQMP_PCAP_STATUS_FPGA_DONE BIT(3) > > +/* ZynqMP SD tap delay tuning */ > +#define SD_ITAPDLY 0xFF180314 > +#define SD_OTAPDLYSEL 0xFF180318 > + > enum pm_ioctl_id { > IOCTL_GET_RPU_OPER_MODE = 0, > IOCTL_SET_RPU_OPER_MODE = 1, > @@ -80,6 +84,22 @@ struct zynqmp_pm_query_data { > u32 arg3; > }; > > +enum pm_node_id { > + NODE_SD_0 = 39, > + NODE_SD_1 = 40, > +}; > + > +enum tap_delay_type { > + PM_TAPDELAY_INPUT = 0, > + PM_TAPDELAY_OUTPUT = 1, > +}; > + > +enum dll_reset_type { > + PM_DLL_RESET_ASSERT = 0, > + PM_DLL_RESET_RELEASE = 1, > + PM_DLL_RESET_PULSE = 2, > +}; > + > struct zynqmp_eemi_ops { > int (*get_api_version)(u32 *version); > int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out); > @@ -99,6 +119,9 @@ struct zynqmp_eemi_ops { > > const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void); > > +int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value); > +int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type); > + > int zynqmp_pm_write_ggs(u32 index, u32 value); > int zynqmp_pm_read_ggs(u32 index, u32 *value); > int zynqmp_pm_write_pggs(u32 index, u32 value); > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |