blob: 55f98cfdaab8ad182b8aca8f0441efc2f120a684 [file] [log] [blame]
Nico Huber706c37f2023-02-11 18:28:33 +01001/*
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 <stdio.h>
16#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19#include <getopt.h>
20#include <limits.h>
21
22#include "libflashprog.h"
23#include "chipdrivers.h"
24#include "flash.h"
25#include "cli.h"
26
27enum settings {
28 QUAD_ENABLE,
29};
30
31static const struct reg_bit_info *get_bit_info(
32 const struct flashctx *flash, enum settings setting)
33{
34 switch (setting) {
35 case QUAD_ENABLE:
36 return &flash->chip->reg_bits.qe;
37 default:
38 return NULL;
39 }
40}
41
42static int config_get(const struct flashctx *flash, enum settings setting)
43{
44 const struct reg_bit_info *const bit = get_bit_info(flash, setting);
45 uint8_t reg_val;
46
47 if (!bit)
48 return 1;
49
50 const int ret = spi_read_register(flash, bit->reg, &reg_val);
51 if (ret)
52 return 1;
53
54 printf("%u\n", reg_val >> bit->bit_index & 1);
55 return 0;
56}
57
58static int config_set(const struct flashctx *flash, enum settings setting, unsigned int value)
59{
60 const struct reg_bit_info *const bit = get_bit_info(flash, setting);
61 uint8_t reg_val;
62 int ret;
63
64 if (!bit)
65 return 1;
66
67 ret = spi_read_register(flash, bit->reg, &reg_val);
68 if (ret)
69 return 1;
70
71 reg_val &= ~(1 << bit->bit_index);
72 reg_val |= (value & 1) << bit->bit_index;
73
74 ret = spi_write_register(flash, bit->reg, reg_val, default_wrsr_target(flash));
75 if (ret)
76 return 1;
77
78 return 0;
79}
80
81static void usage(const char *const name, const char *const msg)
82{
83 if (msg)
84 fprintf(stderr, "\nError: %s\n", msg);
85
86 fprintf(stderr, "\nUsage: %s -p <programmername>[:<parameters] [-c <chipname>]\n"
87 "\t\t\t\t[-V[V[V]]] [-o <logfile>]\n"
88 "\t\t\t\t([--get] <setting>|--set [--volatile] <setting> <value>)\n",
89 name);
90 fprintf(stderr, "\nWhere <setting> can be\n\n"
91 " qe|quad-enable Quad-Enable (QE) bit\n"
92 "\nand <value> can be `true', `false', or a number.\n"
93 "\nBy default, the setting is queried (--get).\n"
94 "\n");
95 exit(1);
96}
97
98static int parse_setting(const char *const setting)
99{
100 if (!strcmp(setting, "qe") ||
101 !strcmp(setting, "quad-enable"))
102 return QUAD_ENABLE;
103 return -1;
104}
105
106static int parse_value(const char *const value)
107{
108 if (!strcmp(value, "true"))
109 return 1;
110 if (!strcmp(value, "false"))
111 return 0;
112
113 char *endptr;
114 const unsigned long i = strtoul(value, &endptr, 0);
115 if (value[0] && !endptr[0] && i <= INT_MAX)
116 return i;
117
118 return -1;
119}
120
121int flashprog_config_main(int argc, char *argv[])
122{
123 static const char optstring[] = "+p:c:Vo:h";
124 static const struct option long_options[] = {
125 {"programmer", 1, NULL, 'p'},
126 {"chip", 1, NULL, 'c'},
127 {"verbose", 0, NULL, 'V'},
128 {"output", 1, NULL, 'o'},
129 {"help", 0, NULL, 'h'},
130 {"get", 0, NULL, OPTION_CONFIG_GET},
131 {"set", 0, NULL, OPTION_CONFIG_SET},
132 {"volatile", 0, NULL, OPTION_CONFIG_VOLATILE},
133 {NULL, 0, NULL, 0},
134 };
135
136 unsigned int ops = 0;
137 int ret, opt, option_index;
138 struct log_args log_args = { FLASHPROG_MSG_INFO, FLASHPROG_MSG_DEBUG2, NULL };
139 struct flash_args flash_args = { 0 };
140 bool get = false, set = false, volat1le = false;
141
142 while ((opt = getopt_long(argc, argv, optstring,
143 long_options, &option_index)) != EOF) {
144 switch (opt) {
145 case 'V':
146 case 'o':
147 ret = cli_parse_log_args(&log_args, opt, optarg);
148 if (ret == 1)
149 usage(argv[0], NULL);
150 else if (ret)
151 goto free_ret;
152 break;
153 case 'p':
154 case 'c':
155 ret = cli_parse_flash_args(&flash_args, opt, optarg);
156 if (ret == 1)
157 usage(argv[0], NULL);
158 else if (ret)
159 goto free_ret;
160 break;
161 case OPTION_CONFIG_GET:
162 get = true;
163 ++ops;
164 break;
165 case OPTION_CONFIG_SET:
166 set = true;
167 ++ops;
168 break;
169 case OPTION_CONFIG_VOLATILE:
170 volat1le = true;
171 break;
172 case '?':
173 case 'h':
174 usage(argv[0], NULL);
175 break;
176 }
177 }
178
179 if (!ops) {
180 get = true;
181 ++ops;
182 }
183 if (ops > 1)
184 usage(argv[0], "Only one operation may be specified.");
185
186 if (!flash_args.prog_name)
187 usage(argv[0], "No programmer specified.");
188
189 if (get && volat1le)
190 usage(argv[0], "`--volatile' may only be specified for `--set'.");
191 if (get && optind != argc - 1)
192 usage(argv[0], "`--get' requires exactly one argument.");
193 if (set && optind != argc - 2)
194 usage(argv[0], "`--set' requires exactly two arguments.");
195
196 const int setting = parse_setting(argv[optind]);
197 if (setting < 0) {
198 fprintf(stderr, "\nError: Unknown <setting> argument `%s'.\n", argv[optind]);
199 usage(argv[0], NULL);
200 }
201 int value = 0;
202 if (set) {
203 value = parse_value(argv[optind + 1]);
204 if (value < 0) {
205 fprintf(stderr, "\nError: Cannot parse value `%s'.\n", argv[optind + 1]);
206 usage(argv[0], NULL);
207 }
208 }
209
210 struct flashprog_programmer *prog;
211 struct flashprog_flashctx *flash;
212 ret = 1;
213
214 if (cli_init())
215 goto free_ret;
216
217 if (log_args.logfile && open_logfile(log_args.logfile))
218 goto free_ret;
219 verbose_screen = log_args.screen_level;
220 verbose_logfile = log_args.logfile_level;
221 start_logging();
222
223 if (flashprog_programmer_init(&prog, flash_args.prog_name, flash_args.prog_args))
224 goto free_ret;
225 if (flashprog_flash_probe(&flash, prog, flash_args.chip)) {
226 fprintf(stderr, "No EEPROM/flash device found.\n");
227 goto shutdown_ret;
228 }
229
230 if (flash->chip->bustype != BUS_SPI || flash->chip->spi_cmd_set != SPI25) {
231 fprintf(stderr, "Only SPI25 flash chips are supported.\n");
232 goto shutdown_ret;
233 }
234
235 flashprog_flag_set(flash, FLASHPROG_FLAG_NON_VOLATILE_WRSR, set && !volat1le);
236
237 if (get)
238 ret = config_get(flash, setting);
239
240 if (set)
241 ret = config_set(flash, setting, value);
242
243 flashprog_flash_release(flash);
244shutdown_ret:
245 flashprog_programmer_shutdown(prog);
246free_ret:
247 free(flash_args.chip);
248 free(flash_args.prog_args);
249 free(flash_args.prog_name);
250 free(log_args.logfile);
251 close_logfile();
252 return ret;
253}