mbox series

[v2,0/4] ASoC platform driver for Apple MCA

Message ID 20220819125430.4920-1-povik+lin@cutebit.org
Headers show
Series ASoC platform driver for Apple MCA | expand

Message

Martin Povišer Aug. 19, 2022, 12:54 p.m. UTC
Hi all,

this is v2 of the ASoC platform driver for MCA peripheral on Apple M1,
to be followed by a machine driver later for sound support on the new
Apple devices. This time I attached a DTS patch for t8103 (M1), which
I guess should go through Marcan's (in CC) tree.

Martin

Changes since v1:
 - reflect the set_fmt provider/consumer change in 6.0-rc1
 - fix the probe function requesting optional reset
 - unroll 'dma-names' in schema
 - fix binding schema/code discrepancy in register ranges
 - minor things

Changes since 'macaudio RFC v2' [0]:
 - addition of locking (extra commit)
 - transition to set_bclk_ratio (instead of getting the bclk ratio from set_sysclk)
 - using shared reset control and documenting the reset in binding
 - formatting, comments, and a minor fix to hw driving

[0] https://lore.kernel.org/asahi/20220606191910.16580-1-povik+lin@cutebit.org/

Martin Povišer (4):
  dt-bindings: sound: Add Apple MCA I2S transceiver
  arm64: dts: apple: t8103: Add MCA and its support
  ASoC: apple: mca: Start new platform driver
  ASoC: apple: mca: Add locks on foreign cluster access

 .../devicetree/bindings/sound/apple,mca.yaml  |  131 ++
 MAINTAINERS                                   |    8 +
 arch/arm64/boot/dts/apple/t8103.dtsi          |   70 +
 sound/soc/Kconfig                             |    1 +
 sound/soc/Makefile                            |    1 +
 sound/soc/apple/Kconfig                       |    9 +
 sound/soc/apple/Makefile                      |    3 +
 sound/soc/apple/mca.c                         | 1170 +++++++++++++++++
 8 files changed, 1393 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/apple,mca.yaml
 create mode 100644 sound/soc/apple/Kconfig
 create mode 100644 sound/soc/apple/Makefile
 create mode 100644 sound/soc/apple/mca.c

Comments

Krzysztof Kozlowski Aug. 19, 2022, 1:12 p.m. UTC | #1
On 19/08/2022 15:54, Martin Povišer wrote:
> Add the MCA I2S transceiver node and its supporting NCO, ADMAC nodes.
> 
> Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
> ---
>  arch/arm64/boot/dts/apple/t8103.dtsi | 70 ++++++++++++++++++++++++++++
>  1 file changed, 70 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
> index 51a63b29d404..2dc3125aca5b 100644
> --- a/arch/arm64/boot/dts/apple/t8103.dtsi
> +++ b/arch/arm64/boot/dts/apple/t8103.dtsi
> @@ -532,6 +532,76 @@ port02: pci@2,0 {
>  						<0 0 0 4 &port02 0 0 0 3>;
>  			};
>  		};
> +
> +		dart_sio: iommu@235004000 {
> +			compatible = "apple,t8103-dart", "apple,dart";
> +			reg = <0x2 0x35004000 0x0 0x4000>;
> +			interrupt-parent = <&aic>;
> +			interrupts = <AIC_IRQ 635 IRQ_TYPE_LEVEL_HIGH>;
> +			#iommu-cells = <1>;
> +			power-domains = <&ps_sio_cpu>;
> +		};
> +
> +		nco_clkref: clock-ref {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <900000000>;
> +			clock-output-names = "nco_ref";
> +		};

Reference clocks are usually physically outside of SoC (e.g. on the
board), so:
1. Not part of "soc" node.
2. It should be defined by board. At least clock-frequency should be there.

