@@ -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