1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2021, Linaro Limited
4 #include <linux/slab.h>
5 #include <linux/wait.h>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
9 #include <linux/delay.h>
10 #include <linux/of_platform.h>
11 #include <linux/jiffies.h>
12 #include <linux/soc/qcom/apr.h>
13 #include <dt-bindings/soc/qcom,gpr.h>
14 #include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
17 #include "audioreach.h"
22 wait_queue_head_t wait
;
23 struct gpr_ibasic_rsp_result_t result
;
27 #define PRM_CMD_REQUEST_HW_RSC 0x0100100F
28 #define PRM_CMD_RSP_REQUEST_HW_RSC 0x02001002
29 #define PRM_CMD_RELEASE_HW_RSC 0x01001010
30 #define PRM_CMD_RSP_RELEASE_HW_RSC 0x02001003
31 #define PARAM_ID_RSC_HW_CORE 0x08001032
32 #define PARAM_ID_RSC_LPASS_CORE 0x0800102B
33 #define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800102C
35 struct prm_cmd_request_hw_core
{
36 struct apm_module_param_data param_data
;
40 struct prm_cmd_request_rsc
{
41 struct apm_module_param_data param_data
;
43 struct audio_hw_clk_cfg clock_id
;
46 struct prm_cmd_release_rsc
{
47 struct apm_module_param_data param_data
;
49 struct audio_hw_clk_rel_cfg clock_id
;
52 static int q6prm_send_cmd_sync(struct q6prm
*prm
, struct gpr_pkt
*pkt
, uint32_t rsp_opcode
)
54 return audioreach_send_cmd_sync(prm
->dev
, prm
->gdev
, &prm
->result
, &prm
->lock
,
55 NULL
, &prm
->wait
, pkt
, rsp_opcode
);
58 static int q6prm_set_hw_core_req(struct device
*dev
, uint32_t hw_block_id
, bool enable
)
60 struct q6prm
*prm
= dev_get_drvdata(dev
->parent
);
61 struct apm_module_param_data
*param_data
;
62 struct prm_cmd_request_hw_core
*req
;
63 gpr_device_t
*gdev
= prm
->gdev
;
64 uint32_t opcode
, rsp_opcode
;
69 opcode
= PRM_CMD_REQUEST_HW_RSC
;
70 rsp_opcode
= PRM_CMD_RSP_REQUEST_HW_RSC
;
72 opcode
= PRM_CMD_RELEASE_HW_RSC
;
73 rsp_opcode
= PRM_CMD_RSP_RELEASE_HW_RSC
;
76 pkt
= audioreach_alloc_cmd_pkt(sizeof(*req
), opcode
, 0, gdev
->svc
.id
, GPR_PRM_MODULE_IID
);
80 req
= (void *)pkt
+ GPR_HDR_SIZE
+ APM_CMD_HDR_SIZE
;
82 param_data
= &req
->param_data
;
84 param_data
->module_instance_id
= GPR_PRM_MODULE_IID
;
85 param_data
->error_code
= 0;
86 param_data
->param_id
= PARAM_ID_RSC_HW_CORE
;
87 param_data
->param_size
= sizeof(*req
) - APM_MODULE_PARAM_DATA_SIZE
;
89 req
->hw_clk_id
= hw_block_id
;
91 rc
= q6prm_send_cmd_sync(prm
, pkt
, rsp_opcode
);
98 int q6prm_vote_lpass_core_hw(struct device
*dev
, uint32_t hw_block_id
,
99 const char *client_name
, uint32_t *client_handle
)
101 return q6prm_set_hw_core_req(dev
, hw_block_id
, true);
104 EXPORT_SYMBOL_GPL(q6prm_vote_lpass_core_hw
);
106 int q6prm_unvote_lpass_core_hw(struct device
*dev
, uint32_t hw_block_id
, uint32_t client_handle
)
108 return q6prm_set_hw_core_req(dev
, hw_block_id
, false);
110 EXPORT_SYMBOL_GPL(q6prm_unvote_lpass_core_hw
);
112 static int q6prm_request_lpass_clock(struct device
*dev
, int clk_id
, int clk_attr
, int clk_root
,
115 struct q6prm
*prm
= dev_get_drvdata(dev
->parent
);
116 struct apm_module_param_data
*param_data
;
117 struct prm_cmd_request_rsc
*req
;
118 gpr_device_t
*gdev
= prm
->gdev
;
122 pkt
= audioreach_alloc_cmd_pkt(sizeof(*req
), PRM_CMD_REQUEST_HW_RSC
, 0, gdev
->svc
.id
,
127 req
= (void *)pkt
+ GPR_HDR_SIZE
+ APM_CMD_HDR_SIZE
;
129 param_data
= &req
->param_data
;
131 param_data
->module_instance_id
= GPR_PRM_MODULE_IID
;
132 param_data
->error_code
= 0;
133 param_data
->param_id
= PARAM_ID_RSC_AUDIO_HW_CLK
;
134 param_data
->param_size
= sizeof(*req
) - APM_MODULE_PARAM_DATA_SIZE
;
137 req
->clock_id
.clock_id
= clk_id
;
138 req
->clock_id
.clock_freq
= freq
;
139 req
->clock_id
.clock_attri
= clk_attr
;
140 req
->clock_id
.clock_root
= clk_root
;
142 rc
= q6prm_send_cmd_sync(prm
, pkt
, PRM_CMD_RSP_REQUEST_HW_RSC
);
149 static int q6prm_release_lpass_clock(struct device
*dev
, int clk_id
, int clk_attr
, int clk_root
,
152 struct q6prm
*prm
= dev_get_drvdata(dev
->parent
);
153 struct apm_module_param_data
*param_data
;
154 struct prm_cmd_release_rsc
*rel
;
155 gpr_device_t
*gdev
= prm
->gdev
;
159 pkt
= audioreach_alloc_cmd_pkt(sizeof(*rel
), PRM_CMD_RELEASE_HW_RSC
, 0, gdev
->svc
.id
,
164 rel
= (void *)pkt
+ GPR_HDR_SIZE
+ APM_CMD_HDR_SIZE
;
166 param_data
= &rel
->param_data
;
168 param_data
->module_instance_id
= GPR_PRM_MODULE_IID
;
169 param_data
->error_code
= 0;
170 param_data
->param_id
= PARAM_ID_RSC_AUDIO_HW_CLK
;
171 param_data
->param_size
= sizeof(*rel
) - APM_MODULE_PARAM_DATA_SIZE
;
174 rel
->clock_id
.clock_id
= clk_id
;
176 rc
= q6prm_send_cmd_sync(prm
, pkt
, PRM_CMD_RSP_RELEASE_HW_RSC
);
183 int q6prm_set_lpass_clock(struct device
*dev
, int clk_id
, int clk_attr
, int clk_root
,
187 return q6prm_request_lpass_clock(dev
, clk_id
, clk_attr
, clk_root
, freq
);
189 return q6prm_release_lpass_clock(dev
, clk_id
, clk_attr
, clk_root
, freq
);
191 EXPORT_SYMBOL_GPL(q6prm_set_lpass_clock
);
193 static int prm_callback(struct gpr_resp_pkt
*data
, void *priv
, int op
)
195 gpr_device_t
*gdev
= priv
;
196 struct q6prm
*prm
= dev_get_drvdata(&gdev
->dev
);
197 struct gpr_ibasic_rsp_result_t
*result
;
198 struct gpr_hdr
*hdr
= &data
->hdr
;
200 switch (hdr
->opcode
) {
201 case PRM_CMD_RSP_REQUEST_HW_RSC
:
202 case PRM_CMD_RSP_RELEASE_HW_RSC
:
203 result
= data
->payload
;
204 prm
->result
.opcode
= hdr
->opcode
;
205 prm
->result
.status
= result
->status
;
215 static int prm_probe(gpr_device_t
*gdev
)
217 struct device
*dev
= &gdev
->dev
;
220 cc
= devm_kzalloc(dev
, sizeof(*cc
), GFP_KERNEL
);
226 mutex_init(&cc
->lock
);
227 init_waitqueue_head(&cc
->wait
);
228 dev_set_drvdata(dev
, cc
);
230 if (!q6apm_is_adsp_ready())
231 return -EPROBE_DEFER
;
233 return devm_of_platform_populate(dev
);
237 static const struct of_device_id prm_device_id
[] = {
238 { .compatible
= "qcom,q6prm" },
241 MODULE_DEVICE_TABLE(of
, prm_device_id
);
244 static gpr_driver_t prm_driver
= {
246 .gpr_callback
= prm_callback
,
249 .of_match_table
= of_match_ptr(prm_device_id
),
253 module_gpr_driver(prm_driver
);
254 MODULE_DESCRIPTION("Q6 Proxy Resource Manager");
255 MODULE_LICENSE("GPL");