| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 | // SPDX-License-Identifier: GPL-2.0+/* * Copyright (C) 2017 Socionext Inc. *   Author: Masahiro Yamada <yamada.masahiro@socionext.com> */#include <clk.h>#include <dm.h>#include <linux/io.h>#include <linux/ioport.h>#include <linux/printk.h>#include "denali.h"struct denali_dt_data {	unsigned int revision;	unsigned int caps;	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,	.ecc_caps = &denali_socfpga_ecc_caps,};NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,		     1024, 8, 16, 24);static const struct denali_dt_data denali_uniphier_v5a_data = {	.caps = DENALI_CAP_HW_ECC_FIXUP |		DENALI_CAP_DMA_64BIT,	.ecc_caps = &denali_uniphier_v5a_ecc_caps,};NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,		     1024, 8, 16);static const struct denali_dt_data denali_uniphier_v5b_data = {	.revision = 0x0501,	.caps = DENALI_CAP_HW_ECC_FIXUP |		DENALI_CAP_DMA_64BIT,	.ecc_caps = &denali_uniphier_v5b_ecc_caps,};static const struct udevice_id denali_nand_dt_ids[] = {	{		.compatible = "altr,socfpga-denali-nand",		.data = (unsigned long)&denali_socfpga_data,	},	{		.compatible = "socionext,uniphier-denali-nand-v5a",		.data = (unsigned long)&denali_uniphier_v5a_data,	},	{		.compatible = "socionext,uniphier-denali-nand-v5b",		.data = (unsigned long)&denali_uniphier_v5b_data,	},	{ /* sentinel */ }};static int denali_dt_probe(struct udevice *dev){	struct denali_nand_info *denali = dev_get_priv(dev);	const struct denali_dt_data *data;	struct clk clk;	struct resource res;	int ret;	data = (void *)dev_get_driver_data(dev);	if (data) {		denali->revision = data->revision;		denali->caps = data->caps;		denali->ecc_caps = data->ecc_caps;	}	denali->dev = dev;	ret = dev_read_resource_byname(dev, "denali_reg", &res);	if (ret)		return ret;	denali->reg = devm_ioremap(dev, res.start, resource_size(&res));	ret = dev_read_resource_byname(dev, "nand_data", &res);	if (ret)		return ret;	denali->host = devm_ioremap(dev, res.start, resource_size(&res));	ret = clk_get_by_index(dev, 0, &clk);	if (ret)		return ret;	ret = clk_enable(&clk);	if (ret)		return ret;	denali->clk_x_rate = clk_get_rate(&clk);	return denali_init(denali);}U_BOOT_DRIVER(denali_nand_dt) = {	.name = "denali-nand-dt",	.id = UCLASS_MISC,	.of_match = denali_nand_dt_ids,	.probe = denali_dt_probe,	.priv_auto_alloc_size = sizeof(struct denali_nand_info),};void board_nand_init(void){	struct udevice *dev;	int ret;	ret = uclass_get_device_by_driver(UCLASS_MISC,					  DM_GET_DRIVER(denali_nand_dt),					  &dev);	if (ret && ret != -ENODEV)		pr_err("Failed to initialize Denali NAND controller. (error %d)\n",		       ret);}
 |