-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
mtd: rawnand: Add Phytium NAND flash controller support
This patch implements a device driver of NAND flash controller for both Phytium PCIe chipset and SoCs. Since interrupt flags depends on the bus implementation, e.g., PCI vs platform, we extract the interrupt register function from NFC driver core. Signed-off-by: Zhu Mingshuai <[email protected]> Signed-off-by: Zhou Yulin <[email protected]> Signed-off-by: Chen Baozi <[email protected]> Signed-off-by: Wang Yinfeng <[email protected]> Signed-off-by: Hu Yeqing <[email protected]>
1 parent
70ad6fc
commit 9264883
Showing
7 changed files
with
2,891 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,42 @@ | ||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
%YAML 1.2 | ||
--- | ||
$id: http://devicetree.org/schemas/mtd/phytium,nfc.yaml# | ||
$schema: http://devicetree.org/meta-schemas/core.yaml# | ||
|
||
title: Phytium Nand Flash controller | ||
|
||
maintainers: | ||
- Chen Baozi <[email protected]> | ||
|
||
properties: | ||
compatible: | ||
const: phytium,nfc | ||
|
||
reg: | ||
maxItems: 1 | ||
|
||
interrupts: | ||
maxItems: 1 | ||
|
||
nand-ecc-strength: | ||
const: 8 | ||
|
||
nand-ecc-step-size: | ||
const: 512 | ||
|
||
allOf: | ||
- $ref: "nand-controller.yaml#" | ||
|
||
required: | ||
- compatible | ||
- reg | ||
- interrupts | ||
|
||
examples: | ||
- | | ||
nand0: nand@28002000 { | ||
compatible = "phytium,nfc"; | ||
reg = <0x0 0x28002000 0x0 0x1000>; | ||
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; | ||
}; |
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
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
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,150 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* PCI driver for Phytium NAND flash controller | ||
* | ||
* Copyright (C) 2021-2023, Phytium Technology Co., Ltd. | ||
*/ | ||
#include <linux/module.h> | ||
#include <linux/pci.h> | ||
#include <linux/device.h> | ||
|
||
#include "phytium_nand.h" | ||
|
||
#define DRV_NAME "phytium_nand_pci" | ||
|
||
static struct mtd_partition partition_info[] = { | ||
{ | ||
.name = "Flash partition 1", | ||
.offset = 0x0000000, | ||
.size = 0x4000000 }, | ||
{ | ||
.name = "Flash partition 2", | ||
.offset = 0x4000000, | ||
.size = 0x8000000 }, | ||
{ | ||
.name = "Flash partition 3", | ||
.offset = 0x8000000, | ||
.size = 0x10000000 }, | ||
{ | ||
.name = "Flash partition 4", | ||
.offset = 0x10000000, | ||
.size = 0x12000000 }, | ||
{ | ||
.name = "Flash partition 5", | ||
.offset = 0x12000000, | ||
.size = 0x14000000 }, | ||
}; | ||
|
||
static struct phytium_nfc_caps x100_nfc_caps = { | ||
.hw_ver = 1, | ||
.int_mask_bits = 13, | ||
.max_cs_nb = 2, | ||
.max_rb_nb = 1, | ||
.legacy_of_bindings = true, | ||
.ecc_strength = 4, | ||
.ecc_step_size = 512, | ||
.nr_parts = 5, | ||
.parts = partition_info, | ||
}; | ||
|
||
static int phytium_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) | ||
{ | ||
struct phytium_nfc *nfc; | ||
int ret; | ||
|
||
ret = pcim_enable_device(pdev); | ||
if (ret) | ||
return ret; | ||
|
||
ret = pcim_iomap_regions(pdev, 0x1, pci_name(pdev)); | ||
if (ret) { | ||
dev_err(&pdev->dev, "I/O memory remapping failed\n"); | ||
return ret; | ||
} | ||
|
||
pci_set_master(pdev); | ||
pci_try_set_mwi(pdev); | ||
|
||
nfc = devm_kzalloc(&pdev->dev, sizeof(struct phytium_nfc), | ||
GFP_KERNEL); | ||
if (!nfc) | ||
return -ENOMEM; | ||
|
||
nfc->dev = &pdev->dev; | ||
nfc->regs = pcim_iomap_table(pdev)[0]; | ||
nfc->irq = pdev->irq; | ||
nfc->caps = &x100_nfc_caps; | ||
|
||
ret = devm_request_irq(nfc->dev, nfc->irq, phytium_nfc_isr, | ||
IRQF_SHARED, "phytium-nfc-pci", nfc); | ||
if (ret) { | ||
dev_err(nfc->dev, "Failed to register NFC interrupt.\n"); | ||
return ret; | ||
} | ||
|
||
ret = phytium_nand_init(nfc); | ||
if (ret) | ||
return ret; | ||
|
||
pci_set_drvdata(pdev, nfc); | ||
|
||
return ret; | ||
} | ||
|
||
static void phytium_pci_remove(struct pci_dev *pdev) | ||
{ | ||
struct phytium_nfc *nfc = pci_get_drvdata(pdev); | ||
int ret; | ||
|
||
ret = phytium_nand_remove(nfc); | ||
if (ret) | ||
dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret); | ||
} | ||
|
||
static int __maybe_unused phytium_nfc_prepare(struct device *dev) | ||
{ | ||
struct pci_dev *pci = to_pci_dev(dev); | ||
struct phytium_nfc *nfc = pci_get_drvdata(pci); | ||
int ret; | ||
|
||
ret = phytium_nand_prepare(nfc); | ||
|
||
return 0; | ||
} | ||
|
||
static int __maybe_unused phytium_nfc_resume(struct device *dev) | ||
{ | ||
struct pci_dev *pci = to_pci_dev(dev); | ||
struct phytium_nfc *nfc = pci_get_drvdata(pci); | ||
int ret; | ||
|
||
ret = phytium_nand_resume(nfc); | ||
|
||
return ret; | ||
} | ||
|
||
static const struct dev_pm_ops phytium_pci_dev_pm_ops = { | ||
.prepare = phytium_nfc_prepare, | ||
.resume = phytium_nfc_resume, | ||
}; | ||
|
||
static const struct pci_device_id phytium_pci_id_table[] = { | ||
{ PCI_VDEVICE(PHYTIUM, 0xdc29) }, | ||
{ } | ||
}; | ||
MODULE_DEVICE_TABLE(pci, phytium_pci_id_table); | ||
|
||
static struct pci_driver phytium_pci_driver = { | ||
.name = DRV_NAME, | ||
.id_table = phytium_pci_id_table, | ||
.probe = phytium_pci_probe, | ||
.remove = phytium_pci_remove, | ||
.driver = { | ||
.pm = &phytium_pci_dev_pm_ops, | ||
}, | ||
}; | ||
module_pci_driver(phytium_pci_driver); | ||
|
||
MODULE_LICENSE("GPL"); | ||
MODULE_DESCRIPTION("PCI driver for Phytium NAND controller"); | ||
MODULE_AUTHOR("Zhu Mingshuai <zhumingshuai@phytium.com.cn>"); |
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,138 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* Core driver for Phytium NAND flash controller | ||
* | ||
* Copyright (C) 2020-2023, Phytium Technology Co., Ltd. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/device.h> | ||
#include <linux/clk.h> | ||
#include <linux/pm_runtime.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/dmaengine.h> | ||
#include <linux/dma-mapping.h> | ||
#include <linux/of.h> | ||
#include <linux/of_dma.h> | ||
#include <linux/acpi.h> | ||
#include <linux/acpi_dma.h> | ||
|
||
#include "phytium_nand.h" | ||
|
||
#define DRV_NAME "phytium_nand_plat" | ||
|
||
static int phytium_nfc_plat_probe(struct platform_device *pdev) | ||
{ | ||
struct device *dev = &pdev->dev; | ||
struct resource *r; | ||
struct phytium_nfc *nfc; | ||
unsigned int ecc_strength; | ||
unsigned int ecc_step_size; | ||
int ret; | ||
|
||
nfc = devm_kzalloc(&pdev->dev, sizeof(struct phytium_nfc), | ||
GFP_KERNEL); | ||
if (!nfc) | ||
return -ENOMEM; | ||
|
||
nfc->dev = dev; | ||
|
||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
nfc->regs = devm_ioremap_resource(dev, r); | ||
if (IS_ERR(nfc->regs)) | ||
return PTR_ERR(nfc->regs); | ||
|
||
dev_info(nfc->dev, "NFC register address :%p, phy address:%llx\n", | ||
nfc->regs, r->start); | ||
|
||
nfc->irq = platform_get_irq(pdev, 0); | ||
if (nfc->irq < 0) { | ||
dev_err(dev, "failed to retrieve irq\n"); | ||
return nfc->irq; | ||
} | ||
|
||
ret = devm_request_irq(dev, nfc->irq, phytium_nfc_isr, 0, | ||
"phytium-nfc-plat", nfc); | ||
if (ret) { | ||
dev_err(nfc->dev, "Failed to register NFC interrupt.\n"); | ||
return ret; | ||
} | ||
|
||
nfc->caps = devm_kzalloc(dev, sizeof(struct phytium_nfc_caps), GFP_KERNEL); | ||
if (!nfc->caps) | ||
return -ENOMEM; | ||
|
||
/* Currently hard-coded parameters */ | ||
nfc->caps->hw_ver = 2; | ||
nfc->caps->int_mask_bits = 17; | ||
nfc->caps->max_cs_nb = 4; | ||
nfc->caps->max_rb_nb = 4; | ||
nfc->caps->nr_parts = 0; | ||
nfc->caps->parts = NULL; | ||
|
||
device_property_read_u32(&pdev->dev, "nand-ecc-strength", &ecc_strength); | ||
nfc->caps->ecc_strength = ecc_strength ? ecc_strength : 8; | ||
|
||
device_property_read_u32(&pdev->dev, "nand-ecc-step-size", &ecc_step_size); | ||
nfc->caps->ecc_step_size = ecc_step_size ? ecc_step_size : 512; | ||
|
||
ret = phytium_nand_init(nfc); | ||
if (ret) | ||
return ret; | ||
|
||
platform_set_drvdata(pdev, nfc); | ||
|
||
return ret; | ||
} | ||
|
||
static int phytium_nfc_plat_remove(struct platform_device *pdev) | ||
{ | ||
struct phytium_nfc *nfc = platform_get_drvdata(pdev); | ||
|
||
return phytium_nand_remove(nfc); | ||
} | ||
|
||
static int __maybe_unused phytium_nfc_plat_prepare(struct device *dev) | ||
{ | ||
struct phytium_nfc *nfc = dev_get_drvdata(dev); | ||
|
||
return phytium_nand_prepare(nfc); | ||
} | ||
|
||
static int __maybe_unused phytium_nfc_plat_resume(struct device *dev) | ||
{ | ||
struct phytium_nfc *nfc = dev_get_drvdata(dev); | ||
int ret; | ||
|
||
ret = phytium_nand_resume(nfc); | ||
|
||
return ret; | ||
} | ||
|
||
static const struct dev_pm_ops phytium_dev_pm_ops = { | ||
.prepare = phytium_nfc_plat_prepare, | ||
.resume = phytium_nfc_plat_resume, | ||
}; | ||
|
||
#ifdef CONFIG_OF | ||
static const struct of_device_id phytium_nfc_of_ids[] = { | ||
{ .compatible = "phytium,nfc", }, | ||
{ } | ||
}; | ||
MODULE_DEVICE_TABLE(of, phytium_nfc_of_ids); | ||
#endif | ||
|
||
static struct platform_driver phytium_nfc_plat_driver = { | ||
.driver = { | ||
.name = DRV_NAME, | ||
.of_match_table = phytium_nfc_of_ids, | ||
.pm = &phytium_dev_pm_ops, | ||
}, | ||
.probe = phytium_nfc_plat_probe, | ||
.remove = phytium_nfc_plat_remove, | ||
}; | ||
module_platform_driver(phytium_nfc_plat_driver) | ||
|
||
MODULE_LICENSE("GPL"); | ||
MODULE_DESCRIPTION("Phytium NAND controller Platform driver"); | ||
MODULE_AUTHOR("Zhu Mingshuai <zhumingshuai@phytium.com.cn>"); |