hisi_uncore_freq.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * HiSilicon uncore frequency scaling driver
  4. *
  5. * Copyright (c) 2025 HiSilicon Co., Ltd
  6. */
  7. #include <linux/acpi.h>
  8. #include <linux/bits.h>
  9. #include <linux/cleanup.h>
  10. #include <linux/devfreq.h>
  11. #include <linux/devfreq-governor.h>
  12. #include <linux/device.h>
  13. #include <linux/dev_printk.h>
  14. #include <linux/errno.h>
  15. #include <linux/iopoll.h>
  16. #include <linux/kernel.h>
  17. #include <linux/ktime.h>
  18. #include <linux/mailbox_client.h>
  19. #include <linux/module.h>
  20. #include <linux/mod_devicetable.h>
  21. #include <linux/mutex.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/pm_opp.h>
  24. #include <linux/property.h>
  25. #include <linux/topology.h>
  26. #include <linux/units.h>
  27. #include <acpi/pcc.h>
  28. struct hisi_uncore_pcc_data {
  29. u16 status;
  30. u16 resv;
  31. u32 data;
  32. };
  33. struct hisi_uncore_pcc_shmem {
  34. struct acpi_pcct_shared_memory head;
  35. struct hisi_uncore_pcc_data pcc_data;
  36. };
  37. enum hisi_uncore_pcc_cmd_type {
  38. HUCF_PCC_CMD_GET_CAP = 0,
  39. HUCF_PCC_CMD_GET_FREQ,
  40. HUCF_PCC_CMD_SET_FREQ,
  41. HUCF_PCC_CMD_GET_MODE,
  42. HUCF_PCC_CMD_SET_MODE,
  43. HUCF_PCC_CMD_GET_PLAT_FREQ_NUM,
  44. HUCF_PCC_CMD_GET_PLAT_FREQ_BY_IDX,
  45. HUCF_PCC_CMD_MAX = 256
  46. };
  47. static int hisi_platform_gov_usage;
  48. static DEFINE_MUTEX(hisi_platform_gov_usage_lock);
  49. enum hisi_uncore_freq_mode {
  50. HUCF_MODE_PLATFORM = 0,
  51. HUCF_MODE_OS,
  52. HUCF_MODE_MAX
  53. };
  54. #define HUCF_CAP_PLATFORM_CTRL BIT(0)
  55. /**
  56. * struct hisi_uncore_freq - hisi uncore frequency scaling device data
  57. * @dev: device of this frequency scaling driver
  58. * @cl: mailbox client object
  59. * @pchan: PCC mailbox channel
  60. * @chan_id: PCC channel ID
  61. * @last_cmd_cmpl_time: timestamp of the last completed PCC command
  62. * @pcc_lock: PCC channel lock
  63. * @devfreq: devfreq data of this hisi_uncore_freq device
  64. * @related_cpus: CPUs whose performance is majorly affected by this
  65. * uncore frequency domain
  66. * @cap: capability flag
  67. */
  68. struct hisi_uncore_freq {
  69. struct device *dev;
  70. struct mbox_client cl;
  71. struct pcc_mbox_chan *pchan;
  72. int chan_id;
  73. ktime_t last_cmd_cmpl_time;
  74. struct mutex pcc_lock;
  75. struct devfreq *devfreq;
  76. struct cpumask related_cpus;
  77. u32 cap;
  78. };
  79. /* PCC channel timeout = PCC nominal latency * NUM */
  80. #define HUCF_PCC_POLL_TIMEOUT_NUM 1000
  81. #define HUCF_PCC_POLL_INTERVAL_US 5
  82. /* Default polling interval in ms for devfreq governors*/
  83. #define HUCF_DEFAULT_POLLING_MS 100
  84. static void hisi_uncore_free_pcc_chan(struct hisi_uncore_freq *uncore)
  85. {
  86. guard(mutex)(&uncore->pcc_lock);
  87. pcc_mbox_free_channel(uncore->pchan);
  88. uncore->pchan = NULL;
  89. }
  90. static void devm_hisi_uncore_free_pcc_chan(void *data)
  91. {
  92. hisi_uncore_free_pcc_chan(data);
  93. }
  94. static int hisi_uncore_request_pcc_chan(struct hisi_uncore_freq *uncore)
  95. {
  96. struct device *dev = uncore->dev;
  97. struct pcc_mbox_chan *pcc_chan;
  98. uncore->cl = (struct mbox_client) {
  99. .dev = dev,
  100. .tx_block = false,
  101. .knows_txdone = true,
  102. };
  103. pcc_chan = pcc_mbox_request_channel(&uncore->cl, uncore->chan_id);
  104. if (IS_ERR(pcc_chan))
  105. return dev_err_probe(dev, PTR_ERR(pcc_chan),
  106. "Failed to request PCC channel %u\n", uncore->chan_id);
  107. if (!pcc_chan->shmem_base_addr) {
  108. pcc_mbox_free_channel(pcc_chan);
  109. return dev_err_probe(dev, -EINVAL,
  110. "Invalid PCC shared memory address\n");
  111. }
  112. if (pcc_chan->shmem_size < sizeof(struct hisi_uncore_pcc_shmem)) {
  113. pcc_mbox_free_channel(pcc_chan);
  114. return dev_err_probe(dev, -EINVAL,
  115. "Invalid PCC shared memory size (%lluB)\n",
  116. pcc_chan->shmem_size);
  117. }
  118. uncore->pchan = pcc_chan;
  119. return devm_add_action_or_reset(uncore->dev,
  120. devm_hisi_uncore_free_pcc_chan, uncore);
  121. }
  122. static acpi_status hisi_uncore_pcc_reg_scan(struct acpi_resource *res,
  123. void *ctx)
  124. {
  125. struct acpi_resource_generic_register *reg;
  126. struct hisi_uncore_freq *uncore;
  127. if (!res || res->type != ACPI_RESOURCE_TYPE_GENERIC_REGISTER)
  128. return AE_OK;
  129. reg = &res->data.generic_reg;
  130. if (reg->space_id != ACPI_ADR_SPACE_PLATFORM_COMM)
  131. return AE_OK;
  132. if (!ctx)
  133. return AE_ERROR;
  134. uncore = ctx;
  135. /* PCC subspace ID stored in Access Size */
  136. uncore->chan_id = reg->access_size;
  137. return AE_CTRL_TERMINATE;
  138. }
  139. static int hisi_uncore_init_pcc_chan(struct hisi_uncore_freq *uncore)
  140. {
  141. acpi_handle handle = ACPI_HANDLE(uncore->dev);
  142. acpi_status status;
  143. int rc;
  144. uncore->chan_id = -1;
  145. status = acpi_walk_resources(handle, METHOD_NAME__CRS,
  146. hisi_uncore_pcc_reg_scan, uncore);
  147. if (ACPI_FAILURE(status) || uncore->chan_id < 0)
  148. return dev_err_probe(uncore->dev, -ENODEV,
  149. "Failed to get a PCC channel\n");
  150. rc = devm_mutex_init(uncore->dev, &uncore->pcc_lock);
  151. if (rc)
  152. return rc;
  153. return hisi_uncore_request_pcc_chan(uncore);
  154. }
  155. static int hisi_uncore_cmd_send(struct hisi_uncore_freq *uncore,
  156. u8 cmd, u32 *data)
  157. {
  158. struct hisi_uncore_pcc_shmem __iomem *addr;
  159. struct hisi_uncore_pcc_shmem shmem;
  160. struct pcc_mbox_chan *pchan;
  161. unsigned int mrtt;
  162. s64 time_delta;
  163. u16 status;
  164. int rc;
  165. guard(mutex)(&uncore->pcc_lock);
  166. pchan = uncore->pchan;
  167. if (!pchan)
  168. return -ENODEV;
  169. addr = (struct hisi_uncore_pcc_shmem __iomem *)pchan->shmem;
  170. if (!addr)
  171. return -EINVAL;
  172. /* Handle the Minimum Request Turnaround Time (MRTT) */
  173. mrtt = pchan->min_turnaround_time;
  174. time_delta = ktime_us_delta(ktime_get(), uncore->last_cmd_cmpl_time);
  175. if (mrtt > time_delta)
  176. udelay(mrtt - time_delta);
  177. /* Copy data */
  178. shmem.head = (struct acpi_pcct_shared_memory) {
  179. .signature = PCC_SIGNATURE | uncore->chan_id,
  180. .command = cmd,
  181. };
  182. shmem.pcc_data.data = *data;
  183. memcpy_toio(addr, &shmem, sizeof(shmem));
  184. /* Ring doorbell */
  185. rc = mbox_send_message(pchan->mchan, &cmd);
  186. if (rc < 0) {
  187. dev_err(uncore->dev, "Failed to send mbox message, %d\n", rc);
  188. return rc;
  189. }
  190. /* Wait status */
  191. rc = readw_poll_timeout(&addr->head.status, status,
  192. status & (PCC_STATUS_CMD_COMPLETE |
  193. PCC_STATUS_ERROR),
  194. HUCF_PCC_POLL_INTERVAL_US,
  195. pchan->latency * HUCF_PCC_POLL_TIMEOUT_NUM);
  196. if (rc) {
  197. dev_err(uncore->dev, "PCC channel response timeout, cmd=%u\n", cmd);
  198. } else if (status & PCC_STATUS_ERROR) {
  199. dev_err(uncore->dev, "PCC cmd error, cmd=%u\n", cmd);
  200. rc = -EIO;
  201. }
  202. uncore->last_cmd_cmpl_time = ktime_get();
  203. /* Copy data back */
  204. memcpy_fromio(data, &addr->pcc_data.data, sizeof(*data));
  205. /* Clear mailbox active req */
  206. mbox_client_txdone(pchan->mchan, rc);
  207. return rc;
  208. }
  209. static int hisi_uncore_target(struct device *dev, unsigned long *freq,
  210. u32 flags)
  211. {
  212. struct hisi_uncore_freq *uncore = dev_get_drvdata(dev);
  213. struct dev_pm_opp *opp;
  214. u32 data;
  215. if (WARN_ON(!uncore || !uncore->pchan))
  216. return -ENODEV;
  217. opp = devfreq_recommended_opp(dev, freq, flags);
  218. if (IS_ERR(opp)) {
  219. dev_err(dev, "Failed to get opp for freq %lu hz\n", *freq);
  220. return PTR_ERR(opp);
  221. }
  222. data = (u32)(dev_pm_opp_get_freq(opp) / HZ_PER_MHZ);
  223. dev_pm_opp_put(opp);
  224. return hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_SET_FREQ, &data);
  225. }
  226. static int hisi_uncore_get_dev_status(struct device *dev,
  227. struct devfreq_dev_status *stat)
  228. {
  229. /* Not used */
  230. return 0;
  231. }
  232. static int hisi_uncore_get_cur_freq(struct device *dev, unsigned long *freq)
  233. {
  234. struct hisi_uncore_freq *uncore = dev_get_drvdata(dev);
  235. u32 data = 0;
  236. int rc;
  237. if (WARN_ON(!uncore || !uncore->pchan))
  238. return -ENODEV;
  239. rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_GET_FREQ, &data);
  240. /*
  241. * Upon a failure, 'data' remains 0 and 'freq' is set to 0 rather than a
  242. * random value. devfreq shouldn't use 'freq' in that case though.
  243. */
  244. *freq = data * HZ_PER_MHZ;
  245. return rc;
  246. }
  247. static void devm_hisi_uncore_remove_opp(void *data)
  248. {
  249. struct hisi_uncore_freq *uncore = data;
  250. dev_pm_opp_remove_all_dynamic(uncore->dev);
  251. }
  252. static int hisi_uncore_init_opp(struct hisi_uncore_freq *uncore)
  253. {
  254. struct device *dev = uncore->dev;
  255. unsigned long freq_mhz;
  256. u32 num, index;
  257. u32 data = 0;
  258. int rc;
  259. rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_GET_PLAT_FREQ_NUM,
  260. &data);
  261. if (rc)
  262. return dev_err_probe(dev, rc, "Failed to get plat freq num\n");
  263. num = data;
  264. for (index = 0; index < num; index++) {
  265. data = index;
  266. rc = hisi_uncore_cmd_send(uncore,
  267. HUCF_PCC_CMD_GET_PLAT_FREQ_BY_IDX,
  268. &data);
  269. if (rc) {
  270. dev_pm_opp_remove_all_dynamic(dev);
  271. return dev_err_probe(dev, rc,
  272. "Failed to get plat freq at index %u\n", index);
  273. }
  274. freq_mhz = data;
  275. /* Don't care OPP voltage, take 1V as default */
  276. rc = dev_pm_opp_add(dev, freq_mhz * HZ_PER_MHZ, 1000000);
  277. if (rc) {
  278. dev_pm_opp_remove_all_dynamic(dev);
  279. return dev_err_probe(dev, rc,
  280. "Add OPP %lu failed\n", freq_mhz);
  281. }
  282. }
  283. return devm_add_action_or_reset(dev, devm_hisi_uncore_remove_opp,
  284. uncore);
  285. }
  286. static int hisi_platform_gov_func(struct devfreq *df, unsigned long *freq)
  287. {
  288. /*
  289. * Platform-controlled mode doesn't care the frequency issued from
  290. * devfreq, so just pick the max freq.
  291. */
  292. *freq = DEVFREQ_MAX_FREQ;
  293. return 0;
  294. }
  295. static int hisi_platform_gov_handler(struct devfreq *df, unsigned int event,
  296. void *val)
  297. {
  298. struct hisi_uncore_freq *uncore = dev_get_drvdata(df->dev.parent);
  299. int rc = 0;
  300. u32 data;
  301. if (WARN_ON(!uncore || !uncore->pchan))
  302. return -ENODEV;
  303. switch (event) {
  304. case DEVFREQ_GOV_START:
  305. data = HUCF_MODE_PLATFORM;
  306. rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_SET_MODE, &data);
  307. if (rc)
  308. dev_err(uncore->dev, "Failed to set platform mode (%d)\n", rc);
  309. break;
  310. case DEVFREQ_GOV_STOP:
  311. data = HUCF_MODE_OS;
  312. rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_SET_MODE, &data);
  313. if (rc)
  314. dev_err(uncore->dev, "Failed to set os mode (%d)\n", rc);
  315. break;
  316. default:
  317. break;
  318. }
  319. return rc;
  320. }
  321. /*
  322. * In the platform-controlled mode, the platform decides the uncore frequency
  323. * and ignores the frequency issued from the driver.
  324. * Thus, create a pseudo 'hisi_platform' governor that stops devfreq monitor
  325. * from working so as to save meaningless overhead.
  326. */
  327. static struct devfreq_governor hisi_platform_governor = {
  328. .name = "hisi_platform",
  329. /*
  330. * Set interrupt_driven to skip the devfreq monitor mechanism, though
  331. * this governor is not interrupt-driven.
  332. */
  333. .flags = DEVFREQ_GOV_FLAG_IRQ_DRIVEN,
  334. .get_target_freq = hisi_platform_gov_func,
  335. .event_handler = hisi_platform_gov_handler,
  336. };
  337. static void hisi_uncore_remove_platform_gov(struct hisi_uncore_freq *uncore)
  338. {
  339. u32 data = HUCF_MODE_PLATFORM;
  340. int rc;
  341. if (!(uncore->cap & HUCF_CAP_PLATFORM_CTRL))
  342. return;
  343. guard(mutex)(&hisi_platform_gov_usage_lock);
  344. if (--hisi_platform_gov_usage == 0) {
  345. rc = devfreq_remove_governor(&hisi_platform_governor);
  346. if (rc)
  347. dev_err(uncore->dev, "Failed to remove hisi_platform gov (%d)\n", rc);
  348. }
  349. /*
  350. * Set to the platform-controlled mode on exit if supported, so as to
  351. * have a certain behaviour when the driver is detached.
  352. */
  353. rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_SET_MODE, &data);
  354. if (rc)
  355. dev_err(uncore->dev, "Failed to set platform mode on exit (%d)\n", rc);
  356. }
  357. static void devm_hisi_uncore_remove_platform_gov(void *data)
  358. {
  359. hisi_uncore_remove_platform_gov(data);
  360. }
  361. static int hisi_uncore_add_platform_gov(struct hisi_uncore_freq *uncore)
  362. {
  363. if (!(uncore->cap & HUCF_CAP_PLATFORM_CTRL))
  364. return 0;
  365. guard(mutex)(&hisi_platform_gov_usage_lock);
  366. if (hisi_platform_gov_usage == 0) {
  367. int rc = devfreq_add_governor(&hisi_platform_governor);
  368. if (rc)
  369. return rc;
  370. }
  371. hisi_platform_gov_usage++;
  372. return devm_add_action_or_reset(uncore->dev,
  373. devm_hisi_uncore_remove_platform_gov,
  374. uncore);
  375. }
  376. /*
  377. * Returns:
  378. * 0 if success, uncore->related_cpus is set.
  379. * -EINVAL if property not found, or property found but without elements in it,
  380. * or invalid arguments received in any of the subroutine.
  381. * Other error codes if it goes wrong.
  382. */
  383. static int hisi_uncore_mark_related_cpus(struct hisi_uncore_freq *uncore,
  384. char *property, int (*get_topo_id)(int cpu),
  385. const struct cpumask *(*get_cpumask)(int cpu))
  386. {
  387. unsigned int i, cpu;
  388. size_t len;
  389. int rc;
  390. rc = device_property_count_u32(uncore->dev, property);
  391. if (rc < 0)
  392. return rc;
  393. if (rc == 0)
  394. return -EINVAL;
  395. len = rc;
  396. u32 *num __free(kfree) = kcalloc(len, sizeof(*num), GFP_KERNEL);
  397. if (!num)
  398. return -ENOMEM;
  399. rc = device_property_read_u32_array(uncore->dev, property, num, len);
  400. if (rc)
  401. return rc;
  402. for (i = 0; i < len; i++) {
  403. for_each_possible_cpu(cpu) {
  404. if (get_topo_id(cpu) != num[i])
  405. continue;
  406. cpumask_or(&uncore->related_cpus,
  407. &uncore->related_cpus, get_cpumask(cpu));
  408. break;
  409. }
  410. }
  411. return 0;
  412. }
  413. static int get_package_id(int cpu)
  414. {
  415. return topology_physical_package_id(cpu);
  416. }
  417. static const struct cpumask *get_package_cpumask(int cpu)
  418. {
  419. return topology_core_cpumask(cpu);
  420. }
  421. static int get_cluster_id(int cpu)
  422. {
  423. return topology_cluster_id(cpu);
  424. }
  425. static const struct cpumask *get_cluster_cpumask(int cpu)
  426. {
  427. return topology_cluster_cpumask(cpu);
  428. }
  429. static int hisi_uncore_mark_related_cpus_wrap(struct hisi_uncore_freq *uncore)
  430. {
  431. int rc;
  432. cpumask_clear(&uncore->related_cpus);
  433. rc = hisi_uncore_mark_related_cpus(uncore, "related-package",
  434. get_package_id,
  435. get_package_cpumask);
  436. /* Success, or firmware probably broken */
  437. if (!rc || rc != -EINVAL)
  438. return rc;
  439. /* Try another property name if rc == -EINVAL */
  440. return hisi_uncore_mark_related_cpus(uncore, "related-cluster",
  441. get_cluster_id,
  442. get_cluster_cpumask);
  443. }
  444. static ssize_t related_cpus_show(struct device *dev,
  445. struct device_attribute *attr, char *buf)
  446. {
  447. struct hisi_uncore_freq *uncore = dev_get_drvdata(dev->parent);
  448. return cpumap_print_to_pagebuf(true, buf, &uncore->related_cpus);
  449. }
  450. static DEVICE_ATTR_RO(related_cpus);
  451. static struct attribute *hisi_uncore_freq_attrs[] = {
  452. &dev_attr_related_cpus.attr,
  453. NULL
  454. };
  455. ATTRIBUTE_GROUPS(hisi_uncore_freq);
  456. static int hisi_uncore_devfreq_register(struct hisi_uncore_freq *uncore)
  457. {
  458. struct devfreq_dev_profile *profile;
  459. struct device *dev = uncore->dev;
  460. unsigned long freq;
  461. u32 data;
  462. int rc;
  463. rc = hisi_uncore_get_cur_freq(dev, &freq);
  464. if (rc)
  465. return dev_err_probe(dev, rc, "Failed to get plat init freq\n");
  466. profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
  467. if (!profile)
  468. return -ENOMEM;
  469. *profile = (struct devfreq_dev_profile) {
  470. .initial_freq = freq,
  471. .polling_ms = HUCF_DEFAULT_POLLING_MS,
  472. .timer = DEVFREQ_TIMER_DELAYED,
  473. .target = hisi_uncore_target,
  474. .get_dev_status = hisi_uncore_get_dev_status,
  475. .get_cur_freq = hisi_uncore_get_cur_freq,
  476. .dev_groups = hisi_uncore_freq_groups,
  477. };
  478. rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_GET_MODE, &data);
  479. if (rc)
  480. return dev_err_probe(dev, rc, "Failed to get operate mode\n");
  481. if (data == HUCF_MODE_PLATFORM)
  482. uncore->devfreq = devm_devfreq_add_device(dev, profile,
  483. hisi_platform_governor.name, NULL);
  484. else
  485. uncore->devfreq = devm_devfreq_add_device(dev, profile,
  486. DEVFREQ_GOV_PERFORMANCE, NULL);
  487. if (IS_ERR(uncore->devfreq))
  488. return dev_err_probe(dev, PTR_ERR(uncore->devfreq),
  489. "Failed to add devfreq device\n");
  490. return 0;
  491. }
  492. static int hisi_uncore_freq_probe(struct platform_device *pdev)
  493. {
  494. struct hisi_uncore_freq *uncore;
  495. struct device *dev = &pdev->dev;
  496. u32 cap;
  497. int rc;
  498. uncore = devm_kzalloc(dev, sizeof(*uncore), GFP_KERNEL);
  499. if (!uncore)
  500. return -ENOMEM;
  501. uncore->dev = dev;
  502. platform_set_drvdata(pdev, uncore);
  503. rc = hisi_uncore_init_pcc_chan(uncore);
  504. if (rc)
  505. return dev_err_probe(dev, rc, "Failed to init PCC channel\n");
  506. rc = hisi_uncore_init_opp(uncore);
  507. if (rc)
  508. return dev_err_probe(dev, rc, "Failed to init OPP\n");
  509. rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_GET_CAP, &cap);
  510. if (rc)
  511. return dev_err_probe(dev, rc, "Failed to get capability\n");
  512. uncore->cap = cap;
  513. rc = hisi_uncore_add_platform_gov(uncore);
  514. if (rc)
  515. return dev_err_probe(dev, rc, "Failed to add hisi_platform governor\n");
  516. rc = hisi_uncore_mark_related_cpus_wrap(uncore);
  517. if (rc)
  518. return dev_err_probe(dev, rc, "Failed to mark related cpus\n");
  519. rc = hisi_uncore_devfreq_register(uncore);
  520. if (rc)
  521. return dev_err_probe(dev, rc, "Failed to register devfreq\n");
  522. return 0;
  523. }
  524. static const struct acpi_device_id hisi_uncore_freq_acpi_match[] = {
  525. { "HISI04F1", },
  526. { }
  527. };
  528. MODULE_DEVICE_TABLE(acpi, hisi_uncore_freq_acpi_match);
  529. static struct platform_driver hisi_uncore_freq_drv = {
  530. .probe = hisi_uncore_freq_probe,
  531. .driver = {
  532. .name = "hisi_uncore_freq",
  533. .acpi_match_table = hisi_uncore_freq_acpi_match,
  534. },
  535. };
  536. module_platform_driver(hisi_uncore_freq_drv);
  537. MODULE_DESCRIPTION("HiSilicon uncore frequency scaling driver");
  538. MODULE_AUTHOR("Jie Zhan <zhanjie9@hisilicon.com>");
  539. MODULE_LICENSE("GPL");