@@ -1866,11 +1866,19 @@ static int test_ext_flash(QspiDev_t* dev)
18661866
18671867#define CADENCE_SRS_OFFSET 0x200
18681868
1869- /* Standard SDHCI Software Reset is in the Clock/Timeout/Reset register */
1870- #define STD_SDHCI_RESET_REG 0x2C /* Clock Control / Timeout / SW Reset */
1871- #define STD_SDHCI_SRA (1U << 24) /* Software Reset for All */
1872- #define STD_SDHCI_SRCMD (1U << 25) /* Software Reset for CMD Line */
1873- #define STD_SDHCI_SRDAT (1U << 26) /* Software Reset for DAT Line */
1869+ /* Standard SDHCI register offsets (byte addresses within the controller) */
1870+ #define STD_SDHCI_HOST_CTRL1 0x28 /* Host Control 1 (8-bit) */
1871+ #define STD_SDHCI_POWER_CTRL 0x29 /* Power Control (8-bit) */
1872+ #define STD_SDHCI_BLKGAP_CTRL 0x2A /* Block Gap Control (8-bit) */
1873+ #define STD_SDHCI_WAKEUP_CTRL 0x2B /* Wakeup Control (8-bit) */
1874+ #define STD_SDHCI_CLK_CTRL 0x2C /* Clock Control (16-bit) */
1875+ #define STD_SDHCI_TIMEOUT_CTRL 0x2E /* Timeout Control (8-bit) */
1876+ #define STD_SDHCI_SW_RESET 0x2F /* Software Reset (8-bit) */
1877+
1878+ /* Software Reset register bits (at offset 0x2F, 8-bit register) */
1879+ #define STD_SDHCI_SRA 0x01 /* Software Reset for All */
1880+ #define STD_SDHCI_SRCMD 0x02 /* Software Reset for CMD Line */
1881+ #define STD_SDHCI_SRDAT 0x04 /* Software Reset for DAT Line */
18741882
18751883/* Handle reads from Cadence HRS registers (0x000-0x1FF) */
18761884static uint32_t zynqmp_sdhci_hrs_read (uint32_t hrs_offset )
@@ -1880,11 +1888,8 @@ static uint32_t zynqmp_sdhci_hrs_read(uint32_t hrs_offset)
18801888 switch (hrs_offset ) {
18811889 case 0x000 : /* HRS00 - Software Reset */
18821890 {
1883- /* Map standard SRA (bit 24 of 0x2C) to Cadence SWR (bit 0).
1884- * SRA is safe because sdhci_platform_init() sets the slot type
1885- * to "Embedded", so the controller accepts BP/SDCE writes after
1886- * reset. */
1887- uint32_t val = * ((volatile uint32_t * )(base + STD_SDHCI_RESET_REG ));
1891+ /* Map standard SRA (byte at 0x2F) to Cadence SWR (bit 0) */
1892+ uint8_t val = * ((volatile uint8_t * )(base + STD_SDHCI_SW_RESET ));
18881893 return (val & STD_SDHCI_SRA ) ? 1U : 0U ;
18891894 }
18901895 case 0x010 : /* HRS04 - PHY access (Cadence-specific) */
@@ -1904,14 +1909,10 @@ static void zynqmp_sdhci_hrs_write(uint32_t hrs_offset, uint32_t val)
19041909 switch (hrs_offset ) {
19051910 case 0x000 : /* HRS00 - Software Reset */
19061911 if (val & 1U ) {
1907- /* Issue SRA (Software Reset for All).
1908- * This is safe because sdhci_platform_init() configures the
1909- * IOU_SLCR slot type to "Embedded" before this reset, so the
1910- * controller will accept Bus Power and SD Clock Enable writes
1911- * during the subsequent initialization. */
1912- uint32_t reg = * ((volatile uint32_t * )(base + STD_SDHCI_RESET_REG ));
1913- reg |= STD_SDHCI_SRA ;
1914- * ((volatile uint32_t * )(base + STD_SDHCI_RESET_REG )) = reg ;
1912+ /* Issue SRA via 8-bit write to offset 0x2F (per SDHCI spec).
1913+ * The Arasan controller requires byte-level access for the
1914+ * Software Reset register. */
1915+ * ((volatile uint8_t * )(base + STD_SDHCI_SW_RESET )) = STD_SDHCI_SRA ;
19151916 }
19161917 break ;
19171918 default :
@@ -1921,13 +1922,24 @@ static void zynqmp_sdhci_hrs_write(uint32_t hrs_offset, uint32_t val)
19211922}
19221923
19231924/* Register access functions for generic SDHCI driver.
1924- * Translates Cadence SD4HC register offsets to standard Arasan SDHCI layout. */
1925+ * Translates Cadence SD4HC register offsets to standard Arasan SDHCI layout.
1926+ *
1927+ * IMPORTANT: The Arasan SDHCI on ZynqMP requires specific register access
1928+ * widths matching the SDHCI specification (see Xilinx SDPS driver reference):
1929+ * - Host Control 1 (0x28): 8-bit
1930+ * - Power Control (0x29): 8-bit
1931+ * - Clock Control (0x2C): 16-bit
1932+ * - Timeout Control (0x2E): 8-bit
1933+ * - Software Reset (0x2F): 8-bit
1934+ * The Cadence driver uses 32-bit SRS10/SRS11 registers that span these byte
1935+ * offsets. We decompose 32-bit writes into the correct access widths. */
19251936uint32_t sdhci_reg_read (uint32_t offset )
19261937{
19271938 volatile uint8_t * base = (volatile uint8_t * )ZYNQMP_SDHCI_BASE ;
19281939
19291940 /* Cadence SRS registers (0x200+) -> standard SDHCI (subtract 0x200) */
19301941 if (offset >= CADENCE_SRS_OFFSET ) {
1942+ /* 32-bit reads work for all SDHCI registers */
19311943 return * ((volatile uint32_t * )(base + offset - CADENCE_SRS_OFFSET ));
19321944 }
19331945 /* Cadence HRS registers (0x000-0x1FF) -> translate to standard equivalents */
@@ -1938,9 +1950,42 @@ void sdhci_reg_write(uint32_t offset, uint32_t val)
19381950{
19391951 volatile uint8_t * base = (volatile uint8_t * )ZYNQMP_SDHCI_BASE ;
19401952
1941- /* Cadence SRS registers (0x200+) -> standard SDHCI (subtract 0x200) */
19421953 if (offset >= CADENCE_SRS_OFFSET ) {
1943- * ((volatile uint32_t * )(base + offset - CADENCE_SRS_OFFSET )) = val ;
1954+ uint32_t std_off = offset - CADENCE_SRS_OFFSET ;
1955+
1956+ /* SRS10 (Cadence 0x228) = standard 0x28-0x2B:
1957+ * 0x28: Host Control 1 (8-bit)
1958+ * 0x29: Power Control (8-bit)
1959+ * 0x2A: Block Gap Control (8-bit)
1960+ * 0x2B: Wakeup Control (8-bit) */
1961+ if (std_off == 0x28 ) {
1962+ * ((volatile uint8_t * )(base + STD_SDHCI_HOST_CTRL1 )) =
1963+ (uint8_t )(val & 0xFF );
1964+ * ((volatile uint8_t * )(base + STD_SDHCI_POWER_CTRL )) =
1965+ (uint8_t )((val >> 8 ) & 0xFF );
1966+ * ((volatile uint8_t * )(base + STD_SDHCI_BLKGAP_CTRL )) =
1967+ (uint8_t )((val >> 16 ) & 0xFF );
1968+ * ((volatile uint8_t * )(base + STD_SDHCI_WAKEUP_CTRL )) =
1969+ (uint8_t )((val >> 24 ) & 0xFF );
1970+ return ;
1971+ }
1972+
1973+ /* SRS11 (Cadence 0x22C) = standard 0x2C-0x2F:
1974+ * 0x2C: Clock Control (16-bit)
1975+ * 0x2E: Timeout Control (8-bit)
1976+ * 0x2F: Software Reset (8-bit) */
1977+ if (std_off == 0x2C ) {
1978+ * ((volatile uint16_t * )(base + STD_SDHCI_CLK_CTRL )) =
1979+ (uint16_t )(val & 0xFFFF );
1980+ * ((volatile uint8_t * )(base + STD_SDHCI_TIMEOUT_CTRL )) =
1981+ (uint8_t )((val >> 16 ) & 0xFF );
1982+ * ((volatile uint8_t * )(base + STD_SDHCI_SW_RESET )) =
1983+ (uint8_t )((val >> 24 ) & 0xFF );
1984+ return ;
1985+ }
1986+
1987+ /* All other SRS registers: 32-bit write */
1988+ * ((volatile uint32_t * )(base + std_off )) = val ;
19441989 return ;
19451990 }
19461991 /* Cadence HRS registers (0x000-0x1FF) -> translate to standard equivalents */
@@ -1964,6 +2009,7 @@ void sdhci_reg_write(uint32_t offset, uint32_t val)
19642009void sdhci_platform_init (void )
19652010{
19662011 uint32_t reg ;
2012+ volatile int i ;
19672013
19682014 /* Set SD1 slot type to "Embedded Slot for One Device" (01).
19692015 * This feeds into the SDHCI Capabilities register bits 31:30 and makes
@@ -1974,6 +2020,14 @@ void sdhci_platform_init(void)
19742020 reg |= (1UL << SD_CONFIG_REG2_SD1_SLOTTYPE_SHIFT ); /* 01 = Embedded */
19752021 IOU_SLCR_SD_CONFIG_REG2 = reg ;
19762022
2023+ /* The SDHCI Capabilities register latches IOU_SLCR values on controller
2024+ * reset. Issue SDIO1 reset via CRL_APB so the controller picks up the
2025+ * new slot type configuration. */
2026+ RST_LPD_IOU2 |= RST_LPD_IOU2_SDIO1 ; /* Assert SDIO1 reset */
2027+ for (i = 0 ; i < 100 ; i ++ ) {} /* Brief delay */
2028+ RST_LPD_IOU2 &= ~RST_LPD_IOU2_SDIO1 ; /* De-assert SDIO1 reset */
2029+ for (i = 0 ; i < 1000 ; i ++ ) {} /* Wait for controller ready */
2030+
19772031#ifdef DEBUG_SDHCI
19782032 {
19792033 volatile uint8_t * base = (volatile uint8_t * )ZYNQMP_SDHCI_BASE ;
0 commit comments