ops-vr41xx.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * ops-vr41xx.c, PCI configuration routines for the PCIU of NEC VR4100 series.
  3. *
  4. * Copyright (C) 2001-2003 MontaVista Software Inc.
  5. * Author: Yoichi Yuasa <source@mvista.com>
  6. * Copyright (C) 2004-2005 Yoichi Yuasa <yuasa@linux-mips.org>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. */
  22. /*
  23. * Changes:
  24. * MontaVista Software Inc. <source@mvista.com>
  25. * - New creation, NEC VR4122 and VR4131 are supported.
  26. */
  27. #include <linux/pci.h>
  28. #include <linux/types.h>
  29. #include <asm/io.h>
  30. #define PCICONFDREG (void __iomem *)KSEG1ADDR(0x0f000c14)
  31. #define PCICONFAREG (void __iomem *)KSEG1ADDR(0x0f000c18)
  32. static inline int set_pci_configuration_address(unsigned char number,
  33. unsigned int devfn, int where)
  34. {
  35. if (number == 0) {
  36. /*
  37. * Type 0 configuration
  38. */
  39. if (PCI_SLOT(devfn) < 11 || where > 0xff)
  40. return -EINVAL;
  41. writel((1U << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) |
  42. (where & 0xfc), PCICONFAREG);
  43. } else {
  44. /*
  45. * Type 1 configuration
  46. */
  47. if (where > 0xff)
  48. return -EINVAL;
  49. writel(((uint32_t)number << 16) | ((devfn & 0xff) << 8) |
  50. (where & 0xfc) | 1U, PCICONFAREG);
  51. }
  52. return 0;
  53. }
  54. static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,
  55. int size, uint32_t *val)
  56. {
  57. uint32_t data;
  58. *val = 0xffffffffU;
  59. if (set_pci_configuration_address(bus->number, devfn, where) < 0)
  60. return PCIBIOS_DEVICE_NOT_FOUND;
  61. data = readl(PCICONFDREG);
  62. switch (size) {
  63. case 1:
  64. *val = (data >> ((where & 3) << 3)) & 0xffU;
  65. break;
  66. case 2:
  67. *val = (data >> ((where & 2) << 3)) & 0xffffU;
  68. break;
  69. case 4:
  70. *val = data;
  71. break;
  72. default:
  73. return PCIBIOS_FUNC_NOT_SUPPORTED;
  74. }
  75. return PCIBIOS_SUCCESSFUL;
  76. }
  77. static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where,
  78. int size, uint32_t val)
  79. {
  80. uint32_t data;
  81. int shift;
  82. if (set_pci_configuration_address(bus->number, devfn, where) < 0)
  83. return PCIBIOS_DEVICE_NOT_FOUND;
  84. data = readl(PCICONFDREG);
  85. switch (size) {
  86. case 1:
  87. shift = (where & 3) << 3;
  88. data &= ~(0xffU << shift);
  89. data |= ((val & 0xffU) << shift);
  90. break;
  91. case 2:
  92. shift = (where & 2) << 3;
  93. data &= ~(0xffffU << shift);
  94. data |= ((val & 0xffffU) << shift);
  95. break;
  96. case 4:
  97. data = val;
  98. break;
  99. default:
  100. return PCIBIOS_FUNC_NOT_SUPPORTED;
  101. }
  102. writel(data, PCICONFDREG);
  103. return PCIBIOS_SUCCESSFUL;
  104. }
  105. struct pci_ops vr41xx_pci_ops = {
  106. .read = pci_config_read,
  107. .write = pci_config_write,
  108. };