uboot/drivers/mtd/nand/nand.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2005
   3 * 2N Telekomunikace, a.s. <www.2n.cz>
   4 * Ladislav Michl <michl@2n.cz>
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0
   7 */
   8
   9#include <common.h>
  10#include <nand.h>
  11#include <errno.h>
  12#include <linux/mtd/concat.h>
  13
  14#ifndef CONFIG_SYS_NAND_BASE_LIST
  15#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
  16#endif
  17
  18DECLARE_GLOBAL_DATA_PTR;
  19
  20int nand_curr_device = -1;
  21
  22static struct mtd_info *nand_info[CONFIG_SYS_MAX_NAND_DEVICE];
  23
  24#ifndef CONFIG_SYS_NAND_SELF_INIT
  25static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
  26static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
  27#endif
  28
  29static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8];
  30
  31static unsigned long total_nand_size; /* in kiB */
  32
  33struct mtd_info *get_nand_dev_by_index(int dev)
  34{
  35        if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev] ||
  36            !nand_info[dev]->name)
  37                return NULL;
  38
  39        return nand_info[dev];
  40}
  41
  42int nand_mtd_to_devnum(struct mtd_info *mtd)
  43{
  44        int i;
  45
  46        for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
  47                if (mtd && get_nand_dev_by_index(i) == mtd)
  48                        return i;
  49        }
  50
  51        return -ENODEV;
  52}
  53
  54/* Register an initialized NAND mtd device with the U-Boot NAND command. */
  55int nand_register(int devnum, struct mtd_info *mtd)
  56{
  57        if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE)
  58                return -EINVAL;
  59
  60        nand_info[devnum] = mtd;
  61
  62        sprintf(dev_name[devnum], "nand%d", devnum);
  63        mtd->name = dev_name[devnum];
  64
  65#ifdef CONFIG_MTD_DEVICE
  66        /*
  67         * Add MTD device so that we can reference it later
  68         * via the mtdcore infrastructure (e.g. ubi).
  69         */
  70        add_mtd_device(mtd);
  71#endif
  72
  73        total_nand_size += mtd->size / 1024;
  74
  75        if (nand_curr_device == -1)
  76                nand_curr_device = devnum;
  77
  78        return 0;
  79}
  80
  81#ifndef CONFIG_SYS_NAND_SELF_INIT
  82static void nand_init_chip(int i)
  83{
  84        struct nand_chip *nand = &nand_chip[i];
  85        struct mtd_info *mtd = nand_to_mtd(nand);
  86        ulong base_addr = base_address[i];
  87        int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;
  88
  89        if (maxchips < 1)
  90                maxchips = 1;
  91
  92        nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;
  93
  94        if (board_nand_init(nand))
  95                return;
  96
  97        if (nand_scan(mtd, maxchips))
  98                return;
  99
 100        nand_register(i, mtd);
 101}
 102#endif
 103
 104#ifdef CONFIG_MTD_CONCAT
 105static void create_mtd_concat(void)
 106{
 107        struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE];
 108        int nand_devices_found = 0;
 109        int i;
 110
 111        for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
 112                struct mtd_info *mtd = get_nand_dev_by_index(i);
 113                if (mtd != NULL) {
 114                        nand_info_list[nand_devices_found] = mtd;
 115                        nand_devices_found++;
 116                }
 117        }
 118        if (nand_devices_found > 1) {
 119                struct mtd_info *mtd;
 120                char c_mtd_name[16];
 121
 122                /*
 123                 * We detected multiple devices. Concatenate them together.
 124                 */
 125                sprintf(c_mtd_name, "nand%d", nand_devices_found);
 126                mtd = mtd_concat_create(nand_info_list, nand_devices_found,
 127                                        c_mtd_name);
 128
 129                if (mtd == NULL)
 130                        return;
 131
 132                nand_register(nand_devices_found, mtd);
 133        }
 134
 135        return;
 136}
 137#else
 138static void create_mtd_concat(void)
 139{
 140}
 141#endif
 142
 143unsigned long nand_size(void)
 144{
 145        return total_nand_size;
 146}
 147
 148void nand_init(void)
 149{
 150        static int initialized;
 151
 152        /*
 153         * Avoid initializing NAND Flash multiple times,
 154         * otherwise it will calculate a wrong total size.
 155         */
 156        if (initialized)
 157                return;
 158        initialized = 1;
 159
 160#ifdef CONFIG_SYS_NAND_SELF_INIT
 161        board_nand_init();
 162#else
 163        int i;
 164
 165        for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
 166                nand_init_chip(i);
 167#endif
 168
 169#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
 170        /*
 171         * Select the chip in the board/cpu specific driver
 172         */
 173        board_nand_select_device(mtd_to_nand(get_nand_dev_by_index(nand_curr_device)),
 174                                 nand_curr_device);
 175#endif
 176
 177        create_mtd_concat();
 178}
 179