19bbd2132SDinh Nguyen /* 29bbd2132SDinh Nguyen * Copyright Altera Corporation (C) 2014-2015 39bbd2132SDinh Nguyen * 49bbd2132SDinh Nguyen * SPDX-License-Identifier: GPL-2.0+ 59bbd2132SDinh Nguyen */ 69bbd2132SDinh Nguyen #include <common.h> 799f453e9SMarek Vasut #include <errno.h> 89bbd2132SDinh Nguyen #include <div64.h> 99bbd2132SDinh Nguyen #include <watchdog.h> 109bbd2132SDinh Nguyen #include <asm/arch/fpga_manager.h> 119bbd2132SDinh Nguyen #include <asm/arch/sdram.h> 129bbd2132SDinh Nguyen #include <asm/arch/system_manager.h> 139bbd2132SDinh Nguyen #include <asm/io.h> 149bbd2132SDinh Nguyen 159bbd2132SDinh Nguyen DECLARE_GLOBAL_DATA_PTR; 169bbd2132SDinh Nguyen 1742f7ebb8SMarek Vasut struct sdram_prot_rule { 1842f7ebb8SMarek Vasut u64 sdram_start; /* SDRAM start address */ 1942f7ebb8SMarek Vasut u64 sdram_end; /* SDRAM end address */ 2042f7ebb8SMarek Vasut u32 rule; /* SDRAM protection rule number: 0-19 */ 2142f7ebb8SMarek Vasut int valid; /* Rule valid or not? 1 - valid, 0 not*/ 2242f7ebb8SMarek Vasut 2342f7ebb8SMarek Vasut u32 security; 2442f7ebb8SMarek Vasut u32 portmask; 2542f7ebb8SMarek Vasut u32 result; 2642f7ebb8SMarek Vasut u32 lo_prot_id; 2742f7ebb8SMarek Vasut u32 hi_prot_id; 2842f7ebb8SMarek Vasut }; 2942f7ebb8SMarek Vasut 309bbd2132SDinh Nguyen static struct socfpga_system_manager *sysmgr_regs = 319bbd2132SDinh Nguyen (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; 329bbd2132SDinh Nguyen static struct socfpga_sdr_ctrl *sdr_ctrl = 3317fdc916SMarek Vasut (struct socfpga_sdr_ctrl *)SDR_CTRLGRP_ADDRESS; 349bbd2132SDinh Nguyen 35f3671697SMarek Vasut /** 36f3671697SMarek Vasut * get_errata_rows() - Up the number of DRAM rows to cover entire address space 37764aa9a9SMarek Vasut * @cfg: SDRAM controller configuration data 38f3671697SMarek Vasut * 39f3671697SMarek Vasut * SDRAM Failure happens when accessing non-existent memory. Artificially 40f3671697SMarek Vasut * increase the number of rows so that the memory controller thinks it has 41f3671697SMarek Vasut * 4GB of RAM. This function returns such amount of rows. 42f3671697SMarek Vasut */ 435af91418SMarek Vasut static int get_errata_rows(const struct socfpga_sdram_config *cfg) 449bbd2132SDinh Nguyen { 45f3671697SMarek Vasut /* Define constant for 4G memory - used for SDRAM errata workaround */ 46f3671697SMarek Vasut #define MEMSIZE_4G (4ULL * 1024ULL * 1024ULL * 1024ULL) 47f3671697SMarek Vasut const unsigned long long memsize = MEMSIZE_4G; 48764aa9a9SMarek Vasut const unsigned int cs = 49764aa9a9SMarek Vasut ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >> 50764aa9a9SMarek Vasut SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1; 51764aa9a9SMarek Vasut const unsigned int rows = 52764aa9a9SMarek Vasut (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >> 53764aa9a9SMarek Vasut SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB; 54764aa9a9SMarek Vasut const unsigned int banks = 55764aa9a9SMarek Vasut (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_BANKBITS_MASK) >> 56764aa9a9SMarek Vasut SDR_CTRLGRP_DRAMADDRW_BANKBITS_LSB; 57764aa9a9SMarek Vasut const unsigned int cols = 58764aa9a9SMarek Vasut (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_COLBITS_MASK) >> 59764aa9a9SMarek Vasut SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB; 60f3671697SMarek Vasut const unsigned int width = 8; 61f3671697SMarek Vasut 629bbd2132SDinh Nguyen unsigned long long newrows; 63f3671697SMarek Vasut int bits, inewrowslog2; 649bbd2132SDinh Nguyen 659bbd2132SDinh Nguyen debug("workaround rows - memsize %lld\n", memsize); 669bbd2132SDinh Nguyen debug("workaround rows - cs %d\n", cs); 679bbd2132SDinh Nguyen debug("workaround rows - width %d\n", width); 689bbd2132SDinh Nguyen debug("workaround rows - rows %d\n", rows); 699bbd2132SDinh Nguyen debug("workaround rows - banks %d\n", banks); 709bbd2132SDinh Nguyen debug("workaround rows - cols %d\n", cols); 719bbd2132SDinh Nguyen 72791d20e1SMarek Vasut newrows = lldiv(memsize, cs * (width / 8)); 739bbd2132SDinh Nguyen debug("rows workaround - term1 %lld\n", newrows); 749bbd2132SDinh Nguyen 75791d20e1SMarek Vasut newrows = lldiv(newrows, (1 << banks) * (1 << cols)); 769bbd2132SDinh Nguyen debug("rows workaround - term2 %lld\n", newrows); 779bbd2132SDinh Nguyen 78791d20e1SMarek Vasut /* 79791d20e1SMarek Vasut * Compute the hamming weight - same as number of bits set. 809bbd2132SDinh Nguyen * Need to see if result is ordinal power of 2 before 819bbd2132SDinh Nguyen * attempting log2 of result. 829bbd2132SDinh Nguyen */ 8358d86144SMarek Vasut bits = generic_hweight32(newrows); 849bbd2132SDinh Nguyen 859bbd2132SDinh Nguyen debug("rows workaround - bits %d\n", bits); 869bbd2132SDinh Nguyen 879bbd2132SDinh Nguyen if (bits != 1) { 889bbd2132SDinh Nguyen printf("SDRAM workaround failed, bits set %d\n", bits); 899bbd2132SDinh Nguyen return rows; 909bbd2132SDinh Nguyen } 919bbd2132SDinh Nguyen 929bbd2132SDinh Nguyen if (newrows > UINT_MAX) { 939bbd2132SDinh Nguyen printf("SDRAM workaround rangecheck failed, %lld\n", newrows); 949bbd2132SDinh Nguyen return rows; 959bbd2132SDinh Nguyen } 969bbd2132SDinh Nguyen 97791d20e1SMarek Vasut inewrowslog2 = __ilog2(newrows); 989bbd2132SDinh Nguyen 99791d20e1SMarek Vasut debug("rows workaround - ilog2 %d, %lld\n", inewrowslog2, newrows); 1009bbd2132SDinh Nguyen 1019bbd2132SDinh Nguyen if (inewrowslog2 == -1) { 102791d20e1SMarek Vasut printf("SDRAM workaround failed, newrows %lld\n", newrows); 1039bbd2132SDinh Nguyen return rows; 1049bbd2132SDinh Nguyen } 1059bbd2132SDinh Nguyen 1069bbd2132SDinh Nguyen return inewrowslog2; 1079bbd2132SDinh Nguyen } 1089bbd2132SDinh Nguyen 1099bbd2132SDinh Nguyen /* SDRAM protection rules vary from 0-19, a total of 20 rules. */ 1109bbd2132SDinh Nguyen static void sdram_set_rule(struct sdram_prot_rule *prule) 1119bbd2132SDinh Nguyen { 1129bbd2132SDinh Nguyen uint32_t lo_addr_bits; 1139bbd2132SDinh Nguyen uint32_t hi_addr_bits; 1149bbd2132SDinh Nguyen int ruleno = prule->rule; 1159bbd2132SDinh Nguyen 1169bbd2132SDinh Nguyen /* Select the rule */ 1179bbd2132SDinh Nguyen writel(ruleno, &sdr_ctrl->prot_rule_rdwr); 1189bbd2132SDinh Nguyen 1199bbd2132SDinh Nguyen /* Obtain the address bits */ 120a003740aSMarek Vasut lo_addr_bits = prule->sdram_start >> 20ULL; 121a003740aSMarek Vasut hi_addr_bits = (prule->sdram_end - 1) >> 20ULL; 1229bbd2132SDinh Nguyen 1239bbd2132SDinh Nguyen debug("sdram set rule start %x, %lld\n", lo_addr_bits, 1249bbd2132SDinh Nguyen prule->sdram_start); 1259bbd2132SDinh Nguyen debug("sdram set rule end %x, %lld\n", hi_addr_bits, 1269bbd2132SDinh Nguyen prule->sdram_end); 1279bbd2132SDinh Nguyen 1289bbd2132SDinh Nguyen /* Set rule addresses */ 1299bbd2132SDinh Nguyen writel(lo_addr_bits | (hi_addr_bits << 12), &sdr_ctrl->prot_rule_addr); 1309bbd2132SDinh Nguyen 1319bbd2132SDinh Nguyen /* Set rule protection ids */ 1329bbd2132SDinh Nguyen writel(prule->lo_prot_id | (prule->hi_prot_id << 12), 1339bbd2132SDinh Nguyen &sdr_ctrl->prot_rule_id); 1349bbd2132SDinh Nguyen 1359bbd2132SDinh Nguyen /* Set the rule data */ 1369bbd2132SDinh Nguyen writel(prule->security | (prule->valid << 2) | 1379bbd2132SDinh Nguyen (prule->portmask << 3) | (prule->result << 13), 1389bbd2132SDinh Nguyen &sdr_ctrl->prot_rule_data); 1399bbd2132SDinh Nguyen 1409bbd2132SDinh Nguyen /* write the rule */ 141a003740aSMarek Vasut writel(ruleno | (1 << 5), &sdr_ctrl->prot_rule_rdwr); 1429bbd2132SDinh Nguyen 1439bbd2132SDinh Nguyen /* Set rule number to 0 by default */ 1449bbd2132SDinh Nguyen writel(0, &sdr_ctrl->prot_rule_rdwr); 1459bbd2132SDinh Nguyen } 1469bbd2132SDinh Nguyen 1479bbd2132SDinh Nguyen static void sdram_get_rule(struct sdram_prot_rule *prule) 1489bbd2132SDinh Nguyen { 149*6d01595fSMarek Vasut u32 addr; 150*6d01595fSMarek Vasut u32 id; 151*6d01595fSMarek Vasut u32 data; 1529bbd2132SDinh Nguyen int ruleno = prule->rule; 1539bbd2132SDinh Nguyen 1549bbd2132SDinh Nguyen /* Read the rule */ 1559bbd2132SDinh Nguyen writel(ruleno, &sdr_ctrl->prot_rule_rdwr); 156*6d01595fSMarek Vasut writel(ruleno | (1 << 6), &sdr_ctrl->prot_rule_rdwr); 1579bbd2132SDinh Nguyen 1589bbd2132SDinh Nguyen /* Get the addresses */ 1599bbd2132SDinh Nguyen addr = readl(&sdr_ctrl->prot_rule_addr); 1609bbd2132SDinh Nguyen prule->sdram_start = (addr & 0xFFF) << 20; 1619bbd2132SDinh Nguyen prule->sdram_end = ((addr >> 12) & 0xFFF) << 20; 1629bbd2132SDinh Nguyen 1639bbd2132SDinh Nguyen /* Get the configured protection IDs */ 1649bbd2132SDinh Nguyen id = readl(&sdr_ctrl->prot_rule_id); 1659bbd2132SDinh Nguyen prule->lo_prot_id = id & 0xFFF; 1669bbd2132SDinh Nguyen prule->hi_prot_id = (id >> 12) & 0xFFF; 1679bbd2132SDinh Nguyen 1689bbd2132SDinh Nguyen /* Get protection data */ 1699bbd2132SDinh Nguyen data = readl(&sdr_ctrl->prot_rule_data); 1709bbd2132SDinh Nguyen 1719bbd2132SDinh Nguyen prule->security = data & 0x3; 1729bbd2132SDinh Nguyen prule->valid = (data >> 2) & 0x1; 1739bbd2132SDinh Nguyen prule->portmask = (data >> 3) & 0x3FF; 1749bbd2132SDinh Nguyen prule->result = (data >> 13) & 0x1; 1759bbd2132SDinh Nguyen } 1769bbd2132SDinh Nguyen 1779bbd2132SDinh Nguyen static void sdram_set_protection_config(uint64_t sdram_start, uint64_t sdram_end) 1789bbd2132SDinh Nguyen { 1799bbd2132SDinh Nguyen struct sdram_prot_rule rule; 1809bbd2132SDinh Nguyen int rules; 1819bbd2132SDinh Nguyen 1829bbd2132SDinh Nguyen /* Start with accepting all SDRAM transaction */ 1839bbd2132SDinh Nguyen writel(0x0, &sdr_ctrl->protport_default); 1849bbd2132SDinh Nguyen 1859bbd2132SDinh Nguyen /* Clear all protection rules for warm boot case */ 186a003740aSMarek Vasut memset(&rule, 0, sizeof(rule)); 1879bbd2132SDinh Nguyen 1889bbd2132SDinh Nguyen for (rules = 0; rules < 20; rules++) { 1899bbd2132SDinh Nguyen rule.rule = rules; 1909bbd2132SDinh Nguyen sdram_set_rule(&rule); 1919bbd2132SDinh Nguyen } 1929bbd2132SDinh Nguyen 1939bbd2132SDinh Nguyen /* new rule: accept SDRAM */ 1949bbd2132SDinh Nguyen rule.sdram_start = sdram_start; 1959bbd2132SDinh Nguyen rule.sdram_end = sdram_end; 1969bbd2132SDinh Nguyen rule.lo_prot_id = 0x0; 1979bbd2132SDinh Nguyen rule.hi_prot_id = 0xFFF; 1989bbd2132SDinh Nguyen rule.portmask = 0x3FF; 1999bbd2132SDinh Nguyen rule.security = 0x3; 2009bbd2132SDinh Nguyen rule.result = 0; 2019bbd2132SDinh Nguyen rule.valid = 1; 2029bbd2132SDinh Nguyen rule.rule = 0; 2039bbd2132SDinh Nguyen 2049bbd2132SDinh Nguyen /* set new rule */ 2059bbd2132SDinh Nguyen sdram_set_rule(&rule); 2069bbd2132SDinh Nguyen 2079bbd2132SDinh Nguyen /* default rule: reject everything */ 2089bbd2132SDinh Nguyen writel(0x3ff, &sdr_ctrl->protport_default); 2099bbd2132SDinh Nguyen } 2109bbd2132SDinh Nguyen 2119bbd2132SDinh Nguyen static void sdram_dump_protection_config(void) 2129bbd2132SDinh Nguyen { 2139bbd2132SDinh Nguyen struct sdram_prot_rule rule; 2149bbd2132SDinh Nguyen int rules; 2159bbd2132SDinh Nguyen 2169bbd2132SDinh Nguyen debug("SDRAM Prot rule, default %x\n", 2179bbd2132SDinh Nguyen readl(&sdr_ctrl->protport_default)); 2189bbd2132SDinh Nguyen 2199bbd2132SDinh Nguyen for (rules = 0; rules < 20; rules++) { 2209bbd2132SDinh Nguyen sdram_get_rule(&rule); 2219bbd2132SDinh Nguyen debug("Rule %d, rules ...\n", rules); 2229bbd2132SDinh Nguyen debug(" sdram start %llx\n", rule.sdram_start); 2239bbd2132SDinh Nguyen debug(" sdram end %llx\n", rule.sdram_end); 2249bbd2132SDinh Nguyen debug(" low prot id %d, hi prot id %d\n", 2259bbd2132SDinh Nguyen rule.lo_prot_id, 2269bbd2132SDinh Nguyen rule.hi_prot_id); 2279bbd2132SDinh Nguyen debug(" portmask %x\n", rule.portmask); 2289bbd2132SDinh Nguyen debug(" security %d\n", rule.security); 2299bbd2132SDinh Nguyen debug(" result %d\n", rule.result); 2309bbd2132SDinh Nguyen debug(" valid %d\n", rule.valid); 2319bbd2132SDinh Nguyen } 2329bbd2132SDinh Nguyen } 2339bbd2132SDinh Nguyen 234269de4f0SMarek Vasut /** 235269de4f0SMarek Vasut * sdram_write_verify() - write to register and verify the write. 236269de4f0SMarek Vasut * @addr: Register address 237269de4f0SMarek Vasut * @val: Value to be written and verified 238269de4f0SMarek Vasut * 239269de4f0SMarek Vasut * This function writes to a register, reads back the value and compares 240269de4f0SMarek Vasut * the result with the written value to check if the data match. 241269de4f0SMarek Vasut */ 242269de4f0SMarek Vasut static unsigned sdram_write_verify(const u32 *addr, const u32 val) 2439bbd2132SDinh Nguyen { 244269de4f0SMarek Vasut u32 rval; 245269de4f0SMarek Vasut 246269de4f0SMarek Vasut debug(" Write - Address 0x%p Data 0x%08x\n", addr, val); 247269de4f0SMarek Vasut writel(val, addr); 248269de4f0SMarek Vasut 2499bbd2132SDinh Nguyen debug(" Read and verify..."); 250269de4f0SMarek Vasut rval = readl(addr); 251269de4f0SMarek Vasut if (rval != val) { 252269de4f0SMarek Vasut debug("FAIL - Address 0x%p Expected 0x%08x Data 0x%08x\n", 253269de4f0SMarek Vasut addr, val, rval); 254269de4f0SMarek Vasut return -EINVAL; 2559bbd2132SDinh Nguyen } 256269de4f0SMarek Vasut 2579bbd2132SDinh Nguyen debug("correct!\n"); 2589bbd2132SDinh Nguyen return 0; 2599bbd2132SDinh Nguyen } 2609bbd2132SDinh Nguyen 26196b869b6SMarek Vasut /** 26296b869b6SMarek Vasut * sdr_get_ctrlcfg() - Get the value of DRAM CTRLCFG register 26396b869b6SMarek Vasut * @cfg: SDRAM controller configuration data 26496b869b6SMarek Vasut * 26596b869b6SMarek Vasut * Return the value of DRAM CTRLCFG register. 26696b869b6SMarek Vasut */ 2675af91418SMarek Vasut static u32 sdr_get_ctrlcfg(const struct socfpga_sdram_config *cfg) 2689bbd2132SDinh Nguyen { 269764aa9a9SMarek Vasut const u32 csbits = 270764aa9a9SMarek Vasut ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >> 271764aa9a9SMarek Vasut SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1; 272764aa9a9SMarek Vasut u32 addrorder = 273764aa9a9SMarek Vasut (cfg->ctrl_cfg & SDR_CTRLGRP_CTRLCFG_ADDRORDER_MASK) >> 274764aa9a9SMarek Vasut SDR_CTRLGRP_CTRLCFG_ADDRORDER_LSB; 275764aa9a9SMarek Vasut 27604ae4489SMarek Vasut u32 ctrl_cfg = cfg->ctrl_cfg; 2779bbd2132SDinh Nguyen 278067c853fSMarek Vasut /* 279067c853fSMarek Vasut * SDRAM Failure When Accessing Non-Existent Memory 2809bbd2132SDinh Nguyen * Set the addrorder field of the SDRAM control register 2819bbd2132SDinh Nguyen * based on the CSBITs setting. 2829bbd2132SDinh Nguyen */ 283764aa9a9SMarek Vasut if (csbits == 1) { 284764aa9a9SMarek Vasut if (addrorder != 0) 285067c853fSMarek Vasut debug("INFO: Changing address order to 0 (chip, row, bank, column)\n"); 286764aa9a9SMarek Vasut addrorder = 0; 287764aa9a9SMarek Vasut } else if (csbits == 2) { 288764aa9a9SMarek Vasut if (addrorder != 2) 289067c853fSMarek Vasut debug("INFO: Changing address order to 2 (row, chip, bank, column)\n"); 290764aa9a9SMarek Vasut addrorder = 2; 2919bbd2132SDinh Nguyen } 2929bbd2132SDinh Nguyen 293764aa9a9SMarek Vasut ctrl_cfg &= ~SDR_CTRLGRP_CTRLCFG_ADDRORDER_MASK; 294067c853fSMarek Vasut ctrl_cfg |= addrorder << SDR_CTRLGRP_CTRLCFG_ADDRORDER_LSB; 2959bbd2132SDinh Nguyen 2969d6b012cSMarek Vasut return ctrl_cfg; 2979bbd2132SDinh Nguyen } 2989bbd2132SDinh Nguyen 29996b869b6SMarek Vasut /** 30096b869b6SMarek Vasut * sdr_get_addr_rw() - Get the value of DRAM ADDRW register 30196b869b6SMarek Vasut * @cfg: SDRAM controller configuration data 30296b869b6SMarek Vasut * 30396b869b6SMarek Vasut * Return the value of DRAM ADDRW register. 30496b869b6SMarek Vasut */ 3055af91418SMarek Vasut static u32 sdr_get_addr_rw(const struct socfpga_sdram_config *cfg) 3069bbd2132SDinh Nguyen { 3079bbd2132SDinh Nguyen /* 3089bbd2132SDinh Nguyen * SDRAM Failure When Accessing Non-Existent Memory 3099bbd2132SDinh Nguyen * Set SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB to 3109bbd2132SDinh Nguyen * log2(number of chip select bits). Since there's only 3119bbd2132SDinh Nguyen * 1 or 2 chip selects, log2(1) => 0, and log2(2) => 1, 3129bbd2132SDinh Nguyen * which is the same as "chip selects" - 1. 3139bbd2132SDinh Nguyen */ 314764aa9a9SMarek Vasut const int rows = get_errata_rows(cfg); 315764aa9a9SMarek Vasut u32 dram_addrw = cfg->dram_addrw & ~SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK; 31604ae4489SMarek Vasut 3179d6b012cSMarek Vasut return dram_addrw | (rows << SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB); 3189bbd2132SDinh Nguyen } 3199bbd2132SDinh Nguyen 3201a302a45SMarek Vasut /** 3211a302a45SMarek Vasut * sdr_load_regs() - Load SDRAM controller registers 3221a302a45SMarek Vasut * @cfg: SDRAM controller configuration data 3231a302a45SMarek Vasut * 3241a302a45SMarek Vasut * This function loads the register values into the SDRAM controller block. 3251a302a45SMarek Vasut */ 3265af91418SMarek Vasut static void sdr_load_regs(const struct socfpga_sdram_config *cfg) 3279bbd2132SDinh Nguyen { 3289d6b012cSMarek Vasut const u32 ctrl_cfg = sdr_get_ctrlcfg(cfg); 3299d6b012cSMarek Vasut const u32 dram_addrw = sdr_get_addr_rw(cfg); 3309d6b012cSMarek Vasut 3319d6b012cSMarek Vasut debug("\nConfiguring CTRLCFG\n"); 3329d6b012cSMarek Vasut writel(ctrl_cfg, &sdr_ctrl->ctrl_cfg); 333076470eeSMarek Vasut 334076470eeSMarek Vasut debug("Configuring DRAMTIMING1\n"); 335076470eeSMarek Vasut writel(cfg->dram_timing1, &sdr_ctrl->dram_timing1); 336076470eeSMarek Vasut 337076470eeSMarek Vasut debug("Configuring DRAMTIMING2\n"); 338076470eeSMarek Vasut writel(cfg->dram_timing2, &sdr_ctrl->dram_timing2); 339076470eeSMarek Vasut 340076470eeSMarek Vasut debug("Configuring DRAMTIMING3\n"); 341076470eeSMarek Vasut writel(cfg->dram_timing3, &sdr_ctrl->dram_timing3); 342076470eeSMarek Vasut 343076470eeSMarek Vasut debug("Configuring DRAMTIMING4\n"); 344076470eeSMarek Vasut writel(cfg->dram_timing4, &sdr_ctrl->dram_timing4); 345076470eeSMarek Vasut 346076470eeSMarek Vasut debug("Configuring LOWPWRTIMING\n"); 347076470eeSMarek Vasut writel(cfg->lowpwr_timing, &sdr_ctrl->lowpwr_timing); 348076470eeSMarek Vasut 3499d6b012cSMarek Vasut debug("Configuring DRAMADDRW\n"); 3509d6b012cSMarek Vasut writel(dram_addrw, &sdr_ctrl->dram_addrw); 3519bbd2132SDinh Nguyen 3529bbd2132SDinh Nguyen debug("Configuring DRAMIFWIDTH\n"); 353dc3b91d9SMarek Vasut writel(cfg->dram_if_width, &sdr_ctrl->dram_if_width); 3549bbd2132SDinh Nguyen 3559bbd2132SDinh Nguyen debug("Configuring DRAMDEVWIDTH\n"); 356dc3b91d9SMarek Vasut writel(cfg->dram_dev_width, &sdr_ctrl->dram_dev_width); 3579bbd2132SDinh Nguyen 3589bbd2132SDinh Nguyen debug("Configuring LOWPWREQ\n"); 359dc3b91d9SMarek Vasut writel(cfg->lowpwr_eq, &sdr_ctrl->lowpwr_eq); 3609bbd2132SDinh Nguyen 3619bbd2132SDinh Nguyen debug("Configuring DRAMINTR\n"); 362dc3b91d9SMarek Vasut writel(cfg->dram_intr, &sdr_ctrl->dram_intr); 3639bbd2132SDinh Nguyen 364076470eeSMarek Vasut debug("Configuring STATICCFG\n"); 365076470eeSMarek Vasut writel(cfg->static_cfg, &sdr_ctrl->static_cfg); 3669bbd2132SDinh Nguyen 3679bbd2132SDinh Nguyen debug("Configuring CTRLWIDTH\n"); 368dc3b91d9SMarek Vasut writel(cfg->ctrl_width, &sdr_ctrl->ctrl_width); 3699bbd2132SDinh Nguyen 3709bbd2132SDinh Nguyen debug("Configuring PORTCFG\n"); 371dc3b91d9SMarek Vasut writel(cfg->port_cfg, &sdr_ctrl->port_cfg); 3729bbd2132SDinh Nguyen 373076470eeSMarek Vasut debug("Configuring FIFOCFG\n"); 374076470eeSMarek Vasut writel(cfg->fifo_cfg, &sdr_ctrl->fifo_cfg); 3759bbd2132SDinh Nguyen 3769bbd2132SDinh Nguyen debug("Configuring MPPRIORITY\n"); 377dc3b91d9SMarek Vasut writel(cfg->mp_priority, &sdr_ctrl->mp_priority); 3789bbd2132SDinh Nguyen 379076470eeSMarek Vasut debug("Configuring MPWEIGHT_MPWEIGHT_0\n"); 380076470eeSMarek Vasut writel(cfg->mp_weight0, &sdr_ctrl->mp_weight0); 381076470eeSMarek Vasut writel(cfg->mp_weight1, &sdr_ctrl->mp_weight1); 382076470eeSMarek Vasut writel(cfg->mp_weight2, &sdr_ctrl->mp_weight2); 383076470eeSMarek Vasut writel(cfg->mp_weight3, &sdr_ctrl->mp_weight3); 384076470eeSMarek Vasut 385076470eeSMarek Vasut debug("Configuring MPPACING_MPPACING_0\n"); 386076470eeSMarek Vasut writel(cfg->mp_pacing0, &sdr_ctrl->mp_pacing0); 387076470eeSMarek Vasut writel(cfg->mp_pacing1, &sdr_ctrl->mp_pacing1); 388076470eeSMarek Vasut writel(cfg->mp_pacing2, &sdr_ctrl->mp_pacing2); 389076470eeSMarek Vasut writel(cfg->mp_pacing3, &sdr_ctrl->mp_pacing3); 390076470eeSMarek Vasut 391076470eeSMarek Vasut debug("Configuring MPTHRESHOLDRST_MPTHRESHOLDRST_0\n"); 392076470eeSMarek Vasut writel(cfg->mp_threshold0, &sdr_ctrl->mp_threshold0); 393076470eeSMarek Vasut writel(cfg->mp_threshold1, &sdr_ctrl->mp_threshold1); 394076470eeSMarek Vasut writel(cfg->mp_threshold2, &sdr_ctrl->mp_threshold2); 3959bbd2132SDinh Nguyen 3969bbd2132SDinh Nguyen debug("Configuring PHYCTRL_PHYCTRL_0\n"); 397dc3b91d9SMarek Vasut writel(cfg->phy_ctrl0, &sdr_ctrl->phy_ctrl0); 3989bbd2132SDinh Nguyen 3999bbd2132SDinh Nguyen debug("Configuring CPORTWIDTH\n"); 400dc3b91d9SMarek Vasut writel(cfg->cport_width, &sdr_ctrl->cport_width); 4019bbd2132SDinh Nguyen 4029bbd2132SDinh Nguyen debug("Configuring CPORTWMAP\n"); 403dc3b91d9SMarek Vasut writel(cfg->cport_wmap, &sdr_ctrl->cport_wmap); 4049bbd2132SDinh Nguyen 4059bbd2132SDinh Nguyen debug("Configuring CPORTRMAP\n"); 406dc3b91d9SMarek Vasut writel(cfg->cport_rmap, &sdr_ctrl->cport_rmap); 4079bbd2132SDinh Nguyen 4089bbd2132SDinh Nguyen debug("Configuring RFIFOCMAP\n"); 409dc3b91d9SMarek Vasut writel(cfg->rfifo_cmap, &sdr_ctrl->rfifo_cmap); 4109bbd2132SDinh Nguyen 4119bbd2132SDinh Nguyen debug("Configuring WFIFOCMAP\n"); 412dc3b91d9SMarek Vasut writel(cfg->wfifo_cmap, &sdr_ctrl->wfifo_cmap); 4139bbd2132SDinh Nguyen 4149bbd2132SDinh Nguyen debug("Configuring CPORTRDWR\n"); 415dc3b91d9SMarek Vasut writel(cfg->cport_rdwr, &sdr_ctrl->cport_rdwr); 4169bbd2132SDinh Nguyen 4179bbd2132SDinh Nguyen debug("Configuring DRAMODT\n"); 418dc3b91d9SMarek Vasut writel(cfg->dram_odt, &sdr_ctrl->dram_odt); 4191a302a45SMarek Vasut } 4201a302a45SMarek Vasut 4211e8a85f8SMarek Vasut /** 4221e8a85f8SMarek Vasut * sdram_mmr_init_full() - Function to initialize SDRAM MMR 4231e8a85f8SMarek Vasut * @sdr_phy_reg: Value of the PHY control register 0 4241e8a85f8SMarek Vasut * 4251e8a85f8SMarek Vasut * Initialize the SDRAM MMR. 4261e8a85f8SMarek Vasut */ 42799f453e9SMarek Vasut int sdram_mmr_init_full(unsigned int sdr_phy_reg) 4281a302a45SMarek Vasut { 4295af91418SMarek Vasut const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config(); 4301a302a45SMarek Vasut const unsigned int rows = 4311a302a45SMarek Vasut (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >> 4321a302a45SMarek Vasut SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB; 433269de4f0SMarek Vasut int ret; 4341a302a45SMarek Vasut 4351a302a45SMarek Vasut writel(rows, &sysmgr_regs->iswgrp_handoff[4]); 4361a302a45SMarek Vasut 4371a302a45SMarek Vasut sdr_load_regs(cfg); 4389bbd2132SDinh Nguyen 4399bbd2132SDinh Nguyen /* saving this value to SYSMGR.ISWGRP.HANDOFF.FPGA2SDR */ 440dc3b91d9SMarek Vasut writel(cfg->fpgaport_rst, &sysmgr_regs->iswgrp_handoff[3]); 4419bbd2132SDinh Nguyen 4429bbd2132SDinh Nguyen /* only enable if the FPGA is programmed */ 4439bbd2132SDinh Nguyen if (fpgamgr_test_fpga_ready()) { 444269de4f0SMarek Vasut ret = sdram_write_verify(&sdr_ctrl->fpgaport_rst, 445269de4f0SMarek Vasut cfg->fpgaport_rst); 446269de4f0SMarek Vasut if (ret) 447269de4f0SMarek Vasut return ret; 4489bbd2132SDinh Nguyen } 4499bbd2132SDinh Nguyen 4509bbd2132SDinh Nguyen /* Restore the SDR PHY Register if valid */ 4519bbd2132SDinh Nguyen if (sdr_phy_reg != 0xffffffff) 4529bbd2132SDinh Nguyen writel(sdr_phy_reg, &sdr_ctrl->phy_ctrl0); 4539bbd2132SDinh Nguyen 454dc3b91d9SMarek Vasut /* Final step - apply configuration changes */ 455dc3b91d9SMarek Vasut debug("Configuring STATICCFG\n"); 456dc3b91d9SMarek Vasut clrsetbits_le32(&sdr_ctrl->static_cfg, 457dc3b91d9SMarek Vasut SDR_CTRLGRP_STATICCFG_APPLYCFG_MASK, 4589bbd2132SDinh Nguyen 1 << SDR_CTRLGRP_STATICCFG_APPLYCFG_LSB); 4599bbd2132SDinh Nguyen 4609bbd2132SDinh Nguyen sdram_set_protection_config(0, sdram_calculate_size()); 4619bbd2132SDinh Nguyen 4629bbd2132SDinh Nguyen sdram_dump_protection_config(); 4639bbd2132SDinh Nguyen 464269de4f0SMarek Vasut return 0; 4659bbd2132SDinh Nguyen } 4669bbd2132SDinh Nguyen 467f97606f2SMarek Vasut /** 468f97606f2SMarek Vasut * sdram_calculate_size() - Calculate SDRAM size 4699bbd2132SDinh Nguyen * 470f97606f2SMarek Vasut * Calculate SDRAM device size based on SDRAM controller parameters. 471f97606f2SMarek Vasut * Size is specified in bytes. 4729bbd2132SDinh Nguyen */ 4739bbd2132SDinh Nguyen unsigned long sdram_calculate_size(void) 4749bbd2132SDinh Nguyen { 4759bbd2132SDinh Nguyen unsigned long temp; 4769bbd2132SDinh Nguyen unsigned long row, bank, col, cs, width; 477bb056d9cSMarek Vasut const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config(); 478bb056d9cSMarek Vasut const unsigned int csbits = 479bb056d9cSMarek Vasut ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >> 480bb056d9cSMarek Vasut SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1; 481bb056d9cSMarek Vasut const unsigned int rowbits = 482bb056d9cSMarek Vasut (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >> 483bb056d9cSMarek Vasut SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB; 4849bbd2132SDinh Nguyen 4859bbd2132SDinh Nguyen temp = readl(&sdr_ctrl->dram_addrw); 4869bbd2132SDinh Nguyen col = (temp & SDR_CTRLGRP_DRAMADDRW_COLBITS_MASK) >> 4879bbd2132SDinh Nguyen SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB; 4889bbd2132SDinh Nguyen 489f97606f2SMarek Vasut /* 490f97606f2SMarek Vasut * SDRAM Failure When Accessing Non-Existent Memory 4919bbd2132SDinh Nguyen * Use ROWBITS from Quartus/QSys to calculate SDRAM size 4929bbd2132SDinh Nguyen * since the FB specifies we modify ROWBITs to work around SDRAM 4939bbd2132SDinh Nguyen * controller issue. 4949bbd2132SDinh Nguyen */ 4959bbd2132SDinh Nguyen row = readl(&sysmgr_regs->iswgrp_handoff[4]); 4969bbd2132SDinh Nguyen if (row == 0) 497bb056d9cSMarek Vasut row = rowbits; 498f97606f2SMarek Vasut /* 499f97606f2SMarek Vasut * If the stored handoff value for rows is greater than 5009bbd2132SDinh Nguyen * the field width in the sdr.dramaddrw register then 5019bbd2132SDinh Nguyen * something is very wrong. Revert to using the the #define 5029bbd2132SDinh Nguyen * value handed off by the SOCEDS tool chain instead of 5039bbd2132SDinh Nguyen * using a broken value. 5049bbd2132SDinh Nguyen */ 5059bbd2132SDinh Nguyen if (row > 31) 506bb056d9cSMarek Vasut row = rowbits; 5079bbd2132SDinh Nguyen 5089bbd2132SDinh Nguyen bank = (temp & SDR_CTRLGRP_DRAMADDRW_BANKBITS_MASK) >> 5099bbd2132SDinh Nguyen SDR_CTRLGRP_DRAMADDRW_BANKBITS_LSB; 5109bbd2132SDinh Nguyen 511f97606f2SMarek Vasut /* 512f97606f2SMarek Vasut * SDRAM Failure When Accessing Non-Existent Memory 5139bbd2132SDinh Nguyen * Use CSBITs from Quartus/QSys to calculate SDRAM size 5149bbd2132SDinh Nguyen * since the FB specifies we modify CSBITs to work around SDRAM 5159bbd2132SDinh Nguyen * controller issue. 5169bbd2132SDinh Nguyen */ 517bb056d9cSMarek Vasut cs = csbits; 5189bbd2132SDinh Nguyen 5199bbd2132SDinh Nguyen width = readl(&sdr_ctrl->dram_if_width); 520f97606f2SMarek Vasut 5219bbd2132SDinh Nguyen /* ECC would not be calculated as its not addressible */ 5229bbd2132SDinh Nguyen if (width == SDRAM_WIDTH_32BIT_WITH_ECC) 5239bbd2132SDinh Nguyen width = 32; 5249bbd2132SDinh Nguyen if (width == SDRAM_WIDTH_16BIT_WITH_ECC) 5259bbd2132SDinh Nguyen width = 16; 5269bbd2132SDinh Nguyen 5279bbd2132SDinh Nguyen /* calculate the SDRAM size base on this info */ 5289bbd2132SDinh Nguyen temp = 1 << (row + bank + col); 5299bbd2132SDinh Nguyen temp = temp * cs * (width / 8); 5309bbd2132SDinh Nguyen 531f97606f2SMarek Vasut debug("%s returns %ld\n", __func__, temp); 5329bbd2132SDinh Nguyen 5339bbd2132SDinh Nguyen return temp; 5349bbd2132SDinh Nguyen } 535