nuttx/boards/arm/stm32/axoloti/src/stm32_extmem.c
Xiang Xiao 54e630e14d arch: Merge up_arch.h into up_internal.h
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2022-03-14 09:32:17 +02:00

309 lines
9.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
* boards/arm/stm32/axoloti/src/stm32_extmem.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <arch/board/board.h>
#include "chip.h"
#include "arm_internal.h"
#include "stm32.h"
#include "axoloti.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef CONFIG_STM32_FMC
#warning "FMC is not enabled"
#endif
/****************************************************************************
* Private Data
****************************************************************************/
/* Axoloti SDRAM GPIO configuration */
static const uint32_t g_sdram_config[] =
{
/* Data lines */
GPIO_FMC_D0, GPIO_FMC_D1, GPIO_FMC_D2, GPIO_FMC_D3,
GPIO_FMC_D4, GPIO_FMC_D5, GPIO_FMC_D6, GPIO_FMC_D7,
GPIO_FMC_D8, GPIO_FMC_D9, GPIO_FMC_D10, GPIO_FMC_D11,
GPIO_FMC_D12, GPIO_FMC_D13, GPIO_FMC_D14, GPIO_FMC_D15,
/* Address lines */
GPIO_FMC_A0, GPIO_FMC_A1, GPIO_FMC_A2, GPIO_FMC_A3,
GPIO_FMC_A4, GPIO_FMC_A5, GPIO_FMC_A6, GPIO_FMC_A7,
GPIO_FMC_A8, GPIO_FMC_A9, GPIO_FMC_A10, GPIO_FMC_A11,
GPIO_FMC_A12,
/* Control lines */
GPIO_FMC_BA0, /* ba0 */
GPIO_FMC_BA1, /* ba1 */
GPIO_FMC_NBL0, /* ldqm */
GPIO_FMC_NBL1, /* udqm */
GPIO_FMC_SDCLK, /* clk */
GPIO_FMC_SDCKE0_1, /* cke */
GPIO_FMC_SDNWE_2, /* we */
GPIO_FMC_SDNCAS, /* cas */
GPIO_FMC_SDNRAS, /* ras */
GPIO_FMC_SDNE0_1, /* cs0 */
GPIO_FMC_SDNE1_2, /* cs1 */
};
#define NUM_SDRAM_GPIOS (sizeof(g_sdram_config) / sizeof(uint32_t))
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_sdram_memtest
*
* Description:
* Test the SDRAM.
*
****************************************************************************/
#define RAND_A 22695477
#define RAND_C 1
#define TEST_ITERATIONS 16
int stm32_sdram_memtest(void *base, uint32_t size)
{
volatile int iter;
volatile int i;
/* Linear write with linear congruential generator values */
for (iter = 0; iter < TEST_ITERATIONS; iter++)
{
uint32_t x = iter;
/* Write */
for (i = 0; i < size / 4; i++)
{
x = (RAND_A * x) + RAND_C;
((volatile uint32_t *)base)[i] = x;
}
/* Read/verify */
x = iter;
for (i = 0; i < size / 4; i++)
{
x = (RAND_A * x) + RAND_C;
if (((volatile uint32_t *)base)[i] != x)
{
return -1;
}
}
}
/* Scattered byte write at linear congruential generator addresses */
for (iter = 0; iter < TEST_ITERATIONS; iter++)
{
uint32_t x = iter;
/* Write */
for (i = 0; i < 1024 * 1024; i++)
{
x = (RAND_A * x) + RAND_C;
((volatile uint8_t *)base)[x & (size - 1)] = (uint8_t) i;
}
/* Read/verify */
x = iter;
for (i = 0; i < 1024 * 1024; i++)
{
x = (RAND_A * x) + RAND_C;
if (((volatile uint8_t *)base)[x & (size - 1)] != (uint8_t) i)
{
return -1;
}
}
}
return OK;
}
/****************************************************************************
* Name: stm32_sdram_initialize
*
* Description:
* Called from stm32_bringup to initialize external SDRAM access.
* The Axoloti uses an Alliance Memory AS4C4M16SA SDRAM.
*
****************************************************************************/
int stm32_sdram_initialize(void)
{
uint32_t val;
int i;
/* Configure SDRAM GPIOs */
for (i = 0; i < NUM_SDRAM_GPIOS; i++)
{
stm32_configgpio(g_sdram_config[i]);
}
/* Enable the FMC */
stm32_fmc_enable();
/* Go through the SDRAM initialization steps per the reference manual.
* The sdclk period is set to 2 x hclk. That is: 168 /2 = 84 MHz
* This gives a clock period of about 11.9 ns
*/
/* Step 1:
* Program the memory device features into the FMC_SDCRx register. The
* SDRAM clock frequency, RBURST and RPIPE must be programmed in the
* FMC_SDCR1 register.
*/
val = FMC_SDCR_RPIPE_1 | /* rpipe = 1 hclk */
FMC_SDCR_READBURST | /* read burst enabled */
FMC_SDCR_SDCLK_2X | /* sdclk = 2 hclk */
FMC_SDCR_CAS_LATENCY_2 | /* cas latency = 2 cycles */
FMC_SDCR_NBANKS_4 | /* 4 internal banks */
FMC_SDCR_WIDTH_16 | /* width = 16 bits */
FMC_SDCR_ROWS_12 | /* numrows = 12 */
FMC_SDCR_COLS_8; /* numcols = 8 bits */
stm32_fmc_sdram_set_control(1, val);
/* Step 2:
* Program the memory device timing into the FMC_SDTRx register. The
* TRP and TRC timings must be programmed in the FMC_SDTR1 register.
*/
val = FMC_SDTR_TRCD(2) | /* ras to cas delay 21ns => 2x11.90ns */
FMC_SDTR_TRP(2) | /* row precharge 21ns => 2x11.90ns */
FMC_SDTR_TRC(6) | /* row cycle time 63ns => 6x11.9ns */
FMC_SDTR_TRAS(4) | /* row active time 42ns = >4x11.9ns */
FMC_SDTR_TWR(4) | /* write to precharge 42ns => 4x11.9ns */
FMC_SDTR_TXSR(6) | /* exit self refresh 65ns => 6x11.9ns */
FMC_SDTR_TMRD(2); /* load mode register to active 2 clks */
stm32_fmc_sdram_set_timing(1, val);
/* Step 3:
* Set MODE bits to 001 and configure the Target Bank bits (CTB1
* and/or CTB2) in the FMC_SDCMR register to start delivering the clock
* to the memory (SDCKE is driven high).
*/
val = FMC_SDCMR_BANK_1 | FMC_SDCMR_CMD_CLK_ENABLE;
stm32_fmc_sdram_command(val);
/* Step 4:
* Wait during the prescribed delay period. Typical delay is around 100
* μs (refer to the SDRAM datasheet for the required delay after
* power-up).
*/
nxsig_usleep(1000);
/* Step 5:
* Set MODE bits to 010 and configure the Target Bank bits (CTB1
* and/or CTB2) in the FMC_SDCMR register to issue a “Precharge All”
* command.
*/
val = FMC_SDCMR_BANK_1 | FMC_SDCMR_CMD_PALL;
stm32_fmc_sdram_command(val);
/* Step 6:
* Set MODE bits to 011, and configure the Target Bank bits (CTB1
* and/or CTB2) as well as the number of consecutive Auto-refresh
* commands (NRFS) in the FMC_SDCMR register. Refer to the SDRAM
* datasheet for the number of Auto-refresh commands that should be
* issued. Typical number is 8.
*/
val = FMC_SDCMR_NRFS(5) | FMC_SDCMR_BANK_1 | FMC_SDCMR_CMD_AUTO_REFRESH;
stm32_fmc_sdram_command(val);
/* Step 7:
* Configure the MRD field according to your SDRAM device, set the MODE
* bits to '100', and configure the Target Bank bits (CTB1 and/or CTB2)
* in the FMC_SDCMR register to issue a "Load Mode Register" command in
* order to program the SDRAM. In particular:
* a) The CAS latency must be selected following configured value in
* FMC_SDCR1/2 registers
* b) The Burst Length (BL) of 1 must be selected by configuring the
* M[2:0] bits to 000 in the mode register (refer to the SDRAM
* datasheet). If the Mode Register is not the same for both SDRAM
* banks, this step has to be repeated twice, once for each bank,
* and the Target Bank bits set accordingly.
*/
val = FMC_SDCMR_MDR_BURST_LENGTH_2 |
FMC_SDCMR_MDR_BURST_TYPE_SEQUENTIAL |
FMC_SDCMR_MDR_CAS_LATENCY_2 |
FMC_SDCMR_MDR_MODE_NORMAL |
FMC_SDCMR_MDR_WBL_SINGLE | FMC_SDCMR_BANK_1 | FMC_SDCMR_CMD_LOAD_MODE;
stm32_fmc_sdram_command(val);
/* Step 8:
* Program the refresh rate in the FMC_SDRTR register
* The refresh rate corresponds to the delay between refresh cycles. Its
* value must be adapted to SDRAM devices.
*/
stm32_fmc_sdram_set_refresh_rate(1292); /* (64ms/4096rows) x 84MHz) - 20 */
/* Step 9:
* For mobile SDRAM devices, to program the extended mode register it
* should be done once the SDRAM device is initialized: First, a dummy
* read access should be performed while BA1=1 and BA=0 (refer to SDRAM
* address mapping section for BA[1:0] address mapping) in order to select
* the extended mode register instead of Load mode register and then
* program the needed value.
*/
/* Setting EMRS is optional and we're not bothering ... */
/* Enable memory writes for bank 1 */
stm32_fmc_sdram_write_protect(1, false);
/* Wait for the controller to be ready */
stm32_fmc_sdram_wait();
return OK;
}