Skip to content

Commit be1d03e

Browse files
committed
Support HDMI audio on NVIDIA Tegra20
Merge series from Dmitry Osipenko <[email protected]>: This series revives Tegra20 S/PDIF driver which was upstreamed long time ago, but never was used. It also turns Tegra DRM HDMI driver into HDMI audio CODEC provider. Finally, HDMI audio is enabled in device-trees. For now the audio is enable only for Acer A500 tablet and Toshiba AC100 netbook because they're already supported by upstream, later on ASUS TF101 tablet will join them. I based S/PDIF patches on Arnd's Bergmann patch from a separate series [1] that removes obsolete slave_id. This eases merging of the patches by removing the merge conflict. This is a note for Mark Brown. I also based this series on top of power management series [2]. I.e. [2] should be applied first, otherwise "Add S/PDIF node to Tegra20 device-tree" patch should have merge conflict. This is a note for Thierry. [1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=273312 [2] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=274534 Changelog: v4: - Added patches that update multi_v7_defconfig with the enabled S/PDIF and APB DMA drivers. v3: - Renamed S/PDIF device-tree clocks as was suggested by Rob Herring. - Added r-bs and acks that were given by Rob Herring to v2. v2: - Corrected I2S yaml problem that was reported by the DT bot for v1 by removing the non-existent required clock-names property. - Removed assigned-clocks property from S/PDIF yaml since this property is now inherited from the clocks property. - Reordered the "tegra20: spdif: Set FIFO trigger level" patch, making it the first sound/soc patch in the series, like it was suggested by Mark Brown in the comment to v1. Also reworded commit message of this patch to *not* make it looks like it should be backported to stable kernels. Arnd Bergmann (1): ASoC: tegra20-spdif: stop setting slave_id Dmitry Osipenko (21): ASoC: dt-bindings: Add binding for Tegra20 S/PDIF ASoC: dt-bindings: tegra20-i2s: Convert to schema ASoC: dt-bindings: tegra20-i2s: Document new nvidia,fixed-parent-rate property dt-bindings: host1x: Document optional HDMI sound-dai-cells ASoC: tegra20: spdif: Set FIFO trigger level ASoC: tegra20: spdif: Support device-tree ASoC: tegra20: spdif: Improve driver's code ASoC: tegra20: spdif: Use more resource-managed helpers ASoC: tegra20: spdif: Reset hardware ASoC: tegra20: spdif: Support system suspend ASoC: tegra20: spdif: Filter out unsupported rates ASoC: tegra20: i2s: Filter out unsupported rates drm/tegra: hdmi: Unwind tegra_hdmi_init() errors drm/tegra: hdmi: Register audio CODEC on Tegra20 ARM: tegra_defconfig: Enable S/PDIF driver ARM: config: multi v7: Enable NVIDIA Tegra20 S/PDIF driver ARM: config: multi v7: Enable NVIDIA Tegra20 APB DMA driver ARM: tegra: Add S/PDIF node to Tegra20 device-tree ARM: tegra: Add HDMI audio graph to Tegra20 device-tree ARM: tegra: acer-a500: Enable S/PDIF and HDMI audio ARM: tegra: paz00: Enable S/PDIF and HDMI audio .../display/tegra/nvidia,tegra20-host1x.txt | 1 + .../bindings/sound/nvidia,tegra20-i2s.txt | 30 --- .../bindings/sound/nvidia,tegra20-i2s.yaml | 77 +++++++ .../bindings/sound/nvidia,tegra20-spdif.yaml | 85 ++++++++ .../boot/dts/tegra20-acer-a500-picasso.dts | 8 + arch/arm/boot/dts/tegra20-paz00.dts | 8 + arch/arm/boot/dts/tegra20.dtsi | 40 +++- arch/arm/configs/multi_v7_defconfig | 2 + arch/arm/configs/tegra_defconfig | 1 + drivers/gpu/drm/tegra/Kconfig | 3 + drivers/gpu/drm/tegra/hdmi.c | 168 +++++++++++++-- sound/soc/tegra/tegra20_i2s.c | 49 +++++ sound/soc/tegra/tegra20_spdif.c | 197 ++++++++++++------ sound/soc/tegra/tegra20_spdif.h | 1 + sound/soc/tegra/tegra_pcm.c | 6 + sound/soc/tegra/tegra_pcm.h | 1 + 16 files changed, 574 insertions(+), 103 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml -- 2.33.1
2 parents a92c1cd + bfa4671 commit be1d03e

File tree

25 files changed

+475
-150
lines changed

25 files changed

+475
-150
lines changed

Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/sound/nvidia,tegra20-i2s.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: NVIDIA Tegra20 I2S Controller
8+
9+
description: |
10+
The I2S Controller streams synchronous serial audio data between system
11+
memory and an external audio device. The controller supports the I2S Left
12+
Justified Mode, Right Justified Mode, and DSP mode formats.
13+
14+
maintainers:
15+
- Thierry Reding <[email protected]>
16+
- Jon Hunter <[email protected]>
17+
18+
properties:
19+
compatible:
20+
const: nvidia,tegra20-i2s
21+
22+
reg:
23+
maxItems: 1
24+
25+
resets:
26+
maxItems: 1
27+
28+
reset-names:
29+
const: i2s
30+
31+
interrupts:
32+
maxItems: 1
33+
34+
clocks:
35+
minItems: 1
36+
37+
dmas:
38+
minItems: 2
39+
40+
dma-names:
41+
items:
42+
- const: rx
43+
- const: tx
44+
45+
nvidia,fixed-parent-rate:
46+
description: |
47+
Specifies whether board prefers parent clock to stay at a fixed rate.
48+
This allows multiple Tegra20 audio components work simultaneously by
49+
limiting number of supportable audio rates.
50+
type: boolean
51+
52+
required:
53+
- compatible
54+
- reg
55+
- resets
56+
- reset-names
57+
- interrupts
58+
- clocks
59+
- dmas
60+
- dma-names
61+
62+
additionalProperties: false
63+
64+
examples:
65+
- |
66+
i2s@70002800 {
67+
compatible = "nvidia,tegra20-i2s";
68+
reg = <0x70002800 0x200>;
69+
interrupts = <45>;
70+
clocks = <&tegra_car 11>;
71+
resets = <&tegra_car 11>;
72+
reset-names = "i2s";
73+
dmas = <&apbdma 21>, <&apbdma 21>;
74+
dma-names = "rx", "tx";
75+
};
76+
77+
...
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/sound/nvidia,tegra20-spdif.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: NVIDIA Tegra20 S/PDIF Controller
8+
9+
description: |
10+
The S/PDIF controller supports both input and output in serial audio
11+
digital interface format. The input controller can digitally recover
12+
a clock from the received stream. The S/PDIF controller is also used
13+
to generate the embedded audio for HDMI output channel.
14+
15+
maintainers:
16+
- Thierry Reding <[email protected]>
17+
- Jon Hunter <[email protected]>
18+
19+
properties:
20+
compatible:
21+
const: nvidia,tegra20-spdif
22+
23+
reg:
24+
maxItems: 1
25+
26+
resets:
27+
maxItems: 1
28+
29+
interrupts:
30+
maxItems: 1
31+
32+
clocks:
33+
minItems: 2
34+
35+
clock-names:
36+
items:
37+
- const: out
38+
- const: in
39+
40+
dmas:
41+
minItems: 2
42+
43+
dma-names:
44+
items:
45+
- const: rx
46+
- const: tx
47+
48+
"#sound-dai-cells":
49+
const: 0
50+
51+
nvidia,fixed-parent-rate:
52+
description: |
53+
Specifies whether board prefers parent clock to stay at a fixed rate.
54+
This allows multiple Tegra20 audio components work simultaneously by
55+
limiting number of supportable audio rates.
56+
type: boolean
57+
58+
required:
59+
- compatible
60+
- reg
61+
- resets
62+
- interrupts
63+
- clocks
64+
- clock-names
65+
- dmas
66+
- dma-names
67+
- "#sound-dai-cells"
68+
69+
additionalProperties: false
70+
71+
examples:
72+
- |
73+
spdif@70002400 {
74+
compatible = "nvidia,tegra20-spdif";
75+
reg = <0x70002400 0x200>;
76+
interrupts = <77>;
77+
clocks = <&clk 99>, <&clk 98>;
78+
clock-names = "out", "in";
79+
resets = <&rst 10>;
80+
dmas = <&apbdma 3>, <&apbdma 3>;
81+
dma-names = "rx", "tx";
82+
#sound-dai-cells = <0>;
83+
};
84+
85+
...

drivers/dma/mmp_pdma.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -727,12 +727,6 @@ static int mmp_pdma_config_write(struct dma_chan *dchan,
727727

728728
chan->dir = direction;
729729
chan->dev_addr = addr;
730-
/* FIXME: drivers should be ported over to use the filter
731-
* function. Once that's done, the following two lines can
732-
* be removed.
733-
*/
734-
if (cfg->slave_id)
735-
chan->drcmr = cfg->slave_id;
736730

737731
return 0;
738732
}

drivers/dma/pxa_dma.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -909,13 +909,6 @@ static void pxad_get_config(struct pxad_chan *chan,
909909
*dcmd |= PXA_DCMD_BURST16;
910910
else if (maxburst == 32)
911911
*dcmd |= PXA_DCMD_BURST32;
912-
913-
/* FIXME: drivers should be ported over to use the filter
914-
* function. Once that's done, the following two lines can
915-
* be removed.
916-
*/
917-
if (chan->cfg.slave_id)
918-
chan->drcmr = chan->cfg.slave_id;
919912
}
920913

921914
static struct dma_async_tx_descriptor *

drivers/dma/qcom/qcom_adm.c

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/device.h>
99
#include <linux/dmaengine.h>
1010
#include <linux/dma-mapping.h>
11+
#include <linux/dma/qcom_adm.h>
1112
#include <linux/init.h>
1213
#include <linux/interrupt.h>
1314
#include <linux/io.h>
@@ -140,6 +141,8 @@ struct adm_chan {
140141

141142
struct adm_async_desc *curr_txd;
142143
struct dma_slave_config slave;
144+
u32 crci;
145+
u32 mux;
143146
struct list_head node;
144147

145148
int error;
@@ -379,8 +382,8 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan,
379382
return ERR_PTR(-EINVAL);
380383
}
381384

382-
crci = achan->slave.slave_id & 0xf;
383-
if (!crci || achan->slave.slave_id > 0x1f) {
385+
crci = achan->crci & 0xf;
386+
if (!crci || achan->crci > 0x1f) {
384387
dev_err(adev->dev, "invalid crci value\n");
385388
return ERR_PTR(-EINVAL);
386389
}
@@ -403,9 +406,7 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan,
403406
if (!async_desc)
404407
return ERR_PTR(-ENOMEM);
405408

406-
if (crci)
407-
async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ?
408-
ADM_CRCI_CTL_MUX_SEL : 0;
409+
async_desc->mux = achan->mux ? ADM_CRCI_CTL_MUX_SEL : 0;
409410
async_desc->crci = crci;
410411
async_desc->blk_size = blk_size;
411412
async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) +
@@ -488,10 +489,13 @@ static int adm_terminate_all(struct dma_chan *chan)
488489
static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)
489490
{
490491
struct adm_chan *achan = to_adm_chan(chan);
492+
struct qcom_adm_peripheral_config *config = cfg->peripheral_config;
491493
unsigned long flag;
492494

493495
spin_lock_irqsave(&achan->vc.lock, flag);
494496
memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config));
497+
if (cfg->peripheral_size == sizeof(config))
498+
achan->crci = config->crci;
495499
spin_unlock_irqrestore(&achan->vc.lock, flag);
496500

