sunxi_sram.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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. static int sunxi_sram_open(struct inode *inode, struct file *file)
  134. {
  135. return single_open(file, sunxi_sram_show, inode->i_private);
  136. }
  137. static const struct file_operations sunxi_sram_fops = {
  138. .open = sunxi_sram_open,
  139. .read = seq_read,
  140. .llseek = seq_lseek,
  141. .release = single_release,
  142. };
  143. static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data *data)
  144. {
  145. return container_of(data, struct sunxi_sram_desc, data);
  146. }
  147. static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *node,
  148. unsigned int *reg_value)
  149. {
  150. const struct of_device_id *match;
  151. const struct sunxi_sram_data *data;
  152. struct sunxi_sram_func *func;
  153. struct of_phandle_args args;
  154. u8 val;
  155. int ret;
  156. ret = of_parse_phandle_with_fixed_args(node, "allwinner,sram", 1, 0,
  157. &args);
  158. if (ret)
  159. return ERR_PTR(ret);
  160. if (!of_device_is_available(args.np)) {
  161. ret = -EBUSY;
  162. goto err;
  163. }
  164. val = args.args[0];
  165. match = of_match_node(sunxi_sram_dt_ids, args.np);
  166. if (!match) {
  167. ret = -EINVAL;
  168. goto err;
  169. }
  170. data = match->data;
  171. if (!data) {
  172. ret = -EINVAL;
  173. goto err;
  174. };
  175. for (func = data->func; func->func; func++) {
  176. if (val == func->val) {
  177. if (reg_value)
  178. *reg_value = func->reg_val;
  179. break;
  180. }
  181. }
  182. if (!func->func) {
  183. ret = -EINVAL;
  184. goto err;
  185. }
  186. of_node_put(args.np);
  187. return match->data;
  188. err:
  189. of_node_put(args.np);
  190. return ERR_PTR(ret);
  191. }
  192. int sunxi_sram_claim(struct device *dev)
  193. {
  194. const struct sunxi_sram_data *sram_data;
  195. struct sunxi_sram_desc *sram_desc;
  196. unsigned int device;
  197. u32 val, mask;
  198. if (IS_ERR(base))
  199. return PTR_ERR(base);
  200. if (!base)
  201. return -EPROBE_DEFER;
  202. if (!dev || !dev->of_node)
  203. return -EINVAL;
  204. sram_data = sunxi_sram_of_parse(dev->of_node, &device);
  205. if (IS_ERR(sram_data))
  206. return PTR_ERR(sram_data);
  207. sram_desc = to_sram_desc(sram_data);
  208. spin_lock(&sram_lock);
  209. if (sram_desc->claimed) {
  210. spin_unlock(&sram_lock);
  211. return -EBUSY;
  212. }
  213. mask = GENMASK(sram_data->offset + sram_data->width - 1,
  214. sram_data->offset);
  215. val = readl(base + sram_data->reg);
  216. val &= ~mask;
  217. writel(val | ((device << sram_data->offset) & mask),
  218. base + sram_data->reg);
  219. spin_unlock(&sram_lock);
  220. return 0;
  221. }
  222. EXPORT_SYMBOL(sunxi_sram_claim);
  223. int sunxi_sram_release(struct device *dev)
  224. {
  225. const struct sunxi_sram_data *sram_data;
  226. struct sunxi_sram_desc *sram_desc;
  227. if (!dev || !dev->of_node)
  228. return -EINVAL;
  229. sram_data = sunxi_sram_of_parse(dev->of_node, NULL);
  230. if (IS_ERR(sram_data))
  231. return -EINVAL;
  232. sram_desc = to_sram_desc(sram_data);
  233. spin_lock(&sram_lock);
  234. sram_desc->claimed = false;
  235. spin_unlock(&sram_lock);
  236. return 0;
  237. }
  238. EXPORT_SYMBOL(sunxi_sram_release);
  239. struct sunxi_sramc_variant {
  240. bool has_emac_clock;
  241. };
  242. static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
  243. /* Nothing special */
  244. };
  245. static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
  246. .has_emac_clock = true,
  247. };
  248. #define SUNXI_SRAM_EMAC_CLOCK_REG 0x30
  249. static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
  250. unsigned int reg)
  251. {
  252. if (reg == SUNXI_SRAM_EMAC_CLOCK_REG)
  253. return true;
  254. return false;
  255. }
  256. static struct regmap_config sunxi_sram_emac_clock_regmap = {
  257. .reg_bits = 32,
  258. .val_bits = 32,
  259. .reg_stride = 4,
  260. /* last defined register */
  261. .max_register = SUNXI_SRAM_EMAC_CLOCK_REG,
  262. /* other devices have no business accessing other registers */
  263. .readable_reg = sunxi_sram_regmap_accessible_reg,
  264. .writeable_reg = sunxi_sram_regmap_accessible_reg,
  265. };
  266. static int sunxi_sram_probe(struct platform_device *pdev)
  267. {
  268. struct resource *res;
  269. struct dentry *d;
  270. struct regmap *emac_clock;
  271. const struct sunxi_sramc_variant *variant;
  272. sram_dev = &pdev->dev;
  273. variant = of_device_get_match_data(&pdev->dev);
  274. if (!variant)
  275. return -EINVAL;
  276. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  277. base = devm_ioremap_resource(&pdev->dev, res);
  278. if (IS_ERR(base))
  279. return PTR_ERR(base);
  280. of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
  281. d = debugfs_create_file("sram", S_IRUGO, NULL, NULL,
  282. &sunxi_sram_fops);
  283. if (!d)
  284. return -ENOMEM;
  285. if (variant->has_emac_clock) {
  286. emac_clock = devm_regmap_init_mmio(&pdev->dev, base,
  287. &sunxi_sram_emac_clock_regmap);
  288. if (IS_ERR(emac_clock))
  289. return PTR_ERR(emac_clock);
  290. }
  291. return 0;
  292. }
  293. static const struct of_device_id sunxi_sram_dt_match[] = {
  294. {
  295. .compatible = "allwinner,sun4i-a10-sram-controller",
  296. .data = &sun4i_a10_sramc_variant,
  297. },
  298. {
  299. .compatible = "allwinner,sun4i-a10-system-control",
  300. .data = &sun4i_a10_sramc_variant,
  301. },
  302. {
  303. .compatible = "allwinner,sun5i-a13-system-control",
  304. .data = &sun4i_a10_sramc_variant,
  305. },
  306. {
  307. .compatible = "allwinner,sun8i-a23-system-control",
  308. .data = &sun4i_a10_sramc_variant,
  309. },
  310. {
  311. .compatible = "allwinner,sun8i-h3-system-control",
  312. .data = &sun4i_a10_sramc_variant,
  313. },
  314. {
  315. .compatible = "allwinner,sun50i-a64-sram-controller",
  316. .data = &sun50i_a64_sramc_variant,
  317. },
  318. {
  319. .compatible = "allwinner,sun50i-a64-system-control",
  320. .data = &sun50i_a64_sramc_variant,
  321. },
  322. { },
  323. };
  324. MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match);
  325. static struct platform_driver sunxi_sram_driver = {
  326. .driver = {
  327. .name = "sunxi-sram",
  328. .of_match_table = sunxi_sram_dt_match,
  329. },
  330. .probe = sunxi_sram_probe,
  331. };
  332. module_platform_driver(sunxi_sram_driver);
  333. MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
  334. MODULE_DESCRIPTION("Allwinner sunXi SRAM Controller Driver");
  335. MODULE_LICENSE("GPL");