> +
> +		nco: nco@23b044000 {
> +			compatible = "apple,t8103-nco", "apple,nco";
> +			reg = <0x2 0x3b044000 0x0 0x14000>;
> +			clocks = <&nco_clkref>;
> +			#clock-cells = <1>;
> +		};
> +
> +		admac: dma-controller@238200000 {
> +			compatible = "apple,t8103-admac", "apple,admac";
> +			reg = <0x2 0x38200000 0x0 0x34000>;
> +			dma-channels = <24>;
> +			interrupts-extended = <0>,
> +					      <&aic AIC_IRQ 626 IRQ_TYPE_LEVEL_HIGH>,
> +					      <0>,
> +					      <0>;
> +			#dma-cells = <1>;
> +			iommus = <&dart_sio 2>;
> +			power-domains = <&ps_sio_adma>;
> +		};
> +
> +		mca: mca@38400000 {

Here node name is as well wrong.

Node names should be generic.
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation



Best regards,
Krzysztof
Martin Povišer Aug. 19, 2022, 2:24 p.m. UTC | #2
> On 19. 8. 2022, at 15:12, Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
> On 19/08/2022 15:54, Martin Povišer wrote:
>> Add the MCA I2S transceiver node and its supporting NCO, ADMAC nodes.
>> 
>> Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
>> ---
>> arch/arm64/boot/dts/apple/t8103.dtsi | 70 ++++++++++++++++++++++++++++
>> 1 file changed, 70 insertions(+)
>> 
>> diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
>> index 51a63b29d404..2dc3125aca5b 100644
>> --- a/arch/arm64/boot/dts/apple/t8103.dtsi
>> +++ b/arch/arm64/boot/dts/apple/t8103.dtsi
>> @@ -532,6 +532,76 @@ port02: pci@2,0 {
>> 						<0 0 0 4 &port02 0 0 0 3>;
>> 			};
>> 		};
>> +
>> +		dart_sio: iommu@235004000 {
>> +			compatible = "apple,t8103-dart", "apple,dart";
>> +			reg = <0x2 0x35004000 0x0 0x4000>;
>> +			interrupt-parent = <&aic>;
>> +			interrupts = <AIC_IRQ 635 IRQ_TYPE_LEVEL_HIGH>;
>> +			#iommu-cells = <1>;
>> +			power-domains = <&ps_sio_cpu>;
>> +		};
>> +
>> +		nco_clkref: clock-ref {
>> +			compatible = "fixed-clock";
>> +			#clock-cells = <0>;
>> +			clock-frequency = <900000000>;
>> +			clock-output-names = "nco_ref";
>> +		};
> 
> Reference clocks are usually physically outside of SoC (e.g. on the
> board), so:
> 1. Not part of "soc" node.
> 2. It should be defined by board. At least clock-frequency should be there.

Ah, right, this deserves commentary: Since this is a reverse-engineered
driver/platform support, we give up on knowing the clock tree exactly. Instead
we model the clock input to the Numerically Controlled Oscillator (‘nco’ node
below) with this fabulated fixed clock reference.

I guess eventually the clock tree is rooted off the SoC, and there’s
nothing guaranteeing the same reference clock to the NCO across machines (being
function of the board wiring and the proprietary firmware). In the end I would
argue for keeping the ‘clock-ref’ here in ’soc' but have the clock-frequency
defined by board.  Sounds reasonable?

