* [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
* 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
* [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
* 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 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 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
* [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
* 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
* [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 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 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).