new sound driver

6 messages, 2 authors, 2006-03-24 · open the first message on its own page

new sound driver

From: Johannes Berg <johannes@sipsolutions.net>
Date: 2006-03-22 09:35:43

Hi,

After considering the code a while I decided that snd-powermac needs to
be rewritten. Ok, kidding, I didn't need to look at the source for
long :)

So I started to rewrite snd-powermac as snd-aoa, which I currently keep
in a git tree at http://johannes.sipsolutions.net/snd-aoa.git/

I will need a bit of help, so this email is intended to solicit that,
and to get some input on what everyone else thinks about what I've been
doing in that code.

Let me start with a brief layout. To those I've talked about this
before: please read again -- I significantly changed what I'm doing.

Since Ben says that he wants to be able to handle really old stuff with
the new driver too, I first created a virtual 'soundbus'. This is in the
module 'soundbus', and doesn't yet have any functionality in itself but
providing the driver model bus object.
I then created an i2sbus module that grabs all i2s devices from the
macio bus, enumerates their children (i2s-a, i2s-b etc) and adds them to
the soundbus.
Obviously, we'll need to add more bus backends there.

Now enter snd-aoa: snd-aoa has a rather generic architecture where the
core just initialises plugin code for different ways to find sound codec
chips. Currently, only one way is implemented -- that is going off the
layout-id property. This part (snd-aoa-fabric-layout.c) is a soundbus
driver and attaches to all soundbus nodes that have a 'sound' child with
a 'layout-id' property that it knows about. The list is encoded in
snd-aoa-layouts.c.
Plan is to make the fabrics and the codecs into modules too, but this
isn't done at the moment. Shouldn't be too hard, and should probably be
done before writing any more fabrics or codecs.

Anyway, back to what happens. Now the fabric module detects a layout-id
that it can handle, so it then goes to instantiate the codecs. Right now
I only have an onyx codec there. It tries to attach to the i2c control
interface (using two methods, but for that refer to the code). Then the
codec creates the alsa mixer devices that it can handle, using some alsa
helper code (snd-aoa-alsa) that manages the alsa card object.

That's about it. It can mute/unmute and control the left/right volume,
so it might work if you use both this and snd-powermac...

I had planned to actually get sound output working last night, but that
didn't turn out since I ended up rewriting all the lower levels.

So let me just say what the immediate plan is:

Firstly, the soundbus objects need to be able to handle data
transmission. What I'm not too sure about is how the API should look
like. I'm thinking that since all objects there are actually sound
objects (well, there's the modem too, but it can get an alsa interface
too), the soundbus objects actually get to create the alsa pcm
interfaces, somehow helped by the codecs to select the valid rates and
formats. Or the codecs create the alsa pcm streams, but refer to
soundbus object functions for handling the actual data transfer. I'd
like to push as much of the interface into the soundbus object as
possible. At this point also the question of how to program the dbdma
engine best comes up. I really don't know, because I don't quite
understand the alsa pcm api.
In any case, I'm thinking of putting dbdma register stuff into the
soundbus module and adding dbdma data to struct soundbus_dev.

Actually, this isn't quite possible. On the newer machines where you
have two codecs on the same i2s bus, we need to have the layout fabric
create the one pcm stream and have it ask the codecs what it should
advertise. Then it needs to advertise the lowest common denominator of
the multiple codecs... (Or can alsa handle pcms that change their
supported rates/formats?) Then it refers to the soundbus functions for
actual data transmission.

Another thing that needs to be done is teach the layout-id fabric module
how to handle all the dozens of platform functions and publish those to
alsa that make sense to be set by the user (like line out select etc.).
Then also register the interrupt ones and handle them appropriately. The
codecs will need to be notified on changes/interrupts though, since in
some cases things need to be switched around there too. This is just a
matter of inventing the right way to find all of the functions...

Whee. I was going to write more but for one it is already long enough,
and I also forgot what I wanted to write :)

johannes

Re: new sound driver

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: 2006-03-22 21:50:47

