adreno_a6xx_rpmh.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/types.h>
  7. #include <soc/qcom/cmd-db.h>
  8. #include <soc/qcom/tcs.h>
  9. #include "adreno.h"
  10. #include "adreno_a6xx.h"
  11. #include "adreno_hfi.h"
  12. #include "kgsl_bus.h"
  13. #include "kgsl_device.h"
  14. struct rpmh_arc_vals {
  15. u32 num;
  16. const u16 *val;
  17. };
  18. struct bcm {
  19. const char *name;
  20. u32 buswidth;
  21. u32 channels;
  22. u32 unit;
  23. u16 width;
  24. u8 vcd;
  25. bool fixed;
  26. };
  27. struct bcm_data {
  28. __le32 unit;
  29. __le16 width;
  30. u8 vcd;
  31. u8 reserved;
  32. };
  33. struct rpmh_bw_votes {
  34. u32 wait_bitmask;
  35. u32 num_cmds;
  36. u32 *addrs;
  37. u32 num_levels;
  38. u32 **cmds;
  39. };
  40. #define ARC_VOTE_SET(pri, sec, vlvl) \
  41. ((((vlvl) & 0xFFFF) << 16) | (((sec) & 0xFF) << 8) | ((pri) & 0xFF))
  42. static int rpmh_arc_cmds(struct rpmh_arc_vals *arc, const char *res_id)
  43. {
  44. size_t len = 0;
  45. arc->val = cmd_db_read_aux_data(res_id, &len);
  46. /*
  47. * cmd_db_read_aux_data() gives us a zero-padded table of
  48. * size len that contains the arc values. To determine the
  49. * number of arc values, we loop through the table and count
  50. * them until we get to the end of the buffer or hit the
  51. * zero padding.
  52. */
  53. for (arc->num = 1; arc->num < (len >> 1); arc->num++) {
  54. if (arc->val[arc->num - 1] != 0 && arc->val[arc->num] == 0)
  55. break;
  56. }
  57. return 0;
  58. }
  59. static int setup_volt_dependency_tbl(uint32_t *votes,
  60. struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail,
  61. u16 *vlvl, unsigned int num_entries)
  62. {
  63. int i, j, k;
  64. uint16_t cur_vlvl;
  65. bool found_match;
  66. /* i tracks current KGSL GPU frequency table entry
  67. * j tracks secondary rail voltage table entry
  68. * k tracks primary rail voltage table entry
  69. */
  70. for (i = 0; i < num_entries; i++) {
  71. found_match = false;
  72. /* Look for a primary rail voltage that matches a VLVL level */
  73. for (k = 0; k < pri_rail->num; k++) {
  74. if (pri_rail->val[k] >= vlvl[i]) {
  75. cur_vlvl = pri_rail->val[k];
  76. found_match = true;
  77. break;
  78. }
  79. }
  80. /* If we did not find a matching VLVL level then abort */
  81. if (!found_match)
  82. return -EINVAL;
  83. /*
  84. * Look for a secondary rail index whose VLVL value
  85. * is greater than or equal to the VLVL value of the
  86. * corresponding index of the primary rail
  87. */
  88. for (j = 0; j < sec_rail->num; j++) {
  89. if (sec_rail->val[j] >= cur_vlvl ||
  90. j + 1 == sec_rail->num)
  91. break;
  92. }
  93. if (j == sec_rail->num)
  94. j = 0;
  95. votes[i] = ARC_VOTE_SET(k, j, cur_vlvl);
  96. }
  97. return 0;
  98. }
  99. /* Generate a set of bandwidth votes for the list of BCMs */
  100. static void tcs_cmd_data(struct bcm *bcms, int count, u32 ab, u32 ib,
  101. u32 *data)
  102. {
  103. int i;
  104. for (i = 0; i < count; i++) {
  105. bool valid = true;
  106. bool commit = false;
  107. u64 avg, peak, x, y;
  108. if (i == count - 1 || bcms[i].vcd != bcms[i + 1].vcd)
  109. commit = true;
  110. /*
  111. * On a660, the "ACV" y vote should be 0x08 if there is a valid
  112. * vote and 0x00 if not. This is kind of hacky and a660 specific
  113. * but we can clean it up when we add a new target
  114. */
  115. if (bcms[i].fixed) {
  116. if (!ab && !ib)
  117. data[i] = BCM_TCS_CMD(commit, false, 0x0, 0x0);
  118. else
  119. data[i] = BCM_TCS_CMD(commit, true, 0x0, 0x8);
  120. continue;
  121. }
  122. /* Multiple the bandwidth by the width of the connection */
  123. avg = ((u64) ab) * bcms[i].width;
  124. /* And then divide by the total width across channels */
  125. do_div(avg, bcms[i].buswidth * bcms[i].channels);
  126. peak = ((u64) ib) * bcms[i].width;
  127. do_div(peak, bcms[i].buswidth);
  128. /* Input bandwidth value is in KBps */
  129. x = avg * 1000ULL;
  130. do_div(x, bcms[i].unit);
  131. /* Input bandwidth value is in KBps */
  132. y = peak * 1000ULL;
  133. do_div(y, bcms[i].unit);
  134. /*
  135. * If a bandwidth value was specified but the calculation ends
  136. * rounding down to zero, set a minimum level
  137. */
  138. if (ab && x == 0)
  139. x = 1;
  140. if (ib && y == 0)
  141. y = 1;
  142. x = min_t(u64, x, BCM_TCS_CMD_VOTE_MASK);
  143. y = min_t(u64, y, BCM_TCS_CMD_VOTE_MASK);
  144. if (!x && !y)
  145. valid = false;
  146. data[i] = BCM_TCS_CMD(commit, valid, x, y);
  147. }
  148. }
  149. static void free_rpmh_bw_votes(struct rpmh_bw_votes *votes)
  150. {
  151. int i;
  152. if (!votes)
  153. return;
  154. for (i = 0; votes->cmds && i < votes->num_levels; i++)
  155. kfree(votes->cmds[i]);
  156. kfree(votes->cmds);
  157. kfree(votes->addrs);
  158. kfree(votes);
  159. }
  160. /* Build the votes table from the specified bandwidth levels */
  161. static struct rpmh_bw_votes *build_rpmh_bw_votes(struct bcm *bcms,
  162. int bcm_count, u32 *levels, int levels_count)
  163. {
  164. struct rpmh_bw_votes *votes;
  165. int i;
  166. votes = kzalloc(sizeof(*votes), GFP_KERNEL);
  167. if (!votes)
  168. return ERR_PTR(-ENOMEM);
  169. votes->addrs = kcalloc(bcm_count, sizeof(*votes->cmds), GFP_KERNEL);
  170. if (!votes->addrs) {
  171. free_rpmh_bw_votes(votes);
  172. return ERR_PTR(-ENOMEM);
  173. }
  174. votes->cmds = kcalloc(levels_count, sizeof(*votes->cmds), GFP_KERNEL);
  175. if (!votes->cmds) {
  176. free_rpmh_bw_votes(votes);
  177. return ERR_PTR(-ENOMEM);
  178. }
  179. votes->num_cmds = bcm_count;
  180. votes->num_levels = levels_count;
  181. /* Get the cmd-db information for each BCM */
  182. for (i = 0; i < bcm_count; i++) {
  183. size_t l;
  184. const struct bcm_data *data;
  185. data = cmd_db_read_aux_data(bcms[i].name, &l);
  186. votes->addrs[i] = cmd_db_read_addr(bcms[i].name);
  187. bcms[i].unit = le32_to_cpu(data->unit);
  188. bcms[i].width = le16_to_cpu(data->width);
  189. bcms[i].vcd = data->vcd;
  190. }
  191. for (i = 0; i < bcm_count; i++) {
  192. if (i == (bcm_count - 1) || bcms[i].vcd != bcms[i + 1].vcd)
  193. votes->wait_bitmask |= (1 << i);
  194. }
  195. for (i = 0; i < levels_count; i++) {
  196. votes->cmds[i] = kcalloc(bcm_count, sizeof(u32), GFP_KERNEL);
  197. if (!votes->cmds[i]) {
  198. free_rpmh_bw_votes(votes);
  199. return ERR_PTR(-ENOMEM);
  200. }
  201. tcs_cmd_data(bcms, bcm_count, 0, levels[i], votes->cmds[i]);
  202. }
  203. return votes;
  204. }
  205. /*
  206. * setup_gmu_arc_votes - Build the gmu voting table
  207. * @adreno_dev: Pointer to adreno device
  208. * @pri_rail: Pointer to primary power rail vlvl table
  209. * @sec_rail: Pointer to second/dependent power rail vlvl table
  210. * @freqs: List of GMU frequencies
  211. * @vlvls: List of GMU voltage levels
  212. *
  213. * This function initializes the cx votes for all gmu frequencies
  214. * for gmu dcvs
  215. */
  216. static int setup_cx_arc_votes(struct adreno_device *adreno_dev,
  217. struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail,
  218. u32 *freqs, u32 *vlvls)
  219. {
  220. /* Hardcoded values of GMU CX voltage levels */
  221. struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
  222. struct a6xx_hfi *hfi = &gmu->hfi;
  223. u16 gmu_cx_vlvl[MAX_CX_LEVELS];
  224. u32 cx_votes[MAX_CX_LEVELS];
  225. struct hfi_dcvstable_cmd *table = &hfi->dcvs_table;
  226. int ret, i;
  227. gmu_cx_vlvl[0] = 0;
  228. gmu_cx_vlvl[1] = vlvls[0];
  229. gmu_cx_vlvl[2] = vlvls[1];
  230. table->gmu_level_num = 3;
  231. table->cx_votes[0].freq = 0;
  232. table->cx_votes[1].freq = freqs[0] / 1000;
  233. table->cx_votes[2].freq = freqs[1] / 1000;
  234. ret = setup_volt_dependency_tbl(cx_votes, pri_rail,
  235. sec_rail, gmu_cx_vlvl, table->gmu_level_num);
  236. if (!ret) {
  237. for (i = 0; i < table->gmu_level_num; i++)
  238. table->cx_votes[i].vote = cx_votes[i];
  239. }
  240. return ret;
  241. }
  242. static int to_cx_hlvl(struct rpmh_arc_vals *cx_rail, u32 vlvl, u32 *hlvl)
  243. {
  244. u32 i;
  245. /*
  246. * This means that the Gx level doesn't have a dependency on Cx level.
  247. * Return the same value to disable cx voting at GMU.
  248. */
  249. if (vlvl == 0xffffffff) {
  250. *hlvl = vlvl;
  251. return 0;
  252. }
  253. for (i = 0; i < cx_rail->num; i++) {
  254. if (cx_rail->val[i] >= vlvl) {
  255. *hlvl = i;
  256. return 0;
  257. }
  258. }
  259. return -EINVAL;
  260. }
  261. /*
  262. * setup_gx_arc_votes - Build the gpu dcvs voting table
  263. * @hfi: Pointer to hfi device
  264. * @pri_rail: Pointer to primary power rail vlvl table
  265. * @sec_rail: Pointer to second/dependent power rail vlvl table
  266. *
  267. * This function initializes the gx votes for all gpu frequencies
  268. * for gpu dcvs
  269. */
  270. static int setup_gx_arc_votes(struct adreno_device *adreno_dev,
  271. struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail,
  272. struct rpmh_arc_vals *cx_rail)
  273. {
  274. struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
  275. struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
  276. struct kgsl_pwrctrl *pwr = &device->pwrctrl;
  277. struct hfi_dcvstable_cmd *table = &gmu->hfi.dcvs_table;
  278. u32 index;
  279. u16 vlvl_tbl[MAX_GX_LEVELS];
  280. u32 gx_votes[MAX_GX_LEVELS];
  281. int ret, i;
  282. /* Add the zero powerlevel for the perf table */
  283. table->gpu_level_num = device->pwrctrl.num_pwrlevels + 1;
  284. if (table->gpu_level_num > pri_rail->num ||
  285. table->gpu_level_num > ARRAY_SIZE(vlvl_tbl)) {
  286. dev_err(&gmu->pdev->dev,
  287. "Defined more GPU DCVS levels than RPMh can support\n");
  288. return -ERANGE;
  289. }
  290. memset(vlvl_tbl, 0, sizeof(vlvl_tbl));
  291. table->gx_votes[0].freq = 0;
  292. table->gx_votes[0].cx_vote = 0;
  293. /* Disable cx vote in gmu dcvs table if it is not supported in DT */
  294. if (pwr->pwrlevels[0].cx_level == 0xffffffff)
  295. table->gx_votes[0].cx_vote = 0xffffffff;
  296. /* GMU power levels are in ascending order */
  297. for (index = 1, i = pwr->num_pwrlevels - 1; i >= 0; i--, index++) {
  298. u32 cx_vlvl = pwr->pwrlevels[i].cx_level;
  299. vlvl_tbl[index] = pwr->pwrlevels[i].voltage_level;
  300. table->gx_votes[index].freq = pwr->pwrlevels[i].gpu_freq / 1000;
  301. ret = to_cx_hlvl(cx_rail, cx_vlvl,
  302. &table->gx_votes[index].cx_vote);
  303. if (ret) {
  304. dev_err(&gmu->pdev->dev, "Unsupported cx corner: %u\n",
  305. cx_vlvl);
  306. return ret;
  307. }
  308. }
  309. ret = setup_volt_dependency_tbl(gx_votes, pri_rail,
  310. sec_rail, vlvl_tbl, table->gpu_level_num);
  311. if (!ret) {
  312. for (i = 0; i < table->gpu_level_num; i++)
  313. table->gx_votes[i].vote = gx_votes[i];
  314. }
  315. return ret;
  316. }
  317. static int build_dcvs_table(struct adreno_device *adreno_dev)
  318. {
  319. struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
  320. struct a6xx_hfi *hfi = &gmu->hfi;
  321. struct rpmh_arc_vals gx_arc, cx_arc, mx_arc;
  322. int ret;
  323. ret = CMD_MSG_HDR(hfi->dcvs_table, H2F_MSG_PERF_TBL);
  324. if (ret)
  325. return ret;
  326. ret = rpmh_arc_cmds(&gx_arc, "gfx.lvl");
  327. if (ret)
  328. return ret;
  329. ret = rpmh_arc_cmds(&cx_arc, "cx.lvl");
  330. if (ret)
  331. return ret;
  332. ret = rpmh_arc_cmds(&mx_arc, "mx.lvl");
  333. if (ret)
  334. return ret;
  335. ret = setup_cx_arc_votes(adreno_dev, &cx_arc, &mx_arc,
  336. gmu->freqs, gmu->vlvls);
  337. if (ret)
  338. return ret;
  339. return setup_gx_arc_votes(adreno_dev, &gx_arc, &mx_arc, &cx_arc);
  340. }
  341. /*
  342. * List of Bus Control Modules (BCMs) that need to be configured for the GPU
  343. * to access DDR. For each bus level we will generate a vote each BC
  344. */
  345. static struct bcm a660_ddr_bcms[] = {
  346. { .name = "SH0", .buswidth = 16 },
  347. { .name = "MC0", .buswidth = 4 },
  348. { .name = "ACV", .fixed = true },
  349. };
  350. /* Same as above, but for the CNOC BCMs */
  351. static struct bcm a660_cnoc_bcms[] = {
  352. { .name = "CN0", .buswidth = 4 },
  353. };
  354. static void build_bw_table_cmd(struct hfi_bwtable_cmd *cmd,
  355. struct rpmh_bw_votes *ddr, struct rpmh_bw_votes *cnoc)
  356. {
  357. u32 i, j;
  358. cmd->bw_level_num = ddr->num_levels;
  359. cmd->ddr_cmds_num = ddr->num_cmds;
  360. cmd->ddr_wait_bitmask = ddr->wait_bitmask;
  361. for (i = 0; i < ddr->num_cmds; i++)
  362. cmd->ddr_cmd_addrs[i] = ddr->addrs[i];
  363. for (i = 0; i < ddr->num_levels; i++)
  364. for (j = 0; j < ddr->num_cmds; j++)
  365. cmd->ddr_cmd_data[i][j] = (u32) ddr->cmds[i][j];
  366. if (!cnoc)
  367. return;
  368. cmd->cnoc_cmds_num = cnoc->num_cmds;
  369. cmd->cnoc_wait_bitmask = cnoc->wait_bitmask;
  370. for (i = 0; i < cnoc->num_cmds; i++)
  371. cmd->cnoc_cmd_addrs[i] = cnoc->addrs[i];
  372. for (i = 0; i < cnoc->num_levels; i++)
  373. for (j = 0; j < cnoc->num_cmds; j++)
  374. cmd->cnoc_cmd_data[i][j] = (u32) cnoc->cmds[i][j];
  375. }
  376. static int build_bw_table(struct adreno_device *adreno_dev)
  377. {
  378. struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
  379. struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
  380. struct kgsl_pwrctrl *pwr = &device->pwrctrl;
  381. struct rpmh_bw_votes *ddr, *cnoc = NULL;
  382. u32 *cnoc_table;
  383. u32 count;
  384. int ret;
  385. ddr = build_rpmh_bw_votes(a660_ddr_bcms, ARRAY_SIZE(a660_ddr_bcms),
  386. pwr->ddr_table, pwr->ddr_table_count);
  387. if (IS_ERR(ddr))
  388. return PTR_ERR(ddr);
  389. cnoc_table = kgsl_bus_get_table(device->pdev, "qcom,bus-table-cnoc",
  390. &count);
  391. if (count > 0)
  392. cnoc = build_rpmh_bw_votes(a660_cnoc_bcms,
  393. ARRAY_SIZE(a660_cnoc_bcms), cnoc_table, count);
  394. kfree(cnoc_table);
  395. if (IS_ERR(cnoc)) {
  396. free_rpmh_bw_votes(ddr);
  397. return PTR_ERR(cnoc);
  398. }
  399. ret = CMD_MSG_HDR(gmu->hfi.bw_table, H2F_MSG_BW_VOTE_TBL);
  400. if (ret)
  401. return ret;
  402. build_bw_table_cmd(&gmu->hfi.bw_table, ddr, cnoc);
  403. free_rpmh_bw_votes(ddr);
  404. free_rpmh_bw_votes(cnoc);
  405. return 0;
  406. }
  407. int a6xx_build_rpmh_tables(struct adreno_device *adreno_dev)
  408. {
  409. int ret;
  410. ret = build_dcvs_table(adreno_dev);
  411. if (ret)
  412. return ret;
  413. return build_bw_table(adreno_dev);
  414. }