gadget-kspconsole/stm32f7_sdram.c
Daniele Lacamera b8a7ffcd31 Initial import
2023-11-27 15:16:45 +01:00

156 lines
4.9 KiB
C

/*
*
* Modified from unicore-mx SDRAM support
*
* Copyright (C) 2014 Chuck McManis <cmcmanis@mcmanis.com>
* Copyright (C) 2016 Maxime Vincent <maxime.vince@gmail.com>
* Copyright (C) 2016-2023 Daniele Lacamera <root@danielinux.net>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/*
* Original authors:
* Maxime Vincent <maxime.vince@gmail.com>
* Chuck McManis <cmcmanis@mcmanis.com>
* Daniele Lacamera <root@danielinux.net>
*
*
*/
#include <stdint.h>
#include <unicore-mx/stm32/gpio.h>
#include <unicore-mx/stm32/rcc.h>
#include <unicore-mx/stm32/fsmc.h>
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;
}