Skip to content

Commit aed2723

Browse files
AaronDotKexyBiscuit
authored andcommitted
UPSTREAM: mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver
This patch describes the two MMC controllers of the Loongson-2K2000 SoC, one providing an eMMC interface and the other exporting an SD/SDIO interface. Compared to the Loongson-2K1000's MMC controllers, their internals are similar, except that we use an internally exclusive DMA engine instead of an externally shared APBDMA engine. Signed-off-by: Binbin Zhou <[email protected]> Reviewed-by: Huacai Chen <[email protected]> Link: https://lore.kernel.org/r/1df46b976abd36003bd553ad8a039e5c97369df0.1750765495.git.zhoubinbin@loongson.cn Signed-off-by: Ulf Hansson <[email protected]> (cherry picked from commit d0f8e96) Signed-off-by: Kexy Biscuit <[email protected]>
1 parent c60cffd commit aed2723

File tree

1 file changed

+231
-0
lines changed

1 file changed

+231
-0
lines changed

drivers/mmc/host/loongson2-mmc.c

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@
4444
#define LOONGSON2_MMC_REG_DATA 0x40 /* Data Register */
4545
#define LOONGSON2_MMC_REG_IEN 0x64 /* Interrupt Enable Register */
4646

47+
/* EMMC DLL Mode Registers */
48+
#define LOONGSON2_MMC_REG_DLLVAL 0xf0 /* DLL Master Lock-value Register */
49+
#define LOONGSON2_MMC_REG_DLLCTL 0xf4 /* DLL Control Register */
50+
#define LOONGSON2_MMC_REG_DELAY 0xf8 /* DLL Delayed Parameter Register */
51+
#define LOONGSON2_MMC_REG_SEL 0xfc /* Bus Mode Selection Register */
52+
53+
/* Exclusive DMA R/W Registers */
54+
#define LOONGSON2_MMC_REG_WDMA_LO 0x400
55+
#define LOONGSON2_MMC_REG_WDMA_HI 0x404
56+
#define LOONGSON2_MMC_REG_RDMA_LO 0x800
57+
#define LOONGSON2_MMC_REG_RDMA_HI 0x804
58+
4759
/* Bitfields of control register */
4860
#define LOONGSON2_MMC_CTL_ENCLK BIT(0)
4961
#define LOONGSON2_MMC_CTL_EXTCLK BIT(1)
@@ -109,6 +121,9 @@
109121
#define LOONGSON2_MMC_DSTS_RESUME BIT(15)
110122
#define LOONGSON2_MMC_DSTS_SUSPEND BIT(16)
111123

124+
/* Bitfields of FIFO Status Register */
125+
#define LOONGSON2_MMC_FSTS_TXFULL BIT(11)
126+
112127
/* Bitfields of interrupt register */
113128
#define LOONGSON2_MMC_INT_DFIN BIT(0)
114129
#define LOONGSON2_MMC_INT_DTIMEOUT BIT(1)
@@ -136,6 +151,44 @@
136151
#define LOONGSON2_MMC_IEN_ALL GENMASK(9, 0)
137152
#define LOONGSON2_MMC_INT_CLEAR GENMASK(9, 0)
138153

