mtd: rawnand: stm32_fmc2: get resources from parent node

FMC2 EBI support has been added. Common resources (registers base
address and clock) can now be shared between the 2 drivers using
"st,stm32mp1-fmc2-nfc" compatible string. It means that the
common resources should now be found in the parent device when EBI
node is available.

Signed-off-by: Christophe Kerello <christophe.kerello@st.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/1591975362-22009-7-git-send-email-christophe.kerello@st.com
This commit is contained in:
Christophe Kerello 2020-06-12 17:22:42 +02:00 committed by Miquel Raynal
parent 51c88a8d3b
commit fbd9b5437b
2 changed files with 51 additions and 23 deletions

View File

@ -415,8 +415,7 @@ config MTD_NAND_TEGRA
config MTD_NAND_STM32_FMC2 config MTD_NAND_STM32_FMC2
tristate "Support for NAND controller on STM32MP SoCs" tristate "Support for NAND controller on STM32MP SoCs"
depends on MACH_STM32MP157 || COMPILE_TEST depends on MACH_STM32MP157 || COMPILE_TEST
select REGMAP select MFD_SYSCON
select REGMAP_MMIO
help help
Enables support for NAND Flash chips on SoCs containing the FMC2 Enables support for NAND Flash chips on SoCs containing the FMC2
NAND controller. This controller is found on STM32MP SoCs. NAND controller. This controller is found on STM32MP SoCs.

View File

@ -11,8 +11,10 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mtd/rawnand.h> #include <linux/mtd/rawnand.h>
#include <linux/of_address.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
@ -204,16 +206,6 @@
#define FMC2_BCHDSR4_EBP7 GENMASK(12, 0) #define FMC2_BCHDSR4_EBP7 GENMASK(12, 0)
#define FMC2_BCHDSR4_EBP8 GENMASK(28, 16) #define FMC2_BCHDSR4_EBP8 GENMASK(28, 16)
/* Regmap registers configuration */
#define FMC2_MAX_REGISTER 0x3fc
static const struct regmap_config stm32_fmc2_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = sizeof(u32),
.max_register = FMC2_MAX_REGISTER,
};
enum stm32_fmc2_ecc { enum stm32_fmc2_ecc {
FMC2_ECC_HAM = 1, FMC2_ECC_HAM = 1,
FMC2_ECC_BCH4 = 4, FMC2_ECC_BCH4 = 4,
@ -253,6 +245,7 @@ struct stm32_fmc2_nfc {
struct nand_controller base; struct nand_controller base;
struct stm32_fmc2_nand nand; struct stm32_fmc2_nand nand;
struct device *dev; struct device *dev;
struct device *cdev;
struct regmap *regmap; struct regmap *regmap;
void __iomem *data_base[FMC2_MAX_CE]; void __iomem *data_base[FMC2_MAX_CE];
void __iomem *cmd_base[FMC2_MAX_CE]; void __iomem *cmd_base[FMC2_MAX_CE];
@ -1384,8 +1377,9 @@ static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc)
pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT); pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT);
/* Enable FMC2 controller */ /* Enable FMC2 controller */
regmap_update_bits(nfc->regmap, FMC2_BCR1, if (nfc->dev == nfc->cdev)
FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); regmap_update_bits(nfc->regmap, FMC2_BCR1,
FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN);
regmap_write(nfc->regmap, FMC2_PCR, pcr); regmap_write(nfc->regmap, FMC2_PCR, pcr);
regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT); regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT);
@ -1815,6 +1809,33 @@ static int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc)
return ret; return ret;
} }
static int stm32_fmc2_nfc_set_cdev(struct stm32_fmc2_nfc *nfc)
{
struct device *dev = nfc->dev;
bool ebi_found = false;
if (dev->parent && of_device_is_compatible(dev->parent->of_node,
"st,stm32mp1-fmc2-ebi"))
ebi_found = true;
if (of_device_is_compatible(dev->of_node, "st,stm32mp1-fmc2-nfc")) {
if (ebi_found) {
nfc->cdev = dev->parent;
return 0;
}
return -EINVAL;
}
if (ebi_found)
return -EINVAL;
nfc->cdev = dev;
return 0;
}
static int stm32_fmc2_nfc_probe(struct platform_device *pdev) static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
@ -1824,8 +1845,9 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
struct mtd_info *mtd; struct mtd_info *mtd;
struct nand_chip *chip; struct nand_chip *chip;
void __iomem *mmio; struct resource cres;
int chip_cs, mem_region, ret, irq; int chip_cs, mem_region, ret, irq;
int start_region = 0;
nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
if (!nfc) if (!nfc)
@ -1835,22 +1857,28 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
nand_controller_init(&nfc->base); nand_controller_init(&nfc->base);
nfc->base.ops = &stm32_fmc2_nfc_controller_ops; nfc->base.ops = &stm32_fmc2_nfc_controller_ops;
ret = stm32_fmc2_nfc_set_cdev(nfc);
if (ret)
return ret;
ret = stm32_fmc2_nfc_parse_dt(nfc); ret = stm32_fmc2_nfc_parse_dt(nfc);
if (ret) if (ret)
return ret; return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ret = of_address_to_resource(nfc->cdev->of_node, 0, &cres);
mmio = devm_ioremap_resource(dev, res); if (ret)
if (IS_ERR(mmio)) return ret;
return PTR_ERR(mmio);
nfc->regmap = devm_regmap_init_mmio(dev, mmio, &stm32_fmc2_regmap_cfg); nfc->io_phys_addr = cres.start;
nfc->regmap = device_node_to_regmap(nfc->cdev->of_node);
if (IS_ERR(nfc->regmap)) if (IS_ERR(nfc->regmap))
return PTR_ERR(nfc->regmap); return PTR_ERR(nfc->regmap);
nfc->io_phys_addr = res->start; if (nfc->dev == nfc->cdev)
start_region = 1;
for (chip_cs = 0, mem_region = 1; chip_cs < FMC2_MAX_CE; for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE;
chip_cs++, mem_region += 3) { chip_cs++, mem_region += 3) {
if (!(nfc->cs_assigned & BIT(chip_cs))) if (!(nfc->cs_assigned & BIT(chip_cs)))
continue; continue;
@ -1888,7 +1916,7 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
init_completion(&nfc->complete); init_completion(&nfc->complete);
nfc->clk = devm_clk_get(dev, NULL); nfc->clk = devm_clk_get(nfc->cdev, NULL);
if (IS_ERR(nfc->clk)) if (IS_ERR(nfc->clk))
return PTR_ERR(nfc->clk); return PTR_ERR(nfc->clk);
@ -2029,6 +2057,7 @@ static SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend,
static const struct of_device_id stm32_fmc2_nfc_match[] = { static const struct of_device_id stm32_fmc2_nfc_match[] = {
{.compatible = "st,stm32mp15-fmc2"}, {.compatible = "st,stm32mp15-fmc2"},
{.compatible = "st,stm32mp1-fmc2-nfc"},
{} {}
}; };
MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match); MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match);