On Wed, 2006-03-22 at 10:35 +0100, Johannes Berg wrote:
Firstly, the soundbus objects need to be able to handle data
transmission. What I'm not too sure about is how the API should look
like. I'm thinking that since all objects there are actually sound
objects (well, there's the modem too, but it can get an alsa interface
too), the soundbus objects actually get to create the alsa pcm
interfaces, somehow helped by the codecs to select the valid rates and
formats. Or the codecs create the alsa pcm streams, but refer to
soundbus object functions for handling the actual data transfer. I'd
like to push as much of the interface into the soundbus object as
possible. At this point also the question of how to program the dbdma
engine best comes up. I really don't know, because I don't quite
understand the alsa pcm api.
In any case, I'm thinking of putting dbdma register stuff into the
soundbus module and adding dbdma data to struct soundbus_dev.
that would make soundbus totally pmac specific, in which case you should
call it aoa-bus or something like that.

Regarding your previous question well... I think the soundbus can create
the pcm streams. Alsa has 2 levels: PCM objects and PCM substreams. We
need the former. Substreams are used when the harware has several
streams that are hw mixed to the same mixers which isn't the case with
apple layout. When we have multiple i2s busses, they are really
independant with separate codecs, frame rates & formats etc.. thus
separate PCM objects.

I think the sound bus should create the PCMs. Now I don't remember from
Alsa API but do we need to know the available rates in advance ? In that
case, we may want to have the bitmask provided by the fabric (from the
layout array for example).

I'm also not sure how Alsa handle changes there. For example, if you
plug a digital input, the entire bus where this input is has to be
clocked from that, thus limiting dynamically what rates/formats are
available. I'm not sure Alsa API can cope with that yet.
Actually, this isn't quite possible. On the newer machines where you
have two codecs on the same i2s bus, we need to have the layout fabric
create the one pcm stream and have it ask the codecs what it should
advertise. Then it needs to advertise the lowest common denominator of
the multiple codecs... (Or can alsa handle pcms that change their
supported rates/formats?) Then it refers to the soundbus functions for
actual data transmission.
The problem is that codec objects have to be created asynchronously
since they use asynchronous i2c discovery. Unless you instanciate them
all but simply mark them "offline" and then mark them "online" later
when the hardware actually shows up. That is fine except for .. topaz
where you need to access the hw to know the chip type, thus you can't
really know everything you need early enough (or maybe you can ...)
 
Another thing that needs to be done is teach the layout-id fabric module
how to handle all the dozens of platform functions and publish those to
alsa that make sense to be set by the user (like line out select etc.).
Then also register the interrupt ones and handle them appropriately. The
codecs will need to be notified on changes/interrupts though, since in
some cases things need to be switched around there too. This is just a
matter of inventing the right way to find all of the functions...

Whee. I was going to write more but for one it is already long enough,
and I also forgot what I wanted to write :)
Just sleep on it for now :) We definitely need a "core" module that
handles all of the gpio mess. ..

Ben.

Re: new sound driver

From: Johannes Berg <johannes@sipsolutions.net>
Date: 2006-03-23 17:13:47

On Thu, 2006-03-23 at 08:50 +1100, Benjamin Herrenschmidt wrote:
that would make soundbus totally pmac specific, in which case you should
call it aoa-bus or something like that.
Yeah, well, I just did it differently now with the dbdma stuff done by
the i2sbus objects.
Regarding your previous question well... I think the soundbus can create
the pcm streams. Alsa has 2 levels: PCM objects and PCM substreams. We
need the former. Substreams are used when the harware has several
streams that are hw mixed to the same mixers which isn't the case with
apple layout. When we have multiple i2s busses, they are really
independant with separate codecs, frame rates & formats etc.. thus
separate PCM objects.

I think the sound bus should create the PCMs. Now I don't remember from
Alsa API but do we need to know the available rates in advance ? In that
case, we may want to have the bitmask provided by the fabric (from the
layout array for example).
Right. I was still confused on the notion of PCM streams vs. objects.
Got that sorted out, and yes, it is creating pcm objects.
I'm also not sure how Alsa handle changes there. For example, if you
plug a digital input, the entire bus where this input is has to be
clocked from that, thus limiting dynamically what rates/formats are
available. I'm not sure Alsa API can cope with that yet.
Well, if we're unlucky the Alsa API must just return -EINVAL to users
trying to use other bitrates, if we're lucky then it copes better ;)
quoted
Actually, this isn't quite possible. On the newer machines where you
have two codecs on the same i2s bus, we need to have the layout fabric
create the one pcm stream and have it ask the codecs what it should
advertise. Then it needs to advertise the lowest common denominator of
the multiple codecs... (Or can alsa handle pcms that change their
supported rates/formats?) Then it refers to the soundbus functions for
actual data transmission.
The problem is that codec objects have to be created asynchronously
since they use asynchronous i2c discovery. Unless you instanciate them
all but simply mark them "offline" and then mark them "online" later
when the hardware actually shows up. That is fine except for .. topaz
where you need to access the hw to know the chip type, thus you can't
really know everything you need early enough (or maybe you can ...)
What I'm currently thinking of is creating one PCM per codec, and then
if you can't use them at the same time just forbid access to it.
 
