Skip to content

Commit 1538ac1

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 fcc3ea8 commit 1538ac1

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

@@ -428,19 +429,8 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
428429
{
429430
struct snd_card *card = dcpaud->card;
430431
struct snd_pcm *pcm;
431-
struct dma_chan *chan;
432432
int ret;
433433

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

@@ -451,7 +441,7 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
451441
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dcp_playback_ops);
452442
dcpaud->substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
453443
snd_pcm_set_managed_buffer(dcpaud->substream, SNDRV_DMA_TYPE_DEV_IRAM,
454-
chan->device->dev, 1024 * 1024,
444+
dcpaud->chan->device->dev, 1024 * 1024,
455445
SIZE_MAX);
456446

457447
pcm->nonatomic = true;
@@ -461,12 +451,12 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
461451
return 0;
462452
}
463453

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

468-
mutex_lock(&dcpaud->data_lock);
469-
if (dcpaud->connected == connected) {
459+
if (!dcpaud->card || dcpaud->connected == connected) {
470460
mutex_unlock(&dcpaud->data_lock);
471461
return;
472462
}
@@ -502,6 +492,53 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud)
502492
strcpy(card->shortname, "Apple DisplayPort");
503493
}
504494

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

526574
void dcpaud_disconnect(struct platform_device *pdev)
527575
{
528576
struct dcp_audio *dcpaud = platform_get_drvdata(pdev);
577+
578+
mutex_lock(&dcpaud->data_lock);
579+
580+
dcpaud->dcp_connected = false;
529581
dcpaud_report_hotplug(dcpaud, false);
530582
}
531583

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

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

589-
return 0;
647+
mutex_lock(&dcpaud->data_lock);
648+
/* ignore errors to prevent audio issues affecting the display side */
649+
dcpaud_init_snd_card(dcpaud);
650+
mutex_unlock(&dcpaud->data_lock);
590651

591-
err_free_card:
592-
snd_card_free(dcpaud->card);
593-
return ret;
652+
ret = device_create_file(dev, &dev_attr_probe_snd_card);
653+
if (ret)
654+
dev_info(dev, "creating force probe sysfs file failed: %d\n", ret);
655+
656+
return 0;
594657
}
595658

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

0 commit comments

Comments
 (0)