vexpress-sysreg.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License version 2 as
  4. * published by the Free Software Foundation.
  5. *
  6. * This program is distributed in the hope that it will be useful,
  7. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. * GNU General Public License for more details.
  10. *
  11. * Copyright (C) 2012 ARM Limited
  12. */
  13. #include <linux/gpio/driver.h>
  14. #include <linux/err.h>
  15. #include <linux/io.h>
  16. #include <linux/mfd/core.h>
  17. #include <linux/of_address.h>
  18. #include <linux/of_platform.h>
  19. #include <linux/platform_data/syscon.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/slab.h>
  22. #include <linux/stat.h>
  23. #include <linux/vexpress.h>
  24. #define SYS_ID 0x000
  25. #define SYS_SW 0x004
  26. #define SYS_LED 0x008
  27. #define SYS_100HZ 0x024
  28. #define SYS_FLAGSSET 0x030
  29. #define SYS_FLAGSCLR 0x034
  30. #define SYS_NVFLAGS 0x038
  31. #define SYS_NVFLAGSSET 0x038
  32. #define SYS_NVFLAGSCLR 0x03c
  33. #define SYS_MCI 0x048
  34. #define SYS_FLASH 0x04c
  35. #define SYS_CFGSW 0x058
  36. #define SYS_24MHZ 0x05c
  37. #define SYS_MISC 0x060
  38. #define SYS_DMA 0x064
  39. #define SYS_PROCID0 0x084
  40. #define SYS_PROCID1 0x088
  41. #define SYS_CFGDATA 0x0a0
  42. #define SYS_CFGCTRL 0x0a4
  43. #define SYS_CFGSTAT 0x0a8
  44. #define SYS_HBI_MASK 0xfff
  45. #define SYS_PROCIDx_HBI_SHIFT 0
  46. #define SYS_MISC_MASTERSITE (1 << 14)
  47. void vexpress_flags_set(u32 data)
  48. {
  49. static void __iomem *base;
  50. if (!base) {
  51. struct device_node *node = of_find_compatible_node(NULL, NULL,
  52. "arm,vexpress-sysreg");
  53. base = of_iomap(node, 0);
  54. }
  55. if (WARN_ON(!base))
  56. return;
  57. writel(~0, base + SYS_FLAGSCLR);
  58. writel(data, base + SYS_FLAGSSET);
  59. }
  60. /* The sysreg block is just a random collection of various functions... */
  61. static struct syscon_platform_data vexpress_sysreg_sys_id_pdata = {
  62. .label = "sys_id",
  63. };
  64. static struct bgpio_pdata vexpress_sysreg_sys_led_pdata = {
  65. .label = "sys_led",
  66. .base = -1,
  67. .ngpio = 8,
  68. };
  69. static struct bgpio_pdata vexpress_sysreg_sys_mci_pdata = {
  70. .label = "sys_mci",
  71. .base = -1,
  72. .ngpio = 2,
  73. };
  74. static struct bgpio_pdata vexpress_sysreg_sys_flash_pdata = {
  75. .label = "sys_flash",
  76. .base = -1,
  77. .ngpio = 1,
  78. };
  79. static struct syscon_platform_data vexpress_sysreg_sys_misc_pdata = {
  80. .label = "sys_misc",
  81. };
  82. static struct syscon_platform_data vexpress_sysreg_sys_procid_pdata = {
  83. .label = "sys_procid",
  84. };
  85. static struct mfd_cell vexpress_sysreg_cells[] = {
  86. {
  87. .name = "syscon",
  88. .num_resources = 1,
  89. .resources = (struct resource []) {
  90. DEFINE_RES_MEM(SYS_ID, 0x4),
  91. },
  92. .platform_data = &vexpress_sysreg_sys_id_pdata,
  93. .pdata_size = sizeof(vexpress_sysreg_sys_id_pdata),
  94. }, {
  95. .name = "basic-mmio-gpio",
  96. .of_compatible = "arm,vexpress-sysreg,sys_led",
  97. .num_resources = 1,
  98. .resources = (struct resource []) {
  99. DEFINE_RES_MEM_NAMED(SYS_LED, 0x4, "dat"),
  100. },
  101. .platform_data = &vexpress_sysreg_sys_led_pdata,
  102. .pdata_size = sizeof(vexpress_sysreg_sys_led_pdata),
  103. }, {
  104. .name = "basic-mmio-gpio",
  105. .of_compatible = "arm,vexpress-sysreg,sys_mci",
  106. .num_resources = 1,
  107. .resources = (struct resource []) {
  108. DEFINE_RES_MEM_NAMED(SYS_MCI, 0x4, "dat"),
  109. },
  110. .platform_data = &vexpress_sysreg_sys_mci_pdata,
  111. .pdata_size = sizeof(vexpress_sysreg_sys_mci_pdata),
  112. }, {
  113. .name = "basic-mmio-gpio",
  114. .of_compatible = "arm,vexpress-sysreg,sys_flash",
  115. .num_resources = 1,
  116. .resources = (struct resource []) {
  117. DEFINE_RES_MEM_NAMED(SYS_FLASH, 0x4, "dat"),
  118. },
  119. .platform_data = &vexpress_sysreg_sys_flash_pdata,
  120. .pdata_size = sizeof(vexpress_sysreg_sys_flash_pdata),
  121. }, {
  122. .name = "syscon",
  123. .num_resources = 1,
  124. .resources = (struct resource []) {
  125. DEFINE_RES_MEM(SYS_MISC, 0x4),
  126. },
  127. .platform_data = &vexpress_sysreg_sys_misc_pdata,
  128. .pdata_size = sizeof(vexpress_sysreg_sys_misc_pdata),
  129. }, {
  130. .name = "syscon",
  131. .num_resources = 1,
  132. .resources = (struct resource []) {
  133. DEFINE_RES_MEM(SYS_PROCID0, 0x8),
  134. },
  135. .platform_data = &vexpress_sysreg_sys_procid_pdata,
  136. .pdata_size = sizeof(vexpress_sysreg_sys_procid_pdata),
  137. }, {
  138. .name = "vexpress-syscfg",
  139. .num_resources = 1,
  140. .resources = (struct resource []) {
  141. DEFINE_RES_MEM(SYS_CFGDATA, 0xc),
  142. },
  143. }
  144. };
  145. static int vexpress_sysreg_probe(struct platform_device *pdev)
  146. {
  147. struct resource *mem;
  148. void __iomem *base;
  149. struct gpio_chip *mmc_gpio_chip;
  150. int master;
  151. u32 dt_hbi;
  152. mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  153. if (!mem)
  154. return -EINVAL;
  155. base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
  156. if (!base)
  157. return -ENOMEM;
  158. master = readl(base + SYS_MISC) & SYS_MISC_MASTERSITE ?
  159. VEXPRESS_SITE_DB2 : VEXPRESS_SITE_DB1;
  160. vexpress_config_set_master(master);
  161. /* Confirm board type against DT property, if available */
  162. if (of_property_read_u32(of_root, "arm,hbi", &dt_hbi) == 0) {
  163. u32 id = readl(base + (master == VEXPRESS_SITE_DB1 ?
  164. SYS_PROCID0 : SYS_PROCID1));
  165. u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
  166. if (WARN_ON(dt_hbi != hbi))
  167. dev_warn(&pdev->dev, "DT HBI (%x) is not matching hardware (%x)!\n",
  168. dt_hbi, hbi);
  169. }
  170. /*
  171. * Duplicated SYS_MCI pseudo-GPIO controller for compatibility with
  172. * older trees using sysreg node for MMC control lines.
  173. */
  174. mmc_gpio_chip = devm_kzalloc(&pdev->dev, sizeof(*mmc_gpio_chip),
  175. GFP_KERNEL);
  176. if (!mmc_gpio_chip)
  177. return -ENOMEM;
  178. bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
  179. NULL, NULL, NULL, NULL, 0);
  180. mmc_gpio_chip->ngpio = 2;
  181. gpiochip_add_data(mmc_gpio_chip, NULL);
  182. return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
  183. vexpress_sysreg_cells,
  184. ARRAY_SIZE(vexpress_sysreg_cells), mem, 0, NULL);
  185. }
  186. static const struct of_device_id vexpress_sysreg_match[] = {
  187. { .compatible = "arm,vexpress-sysreg", },
  188. {},
  189. };
  190. static struct platform_driver vexpress_sysreg_driver = {
  191. .driver = {
  192. .name = "vexpress-sysreg",
  193. .of_match_table = vexpress_sysreg_match,
  194. },
  195. .probe = vexpress_sysreg_probe,
  196. };
  197. static int __init vexpress_sysreg_init(void)
  198. {
  199. struct device_node *node;
  200. /* Need the sysreg early, before any other device... */
  201. for_each_matching_node(node, vexpress_sysreg_match)
  202. of_platform_device_create(node, NULL, NULL);
  203. return platform_driver_register(&vexpress_sysreg_driver);
  204. }
  205. core_initcall(vexpress_sysreg_init);