Just sleep on it for now :) We definitely need a "core" module that
handles all of the gpio mess. ..
Yeah. Haven't even opened that can of worms yet...

johannes

Re: new sound driver

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: 2006-03-23 21:09:17

What I'm currently thinking of is creating one PCM per codec, and then
if you can't use them at the same time just forbid access to it.
No, it should really be one PCM per bus... I don't see why you would
prevent somebody from outputing on both digital and analog outputs at
the same time for example (the same data of course). One PCM = one
stream = one bus carrying the samples. All codecs on that bus whould be
set to the same settings of course. If one can't but the other can, just
mute the one that can't I suppose...

Also, Alsa does have some means of asynchronous notifyication of a state
change on a control (and calls you back later with some locking) though
I'm not too familiar with the details. You should ask on the list once
you have the basic dbdma stuff there :)
 
quoted
Just sleep on it for now :) We definitely need a "core" module that
handles all of the gpio mess. ..
Yeah. Haven't even opened that can of worms yet...

johannes

Re: new sound driver

From: Johannes Berg <johannes@sipsolutions.net>
Date: 2006-03-23 17:00:39

Obviously, I'm still collecting information. For future reference and
archiving, here's the contents of a file I just added to my code
describing how apple derives i2s clocks. Well, as far as I can see from
their code. 

Short description of the i2s clock derivation system Apple uses.


The i2s chip Apple uses has three available clocks: 18432000, 45158400 and
49152000 Hz. These are used to drive the codec's system clock as well as the
i2s transfer bus.

The clocks for these are derived as follows:
First, you need to know the sampling frequency you want to use, and the
system clock the codec requires. The pcm3052 (onyx) for example requires a
system clock of 256*sampling frequency.

Thus, you divide the clock source speed by the sampling frequency and then
the factor the codec chip requires. This is the 'mclk divisor'.
Now you can derive the system clock from the clock source by taking only
every 'mclk divisor' transition of the clock, and thus you get a system
clock of the required speed.

Next, you need to know the i2s bus speed wrt. the sampling frequency. For
Sony and I2S 32x serial formats, this is 32*sampling frequency, for the I2S
64x format it is 64*sampling frequency. Since the i2s wire clock is derived
from the system clock we have already derived from the clock source, you
need to put as 'sclk divisor' the factor between the system clock of the
codec and the bus clock, for example 256/32 (=8) if the codec is driven in
Sony mode.

For the 'sclk divisor' you have to take care that it is an even number or 1
or 3, other values cannot be represented to the i2s chip (see logic in
i2sbus.h).


With a codec system clock (MClk) of 256*sampling frequency, you can have the
following frequencies (in the range from 8KHz to 96KHz) depending on the
clock source you use:
18432000: 9000 12000 14400 18000 24000 36000 72000
45158400: 8820 9800 11025 12600 14700 17640 22050 29400 35280 44100 58800 88200
49152000: 8000 9600 12000 16000 19200 24000 32000 38400 48000 64000 96000
(this is exactly what we can do with the onyx chip)

to create this table use calc (debian package apcalc):
min=8000
max=96000
clock=49152000
factor=256
for (f=min;f<=max;f++) {
  if ((clock%f==0) && ((clock/f)%factor == 0)) {
    div = clock/f/factor ;
    n = ceil(div/2-1) ;
    if ((div==1||div==3||div==5||div==14||(2*(n+1)==div && n<0x1f))
       && (1))
      print f,
  }
}
print ''

Re: new sound driver

From: Johannes Berg <johannes@sipsolutions.net>
Date: 2006-03-24 11:37:38

On Wed, 2006-03-22 at 10:35 +0100, Johannes Berg wrote:
So I started to rewrite snd-powermac as snd-aoa, which I currently keep
in a git tree at http://johannes.sipsolutions.net/snd-aoa.git/
It's a bit hacky (but hopefully those hacks can be removed rather
easily) but it works now for the onyx based machines (powermac8,1, quad
powermac, last 15" powerbook and probably more if you add the layout id)

johannes
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help