light-iopmp.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2021 Alibaba Group Holding Limited.
  4. */
  5. #include <linux/module.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/interrupt.h>
  8. #include <linux/delay.h>
  9. #include <linux/kernel.h>
  10. #include <linux/slab.h>
  11. #include <linux/io.h>
  12. #include <linux/clk.h>
  13. #include <linux/completion.h>
  14. #include <linux/of.h>
  15. #include <linux/of_irq.h>
  16. #include <linux/regulator/consumer.h>
  17. #include <linux/of_platform.h>
  18. #include <linux/err.h>
  19. #include <dt-bindings/soc/thead,light-iopmp.h>
  20. #define LIGHT_PMP_MISC_CTRL 0x04
  21. #define LIGHT_PMP_DUMMY_ADDR 0x08
  22. #define LIGHT_PMP_PAGE_LOCK0 0x40
  23. #define LIGHT_PMP_ATTR_CFG0 0x80
  24. #define LIGHT_DEFAULT_PMP_ATTR_CFG 0xc0
  25. #define LIGHT_PMP_REGION0_SADDR 0x280
  26. #define LIGHT_PMP_REGION0_EADDR 0x284
  27. #define LIGHT_PMP_PAGE_LOCK0_REGIONS 0xFFFF
  28. #define LIGHT_PMP_PAGE_LOCK0_DEFAULT_CFG BIT(16)
  29. #define LIGHT_PMP_PAGE_LOCK0_BYPASS_EN BIT(17)
  30. #define LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR BIT(18)
  31. #define LIGHT_IOPMP_REGION_NUM 16
  32. #define LIGHT_IOPMP_ATTR_CFG_DEFAULT 0xFFFFFFFF
  33. #define LIGHT_IOPMP_DUMMY_ADDR 0x800000
  34. #define LIGHT_IOPMP_CTRL_BYPASS 0xFF000000
  35. struct light_iopmp_entry {
  36. u32 reg_start[LIGHT_IOPMP_REGION_NUM];
  37. u32 reg_end[LIGHT_IOPMP_REGION_NUM];
  38. u32 entry_valid_num;
  39. };
  40. struct light_iopmp_cur_sys_entry {
  41. int iopmp_type;
  42. u32 start_addr;
  43. u32 end_addr;
  44. u32 attr;
  45. int lock;
  46. };
  47. struct light_iopmp_info {
  48. struct device *dev;
  49. int entries;
  50. struct light_iopmp_list *iopmp_list;
  51. struct light_iopmp_cur_sys_entry cur_entry;
  52. struct light_iopmp_entry iopmp_entry[];
  53. };
  54. static struct light_iopmp_list {
  55. int iopmp_type;
  56. resource_size_t offset;
  57. void __iomem *base;
  58. } light_iopmp_lists[] = {
  59. {IOPMP_EMMC, 0xFFFC028000, NULL},
  60. {IOPMP_SDIO0, 0xFFFC029000, NULL},
  61. {IOPMP_SDIO1, 0xFFFC02A000, NULL},
  62. {IOPMP_USB0, 0xFFFC02E000, NULL},
  63. {IOPMP_AO, 0xFFFFC21000, NULL},
  64. {IOPMP_AUD, 0xFFFFC22000, NULL},
  65. {IOPMP_CHIP_DBG, 0xFFFFC37000, NULL},
  66. {IOPMP_EIP120I, 0xFFFF220000, NULL},
  67. {IOPMP_EIP120II, 0xFFFF230000, NULL},
  68. {IOPMP_EIP120III, 0xFFFF240000, NULL},
  69. {IOPMP_ISP0, 0xFFF4080000, NULL},
  70. {IOPMP_ISP1, 0xFFF4081000, NULL},
  71. {IOPMP_DW200, 0xFFF4082000, NULL},
  72. {IOPMP_VIPRE, 0xFFF4083000, NULL},
  73. {IOPMP_VENC, 0xFFFCC60000, NULL},
  74. {IOPMP_VDEC, 0xFFFCC61000, NULL},
  75. {IOPMP_G2D, 0xFFFCC62000, NULL},
  76. {IOPMP_FCE, 0xFFFCC63000, NULL},
  77. {IOPMP_NPU, 0xFFFF01C000, NULL},
  78. {IOPMP0_DPU, 0xFFFF520000, NULL},
  79. {IOPMP1_DPU, 0xFFFF521000, NULL},
  80. {IOPMP_GPU, 0xFFFF522000, NULL},
  81. {IOPMP_GMAC1, 0xFFFC001000, NULL},
  82. {IOPMP_GMAC2, 0xFFFC002000, NULL},
  83. {IOPMP_DMAC, 0xFFFFC20000, NULL},
  84. {IOPMP_TEE_DMAC, 0xFFFF250000, NULL},
  85. {IOPMP_DSP0, 0xFFFF058000, NULL},
  86. {IOPMP_DSP1, 0xFFFF059000, NULL},
  87. };
  88. static const struct light_iopmp_driver_data {
  89. struct light_iopmp_list *iopmp_list;
  90. } light_iopmp_data = {
  91. .iopmp_list = light_iopmp_lists,
  92. };
  93. static int light_iopmp_get_entries(struct light_iopmp_list *match)
  94. {
  95. if (match == light_iopmp_lists)
  96. return ARRAY_SIZE(light_iopmp_lists);
  97. return 0;
  98. }
  99. static int light_iopmp_get_type(struct light_iopmp_info *info, struct device_node *entry_np)
  100. {
  101. int entry_size = info->entries;
  102. struct light_iopmp_list *match = info->iopmp_list;
  103. unsigned long type;
  104. if (kstrtoul(entry_np->name, 0, &type))
  105. return -EINVAL;
  106. if (type < match[0].iopmp_type || type > match[entry_size - 1].iopmp_type)
  107. return -EINVAL;
  108. return type;
  109. }
  110. static bool light_iopmp_type_valid(struct light_iopmp_info *info, int tap)
  111. {
  112. int entry_size = info->entries;
  113. struct light_iopmp_list *match = info->iopmp_list;
  114. if (tap < match[0].iopmp_type || tap > match[entry_size - 1].iopmp_type)
  115. return false;
  116. return true;
  117. }
  118. static void light_iopmp_set_attr_bypass(struct light_iopmp_info *info, int type)
  119. {
  120. void __iomem *regs;
  121. u32 val;
  122. if (!info->iopmp_list[type].base) {
  123. regs = devm_ioremap(info->dev, info->iopmp_list[type].offset, PAGE_SIZE);
  124. if (!regs) {
  125. dev_err(info->dev, "ioremap failed\n");
  126. return;
  127. }
  128. info->iopmp_list[type].base = regs;
  129. }
  130. val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  131. if (val & LIGHT_PMP_PAGE_LOCK0_BYPASS_EN) {
  132. dev_info(info->dev, "iopmp bypass_en is already locked, ignore the tap[%d] setting\n", type);
  133. return;
  134. }
  135. val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
  136. val |= LIGHT_IOPMP_CTRL_BYPASS;
  137. writel(val, info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
  138. /* lock the iopmp */
  139. val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  140. val |= LIGHT_PMP_PAGE_LOCK0_BYPASS_EN;
  141. writel(val, info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  142. }
  143. static void light_iopmp_set_attr_default(struct light_iopmp_info *info, int type, int attr)
  144. {
  145. void __iomem *regs;
  146. u32 val;
  147. if (!info->iopmp_list[type].base) {
  148. regs = devm_ioremap(info->dev, info->iopmp_list[type].offset, PAGE_SIZE);
  149. if (!regs) {
  150. dev_err(info->dev, "ioremap failed\n");
  151. return;
  152. }
  153. info->iopmp_list[type].base = regs;
  154. }
  155. val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  156. if (val & LIGHT_PMP_PAGE_LOCK0_DEFAULT_CFG) {
  157. dev_info(info->dev, "iopmp default cfg is already locked, ignore the tap[%d] setting\n", type);
  158. return;
  159. }
  160. val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
  161. if (val & LIGHT_IOPMP_CTRL_BYPASS) {
  162. dev_info(info->dev, "iopmp bypass is already enabled, ignore the tap[%d] setting\n", type);
  163. return;
  164. }
  165. writel(attr, info->iopmp_list[type].base + LIGHT_DEFAULT_PMP_ATTR_CFG);
  166. /* lock the iopmp */
  167. val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  168. val |= LIGHT_PMP_PAGE_LOCK0_DEFAULT_CFG;
  169. writel(val, info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  170. }
  171. static void light_iopmp_set_attr(struct light_iopmp_info *info, int type, int attr,
  172. int dummy_slave, struct light_iopmp_entry *entry)
  173. {
  174. void __iomem *regs;
  175. bool dummy_slave_lock = false;
  176. u32 val;
  177. int i;
  178. if (!info->iopmp_list[type].base) {
  179. regs = devm_ioremap(info->dev, info->iopmp_list[type].offset, PAGE_SIZE);
  180. if (!regs) {
  181. dev_err(info->dev, "ioremap failed\n");
  182. return;
  183. }
  184. info->iopmp_list[type].base = regs;
  185. }
  186. val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  187. if (val & LIGHT_PMP_PAGE_LOCK0_REGIONS) {
  188. dev_info(info->dev, "iopmp regions cfg is already locked, ignore the tap[%d] setting\n", type);
  189. return;
  190. }
  191. if (val & LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR)
  192. dummy_slave_lock = true;
  193. val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
  194. if (val & LIGHT_IOPMP_CTRL_BYPASS) {
  195. dev_info(info->dev, "iopmp bypass is already enabled, ignore the tap[%d] setting\n", type);
  196. return;
  197. }
  198. for (i = 0; i < entry->entry_valid_num; i++) {
  199. writel(entry->reg_start[i],
  200. info->iopmp_list[type].base + LIGHT_PMP_REGION0_SADDR + (i << 3));
  201. writel(entry->reg_end[i],
  202. info->iopmp_list[type].base + LIGHT_PMP_REGION0_EADDR + (i << 3));
  203. writel(attr, info->iopmp_list[type].base + LIGHT_PMP_ATTR_CFG0 + (i << 2));
  204. }
  205. if (!dummy_slave_lock)
  206. writel(dummy_slave, info->iopmp_list[type].base + LIGHT_PMP_DUMMY_ADDR);
  207. /* lock the iopmp */
  208. val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  209. val |= LIGHT_PMP_PAGE_LOCK0_REGIONS | LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR;
  210. writel(val, info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  211. }
  212. static int light_iopmp_sys_set(struct light_iopmp_info *info)
  213. {
  214. void __iomem *regs;
  215. int type = info->cur_entry.iopmp_type;
  216. bool dummy_slave_lock = false;
  217. u32 val;
  218. if (!info->iopmp_list[type].base) {
  219. regs = devm_ioremap(info->dev, info->iopmp_list[type].offset, PAGE_SIZE);
  220. if (!regs) {
  221. dev_err(info->dev, "ioremap failed\n");
  222. return -ENOMEM;
  223. }
  224. info->iopmp_list[type].base = regs;
  225. }
  226. val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
  227. if (val & LIGHT_IOPMP_CTRL_BYPASS) {
  228. dev_err(info->dev, "iopmp bypass is already enabled, ignore the tap[%d] setting\n", type);
  229. return -EINVAL;
  230. }
  231. val = readl(info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  232. if (val & LIGHT_PMP_PAGE_LOCK0_REGIONS) {
  233. dev_err(info->dev, "iopmp regions cfg is already locked, ignore the tap[%d] setting\n", type);
  234. return -EINVAL;
  235. }
  236. if (val & LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR)
  237. dummy_slave_lock = true;
  238. val = readl(info->iopmp_list[type].base + LIGHT_PMP_MISC_CTRL);
  239. if (val & LIGHT_IOPMP_CTRL_BYPASS) {
  240. dev_err(info->dev, "iopmp bypass is already enabled, ignore the tap[%d] setting\n", type);
  241. return -EINVAL;
  242. }
  243. /* set one region from userspace's config */
  244. writel(info->cur_entry.start_addr,
  245. info->iopmp_list[type].base + LIGHT_PMP_REGION0_SADDR);
  246. writel(info->cur_entry.end_addr,
  247. info->iopmp_list[type].base + LIGHT_PMP_REGION0_EADDR);
  248. writel(info->cur_entry.attr, info->iopmp_list[type].base + LIGHT_PMP_ATTR_CFG0);
  249. if (!dummy_slave_lock)
  250. writel(LIGHT_IOPMP_DUMMY_ADDR, info->iopmp_list[type].base + LIGHT_PMP_DUMMY_ADDR);
  251. /* lock the iopmp */
  252. if (info->cur_entry.lock) {
  253. val = LIGHT_PMP_PAGE_LOCK0_REGIONS | LIGHT_PMP_PAGE_LOCK0_DEFAULT_CFG |
  254. LIGHT_PMP_PAGE_LOCK0_DUMMY_ADDR | LIGHT_PMP_PAGE_LOCK0_BYPASS_EN;
  255. writel(val, info->iopmp_list[type].base + LIGHT_PMP_PAGE_LOCK0);
  256. }
  257. return 0;
  258. }
  259. static ssize_t light_iopmp_tap_show(struct device *dev,
  260. struct device_attribute *attr,
  261. char *buf)
  262. {
  263. struct platform_device *pdev = to_platform_device(dev);
  264. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  265. ssize_t ret;
  266. ret = sprintf(buf, "%d\n", info->cur_entry.iopmp_type);
  267. return ret;
  268. }
  269. static ssize_t light_iopmp_start_addr_show(struct device *dev,
  270. struct device_attribute *attr,
  271. char *buf)
  272. {
  273. struct platform_device *pdev = to_platform_device(dev);
  274. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  275. ssize_t ret;
  276. ret = sprintf(buf, "0x%x\n", info->cur_entry.start_addr);
  277. return ret;
  278. }
  279. static ssize_t light_iopmp_end_addr_show(struct device *dev,
  280. struct device_attribute *attr,
  281. char *buf)
  282. {
  283. struct platform_device *pdev = to_platform_device(dev);
  284. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  285. ssize_t ret;
  286. ret = sprintf(buf, "0x%x\n", info->cur_entry.end_addr);
  287. return ret;
  288. }
  289. static ssize_t light_iopmp_attr_show(struct device *dev,
  290. struct device_attribute *attr,
  291. char *buf)
  292. {
  293. struct platform_device *pdev = to_platform_device(dev);
  294. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  295. ssize_t ret;
  296. ret = sprintf(buf, "0x%x\n", info->cur_entry.attr);
  297. return ret;
  298. }
  299. static ssize_t light_iopmp_lock_show(struct device *dev,
  300. struct device_attribute *attr,
  301. char *buf)
  302. {
  303. struct platform_device *pdev = to_platform_device(dev);
  304. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  305. ssize_t ret;
  306. ret = sprintf(buf, "%s\n", info->cur_entry.lock ? "locked" : "no lock");
  307. return ret;
  308. }
  309. static ssize_t light_iopmp_tap_store(struct device *dev,
  310. struct device_attribute *attr,
  311. const char *buf, size_t count)
  312. {
  313. struct platform_device *pdev = to_platform_device(dev);
  314. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  315. unsigned long val;
  316. if (kstrtoul(buf, 0, &val))
  317. return -EINVAL;
  318. if (light_iopmp_type_valid(info, (int)val))
  319. info->cur_entry.iopmp_type = val;
  320. else
  321. dev_err(dev, "invalid tap value\n");
  322. return count;
  323. }
  324. static ssize_t light_iopmp_start_addr_store(struct device *dev,
  325. struct device_attribute *attr,
  326. const char *buf, size_t count)
  327. {
  328. struct platform_device *pdev = to_platform_device(dev);
  329. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  330. unsigned long val;
  331. if (kstrtoul(buf, 0, &val))
  332. return -EINVAL;
  333. info->cur_entry.start_addr = (u32)val;
  334. return count;
  335. }
  336. static ssize_t light_iopmp_end_addr_store(struct device *dev,
  337. struct device_attribute *attr,
  338. const char *buf, size_t count)
  339. {
  340. struct platform_device *pdev = to_platform_device(dev);
  341. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  342. unsigned long val;
  343. if (kstrtoul(buf, 0, &val))
  344. return -EINVAL;
  345. if (!val)
  346. return -EINVAL;
  347. info->cur_entry.end_addr = (u32)val;
  348. return count;
  349. }
  350. static ssize_t light_iopmp_attr_store(struct device *dev,
  351. struct device_attribute *attr,
  352. const char *buf, size_t count)
  353. {
  354. struct platform_device *pdev = to_platform_device(dev);
  355. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  356. unsigned long val;
  357. if (kstrtoul(buf, 0, &val))
  358. return -EINVAL;
  359. info->cur_entry.attr = (u32)val;
  360. return count;
  361. }
  362. static ssize_t light_iopmp_lock_store(struct device *dev,
  363. struct device_attribute *attr,
  364. const char *buf, size_t count)
  365. {
  366. struct platform_device *pdev = to_platform_device(dev);
  367. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  368. unsigned long val;
  369. if (kstrtoul(buf, 0, &val))
  370. return -EINVAL;
  371. info->cur_entry.lock = (int)val;
  372. return count;
  373. }
  374. static ssize_t light_iopmp_set_store(struct device *dev,
  375. struct device_attribute *attr,
  376. const char *buf, size_t count)
  377. {
  378. struct platform_device *pdev = to_platform_device(dev);
  379. struct light_iopmp_info *info = platform_get_drvdata(pdev);
  380. unsigned long val;
  381. int ret;
  382. if (kstrtoul(buf, 0, &val))
  383. return -EINVAL;
  384. if (!val)
  385. return count;
  386. if (!light_iopmp_type_valid(info, info->cur_entry.iopmp_type)) {
  387. dev_err(dev, "invalid iopmp tap ID\n");
  388. return -EINVAL;
  389. }
  390. if (info->cur_entry.end_addr <= info->cur_entry.start_addr) {
  391. dev_err(dev, "invalid end_addr/start_addr setting\n");
  392. return -EINVAL;
  393. }
  394. ret = light_iopmp_sys_set(info);
  395. if (ret)
  396. return -EINVAL;
  397. return count;
  398. }
  399. static DEVICE_ATTR(light_iopmp_tap, 0644, light_iopmp_tap_show, light_iopmp_tap_store);
  400. static DEVICE_ATTR(light_iopmp_start_addr, 0644, light_iopmp_start_addr_show, light_iopmp_start_addr_store);
  401. static DEVICE_ATTR(light_iopmp_end_addr, 0644, light_iopmp_end_addr_show, light_iopmp_end_addr_store);
  402. static DEVICE_ATTR(light_iopmp_attr, 0644, light_iopmp_attr_show, light_iopmp_attr_store);
  403. static DEVICE_ATTR(light_iopmp_lock, 0644, light_iopmp_lock_show, light_iopmp_lock_store);
  404. static DEVICE_ATTR(light_iopmp_set, 0644, NULL, light_iopmp_set_store);
  405. static struct attribute *light_iopmp_sysfs_entries[] = {
  406. &dev_attr_light_iopmp_tap.attr,
  407. &dev_attr_light_iopmp_start_addr.attr,
  408. &dev_attr_light_iopmp_end_addr.attr,
  409. &dev_attr_light_iopmp_attr.attr,
  410. &dev_attr_light_iopmp_lock.attr,
  411. &dev_attr_light_iopmp_set.attr,
  412. NULL
  413. };
  414. static const struct attribute_group dev_attr_light_iopmp_group = {
  415. .attrs = light_iopmp_sysfs_entries,
  416. };
  417. static int light_iopmp_probe(struct platform_device *pdev)
  418. {
  419. struct device *dev = &pdev->dev;
  420. const struct light_iopmp_driver_data *drvdata = NULL;
  421. struct light_iopmp_list *match;
  422. struct light_iopmp_info *info;
  423. struct device_node *entry_np;
  424. int size, entries;
  425. int ret;
  426. drvdata = device_get_match_data(dev);
  427. if (!drvdata) {
  428. dev_err(dev, "cannot get driver data\n");
  429. return -ENOENT;
  430. }
  431. match = drvdata->iopmp_list;
  432. entries = light_iopmp_get_entries(match);
  433. if (entries <= 0)
  434. return -ENOENT;
  435. size = sizeof(struct light_iopmp_entry) * entries + sizeof(*info);
  436. info = devm_kzalloc(dev, size, GFP_KERNEL);
  437. if (!info)
  438. return -ENOMEM;
  439. info->entries = entries;
  440. info->iopmp_list = match;
  441. info->dev = dev;
  442. for_each_child_of_node(dev->of_node, entry_np) {
  443. int attr = LIGHT_IOPMP_ATTR_CFG_DEFAULT;
  444. int dummy_slave = LIGHT_IOPMP_DUMMY_ADDR;
  445. bool is_default_region = false;
  446. bool bypass_en = false;
  447. int region_size;
  448. int type;
  449. int i = 0, j;
  450. if (!of_device_is_available(entry_np))
  451. continue;
  452. type = light_iopmp_get_type(info, entry_np);
  453. if (type < 0) {
  454. dev_err(dev, "invalid iopmp tap:%d\n", type);
  455. continue;
  456. }
  457. ret = of_property_read_u32(entry_np, "attr", &attr);
  458. if (!ret && (attr == 0))
  459. attr = LIGHT_IOPMP_ATTR_CFG_DEFAULT;
  460. ret = of_property_read_u32(entry_np, "dummy_slave", &dummy_slave);
  461. if (!ret && (dummy_slave == 0))
  462. dummy_slave = LIGHT_IOPMP_DUMMY_ADDR;
  463. region_size = of_property_count_elems_of_size(entry_np, "regions", sizeof(u32));
  464. if (region_size <= 0) {
  465. is_default_region = of_property_read_bool(entry_np, "is_default_region");
  466. bypass_en = of_property_read_bool(entry_np, "bypass_en");
  467. if (!is_default_region && !bypass_en) {
  468. dev_err(dev, "missing/invalid reg property\n");
  469. continue;
  470. }
  471. /* config the iopmp entry */
  472. if (bypass_en)
  473. light_iopmp_set_attr_bypass(info, type);
  474. else if (is_default_region)
  475. light_iopmp_set_attr_default(info, type, attr);
  476. } else {
  477. region_size >>= 1;
  478. if (region_size > LIGHT_IOPMP_REGION_NUM) {
  479. dev_err(dev, "region size is invalid\n");
  480. continue;
  481. }
  482. for (j = 0; j < region_size; j++) {
  483. ret = of_property_read_u32_index(entry_np, "regions",
  484. j << 1, &info->iopmp_entry[i].reg_start[j]);
  485. if (ret)
  486. break;
  487. ret = of_property_read_u32_index(entry_np, "regions",
  488. (j << 1) + 1, &info->iopmp_entry[i].reg_end[j]);
  489. if (ret)
  490. break;
  491. /* check the region valid, otherwise drop the iopmp setting */
  492. if (j && info->iopmp_entry[i].reg_end[j - 1] > info->iopmp_entry[i].reg_start[j])
  493. break;
  494. }
  495. if (j == region_size) {
  496. info->iopmp_entry[i].entry_valid_num = region_size;
  497. /* config the iopmp entry */
  498. light_iopmp_set_attr(info, type, attr, dummy_slave, &info->iopmp_entry[i]);
  499. }
  500. }
  501. i++;
  502. }
  503. /* init the cur entry config */
  504. info->cur_entry.iopmp_type = -1;
  505. info->cur_entry.start_addr = 0;
  506. info->cur_entry.end_addr = 0;
  507. info->cur_entry.attr = 0;
  508. info->cur_entry.lock = false;
  509. platform_set_drvdata(pdev, info);
  510. ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_light_iopmp_group);
  511. if (ret) {
  512. dev_err(&pdev->dev, "Failed to create light iopmp debug sysfs.\n");
  513. return ret;
  514. }
  515. return 0;
  516. }
  517. static int light_iopmp_remove(struct platform_device *pdev)
  518. {
  519. platform_set_drvdata(pdev, NULL);
  520. return 0;
  521. }
  522. static int __maybe_unused light_iopmp_noirq_suspend(struct device *dev)
  523. {
  524. /* the iopmp clocks depend on module theirself,
  525. * we should keep them always enabled in clock's driver
  526. */
  527. return 0;
  528. }
  529. static int __maybe_unused light_iopmp_noirq_resume(struct device *dev)
  530. {
  531. /* TBD: restore IOPMP in noirq stage is too late ?
  532. * we should restore these registers setting in early arch resume ?
  533. */
  534. return 0;
  535. }
  536. static const struct dev_pm_ops light_iopmp_pm_ops = {
  537. SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(light_iopmp_noirq_suspend, light_iopmp_noirq_resume)
  538. };
  539. static const struct of_device_id light_iopmp_of_match[] = {
  540. { .compatible = "thead,light-iopmp", .data = &light_iopmp_data},
  541. {},
  542. };
  543. static struct platform_driver light_iopmp_driver = {
  544. .driver = {
  545. .name = "light-iopmp",
  546. .of_match_table = of_match_ptr(light_iopmp_of_match),
  547. .pm = &light_iopmp_pm_ops,
  548. },
  549. .probe = light_iopmp_probe,
  550. .remove = light_iopmp_remove,
  551. };
  552. static int __init light_iopmp_init(void)
  553. {
  554. return platform_driver_register(&light_iopmp_driver);
  555. }
  556. arch_initcall(light_iopmp_init);
  557. MODULE_ALIAS("platform:light-iopmp");
  558. MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>");
  559. MODULE_DESCRIPTION("Thead Light iopmp driver");
  560. MODULE_LICENSE("GPL v2");