mdss_debug.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /* Copyright (c) 2009-2013, 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. #define pr_fmt(fmt) "%s: " fmt, __func__
  14. #include <linux/debugfs.h>
  15. #include <linux/iopoll.h>
  16. #include <linux/kernel.h>
  17. #include <linux/list.h>
  18. #include <linux/printk.h>
  19. #include <linux/slab.h>
  20. #include <linux/uaccess.h>
  21. #include "mdss.h"
  22. #include "mdss_mdp.h"
  23. #include "mdss_mdp_hwio.h"
  24. #include "mdss_debug.h"
  25. #define DEFAULT_BASE_REG_CNT 0x100
  26. #define GROUP_BYTES 4
  27. #define ROW_BYTES 16
  28. #define MAX_VSYNC_COUNT 0xFFFFFFF
  29. static DEFINE_MUTEX(mdss_debug_lock);
  30. static int mdss_debug_base_open(struct inode *inode, struct file *file)
  31. {
  32. /* non-seekable */
  33. file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
  34. file->private_data = inode->i_private;
  35. return 0;
  36. }
  37. static int mdss_debug_base_release(struct inode *inode, struct file *file)
  38. {
  39. struct mdss_debug_base *dbg = file->private_data;
  40. mutex_lock(&mdss_debug_lock);
  41. if (dbg && dbg->buf) {
  42. kfree(dbg->buf);
  43. dbg->buf_len = 0;
  44. dbg->buf = NULL;
  45. }
  46. mutex_unlock(&mdss_debug_lock);
  47. return 0;
  48. }
  49. static ssize_t mdss_debug_base_offset_write(struct file *file,
  50. const char __user *user_buf, size_t count, loff_t *ppos)
  51. {
  52. struct mdss_debug_base *dbg = file->private_data;
  53. u32 off = 0;
  54. u32 cnt = DEFAULT_BASE_REG_CNT;
  55. char buf[24];
  56. if (!dbg)
  57. return -ENODEV;
  58. if (count >= sizeof(buf))
  59. return -EFAULT;
  60. if (copy_from_user(buf, user_buf, count))
  61. return -EFAULT;
  62. buf[count] = 0; /* end of string */
  63. sscanf(buf, "%5x %x", &off, &cnt);
  64. if (off > dbg->max_offset)
  65. return -EINVAL;
  66. if (cnt > (dbg->max_offset - off))
  67. cnt = dbg->max_offset - off;
  68. mutex_lock(&mdss_debug_lock);
  69. dbg->off = off;
  70. dbg->cnt = cnt;
  71. mutex_unlock(&mdss_debug_lock);
  72. pr_debug("offset=%x cnt=%x\n", off, cnt);
  73. return count;
  74. }
  75. static ssize_t mdss_debug_base_offset_read(struct file *file,
  76. char __user *buff, size_t count, loff_t *ppos)
  77. {
  78. struct mdss_debug_base *dbg = file->private_data;
  79. int len = 0;
  80. char buf[24] = {'\0'};
  81. if (!dbg)
  82. return -ENODEV;
  83. if (*ppos)
  84. return 0; /* the end */
  85. mutex_lock(&mdss_debug_lock);
  86. len = snprintf(buf, sizeof(buf), "0x%08x %x\n", dbg->off, dbg->cnt);
  87. if (len < 0 || len >= sizeof(buf)) {
  88. mutex_unlock(&mdss_debug_lock);
  89. return 0;
  90. }
  91. if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) {
  92. mutex_unlock(&mdss_debug_lock);
  93. return -EFAULT;
  94. }
  95. *ppos += len; /* increase offset */
  96. mutex_unlock(&mdss_debug_lock);
  97. return len;
  98. }
  99. static ssize_t mdss_debug_base_reg_write(struct file *file,
  100. const char __user *user_buf, size_t count, loff_t *ppos)
  101. {
  102. struct mdss_debug_base *dbg = file->private_data;
  103. struct mdss_data_type *mdata = mdss_res;
  104. size_t off;
  105. u32 data, cnt;
  106. char buf[24];
  107. if (!dbg || !mdata)
  108. return -ENODEV;
  109. if (count >= sizeof(buf))
  110. return -EFAULT;
  111. if (copy_from_user(buf, user_buf, count))
  112. return -EFAULT;
  113. buf[count] = 0; /* end of string */
  114. cnt = sscanf(buf, "%x %x", &off, &data);
  115. if (cnt < 2)
  116. return -EFAULT;
  117. if (off >= dbg->max_offset)
  118. return -EFAULT;
  119. if (mdata->debug_inf.debug_enable_clock)
  120. mdata->debug_inf.debug_enable_clock(1);
  121. writel_relaxed(data, dbg->base + off);
  122. if (mdata->debug_inf.debug_enable_clock)
  123. mdata->debug_inf.debug_enable_clock(0);
  124. pr_debug("addr=%x data=%x\n", off, data);
  125. return count;
  126. }
  127. static ssize_t mdss_debug_base_reg_read(struct file *file,
  128. char __user *user_buf, size_t count, loff_t *ppos)
  129. {
  130. struct mdss_debug_base *dbg = file->private_data;
  131. struct mdss_data_type *mdata = mdss_res;
  132. size_t len;
  133. if (!dbg || !mdata) {
  134. pr_err("invalid handle\n");
  135. return -ENODEV;
  136. }
  137. mutex_lock(&mdss_debug_lock);
  138. if (!dbg->buf) {
  139. char dump_buf[64];
  140. char *ptr;
  141. int cnt, tot;
  142. dbg->buf_len = sizeof(dump_buf) *
  143. DIV_ROUND_UP(dbg->cnt, ROW_BYTES);
  144. dbg->buf = kzalloc(dbg->buf_len, GFP_KERNEL);
  145. if (!dbg->buf) {
  146. pr_err("not enough memory to hold reg dump\n");
  147. mutex_unlock(&mdss_debug_lock);
  148. return -ENOMEM;
  149. }
  150. ptr = dbg->base + dbg->off;
  151. tot = 0;
  152. if (mdata->debug_inf.debug_enable_clock)
  153. mdata->debug_inf.debug_enable_clock(1);
  154. for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) {
  155. hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES),
  156. ROW_BYTES, GROUP_BYTES, dump_buf,
  157. sizeof(dump_buf), false);
  158. len = scnprintf(dbg->buf + tot, dbg->buf_len - tot,
  159. "0x%08x: %s\n",
  160. ((int)ptr) - ((int)dbg->base),
  161. dump_buf);
  162. ptr += ROW_BYTES;
  163. tot += len;
  164. if (tot >= dbg->buf_len)
  165. break;
  166. }
  167. if (mdata->debug_inf.debug_enable_clock)
  168. mdata->debug_inf.debug_enable_clock(0);
  169. dbg->buf_len = tot;
  170. }
  171. if (*ppos >= dbg->buf_len) {
  172. mutex_unlock(&mdss_debug_lock);
  173. return 0; /* done reading */
  174. }
  175. len = min(count, dbg->buf_len - (size_t) *ppos);
  176. if (copy_to_user(user_buf, dbg->buf + *ppos, len)) {
  177. pr_err("failed to copy to user\n");
  178. mutex_unlock(&mdss_debug_lock);
  179. return -EFAULT;
  180. }
  181. *ppos += len; /* increase offset */
  182. mutex_unlock(&mdss_debug_lock);
  183. return len;
  184. }
  185. static const struct file_operations mdss_off_fops = {
  186. .open = mdss_debug_base_open,
  187. .release = mdss_debug_base_release,
  188. .read = mdss_debug_base_offset_read,
  189. .write = mdss_debug_base_offset_write,
  190. };
  191. static const struct file_operations mdss_reg_fops = {
  192. .open = mdss_debug_base_open,
  193. .release = mdss_debug_base_release,
  194. .read = mdss_debug_base_reg_read,
  195. .write = mdss_debug_base_reg_write,
  196. };
  197. int mdss_debug_register_base(const char *name, void __iomem *base,
  198. size_t max_offset)
  199. {
  200. struct mdss_data_type *mdata = mdss_res;
  201. struct mdss_debug_data *mdd;
  202. struct mdss_debug_base *dbg;
  203. struct dentry *ent_off, *ent_reg;
  204. char dn[80] = "";
  205. int prefix_len = 0;
  206. if (!mdata || !mdata->debug_inf.debug_data)
  207. return -ENODEV;
  208. mdd = mdata->debug_inf.debug_data;
  209. dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
  210. if (!dbg)
  211. return -ENOMEM;
  212. if (name)
  213. strlcpy(dbg->name, name, sizeof(dbg->name));
  214. dbg->base = base;
  215. dbg->max_offset = max_offset;
  216. dbg->off = 0;
  217. dbg->cnt = DEFAULT_BASE_REG_CNT;
  218. if (name && strcmp(name, "mdp"))
  219. prefix_len = snprintf(dn, sizeof(dn), "%s_", name);
  220. strlcpy(dn + prefix_len, "off", sizeof(dn) - prefix_len);
  221. ent_off = debugfs_create_file(dn, 0644, mdd->root, dbg, &mdss_off_fops);
  222. if (IS_ERR_OR_NULL(ent_off)) {
  223. pr_err("debugfs_create_file: offset fail\n");
  224. goto off_fail;
  225. }
  226. strlcpy(dn + prefix_len, "reg", sizeof(dn) - prefix_len);
  227. ent_reg = debugfs_create_file(dn, 0644, mdd->root, dbg, &mdss_reg_fops);
  228. if (IS_ERR_OR_NULL(ent_reg)) {
  229. pr_err("debugfs_create_file: reg fail\n");
  230. goto reg_fail;
  231. }
  232. list_add(&dbg->head, &mdd->base_list);
  233. return 0;
  234. reg_fail:
  235. debugfs_remove(ent_off);
  236. off_fail:
  237. kfree(dbg);
  238. return -ENODEV;
  239. }
  240. static int mdss_debug_stat_open(struct inode *inode, struct file *file)
  241. {
  242. /* non-seekable */
  243. file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
  244. file->private_data = inode->i_private;
  245. return 0;
  246. }
  247. static int mdss_debug_stat_release(struct inode *inode, struct file *file)
  248. {
  249. return 0;
  250. }
  251. static ssize_t mdss_debug_stat_read(struct file *file, char __user *buff,
  252. size_t count, loff_t *ppos)
  253. {
  254. struct mdss_data_type *mdata = file->private_data;
  255. int len, tot;
  256. char bp[512];
  257. if (*ppos)
  258. return 0; /* the end */
  259. len = sizeof(bp);
  260. tot = scnprintf(bp, len, "\nmdp:\n");
  261. if (mdata->debug_inf.debug_dump_stats)
  262. tot += mdata->debug_inf.debug_dump_stats(mdata,
  263. bp + tot, len - tot);
  264. tot += scnprintf(bp + tot, len - tot, "\n");
  265. if (copy_to_user(buff, bp, tot))
  266. return -EFAULT;
  267. *ppos += tot; /* increase offset */
  268. return tot;
  269. }
  270. static const struct file_operations mdss_stat_fops = {
  271. .open = mdss_debug_stat_open,
  272. .release = mdss_debug_stat_release,
  273. .read = mdss_debug_stat_read,
  274. };
  275. static ssize_t mdss_debug_factor_write(struct file *file,
  276. const char __user *user_buf, size_t count, loff_t *ppos)
  277. {
  278. struct mdss_fudge_factor *factor = file->private_data;
  279. u32 numer = factor->numer;
  280. u32 denom = factor->denom;
  281. char buf[32];
  282. if (!factor)
  283. return -ENODEV;
  284. if (count >= sizeof(buf))
  285. return -EFAULT;
  286. if (copy_from_user(buf, user_buf, count))
  287. return -EFAULT;
  288. buf[count] = 0; /* end of string */
  289. if (strnchr(buf, count, '/')) {
  290. /* Parsing buf as fraction */
  291. if (sscanf(buf, "%u/%u", &numer, &denom) != 2)
  292. return -EFAULT;
  293. } else {
  294. /* Parsing buf as percentage */
  295. if (kstrtouint(buf, 0, &numer))
  296. return -EFAULT;
  297. denom = 100;
  298. }
  299. if (numer && denom) {
  300. factor->numer = numer;
  301. factor->denom = denom;
  302. }
  303. pr_debug("numer=%d denom=%d\n", numer, denom);
  304. return count;
  305. }
  306. static ssize_t mdss_debug_factor_read(struct file *file,
  307. char __user *buff, size_t count, loff_t *ppos)
  308. {
  309. struct mdss_fudge_factor *factor = file->private_data;
  310. int len = 0;
  311. char buf[32] = {'\0'};
  312. if (!factor)
  313. return -ENODEV;
  314. if (*ppos)
  315. return 0; /* the end */
  316. len = snprintf(buf, sizeof(buf), "%d/%d\n",
  317. factor->numer, factor->denom);
  318. if (len < 0 || len >= sizeof(buf))
  319. return 0;
  320. if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
  321. return -EFAULT;
  322. *ppos += len; /* increase offset */
  323. return len;
  324. }
  325. static const struct file_operations mdss_factor_fops = {
  326. .open = simple_open,
  327. .read = mdss_debug_factor_read,
  328. .write = mdss_debug_factor_write,
  329. };
  330. static int mdss_debugfs_cleanup(struct mdss_debug_data *mdd)
  331. {
  332. struct mdss_debug_base *base, *tmp;
  333. if (!mdd)
  334. return 0;
  335. list_for_each_entry_safe(base, tmp, &mdd->base_list, head) {
  336. list_del(&base->head);
  337. kfree(base);
  338. }
  339. if (mdd->root)
  340. debugfs_remove_recursive(mdd->root);
  341. kfree(mdd);
  342. return 0;
  343. }
  344. static int mdss_debugfs_perf_init(struct mdss_debug_data *mdd,
  345. struct mdss_data_type *mdata) {
  346. debugfs_create_u32("min_mdp_clk", 0644, mdd->perf,
  347. (u32 *)&mdata->perf_tune.min_mdp_clk);
  348. debugfs_create_u64("min_bus_vote", 0644, mdd->perf,
  349. (u64 *)&mdata->perf_tune.min_bus_vote);
  350. debugfs_create_file("ab_factor", 0644, mdd->perf,
  351. &mdata->ab_factor, &mdss_factor_fops);
  352. debugfs_create_file("ib_factor", 0644, mdd->perf,
  353. &mdata->ib_factor, &mdss_factor_fops);
  354. debugfs_create_file("ib_factor_overlap", 0644, mdd->perf,
  355. &mdata->ib_factor_overlap, &mdss_factor_fops);
  356. debugfs_create_file("clk_factor", 0644, mdd->perf,
  357. &mdata->clk_factor, &mdss_factor_fops);
  358. debugfs_create_u32("threshold_low", 0644, mdd->perf,
  359. (u32 *)&mdata->max_bw_low);
  360. debugfs_create_u32("threshold_high", 0644, mdd->perf,
  361. (u32 *)&mdata->max_bw_high);
  362. return 0;
  363. }
  364. int mdss_debugfs_init(struct mdss_data_type *mdata)
  365. {
  366. struct mdss_debug_data *mdd;
  367. if (mdata->debug_inf.debug_data) {
  368. pr_warn("mdss debugfs already initialized\n");
  369. return -EBUSY;
  370. }
  371. mdd = kzalloc(sizeof(*mdd), GFP_KERNEL);
  372. if (!mdd) {
  373. pr_err("no memory to create mdss debug data\n");
  374. return -ENOMEM;
  375. }
  376. INIT_LIST_HEAD(&mdd->base_list);
  377. mdd->root = debugfs_create_dir("mdp", NULL);
  378. if (IS_ERR_OR_NULL(mdd->root)) {
  379. pr_err("debugfs_create_dir for mdp failed, error %ld\n",
  380. PTR_ERR(mdd->root));
  381. goto err;
  382. }
  383. debugfs_create_file("stat", 0644, mdd->root, mdata, &mdss_stat_fops);
  384. mdd->perf = debugfs_create_dir("perf", mdd->root);
  385. if (IS_ERR_OR_NULL(mdd->perf)) {
  386. pr_err("debugfs_create_dir perf fail, error %ld\n",
  387. PTR_ERR(mdd->perf));
  388. goto err;
  389. }
  390. mdss_debugfs_perf_init(mdd, mdata);
  391. if (mdss_create_xlog_debug(mdd))
  392. goto err;
  393. mdata->debug_inf.debug_data = mdd;
  394. return 0;
  395. err:
  396. mdss_debugfs_cleanup(mdd);
  397. return -ENODEV;
  398. }
  399. int mdss_debugfs_remove(struct mdss_data_type *mdata)
  400. {
  401. struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
  402. mdss_debugfs_cleanup(mdd);
  403. mdata->debug_inf.debug_data = NULL;
  404. return 0;
  405. }
  406. void mdss_dump_reg(char __iomem *base, int len)
  407. {
  408. char *addr;
  409. u32 x0, x4, x8, xc;
  410. int i;
  411. addr = base;
  412. if (len % 16)
  413. len += 16;
  414. len /= 16;
  415. mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
  416. for (i = 0; i < len; i++) {
  417. x0 = readl_relaxed(addr+0x0);
  418. x4 = readl_relaxed(addr+0x4);
  419. x8 = readl_relaxed(addr+0x8);
  420. xc = readl_relaxed(addr+0xc);
  421. pr_info("%pK : %08x %08x %08x %08x\n", addr, x0, x4, x8, xc);
  422. addr += 16;
  423. }
  424. mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
  425. }
  426. int vsync_count;
  427. static struct mdss_mdp_misr_map {
  428. u32 ctrl_reg;
  429. u32 value_reg;
  430. u32 crc_op_mode;
  431. u32 crc_index;
  432. bool use_ping;
  433. bool is_ping_full;
  434. bool is_pong_full;
  435. struct mutex crc_lock;
  436. u32 crc_ping[MISR_CRC_BATCH_SIZE];
  437. u32 crc_pong[MISR_CRC_BATCH_SIZE];
  438. } mdss_mdp_misr_table[DISPLAY_MISR_MAX] = {
  439. [DISPLAY_MISR_DSI0] = {
  440. .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI0,
  441. .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
  442. .crc_op_mode = 0,
  443. .crc_index = 0,
  444. .use_ping = true,
  445. .is_ping_full = false,
  446. .is_pong_full = false,
  447. },
  448. [DISPLAY_MISR_DSI1] = {
  449. .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI1,
  450. .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
  451. .crc_op_mode = 0,
  452. .crc_index = 0,
  453. .use_ping = true,
  454. .is_ping_full = false,
  455. .is_pong_full = false,
  456. },
  457. [DISPLAY_MISR_EDP] = {
  458. .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_EDP,
  459. .value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
  460. .crc_op_mode = 0,
  461. .crc_index = 0,
  462. .use_ping = true,
  463. .is_ping_full = false,
  464. .is_pong_full = false,
  465. },
  466. [DISPLAY_MISR_HDMI] = {
  467. .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_HDMI,
  468. .value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
  469. .crc_op_mode = 0,
  470. .crc_index = 0,
  471. .use_ping = true,
  472. .is_ping_full = false,
  473. .is_pong_full = false,
  474. },
  475. [DISPLAY_MISR_MDP] = {
  476. .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_MDP,
  477. .value_reg = MDSS_MDP_LP_MISR_SIGN_MDP,
  478. .crc_op_mode = 0,
  479. .crc_index = 0,
  480. .use_ping = true,
  481. .is_ping_full = false,
  482. .is_pong_full = false,
  483. },
  484. };
  485. static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id)
  486. {
  487. struct mdss_mdp_misr_map *map;
  488. if (block_id > DISPLAY_MISR_HDMI && block_id != DISPLAY_MISR_MDP) {
  489. pr_err("MISR Block id (%d) out of range\n", block_id);
  490. return NULL;
  491. }
  492. map = mdss_mdp_misr_table + block_id;
  493. if ((map->ctrl_reg == 0) || (map->value_reg == 0)) {
  494. pr_err("MISR Block id (%d) config not found\n", block_id);
  495. return NULL;
  496. }
  497. return map;
  498. }
  499. int mdss_misr_set(struct mdss_data_type *mdata,
  500. struct mdp_misr *req,
  501. struct mdss_mdp_ctl *ctl)
  502. {
  503. struct mdss_mdp_misr_map *map;
  504. struct mdss_mdp_mixer *mixer;
  505. u32 config = 0, val = 0;
  506. u32 mixer_num = 0;
  507. bool is_valid_wb_mixer = true;
  508. if (!mdata || !req || !ctl) {
  509. pr_err("Invalid input params: mdata = %pK req = %pK ctl = %pK",
  510. mdata, req, ctl);
  511. return -EINVAL;
  512. }
  513. map = mdss_misr_get_map(req->block_id);
  514. if (!map) {
  515. pr_err("Invalid MISR Block=%d\n", req->block_id);
  516. return -EINVAL;
  517. }
  518. mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
  519. if (req->block_id == DISPLAY_MISR_MDP) {
  520. mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
  521. mixer_num = mixer->num;
  522. pr_debug("SET MDP MISR BLK to MDSS_MDP_LP_MISR_SEL_LMIX%d_GC\n",
  523. req->block_id);
  524. switch (mixer_num) {
  525. case MDSS_MDP_INTF_LAYERMIXER0:
  526. pr_debug("Use Layer Mixer 0 for WB CRC\n");
  527. val = MDSS_MDP_LP_MISR_SEL_LMIX0_GC;
  528. break;
  529. case MDSS_MDP_INTF_LAYERMIXER1:
  530. pr_debug("Use Layer Mixer 1 for WB CRC\n");
  531. val = MDSS_MDP_LP_MISR_SEL_LMIX1_GC;
  532. break;
  533. case MDSS_MDP_INTF_LAYERMIXER2:
  534. pr_debug("Use Layer Mixer 2 for WB CRC\n");
  535. val = MDSS_MDP_LP_MISR_SEL_LMIX2_GC;
  536. break;
  537. default:
  538. pr_err("Invalid Layer Mixer %d selected for WB CRC\n",
  539. mixer_num);
  540. is_valid_wb_mixer = false;
  541. break;
  542. }
  543. if (is_valid_wb_mixer)
  544. writel_relaxed(val,
  545. mdata->mdp_base + MDSS_MDP_LP_MISR_SEL);
  546. }
  547. vsync_count = 0;
  548. map->crc_op_mode = req->crc_op_mode;
  549. config = (MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK & req->frame_count) |
  550. (MDSS_MDP_LP_MISR_CTRL_ENABLE);
  551. writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
  552. mdata->mdp_base + map->ctrl_reg);
  553. /* ensure clear is done */
  554. wmb();
  555. memset(map->crc_ping, 0, sizeof(map->crc_ping));
  556. memset(map->crc_pong, 0, sizeof(map->crc_pong));
  557. map->crc_index = 0;
  558. map->use_ping = true;
  559. map->is_ping_full = false;
  560. map->is_pong_full = false;
  561. if (MISR_OP_BM != map->crc_op_mode) {
  562. writel_relaxed(config,
  563. mdata->mdp_base + map->ctrl_reg);
  564. pr_debug("MISR_CTRL = 0x%x",
  565. readl_relaxed(mdata->mdp_base + map->ctrl_reg));
  566. }
  567. mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
  568. return 0;
  569. }
  570. int mdss_misr_get(struct mdss_data_type *mdata,
  571. struct mdp_misr *resp,
  572. struct mdss_mdp_ctl *ctl)
  573. {
  574. struct mdss_mdp_misr_map *map;
  575. u32 status;
  576. int ret = -1;
  577. int i;
  578. map = mdss_misr_get_map(resp->block_id);
  579. if (!map) {
  580. pr_err("Invalid MISR Block=%d\n", resp->block_id);
  581. return -EINVAL;
  582. }
  583. mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
  584. switch (map->crc_op_mode) {
  585. case MISR_OP_SFM:
  586. case MISR_OP_MFM:
  587. ret = readl_poll_timeout(mdata->mdp_base + map->ctrl_reg,
  588. status, status & MDSS_MDP_LP_MISR_CTRL_STATUS,
  589. MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
  590. if (ret == 0) {
  591. resp->crc_value[0] = readl_relaxed(mdata->mdp_base +
  592. map->value_reg);
  593. pr_debug("CRC %d=0x%x\n", resp->block_id,
  594. resp->crc_value[0]);
  595. writel_relaxed(0, mdata->mdp_base + map->ctrl_reg);
  596. } else {
  597. mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
  598. ret = readl_poll_timeout(mdata->mdp_base +
  599. map->ctrl_reg, status,
  600. status & MDSS_MDP_LP_MISR_CTRL_STATUS,
  601. MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
  602. if (ret == 0) {
  603. resp->crc_value[0] =
  604. readl_relaxed(mdata->mdp_base +
  605. map->value_reg);
  606. }
  607. writel_relaxed(0, mdata->mdp_base + map->ctrl_reg);
  608. }
  609. break;
  610. case MISR_OP_BM:
  611. if (map->is_ping_full) {
  612. for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
  613. resp->crc_value[i] = map->crc_ping[i];
  614. memset(map->crc_ping, 0, sizeof(map->crc_ping));
  615. map->is_ping_full = false;
  616. ret = 0;
  617. } else if (map->is_pong_full) {
  618. for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
  619. resp->crc_value[i] = map->crc_pong[i];
  620. memset(map->crc_pong, 0, sizeof(map->crc_pong));
  621. map->is_pong_full = false;
  622. ret = 0;
  623. } else {
  624. pr_debug("mdss_mdp_misr_crc_get PING BUF %s\n",
  625. map->is_ping_full ? "FULL" : "EMPTRY");
  626. pr_debug("mdss_mdp_misr_crc_get PONG BUF %s\n",
  627. map->is_pong_full ? "FULL" : "EMPTRY");
  628. }
  629. resp->crc_op_mode = map->crc_op_mode;
  630. break;
  631. default:
  632. ret = -ENOSYS;
  633. break;
  634. }
  635. mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
  636. return ret;
  637. }
  638. /* This function is expected to be called from interrupt context */
  639. void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
  640. {
  641. struct mdss_mdp_misr_map *map;
  642. u32 status = 0;
  643. u32 crc = 0x0BAD0BAD;
  644. bool crc_stored = false;
  645. map = mdss_misr_get_map(block_id);
  646. if (!map || (map->crc_op_mode != MISR_OP_BM))
  647. return;
  648. status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
  649. if (MDSS_MDP_LP_MISR_CTRL_STATUS & status) {
  650. crc = readl_relaxed(mdata->mdp_base + map->value_reg);
  651. if (map->use_ping) {
  652. if (map->is_ping_full) {
  653. pr_err("PING Buffer FULL\n");
  654. } else {
  655. map->crc_ping[map->crc_index] = crc;
  656. crc_stored = true;
  657. }
  658. } else {
  659. if (map->is_pong_full) {
  660. pr_err("PONG Buffer FULL\n");
  661. } else {
  662. map->crc_pong[map->crc_index] = crc;
  663. crc_stored = true;
  664. }
  665. }
  666. if (crc_stored) {
  667. map->crc_index = (map->crc_index + 1);
  668. if (map->crc_index == MISR_CRC_BATCH_SIZE) {
  669. map->crc_index = 0;
  670. if (true == map->use_ping) {
  671. map->is_ping_full = true;
  672. map->use_ping = false;
  673. } else {
  674. map->is_pong_full = true;
  675. map->use_ping = true;
  676. }
  677. pr_debug("USE BUFF %s\n", map->use_ping ?
  678. "PING" : "PONG");
  679. pr_debug("mdss_misr_crc_collect PING BUF %s\n",
  680. map->is_ping_full ? "FULL" : "EMPTRY");
  681. pr_debug("mdss_misr_crc_collect PONG BUF %s\n",
  682. map->is_pong_full ? "FULL" : "EMPTRY");
  683. }
  684. } else {
  685. pr_err("CRC(%d) Not saved\n", crc);
  686. }
  687. writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
  688. mdata->mdp_base + map->ctrl_reg);
  689. writel_relaxed(MISR_CRC_BATCH_CFG,
  690. mdata->mdp_base + map->ctrl_reg);
  691. } else if (0 == status) {
  692. writel_relaxed(MISR_CRC_BATCH_CFG,
  693. mdata->mdp_base + map->ctrl_reg);
  694. pr_debug("$$ Batch CRC Start $$\n");
  695. }
  696. pr_debug("$$ Vsync Count = %d, CRC=0x%x Indx = %d$$\n",
  697. vsync_count, crc, map->crc_index);
  698. if (MAX_VSYNC_COUNT == vsync_count) {
  699. pr_err("RESET vsync_count(%d)\n", vsync_count);
  700. vsync_count = 0;
  701. } else {
  702. vsync_count += 1;
  703. }
  704. }