Skip to content

Commit 2f7776d

Browse files
committed
drm: apple: audio: Avoid probe errors
Now that the DP audio driver is a component of the display sub-system probe errors will bring down the whole display initialization. To prevent that the audio driver must not fail. Allow delayed sound card initialization if the DMA controller is not ready, for example because the apple-sio module is missing (at all or just in the initeramfs). In the case apple-sio is available later provide as sysfs file "probe_snd_card" to trigger initialization. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 946fcad commit 2f7776d

1 file changed

Lines changed: 105 additions & 42 deletions

File tree

drivers/gpu/drm/apple/audio.c

Lines changed: 105 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct dcp_audio {
4242
unsigned int open_cookie;
4343

4444
struct mutex data_lock;
45+
bool dcp_connected; /// dcp status keep for delayed initialization
4546
bool connected;
4647
unsigned int connection_cookie;
4748

@@ -430,19 +431,8 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
430431
{
431432
struct snd_card *card = dcpaud->card;
432433
struct snd_pcm *pcm;
433-
struct dma_chan *chan;
434434
int ret;
435435

436-
chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx");
437-
if (IS_ERR_OR_NULL(chan)) {
438-
if (!chan)
439-
return -EINVAL;
440-
441-
dev_err(dcpaud->dev, "can't request audio TX DMA channel: %pE\n", chan);
442-
return PTR_ERR(chan);
443-
}
444-
dcpaud->chan = chan;
445-
446436
#define NUM_PLAYBACK 1
447437
#define NUM_CAPTURE 0
448438

@@ -453,7 +443,7 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
453443
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dcp_playback_ops);
454444
dcpaud->substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
455445
snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM,
456-
chan->device->dev, 1024 * 1024,
446+
dcpaud->chan->device->dev, 1024 * 1024,
457447
SIZE_MAX);
458448

459449
pcm->nonatomic = true;
@@ -463,12 +453,12 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
463453
return 0;
464454
}
465455

456+
/* expects to be called with data_lock locked and unlocks it */
466457
static void dcpaud_report_hotplug(struct dcp_audio *dcpaud, bool connected)
467458
{
468459
struct snd_pcm_substream *substream = dcpaud->substream;
469460

470-
mutex_lock(&dcpaud->data_lock);
471-
if (dcpaud->connected == connected) {
461+
if (!dcpaud->card || dcpaud->connected == connected) {
472462
mutex_unlock(&dcpaud->data_lock);
473463
return;
474464
}
@@ -504,6 +494,53 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud)
504494
strscpy(card->shortname, "Apple DisplayPort", sizeof(card->shortname));
505495
}
506496

