@samitouri / QOSamiQemu / commits / 11ed6b9213

hw/sd/sdhci: Extract uSDHC-specific quirk

In Linux, the ESDHC_MIX_CTRL quirk is guarded by esdhc_is_usdhc() while the eSDHC code path uses the standard SDHC interface. Extract the quirk into a new `usdhc_write()` function. Fixes file system corruption on emulated i.MX53 where Linux' esdhc_is_usdhc() returns false. The same likely happens on e500 and imx25-pdk machines. Cc: qemu-stable@nongnu.org Fixes: 75e98bc4f859 ("hw/sd/sdhci: Add TYPE_FSL_ESDHC_BE") Reviewed-by: Bin Meng <bin.meng@processmission.com> Signed-off-by: Bernhard Beschow <shentey@gmail.com> Message-ID: <20260720201133.24796-3-shentey@gmail.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Bernhard Beschow committed Jul 20, 2026 at 22:11 UTC 11ed6b92130a3b075cd6528e991c78538685d56a
1 file changed +44 -29
hw/sd/sdhci.c
+44 -29
@@ -1795,34 +1795,6 @@ esdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
1795 sdhci_write(opaque, offset, value, size);
1796 break;
1797
1798 - case ESDHC_MIX_CTRL:
1799 - /*
1800 - * So, when SD/MMC stack in Linux tries to write to "Transfer
1801 - * Mode Register", ESDHC i.MX quirk code will translate it
1802 - * into a write to ESDHC_MIX_CTRL, so we do the opposite in
1803 - * order to get where we started
1804 - *
1805 - * Note that Auto CMD23 Enable bit is located in a wrong place
1806 - * on i.MX, but since it is not used by QEMU we do not care.
1807 - *
1808 - * We don't want to call sdhci_write(.., SDHC_TRNMOD, ...)
1809 - * here because it will result in a call to
1810 - * sdhci_send_command(s) which we don't want.
1811 - *
1812 - */
1813 - s->trnmod = value & UINT16_MAX;
1814 - break;
1815 - case SDHC_TRNMOD:
1816 - /*
1817 - * Similar to above, but this time a write to "Command
1818 - * Register" will be translated into a 4-byte write to
1819 - * "Transfer Mode register" where lower 16-bit of value would
1820 - * be set to zero. So what we do is fill those bits with
1821 - * cached value from s->trnmod and let the SDHCI
1822 - * infrastructure handle the rest
1823 - */
1824 - sdhci_write(opaque, offset, val | s->trnmod, size);
1825 - break;
1798 case SDHC_BLKSIZE:
1799 /*
1800 * ESDHCI does not implement "Host SDMA Buffer Boundary", and
@@ -1891,9 +1863,52 @@ static void fsl_esdhc_le_init(Object *obj)
1863 qdev_prop_set_uint8(dev, "sd-spec-version", 2);
1864 }
1865
1866 +static void
1867 +usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
1868 +{
1869 + SDHCIState *s = SYSBUS_SDHCI(opaque);
1870 + uint32_t value = (uint32_t)val;
1871 +
1872 + switch (offset) {
1873 + case ESDHC_MIX_CTRL:
1874 + /*
1875 + * So, when SD/MMC stack in Linux tries to write to "Transfer
1876 + * Mode Register", uSDHC i.MX quirk code will translate it
1877 + * into a write to ESDHC_MIX_CTRL, so we do the opposite in
1878 + * order to get where we started.
1879 + *
1880 + * Note that Auto CMD23 Enable bit is located in a wrong place
1881 + * on i.MX, but since it is not used by QEMU we do not care.
1882 + *
1883 + * We don't want to call sdhci_write(.., SDHC_TRNMOD, ...)
1884 + * here because it will result in a call to
1885 + * sdhci_send_command(s) which we don't want.
1886 + *
1887 + */
1888 + s->trnmod = value & UINT16_MAX;
1889 + break;
1890 +
1891 + case SDHC_TRNMOD:
1892 + /*
1893 + * Similar to above, but this time a write to "Command
1894 + * Register" will be translated into a 4-byte write to
1895 + * "Transfer Mode register" where lower 16-bit of value would
1896 + * be set to zero. So what we do is fill those bits with
1897 + * cached value from s->trnmod and let the SDHCI
1898 + * infrastructure handle the rest
1899 + */
1900 + sdhci_write(opaque, offset, val | s->trnmod, size);
1901 + break;
1902 +
1903 + default:
1904 + esdhc_write(opaque, offset, val, size);
1905 + break;
1906 + }
1907 +}
1908 +
1909 static const MemoryRegionOps usdhc_mmio_ops = {
1910 .read = esdhc_read,
1896 - .write = esdhc_write,
1911 + .write = usdhc_write,
1912 .valid = {
1913 .min_access_size = 1,
1914 .max_access_size = 4,