/* * Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct stm32mp_ddr_priv ddr_priv_data; static bool ddr_self_refresh; static int ddr_dt_get_ui_param(void *fdt, int node, struct stm32mp_ddr_config *config) { int ret; uint32_t size; size = sizeof(struct user_input_basic) / sizeof(int); ret = fdt_read_uint32_array(fdt, node, "st,phy-basic", size, (uint32_t *)&config->uib); VERBOSE("%s: %s[0x%x] = %d\n", __func__, "st,phy-basic", size, ret); if (ret != 0) { ERROR("%s: can't read %s, error=%d\n", __func__, "st,phy-basic", ret); return -EINVAL; } size = sizeof(struct user_input_advanced) / sizeof(int); ret = fdt_read_uint32_array(fdt, node, "st,phy-advanced", size, (uint32_t *)&config->uia); VERBOSE("%s: %s[0x%x] = %d\n", __func__, "st,phy-advanced", size, ret); if (ret != 0) { ERROR("%s: can't read %s, error=%d\n", __func__, "st,phy-advanced", ret); return -EINVAL; } size = sizeof(struct user_input_mode_register) / sizeof(int); ret = fdt_read_uint32_array(fdt, node, "st,phy-mr", size, (uint32_t *)&config->uim); VERBOSE("%s: %s[0x%x] = %d\n", __func__, "st,phy-mr", size, ret); if (ret != 0) { ERROR("%s: can't read %s, error=%d\n", __func__, "st,phy-mr", ret); return -EINVAL; } size = sizeof(struct user_input_swizzle) / sizeof(int); ret = fdt_read_uint32_array(fdt, node, "st,phy-swizzle", size, (uint32_t *)&config->uis); VERBOSE("%s: %s[0x%x] = %d\n", __func__, "st,phy-swizzle", size, ret); if (ret != 0) { ERROR("%s: can't read %s, error=%d\n", __func__, "st,phy-swizzle", ret); return -EINVAL; } return 0; } static int stm32mp2_ddr_setup(void) { struct stm32mp_ddr_priv *priv = &ddr_priv_data; int ret; struct stm32mp_ddr_config config; int node; uintptr_t uret; void *fdt; const struct stm32mp_ddr_param param[] = { CTL_PARAM(reg), CTL_PARAM(timing), CTL_PARAM(map), CTL_PARAM(perf) }; if (fdt_get_address(&fdt) == 0) { return -ENOENT; } node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); if (node < 0) { ERROR("%s: can't read DDR node in DT\n", __func__); return -EINVAL; } ret = stm32mp_ddr_dt_get_info(fdt, node, &config.info); if (ret < 0) { return ret; } ret = stm32mp_ddr_dt_get_param(fdt, node, param, ARRAY_SIZE(param), (uintptr_t)&config); if (ret < 0) { return ret; } ret = ddr_dt_get_ui_param(fdt, node, &config); if (ret < 0) { return ret; } config.self_refresh = false; if (stm32mp_is_wakeup_from_standby()) { config.self_refresh = true; } /* Map dynamically RETRAM area to save or restore PHY retention registers */ if (stm32mp_map_retram() != 0) { panic(); } stm32mp2_ddr_init(priv, &config); /* Unmap RETRAM, no more used until next DDR initialization call */ if (stm32mp_unmap_retram() != 0) { panic(); } priv->info.size = config.info.size; VERBOSE("%s : ram size(%lx, %lx)\n", __func__, priv->info.base, priv->info.size); if (stm32mp_map_ddr_non_cacheable() != 0) { panic(); } if (config.self_refresh) { uret = stm32mp_ddr_test_rw_access(); if (uret != 0UL) { ERROR("DDR rw test: can't access memory @ 0x%lx\n", uret); panic(); } /* TODO Restore area overwritten by training */ //stm32_restore_ddr_training_area(); } else { size_t retsize; uret = stm32mp_ddr_test_data_bus(); if (uret != 0UL) { ERROR("DDR data bus test: can't access memory @ 0x%lx\n", uret); panic(); } uret = stm32mp_ddr_test_addr_bus(config.info.size); if (uret != 0UL) { ERROR("DDR addr bus test: can't access memory @ 0x%lx\n", uret); panic(); } retsize = stm32mp_ddr_check_size(); if (retsize < config.info.size) { ERROR("DDR size: 0x%zx does not match DT config: 0x%zx\n", retsize, config.info.size); panic(); } INFO("Memory size = 0x%zx (%zu MB)\n", retsize, retsize / (1024U * 1024U)); } /* * Initialization sequence has configured DDR registers with settings. * The Self Refresh (SR) mode corresponding to these settings has now * to be set. */ ddr_set_sr_mode(ddr_read_sr_mode()); if (stm32mp_unmap_ddr() != 0) { panic(); } /* Save DDR self_refresh state */ ddr_self_refresh = config.self_refresh; return 0; } bool stm32mp2_ddr_is_restored(void) { return ddr_self_refresh; } int stm32mp2_ddr_probe(void) { struct stm32mp_ddr_priv *priv = &ddr_priv_data; VERBOSE("STM32MP DDR probe\n"); priv->ctl = (struct stm32mp_ddrctl *)stm32mp_ddrctrl_base(); priv->phy = (struct stm32mp_ddrphy *)stm32mp_ddrphyc_base(); priv->pwr = stm32mp_pwr_base(); priv->rcc = stm32mp_rcc_base(); priv->info.base = STM32MP_DDR_BASE; priv->info.size = 0; return stm32mp2_ddr_setup(); }