physmap_of_versatile.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Versatile OF physmap driver add-on
  3. *
  4. * Copyright (c) 2016, Linaro Limited
  5. * Author: Linus Walleij <linus.walleij@linaro.org>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20. * MA 02111-1307 USA
  21. */
  22. #include <linux/export.h>
  23. #include <linux/io.h>
  24. #include <linux/of.h>
  25. #include <linux/of_address.h>
  26. #include <linux/of_device.h>
  27. #include <linux/mtd/map.h>
  28. #include <linux/mfd/syscon.h>
  29. #include <linux/regmap.h>
  30. #include <linux/bitops.h>
  31. #include "physmap_of_versatile.h"
  32. static struct regmap *syscon_regmap;
  33. enum versatile_flashprot {
  34. INTEGRATOR_AP_FLASHPROT,
  35. INTEGRATOR_CP_FLASHPROT,
  36. VERSATILE_FLASHPROT,
  37. REALVIEW_FLASHPROT,
  38. };
  39. static const struct of_device_id syscon_match[] = {
  40. {
  41. .compatible = "arm,integrator-ap-syscon",
  42. .data = (void *)INTEGRATOR_AP_FLASHPROT,
  43. },
  44. {
  45. .compatible = "arm,integrator-cp-syscon",
  46. .data = (void *)INTEGRATOR_CP_FLASHPROT,
  47. },
  48. {
  49. .compatible = "arm,core-module-versatile",
  50. .data = (void *)VERSATILE_FLASHPROT,
  51. },
  52. {
  53. .compatible = "arm,realview-eb-syscon",
  54. .data = (void *)REALVIEW_FLASHPROT,
  55. },
  56. {
  57. .compatible = "arm,realview-pb1176-syscon",
  58. .data = (void *)REALVIEW_FLASHPROT,
  59. },
  60. {
  61. .compatible = "arm,realview-pb11mp-syscon",
  62. .data = (void *)REALVIEW_FLASHPROT,
  63. },
  64. {
  65. .compatible = "arm,realview-pba8-syscon",
  66. .data = (void *)REALVIEW_FLASHPROT,
  67. },
  68. {
  69. .compatible = "arm,realview-pbx-syscon",
  70. .data = (void *)REALVIEW_FLASHPROT,
  71. },
  72. {},
  73. };
  74. /*
  75. * Flash protection handling for the Integrator/AP
  76. */
  77. #define INTEGRATOR_SC_CTRLS_OFFSET 0x08
  78. #define INTEGRATOR_SC_CTRLC_OFFSET 0x0C
  79. #define INTEGRATOR_SC_CTRL_FLVPPEN BIT(1)
  80. #define INTEGRATOR_SC_CTRL_FLWP BIT(2)
  81. #define INTEGRATOR_EBI_CSR1_OFFSET 0x04
  82. /* The manual says bit 2, the code says bit 3, trust the code */
  83. #define INTEGRATOR_EBI_WRITE_ENABLE BIT(3)
  84. #define INTEGRATOR_EBI_LOCK_OFFSET 0x20
  85. #define INTEGRATOR_EBI_LOCK_VAL 0xA05F
  86. static const struct of_device_id ebi_match[] = {
  87. { .compatible = "arm,external-bus-interface"},
  88. { },
  89. };
  90. static int ap_flash_init(struct platform_device *pdev)
  91. {
  92. struct device_node *ebi;
  93. void __iomem *ebi_base;
  94. u32 val;
  95. int ret;
  96. /* Look up the EBI */
  97. ebi = of_find_matching_node(NULL, ebi_match);
  98. if (!ebi) {
  99. return -ENODEV;
  100. }
  101. ebi_base = of_iomap(ebi, 0);
  102. if (!ebi_base)
  103. return -ENODEV;
  104. /* Clear VPP and write protection bits */
  105. ret = regmap_write(syscon_regmap,
  106. INTEGRATOR_SC_CTRLC_OFFSET,
  107. INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
  108. if (ret)
  109. dev_err(&pdev->dev, "error clearing Integrator VPP/WP\n");
  110. /* Unlock the EBI */
  111. writel(INTEGRATOR_EBI_LOCK_VAL, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
  112. /* Enable write cycles on the EBI, CSR1 (flash) */
  113. val = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
  114. val |= INTEGRATOR_EBI_WRITE_ENABLE;
  115. writel(val, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
  116. /* Lock the EBI again */
  117. writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
  118. iounmap(ebi_base);
  119. return 0;
  120. }
  121. static void ap_flash_set_vpp(struct map_info *map, int on)
  122. {
  123. int ret;
  124. if (on) {
  125. ret = regmap_write(syscon_regmap,
  126. INTEGRATOR_SC_CTRLS_OFFSET,
  127. INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
  128. if (ret)
  129. pr_err("error enabling AP VPP\n");
  130. } else {
  131. ret = regmap_write(syscon_regmap,
  132. INTEGRATOR_SC_CTRLC_OFFSET,
  133. INTEGRATOR_SC_CTRL_FLVPPEN | INTEGRATOR_SC_CTRL_FLWP);
  134. if (ret)
  135. pr_err("error disabling AP VPP\n");
  136. }
  137. }
  138. /*
  139. * Flash protection handling for the Integrator/CP
  140. */
  141. #define INTCP_FLASHPROG_OFFSET 0x04
  142. #define CINTEGRATOR_FLVPPEN BIT(0)
  143. #define CINTEGRATOR_FLWREN BIT(1)
  144. #define CINTEGRATOR_FLMASK BIT(0)|BIT(1)
  145. static void cp_flash_set_vpp(struct map_info *map, int on)
  146. {
  147. int ret;
  148. if (on) {
  149. ret = regmap_update_bits(syscon_regmap,
  150. INTCP_FLASHPROG_OFFSET,
  151. CINTEGRATOR_FLMASK,
  152. CINTEGRATOR_FLVPPEN | CINTEGRATOR_FLWREN);
  153. if (ret)
  154. pr_err("error setting CP VPP\n");
  155. } else {
  156. ret = regmap_update_bits(syscon_regmap,
  157. INTCP_FLASHPROG_OFFSET,
  158. CINTEGRATOR_FLMASK,
  159. 0);
  160. if (ret)
  161. pr_err("error setting CP VPP\n");
  162. }
  163. }
  164. /*
  165. * Flash protection handling for the Versatiles and RealViews
  166. */
  167. #define VERSATILE_SYS_FLASH_OFFSET 0x4C
  168. static void versatile_flash_set_vpp(struct map_info *map, int on)
  169. {
  170. int ret;
  171. ret = regmap_update_bits(syscon_regmap, VERSATILE_SYS_FLASH_OFFSET,
  172. 0x01, !!on);
  173. if (ret)
  174. pr_err("error setting Versatile VPP\n");
  175. }
  176. int of_flash_probe_versatile(struct platform_device *pdev,
  177. struct device_node *np,
  178. struct map_info *map)
  179. {
  180. struct device_node *sysnp;
  181. const struct of_device_id *devid;
  182. struct regmap *rmap;
  183. static enum versatile_flashprot versatile_flashprot;
  184. int ret;
  185. /* Not all flash chips use this protection line */
  186. if (!of_device_is_compatible(np, "arm,versatile-flash"))
  187. return 0;
  188. /* For first chip probed, look up the syscon regmap */
  189. if (!syscon_regmap) {
  190. sysnp = of_find_matching_node_and_match(NULL,
  191. syscon_match,
  192. &devid);
  193. if (!sysnp)
  194. return -ENODEV;
  195. versatile_flashprot = (enum versatile_flashprot)devid->data;
  196. rmap = syscon_node_to_regmap(sysnp);
  197. if (IS_ERR(rmap))
  198. return PTR_ERR(rmap);
  199. syscon_regmap = rmap;
  200. }
  201. switch (versatile_flashprot) {
  202. case INTEGRATOR_AP_FLASHPROT:
  203. ret = ap_flash_init(pdev);
  204. if (ret)
  205. return ret;
  206. map->set_vpp = ap_flash_set_vpp;
  207. dev_info(&pdev->dev, "Integrator/AP flash protection\n");
  208. break;
  209. case INTEGRATOR_CP_FLASHPROT:
  210. map->set_vpp = cp_flash_set_vpp;
  211. dev_info(&pdev->dev, "Integrator/CP flash protection\n");
  212. break;
  213. case VERSATILE_FLASHPROT:
  214. case REALVIEW_FLASHPROT:
  215. map->set_vpp = versatile_flash_set_vpp;
  216. dev_info(&pdev->dev, "versatile/realview flash protection\n");
  217. break;
  218. default:
  219. dev_info(&pdev->dev, "device marked as Versatile flash "
  220. "but no system controller was found\n");
  221. break;
  222. }
  223. return 0;
  224. }