mcp6x_spi.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * This file is part of the flashrom project.
  3. *
  4. * Copyright (C) 2010 Carl-Daniel Hailfinger
  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; version 2 of the License.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. /* Driver for the NVIDIA MCP6x/MCP7x MCP6X_SPI controller.
  20. * Based on clean room reverse engineered docs from
  21. * http://www.flashrom.org/pipermail/flashrom/2009-December/001180.html
  22. * created by Michael Karcher.
  23. */
  24. #if defined(__i386__) || defined(__x86_64__)
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include "flash.h"
  28. #include "programmer.h"
  29. /* Bit positions for each pin. */
  30. #define MCP6X_SPI_CS 1
  31. #define MCP6X_SPI_SCK 2
  32. #define MCP6X_SPI_MOSI 3
  33. #define MCP6X_SPI_MISO 4
  34. #define MCP6X_SPI_REQUEST 0
  35. #define MCP6X_SPI_GRANT 8
  36. void *mcp6x_spibar = NULL;
  37. /* Cached value of last GPIO state. */
  38. static uint8_t mcp_gpiostate;
  39. static void mcp6x_request_spibus(void)
  40. {
  41. mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
  42. mcp_gpiostate |= 1 << MCP6X_SPI_REQUEST;
  43. mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
  44. /* Wait until we are allowed to use the SPI bus. */
  45. while (!(mmio_readw(mcp6x_spibar + 0x530) & (1 << MCP6X_SPI_GRANT))) ;
  46. /* Update the cache. */
  47. mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
  48. }
  49. static void mcp6x_release_spibus(void)
  50. {
  51. mcp_gpiostate &= ~(1 << MCP6X_SPI_REQUEST);
  52. mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
  53. }
  54. static void mcp6x_bitbang_set_cs(int val)
  55. {
  56. mcp_gpiostate &= ~(1 << MCP6X_SPI_CS);
  57. mcp_gpiostate |= (val << MCP6X_SPI_CS);
  58. mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
  59. }
  60. static void mcp6x_bitbang_set_sck(int val)
  61. {
  62. mcp_gpiostate &= ~(1 << MCP6X_SPI_SCK);
  63. mcp_gpiostate |= (val << MCP6X_SPI_SCK);
  64. mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
  65. }
  66. static void mcp6x_bitbang_set_mosi(int val)
  67. {
  68. mcp_gpiostate &= ~(1 << MCP6X_SPI_MOSI);
  69. mcp_gpiostate |= (val << MCP6X_SPI_MOSI);
  70. mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
  71. }
  72. static int mcp6x_bitbang_get_miso(void)
  73. {
  74. mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
  75. return (mcp_gpiostate >> MCP6X_SPI_MISO) & 0x1;
  76. }
  77. static const struct bitbang_spi_master bitbang_spi_master_mcp6x = {
  78. .type = BITBANG_SPI_MASTER_MCP,
  79. .set_cs = mcp6x_bitbang_set_cs,
  80. .set_sck = mcp6x_bitbang_set_sck,
  81. .set_mosi = mcp6x_bitbang_set_mosi,
  82. .get_miso = mcp6x_bitbang_get_miso,
  83. .request_bus = mcp6x_request_spibus,
  84. .release_bus = mcp6x_release_spibus,
  85. };
  86. int mcp6x_spi_init(int want_spi)
  87. {
  88. uint16_t status;
  89. uint32_t mcp6x_spibaraddr;
  90. struct pci_dev *smbusdev;
  91. /* Look for the SMBus device (SMBus PCI class) */
  92. smbusdev = pci_dev_find_vendorclass(0x10de, 0x0c05);
  93. if (!smbusdev) {
  94. if (want_spi) {
  95. msg_perr("ERROR: SMBus device not found. Not enabling "
  96. "SPI.\n");
  97. return 1;
  98. } else {
  99. msg_pinfo("Odd. SMBus device not found.\n");
  100. return 0;
  101. }
  102. }
  103. msg_pdbg("Found SMBus device %04x:%04x at %02x:%02x:%01x\n",
  104. smbusdev->vendor_id, smbusdev->device_id,
  105. smbusdev->bus, smbusdev->dev, smbusdev->func);
  106. /* Locate the BAR where the SPI interface lives. */
  107. mcp6x_spibaraddr = pci_read_long(smbusdev, 0x74);
  108. /* BAR size is 64k, bits 15..4 are zero, bit 3..0 declare a
  109. * 32-bit non-prefetchable memory BAR.
  110. */
  111. mcp6x_spibaraddr &= ~0xffff;
  112. msg_pdbg("MCP SPI BAR is at 0x%08x\n", mcp6x_spibaraddr);
  113. /* Accessing a NULL pointer BAR is evil. Don't do it. */
  114. if (!mcp6x_spibaraddr && want_spi) {
  115. msg_perr("Error: Chipset is strapped for SPI, but MCP SPI BAR "
  116. "is invalid.\n");
  117. return 1;
  118. } else if (!mcp6x_spibaraddr && !want_spi) {
  119. msg_pdbg("MCP SPI is not used.\n");
  120. return 0;
  121. } else if (mcp6x_spibaraddr && !want_spi) {
  122. msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently"
  123. " doesn't have SPI enabled.\n");
  124. /* FIXME: Should we enable SPI anyway? */
  125. return 0;
  126. }
  127. /* Map the BAR. Bytewise/wordwise access at 0x530 and 0x540. */
  128. mcp6x_spibar = physmap("NVIDIA MCP6x SPI", mcp6x_spibaraddr, 0x544);
  129. #if 0
  130. /* FIXME: Run the physunmap in a shutdown function. */
  131. physunmap(mcp6x_spibar, 0x544);
  132. #endif
  133. status = mmio_readw(mcp6x_spibar + 0x530);
  134. msg_pdbg("SPI control is 0x%04x, req=%i, gnt=%i\n",
  135. status, (status >> MCP6X_SPI_REQUEST) & 0x1,
  136. (status >> MCP6X_SPI_GRANT) & 0x1);
  137. mcp_gpiostate = status & 0xff;
  138. /* Zero halfperiod delay. */
  139. if (bitbang_spi_init(&bitbang_spi_master_mcp6x, 0)) {
  140. /* This should never happen. */
  141. msg_perr("MCP6X bitbang SPI master init failed!\n");
  142. return 1;
  143. }
  144. return 0;
  145. }
  146. #endif