linux-mmc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] LoongArch: Introduce the Loongson-2K MMC host controller driver
@ 2025-05-07  7:28 Binbin Zhou
  2025-05-07  7:28 ` [PATCH v2 1/4] dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding Binbin Zhou
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Binbin Zhou @ 2025-05-07  7:28 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-mmc,
	Binbin Zhou

Hi all:

This patchset introduce the MMC host controller on Loongson-2K series
CPUs.

They are similar, except for the interface characteristics and the use of
DMA engine, specifically, the Loongson-2K0500/Loongson-2K1000 use an
externally shared APBDMA engine, while the Loongson-2K2000 uses an
internally exclusive DMA.

Based on this, I'm splitting the driver into two patches.

List of the patchset:
Patch1: bindings for Loongson-2K0500/Loongson-2K1000;
Patch2: driver for MMC controller using externally shared APBDMA engine;
Patch3: bindings for Loongson-2K2000;
Patch4: driver for MMC controller using internally exclusive DMA.

Thanks.

-------
V2:

patch(1/4):
 - Add reg define for each reg entry.

patch(2/4):
 - Put all code in the c-file;
 - Use mmc_from_priv() instead of host->mmc;
 - Use sdio_signal_irq() instead of mmc_signal_sdio_irq();
 - Use devm_mmc_alloc_host() instead of mmc_alloc_host();
 - Use mmc_regulator_get_supply();

patch(4/4):
 - Add fix_cmd_interrupt function which is needed by Loongson-2K2000.

Link to V1:
https://lore.kernel.org/linux-mmc/cover.1744273956.git.zhoubinbin@loongson.cn/

Binbin Zhou (4):
  dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding
  mmc: loongson2: Add Loongson-2K SD/SDIO controller driver
  dt-bindings: mmc: loongson,ls2k-mmc: Add compatible for
    Loongson-2K2000
  mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver

 .../bindings/mmc/loongson,ls2k-mmc.yaml       |  112 ++
 MAINTAINERS                                   |    7 +
 drivers/mmc/host/Kconfig                      |   13 +
 drivers/mmc/host/Makefile                     |    1 +
 drivers/mmc/host/loongson2-mmc.c              | 1007 +++++++++++++++++
 5 files changed, 1140 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
 create mode 100644 drivers/mmc/host/loongson2-mmc.c


base-commit: 9e12816f9a6195f1f5b7c5dc2e388c2458411b97
-- 
2.47.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 1/4] dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding
  2025-05-07  7:28 [PATCH v2 0/4] LoongArch: Introduce the Loongson-2K MMC host controller driver Binbin Zhou
@ 2025-05-07  7:28 ` Binbin Zhou
  2025-05-08 15:00   ` Conor Dooley
  2025-05-07  7:28 ` [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver Binbin Zhou
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2025-05-07  7:28 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-mmc,
	Binbin Zhou

Add the Loongson-2K SoC's SD/SDIO/eMMC controller binding with DT schema
format using json-schema.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 .../bindings/mmc/loongson,ls2k-mmc.yaml       | 69 +++++++++++++++++++
 MAINTAINERS                                   |  6 ++
 2 files changed, 75 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml

diff --git a/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml b/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
new file mode 100644
index 000000000000..97a0853399f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mmc/loongson,ls2k-mmc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: The SD/SDIO/eMMC host controller for Loongson-2K family SoCs
+
+description:
+  The MMC host controller on the Loongson-2K0500/2K1000 (using an externally
+  shared apbdma controller) provides the SD and SDIO device interfaces.
+
+maintainers:
+  - Binbin Zhou <zhoubinbin@loongson.cn>
+
+allOf:
+  - $ref: mmc-controller.yaml#
+
+properties:
+  compatible:
+    enum:
+      - loongson,ls2k0500-mmc
+      - loongson,ls2k1000-mmc
+
+  reg:
+    items:
+      - description: Loongson-2K MMC controller registers.
+      - description: APB DMA config register for Loongson-2K MMC controller.
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  dmas:
+    maxItems: 1
+
+  dma-names:
+    const: rx-tx
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - dmas
+  - dma-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/clock/loongson,ls2k-clk.h>
+
+    mmc@1fe2c000 {
+        compatible = "loongson,ls2k1000-mmc";
+        reg = <0x1fe2c000 0x68>,
+              <0x1fe00438 0x8>;
+        interrupt-parent = <&liointc0>;
+        interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clk LOONGSON2_APB_CLK>;
+        dmas = <&apbdma1 0>;
+        dma-names = "rx-tx";
+        bus-width = <4>;
+        cd-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 96b827049501..5bf74aa63299 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13935,6 +13935,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml
 F:	drivers/soc/loongson/loongson2_guts.c
 
+LOONGSON-2 SOC SERIES MMC/SD/SDIO CONTROLLER DRIVER
+M:	Binbin Zhou <zhoubinbin@loongson.cn>
+L:	linux-mmc@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
+
 LOONGSON-2 SOC SERIES PM DRIVER
 M:	Yinbo Zhu <zhuyinbo@loongson.cn>
 L:	linux-pm@vger.kernel.org
-- 
2.47.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver
  2025-05-07  7:28 [PATCH v2 0/4] LoongArch: Introduce the Loongson-2K MMC host controller driver Binbin Zhou
  2025-05-07  7:28 ` [PATCH v2 1/4] dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding Binbin Zhou
@ 2025-05-07  7:28 ` Binbin Zhou
  2025-05-08 10:13   ` kernel test robot
                     ` (2 more replies)
  2025-05-07  7:28 ` [PATCH v2 3/4] dt-bindings: mmc: loongson,ls2k-mmc: Add compatible for Loongson-2K2000 Binbin Zhou
  2025-05-07  7:28 ` [PATCH v2 4/4] mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver Binbin Zhou
  3 siblings, 3 replies; 15+ messages in thread
From: Binbin Zhou @ 2025-05-07  7:28 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-mmc,
	Binbin Zhou

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>
---
 MAINTAINERS                      |   1 +
 drivers/mmc/host/Kconfig         |  13 +
 drivers/mmc/host/Makefile        |   1 +
 drivers/mmc/host/loongson2-mmc.c | 802 +++++++++++++++++++++++++++++++
 4 files changed, 817 insertions(+)
 create mode 100644 drivers/mmc/host/loongson2-mmc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 5bf74aa63299..884666933c4d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13940,6 +13940,7 @@ M:	Binbin Zhou <zhoubinbin@loongson.cn>
 L:	linux-mmc@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
+F:	drivers/mmc/host/loongson2-mmc.c
 
 LOONGSON-2 SOC SERIES PM DRIVER
 M:	Yinbo Zhu <zhuyinbo@loongson.cn>
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 264e11fa58ea..bb8d63d7bc5b 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -1097,6 +1097,19 @@ config MMC_OWL
 	  This selects support for the SD/MMC Host Controller on
 	  Actions Semi Owl SoCs.
 
+config MMC_LOONGSON2
+	tristate "Loongson-2K SD/SDIO/eMMC Host Interface support"
+	depends on LOONGARCH || COMPILE_TEST
+	depends on HAS_DMA
+	help
+	  This selects support for the SD/SDIO/eMMC Host Controller on
+	  Loongson-2K series CPUs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mmc_loongson2.
+
+	  If unsure, say N.
+
 config MMC_SDHCI_EXTERNAL_DMA
 	bool
 
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 5147467ec825..ad09453d65da 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_MMC_USDHI6ROL0)	+= usdhi6rol0.o
 obj-$(CONFIG_MMC_TOSHIBA_PCI)	+= toshsd.o
 obj-$(CONFIG_MMC_BCM2835)	+= bcm2835.o
 obj-$(CONFIG_MMC_OWL)		+= owl-mmc.o
+obj-$(CONFIG_MMC_LOONGSON2)	+= loongson2-mmc.o
 
 obj-$(CONFIG_MMC_REALTEK_PCI)	+= rtsx_pci_sdmmc.o
 obj-$(CONFIG_MMC_REALTEK_USB)	+= rtsx_usb_sdmmc.o
diff --git a/drivers/mmc/host/loongson2-mmc.c b/drivers/mmc/host/loongson2-mmc.c
new file mode 100644
index 000000000000..e52fa0a3bc4a
--- /dev/null
+++ b/drivers/mmc/host/loongson2-mmc.c
@@ -0,0 +1,802 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Loongson-2K MMC/SDIO controller driver
+ *
+ * Copyright (C) 2018-2025 Loongson Technology Corporation Limited.
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitrev.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define LOONGSON2_MMC_REG_CTL		0x00 /* Control Register */
+#define LOONGSON2_MMC_REG_PRE		0x04 /* Prescaler Register */
+#define LOONGSON2_MMC_REG_CARG		0x08 /* Command Register */
+#define LOONGSON2_MMC_REG_CCTL		0x0c /* Command Control Register */
+#define LOONGSON2_MMC_REG_CSTS		0x10 /* Command Status Register */
+#define LOONGSON2_MMC_REG_RSP0		0x14 /* Command Response Register 0 */
+#define LOONGSON2_MMC_REG_RSP1		0x18 /* Command Response Register 1 */
+#define LOONGSON2_MMC_REG_RSP2		0x1c /* Command Response Register 2 */
+#define LOONGSON2_MMC_REG_RSP3		0x20 /* Command Response Register 3 */
+#define LOONGSON2_MMC_REG_TIMER		0x24 /* Data Timeout Register */
+#define LOONGSON2_MMC_REG_BSIZE		0x28 /* Block Size Register */
+#define LOONGSON2_MMC_REG_DCTL		0x2c /* Data Control Register */
+#define LOONGSON2_MMC_REG_DCNT		0x30 /* Data Counter Register */
+#define LOONGSON2_MMC_REG_DSTS		0x34 /* Data Status Register */
+#define LOONGSON2_MMC_REG_FSTS		0x38 /* FIFO Status Register */
+#define LOONGSON2_MMC_REG_INT		0x3c /* Interrupt Register */
+#define LOONGSON2_MMC_REG_DATA		0x40 /* Data Register */
+#define LOONGSON2_MMC_REG_IEN		0x64 /* Interrupt Enable Register */
+
+/* Bitfields of control register */
+#define LOONGSON2_MMC_CTL_ENCLK		BIT(0)
+#define LOONGSON2_MMC_CTL_EXTCLK	BIT(1)
+#define LOONGSON2_MMC_CTL_RESET		BIT(8)
+
+/* Bitfields of prescaler register */
+#define LOONGSON2_MMC_PRE		GENMASK(9, 0)
+#define LOONGSON2_MMC_PRE_EN		BIT(31)
+
+/* Bitfields of command control register */
+#define LOONGSON2_MMC_CCTL_INDEX	GENMASK(5, 0)
+#define LOONGSON2_MMC_CCTL_HOST		BIT(6)
+#define LOONGSON2_MMC_CCTL_START	BIT(8)
+#define LOONGSON2_MMC_CCTL_WAIT_RSP	BIT(9)
+#define LOONGSON2_MMC_CCTL_LONG_RSP	BIT(10)
+#define LOONGSON2_MMC_CCTL_ABORT	BIT(12)
+#define LOONGSON2_MMC_CCTL_CHECK	BIT(13)
+#define LOONGSON2_MMC_CCTL_SDIO		BIT(14)
+#define LOONGSON2_MMC_CCTL_CMD6		BIT(18)
+
+/* Bitfields of command status register */
+#define LOONGSON2_MMC_CSTS_INDEX	GENMASK(7, 0)
+#define LOONGSON2_MMC_CSTS_ON		BIT(8)
+#define LOONGSON2_MMC_CSTS_RSP		BIT(9)
+#define LOONGSON2_MMC_CSTS_TIMEOUT	BIT(10)
+#define LOONGSON2_MMC_CSTS_END		BIT(11)
+#define LOONGSON2_MMC_CSTS_CRC_ERR	BIT(12)
+#define LOONGSON2_MMC_CSTS_AUTO_STOP	BIT(13)
+#define LOONGSON2_MMC_CSTS_FIN		BIT(14)
+
+/* Bitfields of data timeout register */
+#define LOONGSON2_MMC_DTIMR		GENMASK(23, 0)
+
+/* Bitfields of block size register */
+#define LOONGSON2_MMC_BSIZE		GENMASK(11, 0)
+
+/* Bitfields of data control register */
+#define LOONGSON2_MMC_DCTL_BNUM		GENMASK(11, 0)
+#define LOONGSON2_MMC_DCTL_START	BIT(14)
+#define LOONGSON2_MMC_DCTL_ENDMA	BIT(15)
+#define LOONGSON2_MMC_DCTL_WIDE		BIT(16)
+#define LOONGSON2_MMC_DCTL_RWAIT	BIT(17)
+#define LOONGSON2_MMC_DCTL_IO_SUSPEND	BIT(18)
+#define LOONGSON2_MMC_DCTL_IO_RESUME	BIT(19)
+#define LOONGSON2_MMC_DCTL_RW_RESUME	BIT(20)
+#define LOONGSON2_MMC_DCTL_8BIT_BUS	BIT(26)
+
+/* Bitfields of sata counter register */
+#define LOONGSON2_MMC_DCNT_BNUM		GENMASK(11, 0)
+#define LOONGSON2_MMC_DCNT_BYTE		GENMASK(23, 12)
+
+/* Bitfields of command status register */
+#define LOONGSON2_MMC_DSTS_RXON		BIT(0)
+#define LOONGSON2_MMC_DSTS_TXON		BIT(1)
+#define LOONGSON2_MMC_DSTS_SBITERR	BIT(2)
+#define LOONGSON2_MMC_DSTS_BUSYFIN	BIT(3)
+#define LOONGSON2_MMC_DSTS_XFERFIN	BIT(4)
+#define LOONGSON2_MMC_DSTS_DTIMEOUT	BIT(5)
+#define LOONGSON2_MMC_DSTS_RXCRC	BIT(6)
+#define LOONGSON2_MMC_DSTS_TXCRC	BIT(7)
+#define LOONGSON2_MMC_DSTS_IRQ		BIT(8)
+#define LOONGSON2_MMC_DSTS_START	BIT(13)
+#define LOONGSON2_MMC_DSTS_RESUME	BIT(15)
+#define LOONGSON2_MMC_DSTS_SUSPEND	BIT(16)
+
+/* Bitfields of interrupt register */
+#define LOONGSON2_MMC_INT_DFIN		BIT(0)
+#define LOONGSON2_MMC_INT_DTIMEOUT	BIT(1)
+#define LOONGSON2_MMC_INT_RXCRC		BIT(2)
+#define LOONGSON2_MMC_INT_TXCRC		BIT(3)
+#define LOONGSON2_MMC_INT_PROGERR	BIT(4)
+#define LOONGSON2_MMC_INT_SDIOIRQ	BIT(5)
+#define LOONGSON2_MMC_INT_CSENT		BIT(6)
+#define LOONGSON2_MMC_INT_CTIMEOUT	BIT(7)
+#define LOONGSON2_MMC_INT_RESPCRC	BIT(8)
+#define LOONGSON2_MMC_INT_BUSYEND	BIT(9)
+
+/* Bitfields of interrupt enable register */
+#define LOONGSON2_MMC_IEN_DFIN		BIT(0)
+#define LOONGSON2_MMC_IEN_DTIMEOUT	BIT(1)
+#define LOONGSON2_MMC_IEN_RXCRC		BIT(2)
+#define LOONGSON2_MMC_IEN_TXCRC		BIT(3)
+#define LOONGSON2_MMC_IEN_PROGERR	BIT(4)
+#define LOONGSON2_MMC_IEN_SDIOIRQ	BIT(5)
+#define LOONGSON2_MMC_IEN_CSENT		BIT(6)
+#define LOONGSON2_MMC_IEN_CTIMEOUT	BIT(7)
+#define LOONGSON2_MMC_IEN_RESPCRC	BIT(8)
+#define LOONGSON2_MMC_IEN_BUSYEND	BIT(9)
+
+#define LOONGSON2_MMC_IEN_ALL		GENMASK(9, 0)
+#define LOONGSON2_MMC_INT_CLEAR		GENMASK(9, 0)
+
+/* Loongson-2K1000 SDIO2 DMA routing register */
+#define LS2K1000_SDIO_DMA_MASK		GENMASK(17, 15)
+#define LS2K1000_DMA0_CONF		0x0
+#define LS2K1000_DMA1_CONF		0x1
+#define LS2K1000_DMA2_CONF		0x2
+#define LS2K1000_DMA3_CONF		0x3
+#define LS2K1000_DMA4_CONF		0x4
+
+/* Loongson-2K0500 SDIO2 DMA routing register */
+#define LS2K0500_SDIO_DMA_MASK		GENMASK(15, 14)
+#define LS2K0500_DMA0_CONF		0x1
+#define LS2K0500_DMA1_CONF		0x2
+#define LS2K0500_DMA2_CONF		0x3
+
+enum loongson2_mmc_state {
+	STATE_NONE,
+	STATE_FINALIZE,
+	STATE_CMDSENT,
+	STATE_RSPFIN,
+	STATE_XFERFINISH,
+	STATE_XFERFINISH_RSPFIN,
+};
+
+struct loongson2_dma_desc {
+	u32 ndesc_addr;
+	u32 mem_addr;
+	u32 apb_addr;
+	u32 len;
+	u32 step_len;
+	u32 step_times;
+	u32 cmd;
+	u32 stats;
+	u32 high_ndesc_addr;
+	u32 high_mem_addr;
+	u32 reserved[2];
+} __packed;
+
+struct loongson2_mmc_host {
+	struct device *dev;
+	struct mmc_request *mrq;
+	struct regmap *regmap;
+	struct resource *res;
+	struct clk *clk;
+	u64 rate;
+	int dma_complete;
+	struct dma_chan *chan;
+	int cmd_is_stop;
+	int bus_width;
+	spinlock_t lock; /* Prevent races with irq handler */
+	enum loongson2_mmc_state state;
+	const struct loongson2_mmc_pdata *pdata;
+};
+
+struct loongson2_mmc_pdata {
+	const struct regmap_config regmap_config;
+	void (*reorder_cmd_data)(struct loongson2_mmc_host *host, struct mmc_command *cmd);
+	int (*setting_dma)(struct loongson2_mmc_host *host, struct platform_device *pdev);
+	int (*prepare_dma)(struct loongson2_mmc_host *host, struct mmc_data *data);
+	void (*release_dma)(struct loongson2_mmc_host *host, struct device *dev);
+};
+
+static void loongson2_mmc_send_command(struct loongson2_mmc_host *host,
+				       struct mmc_command *cmd)
+{
+	u32 cctrl;
+
+	if (cmd->data)
+		host->state = STATE_XFERFINISH_RSPFIN;
+	else if (cmd->flags & MMC_RSP_PRESENT)
+		host->state = STATE_RSPFIN;
+	else
+		host->state = STATE_CMDSENT;
+
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_CARG, cmd->arg);
+
+	cctrl = FIELD_PREP(LOONGSON2_MMC_CCTL_INDEX, cmd->opcode);
+	cctrl |= LOONGSON2_MMC_CCTL_HOST | LOONGSON2_MMC_CCTL_START;
+
+	if (cmd->opcode == SD_SWITCH && cmd->data)
+		cctrl |= LOONGSON2_MMC_CCTL_CMD6;
+
+	if (cmd->flags & MMC_RSP_PRESENT)
+		cctrl |= LOONGSON2_MMC_CCTL_WAIT_RSP;
+
+	if (cmd->flags & MMC_RSP_136)
+		cctrl |= LOONGSON2_MMC_CCTL_LONG_RSP;
+
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_CCTL, cctrl);
+}
+
+static int loongson2_mmc_setup_data(struct loongson2_mmc_host *host,
+				    struct mmc_data *data)
+{
+	u32 dctrl;
+
+	if ((data->blksz & 3) != 0)
+		return -EINVAL;
+
+	dctrl = FIELD_PREP(LOONGSON2_MMC_DCTL_BNUM, data->blocks);
+	dctrl |= LOONGSON2_MMC_DCTL_START | LOONGSON2_MMC_DCTL_ENDMA;
+
+	if (host->bus_width == MMC_BUS_WIDTH_4)
+		dctrl |= LOONGSON2_MMC_DCTL_WIDE;
+	else if (host->bus_width == MMC_BUS_WIDTH_8)
+		dctrl |= LOONGSON2_MMC_DCTL_8BIT_BUS;
+
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_DCTL, dctrl);
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_BSIZE, data->blksz);
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_TIMER, U32_MAX);
+
+	return 0;
+}
+
+static int loongson2_mmc_prepare_dma(struct loongson2_mmc_host *host,
+				     struct mmc_data *data)
+{
+	int ret;
+
+	if (!data)
+		return 0;
+
+	ret = loongson2_mmc_setup_data(host, data);
+	if (ret)
+		return ret;
+
+	host->dma_complete = 0;
+
+	return host->pdata->prepare_dma(host, data);
+}
+
+static void loongson2_mmc_send_request(struct mmc_host *mmc)
+{
+	int ret;
+	struct loongson2_mmc_host *host = mmc_priv(mmc);
+	struct mmc_request *mrq = host->mrq;
+	struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
+
+	ret = loongson2_mmc_prepare_dma(host, cmd->data);
+	if (ret) {
+		dev_err(host->dev, "DMA data prepared failed with %d\n", ret);
+		cmd->error = ret;
+		cmd->data->error = ret;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
+	loongson2_mmc_send_command(host, cmd);
+
+	/* Fix deselect card */
+	if (cmd->opcode == MMC_SELECT_CARD && cmd->arg == 0) {
+		cmd->error = 0;
+		mmc_request_done(mmc, mrq);
+	}
+}
+
+static irqreturn_t loongson2_mmc_irq_worker(int irq, void *devid)
+{
+	struct loongson2_mmc_host *host = (struct loongson2_mmc_host *)devid;
+	struct mmc_host *mmc = mmc_from_priv(host);
+	struct mmc_request *mrq = host->mrq;
+	struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
+
+	if (cmd->data)
+		dma_unmap_sg(mmc_dev(mmc), cmd->data->sg, cmd->data->sg_len,
+			     mmc_get_dma_dir(cmd->data));
+
+	if (cmd->data && !cmd->error &&
+	    !cmd->data->error && !host->dma_complete)
+		return IRQ_HANDLED;
+
+	/* Read response from controller. */
+	regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP0, &cmd->resp[0]);
+	regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP1, &cmd->resp[1]);
+	regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP2, &cmd->resp[2]);
+	regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP3, &cmd->resp[3]);
+
+	/* Cleanup controller */
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_CARG, 0);
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_CCTL, 0);
+
+	if (cmd->data && cmd->error)
+		cmd->data->error = cmd->error;
+
+	if (cmd->data && cmd->data->stop && !host->cmd_is_stop) {
+		host->cmd_is_stop = 1;
+		loongson2_mmc_send_request(mmc);
+		return IRQ_HANDLED;
+	}
+
+	/* If we have no data transfer we are finished here */
+	if (!mrq->data)
+		goto request_done;
+
+	/* Calculate the amount of bytes transfer if there was no error */
+	if (mrq->data->error == 0) {
+		mrq->data->bytes_xfered =
+			(mrq->data->blocks * mrq->data->blksz);
+	} else {
+		mrq->data->bytes_xfered = 0;
+	}
+
+request_done:
+	host->state = STATE_NONE;
+	host->mrq = NULL;
+	mmc_request_done(mmc, mrq);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t loongson2_mmc_irq(int irq, void *devid)
+{
+	struct loongson2_mmc_host *host = (struct loongson2_mmc_host *)devid;
+	struct mmc_host *mmc = mmc_from_priv(host);
+	struct mmc_command *cmd;
+	unsigned long iflags;
+	u32 dsts, imsk;
+
+	regmap_read(host->regmap, LOONGSON2_MMC_REG_INT, &imsk);
+	regmap_read(host->regmap, LOONGSON2_MMC_REG_DSTS, &dsts);
+
+	if ((dsts & LOONGSON2_MMC_DSTS_IRQ) &&
+	    (imsk & LOONGSON2_MMC_INT_SDIOIRQ)) {
+		regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_INT,
+				   LOONGSON2_MMC_INT_SDIOIRQ,
+				   LOONGSON2_MMC_INT_SDIOIRQ);
+
+		sdio_signal_irq(mmc);
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&host->lock, iflags);
+
+	if (host->state == STATE_NONE || host->state == STATE_FINALIZE ||
+	    !host->mrq)
+		goto irq_out;
+
+	cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd;
+	if (!cmd)
+		goto irq_out;
+
+	cmd->error = 0;
+
+	if (imsk & LOONGSON2_MMC_INT_CTIMEOUT) {
+		cmd->error = -ETIMEDOUT;
+		goto close_transfer;
+	}
+
+	if (imsk & LOONGSON2_MMC_INT_CSENT) {
+		if (host->state == STATE_RSPFIN || host->state == STATE_CMDSENT)
+			goto close_transfer;
+
+		if (host->state == STATE_XFERFINISH_RSPFIN)
+			host->state = STATE_XFERFINISH;
+	}
+
+	if (!cmd->data)
+		goto irq_out;
+
+	if (imsk & (LOONGSON2_MMC_INT_RXCRC | LOONGSON2_MMC_INT_TXCRC)) {
+		cmd->data->error = -EILSEQ;
+		goto close_transfer;
+	}
+
+	if (imsk & LOONGSON2_MMC_INT_DTIMEOUT) {
+		cmd->data->error = -ETIMEDOUT;
+		goto close_transfer;
+	}
+
+	if (imsk & LOONGSON2_MMC_INT_DFIN) {
+		if (host->state == STATE_XFERFINISH) {
+			host->dma_complete = 1;
+			goto close_transfer;
+		}
+
+		if (host->state == STATE_XFERFINISH_RSPFIN)
+			host->state = STATE_RSPFIN;
+	}
+
+irq_out:
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, imsk);
+	spin_unlock_irqrestore(&host->lock, iflags);
+	return IRQ_HANDLED;
+
+close_transfer:
+	host->state = STATE_FINALIZE;
+	host->pdata->reorder_cmd_data(host, cmd);
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, imsk);
+	spin_unlock_irqrestore(&host->lock, iflags);
+	return IRQ_WAKE_THREAD;
+}
+
+static void loongson2_mmc_set_clk(struct loongson2_mmc_host *host, struct mmc_ios *ios)
+{
+	u32 pre;
+
+	pre = DIV_ROUND_UP(host->rate, ios->clock);
+	if (pre > 255)
+		pre = 255;
+
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_PRE, pre | LOONGSON2_MMC_PRE_EN);
+
+	regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL,
+			   LOONGSON2_MMC_CTL_ENCLK, LOONGSON2_MMC_CTL_ENCLK);
+}
+
+static void loongson2_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct loongson2_mmc_host *host = mmc_priv(mmc);
+
+	switch (ios->power_mode) {
+	case MMC_POWER_ON:
+	case MMC_POWER_UP:
+		regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_RESET);
+		mdelay(10);
+		regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_EXTCLK);
+		regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, LOONGSON2_MMC_IEN_ALL);
+		regmap_write(host->regmap, LOONGSON2_MMC_REG_IEN, LOONGSON2_MMC_INT_CLEAR);
+		break;
+	case MMC_POWER_OFF:
+		regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL,
+				   LOONGSON2_MMC_CTL_RESET, LOONGSON2_MMC_CTL_RESET);
+		return;
+	default:
+		return;
+	}
+
+	loongson2_mmc_set_clk(host, ios);
+
+	host->bus_width = ios->bus_width;
+}
+
+static void loongson2_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct loongson2_mmc_host *host = mmc_priv(mmc);
+
+	host->cmd_is_stop = 0;
+	host->mrq = mrq;
+	loongson2_mmc_send_request(mmc);
+}
+
+static void loongson2_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct loongson2_mmc_host *host = mmc_priv(mmc);
+
+	regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_IEN,
+			   LOONGSON2_MMC_INT_SDIOIRQ, enable);
+}
+
+static struct mmc_host_ops loongson2_mmc_ops = {
+	.request	= loongson2_mmc_request,
+	.set_ios	= loongson2_mmc_set_ios,
+	.get_ro		= mmc_gpio_get_ro,
+	.get_cd		= mmc_gpio_get_cd,
+	.enable_sdio_irq = loongson2_mmc_enable_sdio_irq,
+};
+
+static const struct regmap_config ls2k1000_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = LOONGSON2_MMC_REG_IEN,
+};
+
+static int loongson2_reorder_cmd_list[] = { SD_APP_SEND_SCR, SD_APP_SEND_NUM_WR_BLKS,
+					    SD_APP_SD_STATUS, MMC_SEND_WRITE_PROT,
+					    SD_SWITCH };
+
+/*
+ * According to SD spec, ACMD13, ACMD22, ACMD51 and CMD30
+ * response datas has different byte order with usual data packets.
+ * However sdio controller will send these datas in usual data format,
+ * so we need to adjust these datas to a protocol consistent byte order.
+ */
+static void loongson2_mmc_reorder_cmd_data(struct loongson2_mmc_host *host,
+					   struct mmc_command *cmd)
+{
+	struct scatterlist *sg;
+	u32 *data;
+	int i, j;
+
+	if (mmc_cmd_type(cmd) != MMC_CMD_ADTC)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(loongson2_reorder_cmd_list); i++)
+		if (cmd->opcode == loongson2_reorder_cmd_list[i])
+			break;
+
+	if (i == ARRAY_SIZE(loongson2_reorder_cmd_list))
+		return;
+
+	for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) {
+		data = sg_virt(&sg[i]);
+		for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++)
+			if (cmd->opcode == SD_SWITCH)
+				data[j] = bitrev8x4(data[j]);
+			else
+				data[j] = cpu_to_be32(data[j]);
+	}
+}
+
+static int loongson2_mmc_prepare_external_dma(struct loongson2_mmc_host *host,
+					      struct mmc_data *data)
+{
+	struct mmc_host *mmc = mmc_from_priv(host);
+	struct dma_async_tx_descriptor *desc;
+	struct dma_slave_config conf = {
+		.src_addr = host->res->start + LOONGSON2_MMC_REG_DATA,
+		.dst_addr = host->res->start + LOONGSON2_MMC_REG_DATA,
+		.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+		.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+	};
+
+	conf.direction = !(data->flags & MMC_DATA_WRITE) ?
+			 DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+
+	dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
+		   mmc_get_dma_dir(data));
+
+	dmaengine_slave_config(host->chan, &conf);
+	desc = dmaengine_prep_slave_sg(host->chan, data->sg, data->sg_len,
+				       conf.direction,
+				       DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+	if (!desc)
+		goto unmap_exit;
+
+	dmaengine_submit(desc);
+	dma_async_issue_pending(host->chan);
+
+	return 0;
+
+unmap_exit:
+	dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len,
+		     mmc_get_dma_dir(data));
+	return -ENOMEM;
+}
+
+static void loongson2_mmc_release_external_dma(struct loongson2_mmc_host *host,
+					       struct device *dev)
+{
+	dma_release_channel(host->chan);
+}
+
+static int ls2k0500_mmc_set_external_dma(struct loongson2_mmc_host *host,
+					 struct platform_device *pdev)
+{
+	int ret, val;
+	void __iomem *regs;
+
+	regs = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	val = readl(regs);
+	val |= FIELD_PREP(LS2K0500_SDIO_DMA_MASK, LS2K0500_DMA2_CONF);
+	writel(val, regs);
+
+	host->chan = dma_request_chan(&pdev->dev, "rx-tx");
+	ret = PTR_ERR_OR_ZERO(host->chan);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot get DMA channel.\n");
+		return  ret;
+	}
+
+	return 0;
+}
+
+static struct loongson2_mmc_pdata ls2k0500_mmc_pdata = {
+	.regmap_config		= ls2k1000_regmap_config,
+	.reorder_cmd_data	= loongson2_mmc_reorder_cmd_data,
+	.setting_dma		= ls2k0500_mmc_set_external_dma,
+	.prepare_dma		= loongson2_mmc_prepare_external_dma,
+	.release_dma		= loongson2_mmc_release_external_dma,
+};
+
+static int ls2k1000_mmc_set_external_dma(struct loongson2_mmc_host *host,
+					 struct platform_device *pdev)
+{
+	int ret, val;
+	void __iomem *regs;
+
+	regs = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	val = readl(regs);
+	val |= FIELD_PREP(LS2K1000_SDIO_DMA_MASK, LS2K1000_DMA1_CONF);
+	writel(val, regs);
+
+	host->chan = dma_request_chan(&pdev->dev, "rx-tx");
+	ret = PTR_ERR_OR_ZERO(host->chan);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot get DMA channel.\n");
+		return  ret;
+	}
+
+	return 0;
+}
+
+static struct loongson2_mmc_pdata ls2k1000_mmc_pdata = {
+	.regmap_config		= ls2k1000_regmap_config,
+	.reorder_cmd_data	= loongson2_mmc_reorder_cmd_data,
+	.setting_dma		= ls2k1000_mmc_set_external_dma,
+	.prepare_dma		= loongson2_mmc_prepare_external_dma,
+	.release_dma		= loongson2_mmc_release_external_dma,
+};
+
+static int loongson2_mmc_resource_request(struct platform_device *pdev,
+					  struct loongson2_mmc_host *host)
+{
+	struct device *dev = &pdev->dev;
+	void __iomem *base;
+	int ret, irq;
+
+	base = devm_platform_get_and_ioremap_resource(pdev, 0, &host->res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	host->regmap = devm_regmap_init_mmio(dev, base, &host->pdata->regmap_config);
+	if (IS_ERR(host->regmap))
+		return PTR_ERR(host->regmap);
+
+	host->clk = devm_clk_get_optional_enabled(dev, NULL);
+	if (IS_ERR(host->clk))
+		return PTR_ERR(host->clk);
+
+	if (host->clk) {
+		ret = devm_clk_rate_exclusive_get(dev, host->clk);
+		if (ret)
+			return PTR_ERR(host->clk);
+
+		host->rate = clk_get_rate(host->clk);
+	} else {
+		/* For ACPI, we get rate through clock-frequency attribute */
+		device_property_read_u64(dev, "clock-frequency", &host->rate);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_request_threaded_irq(dev, irq, loongson2_mmc_irq,
+					loongson2_mmc_irq_worker,
+					IRQF_ONESHOT, "loongson2-mmc", host);
+	if (ret)
+		return ret;
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	return host->pdata->setting_dma(host, pdev);
+}
+
+static int loongson2_mmc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct loongson2_mmc_host *host;
+	struct mmc_host	*mmc;
+	int ret;
+
+	mmc = devm_mmc_alloc_host(dev, sizeof(*host));
+	if (!mmc)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, mmc);
+
+	host = mmc_priv(mmc);
+	host->state = STATE_NONE;
+	spin_lock_init(&host->lock);
+
+	host->pdata = device_get_match_data(dev);
+	if (!host->pdata)
+		return dev_err_probe(dev, -EINVAL, "Failed to get match data\n");
+
+	ret = loongson2_mmc_resource_request(pdev, host);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to request resource\n");
+
+	mmc->ops = &loongson2_mmc_ops;
+	mmc->f_min = DIV_ROUND_UP(host->rate, 256);
+	mmc->f_max = host->rate;
+	mmc->max_blk_count = 4095;
+	mmc->max_blk_size = 4095;
+	mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
+	mmc->max_segs = 1;
+	mmc->max_seg_size = mmc->max_req_size;
+
+	ret = mmc_regulator_get_supply(mmc);
+	if (ret || mmc->ocr_avail == 0) {
+		dev_warn(dev, "can't get voltage, defaulting to 3.3V\n");
+		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+	}
+
+	ret = mmc_of_parse(mmc);
+	if (ret) {
+		dev_err(dev, "Failed to parse device node\n");
+		goto free_dma;
+	}
+
+	ret = mmc_add_host(mmc);
+	if (ret) {
+		dev_err(dev, "Failed to add mmc host.\n");
+		goto free_dma;
+	}
+
+	return 0;
+
+free_dma:
+	host->pdata->release_dma(host, dev);
+	return ret;
+}
+
+static void loongson2_mmc_remove(struct platform_device *pdev)
+{
+	struct mmc_host *mmc  = platform_get_drvdata(pdev);
+	struct loongson2_mmc_host *host = mmc_priv(mmc);
+
+	mmc_remove_host(mmc);
+	host->pdata->release_dma(host, &pdev->dev);
+}
+
+static const struct of_device_id loongson2_mmc_of_ids[] = {
+	{ .compatible = "loongson,ls2k0500-mmc", .data = &ls2k0500_mmc_pdata },
+	{ .compatible = "loongson,ls2k1000-mmc", .data = &ls2k1000_mmc_pdata },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, loongson2_mmc_of_ids);
+
+static int loongson2_mmc_suspend(struct device *dev)
+{
+	struct mmc_host *mmc  = dev_get_drvdata(dev);
+	struct loongson2_mmc_host *host = mmc_priv(mmc);
+
+	clk_disable_unprepare(host->clk);
+
+	return 0;
+}
+
+static int loongson2_mmc_resume(struct device *dev)
+{
+	struct mmc_host *mmc  = dev_get_drvdata(dev);
+	struct loongson2_mmc_host *host = mmc_priv(mmc);
+
+	return clk_prepare_enable(host->clk);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(loongson2_mmc_pm_ops, loongson2_mmc_suspend,
+				loongson2_mmc_resume);
+
+static struct platform_driver loongson2_mmc_driver = {
+	.driver	= {
+		.name = "loongson2-mmc",
+		.of_match_table = loongson2_mmc_of_ids,
+		.pm = pm_ptr(&loongson2_mmc_pm_ops),
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = loongson2_mmc_probe,
+	.remove = loongson2_mmc_remove,
+};
+
+module_platform_driver(loongson2_mmc_driver);
+
+MODULE_DESCRIPTION("Loongson-2K SD/SDIO/eMMC Interface driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited");
+MODULE_LICENSE("GPL");
-- 
2.47.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 3/4] dt-bindings: mmc: loongson,ls2k-mmc: Add compatible for Loongson-2K2000
  2025-05-07  7:28 [PATCH v2 0/4] LoongArch: Introduce the Loongson-2K MMC host controller driver Binbin Zhou
  2025-05-07  7:28 ` [PATCH v2 1/4] dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding Binbin Zhou
  2025-05-07  7:28 ` [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver Binbin Zhou
@ 2025-05-07  7:28 ` Binbin Zhou
  2025-05-08 15:00   ` Conor Dooley
  2025-05-07  7:28 ` [PATCH v2 4/4] mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver Binbin Zhou
  3 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2025-05-07  7:28 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-mmc,
	Binbin Zhou

Add the devicetree compatible for Loongson-2K2000 EMMC/SD/SDIO controller.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 .../bindings/mmc/loongson,ls2k-mmc.yaml       | 47 ++++++++++++++++++-
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml b/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
index 97a0853399f1..6130be214d3c 100644
--- a/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
+++ b/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
@@ -9,6 +9,9 @@ title: The SD/SDIO/eMMC host controller for Loongson-2K family SoCs
 description:
   The MMC host controller on the Loongson-2K0500/2K1000 (using an externally
   shared apbdma controller) provides the SD and SDIO device interfaces.
+  The two MMC host controllers on the Loongson-2K2000 are similar,
+  except that they use internal exclusive DMA. one controller provides
+  the eMMC interface and the other provides the SD/SDIO interface.
 
 maintainers:
   - Binbin Zhou <zhoubinbin@loongson.cn>
@@ -21,8 +24,10 @@ properties:
     enum:
       - loongson,ls2k0500-mmc
       - loongson,ls2k1000-mmc
+      - loongson,ls2k2000-mmc
 
   reg:
+    minItems: 1
     items:
       - description: Loongson-2K MMC controller registers.
       - description: APB DMA config register for Loongson-2K MMC controller.
@@ -44,11 +49,31 @@ required:
   - reg
   - interrupts
   - clocks
-  - dmas
-  - dma-names
 
 unevaluatedProperties: false
 
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - loongson,ls2k0500-mmc
+          - loongson,ls2k1000-mmc
+
+then:
+  properties:
+    reg:
+      minItems: 2
+
+  required:
+    - dmas
+    - dma-names
+
+else:
+  properties:
+    reg:
+      maxItems: 1
+
 examples:
   - |
     #include <dt-bindings/gpio/gpio.h>
@@ -67,3 +92,21 @@ examples:
         bus-width = <4>;
         cd-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
     };
+
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/clock/loongson,ls2k-clk.h>
+
+    mmc@79990000 {
+        compatible = "loongson,ls2k2000-mmc";
+        reg = <0x79990000 0x1000>;
+        interrupt-parent = <&pic>;
+        interrupts = <51 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clk LOONGSON2_EMMC_CLK>;
+        bus-width = <8>;
+        non-removable;
+        cap-mmc-highspeed;
+        mmc-hs200-1_8v;
+        no-sd;
+        no-sdio;
+    };
-- 
2.47.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 4/4] mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver
  2025-05-07  7:28 [PATCH v2 0/4] LoongArch: Introduce the Loongson-2K MMC host controller driver Binbin Zhou
                   ` (2 preceding siblings ...)
  2025-05-07  7:28 ` [PATCH v2 3/4] dt-bindings: mmc: loongson,ls2k-mmc: Add compatible for Loongson-2K2000 Binbin Zhou
@ 2025-05-07  7:28 ` Binbin Zhou
  2025-05-19 11:17   ` Ulf Hansson
  3 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2025-05-07  7:28 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-mmc,
	Binbin Zhou

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 <zhoubinbin@loongson.cn>
---
 drivers/mmc/host/loongson2-mmc.c | 205 +++++++++++++++++++++++++++++++
 1 file changed, 205 insertions(+)

diff --git a/drivers/mmc/host/loongson2-mmc.c b/drivers/mmc/host/loongson2-mmc.c
index e52fa0a3bc4a..d89c3a5adae2 100644
--- a/drivers/mmc/host/loongson2-mmc.c
+++ b/drivers/mmc/host/loongson2-mmc.c
@@ -44,6 +44,18 @@
 #define LOONGSON2_MMC_REG_DATA		0x40 /* Data Register */
 #define LOONGSON2_MMC_REG_IEN		0x64 /* Interrupt Enable Register */
 
+/* EMMC DLL Mode Registers */
+#define LOONGSON2_MMC_REG_DLLVAL	0xf0
+#define LOONGSON2_MMC_REG_DLLCTL	0xf4
+#define LOONGSON2_MMC_REG_DELAY		0xf8
+#define LOONGSON2_MMC_REG_SEL		0xfc
+
+/* Exclusive DMA R/W Registers */
+#define LOONGSON2_MMC_REG_WDMA_LO	0x400
+#define LOONGSON2_MMC_REG_WDMA_HI	0x404
+#define LOONGSON2_MMC_REG_RDMA_LO	0x800
+#define LOONGSON2_MMC_REG_RDMA_HI	0x804
+
 /* Bitfields of control register */
 #define LOONGSON2_MMC_CTL_ENCLK		BIT(0)
 #define LOONGSON2_MMC_CTL_EXTCLK	BIT(1)
@@ -109,6 +121,8 @@
 #define LOONGSON2_MMC_DSTS_RESUME	BIT(15)
 #define LOONGSON2_MMC_DSTS_SUSPEND	BIT(16)
 
+#define LOONGSON2_MMC_FSTS_TXFULL	BIT(11)
+
 /* Bitfields of interrupt register */
 #define LOONGSON2_MMC_INT_DFIN		BIT(0)
 #define LOONGSON2_MMC_INT_DTIMEOUT	BIT(1)
@@ -136,6 +150,37 @@
 #define LOONGSON2_MMC_IEN_ALL		GENMASK(9, 0)
 #define LOONGSON2_MMC_INT_CLEAR		GENMASK(9, 0)
 
+#define LOONGSON2_MMC_DLLVAL_DONE	BIT(8)
+
+#define LOONGSON2_MMC_DLLCTL_TIME	GENMASK(7, 0)
+#define LOONGSON2_MMC_DLLCTL_INCRE	GENMASK(15, 8)
+#define LOONGSON2_MMC_DLLCTL_START	GENMASK(23, 16)
+#define LOONGSON2_MMC_DLLCTL_CLK_MODE	BIT(24)
+#define LOONGSON2_MMC_DLLCTL_START_BIT	BIT(25)
+#define LOONGSON2_MMC_DLLCTL_TIME_BPASS	GENMASK(29, 26)
+
+#define LOONGSON2_MMC_DELAY_PAD		GENMASK(7, 0)
+#define LOONGSON2_MMC_DELAY_RD		GENMASK(15, 8)
+
+#define LOONGSON2_MMC_SEL_DATA		BIT(0)	/* 0: SDR, 1: DDR */
+#define LOONGSON2_MMC_SEL_BUS		BIT(0)	/* 0: EMMC, 1: SDIO */
+
+/* Bitfields in Global Configuration Register */
+#define LOONGSON2_MMC_DMA_64BIT_EN	BIT(0) /* 1: 64 bit support */
+#define LOONGSON2_MMC_DMA_UNCOHERENT_EN	BIT(1) /* 0: cache, 1: uncache */
+#define LOONGSON2_MMC_DMA_ASK_VALID	BIT(2)
+#define LOONGSON2_MMC_DMA_START		BIT(3) /* DMA start operation */
+#define LOONGSON2_MMC_DMA_STOP		BIT(4) /* DMA stop operation */
+#define LOONGSON2_MMC_DMA_CONFIG_MASK	GENMASK_ULL(4, 0) /* DMA controller config bits mask */
+
+/* Bitfields in ndesc_addr field of HW descriptor */
+#define LOONGSON2_MMC_DMA_DESC_EN	BIT(0) /*1: The next descriptor is valid */
+#define LOONGSON2_MMC_DMA_DESC_ADDR_LOW	GENMASK(31, 1)
+
+/* Bitfields in cmd field of HW descriptor */
+#define LOONGSON2_MMC_DMA_INT		BIT(1)	/* Enable DMA interrupts */
+#define LOONGSON2_MMC_DMA_DATA_DIR	BIT(12) /* 1: write to device, 0: read from device */
+
 /* Loongson-2K1000 SDIO2 DMA routing register */
 #define LS2K1000_SDIO_DMA_MASK		GENMASK(17, 15)
 #define LS2K1000_DMA0_CONF		0x0
@@ -180,6 +225,8 @@ struct loongson2_mmc_host {
 	struct resource *res;
 	struct clk *clk;
 	u64 rate;
+	void *sg_cpu;
+	dma_addr_t sg_dma;
 	int dma_complete;
 	struct dma_chan *chan;
 	int cmd_is_stop;
@@ -192,6 +239,7 @@ struct loongson2_mmc_host {
 struct loongson2_mmc_pdata {
 	const struct regmap_config regmap_config;
 	void (*reorder_cmd_data)(struct loongson2_mmc_host *host, struct mmc_command *cmd);
+	void (*fix_cmd_interrupt)(struct loongson2_mmc_host *host, struct mmc_command *cmd);
 	int (*setting_dma)(struct loongson2_mmc_host *host, struct platform_device *pdev);
 	int (*prepare_dma)(struct loongson2_mmc_host *host, struct mmc_data *data);
 	void (*release_dma)(struct loongson2_mmc_host *host, struct device *dev);
@@ -282,6 +330,12 @@ static void loongson2_mmc_send_request(struct mmc_host *mmc)
 		return;
 	}
 
+	/* Fix lose interrupt issue when sending MMC_WRITE_BLOCK
+	 * or MMC_WRITE_MULTIPLE_BLOCK commands
+	 */
+	if (host->pdata->fix_cmd_interrupt)
+		host->pdata->fix_cmd_interrupt(host, cmd);
+
 	loongson2_mmc_send_command(host, cmd);
 
 	/* Fix deselect card */
@@ -426,6 +480,36 @@ static irqreturn_t loongson2_mmc_irq(int irq, void *devid)
 	return IRQ_WAKE_THREAD;
 }
 
+static void loongson2_mmc_ddr_mode_init(struct loongson2_mmc_host *host)
+{
+	u32 val, pad_delay, delay, ret;
+
+	regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_SEL,
+			   LOONGSON2_MMC_SEL_DATA, LOONGSON2_MMC_SEL_DATA);
+
+	val = FIELD_PREP(LOONGSON2_MMC_DLLCTL_TIME, 0xc8)
+	    | FIELD_PREP(LOONGSON2_MMC_DLLCTL_INCRE, 0x1)
+	    | FIELD_PREP(LOONGSON2_MMC_DLLCTL_START, 0x1)
+	    | FIELD_PREP(LOONGSON2_MMC_DLLCTL_CLK_MODE, 0x1)
+	    | FIELD_PREP(LOONGSON2_MMC_DLLCTL_START_BIT, 0x1)
+	    | FIELD_PREP(LOONGSON2_MMC_DLLCTL_TIME_BPASS, 0xf);
+
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_DLLCTL, val);
+
+	ret = regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_DLLVAL, val,
+				       (val & LOONGSON2_MMC_DLLVAL_DONE), 0, 4000);
+	if (ret < 0)
+		return;
+
+	regmap_read(host->regmap, LOONGSON2_MMC_REG_DLLVAL, &val);
+	pad_delay = FIELD_GET(GENMASK(7, 1), val);
+
+	delay = FIELD_PREP(LOONGSON2_MMC_DELAY_PAD, pad_delay)
+	      | FIELD_PREP(LOONGSON2_MMC_DELAY_RD, pad_delay + 1);
+
+	regmap_write(host->regmap, LOONGSON2_MMC_REG_DELAY, delay);
+}
+
 static void loongson2_mmc_set_clk(struct loongson2_mmc_host *host, struct mmc_ios *ios)
 {
 	u32 pre;
@@ -438,6 +522,10 @@ static void loongson2_mmc_set_clk(struct loongson2_mmc_host *host, struct mmc_io
 
 	regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL,
 			   LOONGSON2_MMC_CTL_ENCLK, LOONGSON2_MMC_CTL_ENCLK);
+
+	/* EMMC DDR mode setting */
+	if (ios->timing == MMC_TIMING_UHS_DDR50 || ios->timing == MMC_TIMING_MMC_DDR52)
+		loongson2_mmc_ddr_mode_init(host);
 }
 
 static void loongson2_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -641,6 +729,122 @@ static struct loongson2_mmc_pdata ls2k1000_mmc_pdata = {
 	.release_dma		= loongson2_mmc_release_external_dma,
 };
 
+static const struct regmap_config ls2k2000_mmc_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = LOONGSON2_MMC_REG_RDMA_HI,
+};
+
+static void ls2k2000_mmc_reorder_cmd_data(struct loongson2_mmc_host *host,
+					  struct mmc_command *cmd)
+{
+	struct scatterlist *sg;
+	u32 *data;
+	int i, j;
+
+	if (cmd->opcode != SD_SWITCH || mmc_cmd_type(cmd) != MMC_CMD_ADTC)
+		return;
+
+	for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) {
+		data = sg_virt(&sg[i]);
+		for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++)
+			data[j] = bitrev8x4(data[j]);
+	}
+}
+
+static void ls2k2000_mmc_fix_cmd_interrupt(struct loongson2_mmc_host *host,
+					   struct mmc_command *cmd)
+{
+	int val;
+
+	if (cmd->opcode != MMC_WRITE_BLOCK && cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
+		return;
+
+	regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_FSTS, val,
+				 (val & LOONGSON2_MMC_FSTS_TXFULL), 0, 500);
+}
+
+static int loongson2_mmc_prepare_internal_dma(struct loongson2_mmc_host *host,
+					      struct mmc_data *data)
+{
+	struct loongson2_dma_desc *pdes = (struct loongson2_dma_desc *)host->sg_cpu;
+	struct mmc_host *mmc = mmc_from_priv(host);
+	dma_addr_t next_desc = host->sg_dma;
+	struct scatterlist *sg;
+	int reg_lo, reg_hi;
+	u64 dma_order;
+	int i, ret;
+
+	ret = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
+			 mmc_get_dma_dir(data));
+	if (!ret)
+		return -ENOMEM;
+
+	for_each_sg(data->sg, sg, data->sg_len, i) {
+		pdes[i].len = sg_dma_len(&sg[i]) / 4;
+		pdes[i].step_len = 0;
+		pdes[i].step_times = 1;
+		pdes[i].mem_addr = lower_32_bits(sg_dma_address(&sg[i]));
+		pdes[i].high_mem_addr = upper_32_bits(sg_dma_address(&sg[i]));
+		pdes[i].apb_addr = host->res->start + LOONGSON2_MMC_REG_DATA;
+		pdes[i].cmd = LOONGSON2_MMC_DMA_INT;
+
+		if (data->flags & MMC_DATA_READ) {
+			reg_lo = LOONGSON2_MMC_REG_RDMA_LO;
+			reg_hi = LOONGSON2_MMC_REG_RDMA_HI;
+		} else {
+			pdes[i].cmd |= LOONGSON2_MMC_DMA_DATA_DIR;
+			reg_lo = LOONGSON2_MMC_REG_WDMA_LO;
+			reg_hi = LOONGSON2_MMC_REG_WDMA_HI;
+		}
+
+		next_desc += sizeof(struct loongson2_dma_desc);
+		pdes[i].ndesc_addr = lower_32_bits(next_desc) |
+				     LOONGSON2_MMC_DMA_DESC_EN;
+		pdes[i].high_ndesc_addr = upper_32_bits(next_desc);
+	}
+
+	/* Setting the last descriptor enable bit */
+	pdes[i - 1].ndesc_addr &= ~LOONGSON2_MMC_DMA_DESC_EN;
+
+	dma_order = (host->sg_dma & ~LOONGSON2_MMC_DMA_CONFIG_MASK) |
+		    LOONGSON2_MMC_DMA_64BIT_EN |
+		    LOONGSON2_MMC_DMA_START;
+
+	regmap_write(host->regmap, reg_hi, upper_32_bits(dma_order));
+	regmap_write(host->regmap, reg_lo, lower_32_bits(dma_order));
+
+	return 0;
+}
+
+static int loongson2_mmc_set_internal_dma(struct loongson2_mmc_host *host,
+					  struct platform_device *pdev)
+{
+	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
+					  &host->sg_dma, GFP_KERNEL);
+	if (!host->sg_cpu)
+		return -ENOMEM;
+
+	memset(host->sg_cpu, 0, PAGE_SIZE);
+	return 0;
+}
+
+static void loongson2_mmc_release_internal_dma(struct loongson2_mmc_host *host,
+					       struct device *dev)
+{
+	dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+}
+
+static struct loongson2_mmc_pdata ls2k2000_mmc_pdata = {
+	.regmap_config		= ls2k2000_mmc_regmap_config,
+	.reorder_cmd_data	= ls2k2000_mmc_reorder_cmd_data,
+	.fix_cmd_interrupt	= ls2k2000_mmc_fix_cmd_interrupt,
+	.setting_dma		= loongson2_mmc_set_internal_dma,
+	.prepare_dma		= loongson2_mmc_prepare_internal_dma,
+	.release_dma		= loongson2_mmc_release_internal_dma,
+};
+
 static int loongson2_mmc_resource_request(struct platform_device *pdev,
 					  struct loongson2_mmc_host *host)
 {
@@ -759,6 +963,7 @@ static void loongson2_mmc_remove(struct platform_device *pdev)
 static const struct of_device_id loongson2_mmc_of_ids[] = {
 	{ .compatible = "loongson,ls2k0500-mmc", .data = &ls2k0500_mmc_pdata },
 	{ .compatible = "loongson,ls2k1000-mmc", .data = &ls2k1000_mmc_pdata },
+	{ .compatible = "loongson,ls2k2000-mmc", .data = &ls2k2000_mmc_pdata },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, loongson2_mmc_of_ids);
-- 
2.47.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver
  2025-05-07  7:28 ` [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver Binbin Zhou
@ 2025-05-08 10:13   ` kernel test robot
  2025-05-13  2:09   ` kernel test robot
  2025-05-19 11:03   ` Ulf Hansson
  2 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-05-08 10:13 UTC (permalink / raw)
  To: Binbin Zhou, Binbin Zhou, Huacai Chen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Ulf Hansson
  Cc: llvm, oe-kbuild-all, Xuerui Wang, loongarch, devicetree,
	linux-mmc

Hi Binbin,

kernel test robot noticed the following build errors:

[auto build test ERROR on 9e12816f9a6195f1f5b7c5dc2e388c2458411b97]

url:    https://github.com/intel-lab-lkp/linux/commits/Binbin-Zhou/dt-bindings-mmc-Add-Loongson-2K-SD-SDIO-eMMC-controller-binding/20250507-153435
base:   9e12816f9a6195f1f5b7c5dc2e388c2458411b97
patch link:    https://lore.kernel.org/r/1308b6ca9ffc2674cc0f089cfd163da87e53a8cd.1746581751.git.zhoubinbin%40loongson.cn
patch subject: [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver
config: riscv-allyesconfig (https://download.01.org/0day-ci/archive/20250508/202505081845.0NQYX2nS-lkp@intel.com/config)
compiler: clang version 16.0.6 (https://github.com/llvm/llvm-project 7cbf1a2591520c2491aa35339f227775f4d3adf6)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250508/202505081845.0NQYX2nS-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505081845.0NQYX2nS-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/mmc/host/loongson2-mmc.c:605:20: error: initializer element is not a compile-time constant
           .regmap_config          = ls2k1000_regmap_config,
                                     ^~~~~~~~~~~~~~~~~~~~~~
   drivers/mmc/host/loongson2-mmc.c:637:20: error: initializer element is not a compile-time constant
           .regmap_config          = ls2k1000_regmap_config,
                                     ^~~~~~~~~~~~~~~~~~~~~~
   drivers/mmc/host/loongson2-mmc.c:684:39: warning: shift count >= width of type [-Wshift-count-overflow]
           ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
                                                ^~~~~~~~~~~~~~~~
   include/linux/dma-mapping.h:73:54: note: expanded from macro 'DMA_BIT_MASK'
   #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
                                                        ^ ~~~
   1 warning and 2 errors generated.


vim +605 drivers/mmc/host/loongson2-mmc.c

   603	
   604	static struct loongson2_mmc_pdata ls2k0500_mmc_pdata = {
 > 605		.regmap_config		= ls2k1000_regmap_config,
   606		.reorder_cmd_data	= loongson2_mmc_reorder_cmd_data,
   607		.setting_dma		= ls2k0500_mmc_set_external_dma,
   608		.prepare_dma		= loongson2_mmc_prepare_external_dma,
   609		.release_dma		= loongson2_mmc_release_external_dma,
   610	};
   611	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 3/4] dt-bindings: mmc: loongson,ls2k-mmc: Add compatible for Loongson-2K2000
  2025-05-07  7:28 ` [PATCH v2 3/4] dt-bindings: mmc: loongson,ls2k-mmc: Add compatible for Loongson-2K2000 Binbin Zhou
@ 2025-05-08 15:00   ` Conor Dooley
  0 siblings, 0 replies; 15+ messages in thread
From: Conor Dooley @ 2025-05-08 15:00 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-mmc

[-- Attachment #1: Type: text/plain, Size: 254 bytes --]

On Wed, May 07, 2025 at 03:28:07PM +0800, Binbin Zhou wrote:
> Add the devicetree compatible for Loongson-2K2000 EMMC/SD/SDIO controller.
> 
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>

Acked-by: Conor Dooley <conor.dooley@microchip.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/4] dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding
  2025-05-07  7:28 ` [PATCH v2 1/4] dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding Binbin Zhou
@ 2025-05-08 15:00   ` Conor Dooley
  2025-05-09  1:22     ` Binbin Zhou
  0 siblings, 1 reply; 15+ messages in thread
From: Conor Dooley @ 2025-05-08 15:00 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-mmc

[-- Attachment #1: Type: text/plain, Size: 3356 bytes --]

On Wed, May 07, 2025 at 03:28:05PM +0800, Binbin Zhou wrote:
> Add the Loongson-2K SoC's SD/SDIO/eMMC controller binding with DT schema
> format using json-schema.
> 
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
>  .../bindings/mmc/loongson,ls2k-mmc.yaml       | 69 +++++++++++++++++++
>  MAINTAINERS                                   |  6 ++
>  2 files changed, 75 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
> 
> diff --git a/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml b/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
> new file mode 100644
> index 000000000000..97a0853399f1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
> @@ -0,0 +1,69 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mmc/loongson,ls2k-mmc.yaml#

Filename matching a compatible please.
Otherwise this looks okay to me.

> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: The SD/SDIO/eMMC host controller for Loongson-2K family SoCs
> +
> +description:
> +  The MMC host controller on the Loongson-2K0500/2K1000 (using an externally
> +  shared apbdma controller) provides the SD and SDIO device interfaces.
> +
> +maintainers:
> +  - Binbin Zhou <zhoubinbin@loongson.cn>
> +
> +allOf:
> +  - $ref: mmc-controller.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - loongson,ls2k0500-mmc
> +      - loongson,ls2k1000-mmc
> +
> +  reg:
> +    items:
> +      - description: Loongson-2K MMC controller registers.
> +      - description: APB DMA config register for Loongson-2K MMC controller.
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  dmas:
> +    maxItems: 1
> +
> +  dma-names:
> +    const: rx-tx
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - dmas
> +  - dma-names
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    #include <dt-bindings/clock/loongson,ls2k-clk.h>
> +
> +    mmc@1fe2c000 {
> +        compatible = "loongson,ls2k1000-mmc";
> +        reg = <0x1fe2c000 0x68>,
> +              <0x1fe00438 0x8>;
> +        interrupt-parent = <&liointc0>;
> +        interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
> +        clocks = <&clk LOONGSON2_APB_CLK>;
> +        dmas = <&apbdma1 0>;
> +        dma-names = "rx-tx";
> +        bus-width = <4>;
> +        cd-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 96b827049501..5bf74aa63299 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13935,6 +13935,12 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml
>  F:	drivers/soc/loongson/loongson2_guts.c
>  
> +LOONGSON-2 SOC SERIES MMC/SD/SDIO CONTROLLER DRIVER
> +M:	Binbin Zhou <zhoubinbin@loongson.cn>
> +L:	linux-mmc@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
> +
>  LOONGSON-2 SOC SERIES PM DRIVER
>  M:	Yinbo Zhu <zhuyinbo@loongson.cn>
>  L:	linux-pm@vger.kernel.org
> -- 
> 2.47.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/4] dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding
  2025-05-08 15:00   ` Conor Dooley
@ 2025-05-09  1:22     ` Binbin Zhou
  0 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2025-05-09  1:22 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Ulf Hansson, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-mmc

Hi Conor:

Thanks for your review.

On Thu, May 8, 2025 at 11:01 PM Conor Dooley <conor@kernel.org> wrote:
>
> On Wed, May 07, 2025 at 03:28:05PM +0800, Binbin Zhou wrote:
> > Add the Loongson-2K SoC's SD/SDIO/eMMC controller binding with DT schema
> > format using json-schema.
> >
> > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > ---
> >  .../bindings/mmc/loongson,ls2k-mmc.yaml       | 69 +++++++++++++++++++
> >  MAINTAINERS                                   |  6 ++
> >  2 files changed, 75 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml b/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
> > new file mode 100644
> > index 000000000000..97a0853399f1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
> > @@ -0,0 +1,69 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/mmc/loongson,ls2k-mmc.yaml#
>
> Filename matching a compatible please.
> Otherwise this looks okay to me.

Yes, I forgot about this point, it will be renamed to
loongson,ls2k0500-mmc.yaml.

>
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: The SD/SDIO/eMMC host controller for Loongson-2K family SoCs
> > +
> > +description:
> > +  The MMC host controller on the Loongson-2K0500/2K1000 (using an externally
> > +  shared apbdma controller) provides the SD and SDIO device interfaces.
> > +
> > +maintainers:
> > +  - Binbin Zhou <zhoubinbin@loongson.cn>
> > +
> > +allOf:
> > +  - $ref: mmc-controller.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - loongson,ls2k0500-mmc
> > +      - loongson,ls2k1000-mmc
> > +
> > +  reg:
> > +    items:
> > +      - description: Loongson-2K MMC controller registers.
> > +      - description: APB DMA config register for Loongson-2K MMC controller.
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    maxItems: 1
> > +
> > +  dmas:
> > +    maxItems: 1
> > +
> > +  dma-names:
> > +    const: rx-tx
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - clocks
> > +  - dmas
> > +  - dma-names
> > +
> > +unevaluatedProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/gpio/gpio.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +    #include <dt-bindings/clock/loongson,ls2k-clk.h>
> > +
> > +    mmc@1fe2c000 {
> > +        compatible = "loongson,ls2k1000-mmc";
> > +        reg = <0x1fe2c000 0x68>,
> > +              <0x1fe00438 0x8>;
> > +        interrupt-parent = <&liointc0>;
> > +        interrupts = <31 IRQ_TYPE_LEVEL_HIGH>;
> > +        clocks = <&clk LOONGSON2_APB_CLK>;
> > +        dmas = <&apbdma1 0>;
> > +        dma-names = "rx-tx";
> > +        bus-width = <4>;
> > +        cd-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
> > +    };
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 96b827049501..5bf74aa63299 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -13935,6 +13935,12 @@ S:   Maintained
> >  F:   Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml
> >  F:   drivers/soc/loongson/loongson2_guts.c
> >
> > +LOONGSON-2 SOC SERIES MMC/SD/SDIO CONTROLLER DRIVER
> > +M:   Binbin Zhou <zhoubinbin@loongson.cn>
> > +L:   linux-mmc@vger.kernel.org
> > +S:   Maintained
> > +F:   Documentation/devicetree/bindings/mmc/loongson,ls2k-mmc.yaml
> > +
> >  LOONGSON-2 SOC SERIES PM DRIVER
> >  M:   Yinbo Zhu <zhuyinbo@loongson.cn>
> >  L:   linux-pm@vger.kernel.org
> > --
> > 2.47.1
> >

--
Thanks.
Binbin

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver
  2025-05-07  7:28 ` [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver Binbin Zhou
  2025-05-08 10:13   ` kernel test robot
@ 2025-05-13  2:09   ` kernel test robot
  2025-05-19 11:03   ` Ulf Hansson
  2 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-05-13  2:09 UTC (permalink / raw)
  To: Binbin Zhou, Binbin Zhou, Huacai Chen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Ulf Hansson
  Cc: oe-kbuild-all, Xuerui Wang, loongarch, devicetree, linux-mmc

Hi Binbin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 9e12816f9a6195f1f5b7c5dc2e388c2458411b97]

url:    https://github.com/intel-lab-lkp/linux/commits/Binbin-Zhou/dt-bindings-mmc-Add-Loongson-2K-SD-SDIO-eMMC-controller-binding/20250507-153435
base:   9e12816f9a6195f1f5b7c5dc2e388c2458411b97
patch link:    https://lore.kernel.org/r/1308b6ca9ffc2674cc0f089cfd163da87e53a8cd.1746581751.git.zhoubinbin%40loongson.cn
patch subject: [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver
config: csky-randconfig-r112-20250513 (https://download.01.org/0day-ci/archive/20250513/202505130918.uanOGxju-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 14.2.0
reproduce: (https://download.01.org/0day-ci/archive/20250513/202505130918.uanOGxju-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505130918.uanOGxju-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/mmc/host/loongson2-mmc.c:534:41: sparse: sparse: incorrect type in assignment (different base types) @@     expected unsigned int [usertype] @@     got restricted __be32 [usertype] @@
   drivers/mmc/host/loongson2-mmc.c:534:41: sparse:     expected unsigned int [usertype]
   drivers/mmc/host/loongson2-mmc.c:534:41: sparse:     got restricted __be32 [usertype]

vim +534 drivers/mmc/host/loongson2-mmc.c

   500	
   501	static int loongson2_reorder_cmd_list[] = { SD_APP_SEND_SCR, SD_APP_SEND_NUM_WR_BLKS,
   502						    SD_APP_SD_STATUS, MMC_SEND_WRITE_PROT,
   503						    SD_SWITCH };
   504	
   505	/*
   506	 * According to SD spec, ACMD13, ACMD22, ACMD51 and CMD30
   507	 * response datas has different byte order with usual data packets.
   508	 * However sdio controller will send these datas in usual data format,
   509	 * so we need to adjust these datas to a protocol consistent byte order.
   510	 */
   511	static void loongson2_mmc_reorder_cmd_data(struct loongson2_mmc_host *host,
   512						   struct mmc_command *cmd)
   513	{
   514		struct scatterlist *sg;
   515		u32 *data;
   516		int i, j;
   517	
   518		if (mmc_cmd_type(cmd) != MMC_CMD_ADTC)
   519			return;
   520	
   521		for (i = 0; i < ARRAY_SIZE(loongson2_reorder_cmd_list); i++)
   522			if (cmd->opcode == loongson2_reorder_cmd_list[i])
   523				break;
   524	
   525		if (i == ARRAY_SIZE(loongson2_reorder_cmd_list))
   526			return;
   527	
   528		for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) {
   529			data = sg_virt(&sg[i]);
   530			for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++)
   531				if (cmd->opcode == SD_SWITCH)
   532					data[j] = bitrev8x4(data[j]);
   533				else
 > 534					data[j] = cpu_to_be32(data[j]);
   535		}
   536	}
   537	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver
  2025-05-07  7:28 ` [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver Binbin Zhou
  2025-05-08 10:13   ` kernel test robot
  2025-05-13  2:09   ` kernel test robot
@ 2025-05-19 11:03   ` Ulf Hansson
  2025-06-05  3:03     ` Binbin Zhou
  2 siblings, 1 reply; 15+ messages in thread
From: Ulf Hansson @ 2025-05-19 11:03 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Huacai Chen, Xuerui Wang, loongarch, devicetree,
	linux-mmc

On Wed, 7 May 2025 at 09:28, Binbin Zhou <zhoubinbin@loongson.cn> wrote:
>
> 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>

[...]

> +
> +static void loongson2_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> +       struct loongson2_mmc_host *host = mmc_priv(mmc);

As we now have support for regulators, we should use them here too.

Some something along the lines of this at MMC_POWER_OFF:
if (!IS_ERR(mmc->supply.vmmc))
      mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);

and at MMC_POWER_UP:
if (!IS_ERR(mmc->supply.vmmc))
      mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);

> +
> +       switch (ios->power_mode) {
> +       case MMC_POWER_ON:

Is the fallthrough really what we want here?

MMC_POWER_ON is used quite frequently when changing various ios
settings when the core calls mmc_set_ios(). MMC_POWER_UP is set only
once in mmc_power_up().

> +       case MMC_POWER_UP:
> +               regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_RESET);
> +               mdelay(10);
> +               regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_EXTCLK);
> +               regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, LOONGSON2_MMC_IEN_ALL);
> +               regmap_write(host->regmap, LOONGSON2_MMC_REG_IEN, LOONGSON2_MMC_INT_CLEAR);
> +               break;
> +       case MMC_POWER_OFF:
> +               regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL,
> +                                  LOONGSON2_MMC_CTL_RESET, LOONGSON2_MMC_CTL_RESET);
> +               return;
> +       default:
> +               return;
> +       }
> +
> +       loongson2_mmc_set_clk(host, ios);
> +
> +       host->bus_width = ios->bus_width;
> +}
> +

[...]

> +
> +static void loongson2_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> +{
> +       struct loongson2_mmc_host *host = mmc_priv(mmc);
> +
> +       regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_IEN,
> +                          LOONGSON2_MMC_INT_SDIOIRQ, enable);
> +}
> +
> +static struct mmc_host_ops loongson2_mmc_ops = {
> +       .request        = loongson2_mmc_request,
> +       .set_ios        = loongson2_mmc_set_ios,
> +       .get_ro         = mmc_gpio_get_ro,
> +       .get_cd         = mmc_gpio_get_cd,
> +       .enable_sdio_irq = loongson2_mmc_enable_sdio_irq,

The ->ack_sdio_irq() callback needs to be implemented too.

Moreover we need to set MMC_CAP2_SDIO_IRQ_NOTHREAD.

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 4/4] mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver
  2025-05-07  7:28 ` [PATCH v2 4/4] mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver Binbin Zhou
@ 2025-05-19 11:17   ` Ulf Hansson
  2025-06-03 12:54     ` Binbin Zhou
  0 siblings, 1 reply; 15+ messages in thread
From: Ulf Hansson @ 2025-05-19 11:17 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Huacai Chen, Xuerui Wang, loongarch, devicetree,
	linux-mmc

On Wed, 7 May 2025 at 09:28, Binbin Zhou <zhoubinbin@loongson.cn> wrote:
>
> 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 <zhoubinbin@loongson.cn>

[...]

> +
> +static void ls2k2000_mmc_fix_cmd_interrupt(struct loongson2_mmc_host *host,
> +                                          struct mmc_command *cmd)
> +{
> +       int val;
> +
> +       if (cmd->opcode != MMC_WRITE_BLOCK && cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
> +               return;
> +
> +       regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_FSTS, val,
> +                                (val & LOONGSON2_MMC_FSTS_TXFULL), 0, 500);

Can you please elaborate on what goes on here?

Note that, the mmc core uses a couple of different options to manage
busy detection monitoring on DAT0, for those commands that need it.

*) MMC_CAP_WAIT_WHILE_BUSY - if the host HW and the driver for it
supports IRQ based busy-detection.
*) host_ops->card_busy() callback if the HW can poll the DAT0 manually
for busy-detection.
*) Polling by using CMD13.

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 4/4] mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver
  2025-05-19 11:17   ` Ulf Hansson
@ 2025-06-03 12:54     ` Binbin Zhou
  2025-06-10 12:52       ` Ulf Hansson
  0 siblings, 1 reply; 15+ messages in thread
From: Binbin Zhou @ 2025-06-03 12:54 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Huacai Chen, Xuerui Wang, loongarch, devicetree,
	linux-mmc

Hi Ulf:

Sorry for the late reply.

On Mon, May 19, 2025 at 7:17 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:
>
> On Wed, 7 May 2025 at 09:28, Binbin Zhou <zhoubinbin@loongson.cn> wrote:
> >
> > 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 <zhoubinbin@loongson.cn>
>
> [...]
>
> > +
> > +static void ls2k2000_mmc_fix_cmd_interrupt(struct loongson2_mmc_host *host,
> > +                                          struct mmc_command *cmd)
> > +{
> > +       int val;
> > +
> > +       if (cmd->opcode != MMC_WRITE_BLOCK && cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
> > +               return;
> > +
> > +       regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_FSTS, val,
> > +                                (val & LOONGSON2_MMC_FSTS_TXFULL), 0, 500);
>
> Can you please elaborate on what goes on here?

This is a controller hardware issue. We need to wait until the Tx FIFO
full flag is set before sending the write command. Otherwise, a data
timeout will occur.
>
> Note that, the mmc core uses a couple of different options to manage
> busy detection monitoring on DAT0, for those commands that need it.
>
> *) MMC_CAP_WAIT_WHILE_BUSY - if the host HW and the driver for it
> supports IRQ based busy-detection.
> *) host_ops->card_busy() callback if the HW can poll the DAT0 manually
> for busy-detection.
> *) Polling by using CMD13.
>
> [...]
>
> Kind regards
> Uffe

--
Thanks.
Binbin

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver
  2025-05-19 11:03   ` Ulf Hansson
@ 2025-06-05  3:03     ` Binbin Zhou
  0 siblings, 0 replies; 15+ messages in thread
From: Binbin Zhou @ 2025-06-05  3:03 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Huacai Chen, Xuerui Wang, loongarch, devicetree,
	linux-mmc

Hi Ulf:

Sorry for the late reply.

On Mon, May 19, 2025 at 7:03 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:
>
> On Wed, 7 May 2025 at 09:28, Binbin Zhou <zhoubinbin@loongson.cn> wrote:
> >
> > 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>
>
> [...]
>
> > +
> > +static void loongson2_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > +       struct loongson2_mmc_host *host = mmc_priv(mmc);
>
> As we now have support for regulators, we should use them here too.
>
> Some something along the lines of this at MMC_POWER_OFF:
> if (!IS_ERR(mmc->supply.vmmc))
>       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
>
> and at MMC_POWER_UP:
> if (!IS_ERR(mmc->supply.vmmc))
>       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
>
> > +
> > +       switch (ios->power_mode) {
> > +       case MMC_POWER_ON:
>
> Is the fallthrough really what we want here?
>
> MMC_POWER_ON is used quite frequently when changing various ios
> settings when the core calls mmc_set_ios(). MMC_POWER_UP is set only
> once in mmc_power_up().

Indeed, this has been handled too roughly here. I will try to
subdivide each case and add regulator support.
>
> > +       case MMC_POWER_UP:
> > +               regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_RESET);
> > +               mdelay(10);
> > +               regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_EXTCLK);
> > +               regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, LOONGSON2_MMC_IEN_ALL);
> > +               regmap_write(host->regmap, LOONGSON2_MMC_REG_IEN, LOONGSON2_MMC_INT_CLEAR);
> > +               break;
> > +       case MMC_POWER_OFF:
> > +               regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL,
> > +                                  LOONGSON2_MMC_CTL_RESET, LOONGSON2_MMC_CTL_RESET);
> > +               return;
> > +       default:
> > +               return;
> > +       }
> > +
> > +       loongson2_mmc_set_clk(host, ios);
> > +
> > +       host->bus_width = ios->bus_width;
> > +}
> > +
>
> [...]
>
> > +
> > +static void loongson2_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> > +{
> > +       struct loongson2_mmc_host *host = mmc_priv(mmc);
> > +
> > +       regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_IEN,
> > +                          LOONGSON2_MMC_INT_SDIOIRQ, enable);
> > +}
> > +
> > +static struct mmc_host_ops loongson2_mmc_ops = {
> > +       .request        = loongson2_mmc_request,
> > +       .set_ios        = loongson2_mmc_set_ios,
> > +       .get_ro         = mmc_gpio_get_ro,
> > +       .get_cd         = mmc_gpio_get_cd,
> > +       .enable_sdio_irq = loongson2_mmc_enable_sdio_irq,
>
> The ->ack_sdio_irq() callback needs to be implemented too.
>
> Moreover we need to set MMC_CAP2_SDIO_IRQ_NOTHREAD.

OK..
>
> [...]
>
> Kind regards
> Uffe



-- 
Thanks.
Binbin

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 4/4] mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver
  2025-06-03 12:54     ` Binbin Zhou
@ 2025-06-10 12:52       ` Ulf Hansson
  0 siblings, 0 replies; 15+ messages in thread
From: Ulf Hansson @ 2025-06-10 12:52 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Huacai Chen, Xuerui Wang, loongarch, devicetree,
	linux-mmc

On Tue, 3 Jun 2025 at 14:54, Binbin Zhou <zhoubb.aaron@gmail.com> wrote:
>
> Hi Ulf:
>
> Sorry for the late reply.
>
> On Mon, May 19, 2025 at 7:17 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:
> >
> > On Wed, 7 May 2025 at 09:28, Binbin Zhou <zhoubinbin@loongson.cn> wrote:
> > >
> > > 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 <zhoubinbin@loongson.cn>
> >
> > [...]
> >
> > > +
> > > +static void ls2k2000_mmc_fix_cmd_interrupt(struct loongson2_mmc_host *host,
> > > +                                          struct mmc_command *cmd)
> > > +{
> > > +       int val;
> > > +
> > > +       if (cmd->opcode != MMC_WRITE_BLOCK && cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
> > > +               return;
> > > +
> > > +       regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_FSTS, val,
> > > +                                (val & LOONGSON2_MMC_FSTS_TXFULL), 0, 500);
> >
> > Can you please elaborate on what goes on here?
>
> This is a controller hardware issue. We need to wait until the Tx FIFO
> full flag is set before sending the write command. Otherwise, a data
> timeout will occur.

Okay, thanks for clarifying. Please add a comment in the code about
this as I think it useful to know.

Moreover, I think we should have the value of the timeout specified in a define.

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2025-06-10 12:53 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-07  7:28 [PATCH v2 0/4] LoongArch: Introduce the Loongson-2K MMC host controller driver Binbin Zhou
2025-05-07  7:28 ` [PATCH v2 1/4] dt-bindings: mmc: Add Loongson-2K SD/SDIO/eMMC controller binding Binbin Zhou
2025-05-08 15:00   ` Conor Dooley
2025-05-09  1:22     ` Binbin Zhou
2025-05-07  7:28 ` [PATCH v2 2/4] mmc: loongson2: Add Loongson-2K SD/SDIO controller driver Binbin Zhou
2025-05-08 10:13   ` kernel test robot
2025-05-13  2:09   ` kernel test robot
2025-05-19 11:03   ` Ulf Hansson
2025-06-05  3:03     ` Binbin Zhou
2025-05-07  7:28 ` [PATCH v2 3/4] dt-bindings: mmc: loongson,ls2k-mmc: Add compatible for Loongson-2K2000 Binbin Zhou
2025-05-08 15:00   ` Conor Dooley
2025-05-07  7:28 ` [PATCH v2 4/4] mmc: loongson2: Add Loongson-2K2000 SD/SDIO/eMMC controller driver Binbin Zhou
2025-05-19 11:17   ` Ulf Hansson
2025-06-03 12:54     ` Binbin Zhou
2025-06-10 12:52       ` Ulf Hansson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).