@@ -66,6 +66,8 @@ struct sdhci_cdns_phy_param {
6666
6767struct sdhci_cdns_priv {
6868 void __iomem * hrs_addr ;
69+ void __iomem * ctl_addr ; /* write control */
70+ spinlock_t wrlock ; /* write lock */
6971 bool enhanced_strobe ;
7072 void (* priv_writel )(struct sdhci_cdns_priv * priv , u32 val , void __iomem * reg );
7173 unsigned int nr_phy_params ;
@@ -321,6 +323,91 @@ static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
321323 sdhci_set_uhs_signaling (host , timing );
322324}
323325
326+ /* Elba control register bits [6:3] are byte-lane enables */
327+ #define ELBA_BYTE_ENABLE_MASK (x ) ((x) << 3)
328+
329+ /*
330+ * The Pensando Elba SoC explicitly controls byte-lane enabling on writes
331+ * which includes writes to the HRS registers. The write lock (wrlock)
332+ * is used to ensure byte-lane enable, using write control (ctl_addr),
333+ * occurs before the data write.
334+ */
335+ static void elba_priv_writel (struct sdhci_cdns_priv * priv , u32 val ,
336+ void __iomem * reg )
337+ {
338+ unsigned long flags ;
339+
340+ spin_lock_irqsave (& priv -> wrlock , flags );
341+ writel (GENMASK (7 , 3 ), priv -> ctl_addr );
342+ writel (val , reg );
343+ spin_unlock_irqrestore (& priv -> wrlock , flags );
344+ }
345+
346+ static void elba_write_l (struct sdhci_host * host , u32 val , int reg )
347+ {
348+ elba_priv_writel (sdhci_cdns_priv (host ), val , host -> ioaddr + reg );
349+ }
350+
351+ static void elba_write_w (struct sdhci_host * host , u16 val , int reg )
352+ {
353+ struct sdhci_cdns_priv * priv = sdhci_cdns_priv (host );
354+ u32 shift = reg & GENMASK (1 , 0 );
355+ unsigned long flags ;
356+ u32 byte_enables ;
357+
358+ byte_enables = GENMASK (1 , 0 ) << shift ;
359+ spin_lock_irqsave (& priv -> wrlock , flags );
360+ writel (ELBA_BYTE_ENABLE_MASK (byte_enables ), priv -> ctl_addr );
361+ writew (val , host -> ioaddr + reg );
362+ spin_unlock_irqrestore (& priv -> wrlock , flags );
363+ }
364+
365+ static void elba_write_b (struct sdhci_host * host , u8 val , int reg )
366+ {
367+ struct sdhci_cdns_priv * priv = sdhci_cdns_priv (host );
368+ u32 shift = reg & GENMASK (1 , 0 );
369+ unsigned long flags ;
370+ u32 byte_enables ;
371+
372+ byte_enables = BIT (0 ) << shift ;
373+ spin_lock_irqsave (& priv -> wrlock , flags );
374+ writel (ELBA_BYTE_ENABLE_MASK (byte_enables ), priv -> ctl_addr );
375+ writeb (val , host -> ioaddr + reg );
376+ spin_unlock_irqrestore (& priv -> wrlock , flags );
377+ }
378+
379+ static const struct sdhci_ops sdhci_elba_ops = {
380+ .write_l = elba_write_l ,
381+ .write_w = elba_write_w ,
382+ .write_b = elba_write_b ,
383+ .set_clock = sdhci_set_clock ,
384+ .get_timeout_clock = sdhci_cdns_get_timeout_clock ,
385+ .set_bus_width = sdhci_set_bus_width ,
386+ .reset = sdhci_reset ,
387+ .set_uhs_signaling = sdhci_cdns_set_uhs_signaling ,
388+ };
389+
390+ static int elba_drv_init (struct platform_device * pdev )
391+ {
392+ struct sdhci_host * host = platform_get_drvdata (pdev );
393+ struct sdhci_cdns_priv * priv = sdhci_cdns_priv (host );
394+ void __iomem * ioaddr ;
395+
396+ host -> mmc -> caps |= MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA ;
397+ spin_lock_init (& priv -> wrlock );
398+
399+ /* Byte-lane control register */
400+ ioaddr = devm_platform_ioremap_resource (pdev , 1 );
401+ if (IS_ERR (ioaddr ))
402+ return PTR_ERR (ioaddr );
403+
404+ priv -> ctl_addr = ioaddr ;
405+ priv -> priv_writel = elba_priv_writel ;
406+ writel (ELBA_BYTE_ENABLE_MASK (0xf ), priv -> ctl_addr );
407+
408+ return 0 ;
409+ }
410+
324411static const struct sdhci_ops sdhci_cdns_ops = {
325412 .set_clock = sdhci_set_clock ,
326413 .get_timeout_clock = sdhci_cdns_get_timeout_clock ,
@@ -337,6 +424,13 @@ static const struct sdhci_cdns_drv_data sdhci_cdns_uniphier_drv_data = {
337424 },
338425};
339426
427+ static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = {
428+ .init = elba_drv_init ,
429+ .pltfm_data = {
430+ .ops = & sdhci_elba_ops ,
431+ },
432+ };
433+
340434static const struct sdhci_cdns_drv_data sdhci_cdns_drv_data = {
341435 .pltfm_data = {
342436 .ops = & sdhci_cdns_ops ,
@@ -477,6 +571,10 @@ static const struct of_device_id sdhci_cdns_match[] = {
477571 .compatible = "socionext,uniphier-sd4hc" ,
478572 .data = & sdhci_cdns_uniphier_drv_data ,
479573 },
574+ {
575+ .compatible = "amd,pensando-elba-sd4hc" ,
576+ .data = & sdhci_elba_drv_data ,
577+ },
480578 { .compatible = "cdns,sd4hc" },
481579 { /* sentinel */ }
482580};
0 commit comments