uboot/arch/arm/mach-uniphier/dram_init.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2012-2015 Panasonic Corporation
   4 * Copyright (C) 2015-2017 Socionext Inc.
   5 *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
   6 */
   7
   8#include <common.h>
   9#include <linux/errno.h>
  10#include <linux/io.h>
  11#include <linux/kernel.h>
  12#include <linux/printk.h>
  13#include <linux/sizes.h>
  14#include <asm/global_data.h>
  15
  16#include "init.h"
  17#include "sg-regs.h"
  18#include "soc-info.h"
  19
  20DECLARE_GLOBAL_DATA_PTR;
  21
  22struct uniphier_dram_map {
  23        unsigned long base;
  24        unsigned long size;
  25};
  26
  27static int uniphier_memconf_decode(struct uniphier_dram_map *dram_map,
  28                                   unsigned long sparse_ch1_base, bool have_ch2)
  29{
  30        unsigned long size;
  31        u32 val;
  32
  33        val = readl(sg_base + SG_MEMCONF);
  34
  35        /* set up ch0 */
  36        dram_map[0].base = 0x80000000;
  37
  38        switch (val & SG_MEMCONF_CH0_SZ_MASK) {
  39        case SG_MEMCONF_CH0_SZ_64M:
  40                size = SZ_64M;
  41                break;
  42        case SG_MEMCONF_CH0_SZ_128M:
  43                size = SZ_128M;
  44                break;
  45        case SG_MEMCONF_CH0_SZ_256M:
  46                size = SZ_256M;
  47                break;
  48        case SG_MEMCONF_CH0_SZ_512M:
  49                size = SZ_512M;
  50                break;
  51        case SG_MEMCONF_CH0_SZ_1G:
  52                size = SZ_1G;
  53                break;
  54        default:
  55                pr_err("error: invalid value is set to MEMCONF ch0 size\n");
  56                return -EINVAL;
  57        }
  58
  59        if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2)
  60                size *= 2;
  61
  62        dram_map[0].size = size;
  63
  64        /* set up ch1 */
  65        dram_map[1].base = dram_map[0].base + size;
  66
  67        if (val & SG_MEMCONF_SPARSEMEM) {
  68                if (dram_map[1].base > sparse_ch1_base) {
  69                        pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n");
  70                        pr_warn("Only ch0 is available\n");
  71                        dram_map[1].base = 0;
  72                        return 0;
  73                }
  74
  75                dram_map[1].base = sparse_ch1_base;
  76        }
  77
  78        switch (val & SG_MEMCONF_CH1_SZ_MASK) {
  79        case SG_MEMCONF_CH1_SZ_64M:
  80                size = SZ_64M;
  81                break;
  82        case SG_MEMCONF_CH1_SZ_128M:
  83                size = SZ_128M;
  84                break;
  85        case SG_MEMCONF_CH1_SZ_256M:
  86                size = SZ_256M;
  87                break;
  88        case SG_MEMCONF_CH1_SZ_512M:
  89                size = SZ_512M;
  90                break;
  91        case SG_MEMCONF_CH1_SZ_1G:
  92                size = SZ_1G;
  93                break;
  94        default:
  95                pr_err("error: invalid value is set to MEMCONF ch1 size\n");
  96                return -EINVAL;
  97        }
  98
  99        if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2)
 100                size *= 2;
 101
 102        dram_map[1].size = size;
 103
 104        if (!have_ch2 || val & SG_MEMCONF_CH2_DISABLE)
 105                return 0;
 106
 107        /* set up ch2 */
 108        dram_map[2].base = dram_map[1].base + size;
 109
 110        switch (val & SG_MEMCONF_CH2_SZ_MASK) {
 111        case SG_MEMCONF_CH2_SZ_64M:
 112                size = SZ_64M;
 113                break;
 114        case SG_MEMCONF_CH2_SZ_128M:
 115                size = SZ_128M;
 116                break;
 117        case SG_MEMCONF_CH2_SZ_256M:
 118                size = SZ_256M;
 119                break;
 120        case SG_MEMCONF_CH2_SZ_512M:
 121                size = SZ_512M;
 122                break;
 123        case SG_MEMCONF_CH2_SZ_1G:
 124                size = SZ_1G;
 125                break;
 126        default:
 127                pr_err("error: invalid value is set to MEMCONF ch2 size\n");
 128                return -EINVAL;
 129        }
 130
 131        if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2)
 132                size *= 2;
 133
 134        dram_map[2].size = size;
 135
 136        return 0;
 137}
 138
 139static int uniphier_ld4_dram_map_get(struct uniphier_dram_map dram_map[])
 140{
 141        return uniphier_memconf_decode(dram_map, 0xc0000000, false);
 142}
 143
 144static int uniphier_pro4_dram_map_get(struct uniphier_dram_map dram_map[])
 145{
 146        return uniphier_memconf_decode(dram_map, 0xa0000000, false);
 147}
 148
 149static int uniphier_pxs2_dram_map_get(struct uniphier_dram_map dram_map[])
 150{
 151        return uniphier_memconf_decode(dram_map, 0xc0000000, true);
 152}
 153
 154struct uniphier_dram_init_data {
 155        unsigned int soc_id;
 156        int (*dram_map_get)(struct uniphier_dram_map dram_map[]);
 157};
 158
 159static const struct uniphier_dram_init_data uniphier_dram_init_data[] = {
 160        {
 161                .soc_id = UNIPHIER_LD4_ID,
 162                .dram_map_get = uniphier_ld4_dram_map_get,
 163        },
 164        {
 165                .soc_id = UNIPHIER_PRO4_ID,
 166                .dram_map_get = uniphier_pro4_dram_map_get,
 167        },
 168        {
 169                .soc_id = UNIPHIER_SLD8_ID,
 170                .dram_map_get = uniphier_ld4_dram_map_get,
 171        },
 172        {
 173                .soc_id = UNIPHIER_PRO5_ID,
 174                .dram_map_get = uniphier_ld4_dram_map_get,
 175        },
 176        {
 177                .soc_id = UNIPHIER_PXS2_ID,
 178                .dram_map_get = uniphier_pxs2_dram_map_get,
 179        },
 180        {
 181                .soc_id = UNIPHIER_LD6B_ID,
 182                .dram_map_get = uniphier_pxs2_dram_map_get,
 183        },
 184        {
 185                .soc_id = UNIPHIER_LD11_ID,
 186                .dram_map_get = uniphier_ld4_dram_map_get,
 187        },
 188        {
 189                .soc_id = UNIPHIER_LD20_ID,
 190                .dram_map_get = uniphier_pxs2_dram_map_get,
 191        },
 192        {
 193                .soc_id = UNIPHIER_PXS3_ID,
 194                .dram_map_get = uniphier_pxs2_dram_map_get,
 195        },
 196};
 197UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_dram_init_data,
 198                             uniphier_dram_init_data)
 199
 200static int uniphier_dram_map_get(struct uniphier_dram_map *dram_map)
 201{
 202        const struct uniphier_dram_init_data *data;
 203
 204        data = uniphier_get_dram_init_data();
 205        if (!data) {
 206                pr_err("unsupported SoC\n");
 207                return -ENOTSUPP;
 208        }
 209
 210        return data->dram_map_get(dram_map);
 211}
 212
 213int dram_init(void)
 214{
 215        struct uniphier_dram_map dram_map[3] = {};
 216        bool valid_bank_found = false;
 217        unsigned long prev_top;
 218        int ret, i;
 219
 220        gd->ram_size = 0;
 221
 222        ret = uniphier_dram_map_get(dram_map);
 223        if (ret)
 224                return ret;
 225
 226        for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
 227                unsigned long max_size;
 228
 229                if (!dram_map[i].size)
 230                        continue;
 231
 232                /*
 233                 * U-Boot relocates itself to the tail of the memory region,
 234                 * but it does not expect sparse memory.  We use the first
 235                 * contiguous chunk here.
 236                 */
 237                if (valid_bank_found && prev_top < dram_map[i].base)
 238                        break;
 239
 240                /*
 241                 * Do not use memory that exceeds 32bit address range.  U-Boot
 242                 * relocates itself to the end of the effectively available RAM.
 243                 * This could be a problem for DMA engines that do not support
 244                 * 64bit address (SDMA of SDHCI, UniPhier AV-ether, etc.)
 245                 */
 246                if (dram_map[i].base >= 1ULL << 32)
 247                        break;
 248
 249                max_size = (1ULL << 32) - dram_map[i].base;
 250
 251                gd->ram_size = min(dram_map[i].size, max_size);
 252
 253                if (!valid_bank_found)
 254                        gd->ram_base = dram_map[i].base;
 255
 256                prev_top = dram_map[i].base + dram_map[i].size;
 257                valid_bank_found = true;
 258        }
 259
 260        /*
 261         * LD20 uses the last 64 byte for each channel for dynamic
 262         * DDR PHY training
 263         */
 264        if (uniphier_get_soc_id() == UNIPHIER_LD20_ID)
 265                gd->ram_size -= 64;
 266
 267        return 0;
 268}
 269
 270int dram_init_banksize(void)
 271{
 272        struct uniphier_dram_map dram_map[3] = {};
 273        unsigned long base, top;
 274        bool valid_bank_found = false;
 275        int ret, i;
 276
 277        ret = uniphier_dram_map_get(dram_map);
 278        if (ret)
 279                return ret;
 280
 281        for (i = 0; i < ARRAY_SIZE(dram_map); i++) {
 282                if (i < ARRAY_SIZE(gd->bd->bi_dram)) {
 283                        gd->bd->bi_dram[i].start = dram_map[i].base;
 284                        gd->bd->bi_dram[i].size = dram_map[i].size;
 285                }
 286
 287                if (!dram_map[i].size)
 288                        continue;
 289
 290                if (!valid_bank_found)
 291                        base = dram_map[i].base;
 292                top = dram_map[i].base + dram_map[i].size;
 293                valid_bank_found = true;
 294        }
 295
 296        if (!valid_bank_found)
 297                return -EINVAL;
 298
 299        /* map all the DRAM regions */
 300        uniphier_mem_map_init(base, top - base);
 301
 302        return 0;
 303}
 304