@@ -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>;
|
||||
|
||||
|
||||
+115
-126
@@ -4,193 +4,182 @@
|
||||
* Copyright (C) 2014, Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mtd/spi-nor.h>
|
||||
#include <linux/delay.h>
|
||||
#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,
|
||||
|
||||
+1
-1
Submodule labgrid.basesoftware updated: 21cbed93bc...705c63ebb2
Reference in New Issue
Block a user