Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing Topology 2.0 #2

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open

Introducing Topology 2.0 #2

wants to merge 33 commits into from

Conversation

ranj063
Copy link
Collaborator

@ranj063 ranj063 commented Mar 11, 2021

alsatplg parser support for thesofproject/sof#3211

Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really great work. I think the firts patch probably needs split and it's probably benefition to show the config you are adding in the commit message (as a example is always helpful).

src/topology/channel.c Show resolved Hide resolved

/* type-specific control lists */
struct list_head mixer_list;
struct list_head enum_list;
struct list_head bytes_ext_list;
};


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be deleted.

@@ -288,7 +292,6 @@ int tplg_parse_dai(snd_tplg_t *tplg, snd_config_t *cfg, void *priv);
int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg, void *priv);
int tplg_parse_cc(snd_tplg_t *tplg, snd_config_t *cfg, void *priv);
int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, void *priv);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@@ -766,6 +766,7 @@ enum snd_tplg_type {
SND_TPLG_TYPE_LINK, /*!< Physical DAI link */
SND_TPLG_TYPE_HW_CONFIG, /*!< Link HW config */
SND_TPLG_TYPE_DAI, /*!< Physical DAI */
SND_TPLG_TYPE_CLASS, /*!< Class */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is class sent as a ABI object ? I think this is for ABI types only ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also my be worth an example class def in your commit message.

src/topology/class.c Show resolved Hide resolved
!attr->found) {
SNDERR("Mandatory immutable attribute '%s' not provide for class '%s'",
attr->name, class->name);
return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, do we have the full attribute name here i.e. so we can figure out th elocation of the error ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if not, we can add a TODO: to these.

return class_map[i].id;
}

return -EINVAL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"can't find class X" error would be useful ?

Expose the lookup_channel() so that it can be reused
in topology2.0.

Signed-off-by: Ranjani Sridharan <[email protected]>
@ranj063
Copy link
Collaborator Author

ranj063 commented Mar 23, 2021

@lgirdwood @perexg this PR is now ready for review. Its a lot of commits but the changes are incremental and reasonably well documented. Let me know what you think.

@ranj063 ranj063 requested a review from lgirdwood March 23, 2021 01:08
Split the logic for parsing each hw_config parameter
into a separate function tplg_set_hw_config_param()
and expose it so that they can be reused in topology2.0.

Signed-off-by: Ranjani Sridharan <[email protected]>
Expose the tplg_parse_pcm_param(), tplg_parse_link_param()
tplg_parse_stream_caps_param() functions for parsing the
PCM params, link params and PCM capabilities. These will be
reused in Topology2.0.

Signed-off-by: Ranjani Sridharan <[email protected]>
This will be reused in topology2.0

Signed-off-by: Ranjani Sridharan <[email protected]>
Expose some functions needed for parsing mixer
and byte controls. These will be reused for topology2.0.

Signed-off-by: Ranjani Sridharan <[email protected]>
Expose multiple functions that will be reused to parse
tuples and private data in Topology2.0.

Signed-off-by: Ranjani Sridharan <[email protected]>
Split the widget param parser and expose the function
to be reuse for Topology2.0.

Signed-off-by: Ranjani Sridharan <[email protected]>
Add 2 new fields to struct tplg_tuple_set.
The token_ref field will be used to save the reference
to the token set name. And the list elem will be used
to add the tuple_sets to a list of tuples sets that
will be created in Topology2.0.

Signed-off-by: Ranjani Sridharan <[email protected]>
Topology 2.0 will introduce a new element named object.
In preparation for that, replave the references to object
with element where applicable.

Signed-off-by: Ranjani Sridharan <[email protected]>
Topology today has some common classes that are often reused
throughout with slightly altered configurations
i.e. widgets (components), pipelines, dais and controls.

This PR introduces the high level concept of reusable "class" like
definitions that can be used to create topology objects e.g.
Class.Component - Class for widgets that can be included within
Class.Pipeline. Class definitions typically contain arguments
and attributes. It also adds support for creating a new
class topology element and saving it to the class_list. This
will be used as the template when creating objects of this
class type.

A class typically consists of arguments and attributes. Arguments
and attributes both refer to parameters associated with the class
or its object. The difference is that the arguments are also used
for naming the object.

For ex:, a simple class definition would be

Class.Base."data" {

	DefineArgument."name" {
		type	"string"
	}

	DefineArgument."index" {}

	DefineAttribute."bytes" {}
}

The argument "name" would be used to build the name of the data
object as "data.<name>.<index>".

When parsing the class definition, the arguments and attributes
are stored as part of the attribute_list in struct tplg_class.
Ad attribute/argument can have values that can be of type
integer, long, double or a string.

