cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

denali_dt.c (6376B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * NAND Flash Controller Device Driver for DT
      4 *
      5 * Copyright © 2011, Picochip.
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/delay.h>
     10#include <linux/err.h>
     11#include <linux/io.h>
     12#include <linux/ioport.h>
     13#include <linux/kernel.h>
     14#include <linux/module.h>
     15#include <linux/of.h>
     16#include <linux/of_device.h>
     17#include <linux/platform_device.h>
     18#include <linux/reset.h>
     19
     20#include "denali.h"
     21
     22struct denali_dt {
     23	struct denali_controller controller;
     24	struct clk *clk;	/* core clock */
     25	struct clk *clk_x;	/* bus interface clock */
     26	struct clk *clk_ecc;	/* ECC circuit clock */
     27	struct reset_control *rst;	/* core reset */
     28	struct reset_control *rst_reg;	/* register reset */
     29};
     30
     31struct denali_dt_data {
     32	unsigned int revision;
     33	unsigned int caps;
     34	unsigned int oob_skip_bytes;
     35	const struct nand_ecc_caps *ecc_caps;
     36};
     37
     38NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
     39		     512, 8, 15);
     40static const struct denali_dt_data denali_socfpga_data = {
     41	.caps = DENALI_CAP_HW_ECC_FIXUP,
     42	.oob_skip_bytes = 2,
     43	.ecc_caps = &denali_socfpga_ecc_caps,
     44};
     45
     46NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
     47		     1024, 8, 16, 24);
     48static const struct denali_dt_data denali_uniphier_v5a_data = {
     49	.caps = DENALI_CAP_HW_ECC_FIXUP |
     50		DENALI_CAP_DMA_64BIT,
     51	.oob_skip_bytes = 8,
     52	.ecc_caps = &denali_uniphier_v5a_ecc_caps,
     53};
     54
     55NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
     56		     1024, 8, 16);
     57static const struct denali_dt_data denali_uniphier_v5b_data = {
     58	.revision = 0x0501,
     59	.caps = DENALI_CAP_HW_ECC_FIXUP |
     60		DENALI_CAP_DMA_64BIT,
     61	.oob_skip_bytes = 8,
     62	.ecc_caps = &denali_uniphier_v5b_ecc_caps,
     63};
     64
     65static const struct of_device_id denali_nand_dt_ids[] = {
     66	{
     67		.compatible = "altr,socfpga-denali-nand",
     68		.data = &denali_socfpga_data,
     69	},
     70	{
     71		.compatible = "socionext,uniphier-denali-nand-v5a",
     72		.data = &denali_uniphier_v5a_data,
     73	},
     74	{
     75		.compatible = "socionext,uniphier-denali-nand-v5b",
     76		.data = &denali_uniphier_v5b_data,
     77	},
     78	{ /* sentinel */ }
     79};
     80MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
     81
     82static int denali_dt_chip_init(struct denali_controller *denali,
     83			       struct device_node *chip_np)
     84{
     85	struct denali_chip *dchip;
     86	u32 bank;
     87	int nsels, i, ret;
     88
     89	nsels = of_property_count_u32_elems(chip_np, "reg");
     90	if (nsels < 0)
     91		return nsels;
     92
     93	dchip = devm_kzalloc(denali->dev, struct_size(dchip, sels, nsels),
     94			     GFP_KERNEL);
     95	if (!dchip)
     96		return -ENOMEM;
     97
     98	dchip->nsels = nsels;
     99
    100	for (i = 0; i < nsels; i++) {
    101		ret = of_property_read_u32_index(chip_np, "reg", i, &bank);
    102		if (ret)
    103			return ret;
    104
    105		dchip->sels[i].bank = bank;
    106
    107		nand_set_flash_node(&dchip->chip, chip_np);
    108	}
    109
    110	return denali_chip_init(denali, dchip);
    111}
    112
    113static int denali_dt_probe(struct platform_device *pdev)
    114{
    115	struct device *dev = &pdev->dev;
    116	struct denali_dt *dt;
    117	const struct denali_dt_data *data;
    118	struct denali_controller *denali;
    119	struct device_node *np;
    120	int ret;
    121
    122	dt = devm_kzalloc(dev, sizeof(*dt), GFP_KERNEL);
    123	if (!dt)
    124		return -ENOMEM;
    125	denali = &dt->controller;
    126
    127	data = of_device_get_match_data(dev);
    128	if (WARN_ON(!data))
    129		return -EINVAL;
    130
    131	denali->revision = data->revision;
    132	denali->caps = data->caps;
    133	denali->oob_skip_bytes = data->oob_skip_bytes;
    134	denali->ecc_caps = data->ecc_caps;
    135
    136	denali->dev = dev;
    137	denali->irq = platform_get_irq(pdev, 0);
    138	if (denali->irq < 0)
    139		return denali->irq;
    140
    141	denali->reg = devm_platform_ioremap_resource_byname(pdev, "denali_reg");
    142	if (IS_ERR(denali->reg))
    143		return PTR_ERR(denali->reg);
    144
    145	denali->host = devm_platform_ioremap_resource_byname(pdev, "nand_data");
    146	if (IS_ERR(denali->host))
    147		return PTR_ERR(denali->host);
    148
    149	dt->clk = devm_clk_get(dev, "nand");
    150	if (IS_ERR(dt->clk))
    151		return PTR_ERR(dt->clk);
    152
    153	dt->clk_x = devm_clk_get(dev, "nand_x");
    154	if (IS_ERR(dt->clk_x))
    155		return PTR_ERR(dt->clk_x);
    156
    157	dt->clk_ecc = devm_clk_get(dev, "ecc");
    158	if (IS_ERR(dt->clk_ecc))
    159		return PTR_ERR(dt->clk_ecc);
    160
    161	dt->rst = devm_reset_control_get_optional_shared(dev, "nand");
    162	if (IS_ERR(dt->rst))
    163		return PTR_ERR(dt->rst);
    164
    165	dt->rst_reg = devm_reset_control_get_optional_shared(dev, "reg");
    166	if (IS_ERR(dt->rst_reg))
    167		return PTR_ERR(dt->rst_reg);
    168
    169	ret = clk_prepare_enable(dt->clk);
    170	if (ret)
    171		return ret;
    172
    173	ret = clk_prepare_enable(dt->clk_x);
    174	if (ret)
    175		goto out_disable_clk;
    176
    177	ret = clk_prepare_enable(dt->clk_ecc);
    178	if (ret)
    179		goto out_disable_clk_x;
    180
    181	denali->clk_rate = clk_get_rate(dt->clk);
    182	denali->clk_x_rate = clk_get_rate(dt->clk_x);
    183
    184	/*
    185	 * Deassert the register reset, and the core reset in this order.
    186	 * Deasserting the core reset while the register reset is asserted
    187	 * will cause unpredictable behavior in the controller.
    188	 */
    189	ret = reset_control_deassert(dt->rst_reg);
    190	if (ret)
    191		goto out_disable_clk_ecc;
    192
    193	ret = reset_control_deassert(dt->rst);
    194	if (ret)
    195		goto out_assert_rst_reg;
    196
    197	/*
    198	 * When the reset is deasserted, the initialization sequence is kicked
    199	 * (bootstrap process). The driver must wait until it finished.
    200	 * Otherwise, it will result in unpredictable behavior.
    201	 */
    202	usleep_range(200, 1000);
    203
    204	ret = denali_init(denali);
    205	if (ret)
    206		goto out_assert_rst;
    207
    208	for_each_child_of_node(dev->of_node, np) {
    209		ret = denali_dt_chip_init(denali, np);
    210		if (ret) {
    211			of_node_put(np);
    212			goto out_remove_denali;
    213		}
    214	}
    215
    216	platform_set_drvdata(pdev, dt);
    217
    218	return 0;
    219
    220out_remove_denali:
    221	denali_remove(denali);
    222out_assert_rst:
    223	reset_control_assert(dt->rst);
    224out_assert_rst_reg:
    225	reset_control_assert(dt->rst_reg);
    226out_disable_clk_ecc:
    227	clk_disable_unprepare(dt->clk_ecc);
    228out_disable_clk_x:
    229	clk_disable_unprepare(dt->clk_x);
    230out_disable_clk:
    231	clk_disable_unprepare(dt->clk);
    232
    233	return ret;
    234}
    235
    236static int denali_dt_remove(struct platform_device *pdev)
    237{
    238	struct denali_dt *dt = platform_get_drvdata(pdev);
    239
    240	denali_remove(&dt->controller);
    241	reset_control_assert(dt->rst);
    242	reset_control_assert(dt->rst_reg);
    243	clk_disable_unprepare(dt->clk_ecc);
    244	clk_disable_unprepare(dt->clk_x);
    245	clk_disable_unprepare(dt->clk);
    246
    247	return 0;
    248}
    249
    250static struct platform_driver denali_dt_driver = {
    251	.probe		= denali_dt_probe,
    252	.remove		= denali_dt_remove,
    253	.driver		= {
    254		.name	= "denali-nand-dt",
    255		.of_match_table	= denali_nand_dt_ids,
    256	},
    257};
    258module_platform_driver(denali_dt_driver);
    259
    260MODULE_LICENSE("GPL v2");
    261MODULE_AUTHOR("Jamie Iles");
    262MODULE_DESCRIPTION("DT driver for Denali NAND controller");