xref: /openbmc/u-boot/drivers/sound/hda_codec.c (revision 2ca47137)
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 
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 
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(&regs->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 
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(&regs->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(&regs->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(&regs->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 
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 
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 
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(&regs->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(&regs->gcap), &regs->gcap);
158*2ca47137SSimon Glass 
159*2ca47137SSimon Glass 	/* Read in Codec location */
160*2ca47137SSimon Glass 	reg8 = readb(&regs->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(&regs->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 
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 
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]), &regs->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 
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, &regs->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(&regs->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 
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  */
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, &regs->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  */
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  */
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, &current_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  */
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  */
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", &current_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 			       &current_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  */
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 
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 
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 
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 
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