Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(misc/ssi_psram): Add octal psram (QEMU-231) #112

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 118 additions & 4 deletions hw/misc/ssi_psram.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,34 @@
#define PSRAM_ID_MFG 0x0d
#define PSRAM_ID_KGD 0x5d

#define CMD_READ_OCTAL_REG 0x4040
#define CMD_WRITE_OCTAL_REG 0xc0c0

#define MR0_DRIVE_STRENGHT_HALF ((uint8_t)0b01 << 0)
#define MR0_RD_LATENCY_CODE ((uint8_t)0b010 << 2)
#define MR0_RD_LT_VARIABLE ((uint8_t)0b0 << 5)

#define MR1_VENDOR_ID ((uint8_t)0b01101 << 0)
#define MR1_NO_ULP ((uint8_t)0b0 << 5)

#define MR2_DENSITY_MAPPING_64MB ((uint8_t)0b011 << 0)
#define MR2_DEVICE_ID_3_GEN ((uint8_t)0b10 << 3)
#define MR2_GOOD_DIE_BIT_PASS ((uint8_t)0b1 << 7)

#define MR3_SRF_FAST_REFRESH ((uint8_t)0b1 << 5)
#define MR3_OP_VOLTAGE_1V8 ((uint8_t)0b0 << 6)
#define MR3_RBX_NOT_SUPPORTED ((uint8_t)0b0 << 7)

#define MR4_PASR_64MB ((uint8_t)0b000 << 0)
#define MR4_FAST_REFRESH ((uint8_t)0b0 << 3)
#define MR4_WRITE_LATENCY_5 ((uint8_t)0b010 << 4)

#define MR6_ULP_HALF_SLEEP ((uint8_t)0xF0 << 0)

#define MR8_32BYTE_BURST ((uint8_t)0b01 << 0)
#define MR8_HYBRID_BURST ((uint8_t)0b1 << 2)
#define MR8_RBX_READ_DISABLE ((uint8_t)0b0 << 3)

#define FAKE_16MB_ID 0x6a
#define FAKE_32MB_ID 0x8e

Expand All @@ -44,7 +72,7 @@ static int get_eid_by_size(uint32_t size_mbytes) {
}
}

static uint32_t psram_read(SsiPsramState *s)
static uint32_t psram_quad_read(SsiPsramState *s)
{
uint32_t result = 0;
if (s->command == CMD_READ_ID) {
Expand All @@ -62,19 +90,91 @@ static uint32_t psram_read(SsiPsramState *s)
return result;
}

static void psram_write(SsiPsramState *s, uint32_t value)
static void psram_quad_write(SsiPsramState *s, uint32_t value)
{
if (s->byte_count == s->dummy) {
s->command = value;
}
s->byte_count++;
}

static uint32_t psram_octal_read(SsiPsramState *s)
{
uint32_t result = 0;
if (s->byte_count < 7) return result;

if (s->command == CMD_READ_OCTAL_REG) {
// Odd read bytes correspond to the next register
switch (s->addr)
{
case 0:
result = (s->byte_count % 2) ? s->mr1 : s->mr0;
break;
case 1:
result = (s->byte_count % 2) ? s->mr2 : s->mr1;
break;
case 2:
result = (s->byte_count % 2) ? s->mr3 : s->mr2;
break;
case 3:
result = (s->byte_count % 2) ? s->mr4 : s->mr3;
break;
case 4:
result = (s->byte_count % 2) ? s->mr8 : s->mr4;
break;
case 8:
result = (s->byte_count % 2) ? s->mr0 : s->mr8;
break;
default:
// Should not happen
break;
}
}
return result;
}

static void psram_octal_write(SsiPsramState *s, uint32_t value)
{
// Save the transfer to the state
if (s->byte_count == 0) {
s->command = value << s->byte_count;
} else if (s->byte_count == 1) {
s->command |= value << (s->byte_count * 8);
} else if (s->byte_count == (s->dummy + 2)) { // addr
s->addr = value;
}
s->byte_count++;

// save the write command to the corresponding register
if (s->byte_count == 7 && s->command == CMD_WRITE_OCTAL_REG) {
switch (s->addr)
{
case 0:
s->mr0 = value;
break;
case 4:
s->mr4 = value;
break;
case 8:
s->mr8 = value;
break;
default:
// Should not happen
break;
}
}
}

static uint32_t psram_transfer(SSIPeripheral *dev, uint32_t value)
{
SsiPsramState *s = SSI_PSRAM(dev);
psram_write(s, value);
return psram_read(s);
if (s->is_octal) {
psram_octal_write(s, value);
return psram_octal_read(s);
} else {
psram_quad_write(s, value);
return psram_quad_read(s);
}
}

static int psram_cs(SSIPeripheral *ss, bool select)
Expand All @@ -84,6 +184,7 @@ static int psram_cs(SSIPeripheral *ss, bool select)
if (!select) {
s->byte_count = 0;
s->command = -1;
s->addr = -1;
}
return 0;
}
Expand All @@ -96,12 +197,25 @@ static void psram_realize(SSIPeripheral *ss, Error **errp)
error_report("[PSRAM] Invalid size %dMB for the PSRAM", s->size_mbytes);
}

