uboot/arch/arm/mach-exynos/dmc_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Mem setup common file for different types of DDR present on Exynos boards.
   4 *
   5 * Copyright (C) 2012 Samsung Electronics
   6 */
   7
   8#include <common.h>
   9#include <asm/arch/spl.h>
  10
  11#include "clock_init.h"
  12#include "common_setup.h"
  13#include "exynos5_setup.h"
  14
  15#define ZQ_INIT_TIMEOUT 10000
  16
  17int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16,
  18                        uint32_t *phy1_con16, uint32_t *phy0_con17,
  19                        uint32_t *phy1_con17)
  20{
  21        unsigned long val = 0;
  22        int i;
  23
  24        /*
  25         * ZQ Calibration:
  26         * Select Driver Strength,
  27         * long calibration for manual calibration
  28         */
  29        val = PHY_CON16_RESET_VAL;
  30        val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT;
  31        val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT;
  32        val |= ZQ_CLK_DIV_EN;
  33        writel(val, phy0_con16);
  34        writel(val, phy1_con16);
  35
  36        /* Disable termination */
  37        if (mem->zq_mode_noterm)
  38                val |= PHY_CON16_ZQ_MODE_NOTERM_MASK;
  39        writel(val, phy0_con16);
  40        writel(val, phy1_con16);
  41
  42        /* ZQ_MANUAL_START: Enable */
  43        val |= ZQ_MANUAL_STR;
  44        writel(val, phy0_con16);
  45        writel(val, phy1_con16);
  46
  47        /* ZQ_MANUAL_START: Disable */
  48        val &= ~ZQ_MANUAL_STR;
  49
  50        /*
  51         * Since we are manaully calibrating the ZQ values,
  52         * we are looping for the ZQ_init to complete.
  53         */
  54        i = ZQ_INIT_TIMEOUT;
  55        while ((readl(phy0_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
  56                sdelay(100);
  57                i--;
  58        }
  59        if (!i)
  60                return -1;
  61        writel(val, phy0_con16);
  62
  63        i = ZQ_INIT_TIMEOUT;
  64        while ((readl(phy1_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
  65                sdelay(100);
  66                i--;
  67        }
  68        if (!i)
  69                return -1;
  70        writel(val, phy1_con16);
  71
  72        return 0;
  73}
  74
  75void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode mode)
  76{
  77        unsigned long val;
  78
  79        if (mode == DDR_MODE_DDR3) {
  80                val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE;
  81                writel(val, phycontrol0);
  82        }
  83
  84        /* Update DLL Information: Force DLL Resyncronization */
  85        val = readl(phycontrol0);
  86        val |= FP_RSYNC;
  87        writel(val, phycontrol0);
  88
  89        /* Reset Force DLL Resyncronization */
  90        val = readl(phycontrol0);
  91        val &= ~FP_RSYNC;
  92        writel(val, phycontrol0);
  93}
  94
  95void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd)
  96{
  97        int channel, chip;
  98
  99        for (channel = 0; channel < mem->dmc_channels; channel++) {
 100                unsigned long mask;
 101
 102                mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
 103                for (chip = 0; chip < mem->chips_to_configure; chip++) {
 104                        int i;
 105
 106                        mask |= chip << DIRECT_CMD_CHIP_SHIFT;
 107
 108                        /* Sending NOP command */
 109                        writel(DIRECT_CMD_NOP | mask, directcmd);
 110
 111                        /*
 112                         * TODO(alim.akhtar@samsung.com): Do we need these
 113                         * delays? This one and the next were not there for
 114                         * DDR3.
 115                         */
 116                        sdelay(0x10000);
 117
 118                        /* Sending EMRS/MRS commands */
 119                        for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
 120                                writel(mem->direct_cmd_msr[i] | mask,
 121                                       directcmd);
 122                                sdelay(0x10000);
 123                        }
 124
 125                        if (mem->send_zq_init) {
 126                                /* Sending ZQINIT command */
 127                                writel(DIRECT_CMD_ZQINIT | mask,
 128                                       directcmd);
 129
 130                                sdelay(10000);
 131                        }
 132                }
 133        }
 134}
 135
 136void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd)
 137{
 138        int channel, chip;
 139
 140        for (channel = 0; channel < mem->dmc_channels; channel++) {
 141                unsigned long mask;
 142
 143                mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
 144                for (chip = 0; chip < mem->chips_per_channel; chip++) {
 145                        mask |= chip << DIRECT_CMD_CHIP_SHIFT;
 146
 147                        /* PALL (all banks precharge) CMD */
 148                        writel(DIRECT_CMD_PALL | mask, directcmd);
 149                        sdelay(0x10000);
 150                }
 151        }
 152}
 153
 154void mem_ctrl_init(int reset)
 155{
 156        struct spl_machine_param *param = spl_get_machine_params();
 157        struct mem_timings *mem;
 158        int ret;
 159
 160        mem = clock_get_mem_timings();
 161
 162        /* If there are any other memory variant, add their init call below */
 163        if (param->mem_type == DDR_MODE_DDR3) {
 164                ret = ddr3_mem_ctrl_init(mem, reset);
 165                if (ret) {
 166                        /* will hang if failed to init memory control */
 167                        while (1)
 168                                ;
 169                }
 170        } else {
 171                /* will hang if unknow memory type  */
 172                while (1)
 173                        ;
 174        }
 175}
 176