1*2ca47137SSimon Glass // SPDX-License-Identifier: GPL-2.0
2*2ca47137SSimon Glass /*
3*2ca47137SSimon Glass * Implementation of per-board codec beeping
4*2ca47137SSimon Glass * Copyright (c) 2011 The Chromium OS Authors.
5*2ca47137SSimon Glass * Copyright 2018 Google LLC
6*2ca47137SSimon Glass */
7*2ca47137SSimon Glass
8*2ca47137SSimon Glass #define LOG_CATEGORY UCLASS_SOUND
9*2ca47137SSimon Glass
10*2ca47137SSimon Glass #include <common.h>
11*2ca47137SSimon Glass #include <dm.h>
12*2ca47137SSimon Glass #include <hda_codec.h>
13*2ca47137SSimon Glass #include <pci.h>
14*2ca47137SSimon Glass #include <sound.h>
15*2ca47137SSimon Glass #include <asm/io.h>
16*2ca47137SSimon Glass #include <dt-bindings/sound/azalia.h>
17*2ca47137SSimon Glass
18*2ca47137SSimon Glass /**
19*2ca47137SSimon Glass * struct hda_regs - HDA registers
20*2ca47137SSimon Glass *
21*2ca47137SSimon Glass * https://wiki.osdev.org/Intel_High_Definition_Audio
22*2ca47137SSimon Glass * https://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html
23*2ca47137SSimon Glass */
24*2ca47137SSimon Glass struct hda_regs {
25*2ca47137SSimon Glass u16 gcap;
26*2ca47137SSimon Glass u8 vmin;
27*2ca47137SSimon Glass u8 vmaj;
28*2ca47137SSimon Glass u16 outpay;
29*2ca47137SSimon Glass u16 inpay;
30*2ca47137SSimon Glass u32 gctl;
31*2ca47137SSimon Glass u16 wakeen;
32*2ca47137SSimon Glass u16 statests;
33*2ca47137SSimon Glass u8 reserved[0x50];
34*2ca47137SSimon Glass u32 cmd; /* 0x60 */
35*2ca47137SSimon Glass u32 resp;
36*2ca47137SSimon Glass u32 icii;
37*2ca47137SSimon Glass };
38*2ca47137SSimon Glass
39*2ca47137SSimon Glass enum {
40*2ca47137SSimon Glass HDA_ICII_BUSY = BIT(0),
41*2ca47137SSimon Glass HDA_ICII_VALID = BIT(1),
42*2ca47137SSimon Glass
43*2ca47137SSimon Glass /* Common node IDs */
44*2ca47137SSimon Glass HDA_ROOT_NODE = 0x00,
45*2ca47137SSimon Glass
46*2ca47137SSimon Glass /* HDA verbs fields */
47*2ca47137SSimon Glass HDA_VERB_NID_S = 20,
48*2ca47137SSimon Glass HDA_VERB_VERB_S = 8,
49*2ca47137SSimon Glass HDA_VERB_PARAM_S = 0,
50*2ca47137SSimon Glass
51*2ca47137SSimon Glass HDA_VERB_GET_PARAMS = 0xf00,
52*2ca47137SSimon Glass HDA_VERB_SET_BEEP = 0x70a,
53*2ca47137SSimon Glass
54*2ca47137SSimon Glass /* GET_PARAMS parameter IDs */
55*2ca47137SSimon Glass GET_PARAMS_NODE_COUNT = 0x04,
56*2ca47137SSimon Glass GET_PARAMS_AUDIO_GROUP_CAPS = 0x08,
57*2ca47137SSimon Glass GET_PARAMS_AUDIO_WIDGET_CAPS = 0x09,
58*2ca47137SSimon Glass
59*2ca47137SSimon Glass /* Sub-node fields */
60*2ca47137SSimon Glass NUM_SUB_NODES_S = 0,
61*2ca47137SSimon Glass NUM_SUB_NODES_M = 0xff << NUM_SUB_NODES_S,
62*2ca47137SSimon Glass FIRST_SUB_NODE_S = 16,
63*2ca47137SSimon Glass FIRST_SUB_NODE_M = 0xff << FIRST_SUB_NODE_S,
64*2ca47137SSimon Glass
65*2ca47137SSimon Glass /* Get Audio Function Group Capabilities fields */
66*2ca47137SSimon Glass AUDIO_GROUP_CAPS_BEEP_GEN = 0x10000,
67*2ca47137SSimon Glass
68*2ca47137SSimon Glass /* Get Audio Widget Capabilities fields */
69*2ca47137SSimon Glass AUDIO_WIDGET_TYPE_BEEP = 0x7,
70*2ca47137SSimon Glass AUDIO_WIDGET_TYPE_S = 20,
71*2ca47137SSimon Glass AUDIO_WIDGET_TYPE_M = 0xf << AUDIO_WIDGET_TYPE_S,
72*2ca47137SSimon Glass
73*2ca47137SSimon Glass BEEP_FREQ_BASE = 12000,
74*2ca47137SSimon Glass };
75*2ca47137SSimon Glass
hda_verb(uint nid,uint verb,uint param)76*2ca47137SSimon Glass static inline uint hda_verb(uint nid, uint verb, uint param)
77*2ca47137SSimon Glass {
78*2ca47137SSimon Glass return nid << HDA_VERB_NID_S | verb << HDA_VERB_VERB_S |
79*2ca47137SSimon Glass param << HDA_VERB_PARAM_S;
80*2ca47137SSimon Glass }
81*2ca47137SSimon Glass
hda_wait_for_ready(struct hda_regs * regs)82*2ca47137SSimon Glass int hda_wait_for_ready(struct hda_regs *regs)
83*2ca47137SSimon Glass {
84*2ca47137SSimon Glass int timeout = 1000; /* Use a 1msec timeout */
85*2ca47137SSimon Glass
86*2ca47137SSimon Glass while (timeout--) {
87*2ca47137SSimon Glass u32 reg32 = readl(®s->icii);
88*2ca47137SSimon Glass
89*2ca47137SSimon Glass if (!(reg32 & HDA_ICII_BUSY))
90*2ca47137SSimon Glass return 0;
91*2ca47137SSimon Glass udelay(1);
92*2ca47137SSimon Glass }
93*2ca47137SSimon Glass
94*2ca47137SSimon Glass return -ETIMEDOUT;
95*2ca47137SSimon Glass }
96*2ca47137SSimon Glass
wait_for_response(struct hda_regs * regs,uint * response)97*2ca47137SSimon Glass static int wait_for_response(struct hda_regs *regs, uint *response)
98*2ca47137SSimon Glass {
99*2ca47137SSimon Glass int timeout = 1000;
100*2ca47137SSimon Glass u32 reg32;
101*2ca47137SSimon Glass
102*2ca47137SSimon Glass /* Send the verb to the codec */
103*2ca47137SSimon Glass setbits_le32(®s->icii, HDA_ICII_BUSY | HDA_ICII_VALID);
104*2ca47137SSimon Glass
105*2ca47137SSimon Glass /* Use a 1msec timeout */
106*2ca47137SSimon Glass while (timeout--) {
107*2ca47137SSimon Glass reg32 = readl(®s->icii);
108*2ca47137SSimon Glass if ((reg32 & (HDA_ICII_VALID | HDA_ICII_BUSY)) ==
109*2ca47137SSimon Glass HDA_ICII_VALID) {
110*2ca47137SSimon Glass if (response)
111*2ca47137SSimon Glass *response = readl(®s->resp);
112*2ca47137SSimon Glass return 0;
113*2ca47137SSimon Glass }
114*2ca47137SSimon Glass udelay(1);
115*2ca47137SSimon Glass }
116*2ca47137SSimon Glass
117*2ca47137SSimon Glass return -ETIMEDOUT;
118*2ca47137SSimon Glass }
119*2ca47137SSimon Glass
hda_wait_for_valid(struct hda_regs * regs)120*2ca47137SSimon Glass int hda_wait_for_valid(struct hda_regs *regs)
121*2ca47137SSimon Glass {
122*2ca47137SSimon Glass return wait_for_response(regs, NULL);
123*2ca47137SSimon Glass }
124*2ca47137SSimon Glass
set_bits(void * port,u32 mask,u32 val)125*2ca47137SSimon Glass static int set_bits(void *port, u32 mask, u32 val)
126*2ca47137SSimon Glass {
127*2ca47137SSimon Glass u32 reg32;
128*2ca47137SSimon Glass int count;
129*2ca47137SSimon Glass
130*2ca47137SSimon Glass /* Write (val & mask) to port */
131*2ca47137SSimon Glass clrsetbits_le32(port, mask, val);
132*2ca47137SSimon Glass
133*2ca47137SSimon Glass /* Wait for readback of register to match what was just written to it */
134*2ca47137SSimon Glass count = 50;
135*2ca47137SSimon Glass do {
136*2ca47137SSimon Glass /* Wait 1ms based on BKDG wait time */
137*2ca47137SSimon Glass mdelay(1);
138*2ca47137SSimon Glass reg32 = readl(port) & mask;
139*2ca47137SSimon Glass } while (reg32 != val && --count);
140*2ca47137SSimon Glass
141*2ca47137SSimon Glass /* Timeout occurred */
142*2ca47137SSimon Glass if (!count)
143*2ca47137SSimon Glass return -ETIMEDOUT;
144*2ca47137SSimon Glass
145*2ca47137SSimon Glass return 0;
146*2ca47137SSimon Glass }
147*2ca47137SSimon Glass
hda_codec_detect(struct hda_regs * regs)148*2ca47137SSimon Glass int hda_codec_detect(struct hda_regs *regs)
149*2ca47137SSimon Glass {
150*2ca47137SSimon Glass uint reg8;
151*2ca47137SSimon Glass
152*2ca47137SSimon Glass /* Set Bit 0 to 1 to exit reset state (BAR + 0x8)[0] */
153*2ca47137SSimon Glass if (set_bits(®s->gctl, 1, 1))
154*2ca47137SSimon Glass goto no_codec;
155*2ca47137SSimon Glass
156*2ca47137SSimon Glass /* Write back the value once reset bit is set */
157*2ca47137SSimon Glass writew(readw(®s->gcap), ®s->gcap);
158*2ca47137SSimon Glass
159*2ca47137SSimon Glass /* Read in Codec location */
160*2ca47137SSimon Glass reg8 = readb(®s->statests) & 0xf;
161*2ca47137SSimon Glass if (!reg8)
162*2ca47137SSimon Glass goto no_codec;
163*2ca47137SSimon Glass
164*2ca47137SSimon Glass return reg8;
165*2ca47137SSimon Glass
166*2ca47137SSimon Glass no_codec:
167*2ca47137SSimon Glass /* Codec Not found - put HDA back in reset */
168*2ca47137SSimon Glass set_bits(®s->gctl, 1, 0);
169*2ca47137SSimon Glass log_debug("No codec\n");
170*2ca47137SSimon Glass
171*2ca47137SSimon Glass return 0;
172*2ca47137SSimon Glass }
173*2ca47137SSimon Glass
find_verb_data(struct udevice * dev,uint id,ofnode * nodep)174*2ca47137SSimon Glass static int find_verb_data(struct udevice *dev, uint id, ofnode *nodep)
175*2ca47137SSimon Glass {
176*2ca47137SSimon Glass ofnode parent = dev_read_subnode(dev, "codecs");
177*2ca47137SSimon Glass ofnode node;
178*2ca47137SSimon Glass u32 vendor_id, device_id;
179*2ca47137SSimon Glass
180*2ca47137SSimon Glass ofnode_for_each_subnode(node, parent) {
181*2ca47137SSimon Glass if (ofnode_read_u32(node, "vendor-id", &vendor_id) ||
182*2ca47137SSimon Glass ofnode_read_u32(node, "device-id", &device_id)) {
183*2ca47137SSimon Glass log_debug("Cannot get IDs for '%s'\n",
184*2ca47137SSimon Glass ofnode_get_name(node));
185*2ca47137SSimon Glass return -EINVAL;
186*2ca47137SSimon Glass }
187*2ca47137SSimon Glass if (id != (vendor_id << 16 | device_id)) {
188*2ca47137SSimon Glass log_debug("Skip codec node '%s' for %08x\n",
189*2ca47137SSimon Glass ofnode_get_name(node), id);
190*2ca47137SSimon Glass continue;
191*2ca47137SSimon Glass }
192*2ca47137SSimon Glass
193*2ca47137SSimon Glass log_debug("Found codec node '%s' for %08x\n",
194*2ca47137SSimon Glass ofnode_get_name(node), id);
195*2ca47137SSimon Glass *nodep = node;
196*2ca47137SSimon Glass return 0;
197*2ca47137SSimon Glass }
198*2ca47137SSimon Glass
199*2ca47137SSimon Glass return -ENOENT;
200*2ca47137SSimon Glass }
201*2ca47137SSimon Glass
send_verbs(ofnode node,const char * prop_name,struct hda_regs * regs)202*2ca47137SSimon Glass static int send_verbs(ofnode node, const char *prop_name, struct hda_regs *regs)
203*2ca47137SSimon Glass {
204*2ca47137SSimon Glass int ret, verb_size, i;
205*2ca47137SSimon Glass const u32 *verb;
206*2ca47137SSimon Glass
207*2ca47137SSimon Glass verb = ofnode_get_property(node, prop_name, &verb_size);
208*2ca47137SSimon Glass if (verb_size < 0) {
209*2ca47137SSimon Glass log_debug("No verb data\n");
210*2ca47137SSimon Glass return -EINVAL;
211*2ca47137SSimon Glass }
212*2ca47137SSimon Glass log_debug("verb_size: %d\n", verb_size);
213*2ca47137SSimon Glass
214*2ca47137SSimon Glass for (i = 0; i < verb_size / sizeof(*verb); i++) {
215*2ca47137SSimon Glass ret = hda_wait_for_ready(regs);
216*2ca47137SSimon Glass if (ret) {
217*2ca47137SSimon Glass log_debug(" codec ready timeout\n");
218*2ca47137SSimon Glass return ret;
219*2ca47137SSimon Glass }
220*2ca47137SSimon Glass
221*2ca47137SSimon Glass writel(fdt32_to_cpu(verb[i]), ®s->cmd);
222*2ca47137SSimon Glass
223*2ca47137SSimon Glass ret = hda_wait_for_valid(regs);
224*2ca47137SSimon Glass if (ret) {
225*2ca47137SSimon Glass log_debug(" codec valid timeout\n");
226*2ca47137SSimon Glass return ret;
227*2ca47137SSimon Glass }
228*2ca47137SSimon Glass }
229*2ca47137SSimon Glass
230*2ca47137SSimon Glass return 0;
231*2ca47137SSimon Glass }
232*2ca47137SSimon Glass
codec_init(struct udevice * dev,struct hda_regs * regs,uint addr)233*2ca47137SSimon Glass static int codec_init(struct udevice *dev, struct hda_regs *regs, uint addr)
234*2ca47137SSimon Glass {
235*2ca47137SSimon Glass ofnode node;
236*2ca47137SSimon Glass uint id;
237*2ca47137SSimon Glass int ret;
238*2ca47137SSimon Glass
239*2ca47137SSimon Glass log_debug("Initializing codec #%d\n", addr);
240*2ca47137SSimon Glass ret = hda_wait_for_ready(regs);
241*2ca47137SSimon Glass if (ret) {
242*2ca47137SSimon Glass log_debug(" codec not ready\n");
243*2ca47137SSimon Glass return ret;
244*2ca47137SSimon Glass }
245*2ca47137SSimon Glass
246*2ca47137SSimon Glass /* Read the codec's vendor ID */
247*2ca47137SSimon Glass writel(addr << AZALIA_CODEC_SHIFT |
248*2ca47137SSimon Glass AZALIA_OPCODE_READ_PARAM << AZALIA_VERB_SHIFT |
249*2ca47137SSimon Glass AZALIA_PARAM_VENDOR_ID, ®s->cmd);
250*2ca47137SSimon Glass ret = hda_wait_for_valid(regs);
251*2ca47137SSimon Glass if (ret) {
252*2ca47137SSimon Glass log_debug(" codec not valid\n");
253*2ca47137SSimon Glass return ret;
254*2ca47137SSimon Glass }
255*2ca47137SSimon Glass
256*2ca47137SSimon Glass id = readl(®s->resp);
257*2ca47137SSimon Glass log_debug("codec vid/did: %08x\n", id);
258*2ca47137SSimon Glass ret = find_verb_data(dev, id, &node);
259*2ca47137SSimon Glass if (ret) {
260*2ca47137SSimon Glass log_debug("No verb (err=%d)\n", ret);
261*2ca47137SSimon Glass return ret;
262*2ca47137SSimon Glass }
263*2ca47137SSimon Glass ret = send_verbs(node, "verbs", regs);
264*2ca47137SSimon Glass if (ret) {
265*2ca47137SSimon Glass log_debug("failed to send verbs (err=%d)\n", ret);
266*2ca47137SSimon Glass return ret;
267*2ca47137SSimon Glass }
268*2ca47137SSimon Glass log_debug("verb loaded\n");
269*2ca47137SSimon Glass
270*2ca47137SSimon Glass return 0;
271*2ca47137SSimon Glass }
272*2ca47137SSimon Glass
hda_codecs_init(struct udevice * dev,struct hda_regs * regs,u32 codec_mask)273*2ca47137SSimon Glass int hda_codecs_init(struct udevice *dev, struct hda_regs *regs, u32 codec_mask)
274*2ca47137SSimon Glass {
275*2ca47137SSimon Glass int ret;
276*2ca47137SSimon Glass int i;
277*2ca47137SSimon Glass
278*2ca47137SSimon Glass for (i = 3; i >= 0; i--) {
279*2ca47137SSimon Glass if (codec_mask & (1 << i)) {
280*2ca47137SSimon Glass ret = codec_init(dev, regs, i);
281*2ca47137SSimon Glass if (ret)
282*2ca47137SSimon Glass return ret;
283*2ca47137SSimon Glass }
284*2ca47137SSimon Glass }
285*2ca47137SSimon Glass
286*2ca47137SSimon Glass ret = send_verbs(dev_ofnode(dev), "beep-verbs", regs);
287*2ca47137SSimon Glass if (ret) {
288*2ca47137SSimon Glass log_debug("failed to send beep verbs (err=%d)\n", ret);
289*2ca47137SSimon Glass return ret;
290*2ca47137SSimon Glass }
291*2ca47137SSimon Glass log_debug("beep verbs loaded\n");
292*2ca47137SSimon Glass
293*2ca47137SSimon Glass return 0;
294*2ca47137SSimon Glass }
295*2ca47137SSimon Glass
296*2ca47137SSimon Glass /**
297*2ca47137SSimon Glass * exec_verb() - Write a verb to the codec
298*2ca47137SSimon Glass *
299*2ca47137SSimon Glass * @regs: HDA registers
300*2ca47137SSimon Glass * @val: Command to write
301*2ca47137SSimon Glass * @response: Set to response from codec
302*2ca47137SSimon Glass * @return 0 if OK, -ve on error
303*2ca47137SSimon Glass */
exec_verb(struct hda_regs * regs,uint val,uint * response)304*2ca47137SSimon Glass static int exec_verb(struct hda_regs *regs, uint val, uint *response)
305*2ca47137SSimon Glass {
306*2ca47137SSimon Glass int ret;
307*2ca47137SSimon Glass
308*2ca47137SSimon Glass ret = hda_wait_for_ready(regs);
309*2ca47137SSimon Glass if (ret)
310*2ca47137SSimon Glass return ret;
311*2ca47137SSimon Glass
312*2ca47137SSimon Glass writel(val, ®s->cmd);
313*2ca47137SSimon Glass
314*2ca47137SSimon Glass return wait_for_response(regs, response);
315*2ca47137SSimon Glass }
316*2ca47137SSimon Glass
317*2ca47137SSimon Glass /**
318*2ca47137SSimon Glass * get_subnode_info() - Get subnode information
319*2ca47137SSimon Glass *
320*2ca47137SSimon Glass * @regs: HDA registers
321*2ca47137SSimon Glass * @nid: Parent node ID to check
322*2ca47137SSimon Glass * @num_sub_nodesp: Returns number of subnodes
323*2ca47137SSimon Glass * @start_sub_node_nidp: Returns start subnode number
324*2ca47137SSimon Glass * @return 0 if OK, -ve on error
325*2ca47137SSimon Glass */
get_subnode_info(struct hda_regs * regs,uint nid,uint * num_sub_nodesp,uint * start_sub_node_nidp)326*2ca47137SSimon Glass static int get_subnode_info(struct hda_regs *regs, uint nid,
327*2ca47137SSimon Glass uint *num_sub_nodesp, uint *start_sub_node_nidp)
328*2ca47137SSimon Glass {
329*2ca47137SSimon Glass uint response;
330*2ca47137SSimon Glass int ret;
331*2ca47137SSimon Glass
332*2ca47137SSimon Glass ret = exec_verb(regs, hda_verb(nid, HDA_VERB_GET_PARAMS,
333*2ca47137SSimon Glass GET_PARAMS_NODE_COUNT),
334*2ca47137SSimon Glass &response);
335*2ca47137SSimon Glass if (ret < 0) {
336*2ca47137SSimon Glass printf("Audio: Error reading sub-node info %d\n", nid);
337*2ca47137SSimon Glass return ret;
338*2ca47137SSimon Glass }
339*2ca47137SSimon Glass
340*2ca47137SSimon Glass *num_sub_nodesp = (response & NUM_SUB_NODES_M) >> NUM_SUB_NODES_S;
341*2ca47137SSimon Glass *start_sub_node_nidp = (response & FIRST_SUB_NODE_M) >>
342*2ca47137SSimon Glass FIRST_SUB_NODE_S;
343*2ca47137SSimon Glass
344*2ca47137SSimon Glass return 0;
345*2ca47137SSimon Glass }
346*2ca47137SSimon Glass
347*2ca47137SSimon Glass /**
348*2ca47137SSimon Glass * find_beep_node_in_group() - Finds the beeping node
349*2ca47137SSimon Glass *
350*2ca47137SSimon Glass * Searches the audio group for a node that supports beeping
351*2ca47137SSimon Glass *
352*2ca47137SSimon Glass * @regs: HDA registers
353*2ca47137SSimon Glass * @group_nid: Group node ID to check
354*2ca47137SSimon Glass * @return 0 if OK, -ve on error
355*2ca47137SSimon Glass */
find_beep_node_in_group(struct hda_regs * regs,uint group_nid)356*2ca47137SSimon Glass static uint find_beep_node_in_group(struct hda_regs *regs, uint group_nid)
357*2ca47137SSimon Glass {
358*2ca47137SSimon Glass uint node_count = 0;
359*2ca47137SSimon Glass uint current_nid = 0;
360*2ca47137SSimon Glass uint response;
361*2ca47137SSimon Glass uint end_nid;
362*2ca47137SSimon Glass int ret;
363*2ca47137SSimon Glass
364*2ca47137SSimon Glass ret = get_subnode_info(regs, group_nid, &node_count, ¤t_nid);
365*2ca47137SSimon Glass if (ret < 0)
366*2ca47137SSimon Glass return 0;
367*2ca47137SSimon Glass
368*2ca47137SSimon Glass end_nid = current_nid + node_count;
369*2ca47137SSimon Glass while (current_nid < end_nid) {
370*2ca47137SSimon Glass ret = exec_verb(regs,
371*2ca47137SSimon Glass hda_verb(current_nid, HDA_VERB_GET_PARAMS,
372*2ca47137SSimon Glass GET_PARAMS_AUDIO_WIDGET_CAPS),
373*2ca47137SSimon Glass &response);
374*2ca47137SSimon Glass if (ret < 0) {
375*2ca47137SSimon Glass printf("Audio: Error reading widget caps\n");
376*2ca47137SSimon Glass return 0;
377*2ca47137SSimon Glass }
378*2ca47137SSimon Glass
379*2ca47137SSimon Glass if ((response & AUDIO_WIDGET_TYPE_M) >> AUDIO_WIDGET_TYPE_S ==
380*2ca47137SSimon Glass AUDIO_WIDGET_TYPE_BEEP)
381*2ca47137SSimon Glass return current_nid;
382*2ca47137SSimon Glass
383*2ca47137SSimon Glass current_nid++;
384*2ca47137SSimon Glass }
385*2ca47137SSimon Glass
386*2ca47137SSimon Glass return 0; /* no beep node found */
387*2ca47137SSimon Glass }
388*2ca47137SSimon Glass
389*2ca47137SSimon Glass /**
390*2ca47137SSimon Glass * audio_group_has_beep_node() - Check if group has a beep node
391*2ca47137SSimon Glass *
392*2ca47137SSimon Glass * Checks if the given audio group contains a beep generator
393*2ca47137SSimon Glass * @regs: HDA registers
394*2ca47137SSimon Glass * @nid: Node ID to check
395*2ca47137SSimon Glass * @return 0 if OK, -ve on error
396*2ca47137SSimon Glass */
audio_group_has_beep_node(struct hda_regs * regs,uint nid)397*2ca47137SSimon Glass static int audio_group_has_beep_node(struct hda_regs *regs, uint nid)
398*2ca47137SSimon Glass {
399*2ca47137SSimon Glass uint response;
400*2ca47137SSimon Glass int ret;
401*2ca47137SSimon Glass
402*2ca47137SSimon Glass ret = exec_verb(regs, hda_verb(nid, HDA_VERB_GET_PARAMS,
403*2ca47137SSimon Glass GET_PARAMS_AUDIO_GROUP_CAPS),
404*2ca47137SSimon Glass &response);
405*2ca47137SSimon Glass if (ret < 0) {
406*2ca47137SSimon Glass printf("Audio: Error reading audio group caps %d\n", nid);
407*2ca47137SSimon Glass return 0;
408*2ca47137SSimon Glass }
409*2ca47137SSimon Glass
410*2ca47137SSimon Glass return !!(response & AUDIO_GROUP_CAPS_BEEP_GEN);
411*2ca47137SSimon Glass }
412*2ca47137SSimon Glass
413*2ca47137SSimon Glass /**
414*2ca47137SSimon Glass * get_hda_beep_nid() - Finds the node ID of the beep node
415*2ca47137SSimon Glass *
416*2ca47137SSimon Glass * Finds the nid of the beep node if it exists. Starts at the root node, for
417*2ca47137SSimon Glass * each sub-node checks if the group contains a beep node. If the group
418*2ca47137SSimon Glass * contains a beep node, polls each node in the group until it is found.
419*2ca47137SSimon Glass *
420*2ca47137SSimon Glass * If the device has a intel,beep-nid property, the value of that is used
421*2ca47137SSimon Glass * instead.
422*2ca47137SSimon Glass *
423*2ca47137SSimon Glass * @dev: Sound device
424*2ca47137SSimon Glass * @return Node ID >0 if found, -ve error code otherwise
425*2ca47137SSimon Glass */
get_hda_beep_nid(struct udevice * dev)426*2ca47137SSimon Glass static int get_hda_beep_nid(struct udevice *dev)
427*2ca47137SSimon Glass {
428*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev);
429*2ca47137SSimon Glass uint current_nid = 0;
430*2ca47137SSimon Glass uint node_count = 0;
431*2ca47137SSimon Glass uint end_nid;
432*2ca47137SSimon Glass int ret;
433*2ca47137SSimon Glass
434*2ca47137SSimon Glass /* If the field exists, use the beep nid set in the fdt */
435*2ca47137SSimon Glass ret = dev_read_u32(dev, "intel,beep-nid", ¤t_nid);
436*2ca47137SSimon Glass if (!ret)
437*2ca47137SSimon Glass return current_nid;
438*2ca47137SSimon Glass
439*2ca47137SSimon Glass ret = get_subnode_info(priv->regs, HDA_ROOT_NODE, &node_count,
440*2ca47137SSimon Glass ¤t_nid);
441*2ca47137SSimon Glass if (ret < 0)
442*2ca47137SSimon Glass return ret;
443*2ca47137SSimon Glass
444*2ca47137SSimon Glass end_nid = current_nid + node_count;
445*2ca47137SSimon Glass while (current_nid < end_nid) {
446*2ca47137SSimon Glass if (audio_group_has_beep_node(priv->regs, current_nid))
447*2ca47137SSimon Glass return find_beep_node_in_group(priv->regs,
448*2ca47137SSimon Glass current_nid);
449*2ca47137SSimon Glass current_nid++;
450*2ca47137SSimon Glass }
451*2ca47137SSimon Glass /* no beep node found */
452*2ca47137SSimon Glass
453*2ca47137SSimon Glass return -ENOENT;
454*2ca47137SSimon Glass }
455*2ca47137SSimon Glass
456*2ca47137SSimon Glass /**
457*2ca47137SSimon Glass * set_beep_divisor() - Sets the beep divisor to set the pitch
458*2ca47137SSimon Glass *
459*2ca47137SSimon Glass * @priv: Device's private data
460*2ca47137SSimon Glass * @divider: Divider value (0 to disable the beep)
461*2ca47137SSimon Glass * @return 0 if OK, -ve on error
462*2ca47137SSimon Glass */
set_beep_divisor(struct hda_codec_priv * priv,uint divider)463*2ca47137SSimon Glass static int set_beep_divisor(struct hda_codec_priv *priv, uint divider)
464*2ca47137SSimon Glass {
465*2ca47137SSimon Glass return exec_verb(priv->regs,
466*2ca47137SSimon Glass hda_verb(priv->beep_nid, HDA_VERB_SET_BEEP, divider),
467*2ca47137SSimon Glass NULL);
468*2ca47137SSimon Glass }
469*2ca47137SSimon Glass
hda_codec_init(struct udevice * dev)470*2ca47137SSimon Glass int hda_codec_init(struct udevice *dev)
471*2ca47137SSimon Glass {
472*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev);
473*2ca47137SSimon Glass ulong base_addr;
474*2ca47137SSimon Glass
475*2ca47137SSimon Glass base_addr = dm_pci_read_bar32(dev, 0);
476*2ca47137SSimon Glass log_debug("base = %08lx\n", base_addr);
477*2ca47137SSimon Glass if (!base_addr)
478*2ca47137SSimon Glass return -EINVAL;
479*2ca47137SSimon Glass
480*2ca47137SSimon Glass priv->regs = (struct hda_regs *)base_addr;
481*2ca47137SSimon Glass
482*2ca47137SSimon Glass return 0;
483*2ca47137SSimon Glass }
484*2ca47137SSimon Glass
hda_codec_finish_init(struct udevice * dev)485*2ca47137SSimon Glass int hda_codec_finish_init(struct udevice *dev)
486*2ca47137SSimon Glass {
487*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev);
488*2ca47137SSimon Glass int ret;
489*2ca47137SSimon Glass
490*2ca47137SSimon Glass ret = get_hda_beep_nid(dev);
491*2ca47137SSimon Glass if (ret <= 0) {
492*2ca47137SSimon Glass log_warning("Could not find beep NID (err=%d)\n", ret);
493*2ca47137SSimon Glass return ret ? ret : -ENOENT;
494*2ca47137SSimon Glass }
495*2ca47137SSimon Glass priv->beep_nid = ret;
496*2ca47137SSimon Glass
497*2ca47137SSimon Glass return 0;
498*2ca47137SSimon Glass }
499*2ca47137SSimon Glass
hda_codec_start_beep(struct udevice * dev,int frequency_hz)500*2ca47137SSimon Glass int hda_codec_start_beep(struct udevice *dev, int frequency_hz)
501*2ca47137SSimon Glass {
502*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev);
503*2ca47137SSimon Glass uint divider_val;
504*2ca47137SSimon Glass
505*2ca47137SSimon Glass if (!priv->beep_nid) {
506*2ca47137SSimon Glass log_err("Failed to find a beep-capable node\n");
507*2ca47137SSimon Glass return -ENOENT;
508*2ca47137SSimon Glass }
509*2ca47137SSimon Glass
510*2ca47137SSimon Glass if (!frequency_hz)
511*2ca47137SSimon Glass divider_val = 0; /* off */
512*2ca47137SSimon Glass else if (frequency_hz > BEEP_FREQ_BASE)
513*2ca47137SSimon Glass divider_val = 1;
514*2ca47137SSimon Glass else if (frequency_hz < BEEP_FREQ_BASE / 0xff)
515*2ca47137SSimon Glass divider_val = 0xff;
516*2ca47137SSimon Glass else
517*2ca47137SSimon Glass divider_val = 0xff & (BEEP_FREQ_BASE / frequency_hz);
518*2ca47137SSimon Glass
519*2ca47137SSimon Glass return set_beep_divisor(priv, divider_val);
520*2ca47137SSimon Glass }
521*2ca47137SSimon Glass
hda_codec_stop_beep(struct udevice * dev)522*2ca47137SSimon Glass int hda_codec_stop_beep(struct udevice *dev)
523*2ca47137SSimon Glass {
524*2ca47137SSimon Glass struct hda_codec_priv *priv = dev_get_priv(dev);
525*2ca47137SSimon Glass
526*2ca47137SSimon Glass return set_beep_divisor(priv, 0);
527*2ca47137SSimon Glass }
528*2ca47137SSimon Glass
529*2ca47137SSimon Glass static const struct sound_ops hda_codec_ops = {
530*2ca47137SSimon Glass .setup = hda_codec_finish_init,
531*2ca47137SSimon Glass .start_beep = hda_codec_start_beep,
532*2ca47137SSimon Glass .stop_beep = hda_codec_stop_beep,
533*2ca47137SSimon Glass };
534*2ca47137SSimon Glass
535*2ca47137SSimon Glass U_BOOT_DRIVER(hda_codec) = {
536*2ca47137SSimon Glass .name = "hda_codec",
537*2ca47137SSimon Glass .id = UCLASS_SOUND,
538*2ca47137SSimon Glass .ops = &hda_codec_ops,
539*2ca47137SSimon Glass .priv_auto_alloc_size = sizeof(struct hda_codec_priv),
540*2ca47137SSimon Glass .probe = hda_codec_init,
541*2ca47137SSimon Glass };
542*2ca47137SSimon Glass
543*2ca47137SSimon Glass static struct pci_device_id hda_supported[] = {
544*2ca47137SSimon Glass { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_HDA},
545*2ca47137SSimon Glass { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_HDA},
546*2ca47137SSimon Glass { PCI_DEVICE(PCI_VENDOR_ID_INTEL,
547*2ca47137SSimon Glass PCI_DEVICE_ID_INTEL_WILDCATPOINT_HDA) },
548*2ca47137SSimon Glass
549*2ca47137SSimon Glass /*
550*2ca47137SSimon Glass * Note this driver is not necessarily generic, but it attempts to
551*2ca47137SSimon Glass * support any codec in the hd-audio class
552*2ca47137SSimon Glass */
553*2ca47137SSimon Glass { PCI_DEVICE_CLASS(PCI_CLASS_MULTIMEDIA_HD_AUDIO, 0xffffff) },
554*2ca47137SSimon Glass };
555*2ca47137SSimon Glass
556*2ca47137SSimon Glass U_BOOT_PCI_DEVICE(hda_codec, hda_supported);
557