/* Set the default MR values for the octal psram (ref: Datasheet APS6408L_OBMx) */
s->mr0 = MR0_RD_LT_VARIABLE | MR0_RD_LATENCY_CODE | MR0_DRIVE_STRENGHT_HALF;
s->mr1 = MR1_NO_ULP | MR1_VENDOR_ID;
s->mr2 = MR2_GOOD_DIE_BIT_PASS | MR2_DEVICE_ID_3_GEN | MR2_DENSITY_MAPPING_64MB;
s->mr3 = MR3_RBX_NOT_SUPPORTED | MR3_OP_VOLTAGE_1V8 | MR3_SRF_FAST_REFRESH;
s->mr4 = MR4_WRITE_LATENCY_5 | MR4_FAST_REFRESH | MR4_PASR_64MB;
s->mr8 = MR8_RBX_READ_DISABLE | MR8_HYBRID_BURST | MR8_32BYTE_BURST;

if (s->is_octal) {
s->dummy = 3;
}

/* Allocate the actual array that will act as a vritual RAM */
const uint32_t size_bytes = s->size_mbytes * 1024 * 1024;
memory_region_init_ram(&s->data_mr, OBJECT(s), "psram.memory_region", size_bytes, &error_fatal);
}

static Property psram_properties[] = {
DEFINE_PROP_BOOL("is_octal", SsiPsramState, is_octal, false),
DEFINE_PROP_UINT32("size_mbytes", SsiPsramState, size_mbytes, 4),
DEFINE_PROP_UINT32("dummy", SsiPsramState, dummy, 1),
DEFINE_PROP_END_OF_LIST(),
Expand Down
31 changes: 26 additions & 5 deletions hw/ssi/esp32s3_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,27 @@ static uint64_t esp32s3_spi_read(void *opaque, hwaddr addr, unsigned int size)
case A_SPI_MEM_RD_STATUS:
r = s->mem_rd_st;
break;
case A_SPI_MEM_MISC:
r = s->misc;
break;
case A_SPI_MEM_CACHE_FCTRL:
r = s->cache_fctrl;
break;
case A_SPI_MEM_FSM:
r = s->fsm;
break;
case A_SPI_MEM_W0...A_SPI_MEM_W15:
r = s->data_reg[(addr - A_SPI_MEM_W0) / sizeof(uint32_t)];
break;
case A_SPI_MEM_SUS_STATUS:
r = s->mem_sus_st;
break;
case A_SPI_MEM_MISC:
r = s->misc;
case A_SPI_MEM_DDR_CTRL:
r = s->ddr_ctrl;
break;
case A_SPI_MEM_CLOCK_GATE:
r = s->clock_gate;
break;
default:
#if SPI1_WARNING
warn_report("[SPI1] Unsupported read to 0x%lx", addr);
Expand Down Expand Up @@ -407,22 +420,30 @@ static void esp32s3_spi_write(void *opaque, hwaddr addr,
case A_SPI_MEM_RD_STATUS:
s->mem_rd_st = wvalue;
break;
case A_SPI_MEM_MISC:
s->misc = wvalue;
break;
case A_SPI_MEM_CACHE_FCTRL:
s->cache_fctrl = wvalue;
break;
case A_SPI_MEM_W0...A_SPI_MEM_W15:
s->data_reg[(addr - A_SPI_MEM_W0) / sizeof(uint32_t)] = wvalue;
break;
case A_SPI_MEM_SUS_STATUS:
s->mem_sus_st = wvalue;
break;
case A_SPI_MEM_MISC:
s->misc = value;
case A_SPI_MEM_DDR_CTRL:
s->ddr_ctrl = wvalue;
break;
case A_SPI_MEM_CLOCK_GATE:
s->clock_gate = wvalue;
break;
default:
#if SPI1_WARNING
warn_report("[SPI1] Unsupported write to 0x%lx (%08lx)", addr, value);
#endif
break;
}

}


