blob: 7482c5c103eb78318a845cc67b005d4c4653e513 [file] [log] [blame]
Nico Huber8d0f4652024-05-04 18:52:51 +02001/*
2 * This file is part of the flashprog project.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <stdbool.h>
16#include "flash.h"
17#include "chipdrivers.h"
18#include "programmer.h"
19#include "spi_command.h"
20#include "spi.h"
21
22static int spi_enter_exit_4ba(struct flashctx *const flash, const bool enter)
23{
24 const unsigned char cmd = enter ? JEDEC_ENTER_4_BYTE_ADDR_MODE : JEDEC_EXIT_4_BYTE_ADDR_MODE;
25 int ret = 1;
26
27 if (flash->chip->feature_bits & FEATURE_4BA_ENTER)
28 ret = spi_send_command(flash, sizeof(cmd), 0, &cmd, NULL);
29 else if (flash->chip->feature_bits & FEATURE_4BA_ENTER_WREN)
30 ret = spi_simple_write_cmd(flash, cmd, 0);
31 else if (flash->chip->feature_bits & FEATURE_4BA_ENTER_EAR7)
32 ret = spi_set_extended_address(flash, enter ? 0x80 : 0x00);
33
34 if (!ret)
35 flash->in_4ba_mode = enter;
36 return ret;
37}
38
39static int spi_enter_4ba(struct flashctx *const flash)
40{
41 return spi_enter_exit_4ba(flash, true);
42}
43
44static int spi_exit_4ba(struct flashctx *flash)
45{
46 return spi_enter_exit_4ba(flash, false);
47}
48
Nico Huber930d4212024-05-04 18:59:15 +020049static int spi_prepare_4ba(struct flashctx *const flash)
Nico Huber8d0f4652024-05-04 18:52:51 +020050{
Nico Huber8d0f4652024-05-04 18:52:51 +020051 flash->address_high_byte = -1;
52 flash->in_4ba_mode = false;
53
54 /* Be careful about 4BA chips and broken masters */
55 if (flash->chip->total_size > 16 * 1024 && spi_master_no_4ba_modes(flash)) {
56 /* If we can't use native instructions, bail out */
57 if ((flash->chip->feature_bits & FEATURE_4BA_NATIVE) != FEATURE_4BA_NATIVE
58 || !spi_master_4ba(flash)) {
59 msg_cerr("Programmer doesn't support this chip. Aborting.\n");
60 return 1;
61 }
62 }
63
64 /* Enable/disable 4-byte addressing mode if flash chip supports it */
65 if (flash->chip->feature_bits & (FEATURE_4BA_ENTER | FEATURE_4BA_ENTER_WREN | FEATURE_4BA_ENTER_EAR7)) {
66 int ret;
67 if (spi_master_4ba(flash))
68 ret = spi_enter_4ba(flash);
69 else
70 ret = spi_exit_4ba(flash);
71 if (ret) {
72 msg_cerr("Failed to set correct 4BA mode! Aborting.\n");
73 return 1;
74 }
75 }
76
77 return 0;
78}
Nico Huber930d4212024-05-04 18:59:15 +020079
Nico Huber0c9af0a2024-05-05 12:20:22 +020080static int spi_prepare_quad_io(struct flashctx *const flash)
81{
82 if (!spi_master_quad(flash))
83 return 0;
84
85 /* Check QE bit if present */
86 if (flash->chip->reg_bits.qe.reg != INVALID_REG) {
87 const struct reg_bit_info qe = flash->chip->reg_bits.qe;
88 uint8_t reg_val;
89
90 if (spi_read_register(flash, qe.reg, &reg_val)) {
91 msg_cwarn("Failed read chip register!\n");
92 reg_val = 0;
93 }
94 if (!(reg_val & 1 << qe.bit_index)) {
95 msg_cinfo("Quad-enable (QE) bit is unknown or unset, disabling quad i/o.\n");
96 flash->chip->feature_bits &= ~FEATURE_ANY_QUAD;
97 } else {
98 msg_cdbg("Quad-enable (QE) bit is set.\n");
99 }
100 }
101
102 return 0;
103}
104
Nico Huber930d4212024-05-04 18:59:15 +0200105int spi_prepare_io(struct flashctx *const flash, const enum preparation_steps prep)
106{
107 if (prep != PREPARE_FULL)
108 return 0;
109
110 int ret = spi_prepare_4ba(flash);
111 if (ret)
112 return ret;
113
Nico Huber0c9af0a2024-05-05 12:20:22 +0200114 ret = spi_prepare_quad_io(flash);
115 if (ret)
116 return ret;
117
Nico Huber930d4212024-05-04 18:59:15 +0200118 return 0;
119}
120
121void spi_finish_io(struct flashctx *const flash)
122{
123}