From 55219aec07e08fa0d76b1b1b750b79f391e761cf Mon Sep 17 00:00:00 2001 From: Heinrich Toews Date: Tue, 17 Feb 2026 17:58:35 +0100 Subject: [PATCH] save changes Signed-off-by: Heinrich Toews --- .../dts/ti/k3-am623-pfc-750-84xx-wosm.dtsi | 2 +- drivers/mtd/spi-nor/everspin.c | 241 +++++++++--------- labgrid.basesoftware | 2 +- 3 files changed, 117 insertions(+), 128 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am623-pfc-750-84xx-wosm.dtsi b/arch/arm64/boot/dts/ti/k3-am623-pfc-750-84xx-wosm.dtsi index 3c4734e781d1..b3e3a9e75c88 100644 --- a/arch/arm64/boot/dts/ti/k3-am623-pfc-750-84xx-wosm.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am623-pfc-750-84xx-wosm.dtsi @@ -195,7 +195,7 @@ compatible = "jedec,spi-nor"; reg = <0x0>; - spi-tx-bus-width = <1>; + spi-tx-bus-width = <8>; spi-rx-bus-width = <8>; spi-max-frequency = <25000000>; diff --git a/drivers/mtd/spi-nor/everspin.c b/drivers/mtd/spi-nor/everspin.c index 3b8bb66a2070..7e34193ab307 100644 --- a/drivers/mtd/spi-nor/everspin.c +++ b/drivers/mtd/spi-nor/everspin.c @@ -4,193 +4,182 @@ * Copyright (C) 2014, Freescale Semiconductor, Inc. */ -#include #include +#include #include "core.h" -/* Opcodes and Register Definitions */ -#define SPINOR_OP_EVERSPIN_WRAR 0x71 /* Write Any Register */ -#define SPINOR_OP_EVERSPIN_RDAR 0x65 /* Read Any Register */ -#define SPINOR_REG_EVERSPIN_VCR0 0x000000 /* Volatile Config Register 0 */ -#define EVERSPIN_OCTAL_STR_B7 0xB7 /* Octal STR with Data Strobe */ +/* Opcodes and Registers based on patch and successful tests */ +#define SPINOR_OP_MT_WR_ANY_REG 0x81 /* Write volatile register */ +#define SPINOR_REG_MT_CFR0V 0x00 /* Mode configuration */ +#define SPINOR_REG_MT_CFR1V 0x01 /* Dummy cycle configuration */ +#define SPINOR_MT_OCT_STR 0x97 /* Octal STR without DS */ +#define SPINOR_OP_EVERSPIN_WRAR 0x71 + +static int everspin_mram_write_reg(struct spi_nor *nor, u32 addr, u8 val) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_EVERSPIN_WRAR, 1), + SPI_MEM_OP_ADDR(3, addr, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); + + *nor->bouncebuf = val; + spi_nor_write_enable(nor); + return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); +} +#if 0 /** - * everspin_mram_write_reg - Helper to write to volatile/non-volatile registers + * everspin_mram_write_reg - Uses Opcode 0x81 and 3-byte address */ static int everspin_mram_write_reg(struct spi_nor *nor, u32 addr, u8 val) { struct spi_mem_op op = - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_EVERSPIN_WRAR, 1), + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), SPI_MEM_OP_ADDR(3, addr, 1), SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); - nor->bouncebuf[0] = val; - - /* Send WREN before EVERY register write */ + /* RICHTIG: Wert in den Puffer schreiben */ + *nor->bouncebuf = val; + spi_nor_write_enable(nor); - return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); } - -/** - * everspin_mram_unlock - Clears Block Protection bits in Status Register 1 - */ -static int everspin_mram_unlock(struct spi_nor *nor) -{ - struct spi_mem_op op; - int ret; - - /* Send Write Enable (WREN) */ - spi_nor_write_enable(nor); - - /* Write 0x00 to Status Register 1 (Opcode 01h) */ - nor->bouncebuf[0] = 0x00; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); - - ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); - if (ret) - return ret; - - /* Verify: Read back SR1 */ - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), - SPI_MEM_OP_NO_ADDR, - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); - - ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); - if (ret) - return ret; - - /* Check value at pointer address */ - if (nor->bouncebuf[0] & GENMASK(5, 2)) { - dev_err(nor->dev, "Unlock failed! SR1 still 0x%02x\n", nor->bouncebuf[0]); - return -EACCES; - } - - dev_info(nor->dev, "Unlock successful. SR1 is now 0x%02x\n", nor->bouncebuf[0]); - return 0; -} +#endif static void everspin_mram_default_init(struct spi_nor *nor) { struct spi_mem_op op; int ret; - dev_info(nor->dev, "Starting Everspin MRAM initialization (STR Octal)...\n"); + dev_info(nor->dev, "Initializing Everspin MRAM EM008LX (Octal STR)...\n"); - /* 1. Read SR1 and unlock if necessary */ - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), + /* Auf R2 ausführen, um die permanenten (Non-Volatile) Werte zu lesen */ + u8 nv_registers[] = {0x00, 0x01, 0x02, 0x03, 0x04}; + + dev_info(nor->dev, "Dumping Non-Volatile (NV) Registers from R2...\n"); + + for (int i = 0; i < 5; i++) { + /* Opcode 0x65 ist RDAR (Read Any Register) für NV-Bereiche */ + op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(0x65, 1), + SPI_MEM_OP_ADDR(3, i, 1), + SPI_MEM_OP_DUMMY(8, 1), + SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); + + /* Wichtig: Da R2 im Octal-Modus ist, nutzen wir SNOR_PROTO_8_8_8 */ + ret = spi_nor_read_any_reg(nor, &op, SNOR_PROTO_8_8_8); + + if (!ret) + dev_info(nor->dev, "R2 NV-Register 0x%02x: 0x%02x\n", i, *nor->bouncebuf); + else + dev_err(nor->dev, "Failed to read NV-Register 0x%02x\n", i); + } + + /* Auf R2 ausführen, um Werte zu vergleichen */ + u8 registers[] = {0x00, 0x01, 0x02, 0x03, 0x04}; // VCR0 bis VCR4 + for (int i = 0; i < 5; i++) { + op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(0x85, 1), // RDAR + SPI_MEM_OP_ADDR(3, i, 1), + SPI_MEM_OP_DUMMY(8, 1), + SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); + spi_nor_read_any_reg(nor, &op, SNOR_PROTO_8_8_8); + dev_info(nor->dev, "R2 VCR%d (at 0x%02x): 0x%02x\n", i, i, *nor->bouncebuf); + } + + /* RICHTIG: Cast auf (struct spi_mem_op) hinzugefügt */ + op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), SPI_MEM_OP_NO_ADDR, SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); if (!ret) { - u8 sr1 = nor->bouncebuf[0]; - if (sr1 & GENMASK(5, 2)) { - dev_info(nor->dev, "SR1: 0x%02x | Protection detected, unlocking...\n", sr1); - everspin_mram_unlock(nor); - } else { - dev_info(nor->dev, "SR1: 0x%02x | No protection active.\n", sr1); - } + u8 sr1 = *nor->bouncebuf; + dev_info(nor->dev, "Initial SR1: 0x%02x (BP-Bits: 0x%x)\n", + sr1, (sr1 & 0x3c) >> 2); } - /* 2. Switch to Octal Mode using the correct VCR0 address and value */ - dev_info(nor->dev, "Setting VCR0 to Octal STR (0xB7) at address 0x000000...\n"); - - /* 1. Set the Address Width to 3 Bytes (mandatory for 1MB MRAM) */ nor->params->addr_nbytes = 3; - nor->addr_nbytes = 3; + nor->addr_nbytes = 3; -#if 0 - /* IMPORTANT: Use 0xB7 for Octal with Data Strobe */ - ret = everspin_mram_write_reg(nor, SPINOR_REG_EVERSPIN_VCR0, EVERSPIN_OCTAL_STR_B7); + /* Register-Schreibvorgänge (WREN ist in everspin_mram_write_reg enthalten) */ + everspin_mram_write_reg(nor, SPINOR_REG_MT_CFR1V, 0x08); + everspin_mram_write_reg(nor, SPINOR_REG_MT_CFR0V, SPINOR_MT_OCT_STR); + + /* WICHTIG: Da der Chip nun im Octal-Modus ist, müssen wir das + Protokoll für den folgenden RDSR-Check umstellen! */ - if (ret) { - dev_err(nor->dev, "Error writing VCR0 register (%d)\n", ret); + op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_DUMMY(8, 1), /* Octal-SR braucht oft Dummies */ + SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); + + /* Wir lesen jetzt mit dem Protokoll, das der Chip nun erwartet */ + /* Nutze SNOR_PROTO_8_8_8 für Octal STR */ + ret = spi_nor_read_any_reg(nor, &op, SNOR_PROTO_8_8_8); + if (!ret) { + u8 sr1_after = *nor->bouncebuf; + dev_info(nor->dev, "SR1 after Init (Octal Read): 0x%02x\n", sr1_after); } else { - dev_info(nor->dev, "VCR0 successfully set to Octal STR.\n"); - /* Give the chip a few microseconds to settle the new mode */ - udelay(100); - - /* Read SR1 again to see if WEL is cleared after CFR1V write */ - spi_nor_read_any_reg(nor, &op, nor->reg_proto); - dev_info(nor->dev, "SR1 after VCR0 write: 0x%02x\n", nor->bouncebuf[0]); + dev_err(nor->dev, "Failed to read SR1 in Octal mode (ret %d)\n", ret); } -#endif - /* 3. Ensure NO 4-byte mode is activated */ - nor->flags &= ~SNOR_F_4B_OPCODES; - nor->params->set_4byte_addr_mode = NULL; - - /* 3. Synchronize kernel parameters */ nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; nor->params->rdsr_dummy = 8; nor->params->rdsr_addr_nbytes = 0; - nor->params->addr_nbytes = 4; + nor->params->set_4byte_addr_mode = NULL; nor->flags &= ~SNOR_F_HAS_16BIT_SR; nor->params->quad_enable = NULL; - nor->params->addr_nbytes = 3; - // Manche Cadence-Implementationen brauchen ein explizites Byte-Alignment - nor->program_opcode = SPINOR_OP_PP; + /* 1. Protokolle fest auf Octal setzen, damit der Core nicht wechselt */ + nor->reg_proto = SNOR_PROTO_8_8_8; + nor->read_proto = SNOR_PROTO_8_8_8; + nor->write_proto = SNOR_PROTO_8_8_8; - dev_info(nor->dev, "Standard parameters for OSPI controller set.\n"); + /* 2. SFDP Parsing und 4-Byte-Modus komplett unterdrücken */ + nor->flags &= ~SNOR_F_4B_OPCODES; + nor->flags |= SPI_NOR_SKIP_SFDP; // Falls in deiner Kernel-Version verfügbar + nor->params->set_4byte_addr_mode = NULL; + + /* 3. WICHTIG: Die Dummy-Zyklen für das MTD-System global setzen */ + nor->params->rdsr_dummy = 8; + + dev_info(nor->dev, "MRAM initialized. Protocols forced to Octal.\n"); } +static int everspin_mram_late_init(struct spi_nor *nor) +{ + /* Read: Octal STR (1-8-8) */ + nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_1_8_8; + + /* Versuche SPINOR_OP_READ_1_8_8 (meist 0xFD) */ + spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_1_8_8], + 0, 8, 0xFD, SNOR_PROTO_1_8_8); + + /* Write: Octal STR (1-8-8) */ + nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_1_8_8; + spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_1_8_8], + 0x12, SNOR_PROTO_1_8_8); + + return 0; +} #if 0 static int everspin_mram_late_init(struct spi_nor *nor) { - dev_info(nor->dev, "Configuring Octal opcodes for Read/Write...\n"); - - /* Read Settings: 1-8-8 STR */ + /* Read/Write Settings: Octal STR (1-8-8) */ nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_1_8_8; spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_1_8_8], 0, 8, SPINOR_OP_READ_1_8_8, SNOR_PROTO_1_8_8); - /* Write Settings: 1-8-8 STR */ nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_1_8_8; spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_1_8_8], SPINOR_OP_PP_1_8_8, SNOR_PROTO_1_8_8); - /* In late_init: Versuchen Sie 0x82 statt 0x12, falls vorhanden */ - nor->params->page_programs[SNOR_CMD_PP_1_8_8].opcode = 0x12; - - dev_info(nor->dev, "Everspin MRAM successfully initialized in Octal mode.\n"); return 0; } #endif -static int everspin_mram_late_init(struct spi_nor *nor) -{ - dev_info(nor->dev, "Configuring Hybrid Mode: Octal Read / Single Write...\n"); - - /* 1. Fast Read Settings: Octal STR (1-8-8) */ - nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_1_8_8; - spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_1_8_8], - 0, 8, SPINOR_OP_READ_1_8_8, SNOR_PROTO_1_8_8); - - /* 2. Stable Write Settings: Force Single-SPI (Standard Page Program) */ - /* We disable Octal-Write and enable standard PP */ - nor->params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_8_8; - nor->params->hwcaps.mask |= SNOR_HWCAPS_PP; - - /* Standard Page Program uses Opcode 02h and Protocol 1-1-1 */ - spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP], - SPINOR_OP_PP, - SNOR_PROTO_1_1_1); - - dev_info(nor->dev, "Hybrid Mode initialized: Read 8-8-8, Write 1-1-1.\n"); - return 0; -} - static const struct spi_nor_fixups everspin_mram_fixups = { .default_init = everspin_mram_default_init, .late_init = everspin_mram_late_init, diff --git a/labgrid.basesoftware b/labgrid.basesoftware index 21cbed93bcfb..705c63ebb290 160000 --- a/labgrid.basesoftware +++ b/labgrid.basesoftware @@ -1 +1 @@ -Subproject commit 21cbed93bcfb85f5a1a7f87e6fa2798e907651b9 +Subproject commit 705c63ebb290e1da8f8de0cc4d5ef5547e4528f0