|
37 | 37 |
|
38 | 38 | /* Used for xc3s */ |
39 | 39 | #define USER1 0x02 |
| 40 | +#define USER4 0x23 |
40 | 41 | #define CFG_IN 0x05 |
41 | 42 | #define USERCODE 0x08 |
42 | 43 | #define IDCODE 0x09 |
@@ -278,7 +279,7 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename, |
278 | 279 | SPIInterface(filename, verbose, 256, verify, skip_load_bridge, |
279 | 280 | skip_reset), |
280 | 281 | _device_package(device_package), _spiOverJtagPath(spiOverJtagPath), |
281 | | - _irlen(6), _secondary_filename(secondary_filename) |
| 282 | + _irlen(6), _secondary_filename(secondary_filename), _soj_is_v2(false) |
282 | 283 | { |
283 | 284 | if (prg_type == Device::RD_FLASH) { |
284 | 285 | _mode = Device::READ_MODE; |
@@ -673,11 +674,20 @@ bool Xilinx::post_flash_access() |
673 | 674 |
|
674 | 675 | bool Xilinx::prepare_flash_access() |
675 | 676 | { |
| 677 | + bool ret = false; |
676 | 678 | if (_skip_load_bridge) { |
677 | 679 | printInfo("Skip loading bridge for spiOverjtag"); |
678 | | - return true; |
| 680 | + ret = true; |
| 681 | + } else { |
| 682 | + ret = load_bridge(); |
| 683 | + } |
| 684 | + /* check SpiOverJtag version */ |
| 685 | + if (ret) { |
| 686 | + if (get_spiOverJtag_version() == 2.0f) |
| 687 | + _soj_is_v2 = true; |
| 688 | + printf("SOJ version: %f\n", _soj_is_v2 ? 2.0f : 1.0f); |
679 | 689 | } |
680 | | - return load_bridge(); |
| 690 | + return ret; |
681 | 691 | } |
682 | 692 |
|
683 | 693 | bool Xilinx::load_bridge() |
@@ -714,9 +724,31 @@ bool Xilinx::load_bridge() |
714 | 724 | printError(e.what()); |
715 | 725 | throw std::runtime_error(e.what()); |
716 | 726 | } |
| 727 | + |
717 | 728 | return true; |
718 | 729 | } |
719 | 730 |
|
| 731 | +float Xilinx::get_spiOverJtag_version() |
| 732 | +{ |
| 733 | + uint8_t jtx[6] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 734 | + uint8_t jrx[7]; |
| 735 | + uint8_t rx[6]; |
| 736 | + |
| 737 | + _jtag->shiftIR(USER4, _irlen, Jtag::UPDATE_IR); |
| 738 | + if (_jtag->get_chain_len() > 1) |
| 739 | + _jtag->shiftDR(jtx, NULL, 1, Jtag::SHIFT_DR); |
| 740 | + _jtag->shiftDR(jtx, jrx, 6 * 8); |
| 741 | + _jtag->flush(); |
| 742 | + |
| 743 | + memcpy(rx, &jrx[1], 5); |
| 744 | + rx[5] = '\0'; |
| 745 | + |
| 746 | + float version = atof((const char *)rx); |
| 747 | + if (version == 0.0f) // not supported => 1.0 |
| 748 | + return 1.0f; |
| 749 | + return version; |
| 750 | +} |
| 751 | + |
720 | 752 | void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset, |
721 | 753 | bool unprotect_flash) |
722 | 754 | { |
@@ -2023,6 +2055,10 @@ bool Xilinx::xc2c_flow_program(JedParser *jed) |
2023 | 2055 | int Xilinx::spi_put(uint8_t cmd, |
2024 | 2056 | const uint8_t *tx, uint8_t *rx, uint32_t len) |
2025 | 2057 | { |
| 2058 | + /* SpiOverJtag v2 */ |
| 2059 | + if (_soj_is_v2) |
| 2060 | + return spi_put_v2(cmd, tx, rx, len); |
| 2061 | + |
2026 | 2062 | int xfer_len = len + 1 + ((rx == NULL) ? 0 : 1); |
2027 | 2063 | uint8_t jtx[xfer_len]; |
2028 | 2064 | jtx[0] = McsParser::reverseByte(cmd); |
@@ -2074,6 +2110,10 @@ int Xilinx::spi_put(const uint8_t *tx, uint8_t *rx, uint32_t len) |
2074 | 2110 | int Xilinx::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, |
2075 | 2111 | uint32_t timeout, bool verbose) |
2076 | 2112 | { |
| 2113 | + /* SpiOverJtag v2 */ |
| 2114 | + if (_soj_is_v2) |
| 2115 | + return spi_wait_v2(cmd, mask, cond, timeout, verbose); |
| 2116 | + |
2077 | 2117 | uint8_t rx[2]; |
2078 | 2118 | uint8_t dummy[2]; |
2079 | 2119 | memset(dummy, 0xff, sizeof(dummy)); |
@@ -2108,6 +2148,124 @@ int Xilinx::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, |
2108 | 2148 | } |
2109 | 2149 | } |
2110 | 2150 |
|
| 2151 | +int Xilinx::spi_put_v2(uint8_t cmd, const uint8_t *tx, uint8_t *rx, |
| 2152 | + uint32_t len) |
| 2153 | +{ |
| 2154 | + const uint32_t real_len = len + 1; // rx/tx length + cmd |
| 2155 | + uint32_t kPktLen = real_len + 2 ; // One header and +1 due to the needs of an additional bit/byte |
| 2156 | + uint8_t mode = 0x01; |
| 2157 | + if (real_len > 32) { |
| 2158 | + kPktLen++; // Additional header |
| 2159 | + mode = 0x00; |
| 2160 | + } |
| 2161 | + |
| 2162 | + uint32_t xfer_bit_len = (kPktLen - 1) * 8 + (rx ? 8 : 1); |
| 2163 | + |
| 2164 | + uint8_t jrx[kPktLen]; |
| 2165 | + uint8_t pkt[kPktLen]; |
| 2166 | + uint32_t idx = 0; |
| 2167 | + |
| 2168 | + pkt[idx++] = ((0x1f & real_len) << 3) | ((0x03 & mode) << 1) | 1; |
| 2169 | + if (mode == 0x00) |
| 2170 | + pkt[idx++] = 0xff & (real_len >> 5); |
| 2171 | + |
| 2172 | + pkt[idx++] = McsParser::reverseByte(cmd); |
| 2173 | + if (tx) { |
| 2174 | + for (uint32_t i=0; i < len; i++) |
| 2175 | + pkt[idx++] = McsParser::reverseByte(tx[i]); |
| 2176 | + } else { |
| 2177 | + memset(&pkt[idx], 0, len); |
| 2178 | + idx += len; |
| 2179 | + } |
| 2180 | + |
| 2181 | + /* addr BSCAN user1 */ |
| 2182 | + _jtag->shiftIR(get_ircode(_ircode_map, _user_instruction), NULL, _irlen); |
| 2183 | + _jtag->shiftDR(pkt, (rx == NULL) ? NULL : jrx, xfer_bit_len); |
| 2184 | + _jtag->go_test_logic_reset(); |
| 2185 | + _jtag->flush(); |
| 2186 | + |
| 2187 | + if (_verbose) { |
| 2188 | + for (uint32_t i = 0; i < kPktLen; i++) |
| 2189 | + printf("%02x ", pkt[i]); |
| 2190 | + printf("\n"); |
| 2191 | + } |
| 2192 | + |
| 2193 | + if (rx != NULL) { |
| 2194 | + if (_verbose) { |
| 2195 | + for (uint32_t i = 0; i < kPktLen; i++) |
| 2196 | + printf("%02x ", jrx[i]); |
| 2197 | + printf("\n"); |
| 2198 | + for (uint32_t i = 0; i < kPktLen; i++) |
| 2199 | + printf("%02x ", McsParser::reverseByte(jrx[i])); |
| 2200 | + printf("\n"); |
| 2201 | + } |
| 2202 | + idx = (mode == 0 ? 3 : 2); |
| 2203 | + uint8_t shift = (_jtag->get_chain_len() > 1) ? 2 : 1; |
| 2204 | + for (uint32_t i = 0; i < len; i++) { |
| 2205 | + rx[i] = McsParser::reverseByte(jrx[i + idx] >> shift); |
| 2206 | + if (shift == 1) { |
| 2207 | + rx[i] |= (jrx[i + idx + 1] & 0x01); |
| 2208 | + } else { |
| 2209 | + rx[i] |= ((jrx[i + idx + 1] & 0x01) << 1) | |
| 2210 | + ((jrx[i + idx + 1] & 0x02) >> 1); |
| 2211 | + } |
| 2212 | + if (_verbose) |
| 2213 | + printf("%02x ", rx[i]); |
| 2214 | + } |
| 2215 | + if (_verbose) |
| 2216 | + printf("\n"); |
| 2217 | + } |
| 2218 | + |
| 2219 | + return 0; |
| 2220 | +} |
| 2221 | + |
| 2222 | +int Xilinx::spi_wait_v2(uint8_t cmd, uint8_t mask, uint8_t cond, |
| 2223 | + uint32_t timeout, bool verbose) |
| 2224 | +{ |
| 2225 | + uint8_t rx[2]; |
| 2226 | + uint8_t tx[2]; |
| 2227 | + uint8_t tmp; |
| 2228 | + uint32_t count = 0; |
| 2229 | + uint8_t shift = _jtag->get_chain_len() > 1 ? 2 : 1; |
| 2230 | + |
| 2231 | + tx[0] = (0x2 << 1) | 1; |
| 2232 | + tx[1] = McsParser::reverseByte(cmd); |
| 2233 | + |
| 2234 | + _jtag->shiftIR(get_ircode(_ircode_map, _user_instruction), NULL, _irlen, Jtag::UPDATE_IR); |
| 2235 | + _jtag->shiftDR(tx, NULL, 16, Jtag::SHIFT_DR); |
| 2236 | + |
| 2237 | + tx[0] = tx[1] = 0; |
| 2238 | + |
| 2239 | + do { |
| 2240 | + _jtag->shiftDR(tx, rx, 8*2, Jtag::SHIFT_DR); |
| 2241 | + tmp = (McsParser::reverseByte(rx[0] >> shift)); |
| 2242 | + if (shift == 1) { |
| 2243 | + tmp |= (0x01 & rx[1]); |
| 2244 | + } else { |
| 2245 | + tmp |= ((0x01 & rx[1]) << 1) | |
| 2246 | + (0x01 & (rx[1] >> 1)); |
| 2247 | + } |
| 2248 | + count++; |
| 2249 | + if (count == timeout){ |
| 2250 | + printf("timeout: %x %x %x\n", tmp, rx[0], rx[1]); |
| 2251 | + break; |
| 2252 | + } |
| 2253 | + if (verbose) { |
| 2254 | + printf("%x %x %x %u %02x %02x\n", tmp, mask, cond, count, rx[0], rx[1]); |
| 2255 | + } |
| 2256 | + } while ((tmp & mask) != cond); |
| 2257 | + |
| 2258 | + _jtag->shiftDR(tx, rx, 8*2, Jtag::EXIT1_DR); |
| 2259 | + _jtag->go_test_logic_reset(); |
| 2260 | + |
| 2261 | + if (count == timeout) { |
| 2262 | + printf("%x\n", tmp); |
| 2263 | + std::cout << "wait: Error" << std::endl; |
| 2264 | + return -ETIME; |
| 2265 | + } |
| 2266 | + return 0; |
| 2267 | +} |
| 2268 | + |
2111 | 2269 | void Xilinx::select_flash_chip(xilinx_flash_chip_t flash_chip) { |
2112 | 2270 | switch (flash_chip) { |
2113 | 2271 | case SECONDARY_FLASH: |
|
0 commit comments