Skip to content

Commit

Permalink
phytium: Add support for the Phytium MMC
Browse files Browse the repository at this point in the history
This patch adds the Phytium Multimedia Card driver.

Signed-off-by: xu yan <[email protected]>
Signed-off-by: Cheng Quan <[email protected]>
Signed-off-by: Lai Xueyu <[email protected]>
Signed-off-by: Chen Baozi <[email protected]>
Signed-off-by: Wang Yinfeng <[email protected]>
  • Loading branch information
xu yan authored and MingcongBai committed May 29, 2024
1 parent 70ad6fc commit c2d635f
Show file tree
Hide file tree
Showing 10 changed files with 4,057 additions and 0 deletions.
67 changes: 67 additions & 0 deletions Documentation/devicetree/bindings/mmc/phytium,mci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/phytium,mci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Phytium Multimedia Card Interface controller

description: |
The highspeed MMC host controller on Phytium SoCs provides an interface
for MMC, SD and SDIO types of memory cards.
maintainers:
- Chen Baozi <[email protected]>

allOf:
- $ref: "mmc-controller.yaml"

properties:
compatible:
const: phytium,mci

reg:
maxItems: 1
description: mmc controller base registers.

interrupts:
maxItems: 1
description: mmc controller interrupt.

clocks:
maxItems: 1
description: phandles to input clocks.

clock-names:
items:
- const: phytium_mci_clk

required:
- compatible
- reg
- interrupts
- clocks
- clock-names

examples:
- |
mmc0: mmc@28000000 {
compatible = "phytium,mci";
reg = <0x0 0x28000000 0x0 0x1000>;
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sysclk_1200mhz>;
clock-names = "phytium_mci_clk";
status = "disabled";
};
&mmc0 {
bus-width = <4>;
max-frequency = <50000000>;
cap-sdio-irq;
cap-sd-highspeed;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
no-mmc;
status = "ok";
};
58 changes: 58 additions & 0 deletions Documentation/devicetree/bindings/mmc/phytium,sdci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/phytium,sdci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Phytium SDCI Controller Binding

maintainers:
- Chen Baozi <[email protected]>

allOf:
- $ref: mmc-controller.yaml#

properties:
compatible:
enum:
- phytium,sdci

reg:
maxItems: 1

interrupts:
minItems: 3
maxItems: 3

clocks:
minItems: 1
items:
- description: core clock

clock-names:
minItems: 1
items:
- const: phytium_sdc_clk

required:
- compatible
- reg
- interrupts
- clocks
- clock-names

unevaluatedProperties: false

examples:
- |
sdci: sdci@28207c00 {
compatible = "phytium,sdci";
reg = <0x0 0x28207c00 0x0 0x100>;
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sysclk_600mhz>;
clock-names = "phytium_sdc_clk";
};
...
35 changes: 35 additions & 0 deletions drivers/mmc/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1079,3 +1079,38 @@ config MMC_LITEX
module will be called litex_mmc.

If unsure, say N.

config MMC_PHYTIUM_SDCI
tristate "Phytium SD Host Controller support"
depends on ARM64
help
This selects support for the Phytium SD Host Controller on Phytium
Px210 chipset.

If you have a controller with this interface, say Y or M here.

If unsure, say N.

config MMC_PHYTIUM_MCI_PCI
tristate "Phytium PCI MultiMedia Card Interface support"
depends on ARCH_PHYTIUM
default y if ARCH_PHYTIUM
help
This selects support for the PCI MultiMedia Card Interface on Phytium
Px210 chipset.

If you have a controller with this interface, say Y or M here.

If unsure, say N.

config MMC_PHYTIUM_MCI_PLTFM
tristate "Phytium MultiMedia Card Interface support"
depends on ARCH_PHYTIUM && OF
default y if ARCH_PHYTIUM
help
This selects support for the MultiMedia Card Interface on Phytium
Px210 chipset.

If you have a controller with this interface, say Y or M here.

If unsure, say N.
3 changes: 3 additions & 0 deletions drivers/mmc/host/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ 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_PHYTIUM_SDCI) += phytium-sdci.o
obj-$(CONFIG_MMC_PHYTIUM_MCI_PCI) += phytium-mci-pci.o phytium-mci.o
obj-$(CONFIG_MMC_PHYTIUM_MCI_PLTFM) += phytium-mci-plat.o phytium-mci.o

obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o
Expand Down
175 changes: 175 additions & 0 deletions drivers/mmc/host/phytium-mci-pci.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Phytium Multimedia Card Interface PCI driver
*
* Copyright (C) 2020-2023, Phytium Technology Co., Ltd.
*
*/

#include <linux/module.h>
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include "phytium-mci.h"

static u32 sd_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY |
MMC_CAP_CMD23 | MMC_CAP_4_BIT_DATA;
static u32 sd_caps2 = MMC_CAP2_NO_MMC;

