1 /* 2 * QTest testcase for the M25P80 Flash (Using the Aspeed SPI 3 * Controller) 4 * 5 * Copyright (C) 2016 IBM Corp. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 26 #include "qemu/osdep.h" 27 #include "qemu/bswap.h" 28 #include "libqtest-single.h" 29 #include "qemu/bitops.h" 30 31 /* 32 * ASPEED SPI Controller registers 33 */ 34 #define R_CONF 0x00 35 #define CONF_ENABLE_W0 (1 << 16) 36 #define R_CE_CTRL 0x04 37 #define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */ 38 #define R_CTRL0 0x10 39 #define CTRL_CE_STOP_ACTIVE (1 << 2) 40 #define CTRL_READMODE 0x0 41 #define CTRL_FREADMODE 0x1 42 #define CTRL_WRITEMODE 0x2 43 #define CTRL_USERMODE 0x3 44 #define SR_WEL BIT(1) 45 46 #define ASPEED_FMC_BASE 0x1E620000 47 #define ASPEED_FLASH_BASE 0x20000000 48 49 /* 50 * Flash commands 51 */ 52 enum { 53 JEDEC_READ = 0x9f, 54 RDSR = 0x5, 55 WRDI = 0x4, 56 BULK_ERASE = 0xc7, 57 READ = 0x03, 58 PP = 0x02, 59 WREN = 0x6, 60 RESET_ENABLE = 0x66, 61 RESET_MEMORY = 0x99, 62 EN_4BYTE_ADDR = 0xB7, 63 ERASE_SECTOR = 0xd8, 64 }; 65 66 #define FLASH_JEDEC 0x20ba19 /* n25q256a */ 67 #define FLASH_SIZE (32 * 1024 * 1024) 68 69 #define FLASH_PAGE_SIZE 256 70 71 /* 72 * Use an explicit bswap for the values read/wrote to the flash region 73 * as they are BE and the Aspeed CPU is LE. 74 */ 75 static inline uint32_t make_be32(uint32_t data) 76 { 77 return bswap32(data); 78 } 79 80 static void spi_conf(uint32_t value) 81 { 82 uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF); 83 84 conf |= value; 85 writel(ASPEED_FMC_BASE + R_CONF, conf); 86 } 87 88 static void spi_conf_remove(uint32_t value) 89 { 90 uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF); 91 92 conf &= ~value; 93 writel(ASPEED_FMC_BASE + R_CONF, conf); 94 } 95 96 static void spi_ce_ctrl(uint32_t value) 97 { 98 uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL); 99 100 conf |= value; 101 writel(ASPEED_FMC_BASE + R_CE_CTRL, conf); 102 } 103 104 static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd) 105 { 106 uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); 107 ctrl &= ~(CTRL_USERMODE | 0xff << 16); 108 ctrl |= mode | (cmd << 16); 109 writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); 110 } 111 112 static void spi_ctrl_start_user(void) 113 { 114 uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); 115 116 ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; 117 writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); 118 119 ctrl &= ~CTRL_CE_STOP_ACTIVE; 120 writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); 121 } 122 123 static void spi_ctrl_stop_user(void) 124 { 125 uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); 126 127 ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; 128 writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); 129 } 130 131 static void flash_reset(void) 132 { 133 spi_conf(CONF_ENABLE_W0); 134 135 spi_ctrl_start_user(); 136 writeb(ASPEED_FLASH_BASE, RESET_ENABLE); 137 writeb(ASPEED_FLASH_BASE, RESET_MEMORY); 138 writeb(ASPEED_FLASH_BASE, WREN); 139 writeb(ASPEED_FLASH_BASE, BULK_ERASE); 140 writeb(ASPEED_FLASH_BASE, WRDI); 141 spi_ctrl_stop_user(); 142 143 spi_conf_remove(CONF_ENABLE_W0); 144 } 145 146 static void test_read_jedec(void) 147 { 148 uint32_t jedec = 0x0; 149 150 spi_conf(CONF_ENABLE_W0); 151 152 spi_ctrl_start_user(); 153 writeb(ASPEED_FLASH_BASE, JEDEC_READ); 154 jedec |= readb(ASPEED_FLASH_BASE) << 16; 155 jedec |= readb(ASPEED_FLASH_BASE) << 8; 156 jedec |= readb(ASPEED_FLASH_BASE); 157 spi_ctrl_stop_user(); 158 159 flash_reset(); 160 161 g_assert_cmphex(jedec, ==, FLASH_JEDEC); 162 } 163 164 static void read_page(uint32_t addr, uint32_t *page) 165 { 166 int i; 167 168 spi_ctrl_start_user(); 169 170 writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); 171 writeb(ASPEED_FLASH_BASE, READ); 172 writel(ASPEED_FLASH_BASE, make_be32(addr)); 173 174 /* Continuous read are supported */ 175 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 176 page[i] = make_be32(readl(ASPEED_FLASH_BASE)); 177 } 178 spi_ctrl_stop_user(); 179 } 180 181 static void read_page_mem(uint32_t addr, uint32_t *page) 182 { 183 int i; 184 185 /* move out USER mode to use direct reads from the AHB bus */ 186 spi_ctrl_setmode(CTRL_READMODE, READ); 187 188 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 189 page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4)); 190 } 191 } 192 193 static void test_erase_sector(void) 194 { 195 uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE; 196 uint32_t page[FLASH_PAGE_SIZE / 4]; 197 int i; 198 199 spi_conf(CONF_ENABLE_W0); 200 201 /* 202 * Previous page should be full of 0xffs after backend is 203 * initialized 204 */ 205 read_page(some_page_addr - FLASH_PAGE_SIZE, page); 206 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 207 g_assert_cmphex(page[i], ==, 0xffffffff); 208 } 209 210 spi_ctrl_start_user(); 211 writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); 212 writeb(ASPEED_FLASH_BASE, WREN); 213 writeb(ASPEED_FLASH_BASE, PP); 214 writel(ASPEED_FLASH_BASE, make_be32(some_page_addr)); 215 216 /* Fill the page with its own addresses */ 217 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 218 writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4)); 219 } 220 spi_ctrl_stop_user(); 221 222 /* Check the page is correctly written */ 223 read_page(some_page_addr, page); 224 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 225 g_assert_cmphex(page[i], ==, some_page_addr + i * 4); 226 } 227 228 spi_ctrl_start_user(); 229 writeb(ASPEED_FLASH_BASE, WREN); 230 writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); 231 writeb(ASPEED_FLASH_BASE, ERASE_SECTOR); 232 writel(ASPEED_FLASH_BASE, make_be32(some_page_addr)); 233 spi_ctrl_stop_user(); 234 235 /* Check the page is erased */ 236 read_page(some_page_addr, page); 237 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 238 g_assert_cmphex(page[i], ==, 0xffffffff); 239 } 240 241 flash_reset(); 242 } 243 244 static void test_erase_all(void) 245 { 246 uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE; 247 uint32_t page[FLASH_PAGE_SIZE / 4]; 248 int i; 249 250 spi_conf(CONF_ENABLE_W0); 251 252 /* 253 * Previous page should be full of 0xffs after backend is 254 * initialized 255 */ 256 read_page(some_page_addr - FLASH_PAGE_SIZE, page); 257 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 258 g_assert_cmphex(page[i], ==, 0xffffffff); 259 } 260 261 spi_ctrl_start_user(); 262 writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); 263 writeb(ASPEED_FLASH_BASE, WREN); 264 writeb(ASPEED_FLASH_BASE, PP); 265 writel(ASPEED_FLASH_BASE, make_be32(some_page_addr)); 266 267 /* Fill the page with its own addresses */ 268 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 269 writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4)); 270 } 271 spi_ctrl_stop_user(); 272 273 /* Check the page is correctly written */ 274 read_page(some_page_addr, page); 275 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 276 g_assert_cmphex(page[i], ==, some_page_addr + i * 4); 277 } 278 279 spi_ctrl_start_user(); 280 writeb(ASPEED_FLASH_BASE, WREN); 281 writeb(ASPEED_FLASH_BASE, BULK_ERASE); 282 spi_ctrl_stop_user(); 283 284 /* Check the page is erased */ 285 read_page(some_page_addr, page); 286 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 287 g_assert_cmphex(page[i], ==, 0xffffffff); 288 } 289 290 flash_reset(); 291 } 292 293 static void test_write_page(void) 294 { 295 uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */ 296 uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE; 297 uint32_t page[FLASH_PAGE_SIZE / 4]; 298 int i; 299 300 spi_conf(CONF_ENABLE_W0); 301 302 spi_ctrl_start_user(); 303 writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); 304 writeb(ASPEED_FLASH_BASE, WREN); 305 writeb(ASPEED_FLASH_BASE, PP); 306 writel(ASPEED_FLASH_BASE, make_be32(my_page_addr)); 307 308 /* Fill the page with its own addresses */ 309 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 310 writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4)); 311 } 312 spi_ctrl_stop_user(); 313 314 /* Check what was written */ 315 read_page(my_page_addr, page); 316 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 317 g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 318 } 319 320 /* Check some other page. It should be full of 0xff */ 321 read_page(some_page_addr, page); 322 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 323 g_assert_cmphex(page[i], ==, 0xffffffff); 324 } 325 326 flash_reset(); 327 } 328 329 static void test_read_page_mem(void) 330 { 331 uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */ 332 uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE; 333 uint32_t page[FLASH_PAGE_SIZE / 4]; 334 int i; 335 336 /* Enable 4BYTE mode for controller. This is should be strapped by 337 * HW for CE0 anyhow. 338 */ 339 spi_ce_ctrl(1 << CRTL_EXTENDED0); 340 341 /* Enable 4BYTE mode for flash. */ 342 spi_conf(CONF_ENABLE_W0); 343 spi_ctrl_start_user(); 344 writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); 345 writeb(ASPEED_FLASH_BASE, WREN); 346 writeb(ASPEED_FLASH_BASE, PP); 347 writel(ASPEED_FLASH_BASE, make_be32(my_page_addr)); 348 349 /* Fill the page with its own addresses */ 350 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 351 writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4)); 352 } 353 spi_ctrl_stop_user(); 354 spi_conf_remove(CONF_ENABLE_W0); 355 356 /* Check what was written */ 357 read_page_mem(my_page_addr, page); 358 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 359 g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 360 } 361 362 /* Check some other page. It should be full of 0xff */ 363 read_page_mem(some_page_addr, page); 364 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 365 g_assert_cmphex(page[i], ==, 0xffffffff); 366 } 367 368 flash_reset(); 369 } 370 371 static void test_write_page_mem(void) 372 { 373 uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE; 374 uint32_t page[FLASH_PAGE_SIZE / 4]; 375 int i; 376 377 /* Enable 4BYTE mode for controller. This is should be strapped by 378 * HW for CE0 anyhow. 379 */ 380 spi_ce_ctrl(1 << CRTL_EXTENDED0); 381 382 /* Enable 4BYTE mode for flash. */ 383 spi_conf(CONF_ENABLE_W0); 384 spi_ctrl_start_user(); 385 writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR); 386 writeb(ASPEED_FLASH_BASE, WREN); 387 spi_ctrl_stop_user(); 388 389 /* move out USER mode to use direct writes to the AHB bus */ 390 spi_ctrl_setmode(CTRL_WRITEMODE, PP); 391 392 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 393 writel(ASPEED_FLASH_BASE + my_page_addr + i * 4, 394 make_be32(my_page_addr + i * 4)); 395 } 396 397 /* Check what was written */ 398 read_page_mem(my_page_addr, page); 399 for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { 400 g_assert_cmphex(page[i], ==, my_page_addr + i * 4); 401 } 402 403 flash_reset(); 404 } 405 406 static void test_read_status_reg(void) 407 { 408 uint8_t r; 409 410 spi_conf(CONF_ENABLE_W0); 411 412 spi_ctrl_start_user(); 413 writeb(ASPEED_FLASH_BASE, RDSR); 414 r = readb(ASPEED_FLASH_BASE); 415 spi_ctrl_stop_user(); 416 417 g_assert_cmphex(r & SR_WEL, ==, 0); 418 g_assert(!qtest_qom_get_bool 419 (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); 420 421 spi_ctrl_start_user(); 422 writeb(ASPEED_FLASH_BASE, WREN); 423 writeb(ASPEED_FLASH_BASE, RDSR); 424 r = readb(ASPEED_FLASH_BASE); 425 spi_ctrl_stop_user(); 426 427 g_assert_cmphex(r & SR_WEL, ==, SR_WEL); 428 g_assert(qtest_qom_get_bool 429 (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); 430 431 spi_ctrl_start_user(); 432 writeb(ASPEED_FLASH_BASE, WRDI); 433 writeb(ASPEED_FLASH_BASE, RDSR); 434 r = readb(ASPEED_FLASH_BASE); 435 spi_ctrl_stop_user(); 436 437 g_assert_cmphex(r & SR_WEL, ==, 0); 438 g_assert(!qtest_qom_get_bool 439 (global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable")); 440 441 flash_reset(); 442 } 443 444 static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX"; 445 446 int main(int argc, char **argv) 447 { 448 int ret; 449 int fd; 450 451 g_test_init(&argc, &argv, NULL); 452 453 fd = mkstemp(tmp_path); 454 g_assert(fd >= 0); 455 ret = ftruncate(fd, FLASH_SIZE); 456 g_assert(ret == 0); 457 close(fd); 458 459 global_qtest = qtest_initf("-m 256 -machine palmetto-bmc " 460 "-drive file=%s,format=raw,if=mtd", 461 tmp_path); 462 463 qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec); 464 qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector); 465 qtest_add_func("/ast2400/smc/erase_all", test_erase_all); 466 qtest_add_func("/ast2400/smc/write_page", test_write_page); 467 qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem); 468 qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem); 469 qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg); 470 471 flash_reset(); 472 ret = g_test_run(); 473 474 qtest_quit(global_qtest); 475 unlink(tmp_path); 476 return ret; 477 } 478