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-mobile
mailing list