> 
>> +
>> +		nco: nco@23b044000 {
>> +			compatible = "apple,t8103-nco", "apple,nco";
>> +			reg = <0x2 0x3b044000 0x0 0x14000>;
>> +			clocks = <&nco_clkref>;
>> +			#clock-cells = <1>;
>> +		};
>> +
>> +		admac: dma-controller@238200000 {
>> +			compatible = "apple,t8103-admac", "apple,admac";
>> +			reg = <0x2 0x38200000 0x0 0x34000>;
>> +			dma-channels = <24>;
>> +			interrupts-extended = <0>,
>> +					 <&aic AIC_IRQ 626 IRQ_TYPE_LEVEL_HIGH>,
>> +					 <0>,
>> +					 <0>;
>> +			#dma-cells = <1>;
>> +			iommus = <&dart_sio 2>;
>> +			power-domains = <&ps_sio_adma>;
>> +		};
>> +
>> +		mca: mca@38400000 {
> 
> Here node name is as well wrong.
> 
> Node names should be generic.
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation

OK

Best, Martin

> 
> Best regards,
> Krzysztof
Mark Brown Aug. 22, 2022, 5:39 p.m. UTC | #3
On Fri, Aug 19, 2022 at 02:54:29PM +0200, Martin Povišer wrote:

This all looks good, one style nit and a couple of requests for
clarification below but basically this is fine.

> +++ b/sound/soc/apple/mca.c
> @@ -0,0 +1,1149 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Apple SoCs MCA driver
> + *
> + * Copyright (C) The Asahi Linux Contributors
> + *
> + * The MCA peripheral is made up of a number of identical units called clusters.

Please make the entire comment block a C++ one so things look more
intentional.

> +#define USE_RXB_FOR_CAPTURE

What's this all about?

> +static int mca_fe_enable_clocks(struct mca_cluster *cl)
> +{
> +	struct mca_data *mca = cl->host;
> +	int ret;
> +
> +	ret = clk_prepare_enable(cl->clk_parent);
> +	if (ret) {
> +		dev_err(mca->dev,
> +			"cluster %d: unable to enable clock parent: %d\n",
> +			cl->no, ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * We can't power up the device earlier than this because
> +	 * the power state driver would error out on seeing the device
> +	 * as clock-gated.
> +	 */
> +	cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
> +				      DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
> +					      DL_FLAG_RPM_ACTIVE);

I'm not clear on this dynamically adding and removing device links stuff
- it looks like the main (only?) purpose is to take a runtime PM
reference to the target device which is fine but it's not clear why
device links are involved given that the links are created and destroyed
every time the DAI is used, AFAICT always in the same fixed
relationship.  It's not a problem, it's just unclear.
Mark Brown Aug. 22, 2022, 5:45 p.m. UTC | #4
On Fri, Aug 19, 2022 at 02:54:30PM +0200, Martin Povišer wrote:
> In DAI ops, accesses to the native cluster (of the DAI), and to data of
> clusters related to it by a DPCM frontend-backend link, should have
> been synchronized by the 'pcm_mutex' lock at ASoC level.
> 
> What is not covered are the 'port_driver' accesses on foreign clusters
> to which the current cluster has no a priori relation, so fill in
> locking for that. (This should only matter in bizarre configurations of
> sharing one MCA peripheral between ASoC cards.)

This also looks good.
Martin Povišer Aug. 23, 2022, 7:33 a.m. UTC | #5
> On 22. 8. 2022, at 19:39, Mark Brown <broonie@kernel.org> wrote:
> 
> On Fri, Aug 19, 2022 at 02:54:29PM +0200, Martin Povišer wrote:
> 
> This all looks good, one style nit and a couple of requests for
> clarification below but basically this is fine.
> 
>> +++ b/sound/soc/apple/mca.c
>> @@ -0,0 +1,1149 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Apple SoCs MCA driver
>> + *
>> + * Copyright (C) The Asahi Linux Contributors
>> + *
>> + * The MCA peripheral is made up of a number of identical units called clusters.
> 
> Please make the entire comment block a C++ one so things look more
> intentional.

Is this so that it does not look like the SPDX header was added
mechanically? I will do it, just curious what the reasoning is.

> 
>> +#define USE_RXB_FOR_CAPTURE
> 
> What's this all about?

There’s something we can configure one way or the other way in the
hardware (choosing RXA or RXB unit in a cluster for capture). Since this 
driver developed along reverse-engineering the hardware, this switch
got built in. I want to keep it for future experimentation. Also, as
the driver’s side gig is documenting the hardware, this way it
documents more.

>> +static int mca_fe_enable_clocks(struct mca_cluster *cl)
>> +{
>> +	struct mca_data *mca = cl->host;
>> +	int ret;
>> +
>> +	ret = clk_prepare_enable(cl->clk_parent);
>> +	if (ret) {
>> +		dev_err(mca->dev,
>> +			"cluster %d: unable to enable clock parent: %d\n",
>> +			cl->no, ret);
>> +		return ret;
>> +	}
>> +
>> +	/*
>> +	 * We can't power up the device earlier than this because
>> +	 * the power state driver would error out on seeing the device
>> +	 * as clock-gated.
>> +	 */
>> +	cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
>> +				      DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
>> +					      DL_FLAG_RPM_ACTIVE);
> 
> I'm not clear on this dynamically adding and removing device links stuff
> - it looks like the main (only?) purpose is to take a runtime PM
> reference to the target device which is fine but it's not clear why
> device links are involved given that the links are created and destroyed
> every time the DAI is used, AFAICT always in the same fixed
> relationship.  It's not a problem, it's just unclear.

Indeed the only purpose is powering up the cluster’s power domain (there’s
one domain for each cluster). Adding the links is the only way I know to
do it. They need to be added dynamically (as opposed to statically linking,
say, the DAI’s ->dev to the cluster’s ->pd_dev, which I guess may do
something similar), because we need to sequence the power-up/power-down
with the enablement of the clocks.

Martin
Krzysztof Kozlowski Aug. 23, 2022, 11:02 a.m. UTC | #6
On 19/08/2022 17:24, Martin Povišer wrote:
> 
> 
>> On 19. 8. 2022, at 15:12, Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
>>
>> On 19/08/2022 15:54, Martin Povišer wrote:
>>> Add the MCA I2S transceiver node and its supporting NCO, ADMAC nodes.
>>>
>>> Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
>>> ---
>>> arch/arm64/boot/dts/apple/t8103.dtsi | 70 ++++++++++++++++++++++++++++
>>> 1 file changed, 70 insertions(+)
>>>
>>> diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
>>> index 51a63b29d404..2dc3125aca5b 100644
>>> --- a/arch/arm64/boot/dts/apple/t8103.dtsi
>>> +++ b/arch/arm64/boot/dts/apple/t8103.dtsi
>>> @@ -532,6 +532,76 @@ port02: pci@2,0 {
>>> 						<0 0 0 4 &port02 0 0 0 3>;
>>> 			};
>>> 		};
>>> +
>>> +		dart_sio: iommu@235004000 {
>>> +			compatible = "apple,t8103-dart", "apple,dart";
>>> +			reg = <0x2 0x35004000 0x0 0x4000>;
>>> +			interrupt-parent = <&aic>;
>>> +			interrupts = <AIC_IRQ 635 IRQ_TYPE_LEVEL_HIGH>;
>>> +			#iommu-cells = <1>;
>>> +			power-domains = <&ps_sio_cpu>;
>>> +		};
>>> +
>>> +		nco_clkref: clock-ref {
>>> +			compatible = "fixed-clock";
>>> +			#clock-cells = <0>;
>>> +			clock-frequency = <900000000>;
>>> +			clock-output-names = "nco_ref";
>>> +		};
>>
>> Reference clocks are usually physically outside of SoC (e.g. on the
>> board), so:
>> 1. Not part of "soc" node.
>> 2. It should be defined by board. At least clock-frequency should be there.
> 
> Ah, right, this deserves commentary: Since this is a reverse-engineered
> driver/platform support, we give up on knowing the clock tree exactly. Instead
> we model the clock input to the Numerically Controlled Oscillator (‘nco’ node
> below) with this fabulated fixed clock reference.
> 
> I guess eventually the clock tree is rooted off the SoC, and there’s
> nothing guaranteeing the same reference clock to the NCO across machines (being
> function of the board wiring and the proprietary firmware). In the end I would
> argue for keeping the ‘clock-ref’ here in ’soc' but have the clock-frequency
> defined by board.  Sounds reasonable?

Yes.

Best regards,
Krzysztof
Mark Brown Aug. 23, 2022, 11:31 a.m. UTC | #7
On Tue, Aug 23, 2022 at 09:33:36AM +0200, Martin Povišer wrote:
> > On 22. 8. 2022, at 19:39, Mark Brown <broonie@kernel.org> wrote:
> > On Fri, Aug 19, 2022 at 02:54:29PM +0200, Martin Povišer wrote:

> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +/*
> >> + * Apple SoCs MCA driver
> >> + *
> >> + * Copyright (C) The Asahi Linux Contributors
> >> + *
> >> + * The MCA peripheral is made up of a number of identical units called clusters.

> > Please make the entire comment block a C++ one so things look more
> > intentional.

> Is this so that it does not look like the SPDX header was added
> mechanically? I will do it, just curious what the reasoning is.

Yes, broadly.

> >> +	/*
> >> +	 * We can't power up the device earlier than this because
> >> +	 * the power state driver would error out on seeing the device
> >> +	 * as clock-gated.
> >> +	 */
> >> +	cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
> >> +				      DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
> >> +					      DL_FLAG_RPM_ACTIVE);

> > I'm not clear on this dynamically adding and removing device links stuff
> > - it looks like the main (only?) purpose is to take a runtime PM
> > reference to the target device which is fine but it's not clear why
> > device links are involved given that the links are created and destroyed
> > every time the DAI is used, AFAICT always in the same fixed
> > relationship.  It's not a problem, it's just unclear.

> Indeed the only purpose is powering up the cluster’s power domain (there’s
> one domain for each cluster). Adding the links is the only way I know to
> do it. They need to be added dynamically (as opposed to statically linking,
> say, the DAI’s ->dev to the cluster’s ->pd_dev, which I guess may do
> something similar), because we need to sequence the power-up/power-down
> with the enablement of the clocks.

You could also just do the underlying runtime power management
operations directly couldn't you?  It's not clear what the device link
stuff is adding.
Martin Povišer Aug. 23, 2022, 11:51 a.m. UTC | #8
> On 23. 8. 2022, at 13:31, Mark Brown <broonie@kernel.org> wrote:
> 
> On Tue, Aug 23, 2022 at 09:33:36AM +0200, Martin Povišer wrote:
>>> On 22. 8. 2022, at 19:39, Mark Brown <broonie@kernel.org> wrote:
>>> On Fri, Aug 19, 2022 at 02:54:29PM +0200, Martin Povišer wrote:

>>>> +	/*
>>>> +	 * We can't power up the device earlier than this because
>>>> +	 * the power state driver would error out on seeing the device
>>>> +	 * as clock-gated.
>>>> +	 */
>>>> +	cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
>>>> +				      DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
>>>> +					      DL_FLAG_RPM_ACTIVE);
> 
>>> I'm not clear on this dynamically adding and removing device links stuff
>>> - it looks like the main (only?) purpose is to take a runtime PM
>>> reference to the target device which is fine but it's not clear why
>>> device links are involved given that the links are created and destroyed
>>> every time the DAI is used, AFAICT always in the same fixed
>>> relationship.  It's not a problem, it's just unclear.
> 
>> Indeed the only purpose is powering up the cluster’s power domain (there’s
>> one domain for each cluster). Adding the links is the only way I know to
>> do it. They need to be added dynamically (as opposed to statically linking,
>> say, the DAI’s ->dev to the cluster’s ->pd_dev, which I guess may do
>> something similar), because we need to sequence the power-up/power-down
>> with the enablement of the clocks.
> 
> You could also just do the underlying runtime power management
> operations directly couldn't you?  It's not clear what the device link
> stuff is adding.

