Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

phytium: Add support for the Phytium MMC #147

Merged
merged 1 commit into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1071,3 +1071,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