vexpress-sysreg.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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/basic_mmio_gpio.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_MCI_CARDIN (1 << 0)
  47. #define SYS_MCI_WPROT (1 << 1)
  48. #define SYS_MISC_MASTERSITE (1 << 14)
  49. static void __iomem *__vexpress_sysreg_base;
  50. static void __iomem *vexpress_sysreg_base(void)
  51. {
  52. if (!__vexpress_sysreg_base) {
  53. struct device_node *node = of_find_compatible_node(NULL, NULL,
  54. "arm,vexpress-sysreg");
  55. __vexpress_sysreg_base = of_iomap(node, 0);
  56. }
  57. WARN_ON(!__vexpress_sysreg_base);
  58. return __vexpress_sysreg_base;
  59. }
  60. static int vexpress_sysreg_get_master(void)
  61. {
  62. if (readl(vexpress_sysreg_base() + SYS_MISC) & SYS_MISC_MASTERSITE)
  63. return VEXPRESS_SITE_DB2;
  64. return VEXPRESS_SITE_DB1;
  65. }
  66. void vexpress_flags_set(u32 data)
  67. {
  68. writel(~0, vexpress_sysreg_base() + SYS_FLAGSCLR);
  69. writel(data, vexpress_sysreg_base() + SYS_FLAGSSET);
  70. }
  71. unsigned int vexpress_get_mci_cardin(struct device *dev)
  72. {
  73. return readl(vexpress_sysreg_base() + SYS_MCI) & SYS_MCI_CARDIN;
  74. }
  75. u32 vexpress_get_procid(int site)
  76. {
  77. if (site == VEXPRESS_SITE_MASTER)
  78. site = vexpress_sysreg_get_master();
  79. return readl(vexpress_sysreg_base() + (site == VEXPRESS_SITE_DB1 ?
  80. SYS_PROCID0 : SYS_PROCID1));
  81. }
  82. void __iomem *vexpress_get_24mhz_clock_base(void)
  83. {
  84. return vexpress_sysreg_base() + SYS_24MHZ;
  85. }
  86. void __init vexpress_sysreg_early_init(void __iomem *base)
  87. {
  88. __vexpress_sysreg_base = base;
  89. vexpress_config_set_master(vexpress_sysreg_get_master());
  90. }
  91. /* The sysreg block is just a random collection of various functions... */
  92. static struct syscon_platform_data vexpress_sysreg_sys_id_pdata = {
  93. .label = "sys_id",
  94. };
  95. static struct bgpio_pdata vexpress_sysreg_sys_led_pdata = {
  96. .label = "sys_led",
  97. .base = -1,
  98. .ngpio = 8,
  99. };
  100. static struct bgpio_pdata vexpress_sysreg_sys_mci_pdata = {
  101. .label = "sys_mci",
  102. .base = -1,
  103. .ngpio = 2,
  104. };
  105. static struct bgpio_pdata vexpress_sysreg_sys_flash_pdata = {
  106. .label = "sys_flash",
  107. .base = -1,
  108. .ngpio = 1,
  109. };
  110. static struct syscon_platform_data vexpress_sysreg_sys_misc_pdata = {
  111. .label = "sys_misc",
  112. };
  113. static struct syscon_platform_data vexpress_sysreg_sys_procid_pdata = {
  114. .label = "sys_procid",
  115. };
  116. static struct mfd_cell vexpress_sysreg_cells[] = {
  117. {
  118. .name = "syscon",
  119. .num_resources = 1,
  120. .resources = (struct resource []) {
  121. DEFINE_RES_MEM(SYS_ID, 0x4),
  122. },
  123. .platform_data = &vexpress_sysreg_sys_id_pdata,
  124. .pdata_size = sizeof(vexpress_sysreg_sys_id_pdata),
  125. }, {
  126. .name = "basic-mmio-gpio",
  127. .of_compatible = "arm,vexpress-sysreg,sys_led",
  128. .num_resources = 1,
  129. .resources = (struct resource []) {
  130. DEFINE_RES_MEM_NAMED(SYS_LED, 0x4, "dat"),
  131. },
  132. .platform_data = &vexpress_sysreg_sys_led_pdata,
  133. .pdata_size = sizeof(vexpress_sysreg_sys_led_pdata),
  134. }, {
  135. .name = "basic-mmio-gpio",
  136. .of_compatible = "arm,vexpress-sysreg,sys_mci",
  137. .num_resources = 1,
  138. .resources = (struct resource []) {
  139. DEFINE_RES_MEM_NAMED(SYS_MCI, 0x4, "dat"),
  140. },
  141. .platform_data = &vexpress_sysreg_sys_mci_pdata,
  142. .pdata_size = sizeof(vexpress_sysreg_sys_mci_pdata),
  143. }, {
  144. .name = "basic-mmio-gpio",
  145. .of_compatible = "arm,vexpress-sysreg,sys_flash",
  146. .num_resources = 1,
  147. .resources = (struct resource []) {
  148. DEFINE_RES_MEM_NAMED(SYS_FLASH, 0x4, "dat"),
  149. },
  150. .platform_data = &vexpress_sysreg_sys_flash_pdata,
  151. .pdata_size = sizeof(vexpress_sysreg_sys_flash_pdata),
  152. }, {
  153. .name = "syscon",
  154. .num_resources = 1,
  155. .resources = (struct resource []) {
  156. DEFINE_RES_MEM(SYS_MISC, 0x4),
  157. },
  158. .platform_data = &vexpress_sysreg_sys_misc_pdata,
  159. .pdata_size = sizeof(vexpress_sysreg_sys_misc_pdata),
  160. }, {
  161. .name = "syscon",
  162. .num_resources = 1,
  163. .resources = (struct resource []) {
  164. DEFINE_RES_MEM(SYS_PROCID0, 0x8),
  165. },
  166. .platform_data = &vexpress_sysreg_sys_procid_pdata,
  167. .pdata_size = sizeof(vexpress_sysreg_sys_procid_pdata),
  168. }, {
  169. .name = "vexpress-syscfg",
  170. .num_resources = 1,
  171. .resources = (struct resource []) {
  172. DEFINE_RES_MEM(SYS_CFGDATA, 0xc),
  173. },
  174. }
  175. };
  176. static int vexpress_sysreg_probe(struct platform_device *pdev)
  177. {
  178. struct resource *mem;
  179. void __iomem *base;
  180. struct bgpio_chip *mmc_gpio_chip;
  181. u32 dt_hbi;
  182. mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  183. if (!mem)
  184. return -EINVAL;
  185. base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
  186. if (!base)
  187. return -ENOMEM;
  188. vexpress_config_set_master(vexpress_sysreg_get_master());
  189. /* Confirm board type against DT property, if available */
  190. if (of_property_read_u32(of_root, "arm,hbi", &dt_hbi) == 0) {
  191. u32 id = vexpress_get_procid(VEXPRESS_SITE_MASTER);
  192. u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
  193. if (WARN_ON(dt_hbi != hbi))
  194. dev_warn(&pdev->dev, "DT HBI (%x) is not matching hardware (%x)!\n",
  195. dt_hbi, hbi);
  196. }
  197. /*
  198. * Duplicated SYS_MCI pseudo-GPIO controller for compatibility with
  199. * older trees using sysreg node for MMC control lines.
  200. */
  201. mmc_gpio_chip = devm_kzalloc(&pdev->dev, sizeof(*mmc_gpio_chip),
  202. GFP_KERNEL);
  203. if (!mmc_gpio_chip)
  204. return -ENOMEM;
  205. bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
  206. NULL, NULL, NULL, NULL, 0);
  207. mmc_gpio_chip->gc.ngpio = 2;
  208. gpiochip_add(&mmc_gpio_chip->gc);
  209. return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
  210. vexpress_sysreg_cells,
  211. ARRAY_SIZE(vexpress_sysreg_cells), mem, 0, NULL);
  212. }
  213. static const struct of_device_id vexpress_sysreg_match[] = {
  214. { .compatible = "arm,vexpress-sysreg", },
  215. {},
  216. };
  217. static struct platform_driver vexpress_sysreg_driver = {
  218. .driver = {
  219. .name = "vexpress-sysreg",
  220. .of_match_table = vexpress_sysreg_match,
  221. },
  222. .probe = vexpress_sysreg_probe,
  223. };
  224. static int __init vexpress_sysreg_init(void)
  225. {
  226. struct device_node *node;
  227. /* Need the sysreg early, before any other device... */
  228. for_each_matching_node(node, vexpress_sysreg_match)
  229. of_platform_device_create(node, NULL, NULL);
  230. return platform_driver_register(&vexpress_sysreg_driver);
  231. }
  232. core_initcall(vexpress_sysreg_init);