Expand Down
10 changes: 10 additions & 0 deletions include/hw/misc/ssi_psram.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@ typedef struct SsiPsramState {
uint32_t size_mbytes;
uint32_t dummy;
int command;
int addr;
int byte_count;
bool is_octal;

uint8_t mr0;
uint8_t mr1;
uint8_t mr2;
uint8_t mr3;
uint8_t mr4;
uint8_t mr8;

MemoryRegion data_mr;
} SsiPsramState;

Expand Down
29 changes: 27 additions & 2 deletions include/hw/ssi/esp32s3_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ typedef struct ESP32S3SpiState {
uint32_t mem_miso_len;
uint32_t mem_mosi_len;
uint32_t mem_rd_st;
uint32_t misc;
uint32_t cache_fctrl;
uint32_t fsm;
uint32_t data_reg[ESP32S3_SPI_BUF_WORDS];
uint32_t mem_sus_st;
uint32_t misc;
uint32_t ddr_ctrl;
uint32_t clock_gate;
ESP32S3XtsAesState *xts_aes;
} ESP32S3SpiState;

Expand Down Expand Up @@ -156,6 +160,9 @@ REG32(SPI_MEM_CACHE_FCTRL, 0x03C)
FIELD(SPI_MEM_CACHE_FCTRL, FDIN_DUAL , 3, 1)
FIELD(SPI_MEM_CACHE_FCTRL, CACHE_USR_ADDR_4BYTE, 1, 1)

REG32(SPI_MEM_FSM, 0x054)
FIELD(SPI_MEM_FSM, SPI_FSM, 0, 3)

REG32(SPI_MEM_W0, 0x058)
FIELD(SPI_MEM_W0, BUF0, 0, 32)

Expand Down Expand Up @@ -269,7 +276,25 @@ REG32(SPI_MEM_INT_ST, 0x0CC)
FIELD(SPI_MEM_INT_ST, PES_END_INT_ST, 1, 1)
FIELD(SPI_MEM_INT_ST, PER_END_INT_ST, 0, 1)

REG32(SPI_MEM_CLOCK_GATE, 0x0DC)
REG32(SPI_MEM_DDR_CTRL, 0x0E0)
FIELD(SPI_MEM_DDR_CTRL, FMEM_HYPERBUS_CA, 30, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_OCTA_RAM_ADDR, 29, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_CLK_DIFF_INV, 28, 1)
FIELD(SPI_MEM_DDR_CTRL, SPI_FMEM_HYPERBUS_DUMMY_2X, 27, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_DQS_CA_IN, 26, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_HYPERBUS_MODE, 25, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_CLK_DIFF_EN, 24, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_DDR_DQS_LOOP_MODE, 22, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_DDR_DQS_LOOP, 21, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_USR_DDR_DQS_THD, 14, 7)
FIELD(SPI_MEM_DDR_CTRL, FMEM_OUTMINBYTELEN, 5, 7)
FIELD(SPI_MEM_DDR_CTRL, FMEM_DDR_CMD_DIS, 4, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_DDR_WDAT_SWP, 3, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_DDR_RDAT_SWP, 2, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_VAR_DUMMY, 1, 1)
FIELD(SPI_MEM_DDR_CTRL, FMEM_DDR_EN, 0, 1)

REG32(SPI_MEM_CLOCK_GATE, 0x0E8)
FIELD(SPI_MEM_CLOCK_GATE, CLK_EN, 0, 1)

REG32(SPI_MEM_DATE, 0x3FC)
Expand Down