aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/st/fmc/stm32_fmc2_nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/st/fmc/stm32_fmc2_nand.c')
-rw-r--r--drivers/st/fmc/stm32_fmc2_nand.c112
1 files changed, 89 insertions, 23 deletions
diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c
index b694fff6b..a58a243ad 100644
--- a/drivers/st/fmc/stm32_fmc2_nand.c
+++ b/drivers/st/fmc/stm32_fmc2_nand.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
@@ -22,9 +22,14 @@
#include <lib/mmio.h>
#include <lib/utils_def.h>
+/* Timeout for device interface reset */
+#define TIMEOUT_US_1_MS 1000U
+
/* FMC2 Compatibility */
-#define DT_FMC2_COMPAT "st,stm32mp15-fmc2"
+#define DT_FMC2_EBI_COMPAT "st,stm32mp1-fmc2-ebi"
+#define DT_FMC2_NFC_COMPAT "st,stm32mp1-fmc2-nfc"
#define MAX_CS 2U
+#define MAX_BANK 5U
/* FMC2 Controller Registers */
#define FMC2_BCR1 0x00U
@@ -34,6 +39,7 @@
#define FMC2_PATT 0x8CU
#define FMC2_HECCR 0x94U
#define FMC2_BCHISR 0x254U
+#define FMC2_BCHICR 0x258U
#define FMC2_BCHDSR0 0x27CU
#define FMC2_BCHDSR1 0x280U
#define FMC2_BCHDSR2 0x284U
@@ -79,6 +85,8 @@
#define FMC2_PATT_DEFAULT 0x0A0A0A0AU
/* FMC2_BCHISR register */
#define FMC2_BCHISR_DERF BIT(1)
+/* FMC2_BCHICR register */
+#define FMC2_BCHICR_CLEAR_IRQ GENMASK_32(4, 0)
/* FMC2_BCHDSR0 register */
#define FMC2_BCHDSR0_DUE BIT(0)
#define FMC2_BCHDSR0_DEF BIT(1)
@@ -365,7 +373,7 @@ static int stm32_fmc2_ham_correct(uint8_t *buffer, uint8_t *eccbuffer,
xor_ecc_2b = ecc[1] ^ eccbuffer[1];
xor_ecc_3b = ecc[2] ^ eccbuffer[2];
- xor_ecc.val = 0L;
+ xor_ecc.val = 0U;
xor_ecc.bytes[2] = xor_ecc_3b;
xor_ecc.bytes[1] = xor_ecc_2b;
xor_ecc.bytes[0] = xor_ecc_1b;
@@ -497,6 +505,7 @@ static void stm32_fmc2_hwctl(struct nand_device *nand)
if (nand->ecc.max_bit_corr != FMC2_ECC_HAM) {
mmio_clrbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_WEN);
+ mmio_write_32(fmc2_base() + FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ);
}
stm32_fmc2_set_ecc(true);
@@ -786,22 +795,26 @@ static const struct nand_ctrl_ops ctrl_ops = {
int stm32_fmc2_init(void)
{
- int fmc_node;
- int fmc_subnode = 0;
+ int fmc_ebi_node;
+ int fmc_nfc_node;
+ int fmc_flash_node = 0;
int nchips = 0;
unsigned int i;
void *fdt = NULL;
const fdt32_t *cuint;
struct dt_node_info info;
+ uintptr_t bank_address[MAX_BANK] = { 0, 0, 0, 0, 0 };
+ uint8_t bank_assigned = 0;
+ uint8_t bank;
+ int ret;
if (fdt_get_address(&fdt) == 0) {
return -FDT_ERR_NOTFOUND;
}
- fmc_node = dt_get_node(&info, -1, DT_FMC2_COMPAT);
- if (fmc_node == -FDT_ERR_NOTFOUND) {
- WARN("No FMC2 node found\n");
- return fmc_node;
+ fmc_ebi_node = dt_get_node(&info, -1, DT_FMC2_EBI_COMPAT);
+ if (fmc_ebi_node < 0) {
+ return fmc_ebi_node;
}
if (info.status == DT_DISABLED) {
@@ -817,27 +830,69 @@ int stm32_fmc2_init(void)
stm32_fmc2.clock_id = (unsigned long)info.clock;
stm32_fmc2.reset_id = (unsigned int)info.reset;
- cuint = fdt_getprop(fdt, fmc_node, "reg", NULL);
+ cuint = fdt_getprop(fdt, fmc_ebi_node, "ranges", NULL);
if (cuint == NULL) {
return -FDT_ERR_BADVALUE;
}
- cuint += 2;
-
- for (i = 0U; i < MAX_CS; i++) {
- stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*cuint);
- stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 2));
- stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 4));
- cuint += 6;
+ for (i = 0U; i < MAX_BANK; i++) {
+ bank = fdt32_to_cpu(*cuint);
+ if ((bank >= MAX_BANK) || ((bank_assigned & BIT(bank)) != 0U)) {
+ return -FDT_ERR_BADVALUE;
+ }
+ bank_assigned |= BIT(bank);
+ bank_address[bank] = fdt32_to_cpu(*(cuint + 2));
+ cuint += 4;
}
/* Pinctrl initialization */
- if (dt_set_pinctrl_config(fmc_node) != 0) {
+ if (dt_set_pinctrl_config(fmc_ebi_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ /* Parse NFC controller node */
+ fmc_nfc_node = fdt_node_offset_by_compatible(fdt, fmc_ebi_node,
+ DT_FMC2_NFC_COMPAT);
+ if (fmc_nfc_node < 0) {
+ return fmc_nfc_node;
+ }
+
+ if (fdt_get_status(fmc_nfc_node) == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ cuint = fdt_getprop(fdt, fmc_nfc_node, "reg", NULL);
+ if (cuint == NULL) {
return -FDT_ERR_BADVALUE;
}
+ for (i = 0U; i < MAX_CS; i++) {
+ bank = fdt32_to_cpu(*cuint);
+ if (bank >= MAX_BANK) {
+ return -FDT_ERR_BADVALUE;
+ }
+ stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*(cuint + 1)) +
+ bank_address[bank];
+
+ bank = fdt32_to_cpu(*(cuint + 3));
+ if (bank >= MAX_BANK) {
+ return -FDT_ERR_BADVALUE;
+ }
+ stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 4)) +
+ bank_address[bank];
+
+ bank = fdt32_to_cpu(*(cuint + 6));
+ if (bank >= MAX_BANK) {
+ return -FDT_ERR_BADVALUE;
+ }
+ stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 7)) +
+ bank_address[bank];
+
+ cuint += 9;
+ }
+
/* Parse flash nodes */
- fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) {
+ fdt_for_each_subnode(fmc_flash_node, fdt, fmc_nfc_node) {
nchips++;
}
@@ -846,14 +901,19 @@ int stm32_fmc2_init(void)
return -FDT_ERR_BADVALUE;
}
- fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) {
+ fdt_for_each_subnode(fmc_flash_node, fdt, fmc_nfc_node) {
/* Get chip select */
- cuint = fdt_getprop(fdt, fmc_subnode, "reg", NULL);
+ cuint = fdt_getprop(fdt, fmc_flash_node, "reg", NULL);
if (cuint == NULL) {
WARN("Chip select not well defined\n");
return -FDT_ERR_BADVALUE;
}
+
stm32_fmc2.cs_sel = fdt32_to_cpu(*cuint);
+ if (stm32_fmc2.cs_sel >= MAX_CS) {
+ return -FDT_ERR_BADVALUE;
+ }
+
VERBOSE("NAND CS %i\n", stm32_fmc2.cs_sel);
}
@@ -861,8 +921,14 @@ int stm32_fmc2_init(void)
stm32mp_clk_enable(stm32_fmc2.clock_id);
/* Reset IP */
- stm32mp_reset_assert(stm32_fmc2.reset_id);
- stm32mp_reset_deassert(stm32_fmc2.reset_id);
+ ret = stm32mp_reset_assert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
+ if (ret != 0) {
+ panic();
+ }
+ ret = stm32mp_reset_deassert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
+ if (ret != 0) {
+ panic();
+ }
/* Setup default IP registers */
stm32_fmc2_ctrl_init();