// SPDX-License-Identifier: GPL-2.0 /* * NAND Flash Controller Device Driver for DT * * Copyright © 2011, Picochip. */ #include #include #include #include #include #include #include #include #include #include #include #include "denali.h" struct denali_dt { struct denali_controller denali; struct clk *clk; /* core clock */ struct clk *clk_x; /* bus interface clock */ struct clk *clk_ecc; /* ECC circuit clock */ }; struct denali_dt_data { unsigned int revision; unsigned int caps; unsigned int oob_skip_bytes; const struct nand_ecc_caps *ecc_caps; }; NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15); static const struct denali_dt_data denali_socfpga_data = { .caps = DENALI_CAP_HW_ECC_FIXUP, .oob_skip_bytes = 2, .ecc_caps = &denali_socfpga_ecc_caps, }; /* * Older versions of the kernel driver require the partition nodes * to be direct subnodes of the controller node. Starting with Kernel * v5.2 (d8e8fd0ebf8b ("mtd: rawnand: denali: decouple controller and * NAND chips")) the device node for the Denali controller is seen as a * NAND controller node which has subnodes for each chip attached to that * controller. The chip subnodes then hold the partitions. The barebox * Denali driver also supports chip subnodes like the newer Kernel * driver. To find the container node for the partitions we first try * to find the chip subnodes in the Kernel device tree. Only if we * can't find these we try the controller device node and put the * partitions there. * Note that we take the existence of the chip subnodes in the kernel * device tree as a sign that we put the partitions there. When they * don't exist we use the controller node. This means you have to make * sure the chip subnodes exist when you start a Kernel that requires * these. Beginning with Kernel v5.5 (f34a5072c465 ("mtd: rawnand: denali: * remove the old unified controller/chip DT support")) the chip subnodes * are mandatory for the Kernel. */ static int denali_partition_fixup(struct mtd_info *mtd, struct device_node *root) { struct nand_chip *chip = mtd_to_nand(mtd); struct denali_controller *denali = container_of(chip->controller, struct denali_controller, controller); struct device_node *np, *mtdnp = mtd_get_of_node(mtd); char *name; name = of_get_reproducible_name(mtdnp); np = of_find_node_by_reproducible_name(root, name); free(name); if (np) { dev_info(denali->dev, "Fixing up chip node %s\n", np->full_name); } else { name = of_get_reproducible_name(mtdnp->parent); np = of_find_node_by_reproducible_name(root, name); free(name); if (np) dev_info(denali->dev, "Fixing up controller node %s\n", np->full_name); } if (!np) return -EINVAL; return of_fixup_partitions(np, &mtd->cdev); } static int denali_dt_chip_init(struct denali_controller *denali, struct device_node *chip_np) { struct denali_chip *dchip; u32 bank; int nsels, i, ret; struct mtd_info *mtd; nsels = of_property_count_elems_of_size(chip_np, "reg", sizeof(u32)); if (nsels < 0) return nsels; dchip = xzalloc(sizeof(*dchip) + sizeof(struct denali_chip_sel) *nsels); dchip->nsels = nsels; mtd = nand_to_mtd(&dchip->chip); mtd->of_fixup = denali_partition_fixup; for (i = 0; i < nsels; i++) { ret = of_property_read_u32_index(chip_np, "reg", i, &bank); if (ret) return ret; dchip->sels[i].bank = bank; nand_set_flash_node(&dchip->chip, chip_np); } return denali_chip_init(denali, dchip); } static int denali_dt_probe(struct device_d *ofdev) { struct resource *iores; struct denali_dt *dt; struct denali_controller *denali; struct denali_dt_data *data; struct device_node *np; int ret; if (!IS_ENABLED(CONFIG_OFDEVICE)) return 1; ret = dev_get_drvdata(ofdev, (const void **)&data); if (ret) return ret; dt = kzalloc(sizeof(*dt), GFP_KERNEL); if (!dt) return -ENOMEM; denali = &dt->denali; denali->dev = ofdev; iores = dev_request_mem_resource(ofdev, 0); if (IS_ERR(iores)) return PTR_ERR(iores); denali->host = IOMEM(iores->start); iores = dev_request_mem_resource(ofdev, 1); if (IS_ERR(iores)) return PTR_ERR(iores); denali->reg = IOMEM(iores->start); dt->clk = clk_get(ofdev, "nand"); if (IS_ERR(dt->clk)) return PTR_ERR(dt->clk); dt->clk_x = clk_get(ofdev, "nand_x"); if (IS_ERR(dt->clk_x)) return PTR_ERR(dt->clk_x); dt->clk_ecc = clk_get(ofdev, "ecc"); if (IS_ERR(dt->clk_ecc)) return PTR_ERR(dt->clk_ecc); clk_enable(dt->clk); clk_enable(dt->clk_x); clk_enable(dt->clk_ecc); denali->clk_rate = clk_get_rate(dt->clk); denali->clk_x_rate = clk_get_rate(dt->clk_x); denali->revision = data->revision; denali->caps = data->caps; denali->oob_skip_bytes = data->oob_skip_bytes; denali->ecc_caps = data->ecc_caps; ret = denali_init(denali); if (ret) goto out_disable_clk; for_each_child_of_node(ofdev->device_node, np) { ret = denali_dt_chip_init(denali, np); if (ret) goto out_disable_clk; } return 0; out_disable_clk: clk_disable(dt->clk); return ret; } static __maybe_unused struct of_device_id denali_nand_compatible[] = { { .compatible = "altr,socfpga-denali-nand", .data = &denali_socfpga_data, }, { /* sentinel */ } }; static struct driver_d denali_dt_driver = { .name = "denali-nand-dt", .probe = denali_dt_probe, .of_compatible = DRV_OF_COMPAT(denali_nand_compatible) }; device_platform_driver(denali_dt_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jamie Iles"); MODULE_DESCRIPTION("DT driver for Denali NAND controller");