154+
/* Bitfields of DLL master lock-value register */
155+
#define LOONGSON2_MMC_DLLVAL_DONE BIT(8)
156+
157+
/* Bitfields of DLL control register */
158+
#define LOONGSON2_MMC_DLLCTL_TIME GENMASK(7, 0)
159+
#define LOONGSON2_MMC_DLLCTL_INCRE GENMASK(15, 8)
160+
#define LOONGSON2_MMC_DLLCTL_START GENMASK(23, 16)
161+
#define LOONGSON2_MMC_DLLCTL_CLK_MODE BIT(24)
162+
#define LOONGSON2_MMC_DLLCTL_START_BIT BIT(25)
163+
#define LOONGSON2_MMC_DLLCTL_TIME_BPASS GENMASK(29, 26)
164+
165+
#define LOONGSON2_MMC_DELAY_PAD GENMASK(7, 0)
166+
#define LOONGSON2_MMC_DELAY_RD GENMASK(15, 8)
167+
168+
#define LOONGSON2_MMC_SEL_DATA BIT(0) /* 0: SDR, 1: DDR */
169+
#define LOONGSON2_MMC_SEL_BUS BIT(0) /* 0: EMMC, 1: SDIO */
170+
171+
/* Internal dma controller registers */
172+
173+
/* Bitfields of Global Configuration Register */
174+
#define LOONGSON2_MMC_DMA_64BIT_EN BIT(0) /* 1: 64 bit support */
175+
#define LOONGSON2_MMC_DMA_UNCOHERENT_EN BIT(1) /* 0: cache, 1: uncache */
176+
#define LOONGSON2_MMC_DMA_ASK_VALID BIT(2)
177+
#define LOONGSON2_MMC_DMA_START BIT(3) /* DMA start operation */
178+
#define LOONGSON2_MMC_DMA_STOP BIT(4) /* DMA stop operation */
179+
#define LOONGSON2_MMC_DMA_CONFIG_MASK GENMASK_ULL(4, 0) /* DMA controller config bits mask */
180+
181+
/* Bitfields of ndesc_addr field of HW descriptor */
182+
#define LOONGSON2_MMC_DMA_DESC_EN BIT(0) /*1: The next descriptor is valid */
183+
#define LOONGSON2_MMC_DMA_DESC_ADDR_LOW GENMASK(31, 1)
184+
185+
/* Bitfields of cmd field of HW descriptor */
186+
#define LOONGSON2_MMC_DMA_INT BIT(1) /* Enable DMA interrupts */
187+
#define LOONGSON2_MMC_DMA_DATA_DIR BIT(12) /* 1: write to device, 0: read from device */
188+
189+
#define LOONGSON2_MMC_DLLVAL_TIMEOUT_US 4000
190+
#define LOONGSON2_MMC_TXFULL_TIMEOUT_US 500
191+
139192
/* Loongson-2K1000 SDIO2 DMA routing register */
140193
#define LS2K1000_SDIO_DMA_MASK GENMASK(17, 15)
141194
#define LS2K1000_DMA0_CONF 0x0
@@ -159,13 +212,29 @@ enum loongson2_mmc_state {
159212
STATE_XFERFINISH_RSPFIN,
160213
};
161214

215+
struct loongson2_dma_desc {
216+
u32 ndesc_addr;
217+
u32 mem_addr;
218+
u32 apb_addr;
219+
u32 len;
220+
u32 step_len;
221+
u32 step_times;
222+
u32 cmd;
223+
u32 stats;
224+
u32 high_ndesc_addr;
225+
u32 high_mem_addr;
226+
u32 reserved[2];
227+
} __packed;
228+
162229
struct loongson2_mmc_host {
163230
struct device *dev;
164231
struct mmc_request *mrq;
165232
struct regmap *regmap;
166233
struct resource *res;
167234
struct clk *clk;
168235
u32 current_clk;
236+
void *sg_cpu;
237+
dma_addr_t sg_dma;
169238
int dma_complete;
170239
struct dma_chan *chan;
171240
int cmd_is_stop;
@@ -178,6 +247,7 @@ struct loongson2_mmc_host {
178247
struct loongson2_mmc_pdata {
179248
const struct regmap_config *regmap_config;
180249
void (*reorder_cmd_data)(struct loongson2_mmc_host *host, struct mmc_command *cmd);
250+
void (*fix_data_timeout)(struct loongson2_mmc_host *host, struct mmc_command *cmd);
181251
int (*setting_dma)(struct loongson2_mmc_host *host, struct platform_device *pdev);
182252
int (*prepare_dma)(struct loongson2_mmc_host *host, struct mmc_data *data);
183253
void (*release_dma)(struct loongson2_mmc_host *host, struct device *dev);
@@ -268,6 +338,9 @@ static void loongson2_mmc_send_request(struct mmc_host *mmc)
268338
return;
269339
}
270340

341+
if (host->pdata->fix_data_timeout)
342+
host->pdata->fix_data_timeout(host, cmd);
343+
271344
loongson2_mmc_send_command(host, cmd);
272345

273346
/* Fix deselect card */
@@ -410,6 +483,37 @@ static irqreturn_t loongson2_mmc_irq(int irq, void *devid)
410483
return IRQ_WAKE_THREAD;
411484
}
412485

486+
static void loongson2_mmc_dll_mode_init(struct loongson2_mmc_host *host)
487+
{
488+
u32 val, pad_delay, delay, ret;
489+
490+
regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_SEL,
491+
LOONGSON2_MMC_SEL_DATA, LOONGSON2_MMC_SEL_DATA);
492+
493+
val = FIELD_PREP(LOONGSON2_MMC_DLLCTL_TIME, 0xc8)
494+
| FIELD_PREP(LOONGSON2_MMC_DLLCTL_INCRE, 0x1)
495+
| FIELD_PREP(LOONGSON2_MMC_DLLCTL_START, 0x1)
496+
| FIELD_PREP(LOONGSON2_MMC_DLLCTL_CLK_MODE, 0x1)
497+
| FIELD_PREP(LOONGSON2_MMC_DLLCTL_START_BIT, 0x1)
498+
| FIELD_PREP(LOONGSON2_MMC_DLLCTL_TIME_BPASS, 0xf);
499+
500+
regmap_write(host->regmap, LOONGSON2_MMC_REG_DLLCTL, val);
501+
502+
ret = regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_DLLVAL, val,
503+
(val & LOONGSON2_MMC_DLLVAL_DONE), 0,
504+
LOONGSON2_MMC_DLLVAL_TIMEOUT_US);
505+
if (ret < 0)
506+
return;
507+
508+
regmap_read(host->regmap, LOONGSON2_MMC_REG_DLLVAL, &val);
509+
pad_delay = FIELD_GET(GENMASK(7, 1), val);
510+
511+
delay = FIELD_PREP(LOONGSON2_MMC_DELAY_PAD, pad_delay)
512+
| FIELD_PREP(LOONGSON2_MMC_DELAY_RD, pad_delay + 1);
513+
514+
regmap_write(host->regmap, LOONGSON2_MMC_REG_DELAY, delay);
515+
}
516+
413517
static void loongson2_mmc_set_clk(struct loongson2_mmc_host *host, struct mmc_ios *ios)
414518
{
415519
u32 pre;
@@ -422,6 +526,10 @@ static void loongson2_mmc_set_clk(struct loongson2_mmc_host *host, struct mmc_io
422526

423527
regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL,
424528
LOONGSON2_MMC_CTL_ENCLK, LOONGSON2_MMC_CTL_ENCLK);
529+
530+
/* EMMC DLL mode setting */
531+
if (ios->timing == MMC_TIMING_UHS_DDR50 || ios->timing == MMC_TIMING_MMC_DDR52)
532+
loongson2_mmc_dll_mode_init(host);
425533
}
426534

