/* * * Modified from unicore-mx SDRAM support * * Copyright (C) 2014 Chuck McManis * Copyright (C) 2016 Maxime Vincent * Copyright (C) 2016-2023 Daniele Lacamera * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ /* * Original authors: * Maxime Vincent * Chuck McManis * Daniele Lacamera * * */ #include #include #include #include extern volatile uint32_t jiffies; #define SDRAM_BASE_ADDRESS ((uint8_t *)(0xC0000000)) /* * This is just syntactic sugar but it helps, all of these * GPIO pins get configured in exactly the same way. */ static const struct { uint32_t gpio; uint16_t pins; } sdram_pins[6] = { {GPIOC, GPIO3 }, {GPIOD, GPIO0 | GPIO1 | GPIO3 | GPIO8 | GPIO9 | GPIO10 | GPIO14 | GPIO15}, {GPIOE, GPIO0 | GPIO1 | GPIO7 | GPIO8 | GPIO9 | GPIO10 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15 }, {GPIOF, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO4 | GPIO5 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15 }, {GPIOG, GPIO0 | GPIO1 | GPIO4 | GPIO5 | GPIO8 | GPIO15}, {GPIOH, GPIO3 | GPIO5 } }; static struct sdram_timing timing = { .trcd = 2, /* RCD Delay */ .trp = 2, /* RP Delay */ .twr = 2, /* Write Recovery Time */ .trc = 7, /* Row Cycle Delay */ .tras = 4, /* Self Refresh Time */ .txsr = 7, /* Exit Self Refresh Time */ .tmrd = 2, /* Load to Active Delay */ }; /* * Initialize the SD RAM controller. */ void sdram_init(void) { int i, now; uint32_t cr_tmp, tr_tmp; /* control, timing registers */ /* * First all the GPIO pins that end up as SDRAM pins */ rcc_periph_clock_enable(RCC_GPIOC); rcc_periph_clock_enable(RCC_GPIOD); rcc_periph_clock_enable(RCC_GPIOE); rcc_periph_clock_enable(RCC_GPIOF); rcc_periph_clock_enable(RCC_GPIOG); rcc_periph_clock_enable(RCC_GPIOH); for (i = 0; i < 6; i++) { gpio_mode_setup(sdram_pins[i].gpio, GPIO_MODE_AF, GPIO_PUPD_NONE, sdram_pins[i].pins); gpio_set_output_options(sdram_pins[i].gpio, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, sdram_pins[i].pins); gpio_set_af(sdram_pins[i].gpio, GPIO_AF12, sdram_pins[i].pins); } /* Enable the SDRAM Controller */ #if 1 rcc_periph_clock_enable(RCC_FMC); #else rcc_peripheral_enable_clock(&RCC_AHB3ENR, RCC_AHB3ENR_FMCEN); #endif /* Note the STM32F746G-DISCO board has the ram attached to bank 1 */ /* Timing parameters computed for a ~200 MHz clock */ /* These parameters are specific to the SDRAM chip on the board */ cr_tmp = FMC_SDCR_RPIPE_NONE; cr_tmp |= FMC_SDCR_SDCLK_2HCLK; cr_tmp |= FMC_SDCR_CAS_2CYC; cr_tmp |= FMC_SDCR_NB4; cr_tmp |= FMC_SDCR_MWID_16b; cr_tmp |= FMC_SDCR_NR_12; cr_tmp |= FMC_SDCR_NC_8; /* We're programming BANK 1 * Per the manual some of the parameters only work in CR1 and TR1 * So when using BANK2: we need pull those off and put them in the right place. * FMC_SDCR1 |= (cr_tmp); // & FMC_SDCR_DNC_MASK); * FMC_SDCR2 = cr_tmp; */ FMC_SDCR1 = (cr_tmp); tr_tmp = sdram_timing(&timing); FMC_SDTR1 = (tr_tmp); /* Now start up the Controller per the manual * - Clock config enable * - PALL state * - set auto refresh * - Load the Mode Register */ sdram_command(SDRAM_BANK1, SDRAM_CLK_CONF, 1, 0); /* sleep at least 100uS */ now = jiffies; //while (now + 2 > jiffies) {}; sdram_command(SDRAM_BANK1, SDRAM_PALL, 1, 0); sdram_command(SDRAM_BANK1, SDRAM_AUTO_REFRESH, 8, 0); tr_tmp = SDRAM_MODE_BURST_LENGTH_1 | SDRAM_MODE_BURST_TYPE_SEQUENTIAL | SDRAM_MODE_CAS_LATENCY_2 | SDRAM_MODE_OPERATING_MODE_STANDARD | SDRAM_MODE_WRITEBURST_MODE_SINGLE; sdram_command(SDRAM_BANK1, SDRAM_LOAD_MODE, 1, tr_tmp); /* * set the refresh counter to insure we kick off an * auto refresh often enough to prevent data loss. */ FMC_SDRTR = ((uint32_t)0x0603); /* SDRAM refresh counter (100Mhz SD clock) */ /* and Poof! a 8 megabytes of ram shows up in the address space */ /* Disable write protection */ FMC_SDCR1 &= ~FMC_SDCR_WP_ENABLE; }