On 08.03.24 12:17, Steffen Trumtrar wrote: > Depending on the used SDHCI mode the clock phases are different. > Import the helper function to get these values from the DT from linux v6.7. > > Signed-off-by: Steffen Trumtrar <s.trumtrar@xxxxxxxxxxxxxx> > --- > drivers/mci/arasan-sdhci.c | 121 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 121 insertions(+) > > diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c > index cc1bad8b62..76022708cd 100644 > --- a/drivers/mci/arasan-sdhci.c > +++ b/drivers/mci/arasan-sdhci.c > @@ -30,10 +30,33 @@ > #define SDHCI_ARASAN_BUS_WIDTH 4 > #define TIMEOUT_VAL 0xE > > +#define ZYNQMP_CLK_PHASES 10 > +#define ZYNQMP_CLK_PHASE_UHS_SDR104 6 > +#define ZYNQMP_CLK_PHASE_HS200 9 > +/* Default settings for ZynqMP Clock Phases */ > +#define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0} > +#define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0} "include: mci: sync mci_timing with linux" should be ordered before this patch, because the above two lines depend on it for correctness. > + > +/** > + * struct sdhci_arasan_clk_data - Arasan Controller Clock Data. > + * > + * @clk_phase_in: Array of Input Clock Phase Delays for all speed modes > + * @clk_phase_out: Array of Output Clock Phase Delays for all speed modes > + * @set_clk_delays: Function pointer for setting Clock Delays > + * @clk_of_data: Platform specific runtime clock data storage pointer > + */ > +struct sdhci_arasan_clk_data { > + int clk_phase_in[ZYNQMP_CLK_PHASES + 1]; > + int clk_phase_out[ZYNQMP_CLK_PHASES + 1]; > + void (*set_clk_delays)(struct sdhci *host); > + void *clk_of_data; > +}; > + > struct arasan_sdhci_host { > struct mci_host mci; > struct sdhci sdhci; > unsigned int quirks; /* Arasan deviations from spec */ > + struct sdhci_arasan_clk_data clk_data; > /* Controller does not have CD wired and will not function normally without */ > #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0) > #define SDHCI_ARASAN_QUIRK_NO_1_8_V BIT(1) > @@ -119,6 +142,7 @@ static int arasan_sdhci_init(struct mci_host *mci, struct device *dev) > static void arasan_sdhci_set_clock(struct mci_host *mci, unsigned int clock) > { > struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci); > + struct sdhci_arasan_clk_data *clk_data = &host->clk_data; > > if (host->quirks & SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN) { > /* > @@ -219,6 +243,101 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, > return ret; > } > > +static void sdhci_arasan_set_clk_delays(struct sdhci *host) > +{ > + struct arasan_sdhci_host *arasan_sdhci = sdhci_to_arasan(host); > + struct mci_host *mci = &arasan_sdhci->mci; > + struct sdhci_arasan_clk_data *clk_data = &arasan_sdhci->clk_data; > + > +} > + > +static void arasan_dt_read_clk_phase(struct device *dev, > + struct sdhci_arasan_clk_data *clk_data, > + unsigned int timing, const char *prop) > +{ > + struct device_node *np = dev->of_node; > + > + u32 clk_phase[2] = {0}; > + int ret; > + > + /* > + * Read Tap Delay values from DT, if the DT does not contain the > + * Tap Values then use the pre-defined values. > + */ > + ret = of_property_read_u32_array(np, prop, &clk_phase[0], 2); > + if (ret < 0) { > + dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", > + prop, clk_data->clk_phase_in[timing], > + clk_data->clk_phase_out[timing]); > + return; > + } > + > + /* The values read are Input and Output Clock Delays in order */ > + clk_data->clk_phase_in[timing] = clk_phase[0]; > + clk_data->clk_phase_out[timing] = clk_phase[1]; > +} > + > +/** > + * arasan_dt_parse_clk_phases - Read Clock Delay values from DT > + * > + * @dev: Pointer to our struct device. > + * @clk_data: Pointer to the Clock Data structure > + * > + * Called at initialization to parse the values of Clock Delays. > + */ > +static void arasan_dt_parse_clk_phases(struct device *dev, > + struct sdhci_arasan_clk_data *clk_data) > +{ > + u32 mio_bank = 0; > + int i; > + > + /* > + * This has been kept as a pointer and is assigned a function here. > + * So that different controller variants can assign their own handling > + * function. > + */ > + clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; > + > + if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) { > + u32 zynqmp_iclk_phase[ZYNQMP_CLK_PHASES + 1] = ZYNQMP_ICLK_PHASE; > + u32 zynqmp_oclk_phase[ZYNQMP_CLK_PHASES + 1] = ZYNQMP_OCLK_PHASE; > + > + of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank); > + if (mio_bank == 2) { > + zynqmp_oclk_phase[ZYNQMP_CLK_PHASE_UHS_SDR104] = 90; > + zynqmp_oclk_phase[ZYNQMP_CLK_PHASE_HS200] = 90; > + } > + > + for (i = 0; i <= ZYNQMP_CLK_PHASES; i++) { > + clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i]; > + clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i]; > + } > + } > + > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, > + "clk-phase-legacy"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, > + "clk-phase-mmc-hs"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS, > + "clk-phase-sd-hs"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12, > + "clk-phase-uhs-sdr12"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25, > + "clk-phase-uhs-sdr25"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50, > + "clk-phase-uhs-sdr50"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104, > + "clk-phase-uhs-sdr104"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50, > + "clk-phase-uhs-ddr50"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52, > + "clk-phase-mmc-ddr52"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200, > + "clk-phase-mmc-hs200"); > + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400, > + "clk-phase-mmc-hs400"); > +} > + > static int arasan_sdhci_probe(struct device *dev) > { > struct device_node *np = dev->of_node; > @@ -281,6 +400,8 @@ static int arasan_sdhci_probe(struct device *dev) > mci->f_max = clk_get_rate(clk_xin); > mci->f_min = 50000000 / 256; > > + arasan_dt_parse_clk_phases(dev, &arasan_sdhci->clk_data); > + > /* parse board supported bus width capabilities */ > mci_of_parse(&arasan_sdhci->mci); > > -- 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 |