Skip to content

Commit 3be170f

Browse files
MichaelBellGadgetoid
authored andcommitted
ports/rp2: Compute QMI timing based on system clock.
Signed-off-by: Mike Bell <[email protected]>
1 parent 4cc5ad9 commit 3be170f

File tree

1 file changed

+36
-29
lines changed

1 file changed

+36
-29
lines changed

ports/rp2/rp2_psram.c

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ void __no_inline_not_in_flash_func(psram_set_qmi_timing)() {
1212
;
1313
}
1414

15-
if (clock_get_hz(clk_sys) > 133000000) {
16-
// For > 133 MHz
17-
qmi_hw->m[0].timing = 0x40000202;
18-
} else {
19-
// For <= 133 MHz
20-
qmi_hw->m[0].timing = 0x40000101;
21-
}
15+
// Use the minimum divisor assuming a 133MHz flash.
16+
// RX delay equal to the divisor means sampling at the same time as the next falling edge of SCK after the
17+
// falling edge that generated the data. This is pretty tight at 133MHz but seems to work with the Winbond flash chips.
18+
const int max_flash_freq = 133000000;
19+
const int divisor = (clock_get_hz(clk_sys) + max_flash_freq - 1) / max_flash_freq;
20+
const int rxdelay = divisor;
21+
qmi_hw->m[0].timing = (1 << QMI_M0_TIMING_COOLDOWN_LSB) |
22+
rxdelay << QMI_M1_TIMING_RXDELAY_LSB |
23+
divisor << QMI_M1_TIMING_CLKDIV_LSB;
2224

2325
// Force a read through XIP to ensure the timing is applied
2426
volatile uint32_t *ptr = (volatile uint32_t *)0x14000000;
@@ -126,30 +128,35 @@ size_t __no_inline_not_in_flash_func(psram_init)(uint cs_pin) {
126128
;
127129
}
128130

129-
if (clock_get_hz(clk_sys) >= 120000000) {
130-
// Set PSRAM timing for APS6404:
131-
// - Max select assumes a sys clock speed >= 120MHz
132-
// - Min deselect assumes a sys clock speed <= 305MHz
133-
// - Clkdiv of 2 is OK up to 266MHz.
134-
qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB |
135-
QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB |
136-
15 << QMI_M1_TIMING_MAX_SELECT_LSB |
137-
5 << QMI_M1_TIMING_MIN_DESELECT_LSB |
138-
3 << QMI_M1_TIMING_RXDELAY_LSB |
139-
2 << QMI_M1_TIMING_CLKDIV_LSB;
140-
} else {
141-
// Set PSRAM timing for APS6404:
142-
// - Max select assumes a sys clock speed >= 120MHz
143-
// - Min deselect assumes a sys clock speed <= 138MHz
144-
// - Clkdiv of 1 is OK up to 133MHz.
145-
qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB |
146-
QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB |
147-
15 << QMI_M1_TIMING_MAX_SELECT_LSB |
148-
2 << QMI_M1_TIMING_MIN_DESELECT_LSB |
149-
2 << QMI_M1_TIMING_RXDELAY_LSB |
150-
1 << QMI_M1_TIMING_CLKDIV_LSB;
131+
// Set PSRAM timing for APS6404
132+
//
133+
// Using an rxdelay equal to the divisor isn't enough when running the APS6404 close to 133MHz.
134+
// So: don't allow running at divisor 1 above 100MHz (because delay of 2 would be too late),
135+
// and add an extra 1 to the rxdelay if the divided clock is > 100MHz (i.e. sys clock > 200MHz).
136+
const int max_psram_freq = 133000000;
137+
const int clock_hz = clock_get_hz(clk_sys);
138+
int divisor = (clock_hz + max_psram_freq - 1) / max_psram_freq;
139+
if (divisor == 1 && clock_hz > 100000000) {
140+
divisor = 2;
141+
}
142+
int rxdelay = divisor;
143+
if (clock_hz / divisor > 100000000) {
144+
rxdelay += 1;
151145
}
152146

147+
// - Max select must be <= 8us. The value is given in multiples of 64 system clocks.
148+
// - Min deselect must be >= 18ns. The value is given in system clock cycles - ceil(divisor / 2).
149+
const int clock_period_fs = 1000000000000000ll / clock_hz;
150+
const int max_select = (125 * 1000000) / clock_period_fs; // 125 = 8000ns / 64
151+
const int min_deselect = (18 * 1000000 + (clock_period_fs - 1)) / clock_period_fs - (divisor + 1) / 2;
152+
153+
qmi_hw->m[1].timing = 1 << QMI_M1_TIMING_COOLDOWN_LSB |
154+
QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB |
155+
max_select << QMI_M1_TIMING_MAX_SELECT_LSB |
156+
min_deselect << QMI_M1_TIMING_MIN_DESELECT_LSB |
157+
rxdelay << QMI_M1_TIMING_RXDELAY_LSB |
158+
divisor << QMI_M1_TIMING_CLKDIV_LSB;
159+
153160
// Set PSRAM commands and formats
154161
qmi_hw->m[1].rfmt =
155162
QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | \

0 commit comments

Comments
 (0)