427535
static void loongson2_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -634,6 +742,128 @@ static struct loongson2_mmc_pdata ls2k1000_mmc_pdata = {
634742
.release_dma = loongson2_mmc_release_external_dma,
635743
};
636744

745+
static const struct regmap_config ls2k2000_mmc_regmap_config = {
746+
.reg_bits = 32,
747+
.val_bits = 32,
748+
.reg_stride = 4,
749+
.max_register = LOONGSON2_MMC_REG_RDMA_HI,
750+
};
751+
752+
static void ls2k2000_mmc_reorder_cmd_data(struct loongson2_mmc_host *host,
753+
struct mmc_command *cmd)
754+
{
755+
struct scatterlist *sg;
756+
u32 *data;
757+
int i, j;
758+
759+
if (cmd->opcode != SD_SWITCH || mmc_cmd_type(cmd) != MMC_CMD_ADTC)
760+
return;
761+
762+
for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) {
763+
data = sg_virt(&sg[i]);
764+
for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++)
765+
data[j] = bitrev8x4(data[j]);
766+
}
767+
}
768+
769+
/*
770+
* This is a controller hardware defect. Single/multiple block write commands
771+
* must be sent after the TX FULL flag is set, otherwise a data timeout interrupt
772+
* will occur.
773+
*/
774+
static void ls2k2000_mmc_fix_data_timeout(struct loongson2_mmc_host *host,
775+
struct mmc_command *cmd)
776+
{
777+
int val;
778+
779+
if (cmd->opcode != MMC_WRITE_BLOCK && cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
780+
return;
781+
782+
regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_FSTS, val,
783+
(val & LOONGSON2_MMC_FSTS_TXFULL), 0,
784+
LOONGSON2_MMC_TXFULL_TIMEOUT_US);
785+
}
786+
787+
static int loongson2_mmc_prepare_internal_dma(struct loongson2_mmc_host *host,
788+
struct mmc_data *data)
789+
{
790+
struct loongson2_dma_desc *pdes = (struct loongson2_dma_desc *)host->sg_cpu;
791+
struct mmc_host *mmc = mmc_from_priv(host);
792+
dma_addr_t next_desc = host->sg_dma;
793+
struct scatterlist *sg;
794+
int reg_lo, reg_hi;
795+
u64 dma_order;
796+
int i, ret;
797+
798+
ret = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
799+
mmc_get_dma_dir(data));
800+
if (!ret)
801+
return -ENOMEM;
802+
803+
for_each_sg(data->sg, sg, data->sg_len, i) {
804+
pdes[i].len = sg_dma_len(&sg[i]) / 4;
805+
pdes[i].step_len = 0;
806+
pdes[i].step_times = 1;
807+
pdes[i].mem_addr = lower_32_bits(sg_dma_address(&sg[i]));
808+
pdes[i].high_mem_addr = upper_32_bits(sg_dma_address(&sg[i]));
809+
pdes[i].apb_addr = host->res->start + LOONGSON2_MMC_REG_DATA;
810+
pdes[i].cmd = LOONGSON2_MMC_DMA_INT;
811+
812+
if (data->flags & MMC_DATA_READ) {
813+
reg_lo = LOONGSON2_MMC_REG_RDMA_LO;
814+
reg_hi = LOONGSON2_MMC_REG_RDMA_HI;
815+
} else {
816+
pdes[i].cmd |= LOONGSON2_MMC_DMA_DATA_DIR;
817+
reg_lo = LOONGSON2_MMC_REG_WDMA_LO;
818+
reg_hi = LOONGSON2_MMC_REG_WDMA_HI;
819+
}
820+
821+
next_desc += sizeof(struct loongson2_dma_desc);
822+
pdes[i].ndesc_addr = lower_32_bits(next_desc) |
823+
LOONGSON2_MMC_DMA_DESC_EN;
824+
pdes[i].high_ndesc_addr = upper_32_bits(next_desc);
825+
}
826+
827+
/* Setting the last descriptor enable bit */
828+
pdes[i - 1].ndesc_addr &= ~LOONGSON2_MMC_DMA_DESC_EN;
829+
830+
dma_order = (host->sg_dma & ~LOONGSON2_MMC_DMA_CONFIG_MASK) |
831+
LOONGSON2_MMC_DMA_64BIT_EN |
832+
LOONGSON2_MMC_DMA_START;
833+
834+
regmap_write(host->regmap, reg_hi, upper_32_bits(dma_order));
835+
regmap_write(host->regmap, reg_lo, lower_32_bits(dma_order));
836+
837+
return 0;
838+
}
839+
840+
static int loongson2_mmc_set_internal_dma(struct loongson2_mmc_host *host,
841+
struct platform_device *pdev)
842+
{
843+
host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
844+
&host->sg_dma, GFP_KERNEL);
845+
if (!host->sg_cpu)
846+
return -ENOMEM;
847+
848+
memset(host->sg_cpu, 0, PAGE_SIZE);
849+
return 0;
850+
}
851+
852+
static void loongson2_mmc_release_internal_dma(struct loongson2_mmc_host *host,
853+
struct device *dev)
854+
{
855+
dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
856+
}
857+
858+
static struct loongson2_mmc_pdata ls2k2000_mmc_pdata = {
859+
.regmap_config = &ls2k2000_mmc_regmap_config,
860+
.reorder_cmd_data = ls2k2000_mmc_reorder_cmd_data,
861+
.fix_data_timeout = ls2k2000_mmc_fix_data_timeout,
862+
.setting_dma = loongson2_mmc_set_internal_dma,
863+
.prepare_dma = loongson2_mmc_prepare_internal_dma,
864+
.release_dma = loongson2_mmc_release_internal_dma,
865+
};
866+
637867
static int loongson2_mmc_resource_request(struct platform_device *pdev,
638868
struct loongson2_mmc_host *host)
639869
{
@@ -756,6 +986,7 @@ static void loongson2_mmc_remove(struct platform_device *pdev)
756986
static const struct of_device_id loongson2_mmc_of_ids[] = {
757987
{ .compatible = "loongson,ls2k0500-mmc", .data = &ls2k0500_mmc_pdata },
758988
{ .compatible = "loongson,ls2k1000-mmc", .data = &ls2k1000_mmc_pdata },
989+
{ .compatible = "loongson,ls2k2000-mmc", .data = &ls2k2000_mmc_pdata },
759990
{ },
760991
};
761992
MODULE_DEVICE_TABLE(of, loongson2_mmc_of_ids);

0 commit comments

Comments
 (0)