uboot/drivers/mtd/nand/raw/denali_dt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017 Socionext Inc.
   4 *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
   5 */
   6
   7#include <clk.h>
   8#include <dm.h>
   9#include <dm/device_compat.h>
  10#include <linux/bug.h>
  11#include <linux/delay.h>
  12#include <linux/io.h>
  13#include <linux/ioport.h>
  14#include <linux/printk.h>
  15#include <reset.h>
  16
  17#include "denali.h"
  18
  19struct denali_dt_data {
  20        unsigned int revision;
  21        unsigned int caps;
  22        unsigned int oob_skip_bytes;
  23        const struct nand_ecc_caps *ecc_caps;
  24};
  25
  26NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes,
  27                     512, 8, 15);
  28static const struct denali_dt_data denali_socfpga_data = {
  29        .caps = DENALI_CAP_HW_ECC_FIXUP,
  30        .oob_skip_bytes = 2,
  31        .ecc_caps = &denali_socfpga_ecc_caps,
  32};
  33
  34NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes,
  35                     1024, 8, 16, 24);
  36static const struct denali_dt_data denali_uniphier_v5a_data = {
  37        .caps = DENALI_CAP_HW_ECC_FIXUP |
  38                DENALI_CAP_DMA_64BIT,
  39        .oob_skip_bytes = 8,
  40        .ecc_caps = &denali_uniphier_v5a_ecc_caps,
  41};
  42
  43NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes,
  44                     1024, 8, 16);
  45static const struct denali_dt_data denali_uniphier_v5b_data = {
  46        .revision = 0x0501,
  47        .caps = DENALI_CAP_HW_ECC_FIXUP |
  48                DENALI_CAP_DMA_64BIT,
  49        .oob_skip_bytes = 8,
  50        .ecc_caps = &denali_uniphier_v5b_ecc_caps,
  51};
  52
  53static const struct udevice_id denali_nand_dt_ids[] = {
  54        {
  55                .compatible = "altr,socfpga-denali-nand",
  56                .data = (unsigned long)&denali_socfpga_data,
  57        },
  58        {
  59                .compatible = "socionext,uniphier-denali-nand-v5a",
  60                .data = (unsigned long)&denali_uniphier_v5a_data,
  61        },
  62        {
  63                .compatible = "socionext,uniphier-denali-nand-v5b",
  64                .data = (unsigned long)&denali_uniphier_v5b_data,
  65        },
  66        { /* sentinel */ }
  67};
  68
  69static int denali_dt_probe(struct udevice *dev)
  70{
  71        struct denali_nand_info *denali = dev_get_priv(dev);
  72        const struct denali_dt_data *data;
  73        struct clk clk, clk_x, clk_ecc;
  74        struct reset_ctl_bulk resets;
  75        struct resource res;
  76        int ret;
  77
  78        data = (void *)dev_get_driver_data(dev);
  79        if (WARN_ON(!data))
  80                return -EINVAL;
  81
  82        denali->revision = data->revision;
  83        denali->caps = data->caps;
  84        denali->oob_skip_bytes = data->oob_skip_bytes;
  85        denali->ecc_caps = data->ecc_caps;
  86
  87        denali->dev = dev;
  88
  89        ret = dev_read_resource_byname(dev, "denali_reg", &res);
  90        if (ret)
  91                return ret;
  92
  93        denali->reg = devm_ioremap(dev, res.start, resource_size(&res));
  94
  95        ret = dev_read_resource_byname(dev, "nand_data", &res);
  96        if (ret)
  97                return ret;
  98
  99        denali->host = devm_ioremap(dev, res.start, resource_size(&res));
 100
 101        ret = clk_get_by_name(dev, "nand", &clk);
 102        if (ret)
 103                ret = clk_get_by_index(dev, 0, &clk);
 104        if (ret)
 105                clk.dev = NULL;
 106
 107        ret = clk_get_by_name(dev, "nand_x", &clk_x);
 108        if (ret)
 109                clk_x.dev = NULL;
 110
 111        ret = clk_get_by_name(dev, "ecc", &clk_ecc);
 112        if (ret)
 113                clk_ecc.dev = NULL;
 114
 115        if (clk.dev) {
 116                ret = clk_enable(&clk);
 117                if (ret)
 118                        return ret;
 119        }
 120
 121        if (clk_x.dev) {
 122                ret = clk_enable(&clk_x);
 123                if (ret)
 124                        return ret;
 125        }
 126
 127        if (clk_ecc.dev) {
 128                ret = clk_enable(&clk_ecc);
 129                if (ret)
 130                        return ret;
 131        }
 132
 133        if (clk_x.dev) {
 134                denali->clk_rate = clk_get_rate(&clk);
 135                denali->clk_x_rate = clk_get_rate(&clk_x);
 136        } else {
 137                /*
 138                 * Hardcode the clock rates for the backward compatibility.
 139                 * This works for both SOCFPGA and UniPhier.
 140                 */
 141                dev_notice(dev,
 142                           "necessary clock is missing. default clock rates are used.\n");
 143                denali->clk_rate = 50000000;
 144                denali->clk_x_rate = 200000000;
 145        }
 146
 147        ret = reset_get_bulk(dev, &resets);
 148        if (ret) {
 149                dev_warn(dev, "Can't get reset: %d\n", ret);
 150        } else {
 151                reset_assert_bulk(&resets);
 152                udelay(2);
 153                reset_deassert_bulk(&resets);
 154
 155                /*
 156                 * When the reset is deasserted, the initialization sequence is
 157                 * kicked (bootstrap process). The driver must wait until it is
 158                 * finished. Otherwise, it will result in unpredictable behavior.
 159                 */
 160                ret = denali_wait_reset_complete(denali);
 161                if (ret) {
 162                        dev_err(denali->dev, "reset not completed.\n");
 163                        return ret;
 164                }
 165        }
 166
 167        return denali_init(denali);
 168}
 169
 170U_BOOT_DRIVER(denali_nand_dt) = {
 171        .name = "denali-nand-dt",
 172        .id = UCLASS_MTD,
 173        .of_match = denali_nand_dt_ids,
 174        .probe = denali_dt_probe,
 175        .priv_auto      = sizeof(struct denali_nand_info),
 176};
 177
 178void board_nand_init(void)
 179{
 180        struct udevice *dev;
 181        int ret;
 182
 183        ret = uclass_get_device_by_driver(UCLASS_MTD,
 184                                          DM_DRIVER_GET(denali_nand_dt),
 185                                          &dev);
 186        if (ret && ret != -ENODEV)
 187                pr_err("Failed to initialize Denali NAND controller. (error %d)\n",
 188                       ret);
 189}
 190