497+
static int dcpaud_init_snd_card(struct dcp_audio *dcpaud)
498+
{
499+
int ret;
500+
struct dma_chan *chan;
501+
502+
chan = of_dma_request_slave_channel(dcpaud->dev->of_node, "tx");
503+
/* squelch dma channel request errors, the driver will try again alter */
504+
if (!chan) {
505+
dev_warn(dcpaud->dev, "audio TX DMA channel request failed\n");
506+
return 0;
507+
} else if (IS_ERR(chan)) {
508+
dev_warn(dcpaud->dev, "audio TX DMA channel request failed: %pE\n", chan);
509+
return 0;
510+
}
511+
dcpaud->chan = chan;
512+
513+
ret = snd_card_new(dcpaud->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
514+
THIS_MODULE, 0, &dcpaud->card);
515+
if (ret)
516+
return ret;
517+
518+
dcpaud_set_card_names(dcpaud);
519+
520+
ret = dcpaud_create_pcm(dcpaud);
521+
if (ret)
522+
goto err_free_card;
523+
524+
ret = dcpaud_create_chmap_ctl(dcpaud);
525+
if (ret)
526+
goto err_free_card;
527+
528+
ret = dcpaud_create_jack(dcpaud);
529+
if (ret)
530+
goto err_free_card;
531+
532+
ret = snd_card_register(dcpaud->card);
533+
if (ret)
534+
goto err_free_card;
535+
536+
return 0;
537+
err_free_card:
538+
dev_warn(dcpaud->dev, "Failed to initialize sound card: %d\n", ret);
539+
snd_card_free(dcpaud->card);
540+
dcpaud->card = NULL;
541+
return ret;
542+
}
543+
507544
#ifdef CONFIG_SND_DEBUG
508545
static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *name, void *base, size_t size)
509546
{
@@ -522,15 +559,59 @@ static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *nam
522559
void dcpaud_connect(struct platform_device *pdev, bool connected)
523560
{
524561
struct dcp_audio *dcpaud = platform_get_drvdata(pdev);
562+
563+
mutex_lock(&dcpaud->data_lock);
564+
565+
if (!dcpaud->chan) {
566+
int ret = dcpaud_init_snd_card(dcpaud);
567+
if (ret) {
568+
dcpaud->dcp_connected = connected;
569+
mutex_unlock(&dcpaud->data_lock);
570+
return;
571+
}
572+
}
525573
dcpaud_report_hotplug(dcpaud, connected);
526574
}
527575

528576
void dcpaud_disconnect(struct platform_device *pdev)
529577
{
530578
struct dcp_audio *dcpaud = platform_get_drvdata(pdev);
579+
580+
mutex_lock(&dcpaud->data_lock);
581+
582+
dcpaud->dcp_connected = false;
531583
dcpaud_report_hotplug(dcpaud, false);
532584
}
533585

586+
static ssize_t probe_snd_card_store(struct device *dev,
587+
struct device_attribute *attr,
588+
const char *buf, size_t count)
589+
{
590+
int ret;
591+
bool connected = false;
592+
struct dcp_audio *dcpaud = dev_get_drvdata(dev);
593+
594+
mutex_lock(&dcpaud->data_lock);
595+
596+
if (!dcpaud->chan) {
597+
ret = dcpaud_init_snd_card(dcpaud);
598+
if (ret)
599+
goto out_unlock;
600+
601+
connected = dcpaud->dcp_connected;
602+
if (connected) {
603+
dcpaud_report_hotplug(dcpaud, connected);
604+
goto out;
605+
}
606+
}
607+
out_unlock:
608+
mutex_unlock(&dcpaud->data_lock);
609+
out:
610+
return count;
611+
}
612+
613+
static const DEVICE_ATTR_WO(probe_snd_card);
614+
534615
static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data)
535616
{
536617
struct dcp_audio *dcpaud = dev_get_drvdata(dev);
@@ -553,46 +634,28 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data)
553634
dcp_pdev = of_find_device_by_node(dcp_node);
554635
of_node_put(dcp_node);
555636
if (!dcp_pdev) {
556-
dev_info(dev, "No DP/HDMI audio device not ready\n");
637+
dev_info(dev, "No DP/HDMI audio device, dcp not ready\n");
557638
return 0;
558639
}
559640
dcpaud->dcp_dev = &dcp_pdev->dev;
560641

561-
ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
562-
THIS_MODULE, 0, &dcpaud->card);
563-
if (ret)
564-
return ret;
565-
566-
dcpaud_set_card_names(dcpaud);
567-
568-
ret = dcpaud_create_pcm(dcpaud);
569-
if (ret)
570-
goto err_free_card;
571-
572-
ret = dcpaud_create_chmap_ctl(dcpaud);
573-
if (ret)
574-
goto err_free_card;
575-
576-
ret = dcpaud_create_jack(dcpaud);
577-
if (ret)
578-
goto err_free_card;
579-
580-
ret = snd_card_register(dcpaud->card);
581-
if (ret)
582-
goto err_free_card;
583-
584642
dcpaud_expose_debugfs_blob(dcpaud, "selected_cookie", &dcpaud->selected_cookie,
585643
sizeof(dcpaud->selected_cookie));
586644
dcpaud_expose_debugfs_blob(dcpaud, "elements", dcpaud->elements,
587645
DCPAUD_ELEMENTS_MAXSIZE);
588646
dcpaud_expose_debugfs_blob(dcpaud, "product_attrs", dcpaud->productattrs,
589647
DCPAUD_PRODUCTATTRS_MAXSIZE);
590648

591-
return 0;
649+
mutex_lock(&dcpaud->data_lock);
650+
/* ignore errors to prevent audio issues affecting the display side */
651+
dcpaud_init_snd_card(dcpaud);
652+
mutex_unlock(&dcpaud->data_lock);
592653

593-
err_free_card:
594-
snd_card_free(dcpaud->card);
595-
return ret;
654+
ret = device_create_file(dev, &dev_attr_probe_snd_card);
655+
if (ret)
656+
dev_info(dev, "creating force probe sysfs file failed: %d\n", ret);
657+
658+
return 0;
596659
}
597660

598661
static void dcpaud_comp_unbind(struct device *dev, struct device *main,

0 commit comments

Comments
 (0)