Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mmc: sdhci: add Black Sesame Technologies BST C1200 controller driver

Add SDHCI controller driver for Black Sesame Technologies C1200 SoC.

This driver supports the DWCMSHC SDHCI controller with BST-specific
enhancements including:
- Custom clock management and tuning
- Power management support
- BST-specific register configurations
- Support for eMMC and SD card interfaces
- Hardware limitation workaround for 32-bit DMA addressing

The driver addresses specific hardware constraints where:
- System memory uses 64-bit bus, eMMC controller uses 32-bit bus
- eMMC controller cannot access memory through SMMU due to hardware bug
- All system DRAM is configured outside 4GB boundary (ZONE_DMA32)
- Uses SRAM-based bounce buffer within 32-bit address space

Signed-off-by: Ge Gordon <gordon.ge@bst.ai>
Signed-off-by: Albert Yang <yangzh0906@thundersoft.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Albert Yang and committed by
Ulf Hansson
695824f4 ef7eb1a7

+536
+14
drivers/mmc/host/Kconfig
··· 429 429 430 430 If you have a controller with this interface, say Y or M here. 431 431 432 + config MMC_SDHCI_BST 433 + tristate "SDHCI support for Black Sesame Technologies BST C1200 controller" 434 + depends on ARCH_BST || COMPILE_TEST 435 + depends on MMC_SDHCI_PLTFM 436 + depends on OF 437 + help 438 + This selects the Secure Digital Host Controller Interface (SDHCI) 439 + for Black Sesame Technologies BST C1200 SoC. The controller is 440 + based on Synopsys DesignWare Cores Mobile Storage Controller but 441 + requires platform-specific workarounds for hardware limitations. 442 + 443 + If you have a controller with this interface, say Y or M here. 444 + If unsure, say N. 445 + 432 446 config MMC_SDHCI_F_SDH30 433 447 tristate "SDHCI support for Fujitsu Semiconductor F_SDH30" 434 448 depends on MMC_SDHCI_PLTFM
+1
drivers/mmc/host/Makefile
··· 13 13 obj-$(CONFIG_MMC_SDHCI) += sdhci.o 14 14 obj-$(CONFIG_MMC_SDHCI_UHS2) += sdhci-uhs2.o 15 15 obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o 16 + obj-$(CONFIG_MMC_SDHCI_BST) += sdhci-of-bst.o 16 17 sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ 17 18 sdhci-pci-dwc-mshc.o sdhci-pci-gli.o 18 19 obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
+521
drivers/mmc/host/sdhci-of-bst.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * SDHCI driver for Black Sesame Technologies C1200 controller 4 + * 5 + * Copyright (c) 2025 Black Sesame Technologies 6 + */ 7 + 8 + #include <linux/bits.h> 9 + #include <linux/bitfield.h> 10 + #include <linux/delay.h> 11 + #include <linux/dma-mapping.h> 12 + #include <linux/iopoll.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/of_reserved_mem.h> 16 + #include <linux/platform_device.h> 17 + #include "sdhci.h" 18 + #include "sdhci-pltfm.h" 19 + 20 + /* SDHCI register extensions */ 21 + #define SDHCI_CLOCK_PLL_EN 0x0008 22 + #define SDHCI_VENDOR_PTR_R 0xE8 23 + 24 + /* BST-specific tuning parameters */ 25 + #define BST_TUNING_COUNT 0x20 26 + 27 + /* Synopsys vendor specific registers */ 28 + #define SDHC_EMMC_CTRL_R_OFFSET 0x2C 29 + #define MBIU_CTRL 0x510 30 + 31 + /* MBIU burst control bits */ 32 + #define BURST_INCR16_EN BIT(3) 33 + #define BURST_INCR8_EN BIT(2) 34 + #define BURST_INCR4_EN BIT(1) 35 + #define BURST_EN (BURST_INCR16_EN | BURST_INCR8_EN | BURST_INCR4_EN) 36 + #define MBIU_BURST_MASK GENMASK(3, 0) 37 + 38 + /* CRM (Clock/Reset/Management) register offsets */ 39 + #define SDEMMC_CRM_BCLK_DIV_CTRL 0x08 40 + #define SDEMMC_CRM_TIMER_DIV_CTRL 0x0C 41 + #define SDEMMC_CRM_RX_CLK_CTRL 0x14 42 + #define SDEMMC_CRM_VOL_CTRL 0x1C 43 + #define REG_WR_PROTECT 0x88 44 + #define DELAY_CHAIN_SEL 0x94 45 + 46 + /* CRM register values and bit definitions */ 47 + #define REG_WR_PROTECT_KEY 0x1234abcd 48 + #define BST_VOL_STABLE_ON BIT(7) 49 + #define BST_TIMER_DIV_MASK GENMASK(7, 0) 50 + #define BST_TIMER_DIV_VAL 0x20 51 + #define BST_TIMER_LOAD_BIT BIT(8) 52 + #define BST_BCLK_EN_BIT BIT(10) 53 + #define BST_RX_UPDATE_BIT BIT(11) 54 + #define BST_EMMC_CTRL_RST_N BIT(2) /* eMMC card reset control */ 55 + 56 + /* Clock frequency limits */ 57 + #define BST_DEFAULT_MAX_FREQ 200000000UL /* 200 MHz */ 58 + #define BST_DEFAULT_MIN_FREQ 400000UL /* 400 kHz */ 59 + 60 + /* Clock control bit definitions */ 61 + #define BST_CLOCK_DIV_MASK GENMASK(7, 0) 62 + #define BST_CLOCK_DIV_SHIFT 8 63 + #define BST_BCLK_DIV_MASK GENMASK(9, 0) 64 + 65 + /* Clock frequency thresholds */ 66 + #define BST_CLOCK_THRESHOLD_LOW 1500 67 + 68 + /* Clock stability polling parameters */ 69 + #define BST_CLK_STABLE_POLL_US 1000 /* Poll interval in microseconds */ 70 + #define BST_CLK_STABLE_TIMEOUT_US 20000 /* Timeout for internal clock stabilization (us) */ 71 + 72 + struct sdhci_bst_priv { 73 + void __iomem *crm_reg_base; 74 + }; 75 + 76 + union sdhci_bst_rx_ctrl { 77 + struct { 78 + u32 rx_revert:1, 79 + rx_clk_sel_sec:1, 80 + rx_clk_div:4, 81 + rx_clk_phase_inner:2, 82 + rx_clk_sel_first:1, 83 + rx_clk_phase_out:2, 84 + rx_clk_en:1, 85 + res0:20; 86 + }; 87 + u32 reg; 88 + }; 89 + 90 + static u32 sdhci_bst_crm_read(struct sdhci_pltfm_host *pltfm_host, u32 offset) 91 + { 92 + struct sdhci_bst_priv *priv = sdhci_pltfm_priv(pltfm_host); 93 + 94 + return readl(priv->crm_reg_base + offset); 95 + } 96 + 97 + static void sdhci_bst_crm_write(struct sdhci_pltfm_host *pltfm_host, u32 offset, u32 value) 98 + { 99 + struct sdhci_bst_priv *priv = sdhci_pltfm_priv(pltfm_host); 100 + 101 + writel(value, priv->crm_reg_base + offset); 102 + } 103 + 104 + static int sdhci_bst_wait_int_clk(struct sdhci_host *host) 105 + { 106 + u16 clk; 107 + 108 + if (read_poll_timeout(sdhci_readw, clk, (clk & SDHCI_CLOCK_INT_STABLE), 109 + BST_CLK_STABLE_POLL_US, BST_CLK_STABLE_TIMEOUT_US, false, 110 + host, SDHCI_CLOCK_CONTROL)) 111 + return -EBUSY; 112 + return 0; 113 + } 114 + 115 + static unsigned int sdhci_bst_get_max_clock(struct sdhci_host *host) 116 + { 117 + return BST_DEFAULT_MAX_FREQ; 118 + } 119 + 120 + static unsigned int sdhci_bst_get_min_clock(struct sdhci_host *host) 121 + { 122 + return BST_DEFAULT_MIN_FREQ; 123 + } 124 + 125 + static void sdhci_bst_enable_clk(struct sdhci_host *host, unsigned int clk) 126 + { 127 + struct sdhci_pltfm_host *pltfm_host; 128 + unsigned int div; 129 + u32 val; 130 + union sdhci_bst_rx_ctrl rx_reg; 131 + 132 + pltfm_host = sdhci_priv(host); 133 + 134 + /* Calculate clock divider based on target frequency */ 135 + if (clk == 0) { 136 + div = 0; 137 + } else if (clk < BST_DEFAULT_MIN_FREQ) { 138 + /* Below minimum: use max divider to get closest to min freq */ 139 + div = BST_DEFAULT_MAX_FREQ / BST_DEFAULT_MIN_FREQ; 140 + } else if (clk <= BST_DEFAULT_MAX_FREQ) { 141 + /* Normal range: calculate divider directly */ 142 + div = BST_DEFAULT_MAX_FREQ / clk; 143 + } else { 144 + /* Above maximum: no division needed */ 145 + div = 1; 146 + } 147 + 148 + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 149 + clk &= ~SDHCI_CLOCK_CARD_EN; 150 + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 151 + 152 + clk &= ~SDHCI_CLOCK_PLL_EN; 153 + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 154 + 155 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_TIMER_DIV_CTRL); 156 + val &= ~BST_TIMER_LOAD_BIT; 157 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_TIMER_DIV_CTRL, val); 158 + 159 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_TIMER_DIV_CTRL); 160 + val &= ~BST_TIMER_DIV_MASK; 161 + val |= BST_TIMER_DIV_VAL; 162 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_TIMER_DIV_CTRL, val); 163 + 164 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_TIMER_DIV_CTRL); 165 + val |= BST_TIMER_LOAD_BIT; 166 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_TIMER_DIV_CTRL, val); 167 + 168 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_RX_CLK_CTRL); 169 + val &= ~BST_RX_UPDATE_BIT; 170 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_RX_CLK_CTRL, val); 171 + 172 + rx_reg.reg = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_RX_CLK_CTRL); 173 + 174 + rx_reg.rx_revert = 0; 175 + rx_reg.rx_clk_sel_sec = 1; 176 + rx_reg.rx_clk_div = 4; 177 + rx_reg.rx_clk_phase_inner = 2; 178 + rx_reg.rx_clk_sel_first = 0; 179 + rx_reg.rx_clk_phase_out = 2; 180 + 181 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_RX_CLK_CTRL, rx_reg.reg); 182 + 183 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_RX_CLK_CTRL); 184 + val |= BST_RX_UPDATE_BIT; 185 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_RX_CLK_CTRL, val); 186 + 187 + /* Disable clock first */ 188 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_BCLK_DIV_CTRL); 189 + val &= ~BST_BCLK_EN_BIT; 190 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_BCLK_DIV_CTRL, val); 191 + 192 + /* Setup clock divider */ 193 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_BCLK_DIV_CTRL); 194 + val &= ~BST_BCLK_DIV_MASK; 195 + val |= div; 196 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_BCLK_DIV_CTRL, val); 197 + 198 + /* Enable clock */ 199 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_BCLK_DIV_CTRL); 200 + val |= BST_BCLK_EN_BIT; 201 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_BCLK_DIV_CTRL, val); 202 + 203 + /* RMW the clock divider bits to avoid clobbering other fields */ 204 + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 205 + clk &= ~(BST_CLOCK_DIV_MASK << BST_CLOCK_DIV_SHIFT); 206 + clk |= (div & BST_CLOCK_DIV_MASK) << BST_CLOCK_DIV_SHIFT; 207 + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 208 + 209 + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 210 + clk |= SDHCI_CLOCK_PLL_EN; 211 + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 212 + 213 + clk |= SDHCI_CLOCK_CARD_EN; 214 + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 215 + 216 + clk |= SDHCI_CLOCK_INT_EN; 217 + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 218 + } 219 + 220 + static void sdhci_bst_set_clock(struct sdhci_host *host, unsigned int clock) 221 + { 222 + /* Turn off card/internal/PLL clocks when clock==0 to avoid idle power */ 223 + u32 clk_reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 224 + 225 + if (!clock) { 226 + clk_reg &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_PLL_EN); 227 + sdhci_writew(host, clk_reg, SDHCI_CLOCK_CONTROL); 228 + return; 229 + } 230 + sdhci_bst_enable_clk(host, clock); 231 + } 232 + 233 + /* 234 + * sdhci_bst_reset - Reset the SDHCI host controller with special 235 + * handling for eMMC card reset control. 236 + */ 237 + static void sdhci_bst_reset(struct sdhci_host *host, u8 mask) 238 + { 239 + u16 vendor_ptr, emmc_ctrl_reg; 240 + u32 reg; 241 + 242 + if (host->mmc->caps2 & MMC_CAP2_NO_SD) { 243 + vendor_ptr = sdhci_readw(host, SDHCI_VENDOR_PTR_R); 244 + emmc_ctrl_reg = vendor_ptr + SDHC_EMMC_CTRL_R_OFFSET; 245 + 246 + reg = sdhci_readw(host, emmc_ctrl_reg); 247 + reg &= ~BST_EMMC_CTRL_RST_N; 248 + sdhci_writew(host, reg, emmc_ctrl_reg); 249 + sdhci_reset(host, mask); 250 + usleep_range(10, 20); 251 + reg = sdhci_readw(host, emmc_ctrl_reg); 252 + reg |= BST_EMMC_CTRL_RST_N; 253 + sdhci_writew(host, reg, emmc_ctrl_reg); 254 + } else { 255 + sdhci_reset(host, mask); 256 + } 257 + } 258 + 259 + /* Set timeout control register to maximum value (0xE) */ 260 + static void sdhci_bst_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) 261 + { 262 + sdhci_writeb(host, 0xE, SDHCI_TIMEOUT_CONTROL); 263 + } 264 + 265 + /* 266 + * sdhci_bst_set_power - Set power mode and voltage, also configures 267 + * MBIU burst mode control based on power state. 268 + */ 269 + static void sdhci_bst_set_power(struct sdhci_host *host, unsigned char mode, 270 + unsigned short vdd) 271 + { 272 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 273 + u32 reg; 274 + u32 val; 275 + 276 + sdhci_set_power(host, mode, vdd); 277 + 278 + if (mode == MMC_POWER_OFF) { 279 + /* Disable MBIU burst mode */ 280 + reg = sdhci_readw(host, MBIU_CTRL); 281 + reg &= ~BURST_EN; /* Clear all burst enable bits */ 282 + sdhci_writew(host, reg, MBIU_CTRL); 283 + 284 + /* Disable CRM BCLK */ 285 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_BCLK_DIV_CTRL); 286 + val &= ~BST_BCLK_EN_BIT; 287 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_BCLK_DIV_CTRL, val); 288 + 289 + /* Disable RX clock */ 290 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_RX_CLK_CTRL); 291 + val &= ~BST_RX_UPDATE_BIT; 292 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_RX_CLK_CTRL, val); 293 + 294 + /* Turn off voltage stable power */ 295 + val = sdhci_bst_crm_read(pltfm_host, SDEMMC_CRM_VOL_CTRL); 296 + val &= ~BST_VOL_STABLE_ON; 297 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_VOL_CTRL, val); 298 + } else { 299 + /* Configure burst mode only when powered on */ 300 + reg = sdhci_readw(host, MBIU_CTRL); 301 + reg &= ~MBIU_BURST_MASK; /* Clear burst related bits */ 302 + reg |= BURST_EN; /* Enable burst mode for better bandwidth */ 303 + sdhci_writew(host, reg, MBIU_CTRL); 304 + } 305 + } 306 + 307 + /* 308 + * sdhci_bst_execute_tuning - Execute tuning procedure by trying different 309 + * delay chain values and selecting the optimal one. 310 + */ 311 + static int sdhci_bst_execute_tuning(struct sdhci_host *host, u32 opcode) 312 + { 313 + struct sdhci_pltfm_host *pltfm_host; 314 + int ret = 0, error; 315 + int first_start = -1, first_end = -1, best = 0; 316 + int second_start = -1, second_end = -1, has_failure = 0; 317 + int i; 318 + 319 + pltfm_host = sdhci_priv(host); 320 + 321 + for (i = 0; i < BST_TUNING_COUNT; i++) { 322 + /* Protected write */ 323 + sdhci_bst_crm_write(pltfm_host, REG_WR_PROTECT, REG_WR_PROTECT_KEY); 324 + /* Write tuning value */ 325 + sdhci_bst_crm_write(pltfm_host, DELAY_CHAIN_SEL, (1ul << i) - 1); 326 + 327 + /* Wait for internal clock stable before tuning */ 328 + if (sdhci_bst_wait_int_clk(host)) { 329 + dev_err(mmc_dev(host->mmc), "Internal clock never stabilised\n"); 330 + return -EBUSY; 331 + } 332 + 333 + ret = mmc_send_tuning(host->mmc, opcode, &error); 334 + if (ret != 0) { 335 + has_failure = 1; 336 + } else { 337 + if (has_failure == 0) { 338 + if (first_start == -1) 339 + first_start = i; 340 + first_end = i; 341 + } else { 342 + if (second_start == -1) 343 + second_start = i; 344 + second_end = i; 345 + } 346 + } 347 + } 348 + 349 + /* Calculate best tuning value */ 350 + if (first_end - first_start >= second_end - second_start) 351 + best = ((first_end - first_start) >> 1) + first_start; 352 + else 353 + best = ((second_end - second_start) >> 1) + second_start; 354 + 355 + if (best < 0) 356 + best = 0; 357 + 358 + sdhci_bst_crm_write(pltfm_host, DELAY_CHAIN_SEL, (1ul << best) - 1); 359 + /* Confirm internal clock stable after setting best tuning value */ 360 + if (sdhci_bst_wait_int_clk(host)) { 361 + dev_err(mmc_dev(host->mmc), "Internal clock never stabilised\n"); 362 + return -EBUSY; 363 + } 364 + 365 + return 0; 366 + } 367 + 368 + /* Enable voltage stable power for voltage switch */ 369 + static void sdhci_bst_voltage_switch(struct sdhci_host *host) 370 + { 371 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 372 + 373 + /* Enable voltage stable power */ 374 + sdhci_bst_crm_write(pltfm_host, SDEMMC_CRM_VOL_CTRL, BST_VOL_STABLE_ON); 375 + } 376 + 377 + static const struct sdhci_ops sdhci_bst_ops = { 378 + .set_clock = sdhci_bst_set_clock, 379 + .set_bus_width = sdhci_set_bus_width, 380 + .set_uhs_signaling = sdhci_set_uhs_signaling, 381 + .get_min_clock = sdhci_bst_get_min_clock, 382 + .get_max_clock = sdhci_bst_get_max_clock, 383 + .reset = sdhci_bst_reset, 384 + .set_power = sdhci_bst_set_power, 385 + .set_timeout = sdhci_bst_set_timeout, 386 + .platform_execute_tuning = sdhci_bst_execute_tuning, 387 + .voltage_switch = sdhci_bst_voltage_switch, 388 + }; 389 + 390 + static const struct sdhci_pltfm_data sdhci_bst_pdata = { 391 + .ops = &sdhci_bst_ops, 392 + .quirks = SDHCI_QUIRK_BROKEN_ADMA | 393 + SDHCI_QUIRK_DELAY_AFTER_POWER | 394 + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 395 + SDHCI_QUIRK_INVERTED_WRITE_PROTECT, 396 + .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50 | 397 + SDHCI_QUIRK2_TUNING_WORK_AROUND | 398 + SDHCI_QUIRK2_ACMD23_BROKEN, 399 + }; 400 + 401 + static void sdhci_bst_free_bounce_buffer(struct sdhci_host *host) 402 + { 403 + if (host->bounce_buffer) { 404 + dma_free_coherent(mmc_dev(host->mmc), host->bounce_buffer_size, 405 + host->bounce_buffer, host->bounce_addr); 406 + host->bounce_buffer = NULL; 407 + } 408 + of_reserved_mem_device_release(mmc_dev(host->mmc)); 409 + } 410 + 411 + static int sdhci_bst_alloc_bounce_buffer(struct sdhci_host *host) 412 + { 413 + struct mmc_host *mmc = host->mmc; 414 + unsigned int bounce_size; 415 + int ret; 416 + 417 + /* Fixed SRAM bounce size to 32KB: verified config under 32-bit DMA addressing limit */ 418 + bounce_size = SZ_32K; 419 + 420 + ret = of_reserved_mem_device_init_by_idx(mmc_dev(mmc), mmc_dev(mmc)->of_node, 0); 421 + if (ret) { 422 + dev_err(mmc_dev(mmc), "Failed to initialize reserved memory\n"); 423 + return ret; 424 + } 425 + 426 + host->bounce_buffer = dma_alloc_coherent(mmc_dev(mmc), bounce_size, 427 + &host->bounce_addr, GFP_KERNEL); 428 + if (!host->bounce_buffer) 429 + return -ENOMEM; 430 + 431 + host->bounce_buffer_size = bounce_size; 432 + 433 + return 0; 434 + } 435 + 436 + static int sdhci_bst_probe(struct platform_device *pdev) 437 + { 438 + struct sdhci_pltfm_host *pltfm_host; 439 + struct sdhci_host *host; 440 + struct sdhci_bst_priv *priv; 441 + int err; 442 + 443 + host = sdhci_pltfm_init(pdev, &sdhci_bst_pdata, sizeof(struct sdhci_bst_priv)); 444 + if (IS_ERR(host)) 445 + return PTR_ERR(host); 446 + 447 + pltfm_host = sdhci_priv(host); 448 + priv = sdhci_pltfm_priv(pltfm_host); /* Get platform private data */ 449 + 450 + err = mmc_of_parse(host->mmc); 451 + if (err) 452 + return err; 453 + 454 + sdhci_get_of_property(pdev); 455 + 456 + /* Get CRM registers from the second reg entry */ 457 + priv->crm_reg_base = devm_platform_ioremap_resource(pdev, 1); 458 + if (IS_ERR(priv->crm_reg_base)) { 459 + err = PTR_ERR(priv->crm_reg_base); 460 + return err; 461 + } 462 + 463 + /* 464 + * Silicon constraints for BST C1200: 465 + * - System RAM base is 0x800000000 (above 32-bit addressable range) 466 + * - The eMMC controller DMA engine is limited to 32-bit addressing 467 + * - SMMU cannot be used on this path due to hardware design flaws 468 + * - These are fixed in silicon and cannot be changed in software 469 + * 470 + * Bus/controller mapping: 471 + * - No registers are available to reprogram the address mapping 472 + * - The 32-bit DMA limit is a hard constraint of the controller IP 473 + * 474 + * Given these constraints, an SRAM-based bounce buffer in the 32-bit 475 + * address space is required to enable eMMC DMA on this platform. 476 + */ 477 + err = sdhci_bst_alloc_bounce_buffer(host); 478 + if (err) { 479 + dev_err(&pdev->dev, "Failed to allocate bounce buffer: %d\n", err); 480 + return err; 481 + } 482 + 483 + err = sdhci_add_host(host); 484 + if (err) 485 + goto err_free_bounce_buffer; 486 + 487 + return 0; 488 + 489 + err_free_bounce_buffer: 490 + sdhci_bst_free_bounce_buffer(host); 491 + 492 + return err; 493 + } 494 + 495 + static void sdhci_bst_remove(struct platform_device *pdev) 496 + { 497 + struct sdhci_host *host = platform_get_drvdata(pdev); 498 + 499 + sdhci_bst_free_bounce_buffer(host); 500 + sdhci_pltfm_remove(pdev); 501 + } 502 + 503 + static const struct of_device_id sdhci_bst_ids[] = { 504 + { .compatible = "bst,c1200-sdhci" }, 505 + {} 506 + }; 507 + MODULE_DEVICE_TABLE(of, sdhci_bst_ids); 508 + 509 + static struct platform_driver sdhci_bst_driver = { 510 + .driver = { 511 + .name = "sdhci-bst", 512 + .of_match_table = sdhci_bst_ids, 513 + }, 514 + .probe = sdhci_bst_probe, 515 + .remove = sdhci_bst_remove, 516 + }; 517 + module_platform_driver(sdhci_bst_driver); 518 + 519 + MODULE_DESCRIPTION("Black Sesame Technologies SDHCI driver (BST)"); 520 + MODULE_AUTHOR("Black Sesame Technologies Co., Ltd."); 521 + MODULE_LICENSE("GPL");