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

mmc: loongson2: Add Loongson-2K SD/SDIO controller driver

The MMC controllers on the Loongson-2K series CPUs are similar,
except for the interface characteristics and the use of DMA controllers.

This patch describes the MMC controllers on the Loongson-2K0500/2K1000,
with the distinguishing feature being the use of an externally shared
APBDMA engine.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Reviewed-by: Huacai Chen <chenhuacai@loongson.cn>
Link: https://lore.kernel.org/r/c0a9f0c0279d8e09165c6e2d694b0c35f7fc7e31.1750765495.git.zhoubinbin@loongson.cn
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Binbin Zhou and committed by
Ulf Hansson
21157720 fe62ee33

+813
+1
MAINTAINERS
··· 14180 14180 L: linux-mmc@vger.kernel.org 14181 14181 S: Maintained 14182 14182 F: Documentation/devicetree/bindings/mmc/loongson,ls2k0500-mmc.yaml 14183 + F: drivers/mmc/host/loongson2-mmc.c 14183 14184 14184 14185 LOONGSON-2 SOC SERIES PM DRIVER 14185 14186 M: Yinbo Zhu <zhuyinbo@loongson.cn>
+13
drivers/mmc/host/Kconfig
··· 1111 1111 This selects support for the SD/MMC Host Controller on 1112 1112 Actions Semi Owl SoCs. 1113 1113 1114 + config MMC_LOONGSON2 1115 + tristate "Loongson-2K SD/SDIO/eMMC Host Interface support" 1116 + depends on LOONGARCH || COMPILE_TEST 1117 + depends on HAS_DMA 1118 + help 1119 + This selects support for the SD/SDIO/eMMC Host Controller on 1120 + Loongson-2K series CPUs. 1121 + 1122 + To compile this driver as a module, choose M here: the 1123 + module will be called mmc_loongson2. 1124 + 1125 + If unsure, say N. 1126 + 1114 1127 config MMC_SDHCI_EXTERNAL_DMA 1115 1128 bool 1116 1129
+1
drivers/mmc/host/Makefile
··· 72 72 obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o 73 73 obj-$(CONFIG_MMC_BCM2835) += bcm2835.o 74 74 obj-$(CONFIG_MMC_OWL) += owl-mmc.o 75 + obj-$(CONFIG_MMC_LOONGSON2) += loongson2-mmc.o 75 76 76 77 obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o 77 78 obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o
+798
drivers/mmc/host/loongson2-mmc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Loongson-2K MMC/SDIO controller driver 4 + * 5 + * Copyright (C) 2018-2025 Loongson Technology Corporation Limited. 6 + * 7 + */ 8 + 9 + #include <linux/bitfield.h> 10 + #include <linux/bitrev.h> 11 + #include <linux/clk.h> 12 + #include <linux/delay.h> 13 + #include <linux/dmaengine.h> 14 + #include <linux/dma-mapping.h> 15 + #include <linux/interrupt.h> 16 + #include <linux/io.h> 17 + #include <linux/mmc/core.h> 18 + #include <linux/mmc/host.h> 19 + #include <linux/mmc/mmc.h> 20 + #include <linux/mmc/sd.h> 21 + #include <linux/mmc/sdio.h> 22 + #include <linux/mmc/slot-gpio.h> 23 + #include <linux/module.h> 24 + #include <linux/of.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/regmap.h> 27 + 28 + #define LOONGSON2_MMC_REG_CTL 0x00 /* Control Register */ 29 + #define LOONGSON2_MMC_REG_PRE 0x04 /* Prescaler Register */ 30 + #define LOONGSON2_MMC_REG_CARG 0x08 /* Command Register */ 31 + #define LOONGSON2_MMC_REG_CCTL 0x0c /* Command Control Register */ 32 + #define LOONGSON2_MMC_REG_CSTS 0x10 /* Command Status Register */ 33 + #define LOONGSON2_MMC_REG_RSP0 0x14 /* Command Response Register 0 */ 34 + #define LOONGSON2_MMC_REG_RSP1 0x18 /* Command Response Register 1 */ 35 + #define LOONGSON2_MMC_REG_RSP2 0x1c /* Command Response Register 2 */ 36 + #define LOONGSON2_MMC_REG_RSP3 0x20 /* Command Response Register 3 */ 37 + #define LOONGSON2_MMC_REG_TIMER 0x24 /* Data Timeout Register */ 38 + #define LOONGSON2_MMC_REG_BSIZE 0x28 /* Block Size Register */ 39 + #define LOONGSON2_MMC_REG_DCTL 0x2c /* Data Control Register */ 40 + #define LOONGSON2_MMC_REG_DCNT 0x30 /* Data Counter Register */ 41 + #define LOONGSON2_MMC_REG_DSTS 0x34 /* Data Status Register */ 42 + #define LOONGSON2_MMC_REG_FSTS 0x38 /* FIFO Status Register */ 43 + #define LOONGSON2_MMC_REG_INT 0x3c /* Interrupt Register */ 44 + #define LOONGSON2_MMC_REG_DATA 0x40 /* Data Register */ 45 + #define LOONGSON2_MMC_REG_IEN 0x64 /* Interrupt Enable Register */ 46 + 47 + /* Bitfields of control register */ 48 + #define LOONGSON2_MMC_CTL_ENCLK BIT(0) 49 + #define LOONGSON2_MMC_CTL_EXTCLK BIT(1) 50 + #define LOONGSON2_MMC_CTL_RESET BIT(8) 51 + 52 + /* Bitfields of prescaler register */ 53 + #define LOONGSON2_MMC_PRE GENMASK(9, 0) 54 + #define LOONGSON2_MMC_PRE_EN BIT(31) 55 + 56 + /* Bitfields of command control register */ 57 + #define LOONGSON2_MMC_CCTL_INDEX GENMASK(5, 0) 58 + #define LOONGSON2_MMC_CCTL_HOST BIT(6) 59 + #define LOONGSON2_MMC_CCTL_START BIT(8) 60 + #define LOONGSON2_MMC_CCTL_WAIT_RSP BIT(9) 61 + #define LOONGSON2_MMC_CCTL_LONG_RSP BIT(10) 62 + #define LOONGSON2_MMC_CCTL_ABORT BIT(12) 63 + #define LOONGSON2_MMC_CCTL_CHECK BIT(13) 64 + #define LOONGSON2_MMC_CCTL_SDIO BIT(14) 65 + #define LOONGSON2_MMC_CCTL_CMD6 BIT(18) 66 + 67 + /* Bitfields of command status register */ 68 + #define LOONGSON2_MMC_CSTS_INDEX GENMASK(7, 0) 69 + #define LOONGSON2_MMC_CSTS_ON BIT(8) 70 + #define LOONGSON2_MMC_CSTS_RSP BIT(9) 71 + #define LOONGSON2_MMC_CSTS_TIMEOUT BIT(10) 72 + #define LOONGSON2_MMC_CSTS_END BIT(11) 73 + #define LOONGSON2_MMC_CSTS_CRC_ERR BIT(12) 74 + #define LOONGSON2_MMC_CSTS_AUTO_STOP BIT(13) 75 + #define LOONGSON2_MMC_CSTS_FIN BIT(14) 76 + 77 + /* Bitfields of data timeout register */ 78 + #define LOONGSON2_MMC_DTIMR GENMASK(23, 0) 79 + 80 + /* Bitfields of block size register */ 81 + #define LOONGSON2_MMC_BSIZE GENMASK(11, 0) 82 + 83 + /* Bitfields of data control register */ 84 + #define LOONGSON2_MMC_DCTL_BNUM GENMASK(11, 0) 85 + #define LOONGSON2_MMC_DCTL_START BIT(14) 86 + #define LOONGSON2_MMC_DCTL_ENDMA BIT(15) 87 + #define LOONGSON2_MMC_DCTL_WIDE BIT(16) 88 + #define LOONGSON2_MMC_DCTL_RWAIT BIT(17) 89 + #define LOONGSON2_MMC_DCTL_IO_SUSPEND BIT(18) 90 + #define LOONGSON2_MMC_DCTL_IO_RESUME BIT(19) 91 + #define LOONGSON2_MMC_DCTL_RW_RESUME BIT(20) 92 + #define LOONGSON2_MMC_DCTL_8BIT_BUS BIT(26) 93 + 94 + /* Bitfields of sata counter register */ 95 + #define LOONGSON2_MMC_DCNT_BNUM GENMASK(11, 0) 96 + #define LOONGSON2_MMC_DCNT_BYTE GENMASK(23, 12) 97 + 98 + /* Bitfields of command status register */ 99 + #define LOONGSON2_MMC_DSTS_RXON BIT(0) 100 + #define LOONGSON2_MMC_DSTS_TXON BIT(1) 101 + #define LOONGSON2_MMC_DSTS_SBITERR BIT(2) 102 + #define LOONGSON2_MMC_DSTS_BUSYFIN BIT(3) 103 + #define LOONGSON2_MMC_DSTS_XFERFIN BIT(4) 104 + #define LOONGSON2_MMC_DSTS_DTIMEOUT BIT(5) 105 + #define LOONGSON2_MMC_DSTS_RXCRC BIT(6) 106 + #define LOONGSON2_MMC_DSTS_TXCRC BIT(7) 107 + #define LOONGSON2_MMC_DSTS_IRQ BIT(8) 108 + #define LOONGSON2_MMC_DSTS_START BIT(13) 109 + #define LOONGSON2_MMC_DSTS_RESUME BIT(15) 110 + #define LOONGSON2_MMC_DSTS_SUSPEND BIT(16) 111 + 112 + /* Bitfields of interrupt register */ 113 + #define LOONGSON2_MMC_INT_DFIN BIT(0) 114 + #define LOONGSON2_MMC_INT_DTIMEOUT BIT(1) 115 + #define LOONGSON2_MMC_INT_RXCRC BIT(2) 116 + #define LOONGSON2_MMC_INT_TXCRC BIT(3) 117 + #define LOONGSON2_MMC_INT_PROGERR BIT(4) 118 + #define LOONGSON2_MMC_INT_SDIOIRQ BIT(5) 119 + #define LOONGSON2_MMC_INT_CSENT BIT(6) 120 + #define LOONGSON2_MMC_INT_CTIMEOUT BIT(7) 121 + #define LOONGSON2_MMC_INT_RESPCRC BIT(8) 122 + #define LOONGSON2_MMC_INT_BUSYEND BIT(9) 123 + 124 + /* Bitfields of interrupt enable register */ 125 + #define LOONGSON2_MMC_IEN_DFIN BIT(0) 126 + #define LOONGSON2_MMC_IEN_DTIMEOUT BIT(1) 127 + #define LOONGSON2_MMC_IEN_RXCRC BIT(2) 128 + #define LOONGSON2_MMC_IEN_TXCRC BIT(3) 129 + #define LOONGSON2_MMC_IEN_PROGERR BIT(4) 130 + #define LOONGSON2_MMC_IEN_SDIOIRQ BIT(5) 131 + #define LOONGSON2_MMC_IEN_CSENT BIT(6) 132 + #define LOONGSON2_MMC_IEN_CTIMEOUT BIT(7) 133 + #define LOONGSON2_MMC_IEN_RESPCRC BIT(8) 134 + #define LOONGSON2_MMC_IEN_BUSYEND BIT(9) 135 + 136 + #define LOONGSON2_MMC_IEN_ALL GENMASK(9, 0) 137 + #define LOONGSON2_MMC_INT_CLEAR GENMASK(9, 0) 138 + 139 + /* Loongson-2K1000 SDIO2 DMA routing register */ 140 + #define LS2K1000_SDIO_DMA_MASK GENMASK(17, 15) 141 + #define LS2K1000_DMA0_CONF 0x0 142 + #define LS2K1000_DMA1_CONF 0x1 143 + #define LS2K1000_DMA2_CONF 0x2 144 + #define LS2K1000_DMA3_CONF 0x3 145 + #define LS2K1000_DMA4_CONF 0x4 146 + 147 + /* Loongson-2K0500 SDIO2 DMA routing register */ 148 + #define LS2K0500_SDIO_DMA_MASK GENMASK(15, 14) 149 + #define LS2K0500_DMA0_CONF 0x1 150 + #define LS2K0500_DMA1_CONF 0x2 151 + #define LS2K0500_DMA2_CONF 0x3 152 + 153 + enum loongson2_mmc_state { 154 + STATE_NONE, 155 + STATE_FINALIZE, 156 + STATE_CMDSENT, 157 + STATE_RSPFIN, 158 + STATE_XFERFINISH, 159 + STATE_XFERFINISH_RSPFIN, 160 + }; 161 + 162 + struct loongson2_mmc_host { 163 + struct device *dev; 164 + struct mmc_request *mrq; 165 + struct regmap *regmap; 166 + struct resource *res; 167 + struct clk *clk; 168 + u32 current_clk; 169 + int dma_complete; 170 + struct dma_chan *chan; 171 + int cmd_is_stop; 172 + int bus_width; 173 + spinlock_t lock; /* Prevent races with irq handler */ 174 + enum loongson2_mmc_state state; 175 + const struct loongson2_mmc_pdata *pdata; 176 + }; 177 + 178 + struct loongson2_mmc_pdata { 179 + const struct regmap_config *regmap_config; 180 + void (*reorder_cmd_data)(struct loongson2_mmc_host *host, struct mmc_command *cmd); 181 + int (*setting_dma)(struct loongson2_mmc_host *host, struct platform_device *pdev); 182 + int (*prepare_dma)(struct loongson2_mmc_host *host, struct mmc_data *data); 183 + void (*release_dma)(struct loongson2_mmc_host *host, struct device *dev); 184 + }; 185 + 186 + static void loongson2_mmc_send_command(struct loongson2_mmc_host *host, 187 + struct mmc_command *cmd) 188 + { 189 + u32 cctrl; 190 + 191 + if (cmd->data) 192 + host->state = STATE_XFERFINISH_RSPFIN; 193 + else if (cmd->flags & MMC_RSP_PRESENT) 194 + host->state = STATE_RSPFIN; 195 + else 196 + host->state = STATE_CMDSENT; 197 + 198 + regmap_write(host->regmap, LOONGSON2_MMC_REG_CARG, cmd->arg); 199 + 200 + cctrl = FIELD_PREP(LOONGSON2_MMC_CCTL_INDEX, cmd->opcode); 201 + cctrl |= LOONGSON2_MMC_CCTL_HOST | LOONGSON2_MMC_CCTL_START; 202 + 203 + if (cmd->opcode == SD_SWITCH && cmd->data) 204 + cctrl |= LOONGSON2_MMC_CCTL_CMD6; 205 + 206 + if (cmd->flags & MMC_RSP_PRESENT) 207 + cctrl |= LOONGSON2_MMC_CCTL_WAIT_RSP; 208 + 209 + if (cmd->flags & MMC_RSP_136) 210 + cctrl |= LOONGSON2_MMC_CCTL_LONG_RSP; 211 + 212 + regmap_write(host->regmap, LOONGSON2_MMC_REG_CCTL, cctrl); 213 + } 214 + 215 + static int loongson2_mmc_setup_data(struct loongson2_mmc_host *host, 216 + struct mmc_data *data) 217 + { 218 + u32 dctrl; 219 + 220 + if ((data->blksz & 3) != 0) 221 + return -EINVAL; 222 + 223 + dctrl = FIELD_PREP(LOONGSON2_MMC_DCTL_BNUM, data->blocks); 224 + dctrl |= LOONGSON2_MMC_DCTL_START | LOONGSON2_MMC_DCTL_ENDMA; 225 + 226 + if (host->bus_width == MMC_BUS_WIDTH_4) 227 + dctrl |= LOONGSON2_MMC_DCTL_WIDE; 228 + else if (host->bus_width == MMC_BUS_WIDTH_8) 229 + dctrl |= LOONGSON2_MMC_DCTL_8BIT_BUS; 230 + 231 + regmap_write(host->regmap, LOONGSON2_MMC_REG_DCTL, dctrl); 232 + regmap_write(host->regmap, LOONGSON2_MMC_REG_BSIZE, data->blksz); 233 + regmap_write(host->regmap, LOONGSON2_MMC_REG_TIMER, U32_MAX); 234 + 235 + return 0; 236 + } 237 + 238 + static int loongson2_mmc_prepare_dma(struct loongson2_mmc_host *host, 239 + struct mmc_data *data) 240 + { 241 + int ret; 242 + 243 + if (!data) 244 + return 0; 245 + 246 + ret = loongson2_mmc_setup_data(host, data); 247 + if (ret) 248 + return ret; 249 + 250 + host->dma_complete = 0; 251 + 252 + return host->pdata->prepare_dma(host, data); 253 + } 254 + 255 + static void loongson2_mmc_send_request(struct mmc_host *mmc) 256 + { 257 + int ret; 258 + struct loongson2_mmc_host *host = mmc_priv(mmc); 259 + struct mmc_request *mrq = host->mrq; 260 + struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; 261 + 262 + ret = loongson2_mmc_prepare_dma(host, cmd->data); 263 + if (ret) { 264 + dev_err(host->dev, "DMA data prepared failed with %d\n", ret); 265 + cmd->error = ret; 266 + cmd->data->error = ret; 267 + mmc_request_done(mmc, mrq); 268 + return; 269 + } 270 + 271 + loongson2_mmc_send_command(host, cmd); 272 + 273 + /* Fix deselect card */ 274 + if (cmd->opcode == MMC_SELECT_CARD && cmd->arg == 0) { 275 + cmd->error = 0; 276 + mmc_request_done(mmc, mrq); 277 + } 278 + } 279 + 280 + static irqreturn_t loongson2_mmc_irq_worker(int irq, void *devid) 281 + { 282 + struct loongson2_mmc_host *host = (struct loongson2_mmc_host *)devid; 283 + struct mmc_host *mmc = mmc_from_priv(host); 284 + struct mmc_request *mrq = host->mrq; 285 + struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; 286 + 287 + if (cmd->data) 288 + dma_unmap_sg(mmc_dev(mmc), cmd->data->sg, cmd->data->sg_len, 289 + mmc_get_dma_dir(cmd->data)); 290 + 291 + if (cmd->data && !cmd->error && 292 + !cmd->data->error && !host->dma_complete) 293 + return IRQ_HANDLED; 294 + 295 + /* Read response from controller. */ 296 + regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP0, &cmd->resp[0]); 297 + regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP1, &cmd->resp[1]); 298 + regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP2, &cmd->resp[2]); 299 + regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP3, &cmd->resp[3]); 300 + 301 + /* Cleanup controller */ 302 + regmap_write(host->regmap, LOONGSON2_MMC_REG_CARG, 0); 303 + regmap_write(host->regmap, LOONGSON2_MMC_REG_CCTL, 0); 304 + 305 + if (cmd->data && cmd->error) 306 + cmd->data->error = cmd->error; 307 + 308 + if (cmd->data && cmd->data->stop && !host->cmd_is_stop) { 309 + host->cmd_is_stop = 1; 310 + loongson2_mmc_send_request(mmc); 311 + return IRQ_HANDLED; 312 + } 313 + 314 + /* If we have no data transfer we are finished here */ 315 + if (!mrq->data) 316 + goto request_done; 317 + 318 + /* Calculate the amount of bytes transfer if there was no error */ 319 + if (mrq->data->error == 0) { 320 + mrq->data->bytes_xfered = 321 + (mrq->data->blocks * mrq->data->blksz); 322 + } else { 323 + mrq->data->bytes_xfered = 0; 324 + } 325 + 326 + request_done: 327 + host->state = STATE_NONE; 328 + host->mrq = NULL; 329 + mmc_request_done(mmc, mrq); 330 + return IRQ_HANDLED; 331 + } 332 + 333 + static irqreturn_t loongson2_mmc_irq(int irq, void *devid) 334 + { 335 + struct loongson2_mmc_host *host = (struct loongson2_mmc_host *)devid; 336 + struct mmc_host *mmc = mmc_from_priv(host); 337 + struct mmc_command *cmd; 338 + unsigned long iflags; 339 + u32 dsts, imsk; 340 + 341 + regmap_read(host->regmap, LOONGSON2_MMC_REG_INT, &imsk); 342 + regmap_read(host->regmap, LOONGSON2_MMC_REG_DSTS, &dsts); 343 + 344 + if ((dsts & LOONGSON2_MMC_DSTS_IRQ) && 345 + (imsk & LOONGSON2_MMC_INT_SDIOIRQ)) { 346 + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_INT, 347 + LOONGSON2_MMC_INT_SDIOIRQ, LOONGSON2_MMC_INT_SDIOIRQ); 348 + 349 + sdio_signal_irq(mmc); 350 + return IRQ_HANDLED; 351 + } 352 + 353 + spin_lock_irqsave(&host->lock, iflags); 354 + 355 + if (host->state == STATE_NONE || host->state == STATE_FINALIZE || !host->mrq) 356 + goto irq_out; 357 + 358 + cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd; 359 + if (!cmd) 360 + goto irq_out; 361 + 362 + cmd->error = 0; 363 + 364 + if (imsk & LOONGSON2_MMC_INT_CTIMEOUT) { 365 + cmd->error = -ETIMEDOUT; 366 + goto close_transfer; 367 + } 368 + 369 + if (imsk & LOONGSON2_MMC_INT_CSENT) { 370 + if (host->state == STATE_RSPFIN || host->state == STATE_CMDSENT) 371 + goto close_transfer; 372 + 373 + if (host->state == STATE_XFERFINISH_RSPFIN) 374 + host->state = STATE_XFERFINISH; 375 + } 376 + 377 + if (!cmd->data) 378 + goto irq_out; 379 + 380 + if (imsk & (LOONGSON2_MMC_INT_RXCRC | LOONGSON2_MMC_INT_TXCRC)) { 381 + cmd->data->error = -EILSEQ; 382 + goto close_transfer; 383 + } 384 + 385 + if (imsk & LOONGSON2_MMC_INT_DTIMEOUT) { 386 + cmd->data->error = -ETIMEDOUT; 387 + goto close_transfer; 388 + } 389 + 390 + if (imsk & LOONGSON2_MMC_INT_DFIN) { 391 + if (host->state == STATE_XFERFINISH) { 392 + host->dma_complete = 1; 393 + goto close_transfer; 394 + } 395 + 396 + if (host->state == STATE_XFERFINISH_RSPFIN) 397 + host->state = STATE_RSPFIN; 398 + } 399 + 400 + irq_out: 401 + regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, imsk); 402 + spin_unlock_irqrestore(&host->lock, iflags); 403 + return IRQ_HANDLED; 404 + 405 + close_transfer: 406 + host->state = STATE_FINALIZE; 407 + host->pdata->reorder_cmd_data(host, cmd); 408 + regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, imsk); 409 + spin_unlock_irqrestore(&host->lock, iflags); 410 + return IRQ_WAKE_THREAD; 411 + } 412 + 413 + static void loongson2_mmc_set_clk(struct loongson2_mmc_host *host, struct mmc_ios *ios) 414 + { 415 + u32 pre; 416 + 417 + pre = DIV_ROUND_UP(host->current_clk, ios->clock); 418 + if (pre > 255) 419 + pre = 255; 420 + 421 + regmap_write(host->regmap, LOONGSON2_MMC_REG_PRE, pre | LOONGSON2_MMC_PRE_EN); 422 + 423 + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL, 424 + LOONGSON2_MMC_CTL_ENCLK, LOONGSON2_MMC_CTL_ENCLK); 425 + } 426 + 427 + static void loongson2_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 428 + { 429 + struct loongson2_mmc_host *host = mmc_priv(mmc); 430 + int ret; 431 + 432 + if (ios->power_mode == MMC_POWER_UP) { 433 + if (!IS_ERR(mmc->supply.vmmc)) { 434 + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); 435 + if (ret) { 436 + dev_err(host->dev, "failed to enable vmmc regulator\n"); 437 + return; /* return, if failed turn on vmmc */ 438 + } 439 + } 440 + regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_RESET); 441 + mdelay(10); 442 + regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_EXTCLK); 443 + regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, LOONGSON2_MMC_IEN_ALL); 444 + regmap_write(host->regmap, LOONGSON2_MMC_REG_IEN, LOONGSON2_MMC_INT_CLEAR); 445 + } else if (ios->power_mode == MMC_POWER_OFF) { 446 + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL, 447 + LOONGSON2_MMC_CTL_RESET, LOONGSON2_MMC_CTL_RESET); 448 + if (!IS_ERR(mmc->supply.vmmc)) 449 + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 450 + return; 451 + } 452 + 453 + loongson2_mmc_set_clk(host, ios); 454 + 455 + host->bus_width = ios->bus_width; 456 + } 457 + 458 + static void loongson2_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) 459 + { 460 + struct loongson2_mmc_host *host = mmc_priv(mmc); 461 + 462 + host->cmd_is_stop = 0; 463 + host->mrq = mrq; 464 + loongson2_mmc_send_request(mmc); 465 + } 466 + 467 + static void loongson2_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) 468 + { 469 + struct loongson2_mmc_host *host = mmc_priv(mmc); 470 + 471 + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_IEN, LOONGSON2_MMC_INT_SDIOIRQ, enable); 472 + } 473 + 474 + static void loongson2_mmc_ack_sdio_irq(struct mmc_host *mmc) 475 + { 476 + loongson2_mmc_enable_sdio_irq(mmc, 1); 477 + } 478 + 479 + static struct mmc_host_ops loongson2_mmc_ops = { 480 + .request = loongson2_mmc_request, 481 + .set_ios = loongson2_mmc_set_ios, 482 + .get_ro = mmc_gpio_get_ro, 483 + .get_cd = mmc_gpio_get_cd, 484 + .enable_sdio_irq = loongson2_mmc_enable_sdio_irq, 485 + .ack_sdio_irq = loongson2_mmc_ack_sdio_irq, 486 + }; 487 + 488 + static const struct regmap_config ls2k1000_mmc_regmap_config = { 489 + .reg_bits = 32, 490 + .val_bits = 32, 491 + .reg_stride = 4, 492 + .max_register = LOONGSON2_MMC_REG_IEN, 493 + }; 494 + 495 + static int loongson2_reorder_cmd_list[] = { SD_APP_SEND_SCR, SD_APP_SEND_NUM_WR_BLKS, 496 + SD_APP_SD_STATUS, MMC_SEND_WRITE_PROT, SD_SWITCH }; 497 + 498 + /* 499 + * According to SD spec, ACMD13, ACMD22, ACMD51 and CMD30 500 + * response datas has different byte order with usual data packets. 501 + * However sdio controller will send these datas in usual data format, 502 + * so we need to adjust these datas to a protocol consistent byte order. 503 + */ 504 + static void loongson2_mmc_reorder_cmd_data(struct loongson2_mmc_host *host, 505 + struct mmc_command *cmd) 506 + { 507 + struct scatterlist *sg; 508 + u32 *data; 509 + int i, j; 510 + 511 + if (mmc_cmd_type(cmd) != MMC_CMD_ADTC) 512 + return; 513 + 514 + for (i = 0; i < ARRAY_SIZE(loongson2_reorder_cmd_list); i++) 515 + if (cmd->opcode == loongson2_reorder_cmd_list[i]) 516 + break; 517 + 518 + if (i == ARRAY_SIZE(loongson2_reorder_cmd_list)) 519 + return; 520 + 521 + for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) { 522 + data = sg_virt(&sg[i]); 523 + for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++) 524 + if (cmd->opcode == SD_SWITCH) 525 + data[j] = bitrev8x4(data[j]); 526 + else 527 + data[j] = (__force u32)cpu_to_be32(data[j]); 528 + } 529 + } 530 + 531 + static int loongson2_mmc_prepare_external_dma(struct loongson2_mmc_host *host, 532 + struct mmc_data *data) 533 + { 534 + struct mmc_host *mmc = mmc_from_priv(host); 535 + struct dma_slave_config dma_conf = { }; 536 + struct dma_async_tx_descriptor *desc; 537 + int ret; 538 + 539 + ret = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, 540 + mmc_get_dma_dir(data)); 541 + if (!ret) 542 + return -ENOMEM; 543 + 544 + dma_conf.src_addr = host->res->start + LOONGSON2_MMC_REG_DATA, 545 + dma_conf.dst_addr = host->res->start + LOONGSON2_MMC_REG_DATA, 546 + dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 547 + dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 548 + dma_conf.direction = !(data->flags & MMC_DATA_WRITE) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; 549 + 550 + dmaengine_slave_config(host->chan, &dma_conf); 551 + desc = dmaengine_prep_slave_sg(host->chan, data->sg, data->sg_len, 552 + dma_conf.direction, 553 + DMA_CTRL_ACK | DMA_PREP_INTERRUPT); 554 + if (!desc) 555 + goto unmap_exit; 556 + 557 + dmaengine_submit(desc); 558 + dma_async_issue_pending(host->chan); 559 + 560 + return 0; 561 + 562 + unmap_exit: 563 + dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len, mmc_get_dma_dir(data)); 564 + return -ENOMEM; 565 + } 566 + 567 + static void loongson2_mmc_release_external_dma(struct loongson2_mmc_host *host, 568 + struct device *dev) 569 + { 570 + dma_release_channel(host->chan); 571 + } 572 + 573 + static int ls2k0500_mmc_set_external_dma(struct loongson2_mmc_host *host, 574 + struct platform_device *pdev) 575 + { 576 + int ret, val; 577 + void __iomem *regs; 578 + 579 + regs = devm_platform_ioremap_resource(pdev, 1); 580 + if (IS_ERR(regs)) 581 + return PTR_ERR(regs); 582 + 583 + val = readl(regs); 584 + val |= FIELD_PREP(LS2K0500_SDIO_DMA_MASK, LS2K0500_DMA2_CONF); 585 + writel(val, regs); 586 + 587 + host->chan = dma_request_chan(&pdev->dev, "rx-tx"); 588 + ret = PTR_ERR_OR_ZERO(host->chan); 589 + if (ret) { 590 + dev_err(&pdev->dev, "Cannot get DMA channel.\n"); 591 + return ret; 592 + } 593 + 594 + return 0; 595 + } 596 + 597 + static struct loongson2_mmc_pdata ls2k0500_mmc_pdata = { 598 + .regmap_config = &ls2k1000_mmc_regmap_config, 599 + .reorder_cmd_data = loongson2_mmc_reorder_cmd_data, 600 + .setting_dma = ls2k0500_mmc_set_external_dma, 601 + .prepare_dma = loongson2_mmc_prepare_external_dma, 602 + .release_dma = loongson2_mmc_release_external_dma, 603 + }; 604 + 605 + static int ls2k1000_mmc_set_external_dma(struct loongson2_mmc_host *host, 606 + struct platform_device *pdev) 607 + { 608 + int ret, val; 609 + void __iomem *regs; 610 + 611 + regs = devm_platform_ioremap_resource(pdev, 1); 612 + if (IS_ERR(regs)) 613 + return PTR_ERR(regs); 614 + 615 + val = readl(regs); 616 + val |= FIELD_PREP(LS2K1000_SDIO_DMA_MASK, LS2K1000_DMA1_CONF); 617 + writel(val, regs); 618 + 619 + host->chan = dma_request_chan(&pdev->dev, "rx-tx"); 620 + ret = PTR_ERR_OR_ZERO(host->chan); 621 + if (ret) { 622 + dev_err(&pdev->dev, "Cannot get DMA channel.\n"); 623 + return ret; 624 + } 625 + 626 + return 0; 627 + } 628 + 629 + static struct loongson2_mmc_pdata ls2k1000_mmc_pdata = { 630 + .regmap_config = &ls2k1000_mmc_regmap_config, 631 + .reorder_cmd_data = loongson2_mmc_reorder_cmd_data, 632 + .setting_dma = ls2k1000_mmc_set_external_dma, 633 + .prepare_dma = loongson2_mmc_prepare_external_dma, 634 + .release_dma = loongson2_mmc_release_external_dma, 635 + }; 636 + 637 + static int loongson2_mmc_resource_request(struct platform_device *pdev, 638 + struct loongson2_mmc_host *host) 639 + { 640 + struct device *dev = &pdev->dev; 641 + void __iomem *base; 642 + int ret, irq; 643 + 644 + base = devm_platform_get_and_ioremap_resource(pdev, 0, &host->res); 645 + if (IS_ERR(base)) 646 + return PTR_ERR(base); 647 + 648 + host->regmap = devm_regmap_init_mmio(dev, base, host->pdata->regmap_config); 649 + if (IS_ERR(host->regmap)) 650 + return PTR_ERR(host->regmap); 651 + 652 + host->clk = devm_clk_get_optional_enabled(dev, NULL); 653 + if (IS_ERR(host->clk)) 654 + return PTR_ERR(host->clk); 655 + 656 + if (host->clk) { 657 + ret = devm_clk_rate_exclusive_get(dev, host->clk); 658 + if (ret) 659 + return PTR_ERR(host->clk); 660 + 661 + host->current_clk = clk_get_rate(host->clk); 662 + } else { 663 + /* For ACPI, the clock is accessed via the clock-frequency attribute. */ 664 + device_property_read_u32(dev, "clock-frequency", &host->current_clk); 665 + } 666 + 667 + irq = platform_get_irq(pdev, 0); 668 + if (irq < 0) 669 + return irq; 670 + 671 + ret = devm_request_threaded_irq(dev, irq, loongson2_mmc_irq, 672 + loongson2_mmc_irq_worker, 673 + IRQF_ONESHOT, "loongson2-mmc", host); 674 + if (ret) 675 + return ret; 676 + 677 + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 678 + if (ret) 679 + return ret; 680 + 681 + return host->pdata->setting_dma(host, pdev); 682 + } 683 + 684 + static int loongson2_mmc_probe(struct platform_device *pdev) 685 + { 686 + struct device *dev = &pdev->dev; 687 + struct loongson2_mmc_host *host; 688 + struct mmc_host *mmc; 689 + int ret; 690 + 691 + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); 692 + if (!mmc) 693 + return -ENOMEM; 694 + 695 + platform_set_drvdata(pdev, mmc); 696 + 697 + host = mmc_priv(mmc); 698 + host->state = STATE_NONE; 699 + spin_lock_init(&host->lock); 700 + 701 + host->pdata = device_get_match_data(dev); 702 + if (!host->pdata) 703 + return dev_err_probe(dev, -EINVAL, "Failed to get match data\n"); 704 + 705 + ret = loongson2_mmc_resource_request(pdev, host); 706 + if (ret) 707 + return dev_err_probe(dev, ret, "Failed to request resource\n"); 708 + 709 + mmc->ops = &loongson2_mmc_ops; 710 + mmc->f_min = DIV_ROUND_UP(host->current_clk, 256); 711 + mmc->f_max = host->current_clk; 712 + mmc->max_blk_count = 4095; 713 + mmc->max_blk_size = 4095; 714 + mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; 715 + mmc->max_segs = 1; 716 + mmc->max_seg_size = mmc->max_req_size; 717 + 718 + /* Process SDIO IRQs through the sdio_irq_work. */ 719 + if (mmc->caps & MMC_CAP_SDIO_IRQ) 720 + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; 721 + 722 + ret = mmc_regulator_get_supply(mmc); 723 + if (ret || mmc->ocr_avail == 0) { 724 + dev_warn(dev, "Can't get voltage, defaulting to 3.3V\n"); 725 + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 726 + } 727 + 728 + ret = mmc_of_parse(mmc); 729 + if (ret) { 730 + dev_err(dev, "Failed to parse device node\n"); 731 + goto free_dma; 732 + } 733 + 734 + ret = mmc_add_host(mmc); 735 + if (ret) { 736 + dev_err(dev, "Failed to add mmc host\n"); 737 + goto free_dma; 738 + } 739 + 740 + return 0; 741 + 742 + free_dma: 743 + host->pdata->release_dma(host, dev); 744 + return ret; 745 + } 746 + 747 + static void loongson2_mmc_remove(struct platform_device *pdev) 748 + { 749 + struct mmc_host *mmc = platform_get_drvdata(pdev); 750 + struct loongson2_mmc_host *host = mmc_priv(mmc); 751 + 752 + mmc_remove_host(mmc); 753 + host->pdata->release_dma(host, &pdev->dev); 754 + } 755 + 756 + static const struct of_device_id loongson2_mmc_of_ids[] = { 757 + { .compatible = "loongson,ls2k0500-mmc", .data = &ls2k0500_mmc_pdata }, 758 + { .compatible = "loongson,ls2k1000-mmc", .data = &ls2k1000_mmc_pdata }, 759 + { }, 760 + }; 761 + MODULE_DEVICE_TABLE(of, loongson2_mmc_of_ids); 762 + 763 + static int loongson2_mmc_suspend(struct device *dev) 764 + { 765 + struct mmc_host *mmc = dev_get_drvdata(dev); 766 + struct loongson2_mmc_host *host = mmc_priv(mmc); 767 + 768 + clk_disable_unprepare(host->clk); 769 + 770 + return 0; 771 + } 772 + 773 + static int loongson2_mmc_resume(struct device *dev) 774 + { 775 + struct mmc_host *mmc = dev_get_drvdata(dev); 776 + struct loongson2_mmc_host *host = mmc_priv(mmc); 777 + 778 + return clk_prepare_enable(host->clk); 779 + } 780 + 781 + static DEFINE_SIMPLE_DEV_PM_OPS(loongson2_mmc_pm_ops, loongson2_mmc_suspend, loongson2_mmc_resume); 782 + 783 + static struct platform_driver loongson2_mmc_driver = { 784 + .driver = { 785 + .name = "loongson2-mmc", 786 + .of_match_table = loongson2_mmc_of_ids, 787 + .pm = pm_ptr(&loongson2_mmc_pm_ops), 788 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 789 + }, 790 + .probe = loongson2_mmc_probe, 791 + .remove = loongson2_mmc_remove, 792 + }; 793 + 794 + module_platform_driver(loongson2_mmc_driver); 795 + 796 + MODULE_DESCRIPTION("Loongson-2K SD/SDIO/eMMC Interface driver"); 797 + MODULE_AUTHOR("Loongson Technology Corporation Limited"); 798 + MODULE_LICENSE("GPL");