497501
return 0;
@@ -694,6 +698,45 @@ static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan,
694698
achan->vc.desc_free = adm_dma_free_desc;
695699
}
696700

701+
/**
702+
* adm_dma_xlate
703+
* @dma_spec: pointer to DMA specifier as found in the device tree
704+
* @ofdma: pointer to DMA controller data
705+
*
706+
* This can use either 1-cell or 2-cell formats, the first cell
707+
* identifies the slave device, while the optional second cell
708+
* contains the crci value.
709+
*
710+
* Returns pointer to appropriate dma channel on success or NULL on error.
711+
*/
712+
static struct dma_chan *adm_dma_xlate(struct of_phandle_args *dma_spec,
713+
struct of_dma *ofdma)
714+
{
715+
struct dma_device *dev = ofdma->of_dma_data;
716+
struct dma_chan *chan, *candidate = NULL;
717+
struct adm_chan *achan;
718+
719+
if (!dev || dma_spec->args_count > 2)
720+
return NULL;
721+
722+
list_for_each_entry(chan, &dev->channels, device_node)
723+
if (chan->chan_id == dma_spec->args[0]) {
724+
candidate = chan;
725+
break;
726+
}
727+
728+
if (!candidate)
729+
return NULL;
730+
731+
achan = to_adm_chan(candidate);
732+
if (dma_spec->args_count == 2)
733+
achan->crci = dma_spec->args[1];
734+
else
735+
achan->crci = 0;
736+
737+
return dma_get_slave_channel(candidate);
738+
}
739+
697740
static int adm_dma_probe(struct platform_device *pdev)
698741
{
699742
struct adm_device *adev;
@@ -838,8 +881,7 @@ static int adm_dma_probe(struct platform_device *pdev)
838881
goto err_disable_clks;
839882
}
840883

