ast1100.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*
  2. * This file is part of the flashrom project.
  3. *
  4. * Copyright (C) 2017 Raptor Engineering, LLC
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "flash.h"
  23. #include "programmer.h"
  24. #include "hwaccess.h"
  25. #define PCI_VENDOR_ID_ASPEED 0x1a03
  26. #define ASPEED_MEMMAP_SIZE (128 * 1024)
  27. #define ASPEED_P2A_OFFSET 0x10000
  28. #define AST1100_SCU_APB_ADDR 0x1e6e2000
  29. #define AST1100_SCU_APB_BRIDGE_OFFSET (AST1100_SCU_APB_ADDR & 0xffff)
  30. #define AST1100_SCU_PROT_KEY 0x00
  31. #define AST1100_SCU_HW_STRAP 0x70
  32. #define AST1100_SCU_PASSWORD 0x1688a8a8
  33. #define AST1100_SCU_BOOT_SRC_MASK 0x3
  34. #define AST1100_SCU_BOOT_SPI 0x2
  35. #define AST1100_SCU_BOOT_NONE 0x3
  36. #define AST1100_SMC_APB_ADDR 0x16000000
  37. #define AST1100_SMC_SMC00 0x00
  38. #define AST1100_SMC_CE_CTL(N) (0x4 + (N * 4))
  39. #define AST1100_SMC_SEGMENT_SIZE_MASK 0x3
  40. #define AST1100_SMC_SEGMENT_SIZE_32M 0x0
  41. #define AST1100_SMC_SEGMENT_SIZE_16M 0x1
  42. #define AST1100_SMC_SEGMENT_SIZE_8M 0x2
  43. #define AST1100_SMC_SEGMENT_SIZE_4M 0x3
  44. #define AST1100_SMC_FLASH_MMIO_ADDR 0x10000000
  45. #define AST1100_SPI_CMD_FAST_R_MODE 0x1
  46. #define AST1100_SPI_CMD_USER_MODE 0x3
  47. #define AST1100_SPI_CMD_MASK 0x3
  48. #define AST1100_SPI_STOP_CE_ACTIVE (0x1 << 2)
  49. #define AST1100_SPI_SPEED_SHIFT 8
  50. #define AST1100_SPI_SPEED_MASK (0x7 << AST1100_SPI_SPEED_SHIFT)
  51. #define AST1100_SPI_FLASH_MMIO_ADDR 0x30000000
  52. #define AST1100_WDT_APB_ADDR 0x1e785000
  53. #define AST1100_WDT_APB_BRIDGE_OFFSET (AST1100_WDT_APB_ADDR & 0xffff)
  54. #define AST1100_WDT1_CTR 0x00
  55. #define AST1100_WDT1_CTR_RELOAD 0x04
  56. #define AST1100_WDT1_CTR_RESTART 0x08
  57. #define AST1100_WDT1_CTL 0x0c
  58. #define AST1100_WDT_SET_CLOCK (0x1 << 4)
  59. #define AST1100_WDT_RESET_SYSTEM (0x1 << 1)
  60. #define AST1100_WDT_ENABLE (0x1 << 0)
  61. uint8_t *ast1100_device_bar = 0;
  62. uint8_t ast1100_device_spi_bus = 0;
  63. uint8_t ast1100_device_spi_speed = 0;
  64. uint8_t ast1100_device_halt_cpu = 0;
  65. uint8_t ast1100_device_reset_cpu = 0;
  66. uint8_t ast1100_device_resume_cpu = 0;
  67. uint8_t ast1100_device_tickle_fw = 0;
  68. uint32_t ast1100_device_flash_mmio_offset = 0;
  69. uint32_t ast1100_original_wdt_conf = 0;
  70. const struct dev_entry bmc_aspeed_ast1100[] = {
  71. {PCI_VENDOR_ID_ASPEED, 0x2000, OK, "ASPEED", "AST1100" },
  72. {0},
  73. };
  74. static int ast1100_spi_send_command(struct flashctx *flash,
  75. unsigned int writecnt, unsigned int readcnt,
  76. const unsigned char *writearr,
  77. unsigned char *readarr);
  78. static const struct spi_master spi_master_ast1100 = {
  79. .type = SPI_CONTROLLER_AST1100,
  80. .max_data_read = 256,
  81. .max_data_write = 256,
  82. .command = ast1100_spi_send_command,
  83. .multicommand = default_spi_send_multicommand,
  84. .read = default_spi_read,
  85. .write_256 = default_spi_write_256,
  86. .write_aai = default_spi_write_aai,
  87. };
  88. static int ast1100_set_a2b_bridge_scu(void)
  89. {
  90. pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
  91. pci_mmio_writel(AST1100_SCU_APB_ADDR & 0xffff0000, ast1100_device_bar + 0xf004);
  92. pci_mmio_writel(0x1, ast1100_device_bar + 0xf000);
  93. return 0;
  94. }
  95. static int ast1100_set_a2b_bridge_wdt(void)
  96. {
  97. pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
  98. pci_mmio_writel(AST1100_WDT_APB_ADDR & 0xffff0000, ast1100_device_bar + 0xf004);
  99. pci_mmio_writel(0x1, ast1100_device_bar + 0xf000);
  100. return 0;
  101. }
  102. static int ast1100_set_a2b_bridge_smc(void)
  103. {
  104. pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
  105. pci_mmio_writel(AST1100_SMC_APB_ADDR, ast1100_device_bar + 0xf004);
  106. pci_mmio_writel(0x1, ast1100_device_bar + 0xf000);
  107. return 0;
  108. }
  109. static int ast1100_set_a2b_bridge_smc_flash(void)
  110. {
  111. pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
  112. pci_mmio_writel(AST1100_SMC_FLASH_MMIO_ADDR + ast1100_device_flash_mmio_offset, ast1100_device_bar + 0xf004);
  113. pci_mmio_writel(0x1, ast1100_device_bar + 0xf000);
  114. return 0;
  115. }
  116. static int ast1100_disable_cpu(void) {
  117. uint32_t dword;
  118. if (ast1100_device_halt_cpu) {
  119. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_HW_STRAP);
  120. if (((dword & AST1100_SCU_BOOT_SRC_MASK) != AST1100_SCU_BOOT_SPI)
  121. && ((dword & AST1100_SCU_BOOT_SRC_MASK) != AST1100_SCU_BOOT_NONE)) { /* NONE permitted to allow for BMC recovery after Ctrl+C or crash */
  122. msg_perr("CPU halt requested but CPU firmware source is not SPI.\n");
  123. pci_mmio_writel(0x0, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_PROT_KEY);
  124. ast1100_device_halt_cpu = 0;
  125. return 1;
  126. }
  127. /* Disable CPU */
  128. ast1100_set_a2b_bridge_scu();
  129. pci_mmio_writel((dword & ~AST1100_SCU_BOOT_SRC_MASK) | AST1100_SCU_BOOT_NONE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_HW_STRAP);
  130. ast1100_original_wdt_conf = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
  131. pci_mmio_writel(ast1100_original_wdt_conf & 0xffff0, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
  132. }
  133. return 0;
  134. }
  135. static int ast1100_enable_cpu(void) {
  136. uint32_t dword;
  137. if (ast1100_device_halt_cpu && ast1100_device_resume_cpu) {
  138. /* Re-enable CPU */
  139. ast1100_set_a2b_bridge_scu();
  140. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_HW_STRAP);
  141. pci_mmio_writel((dword & ~AST1100_SCU_BOOT_SRC_MASK) | AST1100_SCU_BOOT_SPI, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_HW_STRAP);
  142. }
  143. return 0;
  144. }
  145. static int ast1100_reset_cpu(void) {
  146. if (ast1100_device_reset_cpu) {
  147. /* Disable WDT from issuing full SoC reset
  148. * Without this, OpenPOWER systems will crash when the GPIO blocks are reset on WDT timeout
  149. */
  150. msg_pinfo("Configuring P2A bridge for WDT access\n");
  151. ast1100_set_a2b_bridge_wdt();
  152. ast1100_original_wdt_conf = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
  153. /* Initiate reset */
  154. msg_pinfo("Setting WDT to reset CPU immediately\n");
  155. pci_mmio_writel(ast1100_original_wdt_conf & 0xffff0, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
  156. pci_mmio_writel(0xec08ce00, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTR_RELOAD);
  157. pci_mmio_writel(0x4755, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTR_RESTART);
  158. pci_mmio_writel(AST1100_WDT_SET_CLOCK, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
  159. pci_mmio_writel(AST1100_WDT_RESET_SYSTEM | AST1100_WDT_ENABLE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_WDT_APB_BRIDGE_OFFSET + AST1100_WDT1_CTL);
  160. }
  161. return 0;
  162. }
  163. static int ast1100_shutdown(void *data) {
  164. /* Reactivate CPU if previously deactivated */
  165. ast1100_enable_cpu();
  166. /* Reset CPU if requested */
  167. ast1100_reset_cpu();
  168. /* Disable backdoor APB access */
  169. pci_mmio_writel(0x0, ast1100_device_bar + 0xf000);
  170. return 0;
  171. }
  172. int ast1100_init(void)
  173. {
  174. struct pci_dev *dev = NULL;
  175. uint32_t dword;
  176. char *arg;
  177. ast1100_device_spi_bus = 0;
  178. arg = extract_programmer_param("spibus");
  179. if (arg)
  180. ast1100_device_spi_bus = strtol(arg, NULL, 0);
  181. free(arg);
  182. ast1100_device_spi_speed = 0;
  183. arg = extract_programmer_param("spispeed");
  184. if (arg)
  185. ast1100_device_spi_speed = strtol(arg, NULL, 0);
  186. free(arg);
  187. ast1100_device_halt_cpu = 0;
  188. arg = extract_programmer_param("cpu");
  189. if (arg && !strcmp(arg,"pause")) {
  190. ast1100_device_halt_cpu = 1;
  191. ast1100_device_resume_cpu = 1;
  192. ast1100_device_reset_cpu = 0;
  193. }
  194. else if (arg && !strcmp(arg,"halt")) {
  195. ast1100_device_halt_cpu = 1;
  196. ast1100_device_resume_cpu = 0;
  197. ast1100_device_reset_cpu = 0;
  198. }
  199. else if (arg && !strcmp(arg,"reset")) {
  200. ast1100_device_halt_cpu = 1;
  201. ast1100_device_resume_cpu = 1;
  202. ast1100_device_reset_cpu = 1;
  203. }
  204. else if (arg) {
  205. msg_perr("Invalid CPU option! Valid values are: pause | halt | reset\n");
  206. return 1;
  207. }
  208. arg = extract_programmer_param("tickle");
  209. if (arg && !strcmp(arg,"true"))
  210. ast1100_device_tickle_fw = 1;
  211. free(arg);
  212. if ((ast1100_device_spi_bus < 0) || (ast1100_device_spi_bus > 2)) {
  213. msg_perr("SPI bus number out of range! Valid values are 0 - 2.\n");
  214. return 1;
  215. }
  216. if (rget_io_perms())
  217. return 1;
  218. dev = pcidev_init(bmc_aspeed_ast1100, PCI_BASE_ADDRESS_1);
  219. if (!dev)
  220. return 1;
  221. uintptr_t io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_1);
  222. if (!io_base_addr)
  223. return 1;
  224. msg_pinfo("Detected ASPEED MMIO base address: %p.\n", (void*)io_base_addr);
  225. ast1100_device_bar = rphysmap("ASPEED", io_base_addr, ASPEED_MEMMAP_SIZE);
  226. if (ast1100_device_bar == ERROR_PTR)
  227. return 1;
  228. if (register_shutdown(ast1100_shutdown, dev))
  229. return 1;
  230. io_base_addr += ASPEED_P2A_OFFSET;
  231. msg_pinfo("ASPEED P2A base address: %p.\n", (void*)io_base_addr);
  232. msg_pinfo("Configuring P2A bridge for SCU access\n");
  233. ast1100_set_a2b_bridge_scu();
  234. pci_mmio_writel(AST1100_SCU_PASSWORD, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SCU_APB_BRIDGE_OFFSET + AST1100_SCU_PROT_KEY);
  235. /* Halt CPU if requested */
  236. if (ast1100_disable_cpu())
  237. return 1;
  238. msg_pinfo("Configuring P2A bridge for SMC access\n");
  239. ast1100_set_a2b_bridge_smc();
  240. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_SMC00);
  241. if (((dword >> ((ast1100_device_spi_bus * 2) + 4)) & 0x3) != 0x2) {
  242. msg_perr("CE%01x Flash type is not SPI!\n", ast1100_device_spi_bus);
  243. return 1;
  244. }
  245. msg_pinfo("Setting CE%01x SPI relative clock speed to %d\n", ast1100_device_spi_bus, ast1100_device_spi_speed);
  246. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  247. dword &= ~AST1100_SPI_SPEED_MASK;
  248. pci_mmio_writel(dword | ((ast1100_device_spi_speed << AST1100_SPI_SPEED_SHIFT) & AST1100_SPI_SPEED_MASK), ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  249. msg_pinfo("Enabling CE%01x write\n", ast1100_device_spi_bus);
  250. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_SMC00);
  251. pci_mmio_writel(dword | (0x1 << (10 + ast1100_device_spi_bus)), ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_SMC00);
  252. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_SMC00);
  253. dword &= AST1100_SMC_SEGMENT_SIZE_MASK;
  254. switch (dword & AST1100_SMC_SEGMENT_SIZE_MASK) {
  255. case AST1100_SMC_SEGMENT_SIZE_32M:
  256. ast1100_device_flash_mmio_offset = 0x2000000;
  257. break;
  258. case AST1100_SMC_SEGMENT_SIZE_16M:
  259. ast1100_device_flash_mmio_offset = 0x1000000;
  260. break;
  261. case AST1100_SMC_SEGMENT_SIZE_8M:
  262. ast1100_device_flash_mmio_offset = 0x800000;
  263. break;
  264. case AST1100_SMC_SEGMENT_SIZE_4M:
  265. ast1100_device_flash_mmio_offset = 0x400000;
  266. break;
  267. default:
  268. ast1100_device_flash_mmio_offset = 0x2000000;
  269. }
  270. msg_pinfo("Segment size: 0x%08x\n", ast1100_device_flash_mmio_offset);
  271. ast1100_device_flash_mmio_offset = ast1100_device_flash_mmio_offset * ast1100_device_spi_bus;
  272. msg_pinfo("Using CE%01x offset 0x%08x\n", ast1100_device_spi_bus, ast1100_device_flash_mmio_offset);
  273. register_spi_master(&spi_master_ast1100);
  274. return 0;
  275. }
  276. static void ast1100_spi_xfer_data(struct flashctx *flash,
  277. unsigned int writecnt, unsigned int readcnt,
  278. const unsigned char *writearr,
  279. unsigned char *readarr)
  280. {
  281. int i;
  282. uint32_t dword;
  283. for (i = 0; i < writecnt; i++)
  284. msg_pspew("[%02x]", writearr[i]);
  285. msg_pspew("\n");
  286. for (i = 0; i < writecnt; i=i+4) {
  287. if ((writecnt - i) < 4)
  288. break;
  289. dword = writearr[i];
  290. dword |= writearr[i + 1] << 8;
  291. dword |= writearr[i + 2] << 16;
  292. dword |= writearr[i + 3] << 24;
  293. pci_mmio_writel(dword, ast1100_device_bar + ASPEED_P2A_OFFSET);
  294. }
  295. for (; i < writecnt; i++)
  296. pci_mmio_writeb(writearr[i], ast1100_device_bar + ASPEED_P2A_OFFSET);
  297. programmer_delay(1);
  298. for (i = 0; i < readcnt;) {
  299. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET);
  300. if (i < readcnt)
  301. readarr[i] = dword & 0xff;
  302. i++;
  303. if (i < readcnt)
  304. readarr[i] = (dword >> 8) & 0xff;
  305. i++;
  306. if (i < readcnt)
  307. readarr[i] = (dword >> 16) & 0xff;
  308. i++;
  309. if (i < readcnt)
  310. readarr[i] = (dword >> 24) & 0xff;
  311. i++;
  312. }
  313. for (i = 0; i < readcnt; i++)
  314. msg_pspew("[%02x]", readarr[i]);
  315. msg_pspew("\n");
  316. }
  317. /* Returns 0 upon success, a negative number upon errors. */
  318. static int ast1100_spi_send_command(struct flashctx *flash,
  319. unsigned int writecnt, unsigned int readcnt,
  320. const unsigned char *writearr,
  321. unsigned char *readarr)
  322. {
  323. uint32_t dword;
  324. msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, *writearr, writecnt, readcnt);
  325. /* Set up user command mode */
  326. ast1100_set_a2b_bridge_smc();
  327. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  328. pci_mmio_writel(dword | AST1100_SPI_CMD_USER_MODE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  329. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  330. pci_mmio_writel(dword & ~AST1100_SPI_STOP_CE_ACTIVE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  331. /* Transfer data */
  332. ast1100_set_a2b_bridge_smc_flash();
  333. ast1100_spi_xfer_data(flash, writecnt, readcnt, writearr, readarr);
  334. /* Tear down user command mode */
  335. ast1100_set_a2b_bridge_smc();
  336. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  337. pci_mmio_writel(dword | AST1100_SPI_STOP_CE_ACTIVE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  338. dword = pci_mmio_readl(ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  339. pci_mmio_writel((dword & ~AST1100_SPI_CMD_MASK) | AST1100_SPI_CMD_FAST_R_MODE, ast1100_device_bar + ASPEED_P2A_OFFSET + AST1100_SMC_CE_CTL(ast1100_device_spi_bus));
  340. if (ast1100_device_tickle_fw) {
  341. ast1100_enable_cpu();
  342. programmer_delay(100);
  343. ast1100_disable_cpu();
  344. }
  345. return 0;
  346. }