static u32 emmc_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | MMC_CAP_WAIT_WHILE_BUSY |
MMC_CAP_CMD23 | MMC_CAP_HW_RESET | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_NONREMOVABLE;
static u32 emmc_caps2 = MMC_CAP2_NO_SDIO | MMC_CAP2_NO_SD;

#define PCI_BAR_NO 0

#if defined CONFIG_PM && defined CONFIG_PM_SLEEP
static const struct dev_pm_ops phytium_mci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(phytium_mci_suspend,
phytium_mci_resume)
SET_RUNTIME_PM_OPS(phytium_mci_runtime_suspend,
phytium_mci_runtime_resume, NULL)
};
#else
#define phytium_mci_dev_pm_ops NULL
#endif

static int
phytium_mci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
{
struct phytium_mci_host *host;
struct mmc_host *mmc;
int ret;

ret = pcim_enable_device(pdev);

if (ret)
return ret;
pci_set_master(pdev);

mmc = mmc_alloc_host(sizeof(struct phytium_mci_host), &pdev->dev);

if (!mmc)
return -ENOMEM;

host = mmc_priv(mmc);

pci_enable_msi(pdev);

host->irq = pdev->irq;
host->irq_flags = IRQF_SHARED;
host->dev = &pdev->dev;
ret = pcim_iomap_regions(pdev, 1 << PCI_BAR_NO, pci_name(pdev));

if (ret) {
dev_err(&pdev->dev, "I/O memory remapping failed\n");
goto host_free;
}

host->base = pcim_iomap_table(pdev)[PCI_BAR_NO];
host->is_use_dma = 1;
host->is_device_x100 = 1;

if (pdev->devfn == 2) {
host->caps = emmc_caps;
host->caps2 = emmc_caps2;
} else {
host->caps = sd_caps;
host->caps2 = sd_caps2;
mmc->f_max = 25000000; /* stable frequency */
}

host->mmc = mmc;
host->clk_rate = MCI_CLK;

dev_info(&pdev->dev, "%s %d: [bar %d] addr: 0x%llx size: 0x%llx km: 0x%llx devfn:%d\n",
__func__, __LINE__, PCI_BAR_NO, pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0), (uint64_t)host->base, pdev->devfn);

dev_dbg(&pdev->dev, "%s %d:irq:0x%x\n", __func__, __LINE__, host->irq);

ret = phytium_mci_common_probe(host);

if (ret == MCI_REALEASE_MEM) {
ret = -ENOMEM;
goto release_mem;
} else if (ret) {
goto release;
}
pci_set_drvdata(pdev, mmc);
dev_info(&pdev->dev, "%s %d: probe phytium mci successful.\n", __func__, __LINE__);
return 0;

release:
phytium_mci_deinit_hw(host);
release_mem:

if (host->dma.adma_table) {
dma_free_coherent(&pdev->dev,
MAX_BD_NUM * sizeof(struct phytium_adma2_64_desc),
host->dma.adma_table, host->dma.adma_addr);
}
host_free:
mmc_free_host(mmc);
pci_disable_device(pdev);
return ret;
}

static void phytium_mci_pci_remove(struct pci_dev *pdev)
{
struct phytium_mci_host *host;
struct mmc_host *mmc;

mmc = pci_get_drvdata(pdev);
if (!mmc) {
dev_info(&pdev->dev, "%s %d: mmc is null.\n", __func__, __LINE__);
return;
}
host = mmc_priv(mmc);
if (!host) {
dev_info(&pdev->dev, "%s %d: host is null.\n", __func__, __LINE__);
mmc_remove_host(mmc);
mmc_free_host(mmc);
return;
}

del_timer(&host->hotplug_timer);

mmc_remove_host(host->mmc);

if (host->dma.adma_table) {
dma_free_coherent(&pdev->dev,
MAX_BD_NUM * sizeof(struct phytium_adma2_64_desc),
host->dma.adma_table, host->dma.adma_addr);
}
phytium_mci_deinit_hw(host);
mmc_free_host(mmc);
pci_set_drvdata(pdev, NULL);
}

static const struct pci_device_id phytium_mci_pci_tbl[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_PHYTIUM, 0xdc28),
.class = 0x5,
.class_mask = 0,
},
{}
};
MODULE_DEVICE_TABLE(pci, phytium_mci_pci_tbl);

static struct pci_driver phytium_mci_pci_driver = {
.name = "phytium-mci-pci",
.id_table = phytium_mci_pci_tbl,
.probe = phytium_mci_pci_probe,
.remove = phytium_mci_pci_remove,
.driver = {
.pm = &phytium_mci_dev_pm_ops,
}
};
module_pci_driver(phytium_mci_pci_driver);

MODULE_DESCRIPTION("Phytium Multimedia Card Interface PCI driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cheng Quan <[email protected]>");
Loading

0 comments on commit c2d635f

Please sign in to comment.