-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
phytium: Add support for the Phytium MMC
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
1 parent
70ad6fc
commit c2d635f
Showing
10 changed files
with
4,057 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | ||
}; | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]>"); |
Oops, something went wrong.