@@ -12,13 +12,15 @@ void __no_inline_not_in_flash_func(psram_set_qmi_timing)() {
12
12
;
13
13
}
14
14
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 ;
22
24
23
25
// Force a read through XIP to ensure the timing is applied
24
26
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) {
126
128
;
127
129
}
128
130
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 ;
151
145
}
152
146
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
+
153
160
// Set PSRAM commands and formats
154
161
qmi_hw -> m [1 ].rfmt =
155
162
QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | \
0 commit comments