crm.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME
  6. #include <linux/delay.h>
  7. #include <linux/interrupt.h>
  8. #include <linux/io.h>
  9. #include <linux/iopoll.h>
  10. #include <linux/ipc_logging.h>
  11. #include <linux/kernel.h>
  12. #include <linux/list.h>
  13. #include <linux/module.h>
  14. #include <linux/of.h>
  15. #include <linux/of_device.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/slab.h>
  18. #include <linux/string.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/vmalloc.h>
  21. #include <linux/wait.h>
  22. #include <soc/qcom/crm.h>
  23. #define CREATE_TRACE_POINTS
  24. #include "trace-crm.h"
  25. #define CRM_DRV_IPC_LOG_SIZE 2
  26. #define MAX_NAME_LENGTH 20
  27. #define PERF_OL_VCD 0
  28. #define BW_VOTE_VCD 1
  29. #define MAX_VCD_TYPE 2
  30. #define VPAGE_SHIFT_BITS 0xFFF
  31. /* Common CRM Registers */
  32. #define CRM_VERSION 0
  33. /* Offsets for CRM_VERSION Register */
  34. #define MAJOR_VER_MASK 0xFF
  35. #define MAJOR_VER_SHIFT 16
  36. #define MINOR_VER_MASK 0xFF
  37. #define MINOR_VER_SHIFT 8
  38. #define CRM_CFG_PARAM_1 0x4
  39. /* Offsets for CRM_CFG_PARAM_1 Register */
  40. #define NUM_SW_DRVS_MASK 0xF
  41. #define NUM_SW_DRVS_SHIFT 20
  42. #define NUM_HW_DRVS_MASK 0xF
  43. #define NUM_HW_DRVS_SHIFT 16
  44. #define NUM_VCD_VOTED_BY_BW_MASK 0xF
  45. #define NUM_VCD_VOTED_BY_BW_SHIFT 24
  46. #define NUM_OF_RAILS_MASK 0xF
  47. #define NUM_OF_RAILS_SHIFT 12
  48. #define NUM_VCD_VOTED_BY_PERF_OL_MASK 0xF
  49. #define NUM_VCD_VOTED_BY_PERF_OL_SHIFT 8
  50. #define NUM_CH_MASK 0xF
  51. #define NUM_CH_SHIFT 4
  52. #define NUM_PWR_STATES_PER_CH_MASK 0xF
  53. #define NUM_PWR_STATES_PER_CH_SHIFT 0
  54. #define CRM_CFG_PARAM_2 0x8
  55. /* Offsets for CRM_CFG_PARAM_2 Register */
  56. #define NUM_OF_NODES_MASK 0x1F
  57. #define NUM_OF_NODES_SHIFT 26
  58. #define CRM_ENABLE 0xC
  59. /* Applicable for HW & SW DRVs BW Registers */
  60. #define PERF_OL_VALUE_BITS 0x7
  61. /* Applicable for HW & SW DRVs BW Registers */
  62. #define BW_VOTE_VALID BIT(29)
  63. /* Applicable only for SW DRVs BW Registers */
  64. #define BW_VOTE_COMMIT BIT(30)
  65. /* Applicable only for SW DRVs BW Registers */
  66. #define BW_VOTE_RESP_REQ BIT(31)
  67. /* Set 1 to Enable IRQ for each VCD */
  68. #define IRQ_ENABLE_BIT BIT(0)
  69. #define IRQ_CLEAR_BIT BIT(0)
  70. /* Set 1 to Enable CHN_BEHAVE for each HW DRV */
  71. #define CHN_BEHAVE_BIT BIT(0)
  72. /* SW DRV has ACTIVE, SLEEP and WAKE PWR STATES */
  73. #define MAX_SW_DRV_PWR_STATES 3
  74. /* Time out for ACTIVE Only PWR STATE completion IRQ */
  75. #define CRM_TIMEOUT_MS 5000
  76. #define CH0 0
  77. #define CH0_CHN_BUSY BIT(0)
  78. #define CH1 1
  79. #define CH1_CHN_BUSY BIT(1)
  80. #define crm_print_reg(addr, val)\
  81. pr_err("addr:0x%x, val:0x%x\n", addr, val)
  82. #define crm_print_hw_reg(drv_num, channel, res_type, res_num, pwr_st, addr, val)\
  83. pr_err("drv:%d, chn:%d, %s:%d, pwr_st:%d, addr:0x%x, val:0x%x\n",\
  84. drv_num, channel, res_type == PERF_OL_VCD ?\
  85. "vcd" : "node", res_num, pwr_st, addr, val)
  86. enum {
  87. /* CRM DRV Register */
  88. DRV_BASE,
  89. DRV_DISTANCE,
  90. /* VCD or ND Distance */
  91. DRV_RESOURCE_DISTANCE,
  92. /* DRV's PWR_ST Registers */
  93. PWR_ST0,
  94. PWR_ST1,
  95. PWR_ST2,
  96. PWR_ST3,
  97. PWR_ST4,
  98. /* Offset for power state distances in a channel */
  99. PWR_ST_CHN_DISTANCE,
  100. /* VCD's IRQ Registers, one per VCD at VCD_DISTANCE */
  101. IRQ_STATUS,
  102. IRQ_CLEAR,
  103. IRQ_ENABLE,
  104. /* DRV's Channel Registers, one per DRV at CH_DRV_DISTANCE */
  105. CHN_BUSY,
  106. CHN_UPDATE,
  107. CHN_BEHAVE,
  108. CHN_DRV_DISTANCE,
  109. /* SW DRV's PWR_ST mapped to PWR_ST0/1/2 for ACTIVE/SLEEP/WAKE */
  110. ACTIVE_VOTE = PWR_ST0,
  111. SLEEP_VOTE = PWR_ST1,
  112. WAKE_VOTE = PWR_ST2,
  113. /* Status Registers */
  114. PERF_OL_STATUS = IRQ_STATUS,
  115. PWR_IDX_STATUS = IRQ_CLEAR,
  116. };
  117. enum channel_type {
  118. CHN_IN_USE,
  119. CHN_FREE,
  120. };
  121. enum {
  122. /* CRM Register */
  123. CRM_BASE,
  124. CRM_DISTANCE,
  125. /* CRMV Registers */
  126. AGGR_VOL_STS,
  127. SEQ_VOL_STS,
  128. CURR_VOL_STS,
  129. RAIL_FSM_STS,
  130. RAIL_TCS_STS,
  131. /* CRMB Registers */
  132. STATUS_BE,
  133. STATUS_FE,
  134. /* CRMC Registers */
  135. AGGR_PERF_OL,
  136. CURR_PERF_OL,
  137. SEQ_STATUS,
  138. };
  139. static u32 chn_regs[] = {
  140. [CHN_BUSY] = 0x1000,
  141. [CHN_UPDATE] = 0x1020,
  142. [CHN_BEHAVE] = 0x1040,
  143. [CHN_DRV_DISTANCE] = 0x4,
  144. };
  145. static u32 crmv_regs[] = {
  146. [CRM_BASE] = 0x0,
  147. [CRM_DISTANCE] = 0x80,
  148. [AGGR_VOL_STS] = 0x0,
  149. [SEQ_VOL_STS] = 0x4,
  150. [CURR_VOL_STS] = 0x8,
  151. [RAIL_FSM_STS] = 0x14,
  152. [RAIL_TCS_STS] = 0x38,
  153. };
  154. static u32 crmb_regs[] = {
  155. [CRM_BASE] = 0x0,
  156. [CRM_DISTANCE] = 0x400,
  157. [STATUS_BE] = 0x120,
  158. [STATUS_FE] = 0x124,
  159. };
  160. static u32 crmc_regs[] = {
  161. [CRM_BASE] = 0x0,
  162. [CRM_DISTANCE] = 0x200,
  163. [AGGR_PERF_OL] = 0x4,
  164. [CURR_PERF_OL] = 0xc,
  165. [SEQ_STATUS] = 0x1a0,
  166. };
  167. static u32 hw_drv_perf_ol_vcd_regs[] = {
  168. [DRV_BASE] = 0x200,
  169. [DRV_DISTANCE] = 0x200,
  170. [DRV_RESOURCE_DISTANCE] = 0x4,
  171. [PWR_ST0] = 0x0,
  172. [PWR_ST1] = 0x40,
  173. [PWR_ST2] = 0x80,
  174. [PWR_ST3] = 0x600,
  175. [PWR_ST4] = 0x640,
  176. [PWR_ST_CHN_DISTANCE] = 0x4,
  177. [PERF_OL_STATUS] = 0x1C0,
  178. };
  179. static u32 hw_drv_bw_vote_vcd_regs[] = {
  180. [DRV_BASE] = 0x200,
  181. [DRV_DISTANCE] = 0x200,
  182. [DRV_RESOURCE_DISTANCE] = 0x4,
  183. [PWR_ST0] = 0xC0,
  184. [PWR_ST1] = 0x140,
  185. [PWR_ST2] = 0x680,
  186. [PWR_ST3] = 0x700,
  187. [PWR_ST4] = 0x780,
  188. [PWR_ST_CHN_DISTANCE] = 0x4,
  189. [PWR_IDX_STATUS] = 0x1F0,
  190. };
  191. static u32 sw_drv_perf_ol_vcd_regs[] = {
  192. [DRV_BASE] = 0x1060,
  193. [DRV_DISTANCE] = 0x1000,
  194. [DRV_RESOURCE_DISTANCE] = 0x4,
  195. [PWR_ST0] = 0x0,
  196. [PWR_ST1] = 0x40,
  197. [PWR_ST2] = 0x80,
  198. [PWR_ST_CHN_DISTANCE] = 0x0,
  199. [IRQ_STATUS] = 0x100,
  200. [IRQ_CLEAR] = 0x140,
  201. [IRQ_ENABLE] = 0x180,
  202. };
  203. static u32 sw_drv_bw_vote_vcd_regs[] = {
  204. [DRV_BASE] = 0x1060,
  205. [DRV_DISTANCE] = 0x1000,
  206. [DRV_RESOURCE_DISTANCE] = 0x4,
  207. [PWR_ST0] = 0x3A0,
  208. [PWR_ST1] = 0x3E0,
  209. [PWR_ST2] = 0x420,
  210. [PWR_ST_CHN_DISTANCE] = 0x0,
  211. [IRQ_STATUS] = 0x4A0,
  212. [IRQ_CLEAR] = 0x4E0,
  213. [IRQ_ENABLE] = 0x520,
  214. };
  215. struct crm_desc {
  216. bool set_chn_behave;
  217. };
  218. /**
  219. * struct crm_sw_votes: SW DRV's ACTIVE_VOTEs in progress.
  220. * One per VCD.
  221. *
  222. * @cmd: The ACTIVE_VOTE being sent to CRM.
  223. * @compl: Wait for completion if the cmd->wait is set.
  224. * Applicable only for ACTIVE_VOTEs.
  225. * @in_progress: Indicates if the cmd is in flight.
  226. * @wait: Wait queue used to wait for @in_progress to be false.
  227. * This is needed because HW do not keep a record of new
  228. * requests issued until current one is completed.
  229. */
  230. struct crm_sw_votes {
  231. struct crm_cmd cmd;
  232. struct completion compl;
  233. bool in_progress;
  234. wait_queue_head_t wait;
  235. };
  236. /**
  237. * struct crm_vcd: The Virtual Clock Domain's (VCDs) of the CRM.
  238. * One per VCD type.
  239. *
  240. * @cache: Cache of vcd's power_state to data
  241. * @num_pwr_states: Number of pwr state that DRV VCD can vote for.
  242. * @num_resources: Number of VCD resources (for PERF_OL votes) OR
  243. * Number of Node resoureces (for BW votes)
  244. * @cache_dirty: Flag to indicate if all the votes are applied.
  245. * @offsets: Register offsets for DRV controller.
  246. * @sw_votes: Cache of SW DRV's ACTIVE_VOTEs.
  247. */
  248. struct crm_vcd {
  249. u32 **cache;
  250. u32 num_pwr_states;
  251. u32 num_resources;
  252. u32 *offsets;
  253. bool cache_dirty;
  254. struct crm_sw_votes *sw_votes;
  255. };
  256. /**
  257. * struct crm_drv: The Direct Resource Voter (DRV) of the
  258. * CESTA Resource manager (CRM).
  259. *
  260. * @name: Controller identifier.
  261. * @base: Base address of the CRM device.
  262. * @drv_id: DRV (Direct Resource Voter) number.
  263. * @num_channels: Number of Channels, Applicable only for HW DRV
  264. * @vcd: VCDs in this DRV.
  265. * @irq: IRQ at gic.
  266. * @initialized: Whether DRV is initialized
  267. * @lock: Synchronize state of the controller. If CRM's cache's
  268. * lock will also be held, the order is: drv->cache_lock
  269. * then drv->lock.
  270. * @cache_lock: Synchronize VCD cache updates
  271. * @client: Handle to the DRV's client.
  272. * @ipc_log_ctx: IPC logger handle
  273. */
  274. struct crm_drv {
  275. enum crm_drv_type drv_type;
  276. char name[MAX_NAME_LENGTH];
  277. void __iomem *base;
  278. u32 drv_id;
  279. u32 num_channels;
  280. u32 *offsets;
  281. struct crm_vcd vcd[MAX_VCD_TYPE];
  282. spinlock_t lock;
  283. spinlock_t cache_lock;
  284. int irq;
  285. bool initialized;
  286. void *ipc_log_ctx;
  287. };
  288. /**
  289. * struct crm_mgr: The CRM HW block used for aggregating votes
  290. * from SW and HW DRVs.
  291. *
  292. * @name: CRM HW block name.
  293. * @base: Base address of the CRM block.
  294. * @num_resources: Number of PERF_OL or BW_VOTE resources.
  295. * @offsets: Register offsets for CRM manager.
  296. */
  297. struct crm_mgr {
  298. char name[MAX_NAME_LENGTH];
  299. void __iomem *base;
  300. u32 num_resources;
  301. u32 *offsets;
  302. };
  303. /**
  304. * struct crm_drv_top: Our representation of the top CRM device.
  305. *
  306. * @name: CRM device name.
  307. * @base: Base address of the CRM device.
  308. * @hw_drvs: Controller for each HW DRV
  309. * @num_hw_drvs: Number of HW DRV controllers in the CRM device
  310. * @num_channels: Number of Channels, Applicable only for HW DRV
  311. * @sw_drvs: Controller for each SW DRV
  312. * @num_sw_drvs: Number of SW DRV controllers in the CRM device
  313. * @crmv_mgr: Controller for CRMV device.
  314. * @crmb_mgr: Controller for CRMB device.
  315. * @crmc_mgr: Controller for CRMC device.
  316. * @list: CRM device added in crm_dev_list.
  317. * @desc: CRM description
  318. * @dev: CRM dev
  319. * @pdev: CRM platform device
  320. */
  321. struct crm_drv_top {
  322. char name[MAX_NAME_LENGTH];
  323. void __iomem *base;
  324. struct crm_drv *hw_drvs;
  325. int num_hw_drvs;
  326. u32 num_channels;
  327. struct crm_drv *sw_drvs;
  328. int num_sw_drvs;
  329. struct crm_mgr crmv_mgr;
  330. struct crm_mgr crmb_mgr;
  331. struct crm_mgr crmc_mgr;
  332. struct list_head list;
  333. const struct crm_desc *desc;
  334. struct device *dev;
  335. struct platform_device *pdev;
  336. };
  337. static LIST_HEAD(crm_dev_list);
  338. static inline u32 get_crm_phy_addr(void __iomem *base)
  339. {
  340. return page_to_phys(vmalloc_to_page(base));
  341. }
  342. static inline u32 crm_get_channel_offset(const struct crm_drv *drv, u32 reg)
  343. {
  344. return drv->offsets[reg] + drv->drv_id * drv->offsets[CHN_DRV_DISTANCE];
  345. }
  346. static void write_crm_channel(const struct crm_drv *drv, u32 reg, u32 data)
  347. {
  348. u32 offset = crm_get_channel_offset(drv, reg);
  349. writel_relaxed(data, drv->base + offset);
  350. }
  351. static u32 read_crm_channel(const struct crm_drv *drv, u32 reg)
  352. {
  353. u32 offset = crm_get_channel_offset(drv, reg);
  354. return readl_relaxed(drv->base + offset);
  355. }
  356. static inline u32 crm_get_offset(const struct crm_drv *drv, u32 reg, u32 ch, u32 vcd_type,
  357. u32 resource_idx)
  358. {
  359. const struct crm_vcd *vcd = &drv->vcd[vcd_type];
  360. u32 offset;
  361. offset = vcd->offsets[DRV_BASE] + drv->drv_id * vcd->offsets[DRV_DISTANCE];
  362. offset += vcd->offsets[reg];
  363. offset += ch * vcd->num_resources * vcd->offsets[PWR_ST_CHN_DISTANCE];
  364. offset += resource_idx * vcd->offsets[DRV_RESOURCE_DISTANCE];
  365. return offset;
  366. }
  367. static void write_crm_reg(const struct crm_drv *drv, u32 reg, u32 ch, u32 vcd_type,
  368. u32 resource_idx, u32 data)
  369. {
  370. u32 offset = crm_get_offset(drv, reg, ch, vcd_type, resource_idx);
  371. writel_relaxed(data, drv->base + offset);
  372. }
  373. static u32 read_crm_reg(const struct crm_drv *drv, u32 reg, u32 ch, u32 vcd_type,
  374. u32 resource_idx)
  375. {
  376. u32 offset = crm_get_offset(drv, reg, ch, vcd_type, resource_idx);
  377. return readl_relaxed(drv->base + offset);
  378. }
  379. static inline u32 crm_mgr_get_offset(const struct crm_mgr *mgr, u32 reg, u32 resource_idx)
  380. {
  381. u32 offset;
  382. offset = mgr->offsets[CRM_BASE] + resource_idx * mgr->offsets[CRM_DISTANCE];
  383. offset += mgr->offsets[reg];
  384. return offset;
  385. }
  386. static u32 read_crm_mgr_reg(const struct crm_mgr *mgr, u32 reg, u32 resource_idx)
  387. {
  388. u32 offset = crm_mgr_get_offset(mgr, reg, resource_idx);
  389. return readl_relaxed(mgr->base + offset);
  390. }
  391. static struct crm_drv *get_crm_drv(const struct device *dev, enum crm_drv_type drv_type,
  392. u32 drv_id)
  393. {
  394. struct crm_drv_top *crm;
  395. if (!dev)
  396. return NULL;
  397. crm = dev_get_drvdata(dev);
  398. if (drv_type == CRM_HW_DRV && drv_id < crm->num_hw_drvs)
  399. return &crm->hw_drvs[drv_id];
  400. else if (drv_type == CRM_SW_DRV && drv_id < crm->num_sw_drvs)
  401. return &crm->sw_drvs[drv_id];
  402. return NULL;
  403. }
  404. /**
  405. * crm_get_channel() - Get the channel to Update the data
  406. * @drv: The CRM DRV controller.
  407. * @chn_type: The type of channel to find.
  408. *
  409. * Return:
  410. * * 0 - Success
  411. * * -Error - Error code
  412. */
  413. static int crm_get_channel(struct crm_drv *drv, enum channel_type ch_type, u32 *ch)
  414. {
  415. u32 chn_update;
  416. if (drv->num_channels == 0)
  417. return -EBUSY;
  418. /* Select Unused channel */
  419. chn_update = read_crm_channel(drv, CHN_UPDATE);
  420. if (!chn_update) {
  421. /* Start with ch0 if none are in use */
  422. *ch = CH0;
  423. return 0;
  424. }
  425. if (chn_update & CH0_CHN_BUSY)
  426. *ch = ch_type == CHN_FREE ? CH1 : CH0;
  427. else if (chn_update & CH1_CHN_BUSY)
  428. *ch = ch_type == CHN_FREE ? CH0 : CH1;
  429. else
  430. return -EBUSY;
  431. return 0;
  432. }
  433. int crm_channel_switch_complete(const struct crm_drv *drv, u32 ch)
  434. {
  435. u32 sts;
  436. int retry = 100, ret = 0;
  437. do {
  438. sts = read_crm_channel(drv, CHN_BUSY);
  439. if (ch == 0)
  440. sts &= CH0_CHN_BUSY;
  441. else
  442. sts &= CH1_CHN_BUSY;
  443. retry--;
  444. /*
  445. * Wait till all the votes are applied to new
  446. * channel during channel switch.
  447. * Maximum delay of 5 msec.
  448. */
  449. udelay(100);
  450. } while ((sts != BIT(ch)) && retry);
  451. if (!retry)
  452. ret = -EBUSY;
  453. trace_crm_switch_channel(drv->name, ch, ret);
  454. ipc_log_string(drv->ipc_log_ctx, "Switch Channel: ch: %u ret: %d", ch, ret);
  455. return ret;
  456. }
  457. /**
  458. * crm_switch_channel() - Switch to the channel
  459. * @drv: The controller DRV.
  460. * @ch: The channel number to switch to.
  461. *
  462. * NOTE: Caller should ensure serialization before making this call.
  463. * Return:
  464. * * 0 - Success
  465. * * -Error - Error code
  466. */
  467. int crm_switch_channel(const struct crm_drv *drv, u32 ch)
  468. {
  469. write_crm_channel(drv, CHN_UPDATE, BIT(ch));
  470. return crm_channel_switch_complete(drv, ch);
  471. }
  472. static u32 crm_get_pwr_state_reg(int pwr_state)
  473. {
  474. u32 reg;
  475. switch (pwr_state) {
  476. case 0:
  477. reg = PWR_ST0;
  478. break;
  479. case 1:
  480. reg = PWR_ST1;
  481. break;
  482. case 2:
  483. reg = PWR_ST2;
  484. break;
  485. case 3:
  486. reg = PWR_ST3;
  487. break;
  488. case 4:
  489. reg = PWR_ST4;
  490. break;
  491. default:
  492. WARN_ON(1);
  493. reg = PWR_ST0;
  494. }
  495. return reg;
  496. }
  497. static int _crm_dump_drv_regs(struct crm_drv *drv)
  498. {
  499. struct crm_vcd *vcd;
  500. u32 chn, reg;
  501. u32 phy_base, data, offset;
  502. int m, j, k;
  503. int ret = 0;
  504. phy_base = get_crm_phy_addr(drv->base);
  505. pr_err("HW DRV%d Regs\n", drv->drv_id);
  506. spin_lock(&drv->cache_lock);
  507. ret = crm_get_channel(drv, CHN_IN_USE, &chn);
  508. if (ret) {
  509. spin_unlock(&drv->cache_lock);
  510. return ret;
  511. }
  512. for (m = 0; m < MAX_VCD_TYPE; m++) {
  513. vcd = &drv->vcd[m];
  514. for (k = 0; k < vcd->num_resources; k++) {
  515. for (j = 0; j < vcd->num_pwr_states; j++) {
  516. reg = crm_get_pwr_state_reg(j);
  517. offset = crm_get_offset(drv, reg, chn, m, k);
  518. data = readl_relaxed(drv->base + offset);
  519. crm_print_hw_reg(drv->drv_id, chn, m, k,
  520. reg-PWR_ST0, phy_base + offset, data);
  521. }
  522. }
  523. }
  524. vcd = &drv->vcd[PERF_OL_VCD];
  525. pr_err("DRV%d HW PERF_OL Status\n", drv->drv_id);
  526. for (k = 0; k < vcd->num_resources; k++) {
  527. offset = crm_get_offset(drv, PERF_OL_STATUS, 0, PERF_OL_VCD, k);
  528. data = readl_relaxed(drv->base + offset);
  529. crm_print_reg(phy_base + offset, data);
  530. }
  531. pr_err("DRV%d HW BW Status\n", drv->drv_id);
  532. offset = crm_get_offset(drv, PWR_IDX_STATUS, 0, BW_VOTE_VCD, 0);
  533. data = readl_relaxed(drv->base + offset);
  534. crm_print_reg(phy_base + offset, data);
  535. offset = crm_get_channel_offset(drv, CHN_BUSY);
  536. data = readl_relaxed(drv->base + offset);
  537. crm_print_reg(phy_base + offset, data);
  538. spin_unlock(&drv->cache_lock);
  539. return ret;
  540. }
  541. static int _crm_dump_regs(const struct device *dev)
  542. {
  543. struct crm_drv_top *crm;
  544. u32 phy_base, data, offset;
  545. int i;
  546. crm = dev_get_drvdata(dev);
  547. pr_err("CRMB Regs\n");
  548. phy_base = get_crm_phy_addr(crm->crmb_mgr.base) +
  549. ((unsigned long) crm->crmb_mgr.base & VPAGE_SHIFT_BITS);
  550. for (i = 0; i < crm->crmb_mgr.num_resources; i++) {
  551. offset = crm_mgr_get_offset(&crm->crmb_mgr, STATUS_BE, i);
  552. data = readl_relaxed(crm->crmb_mgr.base + offset);
  553. crm_print_reg(phy_base + offset, data);
  554. offset = crm_mgr_get_offset(&crm->crmb_mgr, STATUS_FE, i);
  555. data = readl_relaxed(crm->crmb_mgr.base + offset);
  556. crm_print_reg(phy_base + offset, data);
  557. }
  558. pr_err("CRMC Regs\n");
  559. phy_base = get_crm_phy_addr(crm->crmc_mgr.base) +
  560. ((unsigned long) crm->crmc_mgr.base & VPAGE_SHIFT_BITS);
  561. for (i = 0; i < crm->crmc_mgr.num_resources; i++) {
  562. offset = crm_mgr_get_offset(&crm->crmc_mgr, AGGR_PERF_OL, i);
  563. data = readl_relaxed(crm->crmc_mgr.base + offset);
  564. crm_print_reg(phy_base + offset, data);
  565. }
  566. for (i = 0; i < (crm->crmc_mgr.num_resources + crm->crmb_mgr.num_resources); i++) {
  567. offset = crm_mgr_get_offset(&crm->crmc_mgr, CURR_PERF_OL, i);
  568. data = readl_relaxed(crm->crmc_mgr.base + offset);
  569. crm_print_reg(phy_base + offset, data);
  570. offset = crm_mgr_get_offset(&crm->crmc_mgr, SEQ_STATUS, i);
  571. data = readl_relaxed(crm->crmc_mgr.base + offset);
  572. crm_print_reg(phy_base + offset, data);
  573. }
  574. pr_err("CRMV Regs\n");
  575. phy_base = get_crm_phy_addr(crm->crmv_mgr.base) +
  576. ((unsigned long) crm->crmv_mgr.base & VPAGE_SHIFT_BITS);
  577. for (i = 0; i < crm->crmv_mgr.num_resources; i++) {
  578. offset = crm_mgr_get_offset(&crm->crmv_mgr, AGGR_VOL_STS, i);
  579. data = readl_relaxed(crm->crmv_mgr.base + offset);
  580. crm_print_reg(phy_base + offset, data);
  581. offset = crm_mgr_get_offset(&crm->crmv_mgr, SEQ_VOL_STS, i);
  582. data = readl_relaxed(crm->crmv_mgr.base + offset);
  583. crm_print_reg(phy_base + offset, data);
  584. offset = crm_mgr_get_offset(&crm->crmv_mgr, CURR_VOL_STS, i);
  585. data = readl_relaxed(crm->crmv_mgr.base + offset);
  586. crm_print_reg(phy_base + offset, data);
  587. offset = crm_mgr_get_offset(&crm->crmv_mgr, RAIL_FSM_STS, i);
  588. data = readl_relaxed(crm->crmv_mgr.base + offset);
  589. crm_print_reg(phy_base + offset, data);
  590. offset = crm_mgr_get_offset(&crm->crmv_mgr, RAIL_TCS_STS, i);
  591. data = readl_relaxed(crm->crmv_mgr.base + offset);
  592. crm_print_reg(phy_base + offset, data);
  593. }
  594. return 0;
  595. }
  596. static void crm_flush_cache(struct crm_drv *drv, struct crm_vcd *vcd, u32 ch, u32 vcd_type)
  597. {
  598. int i, j;
  599. u32 reg;
  600. for (i = 0; i < vcd->num_resources; i++) {
  601. for (j = 0; j < vcd->num_pwr_states; j++) {
  602. reg = crm_get_pwr_state_reg(j);
  603. write_crm_reg(drv, reg, ch, vcd_type, i, vcd->cache[i][j]);
  604. trace_crm_write_vcd_votes(drv->name, vcd_type, i, j, vcd->cache[i][j]);
  605. ipc_log_string(drv->ipc_log_ctx,
  606. "Flush: type: %u resource_idx:%u pwr_state: %u data: %#x",
  607. vcd_type, i, j, vcd->cache[i][j]);
  608. }
  609. }
  610. }
  611. /**
  612. * crm_write_pwr_states() - Flush the power state votes for HW DRVs.
  613. * @dev: The CRM device
  614. * @drv_id: HW DRV ID for which to flush the power state votes.
  615. *
  616. * Find the non-active channel, writes various power states that
  617. * were cached with crm_write_perf_ol() and crm_write_bw_vote()
  618. * APIs and does a channel switch.
  619. *
  620. * Applicable only for HW DRVs for which the votes are cached.
  621. * SW DRVs votes are immediately written.
  622. *
  623. * Return:
  624. * * 0 - Success
  625. * * -Error - Error code
  626. */
  627. int crm_write_pwr_states(const struct device *dev, u32 drv_id)
  628. {
  629. struct crm_drv *drv = get_crm_drv(dev, CRM_HW_DRV, drv_id);
  630. struct crm_vcd *vcd;
  631. u32 ch;
  632. int i;
  633. int ret;
  634. if (!drv || drv->drv_type == CRM_SW_DRV)
  635. return -EINVAL;
  636. spin_lock(&drv->cache_lock);
  637. ret = crm_get_channel(drv, CHN_FREE, &ch);
  638. if (ret)
  639. goto exit;
  640. for (i = 0; i < MAX_VCD_TYPE; i++) {
  641. vcd = &drv->vcd[i];
  642. crm_flush_cache(drv, vcd, ch, i);
  643. }
  644. ret = crm_switch_channel(drv, ch);
  645. if (ret)
  646. goto exit;
  647. exit:
  648. spin_unlock(&drv->cache_lock);
  649. /* Dump CRM registers for debug */
  650. if (ret) {
  651. _crm_dump_drv_regs(drv);
  652. _crm_dump_regs(dev);
  653. BUG_ON(1);
  654. }
  655. return ret;
  656. }
  657. EXPORT_SYMBOL_GPL(crm_write_pwr_states);
  658. /**
  659. * crm_dump_drv_regs() - Dump CRM DRV registers for debug purposes.
  660. * @name: The name of the crm device to dump for.
  661. * @drv_id: DRV ID for which to dump for.
  662. *
  663. * Return:
  664. * * 0 - Success
  665. * * -Error - Error code
  666. */
  667. int crm_dump_drv_regs(const char *name, u32 drv_id)
  668. {
  669. struct crm_drv_top *crm;
  670. struct crm_drv *drv;
  671. const struct device *dev;
  672. dev = crm_get_device(name);
  673. if (IS_ERR(dev))
  674. return -EINVAL;
  675. crm = dev_get_drvdata(dev);
  676. drv = get_crm_drv(dev, CRM_HW_DRV, drv_id);
  677. if (!drv)
  678. return -EINVAL;
  679. return _crm_dump_drv_regs(drv);
  680. }
  681. EXPORT_SYMBOL_GPL(crm_dump_drv_regs);
  682. /**
  683. * crm_dump_regs() - Dump CRM registers for debug purposes.
  684. * @name: The name of the crm device to dump for.
  685. *
  686. * Return:
  687. * * 0 - Success
  688. * * -Error - Error code
  689. */
  690. int crm_dump_regs(const char *name)
  691. {
  692. const struct device *dev;
  693. dev = crm_get_device(name);
  694. if (IS_ERR(dev))
  695. return -EINVAL;
  696. return _crm_dump_regs(dev);
  697. }
  698. EXPORT_SYMBOL_GPL(crm_dump_regs);
  699. /**
  700. * crm_dump_regs() - Dump CRM registers for debug purposes.
  701. * @name: The name of the crm device to dump for.
  702. * @vcd_idx: The VCD index to read from.
  703. * @data: Read CURR_PERF_OL register value into this.
  704. *
  705. * Return:
  706. * * 0 - Success
  707. * * -Error - Error code
  708. */
  709. int crm_read_curr_perf_ol(const char *name, int vcd_idx, u32 *data)
  710. {
  711. struct crm_drv_top *crm;
  712. const struct device *dev;
  713. dev = crm_get_device(name);
  714. if (IS_ERR(dev))
  715. return -EINVAL;
  716. crm = dev_get_drvdata(dev);
  717. if (vcd_idx >= crm->crmc_mgr.num_resources)
  718. return -EINVAL;
  719. *data = read_crm_mgr_reg(&crm->crmc_mgr, CURR_PERF_OL, vcd_idx);
  720. return 0;
  721. }
  722. EXPORT_SYMBOL_GPL(crm_read_curr_perf_ol);
  723. static void crm_vote_completion(struct crm_sw_votes *votes)
  724. {
  725. struct completion *compl = &votes->compl;
  726. votes->in_progress = false;
  727. complete(compl);
  728. }
  729. /**
  730. * crm_vote_complete_irq() - Vote completion interrupt handler for SW DRVs.
  731. * @irq: The IRQ number (ignored).
  732. * @p: Pointer to "struct crm_drv".
  733. *
  734. * Called for ACTIVE_VOTE transfers (those are the only ones we enable the
  735. * IRQ for) when a transfer is done.
  736. *
  737. * Return: IRQ_HANDLED
  738. */
  739. static irqreturn_t crm_vote_complete_irq(int irq, void *p)
  740. {
  741. struct crm_drv_top *crm = p;
  742. struct crm_drv *drv;
  743. struct crm_vcd *vcd;
  744. struct crm_sw_votes *votes;
  745. unsigned long irq_status;
  746. int i, j, k;
  747. for (i = 0; i < crm->num_sw_drvs; i++) {
  748. drv = &crm->sw_drvs[i];
  749. if (!drv->initialized)
  750. continue;
  751. spin_lock(&drv->lock);
  752. for (j = 0; j < MAX_VCD_TYPE; j++) {
  753. vcd = &drv->vcd[j];
  754. for (k = 0; k < vcd->num_resources; k++) {
  755. irq_status = read_crm_reg(drv, IRQ_STATUS, 0, j, k);
  756. if (!irq_status)
  757. continue;
  758. write_crm_reg(drv, IRQ_CLEAR, 0, j, k, IRQ_CLEAR_BIT);
  759. trace_crm_irq(drv->name, j, k, irq_status);
  760. ipc_log_string(drv->ipc_log_ctx,
  761. "IRQ: type: %u resource_idx:%u irq_status: %lu"
  762. , j, k, irq_status);
  763. votes = &vcd->sw_votes[k];
  764. if (!votes->in_progress) {
  765. WARN_ON(1);
  766. continue;
  767. }
  768. if (votes->cmd.wait)
  769. crm_vote_completion(votes);
  770. }
  771. }
  772. spin_unlock(&drv->lock);
  773. }
  774. return IRQ_HANDLED;
  775. }
  776. static void crm_fill_cmd(struct crm_cmd *dest, const struct crm_cmd *src)
  777. {
  778. dest->resource_idx = src->resource_idx;
  779. dest->pwr_state = src->pwr_state;
  780. dest->data = src->data;
  781. dest->wait = src->wait;
  782. }
  783. static u32 crm_get_pwr_state(struct crm_drv *drv, const struct crm_cmd *cmd)
  784. {
  785. enum crm_sw_drv_state sw;
  786. enum crm_hw_drv_state hw;
  787. u32 pwr_state;
  788. if (drv->drv_type == CRM_HW_DRV) {
  789. hw = cmd->pwr_state.hw;
  790. pwr_state = hw;
  791. } else {
  792. sw = cmd->pwr_state.sw;
  793. pwr_state = sw;
  794. }
  795. return pwr_state;
  796. }
  797. static int crm_send_cmd(struct crm_drv *drv, u32 vcd_type, const struct crm_cmd *cmd)
  798. {
  799. struct crm_vcd *vcd = &drv->vcd[vcd_type];
  800. u32 resource_idx = cmd->resource_idx;
  801. u32 pwr_state = crm_get_pwr_state(drv, cmd);
  802. u32 data = cmd->data;
  803. bool wait = cmd->wait;
  804. unsigned long flags;
  805. struct completion *compl = NULL;
  806. u32 time_left;
  807. spin_lock_irqsave(&drv->lock, flags);
  808. /* Set COMMIT to start aggregating votes */
  809. if (vcd_type == BW_VOTE_VCD) {
  810. data |= BW_VOTE_COMMIT;
  811. if (wait)
  812. data |= BW_VOTE_RESP_REQ;
  813. }
  814. /* Note: Set BIT(31) for RESP_REQ and BIT(30) for COMMIT */
  815. switch (pwr_state) {
  816. case CRM_ACTIVE_STATE:
  817. /* Wait forever for a previous request to complete */
  818. wait_event_lock_irq(vcd->sw_votes[resource_idx].wait,
  819. !vcd->sw_votes[resource_idx].in_progress,
  820. drv->lock);
  821. compl = &vcd->sw_votes[resource_idx].compl;
  822. init_completion(compl);
  823. crm_fill_cmd(&vcd->sw_votes[resource_idx].cmd, cmd);
  824. vcd->sw_votes[resource_idx].in_progress = true;
  825. write_crm_reg(drv, PWR_ST0, 0, vcd_type, resource_idx, data);
  826. break;
  827. case CRM_SLEEP_STATE:
  828. write_crm_reg(drv, PWR_ST1, 0, vcd_type, resource_idx, data);
  829. break;
  830. case CRM_WAKE_STATE:
  831. write_crm_reg(drv, PWR_ST2, 0, vcd_type, resource_idx, data);
  832. break;
  833. default:
  834. WARN_ON(1);
  835. break;
  836. }
  837. spin_unlock_irqrestore(&drv->lock, flags);
  838. trace_crm_write_vcd_votes(drv->name, vcd_type, resource_idx, pwr_state, data);
  839. ipc_log_string(drv->ipc_log_ctx,
  840. "Write: type: %u resource_idx:%u pwr_state: %u data: %#x",
  841. vcd_type, resource_idx, pwr_state, data);
  842. if (compl && wait) {
  843. time_left = CRM_TIMEOUT_MS;
  844. time_left = wait_for_completion_timeout(compl, time_left);
  845. if (!time_left) {
  846. WARN_ON(1);
  847. return -ETIMEDOUT;
  848. }
  849. /* Unblock new requests for same VCD */
  850. wake_up(&vcd->sw_votes[resource_idx].wait);
  851. }
  852. return 0;
  853. }
  854. static void crm_cache_vcd_votes(struct crm_drv *drv, u32 vcd_type, const struct crm_cmd *cmd)
  855. {
  856. struct crm_vcd *vcd = &drv->vcd[vcd_type];
  857. u32 resource_idx = cmd->resource_idx;
  858. u32 pwr_state = crm_get_pwr_state(drv, cmd);
  859. u32 data = cmd->data;
  860. spin_lock(&drv->cache_lock);
  861. vcd->cache[resource_idx][pwr_state] = data;
  862. vcd->cache_dirty = true;
  863. spin_unlock(&drv->cache_lock);
  864. trace_crm_cache_vcd_votes(drv->name, vcd_type, resource_idx, pwr_state, data);
  865. ipc_log_string(drv->ipc_log_ctx,
  866. "Cache: type: %u resource_idx:%u pwr_state: %u data: %#x",
  867. vcd_type, resource_idx, pwr_state, data);
  868. }
  869. static bool crm_is_invalid_cmd(struct crm_drv *drv, u32 vcd_type, const struct crm_cmd *cmd)
  870. {
  871. struct crm_vcd *vcd;
  872. u32 resource_idx;
  873. u32 pwr_state;
  874. u32 data;
  875. bool ret;
  876. if (!drv || !cmd)
  877. return true;
  878. vcd = &drv->vcd[vcd_type];
  879. resource_idx = cmd->resource_idx;
  880. pwr_state = crm_get_pwr_state(drv, cmd);
  881. data = cmd->data;
  882. if (pwr_state >= vcd->num_pwr_states)
  883. ret = true;
  884. else if (resource_idx >= vcd->num_resources)
  885. ret = true;
  886. else if (vcd_type == BW_VOTE_VCD && !(data & BW_VOTE_VALID))
  887. ret = true;
  888. else if (vcd_type == PERF_OL_VCD && (data & ~PERF_OL_VALUE_BITS))
  889. ret = true;
  890. else
  891. ret = false;
  892. return ret;
  893. }
  894. /**
  895. * crm_write_perf_ol() - Write a perf ol vote for a resource
  896. * @dev: The CRM device
  897. * @drv_type: The CRM DRV type, either SW or HW DRV.
  898. * @drv_id: DRV ID for which the votes are sent
  899. * @cmd: The CRM CMD
  900. *
  901. * Caches the votes for HW DRV and immediately returns.
  902. * The votes are written to unused channel with a call to
  903. * crm_write_pwr_states().
  904. *
  905. * Caches the votes for logging and immediately sents the votes for SW DRVs
  906. * if the @cmd have .wait set and is for ACTIVE_VOTE then waits for completion
  907. * IRQ before return. for SLEEP_VOTE and WAKE_VOTE no completion IRQ is sent
  908. * and they are triggered within HW during idle/awake scenarios.
  909. *
  910. * Return:
  911. * * 0 - Success
  912. * * -Error - Error code
  913. */
  914. int crm_write_perf_ol(const struct device *dev, enum crm_drv_type drv_type,
  915. u32 drv_id, const struct crm_cmd *cmd)
  916. {
  917. struct crm_drv *drv = get_crm_drv(dev, drv_type, drv_id);
  918. int ret;
  919. ret = crm_is_invalid_cmd(drv, PERF_OL_VCD, cmd);
  920. if (ret)
  921. return -EINVAL;
  922. /* Cache the votes first */
  923. crm_cache_vcd_votes(drv, PERF_OL_VCD, cmd);
  924. /* Send SW DRV votes immediately for ACTIVE/SLEEP/WAKE states */
  925. if (drv_type == CRM_SW_DRV)
  926. return crm_send_cmd(drv, PERF_OL_VCD, cmd);
  927. return 0;
  928. }
  929. EXPORT_SYMBOL_GPL(crm_write_perf_ol);
  930. /**
  931. * crm_write_bw_vote() - Write a bw vote for a resource
  932. * @dev: The CRM device
  933. * @drv_type: The CRM DRV type, either SW or HW DRV.
  934. * @drv_id: DRV ID for which the votes are sent
  935. * @cmd: The CRM CMD
  936. *
  937. * Caches the votes for HW DRV and immediately returns.
  938. * The votes are written to unused channel with a call to
  939. * crm_write_pwr_states().
  940. *
  941. * Caches the votes for logging and immediately sents the votes for SW DRVs
  942. * if the @cmd have .wait set and is for ACTIVE_VOTE then waits for completion
  943. * IRQ before return. for SLEEP_VOTE and WAKE_VOTE no completion IRQ is sent
  944. * and they are triggered within HW during idle/awake scenarios.
  945. *
  946. * Return:
  947. * * 0 - Success
  948. * * -Error - Error code
  949. */
  950. int crm_write_bw_vote(const struct device *dev, enum crm_drv_type drv_type,
  951. u32 drv_id, const struct crm_cmd *cmd)
  952. {
  953. struct crm_drv *drv = get_crm_drv(dev, drv_type, drv_id);
  954. int ret;
  955. ret = crm_is_invalid_cmd(drv, BW_VOTE_VCD, cmd);
  956. if (ret)
  957. return -EINVAL;
  958. /* Cache the votes first */
  959. crm_cache_vcd_votes(drv, BW_VOTE_VCD, cmd);
  960. /* Send SW DRV votes immediately for ACTIVE/SLEEP/WAKE states */
  961. if (drv_type == CRM_SW_DRV)
  962. return crm_send_cmd(drv, BW_VOTE_VCD, cmd);
  963. return 0;
  964. }
  965. EXPORT_SYMBOL_GPL(crm_write_bw_vote);
  966. /**
  967. * crm_get_device() - Returns a CRM device handle.
  968. * @name: The CRM device name for which handle is needed.
  969. *
  970. * Finds the CRM device from list of available CRM devices.
  971. * The @name should match the label property in device which are "cam_crm"
  972. * or "pcie_crm".
  973. *
  974. * Return:
  975. * * Device pointer - Success
  976. * * -Error pointer - Error
  977. */
  978. const struct device *crm_get_device(const char *name)
  979. {
  980. struct crm_drv_top *crm;
  981. list_for_each_entry(crm, &crm_dev_list, list) {
  982. if (!strcmp(name, crm->name))
  983. return crm->dev;
  984. }
  985. return ERR_PTR(-ENODEV);
  986. }
  987. EXPORT_SYMBOL_GPL(crm_get_device);
  988. static void crm_set_chn_behave(struct crm_drv_top *crm)
  989. {
  990. int i;
  991. if (!crm->desc->set_chn_behave)
  992. return;
  993. for (i = 0; i < crm->num_hw_drvs; i++)
  994. write_crm_channel(&crm->hw_drvs[i], CHN_BEHAVE, CHN_BEHAVE_BIT);
  995. }
  996. static int crm_probe_get_irqs(struct crm_drv_top *crm)
  997. {
  998. struct crm_drv *drvs = crm->sw_drvs;
  999. struct crm_vcd *vcd;
  1000. int i, j, k;
  1001. int irq;
  1002. int ret;
  1003. if (!crm->num_sw_drvs)
  1004. return 0;
  1005. irq = platform_get_irq_byname(crm->pdev, crm->name);
  1006. if (irq < 0)
  1007. return irq;
  1008. ret = devm_request_irq(crm->dev, irq, crm_vote_complete_irq,
  1009. IRQF_TRIGGER_RISING, crm->name, crm);
  1010. if (ret)
  1011. return ret;
  1012. /* Only SW DRVs have associated vote completion IRQ */
  1013. for (i = 0; i < crm->num_sw_drvs; i++) {
  1014. if (!crm->sw_drvs[i].initialized)
  1015. continue;
  1016. drvs[i].irq = irq;
  1017. /* SW DRV do not have any channels */
  1018. drvs[i].num_channels = 0;
  1019. /* Additionally allocate memory for sw_votes */
  1020. for (j = 0; j < MAX_VCD_TYPE; j++) {
  1021. vcd = &drvs[i].vcd[j];
  1022. vcd->sw_votes = devm_kcalloc(crm->dev, vcd->num_resources,
  1023. sizeof(struct crm_sw_votes),
  1024. GFP_KERNEL);
  1025. if (!vcd->sw_votes)
  1026. return -ENOMEM;
  1027. /* Enable IRQs for all VCDs */
  1028. for (k = 0; k < vcd->num_resources; k++) {
  1029. init_waitqueue_head(&vcd->sw_votes[k].wait);
  1030. write_crm_reg(&drvs[i], IRQ_ENABLE, 0, j, k, IRQ_ENABLE_BIT);
  1031. }
  1032. }
  1033. }
  1034. return 0;
  1035. }
  1036. static int crm_probe_alloc_vcd_caches(struct crm_drv_top *crm, struct crm_vcd *vcd)
  1037. {
  1038. u32 num_resources = vcd->num_resources;
  1039. u32 num_pwr_states = vcd->num_pwr_states;
  1040. int i;
  1041. vcd->cache = devm_kcalloc(crm->dev, num_resources, sizeof(u32 *), GFP_KERNEL);
  1042. if (!vcd->cache)
  1043. return -ENOMEM;
  1044. for (i = 0; i < num_resources; i++) {
  1045. vcd->cache[i] = devm_kcalloc(crm->dev, num_pwr_states, sizeof(u32), GFP_KERNEL);
  1046. if (!vcd->cache[i])
  1047. return -ENOMEM;
  1048. }
  1049. return 0;
  1050. }
  1051. static int crm_probe_set_vcd_caches(struct crm_drv_top *crm, u32 crm_cfg, u32 crm_cfg_2)
  1052. {
  1053. struct crm_vcd *vcd;
  1054. struct crm_drv *drv;
  1055. u32 num_perf_ol_vcds, num_nds, num_pwr_states;
  1056. u32 num_bw_vote_vcds, num_rails;
  1057. int i, j, ret;
  1058. num_rails = crm_cfg & (NUM_OF_RAILS_MASK << NUM_OF_RAILS_SHIFT);
  1059. num_rails >>= NUM_OF_RAILS_SHIFT;
  1060. num_perf_ol_vcds = crm_cfg & (NUM_VCD_VOTED_BY_PERF_OL_MASK <<
  1061. NUM_VCD_VOTED_BY_PERF_OL_SHIFT);
  1062. num_perf_ol_vcds >>= NUM_VCD_VOTED_BY_PERF_OL_SHIFT;
  1063. num_bw_vote_vcds = crm_cfg & (NUM_VCD_VOTED_BY_BW_MASK <<
  1064. NUM_VCD_VOTED_BY_BW_SHIFT);
  1065. num_bw_vote_vcds >>= NUM_VCD_VOTED_BY_BW_SHIFT;
  1066. num_pwr_states = crm_cfg & (NUM_PWR_STATES_PER_CH_MASK <<
  1067. NUM_PWR_STATES_PER_CH_SHIFT);
  1068. num_pwr_states >>= NUM_PWR_STATES_PER_CH_SHIFT;
  1069. num_nds = crm_cfg_2 & (NUM_OF_NODES_MASK << NUM_OF_NODES_SHIFT);
  1070. num_nds >>= NUM_OF_NODES_SHIFT;
  1071. for (i = 0; i < crm->num_hw_drvs; i++) {
  1072. drv = &crm->hw_drvs[i];
  1073. if (!drv->initialized)
  1074. continue;
  1075. drv->drv_type = CRM_HW_DRV;
  1076. for (j = 0; j < MAX_VCD_TYPE; j++) {
  1077. vcd = &drv->vcd[j];
  1078. if (j == PERF_OL_VCD) {
  1079. vcd->offsets = hw_drv_perf_ol_vcd_regs;
  1080. vcd->num_resources = num_perf_ol_vcds;
  1081. } else if (j == BW_VOTE_VCD) {
  1082. vcd->offsets = hw_drv_bw_vote_vcd_regs;
  1083. /* BW_VOTE_VCD can have multiple NDs with which BW can be voted */
  1084. vcd->num_resources = num_nds;
  1085. } else {
  1086. continue;
  1087. }
  1088. vcd->num_pwr_states = num_pwr_states;
  1089. ret = crm_probe_alloc_vcd_caches(crm, vcd);
  1090. if (ret)
  1091. return ret;
  1092. }
  1093. }
  1094. for (i = 0; i < crm->num_sw_drvs; i++) {
  1095. drv = &crm->sw_drvs[i];
  1096. if (!drv->initialized)
  1097. continue;
  1098. drv->drv_type = CRM_SW_DRV;
  1099. for (j = 0; j < MAX_VCD_TYPE; j++) {
  1100. vcd = &drv->vcd[j];
  1101. if (j == PERF_OL_VCD) {
  1102. vcd->offsets = sw_drv_perf_ol_vcd_regs;
  1103. vcd->num_resources = num_perf_ol_vcds;
  1104. } else if (j == BW_VOTE_VCD) {
  1105. vcd->offsets = sw_drv_bw_vote_vcd_regs;
  1106. /* BW_VOTE_VCD can have multiple NDs with which BW can be voted */
  1107. vcd->num_resources = num_nds;
  1108. } else {
  1109. continue;
  1110. }
  1111. vcd->num_pwr_states = MAX_SW_DRV_PWR_STATES;
  1112. ret = crm_probe_alloc_vcd_caches(crm, vcd);
  1113. if (ret)
  1114. return ret;
  1115. }
  1116. }
  1117. crm->crmv_mgr.offsets = crmv_regs;
  1118. crm->crmv_mgr.num_resources = num_rails;
  1119. crm->crmb_mgr.offsets = crmb_regs;
  1120. crm->crmb_mgr.num_resources = num_bw_vote_vcds;
  1121. crm->crmc_mgr.offsets = crmc_regs;
  1122. crm->crmc_mgr.num_resources = num_perf_ol_vcds;
  1123. return 0;
  1124. }
  1125. static struct crm_drv *crm_probe_get_drvs(struct crm_drv_top *crm, int num_drvs,
  1126. const char *prop_name, const char *name)
  1127. {
  1128. struct device_node *dn = crm->dev->of_node;
  1129. u32 *drv_ids;
  1130. int i, id;
  1131. int ret;
  1132. struct crm_drv *drvs;
  1133. if (!num_drvs)
  1134. return ERR_PTR(-EINVAL);
  1135. drvs = devm_kcalloc(crm->dev, num_drvs, sizeof(struct crm_drv), GFP_KERNEL);
  1136. if (!drvs)
  1137. return ERR_PTR(-ENOMEM);
  1138. drv_ids = kcalloc(num_drvs, sizeof(u32), GFP_KERNEL);
  1139. if (!drv_ids)
  1140. return ERR_PTR(-ENOMEM);
  1141. ret = of_property_read_u32_array(dn, prop_name, drv_ids, num_drvs);
  1142. if (ret) {
  1143. kfree(drv_ids);
  1144. return ERR_PTR(ret);
  1145. }
  1146. for (i = 0; i < num_drvs; i++) {
  1147. id = drv_ids[i];
  1148. scnprintf(drvs[i].name, sizeof(drvs[i].name), "%s_%s_%d", crm->name, name, id);
  1149. drvs[i].drv_id = id;
  1150. drvs[i].base = crm->base;
  1151. spin_lock_init(&drvs[i].lock);
  1152. spin_lock_init(&drvs[i].cache_lock);
  1153. drvs[i].ipc_log_ctx = ipc_log_context_create(
  1154. CRM_DRV_IPC_LOG_SIZE,
  1155. drvs[i].name, 0);
  1156. drvs[i].offsets = chn_regs;
  1157. drvs[i].num_channels = crm->num_channels;
  1158. drvs[i].initialized = true;
  1159. }
  1160. kfree(drv_ids);
  1161. return drvs;
  1162. }
  1163. static int crm_probe_drvs(struct crm_drv_top *crm, struct device_node *dn)
  1164. {
  1165. u32 crm_ver, major_ver, minor_ver;
  1166. u32 crm_cfg, crm_cfg_2;
  1167. int num_hw_drvs, num_sw_drvs;
  1168. crm_ver = readl_relaxed(crm->base + CRM_VERSION);
  1169. major_ver = crm_ver & (MAJOR_VER_MASK << MAJOR_VER_SHIFT);
  1170. major_ver >>= MAJOR_VER_SHIFT;
  1171. minor_ver = crm_ver & (MINOR_VER_MASK << MINOR_VER_SHIFT);
  1172. minor_ver >>= MINOR_VER_SHIFT;
  1173. pr_debug("CRM %s running version = %u.%u\n", crm->name, major_ver, minor_ver);
  1174. crm_cfg = readl_relaxed(crm->base + CRM_CFG_PARAM_1);
  1175. num_hw_drvs = crm_cfg & (NUM_HW_DRVS_MASK << NUM_HW_DRVS_SHIFT);
  1176. num_hw_drvs >>= NUM_HW_DRVS_SHIFT;
  1177. num_sw_drvs = crm_cfg & (NUM_SW_DRVS_MASK << NUM_SW_DRVS_SHIFT);
  1178. num_sw_drvs >>= NUM_SW_DRVS_SHIFT;
  1179. crm->num_channels = crm_cfg & (NUM_CH_MASK << NUM_CH_SHIFT);
  1180. crm->num_channels >>= NUM_CH_SHIFT;
  1181. crm->num_hw_drvs = of_property_count_u32_elems(dn, "qcom,hw-drv-ids");
  1182. if (crm->num_hw_drvs < 0) {
  1183. crm->num_hw_drvs = 0;
  1184. goto skip_hw_drvs;
  1185. }
  1186. crm->hw_drvs = crm_probe_get_drvs(crm, crm->num_hw_drvs, "qcom,hw-drv-ids", "hw_drv");
  1187. if (IS_ERR(crm->hw_drvs))
  1188. return PTR_ERR(crm->hw_drvs);
  1189. skip_hw_drvs:
  1190. crm->num_sw_drvs = of_property_count_u32_elems(dn, "qcom,sw-drv-ids");
  1191. if (crm->num_sw_drvs < 0) {
  1192. crm->num_sw_drvs = 0;
  1193. goto skip_sw_drvs;
  1194. }
  1195. crm->sw_drvs = crm_probe_get_drvs(crm, crm->num_sw_drvs, "qcom,sw-drv-ids", "sw_drv");
  1196. if (IS_ERR(crm->sw_drvs))
  1197. return PTR_ERR(crm->sw_drvs);
  1198. skip_sw_drvs:
  1199. if (crm->num_sw_drvs > num_sw_drvs ||
  1200. crm->num_hw_drvs > num_hw_drvs ||
  1201. (!crm->num_sw_drvs && !crm->num_hw_drvs))
  1202. return -EINVAL;
  1203. crm_cfg_2 = readl_relaxed(crm->base + CRM_CFG_PARAM_2);
  1204. return crm_probe_set_vcd_caches(crm, crm_cfg, crm_cfg_2);
  1205. }
  1206. static int crm_probe_platform_resources(struct platform_device *pdev, struct crm_drv_top *crm)
  1207. {
  1208. struct resource *res;
  1209. crm->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
  1210. if (IS_ERR(crm->base))
  1211. return -ENOMEM;
  1212. crm->crmb_mgr.base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
  1213. if (IS_ERR(crm->crmb_mgr.base))
  1214. return -ENOMEM;
  1215. strscpy(crm->crmb_mgr.name, res->name, sizeof(crm->crmb_mgr.name));
  1216. crm->crmc_mgr.base = devm_platform_get_and_ioremap_resource(pdev, 2, &res);
  1217. if (IS_ERR(crm->crmc_mgr.base))
  1218. return -ENOMEM;
  1219. strscpy(crm->crmc_mgr.name, res->name, sizeof(crm->crmc_mgr.name));
  1220. crm->crmv_mgr.base = devm_platform_get_and_ioremap_resource(pdev, 3, &res);
  1221. if (IS_ERR(crm->crmv_mgr.base))
  1222. return -ENOMEM;
  1223. strscpy(crm->crmv_mgr.name, res->name, sizeof(crm->crmv_mgr.name));
  1224. return 0;
  1225. }
  1226. static int crm_probe(struct platform_device *pdev)
  1227. {
  1228. struct device_node *dn = pdev->dev.of_node;
  1229. struct crm_drv_top *crm;
  1230. const char *name;
  1231. u32 crm_en;
  1232. int ret;
  1233. crm = devm_kzalloc(&pdev->dev, sizeof(*crm), GFP_KERNEL);
  1234. if (!crm)
  1235. return -ENOMEM;
  1236. crm->desc = of_device_get_match_data(&pdev->dev);
  1237. if (!crm->desc)
  1238. return -EINVAL;
  1239. name = of_get_property(dn, "label", NULL);
  1240. if (!name)
  1241. name = dev_name(&pdev->dev);
  1242. crm->pdev = pdev;
  1243. crm->dev = &pdev->dev;
  1244. scnprintf(crm->name, sizeof(crm->name), "%s", name);
  1245. ret = crm_probe_platform_resources(pdev, crm);
  1246. if (ret)
  1247. return ret;
  1248. crm_en = readl_relaxed(crm->base + CRM_ENABLE);
  1249. if (!crm_en)
  1250. return -EINVAL;
  1251. ret = crm_probe_drvs(crm, dn);
  1252. if (ret)
  1253. return ret;
  1254. ret = crm_probe_get_irqs(crm);
  1255. if (ret)
  1256. return ret;
  1257. crm_set_chn_behave(crm);
  1258. INIT_LIST_HEAD(&crm->list);
  1259. list_add_tail(&crm->list, &crm_dev_list);
  1260. dev_set_drvdata(&pdev->dev, crm);
  1261. return ret;
  1262. }
  1263. struct crm_desc cam_crm_desc = {
  1264. .set_chn_behave = true,
  1265. };
  1266. struct crm_desc pcie_crm_desc = {
  1267. .set_chn_behave = false,
  1268. };
  1269. static const struct of_device_id crm_drv_match[] = {
  1270. { .compatible = "qcom,cam-crm", .data = &cam_crm_desc},
  1271. { .compatible = "qcom,pcie-crm", .data = &pcie_crm_desc},
  1272. { }
  1273. };
  1274. MODULE_DEVICE_TABLE(of, crm_drv_match);
  1275. static struct platform_driver crm_driver = {
  1276. .probe = crm_probe,
  1277. .driver = {
  1278. .name = "crm",
  1279. .of_match_table = crm_drv_match,
  1280. .suppress_bind_attrs = true,
  1281. },
  1282. };
  1283. module_platform_driver(crm_driver);
  1284. MODULE_DESCRIPTION("Qualcomm Technologies, Inc. (QTI) CRM Driver");
  1285. MODULE_LICENSE("GPL");