This seems to be the way to do it. Quoting from documentation of
dev_pm_domain_attach_by_id, by which we obtain the mca->dev and cl->pd_dev
the link is between:

 * This function should typically be invoked by a driver during the probe phase,
 * in case its device requires power management through multiple PM domains. The
 * driver may benefit from using the received device, to configure device-links
 * towards its original device. Depending on the use-case and if needed, the
 * links may be dynamically changed by the driver, which allows it to control
 * the power to the PM domains independently from each other.

--
Martin
Martin Povišer Aug. 23, 2022, 11:53 a.m. UTC | #9
> On 23. 8. 2022, at 13:51, Martin Povišer <povik+lin@cutebit.org> wrote:
> 
> 
> 
>> On 23. 8. 2022, at 13:31, Mark Brown <broonie@kernel.org> wrote:
>> 
>> On Tue, Aug 23, 2022 at 09:33:36AM +0200, Martin Povišer wrote:
>>>> On 22. 8. 2022, at 19:39, Mark Brown <broonie@kernel.org> wrote:
>>>> On Fri, Aug 19, 2022 at 02:54:29PM +0200, Martin Povišer wrote:
> 
>>>>> +	/*
>>>>> +	 * We can't power up the device earlier than this because
>>>>> +	 * the power state driver would error out on seeing the device
>>>>> +	 * as clock-gated.
>>>>> +	 */
>>>>> +	cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
>>>>> +				 DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
>>>>> +					 DL_FLAG_RPM_ACTIVE);
>> 
>>>> I'm not clear on this dynamically adding and removing device links stuff
>>>> - it looks like the main (only?) purpose is to take a runtime PM
>>>> reference to the target device which is fine but it's not clear why
>>>> device links are involved given that the links are created and destroyed
>>>> every time the DAI is used, AFAICT always in the same fixed
>>>> relationship. It's not a problem, it's just unclear.
>> 
>>> Indeed the only purpose is powering up the cluster’s power domain (there’s
>>> one domain for each cluster). Adding the links is the only way I know to
>>> do it. They need to be added dynamically (as opposed to statically linking,
>>> say, the DAI’s ->dev to the cluster’s ->pd_dev, which I guess may do
>>> something similar), because we need to sequence the power-up/power-down
>>> with the enablement of the clocks.
>> 
>> You could also just do the underlying runtime power management
>> operations directly couldn't you? It's not clear what the device link
>> stuff is adding.
> 
> This seems to be the way to do it. Quoting from documentation of
> dev_pm_domain_attach_by_id, by which we obtain the mca->dev and cl->pd_dev
> the link is between:
> 
> * This function should typically be invoked by a driver during the probe phase,
> * in case its device requires power management through multiple PM domains. The
> * driver may benefit from using the received device, to configure device-links
> * towards its original device. Depending on the use-case and if needed, the
> * links may be dynamically changed by the driver, which allows it to control
> * the power to the PM domains independently from each other.
> 
> --
> Martin

Pardon, just the cl->pd_dev is from dev_pm_domain_attach_by_id, mca->dev is
the original device.

Martin