Signed-off-by: Ranjani Sridharan <[email protected]>
Attributes/arguments in a class could refer to tuple
values that need to be added to the private data.
Add a field called token_ref to struct tplg_attribute
stores the name of SectionVendorTokens and the tuple type
that will be used to build the tuple value for the attribute.
For ex: "sof_tkn_dai.word" refers to the SectionVendorTokens
with the name "sof_tkn_dai" and "word" refers to the tuple
type.

Signed-off-by: Ranjani Sridharan <[email protected]>
One of the main advantages with Topology2.0 is the
ability to validate the types and values for
the arguments and attributes for a class instance.
Add the constraint field for struct tplg_attribute that
will be used to parse and save the constraints
specified for the attribute/argument in the class definition.

Typical constraints include min/max value or a set
of valid values allowed for the attribute. The set
of valid values can also be translated from a string value
to an integer value during topology build.

An example for attribute constraint would be:
DefineAttribute."direction" {
		token_ref	"sof_tkn_dai.word"
		constraints {
			value_ref       "sof_tkn_direction"
			values [
				"playback"
				"capture"
			]
		}
}

where the value_ref "sof_tkn_direction" would translate the values
as follows:
SectionVendorTokens."sof_tkn_direction" {
	playback	"0"
	capture	"1"
}

Signed-off-by: Ranjani Sridharan <[email protected]>
Class definitions may also provide default values
for some attributes. Parse and save these values.
Attributes/arguments that have constraints are validated
against the set constraints. The following example shows
a class definition with default attribute values:

Class.Base."hw_config" {
	#
	# Argument used to construct hw config (hw config ID)
	#
	DefineArgument."id" {}

	DefineAttribute."format" {
		constraints {
			values [
				"I2S"
				"DSP_A"
				"DSP_B"
			]
		}
	}

	DefineAttribute."mclk" {}

	DefineAttribute."mclk_freq" {}

	DefineAttribute."bclk" {}

	DefineAttribute."bclk_freq" {}

	DefineAttribute."fsync" {}

	DefineAttribute."fsync_freq" {}

	DefineAttribute."tdm_slots" {}

	DefineAttribute."tdm_slot_width" {}

	DefineAttribute."tx_slots" {}

	DefineAttribute."rx_slots" {}

	format		"I2S"
	mclk		"codec_mclk_in"
	bclk		"codec_consumer"
	fsync		"codec_consumer"
	fsync_freq	48000
	tdm_slots	2
	tx_slots	3
	rx_slots	3
}

Signed-off-by: Ranjani Sridharan <[email protected]>
Another type of constraint the attributes can have is whether
their value is immutable (fixed in class definition),
mandatory, automatic or deprecated. Class definitions categorize
attributes by specifying the attribute name in the
attributes.mandatory/immutable/deprecated array. An example
for this is:
	attributes {
		mandatory [
			"no_pm"
			"uuid"
			"widget_type"
		]
		immutable [
			"uuid"
		]
		automatic [
			"stream_name"
		]
		deprecated [
			"preload_count"
		]
	}

Signed-off-by: Ranjani Sridharan <[email protected]>
The Object keyword is used to instantiate a class.
When an object is instantiated, it must be provided
with arguments and mandatory attributes. Example
object instantiation:

	Object.host."N" {
		direction		"playback"
		period_sink_count	2
		period_source_count	0
		widget_type		"aif_in"
	}
where 'N' is a unique identifier for this object in the
parent alsaconf node. For objects that have an index
attribute, this value is copied to the index attribute
by the compiler.

The default attributes values for a class are copied
over to the object when the object is created.
But these will be overriden when they are explictly
set during object instantation as above.

Signed-off-by: Ranjani Sridharan <[email protected]>
Apart from attributes, arguments and constraints, a
class definition could also include child objects.
Parse these child objects and save them in the class'
object_list.

An example of this would be a PGA widget class with 2
mixer controls as follows:
Class.Component."pga" {
	/* PGA arguments and attribute definitions (not shown) */

	Object.mixer."0" {
		name	"Master Playback Volume"
	}

	Object.mixer."1" {
		name	"Mute Switch"
	}

	/* PGA default values(not shown) */
}

Signed-off-by: Ranjani Sridharan <[email protected]>
When creating an object, also copy all the child objects that
the class definitions may include. This has to be done
recursively until all the child objects within objects are
copied.

Signed-off-by: Ranjani Sridharan <[email protected]>
Just like classes, objects can have other objects when
they are instantiated. Parse these(recursively) and add them
to the object's object_list. For ex: mixer objects could have
child objects for specifying the ops, channels, tlv etc.
           Object.mixer."0" {
                    #Channel register and shift for Front Left/Right
                    Object.channel."0" {
                            name    "fl"
                            shift   0
                    }
                    Object.channel."1" {
                            name    "fr"
                    }

                    Object.tlv."0" {
                            name    "vtlv_m64s2"
                            Object.scale."0" {
                                    name    "m64s2"
                                    mute    1
                            }
                    }

                    Object.ops."0" {
                            name    "ctl"
                            info "volsw"
                            alsa-project#256 binds the mixer control to volume get/put handlers
                            get 256
                            put 256
                    }
            }

