sunxi_sram.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * Allwinner SoCs SRAM Controller Driver
  3. *
  4. * Copyright (C) 2015 Maxime Ripard
  5. *
  6. * Author: Maxime Ripard <maxime.ripard@free-electrons.com>
  7. *
  8. * This file is licensed under the terms of the GNU General Public
  9. * License version 2. This program is licensed "as is" without any
  10. * warranty of any kind, whether express or implied.
  11. */
  12. #include <linux/debugfs.h>
  13. #include <linux/io.h>
  14. #include <linux/module.h>
  15. #include <linux/of.h>
  16. #include <linux/of_address.h>
  17. #include <linux/of_device.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/regmap.h>
  20. #include <linux/soc/sunxi/sunxi_sram.h>
  21. struct sunxi_sram_func {
  22. char *func;
  23. u8 val;
  24. u32 reg_val;
  25. };
  26. struct sunxi_sram_data {
  27. char *name;
  28. u8 reg;
  29. u8 offset;
  30. u8 width;
  31. struct sunxi_sram_func *func;
  32. struct list_head list;
  33. };
  34. struct sunxi_sram_desc {
  35. struct sunxi_sram_data data;
  36. bool claimed;
  37. };
  38. #define SUNXI_SRAM_MAP(_reg_val, _val, _func) \
  39. { \
  40. .func = _func, \
  41. .val = _val, \
  42. .reg_val = _reg_val, \
  43. }
  44. #define SUNXI_SRAM_DATA(_name, _reg, _off, _width, ...) \
  45. { \
  46. .name = _name, \
  47. .reg = _reg, \
  48. .offset = _off, \
  49. .width = _width, \
  50. .func = (struct sunxi_sram_func[]){ \
  51. __VA_ARGS__, { } }, \
  52. }
  53. static struct sunxi_sram_desc sun4i_a10_sram_a3_a4 = {
  54. .data = SUNXI_SRAM_DATA("A3-A4", 0x4, 0x4, 2,
  55. SUNXI_SRAM_MAP(0, 0, "cpu"),
  56. SUNXI_SRAM_MAP(1, 1, "emac")),
  57. };
  58. static struct sunxi_sram_desc sun4i_a10_sram_c1 = {
  59. .data = SUNXI_SRAM_DATA("C1", 0x0, 0x0, 31,
  60. SUNXI_SRAM_MAP(0, 0, "cpu"),
  61. SUNXI_SRAM_MAP(0x7fffffff, 1, "ve")),
  62. };
  63. static struct sunxi_sram_desc sun4i_a10_sram_d = {
  64. .data = SUNXI_SRAM_DATA("D", 0x4, 0x0, 1,
  65. SUNXI_SRAM_MAP(0, 0, "cpu"),
  66. SUNXI_SRAM_MAP(1, 1, "usb-otg")),
  67. };
  68. static struct sunxi_sram_desc sun50i_a64_sram_c = {
  69. .data = SUNXI_SRAM_DATA("C", 0x4, 24, 1,
  70. SUNXI_SRAM_MAP(0, 1, "cpu"),
  71. SUNXI_SRAM_MAP(1, 0, "de2")),
  72. };
  73. static const struct of_device_id sunxi_sram_dt_ids[] = {
  74. {
  75. .compatible = "allwinner,sun4i-a10-sram-a3-a4",
  76. .data = &sun4i_a10_sram_a3_a4.data,
  77. },
  78. {
  79. .compatible = "allwinner,sun4i-a10-sram-c1",
  80. .data = &sun4i_a10_sram_c1.data,
  81. },
  82. {
  83. .compatible = "allwinner,sun4i-a10-sram-d",
  84. .data = &sun4i_a10_sram_d.data,
  85. },
  86. {
  87. .compatible = "allwinner,sun50i-a64-sram-c",
  88. .data = &sun50i_a64_sram_c.data,
  89. },
  90. {}
  91. };
  92. static struct device *sram_dev;
  93. static LIST_HEAD(claimed_sram);
  94. static DEFINE_SPINLOCK(sram_lock);
  95. static void __iomem *base;
  96. static int sunxi_sram_show(struct seq_file *s, void *data)
  97. {
  98. struct device_node *sram_node, *section_node;
  99. const struct sunxi_sram_data *sram_data;
  100. const struct of_device_id *match;
  101. struct sunxi_sram_func *func;
  102. const __be32 *sram_addr_p, *section_addr_p;
  103. u32 val;
  104. seq_puts(s, "Allwinner sunXi SRAM\n");
  105. seq_puts(s, "--------------------\n\n");
  106. for_each_child_of_node(sram_dev->of_node, sram_node) {
  107. sram_addr_p = of_get_address(sram_node, 0, NULL, NULL);
  108. seq_printf(s, "sram@%08x\n",
  109. be32_to_cpu(*sram_addr_p));
  110. for_each_child_of_node(sram_node, section_node) {
  111. match = of_match_node(sunxi_sram_dt_ids, section_node);
  112. if (!match)
  113. continue;
  114. sram_data = match->data;
  115. section_addr_p = of_get_address(section_node, 0,
  116. NULL, NULL);
  117. seq_printf(s, "\tsection@%04x\t(%s)\n",
  118. be32_to_cpu(*section_addr_p),
  119. sram_data->name);
  120. val = readl(base + sram_data->reg);
  121. val >>= sram_data->offset;
  122. val &= GENMASK(sram_data->width - 1, 0);
  123. for (func = sram_data->func; func->func; func++) {
  124. seq_printf(s, "\t\t%s%c\n", func->func,
  125. func->reg_val == val ?
  126. '*' : ' ');
  127. }
  128. }
  129. seq_puts(s, "\n");
  130. }
  131. return 0;
  132. }
  133. DEFINE_SHOW_ATTRIBUTE(sunxi_sram);
  134. static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data *data)
  135. {
  136. return container_of(data, struct sunxi_sram_desc, data);
  137. }
  138. static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *node,
  139. unsigned int *reg_value)
  140. {
  141. const struct of_device_id *match;
  142. const struct sunxi_sram_data *data;
  143. struct sunxi_sram_func *func;
  144. struct of_phandle_args args;
  145. u8 val;
  146. int ret;
  147. ret = of_parse_phandle_with_fixed_args(node, "allwinner,sram", 1, 0,
  148. &args);
  149. if (ret)
  150. return ERR_PTR(ret);
  151. if (!of_device_is_available(args.np)) {
  152. ret = -EBUSY;
  153. goto err;
  154. }
  155. val = args.args[0];
  156. match = of_match_node(sunxi_sram_dt_ids, args.np);
  157. if (!match) {
  158. ret = -EINVAL;
  159. goto err;
  160. }
  161. data = match->data;
  162. if (!data) {
  163. ret = -EINVAL;
  164. goto err;
  165. };
  166. for (func = data->func; func->func; func++) {
  167. if (val == func->val) {
  168. if (reg_value)
  169. *reg_value = func->reg_val;
  170. break;
  171. }
  172. }
  173. if (!func->func) {
  174. ret = -EINVAL;
  175. goto err;
  176. }
  177. of_node_put(args.np);
  178. return match->data;
  179. err:
  180. of_node_put(args.np);
  181. return ERR_PTR(ret);
  182. }
  183. int sunxi_sram_claim(struct device *dev)
  184. {
  185. const struct sunxi_sram_data *sram_data;
  186. struct sunxi_sram_desc *sram_desc;
  187. unsigned int device;
  188. u32 val, mask;
  189. if (IS_ERR(base))
  190. return PTR_ERR(base);
  191. if (!base)
  192. return -EPROBE_DEFER;
  193. if (!dev || !dev->of_node)
  194. return -EINVAL;
  195. sram_data = sunxi_sram_of_parse(dev->of_node, &device);
  196. if (IS_ERR(sram_data))
  197. return PTR_ERR(sram_data);
  198. sram_desc = to_sram_desc(sram_data);
  199. spin_lock(&sram_lock);
  200. if (sram_desc->claimed) {
  201. spin_unlock(&sram_lock);
  202. return -EBUSY;
  203. }
  204. mask = GENMASK(sram_data->offset + sram_data->width - 1,
  205. sram_data->offset);
  206. val = readl(base + sram_data->reg);
  207. val &= ~mask;
  208. writel(val | ((device << sram_data->offset) & mask),
  209. base + sram_data->reg);
  210. spin_unlock(&sram_lock);
  211. return 0;
  212. }
  213. EXPORT_SYMBOL(sunxi_sram_claim);
  214. int sunxi_sram_release(struct device *dev)
  215. {
  216. const struct sunxi_sram_data *sram_data;
  217. struct sunxi_sram_desc *sram_desc;
  218. if (!dev || !dev->of_node)
  219. return -EINVAL;
  220. sram_data = sunxi_sram_of_parse(dev->of_node, NULL);
  221. if (IS_ERR(sram_data))
  222. return -EINVAL;
  223. sram_desc = to_sram_desc(sram_data);
  224. spin_lock(&sram_lock);
  225. sram_desc->claimed = false;
  226. spin_unlock(&sram_lock);
  227. return 0;
  228. }
  229. EXPORT_SYMBOL(sunxi_sram_release);
  230. struct sunxi_sramc_variant {
  231. bool has_emac_clock;
  232. };
  233. static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
  234. /* Nothing special */
  235. };
  236. static const struct sunxi_sramc_variant sun8i_h3_sramc_variant = {
  237. .has_emac_clock = true,
  238. };
  239. static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
  240. .has_emac_clock = true,
  241. };
  242. #define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
  243. static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
  244. unsigned int reg)
  245. {
  246. if (reg == SUNXI_SRAM_EMAC_CLOCK_REG)
  247. return true;
  248. return false;
  249. }
  250. static struct regmap_config sunxi_sram_emac_clock_regmap = {
  251. .reg_bits = 32,
  252. .val_bits = 32,
  253. .reg_stride = 4,
  254. /* last defined register */
  255. .max_register = SUNXI_SRAM_EMAC_CLOCK_REG,
  256. /* other devices have no business accessing other registers */
  257. .readable_reg = sunxi_sram_regmap_accessible_reg,
  258. .writeable_reg = sunxi_sram_regmap_accessible_reg,
  259. };
  260. static int sunxi_sram_probe(struct platform_device *pdev)
  261. {
  262. struct resource *res;
  263. struct dentry *d;
  264. struct regmap *emac_clock;
  265. const struct sunxi_sramc_variant *variant;
  266. sram_dev = &pdev->dev;
  267. variant = of_device_get_match_data(&pdev->dev);
  268. if (!variant)
  269. return -EINVAL;
  270. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  271. base = devm_ioremap_resource(&pdev->dev, res);
  272. if (IS_ERR(base))
  273. return PTR_ERR(base);
  274. of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
  275. d = debugfs_create_file("sram", S_IRUGO, NULL, NULL,
  276. &sunxi_sram_fops);
  277. if (!d)
  278. return -ENOMEM;
  279. if (variant->has_emac_clock) {
  280. emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
  281. &sunxi_sram_emac_clock_regmap);
  282. if (IS_ERR(emac_clock))
  283. return PTR_ERR(emac_clock);
  284. }
  285. return 0;
  286. }
  287. static const struct of_device_id sunxi_sram_dt_match[] = {
  288. {
  289. .compatible = "allwinner,sun4i-a10-sram-controller",
  290. .data = &sun4i_a10_sramc_variant,
  291. },
  292. {
  293. .compatible = "allwinner,sun4i-a10-system-control",
  294. .data = &sun4i_a10_sramc_variant,
  295. },
  296. {
  297. .compatible = "allwinner,sun5i-a13-system-control",
  298. .data = &sun4i_a10_sramc_variant,
  299. },
  300. {
  301. .compatible = "allwinner,sun8i-a23-system-control",
  302. .data = &sun4i_a10_sramc_variant,
  303. },
  304. {
  305. .compatible = "allwinner,sun8i-h3-system-control",
  306. .data = &sun8i_h3_sramc_variant,
  307. },
  308. {
  309. .compatible = "allwinner,sun50i-a64-sram-controller",
  310. .data = &sun50i_a64_sramc_variant,
  311. },
  312. {
  313. .compatible = "allwinner,sun50i-a64-system-control",
  314. .data = &sun50i_a64_sramc_variant,
  315. },
  316. {
  317. .compatible = "allwinner,sun50i-h5-system-control",
  318. .data = &sun50i_a64_sramc_variant,
  319. },
  320. { },
  321. };
  322. MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match);
  323. static struct platform_driver sunxi_sram_driver = {
  324. .driver = {
  325. .name = "sunxi-sram",
  326. .of_match_table = sunxi_sram_dt_match,
  327. },
  328. .probe = sunxi_sram_probe,
  329. };
  330. module_platform_driver(sunxi_sram_driver);
  331. MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
  332. MODULE_DESCRIPTION("Allwinner sunXi SRAM Controller Driver");
  333. MODULE_LICENSE("GPL");