cl_dsp-debugfs.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // cl_dsp.c -- DSP Control for non-ALSA Cirrus Logic Devices
  4. //
  5. // Copyright 2021 Cirrus Logic, Inc.
  6. //
  7. // Author: Fred Treven <[email protected]>
  8. #include <linux/firmware/cirrus/cl_dsp.h>
  9. #ifdef CONFIG_DEBUG_FS
  10. static inline u32 host_buffer_field_reg(struct cl_dsp_logger *dl,
  11. unsigned long offset)
  12. {
  13. return (u32)(CL_DSP_HALO_XMEM_UNPACKED24_BASE +
  14. ((dl->host_buf_ptr + offset) * CL_DSP_BYTES_PER_WORD));
  15. }
  16. static inline u32 host_buffer_data_reg(struct cl_dsp_logger *dl, int offset)
  17. {
  18. return (u32)(CL_DSP_HALO_XMEM_UNPACKED24_BASE +
  19. ((dl->host_buf_base + offset) * CL_DSP_BYTES_PER_WORD));
  20. }
  21. static int cl_dsp_host_buffer_field_read(struct cl_dsp_debugfs *db,
  22. unsigned long field_offset, u32 *data)
  23. {
  24. struct regmap *regmap = db->core->regmap;
  25. __be32 raw;
  26. u32 reg;
  27. int ret;
  28. reg = host_buffer_field_reg(&db->dl, field_offset);
  29. ret = regmap_raw_read(regmap, reg, &raw, sizeof(raw));
  30. if (ret) {
  31. dev_err(db->core->dev, "Failed to get raw host buffer data\n");
  32. return ret;
  33. }
  34. *data = CL_DSP_HOST_BUFFER_DATA_MASK & be32_to_cpu(raw);
  35. return 0;
  36. }
  37. static int cl_dsp_host_buffer_field_write(struct cl_dsp_debugfs *db,
  38. unsigned long field_offset, u32 data)
  39. {
  40. struct regmap *regmap = db->core->regmap;
  41. struct device *dev = db->core->dev;
  42. int ret;
  43. u32 reg;
  44. reg = host_buffer_field_reg(&db->dl, field_offset);
  45. ret = regmap_write(regmap, reg, data);
  46. if (ret)
  47. dev_err(dev, "Failed to set host buffer data: %d\n", ret);
  48. return ret;
  49. }
  50. static ssize_t cl_dsp_debugfs_logger_en_read(struct file *file,
  51. char __user *user_buf, size_t count, loff_t *ppos)
  52. {
  53. struct cl_dsp_debugfs *db = file->private_data;
  54. struct regmap *regmap = db->core->regmap;
  55. char str[CL_DSP_DEBUGFS_TRACE_LOG_STRING_SIZE];
  56. u32 reg, val;
  57. ssize_t ret;
  58. ret = cl_dsp_get_reg(db->core, "ENABLED", CL_DSP_XM_UNPACKED_TYPE,
  59. db->dl.algo_id, &reg);
  60. if (ret)
  61. return ret;
  62. ret = pm_runtime_get_sync(db->core->dev);
  63. if (ret < 0) {
  64. dev_err(db->core->dev, "PM Runtime Resume Failed\n");
  65. return ret;
  66. }
  67. ret = regmap_read(regmap, reg, &val);
  68. if (ret) {
  69. dev_err(db->core->dev, "Failed to get host buffer status\n");
  70. goto pm_exit;
  71. }
  72. ret = snprintf(str, CL_DSP_DEBUGFS_TRACE_LOG_STRING_SIZE, "%d\n", val);
  73. if (ret <= 0) {
  74. dev_err(db->core->dev, "Failed to parse host buffer status\n");
  75. goto pm_exit;
  76. }
  77. ret = simple_read_from_buffer(user_buf, count, ppos, str, strlen(str));
  78. pm_exit:
  79. pm_runtime_mark_last_busy(db->core->dev);
  80. pm_runtime_put_autosuspend(db->core->dev);
  81. return ret;
  82. }
  83. static ssize_t cl_dsp_debugfs_logger_en_write(struct file *file,
  84. const char __user *user_buf, size_t count, loff_t *ppos)
  85. {
  86. struct cl_dsp_debugfs *db = file->private_data;
  87. struct regmap *regmap = db->core->regmap;
  88. struct device *dev = db->core->dev;
  89. u32 reg, val;
  90. ssize_t ret;
  91. char *str;
  92. str = kzalloc(count, GFP_KERNEL);
  93. if (!str)
  94. return -ENOMEM;
  95. ret = simple_write_to_buffer(str, count, ppos, user_buf, count);
  96. if (ret <= 0) {
  97. dev_err(dev, "Failed to write debugfs data\n");
  98. goto exit_free;
  99. }
  100. ret = kstrtou32(str, 10, &val);
  101. if (ret)
  102. goto exit_free;
  103. if (val != CL_DSP_DEBUGFS_TRACE_LOG_DISABLE &&
  104. val != CL_DSP_DEBUGFS_TRACE_LOG_ENABLE) {
  105. dev_err(dev, "Invalid trace log write: %u\n", val);
  106. ret = -EINVAL;
  107. goto exit_free;
  108. }
  109. ret = cl_dsp_get_reg(db->core, "ENABLED", CL_DSP_XM_UNPACKED_TYPE,
  110. db->dl.algo_id, &reg);
  111. if (ret)
  112. goto exit_free;
  113. ret = pm_runtime_get_sync(dev);
  114. if (ret < 0) {
  115. dev_err(db->core->dev, "PM Runtime Resume Failed\n");
  116. goto exit_free;
  117. }
  118. ret = regmap_write(regmap, reg, val);
  119. if (ret) {
  120. dev_err(dev, "Failed to set trace log status\n");
  121. goto exit_pm;
  122. }
  123. if (val == CL_DSP_DEBUGFS_TRACE_LOG_DISABLE) {
  124. /* Set next_read_index to -1 to reset logger */
  125. ret = cl_dsp_host_buffer_field_write(db,
  126. HOST_BUFFER_FIELD(next_read_index),
  127. CL_DSP_HOST_BUFFER_READ_INDEX_RESET);
  128. if (ret) {
  129. dev_err(dev, "Failed to reset event logger\n");
  130. goto exit_pm;
  131. }
  132. db->dl.buf_data_size = 0;
  133. kfree(db->dl.buf_data);
  134. }
  135. exit_pm:
  136. pm_runtime_mark_last_busy(dev);
  137. pm_runtime_put_autosuspend(dev);
  138. exit_free:
  139. kfree(str);
  140. return ret ? ret : count;
  141. }
  142. static ssize_t cl_dsp_debugfs_timestamp_shift_read(struct file *file,
  143. char __user *user_buf, size_t count, loff_t *ppos)
  144. {
  145. struct cl_dsp_debugfs *db = file->private_data;
  146. struct regmap *regmap = db->core->regmap;
  147. char str[CL_DSP_DEBUGFS_TRACE_LOG_STRING_SIZE];
  148. u32 reg, val;
  149. ssize_t ret;
  150. ret = cl_dsp_get_reg(db->core, "TIMESTAMP_SHIFT",
  151. CL_DSP_XM_UNPACKED_TYPE, db->dl.algo_id, &reg);
  152. if (ret)
  153. return ret;
  154. ret = pm_runtime_get_sync(db->core->dev);
  155. if (ret < 0) {
  156. dev_err(db->core->dev, "PM Runtime Resume Failed\n");
  157. return ret;
  158. }
  159. ret = regmap_read(regmap, reg, &val);
  160. if (ret) {
  161. dev_err(db->core->dev, "Failed to get timestamp shift\n");
  162. goto pm_exit;
  163. }
  164. ret = snprintf(str, CL_DSP_DEBUGFS_TRACE_LOG_STRING_SIZE, "%d\n", val);
  165. if (ret <= 0) {
  166. dev_err(db->core->dev, "Failed to parse host buffer status\n");
  167. goto pm_exit;
  168. }
  169. ret = simple_read_from_buffer(user_buf, count, ppos, str, strlen(str));
  170. pm_exit:
  171. pm_runtime_mark_last_busy(db->core->dev);
  172. pm_runtime_put_autosuspend(db->core->dev);
  173. return ret;
  174. }
  175. static int cl_dsp_host_buffer_data_read(struct cl_dsp_debugfs *db,
  176. u32 read_index, u32 num_words)
  177. {
  178. u32 start_reg, offset = db->dl.buf_data_size;
  179. struct regmap *regmap = db->core->regmap;
  180. struct device *dev = db->core->dev;
  181. int ret;
  182. start_reg = host_buffer_data_reg(&db->dl, (unsigned long)read_index);
  183. db->dl.buf_data_size += num_words;
  184. db->dl.buf_data = krealloc(db->dl.buf_data, db->dl.buf_data_size * 4,
  185. GFP_KERNEL);
  186. if (!db->dl.buf_data || IS_ERR(db->dl.buf_data)) {
  187. dev_err(dev, "Failed to allocate buffer data space\n");
  188. return -ENOMEM;
  189. }
  190. ret = regmap_bulk_read(regmap, start_reg, db->dl.buf_data + offset,
  191. num_words);
  192. if (ret)
  193. dev_err(dev, "Failed to get host buffer data\n");
  194. return ret;
  195. }
  196. int cl_dsp_logger_update(struct cl_dsp_debugfs *db)
  197. {
  198. struct cl_dsp_logger *dl = &db->dl;
  199. struct device *dev = db->core->dev;
  200. u32 n_read_index, n_write_index, num_words;
  201. u32 nirq, irq, error_code;
  202. int ret;
  203. /* Check if interrupt was asserted due to an error */
  204. ret = cl_dsp_host_buffer_field_read(db, HOST_BUFFER_FIELD(error),
  205. &error_code);
  206. if (ret)
  207. return ret;
  208. if (error_code) {
  209. if (error_code != CL_DSP_HOST_BUFFER_ERROR_OVERFLOW) {
  210. dev_err(dev, "Fatal Host Buffer Error with code 0x%X\n",
  211. error_code);
  212. return -ENOTRECOVERABLE;
  213. }
  214. dev_warn(dev, "Data lost from Host Buffer Overflow\n");
  215. }
  216. /* Check if next read index is != -1 in order to continue */
  217. ret = cl_dsp_host_buffer_field_read(db,
  218. HOST_BUFFER_FIELD(next_read_index), &n_read_index);
  219. if (ret)
  220. return ret;
  221. if (n_read_index == CL_DSP_HOST_BUFFER_READ_INDEX_RESET) {
  222. dev_err(dev, "Host Buffer Not Initialized\n");
  223. return -EPERM;
  224. }
  225. ret = cl_dsp_host_buffer_field_read(db, HOST_BUFFER_FIELD(irq_count),
  226. &nirq);
  227. if (ret)
  228. return ret;
  229. ret = cl_dsp_host_buffer_field_read(db, HOST_BUFFER_FIELD(irq_ack),
  230. &irq);
  231. if (ret)
  232. return ret;
  233. ret = cl_dsp_host_buffer_field_read(
  234. db, HOST_BUFFER_FIELD(next_write_index), &n_write_index);
  235. if (ret)
  236. return ret;
  237. if (n_write_index < n_read_index)
  238. num_words = (n_write_index + dl->host_buf_size_words) -
  239. n_read_index;
  240. else
  241. num_words = n_write_index - n_read_index;
  242. /* Get all messages in buffer */
  243. ret = cl_dsp_host_buffer_data_read(db, n_read_index, num_words);
  244. if (ret)
  245. return ret;
  246. /* Set next_read_index to next_write_index */
  247. ret = cl_dsp_host_buffer_field_write(db,
  248. HOST_BUFFER_FIELD(next_read_index), n_write_index - 1);
  249. if (ret)
  250. return ret;
  251. /* Reset irq_ack by writing irq_count | 0x1 */
  252. ret = cl_dsp_host_buffer_field_write(db, HOST_BUFFER_FIELD(irq_ack),
  253. nirq | CL_DSP_HOST_BUFFER_IRQ_MASK);
  254. if (ret)
  255. return ret;
  256. ret = cl_dsp_host_buffer_field_read(db,
  257. HOST_BUFFER_FIELD(irq_ack), &irq);
  258. if (ret)
  259. return ret;
  260. return 0;
  261. }
  262. EXPORT_SYMBOL(cl_dsp_logger_update);
  263. static int cl_dsp_debugfs_logger_open(struct inode *inode, struct file *file)
  264. {
  265. struct cl_dsp_debugfs *db;
  266. int ret;
  267. ret = simple_open(inode, file);
  268. if (ret)
  269. return ret;
  270. db = file->private_data;
  271. return 0;
  272. }
  273. static ssize_t cl_dsp_debugfs_logger_read(struct file *file,
  274. char __user *user_buf, size_t count,
  275. loff_t *ppos)
  276. {
  277. struct cl_dsp_debugfs *db = file->private_data;
  278. struct cl_dsp_logger *dl = &db->dl;
  279. struct device *dev = db->core->dev;
  280. ssize_t ret, buf_str_size;
  281. char *str, *buf_str;
  282. int i;
  283. if (dl->buf_data_size == 0)
  284. return -ENODATA;
  285. buf_str_size =
  286. CL_DSP_HOST_BUFFER_DATA_SLOT_SIZE * dl->buf_data_size;
  287. buf_str = kzalloc(buf_str_size, GFP_KERNEL);
  288. if (!buf_str)
  289. return -ENOMEM;
  290. str = kzalloc(CL_DSP_HOST_BUFFER_DATA_SLOT_SIZE, GFP_KERNEL);
  291. if (!str) {
  292. ret = -ENOMEM;
  293. goto err_free2;
  294. }
  295. for (i = 0; i < dl->buf_data_size; i++) {
  296. ret = snprintf(str, CL_DSP_HOST_BUFFER_DATA_SLOT_SIZE, "%08X ",
  297. dl->buf_data[i]);
  298. if (ret <= 0) {
  299. dev_err(dev, "Failed to get host buffer data string\n");
  300. goto err_free1;
  301. }
  302. strncat(buf_str, str, CL_DSP_HOST_BUFFER_DATA_SLOT_SIZE);
  303. }
  304. ret = simple_read_from_buffer(user_buf, count, ppos, buf_str,
  305. strlen(buf_str));
  306. err_free1:
  307. kfree(str);
  308. err_free2:
  309. kfree(buf_str);
  310. return ret;
  311. }
  312. static const struct {
  313. const char *name;
  314. const struct file_operations fops;
  315. } cl_dsp_debugfs_fops[] = {
  316. {
  317. .name = "log_data",
  318. .fops = {
  319. .owner = THIS_MODULE,
  320. .open = cl_dsp_debugfs_logger_open,
  321. .read = cl_dsp_debugfs_logger_read,
  322. },
  323. },
  324. {
  325. .name = "logger_en",
  326. .fops = {
  327. .owner = THIS_MODULE,
  328. .open = simple_open,
  329. .read = cl_dsp_debugfs_logger_en_read,
  330. .write = cl_dsp_debugfs_logger_en_write,
  331. },
  332. },
  333. {
  334. .name = "timestamp_shift",
  335. .fops = {
  336. .owner = THIS_MODULE,
  337. .open = simple_open,
  338. .read = cl_dsp_debugfs_timestamp_shift_read,
  339. }
  340. },
  341. };
  342. static int cl_dsp_logger_init(struct cl_dsp_debugfs *db)
  343. {
  344. struct regmap *regmap = db->core->regmap;
  345. struct cl_dsp *dsp = db->core;
  346. u32 reg;
  347. int ret;
  348. ret = cl_dsp_get_reg(dsp, "EVENT_LOG_HEADER", CL_DSP_XM_UNPACKED_TYPE,
  349. db->dl.algo_id, &reg);
  350. if (ret)
  351. return ret;
  352. ret = regmap_read(regmap, reg, &db->dl.host_buf_ptr);
  353. if (ret) {
  354. dev_err(db->core->dev, "Failed to get host buffer address\n");
  355. return ret;
  356. }
  357. ret = cl_dsp_host_buffer_field_read(db, HOST_BUFFER_FIELD(buf1_base),
  358. &db->dl.host_buf_base);
  359. if (ret)
  360. return ret;
  361. ret = cl_dsp_host_buffer_field_read(db,
  362. HOST_BUFFER_FIELD(buf_total_size),
  363. &db->dl.host_buf_size_words);
  364. if (ret)
  365. return ret;
  366. ret = cl_dsp_host_buffer_field_read(db,
  367. HOST_BUFFER_FIELD(high_water_mark),
  368. &db->dl.high_watermark);
  369. if (ret)
  370. return ret;
  371. /* Set next_read_index to -1 to reset logger */
  372. ret = cl_dsp_host_buffer_field_write(db,
  373. HOST_BUFFER_FIELD(next_read_index),
  374. CL_DSP_HOST_BUFFER_READ_INDEX_RESET);
  375. if (ret)
  376. dev_err(db->core->dev, "Failed to reset event logger\n");
  377. return ret;
  378. }
  379. struct cl_dsp_debugfs *cl_dsp_debugfs_create(struct cl_dsp *dsp,
  380. struct dentry *parent_node,
  381. u32 event_log_algo_id)
  382. {
  383. struct cl_dsp_debugfs *db;
  384. int ret, i;
  385. if (IS_ERR(dsp))
  386. return ERR_CAST(dsp);
  387. if (!dsp)
  388. return NULL;
  389. if (IS_ERR(parent_node))
  390. return ERR_CAST(parent_node);
  391. if (!parent_node)
  392. return NULL;
  393. db = kzalloc(sizeof(*db), GFP_KERNEL);
  394. if (!db)
  395. return ERR_PTR(-ENOMEM);
  396. db->core = dsp;
  397. db->debugfs_root = parent_node ? parent_node : NULL;
  398. db->debugfs_node = debugfs_create_dir("cl_dsp", db->debugfs_root);
  399. if (IS_ERR(db->debugfs_node)) {
  400. ret = PTR_ERR(db->debugfs_node);
  401. kfree(db);
  402. return ERR_PTR(ret);
  403. }
  404. for (i = 0; i < CL_DSP_DEBUGFS_NUM_CONTROLS; i++)
  405. debugfs_create_file(cl_dsp_debugfs_fops[i].name,
  406. CL_DSP_DEBUGFS_RW_FILE_MODE, db->debugfs_node,
  407. db, &cl_dsp_debugfs_fops[i].fops);
  408. db->dl.algo_id = event_log_algo_id;
  409. ret = cl_dsp_logger_init(db);
  410. if (ret)
  411. return ERR_PTR(ret);
  412. debugfs_create_u32("high_watermark", CL_DSP_DEBUGFS_RO_FILE_MODE,
  413. db->debugfs_node, &db->dl.high_watermark);
  414. return db;
  415. }
  416. EXPORT_SYMBOL(cl_dsp_debugfs_create);
  417. void cl_dsp_debugfs_destroy(struct cl_dsp_debugfs *db)
  418. {
  419. if (IS_ERR_OR_NULL(db))
  420. return;
  421. debugfs_remove_recursive(db->debugfs_node);
  422. kfree(db);
  423. }
  424. EXPORT_SYMBOL(cl_dsp_debugfs_destroy);
  425. #endif /* CONFIG_DEBUG_FS */
  426. MODULE_DESCRIPTION("CL DSP Debugfs Driver");
  427. MODULE_AUTHOR("Fred Treven, Cirrus Logic Inc. <[email protected]>");
  428. MODULE_LICENSE("GPL");