Signed-off-by: Ranjani Sridharan <[email protected]>
Add a couple of helper functions to look up objects
within a prent's object_list or the global topology
object list based on class_name and the value for
the unique attribute in the class.

Signed-off-by: Ranjani Sridharan <[email protected]>
One of the key features of Topology2.0 is the concept
of inheriting object attribute values from parent
attribute values. Inheritance is implicit when an attribute
in a child object shares the same name as an attribute
in the parent object. When creating an object, make sure
to pass down the attribute values to all its child objects
recursively.

Alternatively, a parent object can also explictly set
an attribute for its child object by using the
object's class name and index attribute as follows:

Object.volume-playback."1" {
	pipeline_id	1
	pcm_id		0
	pcm_name	"Port0"
	format		"s24le"

	# Set value for mixer.0 in pga.0
	pga.0.mixer.0.name "1 Master Playback Volume"
}

The last line in the above object instance, sets the
mixer name for the mixer object with index 0 in the
PGA object with index 0 in the volume-playback object.

As a rule of thumb, the attribute value set for an object always
overrides inherited values from parent or the ones explicitly
set in the parent.

Signed-off-by: Ranjani Sridharan <[email protected]>
Once an object is created, the next step is to create
the topology element for the topology builder. This patch
adds support for build BASE type objects specifically for
manifest and data objects.

Before building the topology elements, the compiler
needs to ensure that all the mandatory attributes
have been provided. Also, if attributes have references
for valid values, they need to be translated to the
appropriate tuple value.

Signed-off-by: Ranjani Sridharan <[email protected]>
Many topology elements pack tuple data in their private
data. Iterate through the attribute list of an object
and build tuple sets for those attributes that have the
token_ref field set. Add a new field, tuple_set_list
to struct objects and add the tuple sets to the list.

Once the tuple_sets are built for an object, the compiler
scans the tuple sets against the provided token reference
and builds the private data array.

Signed-off-by: Ranjani Sridharan <[email protected]>
Add some commonly used Classes such as Component, DAI, Pipeline
PCM as pre-defined class types. Update the struct tplg_object
to include type-specific data based on class type for some
classes.

Signed-off-by: Ranjani Sridharan <[email protected]>
Add support for building DAPM widget/component type
class objects by creating the topology element
of type SND_TPLG_TYPE_DAPM_WIDGET and setting
the widget params based on the object attributes.

Signed-off-by: Ranjani Sridharan <[email protected]>
SND_TPLG_TYPE_DAPM_WIDGET type topology elements can
contaim kcontrols associated with them. Add support
for building the controls of type mixer/bytes when
building the widget. ENum control support will be addded
later.

Signed-off-by: Ranjani Sridharan <[email protected]>
Add support for SND_TPLG_TYPE_STREAM_CAPS and
SND_TPLG_TYPE_PCM type topology elements by
parsing the PCM class objects and their attributes.

Signed-off-by: Ranjani Sridharan <[email protected]>
Add support for building SND_TPLG_TYPE_BE type
topology elements by parsing the SND_TPLG_CLASS_TYPE_DAI
type objects and their attributes.

Signed-off-by: Ranjani Sridharan <[email protected]>
Sanity check while creating SND_TPLG_CLASS_TYPE_PIPELINE
type objects.

Signed-off-by: Ranjani Sridharan <[email protected]>
Add support for building SND_TPLG_TYPE_DAPM_GRAPH type
topology elements by pasring the objects of class
"connection" and their attributes.

Signed-off-by: Ranjani Sridharan <[email protected]>
Attributes have a constraint called
TPLG_CLASS_ATTRIBUTE_MASK_AUTOMATIC that allows
the values to be updated by the alsatplg compiler
when the object containing the attribute is
built. One example of an automatic attribute
is the "stream_name" attribute for "host"
and "copier" class objects. Add the logic to update the
stream name for such objects.

Signed-off-by: Ranjani Sridharan <[email protected]>
The buffer class's "size" attribute is an autmatic attribute.
It needs to computed using the pipeline attributes along with
some of the buffer object attributes. Add support for updating
it.

Signed-off-by: Ranjani Sridharan <[email protected]>
Endpoint class' "widget_name" attribute is an automatic attribute.
It's value should be set after resolving the object reference in
the "widget" attribute. If the "widget" attribute value does not
contain the "Object." prefix, its value is simply copied to the
widget_name attribute.

Signed-off-by: Ranjani Sridharan <[email protected]>
The source_widget and sink_widget attributes in
the connection class are automatic attributes.
Their values need to be updated based on the "source" and
"sink" attribute values.

Signed-off-by: Ranjani Sridharan <[email protected]>
Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ranj063 I think we are good to split up the PR and start upstreaming into alsa-lib.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants