HDA sound driver mod for sigmatel 92xx

Wesley Morgan morganw at chemikals.org
Thu Jul 13 01:05:08 UTC 2006


On Wed, 12 Jul 2006, Eric Anderson wrote:

> On 07/09/06 09:11, Wesley Morgan wrote:
>> 
>> With a little help from the netbsd azalia driver (a wonderful piece of 
>> work, by the way) and the hda specs, I've been able to get Andrea's hdac 
>> code to work with my laptop. I believe the problem was that the codec and 
>> dac started out in some kind of low-power mode and needed to be woken up 
>> before they would work.
>> 
>> Hopefully someone is still working on a proper driver, but for now, I can 
>> watch movies again!
>> 
>> A diff against Andrea's work is attached.
>
>
> I couldn't get this patch to work - all hunks fail.  What am I doing wrong?

Make sure your mailer didn't wrap long lines? It applies cleanly for me. 
I've attached a newer diff that makes the mixer work properly as well, but 
it's hard-coded to the correct widget for me so it might not work for 
everyone.


[morganw at catalyst:~$]: tar zxf hdac.tgz
[morganw at catalyst:~$]: cd hdac
[morganw at catalyst:~/hdac$]: patch < ../sigma.diff
Hmm...  Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|diff -urb hdac/hdac.c hdac-sigma/hdac.c
|--- hdac/hdac.c        Mon Jun  5 15:15:12 2006
|+++ hdac-sigma/hdac.c  Sun Jul  9 10:10:37 2006
--------------------------
Patching file hdac.c using Plan A...
Hunk #1 succeeded at 247.
Hunk #2 succeeded at 261.
Hunk #3 succeeded at 787.
Hunk #4 succeeded at 821.
Hunk #5 succeeded at 894.
Hunk #6 succeeded at 945.
Hunk #7 succeeded at 974.
Hunk #8 succeeded at 1270.
Hmm...  Ignoring the trailing garbage.
done




-- 
This .signature sanitized for your protection
-------------- next part --------------
diff -urb hdac/hdac.c hdac-sigma/hdac.c
--- hdac/hdac.c	Mon Jun  5 15:15:12 2006
+++ hdac-sigma/hdac.c	Wed Jul 12 21:02:32 2006
@@ -247,7 +247,8 @@
 	 * Reset the controller. The reset must remain asserted for
 	 * a minimum of 100us.
 	 */
-	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, 0x0);
+	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
+	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~ HDAC_GCTL_CRST);
 	count = 10000;
 	while (count) {
 		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
@@ -260,11 +261,11 @@
 		return (ENXIO);
 	}
 	DELAY(100);
-	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_GCTL_CRST);
+	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
+	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
 	count = 10000;
 	while (count) {
-		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
-		if ((gctl & HDAC_GCTL_CRST) == HDAC_GCTL_CRST)
+		if (HDAC_READ_4(&sc->mem, HDAC_GCTL) & HDAC_GCTL_CRST)
 			break;
 		count--;
 	}
@@ -273,6 +274,10 @@
 		device_printf(sc->dev, "Device stuck in reset\n");
 		return(ENXIO);
 	}
+/*
+	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
+	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_UNSOL);
+*/
 
 	/*
 	 * Wait for codecs to finish their own reset sequence. The delay here
@@ -786,6 +791,10 @@
 	devinfo->stepping_id = HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
 	devinfo->node_type = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(fctgrptype);
 

+
+	device_printf(sc->dev, "Vendor info: %x %x %x %x %x %x\n", vendorid, devinfo->vendor_id, devinfo->device_id,
+		devinfo->revision_id, devinfo->stepping_id, devinfo->node_type);
+
 	hdac_add_child(sc, devinfo);
 }
 
@@ -816,6 +825,10 @@
 	uint32_t rc, sf, st;
 	uint32_t fmt = sorbo_get_fmt(sc);
 
+
+	rc = HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid);
+	device_printf(sc->dev, "Config %x\n", rc);
+
 	rc = hdac_command_sendone_internal(sc,
 		HDA_CMD_SET_CONV_STREAM_CHAN(cad, nid, 1 << 4), 0);
 	if (rc)
@@ -854,12 +867,26 @@
 }
 
 static void
-sorbo_set_amp(struct hdac_softc *sc, int cda, int ni, int amp)
+sorbo_set_amp(struct hdac_softc *sc, int cda, int ni, int left, int right)
 {
-	uint16_t pay = (1 << 15) | (3 << 12) | amp;
+	uint16_t pay = 0;
+	
+	if (left != right) {
+		pay = (1 << 15) | (1 << 13) | left;
 
 	hdac_command_sendone_internal(sc,
 		HDA_CMD_SET_AMP_GAIN_MUTE(cda, ni, pay), cda);
+
+		pay = (1 << 15) | (1 << 12) | right;
+
+		hdac_command_sendone_internal(sc,
+			HDA_CMD_SET_AMP_GAIN_MUTE(cda, ni, pay), cda);
+	} else {
+		pay = (1 << 15) | (3 << 12) | left;
+
+		hdac_command_sendone_internal(sc,
+			HDA_CMD_SET_AMP_GAIN_MUTE(cda, ni, pay), cda);
+	}
 }
 
 static void
@@ -885,8 +912,10 @@
 
 	ct = hdac_command_sendone_internal(sc,
 		HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad);
-	ct |= (1 << 6) | (1 << 7);
-	ct = hdac_command_sendone_internal(sc,
+
+	ct |= (1 << 6) | (1 << 2) | (1);
+
+	hdac_command_sendone_internal(sc,
 		HDA_CMD_SET_PIN_WIDGET_CTRL(cad, nid, ct), cad);
 
 	capa = hdac_command_sendone_internal(sc,
@@ -934,18 +963,26 @@
 	
 	device_printf(sc->dev, "node %d type %x cap %x\n", nodeid, type, rc);
 
-	if (0)
-	sorbo_set_amp(sc, codecid, nodeid, 40);
+	if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(rc)) {
+		hdac_command_sendone_internal(sc,
+			HDA_CMD_SET_POWER_STATE(codecid, nodeid, HDA_CMD_POWER_STATE_D0), codecid);
+	}
 
 	if (0 && HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET(rc)) {
 		sorbo_own_proc(sc, codecid, nodeid);
 	}
 
-	if (0 && type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) {
+	if (type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) {
 		sorbo_conf_output(sc, codecid, nodeid);
+		device_printf(sc->dev, "sorbo_conf_output: codec: %d node: %d\n", codecid, nodeid);
 	}	
-	else if (0 && type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
+	else if (type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) {
+		sorbo_set_amp(sc, codecid, nodeid, 75, 75);
+	}	
+	else if (type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
 		sorbo_conf_pin(sc, codecid, nodeid);
+		sorbo_set_amp(sc, codecid, nodeid, 75, 75);
+	}
 }
 
 static void
@@ -955,19 +992,22 @@
 	int startnode;
 	int endnode;
 	int i;
-//	uint32_t pw;
+	uint32_t pw;
 	
 	subnode = hdac_command_sendone_internal(sc,
 	    HDA_CMD_GET_PARAMETER(0 , 1, HDA_PARAM_SUB_NODE_COUNT), 0);
+	
 	startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode);
 	endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode);
 
-#if 0
+	hdac_command_sendone_internal(sc,
+		HDA_CMD_SET_POWER_STATE(0, 1, HDA_CMD_POWER_STATE_D0), 0);
+
 	pw = hdac_command_sendone_internal(sc,
 		HDA_CMD_GET_POWER_STATE(0, 1), 0);
 
 	device_printf(sc->dev, "PW %x\n", pw);
-#endif
+	device_printf(sc->dev, "start: %d endnode: %d\n", startnode, endnode);
 
 	for (i = startnode; i < endnode; i++) {
 		sorbo_print_widget(sc, 0, i);
@@ -1248,15 +1288,12 @@
 
 	hdac_scan_codecs(sc);
 
-	if (0)
 	sorbo_enum(sc);
 
 	sorbo_stop_stream(sc);
 	sorbo_reset_stream(sc);
 	sorbo_stream_setid(sc);
 
-	sorbo_conf_output(sc, 0, 3);
-	sorbo_set_amp(sc, 0, 5, 40);
 	sorbo_alloc_bdl(sc, 256);
 	sorbo_enable_stream_interrupts(sc);	
 	sc->lame = 1;
@@ -1591,21 +1628,26 @@
 static int
 hdacmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
 {
-	int vol = 0;
-	int max = 63;
+	int left_vol = 0, right_vol = 0;
+	int max = ((1<<5) - 1);
 	struct hdac_softc *sc = mix_getdevinfo(m);
-	vol = (left*63)/100;
 
-	if (left == 100 || vol > max)
-		vol = max;
+	left_vol = (left * max) / 100;
+	if ((left == 100) || (left_vol > max))
+		left_vol = max;
 
-//	printf("Vol = %d\n", vol);
-	if (sc->lame)
-		sorbo_set_amp(sc, 0, 5, vol);
+	right_vol = (right * max) / 100;
+	if ((right == 100) || (right_vol > max))
+		right_vol = max;
+
+	if (sc->lame) {
+/*		device_printf(sc->dev, "setting volume to %x:%x\n", left_vol, right_vol); */
+		sorbo_set_amp(sc, 0, 11, left_vol, right_vol);
+	}
 	
-	vol = left | (left << 8);
+	left_vol = left | (right << 8);
 
-	return vol;
+	return left_vol;
 }
 
 static int


More information about the freebsd-multimedia mailing list