841-
ret = of_dma_controller_register(pdev->dev.of_node,
842-
of_dma_xlate_by_chan_id,
884+
ret = of_dma_controller_register(pdev->dev.of_node, adm_dma_xlate,
843885
&adev->common);
844886
if (ret)
845887
goto err_unregister_dma;

drivers/dma/sh/shdma-base.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -786,14 +786,6 @@ static int shdma_config(struct dma_chan *chan,
786786
if (!config)
787787
return -EINVAL;
788788

789-
/*
790-
* overriding the slave_id through dma_slave_config is deprecated,
791-
* but possibly some out-of-tree drivers still do it.
792-
*/
793-
if (WARN_ON_ONCE(config->slave_id &&
794-
config->slave_id != schan->real_slave_id))
795-
schan->real_slave_id = config->slave_id;
796-
797789
/*
798790
* We could lock this, but you shouldn't be configuring the
799791
* channel, while using it...

drivers/dma/sprd-dma.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -795,9 +795,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
795795
return dst_datawidth;
796796
}
797797

798-
if (slave_cfg->slave_id)
799-
schan->dev_id = slave_cfg->slave_id;
800-
801798
hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET;
802799

803800
/*

drivers/dma/tegra20-apb-dma.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,6 @@ static int tegra_dma_slave_config(struct dma_chan *dc,
343343
}
344344

345345
memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig));
346-
if (tdc->slave_id == TEGRA_APBDMA_SLAVE_ID_INVALID &&
347-
sconfig->device_fc) {
348-
if (sconfig->slave_id > TEGRA_APBDMA_CSR_REQ_SEL_MASK)
349-
return -EINVAL;
350-
tdc->slave_id = sconfig->slave_id;
351-
}
352346
tdc->config_init = true;
353347

354348
return 0;

0 commit comments

Comments
 (0)