ubwcp_hw.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #include <linux/module.h>
  6. #include <linux/kernel.h>
  7. #include <linux/dma-buf.h>
  8. #include <linux/slab.h>
  9. #include <linux/cdev.h>
  10. #include <linux/qcom_scm.h>
  11. #include <linux/delay.h>
  12. #include "ubwcp_hw.h"
  13. extern u32 ubwcp_debug_trace_enable;
  14. //#define DBG(fmt, args...)
  15. #define DBG(fmt, args...) \
  16. do { \
  17. if (ubwcp_debug_trace_enable) \
  18. pr_err("ubwcp: hw: %s(): " fmt "\n", __func__, ##args); \
  19. } while (0)
  20. #define ERR(fmt, args...) \
  21. do { \
  22. if (ubwcp_debug_trace_enable) \
  23. pr_err("ubwcp: hw: %s(): ~~~ERROR~~~: " fmt "\n", __func__, ##args); \
  24. } while (0)
  25. MODULE_LICENSE("GPL");
  26. #define PAGE_ADDR_4K(_x) ((_x) >> 12)
  27. /* register offsets from base */
  28. #define RANGE_LOWER 0x0000
  29. #define RANGE_HIGHER 0x0800
  30. #define DESC_BASE 0x1000
  31. #define DESC_BASE_STRIDE 0x1004
  32. #define CONFIG 0x1008
  33. #define ENCODER_CONFIG 0x100C
  34. #define ENCODER_STATUS 0x1010
  35. #define DECODER_CONFIG 0x1014
  36. #define DECODER_STATUS 0x1018
  37. #define RANGE_CHECK_FAIL 0x101C
  38. #define RANGE_CHECK_CONTROL 0x1020
  39. #define RANGE_CHECK_STATUS 0x1060
  40. #define FLUSH_CONTROL 0x10A0
  41. #define FLUSH_STATUS 0x10A4
  42. #define INTERRUPT_SET 0x10B0
  43. #define INTERRUPT_STATUS_READ 0x10C0
  44. #define INTERRUPT_STATUS_WRITE 0x10C4
  45. #define INTERRUPT_STATUS_ENCODE 0x10C8
  46. #define INTERRUPT_STATUS_DECODE 0x10CC
  47. #define INTERRUPT_READ_SRC_LOW 0x1100
  48. #define INTERRUPT_READ_SRC_HIGH 0x1104
  49. #define INTERRUPT_WRITE_SRC_LOW 0x1108
  50. #define INTERRUPT_WRITE_SRC_HIGH 0x110C
  51. #define INTERRUPT_ENCODE_SRC_LOW 0x1110
  52. #define INTERRUPT_ENCODE_SRC_HIGH 0x1114
  53. #define INTERRUPT_DECODE_SRC_LOW 0x1118
  54. #define INTERRUPT_DECODE_SRC_HIGH 0x111C
  55. #define INTERRUPT_CLEAR 0x1120
  56. #define QNS4_PARAMS 0x1124
  57. #define OVERRIDE 0x112C
  58. #define VERSION_CONTROL 0x1130
  59. /* read/write register */
  60. #if defined(UBWCP_USE_SMC)
  61. #define UBWCP_REG_READ(_base, _offset) \
  62. ({u32 _reg = 0; int _ret; \
  63. _ret = qcom_scm_io_readl((phys_addr_t)(_base + _offset), &_reg); \
  64. if (_ret) \
  65. DBG("scm_read() failed: %d", _ret); \
  66. else \
  67. DBG("scm_read() : %p + 0x%x -> 0x%08x", _base, _offset, _reg); \
  68. _reg; })
  69. #define UBWCP_REG_WRITE(_base, _offset, _value) \
  70. {int _ret;\
  71. _ret = qcom_scm_io_writel((phys_addr_t)(_base + _offset), _value); \
  72. if (_ret) \
  73. DBG("scm_write() failed: %d", _ret); \
  74. else \
  75. DBG("scm_write(): %p + 0x%x <- 0x%08x", _base, _offset, _value); \
  76. }
  77. #elif defined(UBWCP_DEBUG_REG_RW)
  78. #define UBWCP_REG_READ(_base, _offset) \
  79. ({u32 _reg; \
  80. _reg = ioread32(_base + _offset); \
  81. DBG("READ : 0x%x -> 0x%08x", _offset, _reg); \
  82. _reg; })
  83. #define UBWCP_REG_WRITE(_base, _offset, _value) \
  84. { \
  85. DBG("WRITE: 0x%x <- 0x%08x", _offset, _value); \
  86. iowrite32(_value, _base + _offset); \
  87. }
  88. #elif defined(UBWCP_DUMMY_REG_RW)
  89. /* do nothing */
  90. #define UBWCP_REG_READ(_base, _offset) ((_base + _offset) ? 0x0 : 0x0)
  91. #define UBWCP_REG_WRITE(_base, _offset, _value) ((_base + _offset + _value) ? 0x0 : 0x0)
  92. #else
  93. #define UBWCP_REG_READ(_base, _offset) ioread32(_base + _offset)
  94. #define UBWCP_REG_WRITE(_base, _offset, _value) iowrite32(_value, _base + _offset)
  95. #endif
  96. #define UBWCP_REG_READ_NO_DBG(_base, _offset) ioread32(_base + _offset)
  97. #define UBWCP_REG_WRITE_NO_DBG(_base, _offset, _value) iowrite32(_value, _base + _offset)
  98. void ubwcp_hw_interrupt_enable(void __iomem *base, u16 interrupt, bool enable)
  99. {
  100. u32 value;
  101. value = UBWCP_REG_READ(base, INTERRUPT_SET);
  102. if (enable)
  103. value = value | (1 << interrupt);
  104. else
  105. value = value & ~(1 << interrupt);
  106. UBWCP_REG_WRITE(base, INTERRUPT_SET, value);
  107. }
  108. EXPORT_SYMBOL(ubwcp_hw_interrupt_enable);
  109. void ubwcp_hw_interrupt_clear(void __iomem *base, u16 interrupt)
  110. {
  111. UBWCP_REG_WRITE_NO_DBG(base, INTERRUPT_CLEAR, (1 << interrupt));
  112. }
  113. EXPORT_SYMBOL(ubwcp_hw_interrupt_clear);
  114. int ubwcp_hw_interrupt_status(void __iomem *base, u16 interrupt)
  115. {
  116. int value = -1;
  117. switch (interrupt) {
  118. case INTERRUPT_READ_ERROR:
  119. value = UBWCP_REG_READ(base, INTERRUPT_STATUS_READ) & 0x1;
  120. break;
  121. case INTERRUPT_WRITE_ERROR:
  122. value = UBWCP_REG_READ(base, INTERRUPT_STATUS_WRITE) & 0x1;
  123. break;
  124. case INTERRUPT_DECODE_ERROR:
  125. value = UBWCP_REG_READ(base, INTERRUPT_STATUS_DECODE) & 0x1;
  126. break;
  127. case INTERRUPT_ENCODE_ERROR:
  128. value = UBWCP_REG_READ(base, INTERRUPT_STATUS_ENCODE) & 0x1;
  129. break;
  130. default:
  131. /* TBD: fatal error? */
  132. break;
  133. }
  134. return value;
  135. }
  136. /* returns the address which caused this interrupt */
  137. u64 ubwcp_hw_interrupt_src_address(void __iomem *base, u16 interrupt)
  138. {
  139. u32 addr_low;
  140. u32 addr_high;
  141. switch (interrupt) {
  142. case INTERRUPT_READ_ERROR:
  143. addr_low = UBWCP_REG_READ(base, INTERRUPT_READ_SRC_LOW);
  144. addr_high = UBWCP_REG_READ(base, INTERRUPT_READ_SRC_HIGH) & 0xF;
  145. break;
  146. case INTERRUPT_WRITE_ERROR:
  147. addr_low = UBWCP_REG_READ(base, INTERRUPT_WRITE_SRC_LOW);
  148. addr_high = UBWCP_REG_READ(base, INTERRUPT_WRITE_SRC_HIGH) & 0xF;
  149. break;
  150. case INTERRUPT_DECODE_ERROR:
  151. addr_low = UBWCP_REG_READ(base, INTERRUPT_DECODE_SRC_LOW);
  152. addr_high = UBWCP_REG_READ(base, INTERRUPT_DECODE_SRC_HIGH) & 0xF;
  153. break;
  154. case INTERRUPT_ENCODE_ERROR:
  155. addr_low = UBWCP_REG_READ(base, INTERRUPT_ENCODE_SRC_LOW);
  156. addr_high = UBWCP_REG_READ(base, INTERRUPT_ENCODE_SRC_HIGH) & 0xF;
  157. break;
  158. default:
  159. /* TBD: fatal error? */
  160. addr_low = 0x0;
  161. addr_high = 0x0;
  162. break;
  163. }
  164. return ((addr_high << 31) | addr_low);
  165. }
  166. EXPORT_SYMBOL(ubwcp_hw_interrupt_src_address);
  167. /*
  168. * @index: index of buffer (from 0 to 255)
  169. * @pa : ULA PA start address
  170. * @size : size of ULA PA address range
  171. */
  172. void ubwcp_hw_set_range_check(void __iomem *base, u16 index, phys_addr_t pa, size_t size)
  173. {
  174. u32 lower;
  175. u32 higher;
  176. lower = PAGE_ADDR_4K(pa);
  177. higher = PAGE_ADDR_4K(pa + size);
  178. UBWCP_REG_WRITE(base, RANGE_LOWER + index*4, lower);
  179. UBWCP_REG_WRITE(base, RANGE_HIGHER + index*4, higher);
  180. }
  181. EXPORT_SYMBOL(ubwcp_hw_set_range_check);
  182. /* enable range ck:
  183. * identify control register for this index.
  184. * 32bits in each ctrl reg. upto 8 regs for 256 indexes
  185. */
  186. void ubwcp_hw_enable_range_check(void __iomem *base, u16 index)
  187. {
  188. u32 val;
  189. u16 ctrl_reg = index >> 5;
  190. val = UBWCP_REG_READ(base, RANGE_CHECK_CONTROL + ctrl_reg*4);
  191. val |= (1 << (index & 0x1F));
  192. UBWCP_REG_WRITE(base, RANGE_CHECK_CONTROL + ctrl_reg*4, val);
  193. }
  194. EXPORT_SYMBOL(ubwcp_hw_enable_range_check);
  195. void ubwcp_hw_disable_range_check(void __iomem *base, u16 index)
  196. {
  197. u32 val;
  198. u16 ctrl_reg = index >> 5;
  199. val = UBWCP_REG_READ(base, RANGE_CHECK_CONTROL + ctrl_reg*4);
  200. val &= ~(1 << (index & 0x1F));
  201. UBWCP_REG_WRITE(base, RANGE_CHECK_CONTROL + ctrl_reg*4, val);
  202. }
  203. EXPORT_SYMBOL(ubwcp_hw_disable_range_check);
  204. void ubwcp_hw_set_buf_desc(void __iomem *base, u64 desc_addr, u16 desc_stride)
  205. {
  206. UBWCP_REG_WRITE(base, DESC_BASE, PAGE_ADDR_4K(desc_addr));
  207. UBWCP_REG_WRITE(base, DESC_BASE_STRIDE, desc_stride);
  208. }
  209. EXPORT_SYMBOL(ubwcp_hw_set_buf_desc);
  210. /* Value set here is returned upon read of an address that fails range check.
  211. * Writes are ignored.
  212. * Will also generate range_check_fail interrupt if enabled.
  213. * if we don't program, default value is: 0x92929292
  214. */
  215. void ubwcp_hw_set_default_range_check_value(void __iomem *base, u32 val)
  216. {
  217. UBWCP_REG_WRITE(base, RANGE_CHECK_FAIL, val);
  218. }
  219. void ubwcp_hw_version(void __iomem *base, u32 *major, u32 *minor)
  220. {
  221. u32 version;
  222. version = UBWCP_REG_READ(base, VERSION_CONTROL);
  223. *major = version & 0xF;
  224. *minor = (version & 0xF0) >> 4;
  225. }
  226. EXPORT_SYMBOL(ubwcp_hw_version);
  227. /* TBD: */
  228. void ubwcp_hw_macro_tile_config(void __iomem *base)
  229. {
  230. //TODO: In future add in support for LP4
  231. //May be able to determine DDR version via call to
  232. //of_fdt_get_ddrtype()
  233. /*
  234. * For Lanai assume 4 Channel LP5 DDR so from HSR
  235. * MAL Size 32B
  236. * Highest Bank Bit 16
  237. * Level 1 Bank Swizzling Disable
  238. * Level 2 Bank Swizzling Enable
  239. * Level 3 Bank Swizzling Enable
  240. * Bank Spreading Enable
  241. * Macrotiling Configuration (Num Channels) 8
  242. */
  243. UBWCP_REG_WRITE(base, CONFIG, 0x1E3);
  244. }
  245. /* TBD: */
  246. void ubwcp_hw_decoder_config(void __iomem *base)
  247. {
  248. /*
  249. * For Lanai assume AMSBC (UBWC4.4/4.3) algorithm is used == b11
  250. * For Lanai assume 4 Channel LP5 DDR so MAL Size 32B == b0
  251. */
  252. UBWCP_REG_WRITE(base, DECODER_CONFIG, 0x7);
  253. }
  254. /* TBD: */
  255. void ubwcp_hw_encoder_config(void __iomem *base)
  256. {
  257. /*
  258. * For Lanai assume AMSBC (UBWC4.4/4.3) algorithm is used == b11
  259. * For Lanai assume 4 Channel LP5 DDR so MAL Size 32B == b0
  260. */
  261. UBWCP_REG_WRITE(base, ENCODER_CONFIG, 0x7);
  262. }
  263. int ubwcp_hw_flush(void __iomem *base)
  264. {
  265. u32 flush_complete = 0;
  266. u32 count = 20;
  267. UBWCP_REG_WRITE(base, FLUSH_CONTROL, 0x3);
  268. do {
  269. flush_complete = UBWCP_REG_READ(base, FLUSH_STATUS) & 0x1;
  270. if (flush_complete) {
  271. UBWCP_REG_WRITE(base, FLUSH_CONTROL, 0x0);
  272. return 0;
  273. }
  274. udelay(100);
  275. } while (count--);
  276. ERR("~~~~~ FLUSH FAILED ~~~~~");
  277. return -1;
  278. }
  279. EXPORT_SYMBOL(ubwcp_hw_flush);
  280. void ubwcp_hw_power_vote_status(void __iomem *pwr_ctrl, u8 *vote, u8 *status)
  281. {
  282. u32 reg;
  283. reg = UBWCP_REG_READ(pwr_ctrl, 0);
  284. *vote = (reg & BIT(0)) >> 0;
  285. *status = (reg & BIT(31)) >> 31;
  286. DBG("pwr_ctrl reg: 0x%x (vote = %d status = %d)", reg, *vote, *status);
  287. }
  288. void ubwcp_hw_one_time_init(void __iomem *base)
  289. {
  290. u32 reg;
  291. /* hack: set dataless hazard override bit */
  292. reg = UBWCP_REG_READ(base, OVERRIDE);
  293. UBWCP_REG_WRITE(base, OVERRIDE, 0x2000);
  294. reg = UBWCP_REG_READ(base, OVERRIDE);
  295. /* Configure SID */
  296. reg = UBWCP_REG_READ(base, QNS4_PARAMS);
  297. reg &= ~(0x3F);
  298. reg |= 0x1; /* desc buffer */
  299. reg |= (0 << 3); /* pixel data */
  300. UBWCP_REG_WRITE(base, QNS4_PARAMS, reg);
  301. reg = UBWCP_REG_READ(base, QNS4_PARAMS);
  302. ubwcp_hw_decoder_config(base);
  303. ubwcp_hw_encoder_config(base);
  304. ubwcp_hw_macro_tile_config(base);
  305. }
  306. EXPORT_SYMBOL(ubwcp_hw_one_time_init);