msm-spm.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/delay.h>
  16. #include <linux/init.h>
  17. #include <linux/io.h>
  18. #include <linux/slab.h>
  19. #include "spm_driver.h"
  20. #define MSM_SPM_PMIC_STATE_IDLE 0
  21. enum {
  22. MSM_SPM_DEBUG_SHADOW = 1U << 0,
  23. MSM_SPM_DEBUG_VCTL = 1U << 1,
  24. };
  25. static int msm_spm_debug_mask;
  26. module_param_named(
  27. debug_mask, msm_spm_debug_mask, int, 0664
  28. );
  29. struct saw2_data {
  30. const char *ver_name;
  31. uint32_t major;
  32. uint32_t minor;
  33. uint32_t *spm_reg_offset_ptr;
  34. };
  35. static uint32_t msm_spm_reg_offsets_saw2_v2_1[MSM_SPM_REG_NR] = {
  36. [MSM_SPM_REG_SAW_SECURE] = 0x00,
  37. [MSM_SPM_REG_SAW_ID] = 0x04,
  38. [MSM_SPM_REG_SAW_CFG] = 0x08,
  39. [MSM_SPM_REG_SAW_SPM_STS] = 0x0C,
  40. [MSM_SPM_REG_SAW_AVS_STS] = 0x10,
  41. [MSM_SPM_REG_SAW_PMIC_STS] = 0x14,
  42. [MSM_SPM_REG_SAW_RST] = 0x18,
  43. [MSM_SPM_REG_SAW_VCTL] = 0x1C,
  44. [MSM_SPM_REG_SAW_AVS_CTL] = 0x20,
  45. [MSM_SPM_REG_SAW_AVS_LIMIT] = 0x24,
  46. [MSM_SPM_REG_SAW_AVS_DLY] = 0x28,
  47. [MSM_SPM_REG_SAW_AVS_HYSTERESIS] = 0x2C,
  48. [MSM_SPM_REG_SAW_SPM_CTL] = 0x30,
  49. [MSM_SPM_REG_SAW_SPM_DLY] = 0x34,
  50. [MSM_SPM_REG_SAW_PMIC_DATA_0] = 0x40,
  51. [MSM_SPM_REG_SAW_PMIC_DATA_1] = 0x44,
  52. [MSM_SPM_REG_SAW_PMIC_DATA_2] = 0x48,
  53. [MSM_SPM_REG_SAW_PMIC_DATA_3] = 0x4C,
  54. [MSM_SPM_REG_SAW_PMIC_DATA_4] = 0x50,
  55. [MSM_SPM_REG_SAW_PMIC_DATA_5] = 0x54,
  56. [MSM_SPM_REG_SAW_PMIC_DATA_6] = 0x58,
  57. [MSM_SPM_REG_SAW_PMIC_DATA_7] = 0x5C,
  58. [MSM_SPM_REG_SAW_SEQ_ENTRY] = 0x80,
  59. [MSM_SPM_REG_SAW_VERSION] = 0xFD0,
  60. };
  61. static uint32_t msm_spm_reg_offsets_saw2_v3_0[MSM_SPM_REG_NR] = {
  62. [MSM_SPM_REG_SAW_SECURE] = 0x00,
  63. [MSM_SPM_REG_SAW_ID] = 0x04,
  64. [MSM_SPM_REG_SAW_CFG] = 0x08,
  65. [MSM_SPM_REG_SAW_SPM_STS] = 0x0C,
  66. [MSM_SPM_REG_SAW_AVS_STS] = 0x10,
  67. [MSM_SPM_REG_SAW_PMIC_STS] = 0x14,
  68. [MSM_SPM_REG_SAW_RST] = 0x18,
  69. [MSM_SPM_REG_SAW_VCTL] = 0x1C,
  70. [MSM_SPM_REG_SAW_AVS_CTL] = 0x20,
  71. [MSM_SPM_REG_SAW_AVS_LIMIT] = 0x24,
  72. [MSM_SPM_REG_SAW_AVS_DLY] = 0x28,
  73. [MSM_SPM_REG_SAW_AVS_HYSTERESIS] = 0x2C,
  74. [MSM_SPM_REG_SAW_SPM_CTL] = 0x30,
  75. [MSM_SPM_REG_SAW_SPM_DLY] = 0x34,
  76. [MSM_SPM_REG_SAW_STS2] = 0x38,
  77. [MSM_SPM_REG_SAW_PMIC_DATA_0] = 0x40,
  78. [MSM_SPM_REG_SAW_PMIC_DATA_1] = 0x44,
  79. [MSM_SPM_REG_SAW_PMIC_DATA_2] = 0x48,
  80. [MSM_SPM_REG_SAW_PMIC_DATA_3] = 0x4C,
  81. [MSM_SPM_REG_SAW_PMIC_DATA_4] = 0x50,
  82. [MSM_SPM_REG_SAW_PMIC_DATA_5] = 0x54,
  83. [MSM_SPM_REG_SAW_PMIC_DATA_6] = 0x58,
  84. [MSM_SPM_REG_SAW_PMIC_DATA_7] = 0x5C,
  85. [MSM_SPM_REG_SAW_SEQ_ENTRY] = 0x400,
  86. [MSM_SPM_REG_SAW_VERSION] = 0xFD0,
  87. };
  88. static uint32_t msm_spm_reg_offsets_saw2_v4_1[MSM_SPM_REG_NR] = {
  89. [MSM_SPM_REG_SAW_SECURE] = 0xC00,
  90. [MSM_SPM_REG_SAW_ID] = 0xC04,
  91. [MSM_SPM_REG_SAW_STS2] = 0xC10,
  92. [MSM_SPM_REG_SAW_SPM_STS] = 0xC0C,
  93. [MSM_SPM_REG_SAW_AVS_STS] = 0xC14,
  94. [MSM_SPM_REG_SAW_PMIC_STS] = 0xC18,
  95. [MSM_SPM_REG_SAW_RST] = 0xC1C,
  96. [MSM_SPM_REG_SAW_VCTL] = 0x900,
  97. [MSM_SPM_REG_SAW_AVS_CTL] = 0x904,
  98. [MSM_SPM_REG_SAW_AVS_LIMIT] = 0x908,
  99. [MSM_SPM_REG_SAW_AVS_DLY] = 0x90C,
  100. [MSM_SPM_REG_SAW_SPM_CTL] = 0x0,
  101. [MSM_SPM_REG_SAW_SPM_DLY] = 0x4,
  102. [MSM_SPM_REG_SAW_CFG] = 0x0C,
  103. [MSM_SPM_REG_SAW_PMIC_DATA_0] = 0x40,
  104. [MSM_SPM_REG_SAW_PMIC_DATA_1] = 0x44,
  105. [MSM_SPM_REG_SAW_PMIC_DATA_2] = 0x48,
  106. [MSM_SPM_REG_SAW_PMIC_DATA_3] = 0x4C,
  107. [MSM_SPM_REG_SAW_PMIC_DATA_4] = 0x50,
  108. [MSM_SPM_REG_SAW_PMIC_DATA_5] = 0x54,
  109. [MSM_SPM_REG_SAW_SEQ_ENTRY] = 0x400,
  110. [MSM_SPM_REG_SAW_VERSION] = 0xFD0,
  111. };
  112. static struct saw2_data saw2_info[] = {
  113. [0] = {
  114. "SAW_v2.1",
  115. 0x2,
  116. 0x1,
  117. msm_spm_reg_offsets_saw2_v2_1,
  118. },
  119. [1] = {
  120. "SAW_v2.3",
  121. 0x3,
  122. 0x0,
  123. msm_spm_reg_offsets_saw2_v3_0,
  124. },
  125. [2] = {
  126. "SAW_v3.0",
  127. 0x1,
  128. 0x0,
  129. msm_spm_reg_offsets_saw2_v3_0,
  130. },
  131. [3] = {
  132. "SAW_v4.0",
  133. 0x4,
  134. 0x1,
  135. msm_spm_reg_offsets_saw2_v4_1,
  136. },
  137. };
  138. static uint32_t num_pmic_data;
  139. static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
  140. unsigned int reg_index)
  141. {
  142. if (!dev || !dev->reg_shadow)
  143. return;
  144. __raw_writel(dev->reg_shadow[reg_index],
  145. dev->reg_base_addr + dev->reg_offsets[reg_index]);
  146. }
  147. static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
  148. unsigned int reg_index)
  149. {
  150. dev->reg_shadow[reg_index] =
  151. __raw_readl(dev->reg_base_addr +
  152. dev->reg_offsets[reg_index]);
  153. }
  154. static inline uint32_t msm_spm_drv_get_num_spm_entry(
  155. struct msm_spm_driver_data *dev)
  156. {
  157. if (!dev)
  158. return -ENODEV;
  159. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_ID);
  160. return (dev->reg_shadow[MSM_SPM_REG_SAW_ID] >> 24) & 0xFF;
  161. }
  162. static inline void msm_spm_drv_set_start_addr(
  163. struct msm_spm_driver_data *dev, uint32_t ctl)
  164. {
  165. dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] = ctl;
  166. }
  167. static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev)
  168. {
  169. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_ID);
  170. return (dev->reg_shadow[MSM_SPM_REG_SAW_ID] >> 2) & 0x1;
  171. }
  172. static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
  173. uint32_t vlevel, uint32_t vctl_port)
  174. {
  175. unsigned int pmic_data = 0;
  176. pmic_data |= vlevel;
  177. pmic_data |= (vctl_port & 0x7) << 16;
  178. dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] &= ~0x700FF;
  179. dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] |= pmic_data;
  180. dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_DATA_3] &= ~0x700FF;
  181. dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_DATA_3] |= pmic_data;
  182. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_VCTL);
  183. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_PMIC_DATA_3);
  184. }
  185. static inline uint32_t msm_spm_drv_get_num_pmic_data(
  186. struct msm_spm_driver_data *dev)
  187. {
  188. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_ID);
  189. mb(); /* Ensure we flush */
  190. return (dev->reg_shadow[MSM_SPM_REG_SAW_ID] >> 4) & 0x7;
  191. }
  192. static inline uint32_t msm_spm_drv_get_sts_pmic_state(
  193. struct msm_spm_driver_data *dev)
  194. {
  195. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_PMIC_STS);
  196. return (dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_STS] >> 16) &
  197. 0x03;
  198. }
  199. uint32_t msm_spm_drv_get_sts_curr_pmic_data(
  200. struct msm_spm_driver_data *dev)
  201. {
  202. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_PMIC_STS);
  203. return dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_STS] & 0x300FF;
  204. }
  205. static inline void msm_spm_drv_get_saw2_ver(struct msm_spm_driver_data *dev,
  206. uint32_t *major, uint32_t *minor)
  207. {
  208. uint32_t val = 0;
  209. dev->reg_shadow[MSM_SPM_REG_SAW_VERSION] =
  210. __raw_readl(dev->reg_base_addr + dev->ver_reg);
  211. val = dev->reg_shadow[MSM_SPM_REG_SAW_VERSION];
  212. *major = (val >> 28) & 0xF;
  213. *minor = (val >> 16) & 0xFFF;
  214. }
  215. inline int msm_spm_drv_set_spm_enable(
  216. struct msm_spm_driver_data *dev, bool enable)
  217. {
  218. uint32_t value = enable ? 0x01 : 0x00;
  219. if (!dev)
  220. return -EINVAL;
  221. if ((dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] & 0x01) ^ value) {
  222. dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] &= ~0x1;
  223. dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] |= value;
  224. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_SPM_CTL);
  225. wmb(); /* Ensure we flush */
  226. }
  227. return 0;
  228. }
  229. int msm_spm_drv_get_avs_enable(struct msm_spm_driver_data *dev)
  230. {
  231. if (!dev)
  232. return -EINVAL;
  233. return dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & 0x01;
  234. }
  235. int msm_spm_drv_set_avs_enable(struct msm_spm_driver_data *dev,
  236. bool enable)
  237. {
  238. uint32_t value = enable ? 0x1 : 0x0;
  239. if (!dev)
  240. return -EINVAL;
  241. if ((dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & 0x1) ^ value) {
  242. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~0x1;
  243. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= value;
  244. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  245. }
  246. return 0;
  247. }
  248. int msm_spm_drv_set_avs_limit(struct msm_spm_driver_data *dev,
  249. uint32_t min_lvl, uint32_t max_lvl)
  250. {
  251. uint32_t value = (max_lvl & 0xff) << 16 | (min_lvl & 0xff);
  252. if (!dev)
  253. return -EINVAL;
  254. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_LIMIT] = value;
  255. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_LIMIT);
  256. return 0;
  257. }
  258. static int msm_spm_drv_avs_irq_mask(enum msm_spm_avs_irq irq)
  259. {
  260. switch (irq) {
  261. case MSM_SPM_AVS_IRQ_MIN:
  262. return BIT(1);
  263. case MSM_SPM_AVS_IRQ_MAX:
  264. return BIT(2);
  265. default:
  266. return -EINVAL;
  267. }
  268. }
  269. int msm_spm_drv_set_avs_irq_enable(struct msm_spm_driver_data *dev,
  270. enum msm_spm_avs_irq irq, bool enable)
  271. {
  272. int mask = msm_spm_drv_avs_irq_mask(irq);
  273. uint32_t value;
  274. if (!dev)
  275. return -EINVAL;
  276. else if (mask < 0)
  277. return mask;
  278. value = enable ? mask : 0;
  279. if ((dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & mask) ^ value) {
  280. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~mask;
  281. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= value;
  282. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  283. }
  284. return 0;
  285. }
  286. int msm_spm_drv_avs_clear_irq(struct msm_spm_driver_data *dev,
  287. enum msm_spm_avs_irq irq)
  288. {
  289. int mask = msm_spm_drv_avs_irq_mask(irq);
  290. if (!dev)
  291. return -EINVAL;
  292. else if (mask < 0)
  293. return mask;
  294. if (dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & mask) {
  295. /*
  296. * The interrupt status is cleared by disabling and then
  297. * re-enabling the interrupt.
  298. */
  299. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~mask;
  300. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  301. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= mask;
  302. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  303. }
  304. return 0;
  305. }
  306. void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev)
  307. {
  308. int i;
  309. int num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
  310. if (!dev) {
  311. __WARN();
  312. return;
  313. }
  314. for (i = 0; i < num_spm_entry; i++) {
  315. __raw_writel(dev->reg_seq_entry_shadow[i],
  316. dev->reg_base_addr
  317. + dev->reg_offsets[MSM_SPM_REG_SAW_SEQ_ENTRY]
  318. + 4 * i);
  319. }
  320. mb(); /* Ensure we flush */
  321. }
  322. void dump_regs(struct msm_spm_driver_data *dev, int cpu)
  323. {
  324. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_SPM_STS);
  325. mb(); /* Ensure we flush */
  326. pr_err("CPU%d: spm register MSM_SPM_REG_SAW_SPM_STS: 0x%x\n", cpu,
  327. dev->reg_shadow[MSM_SPM_REG_SAW_SPM_STS]);
  328. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_SPM_CTL);
  329. mb(); /* Ensure we flush */
  330. pr_err("CPU%d: spm register MSM_SPM_REG_SAW_SPM_CTL: 0x%x\n", cpu,
  331. dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL]);
  332. }
  333. int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
  334. uint8_t *cmd, uint32_t *offset)
  335. {
  336. uint32_t cmd_w;
  337. uint32_t offset_w = *offset / 4;
  338. uint8_t last_cmd;
  339. if (!cmd)
  340. return -EINVAL;
  341. while (1) {
  342. int i;
  343. cmd_w = 0;
  344. last_cmd = 0;
  345. cmd_w = dev->reg_seq_entry_shadow[offset_w];
  346. for (i = (*offset % 4); i < 4; i++) {
  347. last_cmd = *(cmd++);
  348. cmd_w |= last_cmd << (i * 8);
  349. (*offset)++;
  350. if (last_cmd == 0x0f)
  351. break;
  352. }
  353. dev->reg_seq_entry_shadow[offset_w++] = cmd_w;
  354. if (last_cmd == 0x0f)
  355. break;
  356. }
  357. return 0;
  358. }
  359. int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
  360. uint32_t ctl)
  361. {
  362. /* SPM is configured to reset start address to zero after end of Program
  363. */
  364. if (!dev)
  365. return -EINVAL;
  366. msm_spm_drv_set_start_addr(dev, ctl);
  367. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_SPM_CTL);
  368. wmb(); /* Ensure we flush */
  369. if (msm_spm_debug_mask & MSM_SPM_DEBUG_SHADOW) {
  370. int i;
  371. for (i = 0; i < MSM_SPM_REG_NR; i++)
  372. pr_info("%s: reg %02x = 0x%08x\n", __func__,
  373. dev->reg_offsets[i], dev->reg_shadow[i]);
  374. }
  375. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_SPM_STS);
  376. return 0;
  377. }
  378. uint32_t msm_spm_drv_get_vdd(struct msm_spm_driver_data *dev)
  379. {
  380. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_PMIC_STS);
  381. return dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_STS] & 0xFF;
  382. }
  383. #ifdef CONFIG_MSM_AVS_HW
  384. static bool msm_spm_drv_is_avs_enabled(struct msm_spm_driver_data *dev)
  385. {
  386. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  387. return dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & BIT(0);
  388. }
  389. static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev)
  390. {
  391. msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  392. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~BIT(27);
  393. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  394. }
  395. static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev)
  396. {
  397. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= BIT(27);
  398. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  399. }
  400. static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
  401. unsigned int vlevel)
  402. {
  403. vlevel &= 0x3f;
  404. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~0x7efc00;
  405. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= ((vlevel - 4) << 10);
  406. dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= (vlevel << 17);
  407. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
  408. }
  409. #else
  410. static bool msm_spm_drv_is_avs_enabled(struct msm_spm_driver_data *dev)
  411. {
  412. return false;
  413. }
  414. static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev) { }
  415. static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev) { }
  416. static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
  417. unsigned int vlevel) { }
  418. #endif
  419. static inline int msm_spm_drv_validate_data(struct msm_spm_driver_data *dev,
  420. unsigned int vlevel, int vctl_port)
  421. {
  422. int timeout_us = dev->vctl_timeout_us;
  423. uint32_t new_level;
  424. /* Confirm the voltage we set was what hardware sent and
  425. * FSM is idle.
  426. */
  427. do {
  428. udelay(1);
  429. new_level = msm_spm_drv_get_sts_curr_pmic_data(dev);
  430. /**
  431. * VCTL_PORT has to be 0, for vlevel to be updated.
  432. * If port is not 0, check for PMIC_STATE only.
  433. */
  434. if (((new_level & 0x30000) == MSM_SPM_PMIC_STATE_IDLE) &&
  435. (vctl_port || ((new_level & 0xFF) == vlevel)))
  436. break;
  437. } while (--timeout_us);
  438. if (!timeout_us) {
  439. pr_err("Wrong level %#x\n", new_level);
  440. return -EIO;
  441. }
  442. if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
  443. pr_info("%s: done, remaining timeout %u us\n",
  444. __func__, timeout_us);
  445. return 0;
  446. }
  447. int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel)
  448. {
  449. uint32_t vlevel_set = vlevel;
  450. bool avs_enabled;
  451. int ret = 0;
  452. if (!dev)
  453. return -EINVAL;
  454. avs_enabled = msm_spm_drv_is_avs_enabled(dev);
  455. if (!msm_spm_pmic_arb_present(dev))
  456. return -ENODEV;
  457. if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
  458. pr_info("%s: requesting vlevel %#x\n", __func__, vlevel);
  459. if (avs_enabled)
  460. msm_spm_drv_disable_avs(dev);
  461. if (dev->vctl_port_ub >= 0) {
  462. /**
  463. * VCTL can send 8bit voltage level at once.
  464. * Send lower 8bit first, vlevel change happens
  465. * when upper 8bit is sent.
  466. */
  467. vlevel = vlevel_set & 0xFF;
  468. }
  469. /* Kick the state machine back to idle */
  470. dev->reg_shadow[MSM_SPM_REG_SAW_RST] = 1;
  471. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_RST);
  472. msm_spm_drv_set_vctl2(dev, vlevel, dev->vctl_port);
  473. ret = msm_spm_drv_validate_data(dev, vlevel, dev->vctl_port);
  474. if (ret)
  475. goto set_vdd_bail;
  476. if (dev->vctl_port_ub >= 0) {
  477. /* Send upper 8bit of voltage level */
  478. vlevel = (vlevel_set >> 8) & 0xFF;
  479. /* Kick the state machine back to idle */
  480. dev->reg_shadow[MSM_SPM_REG_SAW_RST] = 1;
  481. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_RST);
  482. /*
  483. * Steps for sending for vctl port other than '0'
  484. * Write VCTL register with pmic data and address index
  485. * Perform system barrier
  486. * Wait for 1us
  487. * Read PMIC_STS register to make sure operation is complete
  488. */
  489. msm_spm_drv_set_vctl2(dev, vlevel, dev->vctl_port_ub);
  490. mb(); /* To make sure data is sent before checking status */
  491. ret = msm_spm_drv_validate_data(dev, vlevel, dev->vctl_port_ub);
  492. if (ret)
  493. goto set_vdd_bail;
  494. }
  495. /* Set AVS min/max */
  496. if (avs_enabled) {
  497. msm_spm_drv_set_avs_vlevel(dev, vlevel_set);
  498. msm_spm_drv_enable_avs(dev);
  499. }
  500. return ret;
  501. set_vdd_bail:
  502. if (avs_enabled)
  503. msm_spm_drv_enable_avs(dev);
  504. pr_err("%s: failed %#x vlevel setting in timeout %uus\n",
  505. __func__, vlevel_set, dev->vctl_timeout_us);
  506. return -EIO;
  507. }
  508. static int msm_spm_drv_get_pmic_port(struct msm_spm_driver_data *dev,
  509. enum msm_spm_pmic_port port)
  510. {
  511. int index = -1;
  512. switch (port) {
  513. case MSM_SPM_PMIC_VCTL_PORT:
  514. index = dev->vctl_port;
  515. break;
  516. case MSM_SPM_PMIC_PHASE_PORT:
  517. index = dev->phase_port;
  518. break;
  519. case MSM_SPM_PMIC_PFM_PORT:
  520. index = dev->pfm_port;
  521. break;
  522. default:
  523. break;
  524. }
  525. return index;
  526. }
  527. int msm_spm_drv_set_pmic_data(struct msm_spm_driver_data *dev,
  528. enum msm_spm_pmic_port port, unsigned int data)
  529. {
  530. unsigned int pmic_data = 0;
  531. unsigned int timeout_us = 0;
  532. int index = 0;
  533. if (!msm_spm_pmic_arb_present(dev))
  534. return -ENODEV;
  535. index = msm_spm_drv_get_pmic_port(dev, port);
  536. if (index < 0)
  537. return -ENODEV;
  538. pmic_data |= data & 0xFF;
  539. pmic_data |= (index & 0x7) << 16;
  540. dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] &= ~0x700FF;
  541. dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] |= pmic_data;
  542. msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_VCTL);
  543. mb(); /* Ensure we flush */
  544. timeout_us = dev->vctl_timeout_us;
  545. /**
  546. * Confirm the pmic data set was what hardware sent by
  547. * checking the PMIC FSM state.
  548. * We cannot use the sts_pmic_data and check it against
  549. * the value like we do fot set_vdd, since the PMIC_STS
  550. * is only updated for SAW_VCTL sent with port index 0.
  551. */
  552. do {
  553. if (msm_spm_drv_get_sts_pmic_state(dev) ==
  554. MSM_SPM_PMIC_STATE_IDLE)
  555. break;
  556. udelay(1);
  557. } while (--timeout_us);
  558. if (!timeout_us) {
  559. pr_err("%s: failed, remaining timeout %u us, data %d\n",
  560. __func__, timeout_us, data);
  561. return -EIO;
  562. }
  563. return 0;
  564. }
  565. void msm_spm_drv_reinit(struct msm_spm_driver_data *dev, bool seq_write)
  566. {
  567. int i;
  568. if (seq_write)
  569. msm_spm_drv_flush_seq_entry(dev);
  570. for (i = 0; i < MSM_SPM_REG_SAW_PMIC_DATA_0 + num_pmic_data; i++)
  571. msm_spm_drv_load_shadow(dev, i);
  572. for (i = MSM_SPM_REG_NR_INITIALIZE + 1; i < MSM_SPM_REG_NR; i++)
  573. msm_spm_drv_load_shadow(dev, i);
  574. }
  575. int msm_spm_drv_reg_init(struct msm_spm_driver_data *dev,
  576. struct msm_spm_platform_data *data)
  577. {
  578. int i;
  579. bool found = false;
  580. dev->ver_reg = data->ver_reg;
  581. dev->reg_base_addr = data->reg_base_addr;
  582. msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);
  583. for (i = 0; i < ARRAY_SIZE(saw2_info); i++)
  584. if (dev->major == saw2_info[i].major &&
  585. dev->minor == saw2_info[i].minor) {
  586. pr_debug("%s: Version found\n",
  587. saw2_info[i].ver_name);
  588. dev->reg_offsets = saw2_info[i].spm_reg_offset_ptr;
  589. found = true;
  590. break;
  591. }
  592. if (!found) {
  593. pr_err("%s: No SAW version found\n", __func__);
  594. WARN_ON(!found);
  595. }
  596. return 0;
  597. }
  598. void msm_spm_drv_upd_reg_shadow(struct msm_spm_driver_data *dev, int id,
  599. int val)
  600. {
  601. dev->reg_shadow[id] = val;
  602. msm_spm_drv_flush_shadow(dev, id);
  603. /* Complete the above writes before other accesses */
  604. mb();
  605. }
  606. int msm_spm_drv_init(struct msm_spm_driver_data *dev,
  607. struct msm_spm_platform_data *data)
  608. {
  609. int num_spm_entry;
  610. if (!dev || !data)
  611. return -ENODEV;
  612. dev->vctl_port = data->vctl_port;
  613. dev->vctl_port_ub = data->vctl_port_ub;
  614. dev->phase_port = data->phase_port;
  615. dev->pfm_port = data->pfm_port;
  616. dev->reg_base_addr = data->reg_base_addr;
  617. memcpy(dev->reg_shadow, data->reg_init_values,
  618. sizeof(data->reg_init_values));
  619. dev->vctl_timeout_us = data->vctl_timeout_us;
  620. if (!num_pmic_data)
  621. num_pmic_data = msm_spm_drv_get_num_pmic_data(dev);
  622. num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
  623. dev->reg_seq_entry_shadow =
  624. kzalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
  625. GFP_KERNEL);
  626. if (!dev->reg_seq_entry_shadow)
  627. return -ENOMEM;
  628. return 0;
  629. }