Re: [PATCH RFC v2 0/2] Disable planes on blanked CRTC and enable on unblank
On 11/17/15 12:28, Daniel Vetter wrote: On Fri, Nov 13, 2015 at 05:53:13PM +0200, Jyri Sarha wrote: Since first RFC version: - Added "drm/atomic: Track drm_plane's active state"-patch We would need something like this to get rid off OMAPDSS somewhat messy runtime_resume code. How does this look, could this generic solution be refined to be acceptable for mainline, or should we start looking a local solution to omapdrm? One more comment besides what I've written in the older thread: You're not on latest drm-next, which has gained an active_only paramter to the plane commit helper. It might be best to discuss this topic on #dri-devel on freenode irc a bit. Thanks a lot for you comments! I just rebased my stuff on top the the latest drm-next. I think I need digest your earlier comments about drm_atomic_add_affected_planes etc. a bit before I can take advantage of any interactive communication. I'll try to follow those instruction first and see where it leads me. Thanks, Jyri Cheers, Daniel Jyri Sarha (2): drm/atomic: Track drm_plane's active state drm/atomic: Disable planes on blanked CRTC and enable on unblank drivers/gpu/drm/drm_atomic_helper.c | 82 + drivers/gpu/drm/drm_plane_helper.c | 10 + include/drm/drm_atomic_helper.h | 39 +- include/drm/drm_crtc.h | 2 + 4 files changed, 70 insertions(+), 63 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] clk: gpio: Get parent clk names already in of_gpio_clk_setup()
Get parent clk names already in of_gpio_clk_setup() and store the names in struct clk_gpio_delayed_register_data. of_clk_get_parent_name() can not be called in struct of_clk_provider's get() callback since it may make a recursive call to of_clk_get_from_provider() and this in turn tries to recursively lock of_clk_mutex. Signed-off-by: Jyri Sarha <jsa...@ti.com> Cc: Sergej Sawazki <c...@gmx.de> --- Something has changed in Linux mainline so that getting the clk parent names in struct of_clk_provider's get() callback does not work anymore. This patch should fix the problem. drivers/clk/clk-gpio.c | 33 + 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 10819e2..335322d 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -209,6 +209,8 @@ EXPORT_SYMBOL_GPL(clk_register_gpio_mux); struct clk_gpio_delayed_register_data { const char *gpio_name; + int num_parents; + const char **parent_names; struct device_node *node; struct mutex lock; struct clk *clk; @@ -222,8 +224,6 @@ static struct clk *of_clk_gpio_delayed_register_get( { struct clk_gpio_delayed_register_data *data = _data; struct clk *clk; - const char **parent_names; - int i, num_parents; int gpio; enum of_gpio_flags of_flags; @@ -248,26 +248,14 @@ static struct clk *of_clk_gpio_delayed_register_get( return ERR_PTR(gpio); } - num_parents = of_clk_get_parent_count(data->node); - - parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); - if (!parent_names) { - clk = ERR_PTR(-ENOMEM); - goto out; - } - - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(data->node, i); - - clk = data->clk_register_get(data->node->name, parent_names, - num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); + clk = data->clk_register_get(data->node->name, data->parent_names, + data->num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); if (IS_ERR(clk)) goto out; data->clk = clk; out: mutex_unlock(>lock); - kfree(parent_names); return clk; } @@ -296,11 +284,24 @@ static void __init of_gpio_clk_setup(struct device_node *node, unsigned gpio, bool active_low)) { struct clk_gpio_delayed_register_data *data; + const char **parent_names; + int i, num_parents; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return; + num_parents = of_clk_get_parent_count(node); + + parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + data->num_parents = num_parents; + data->parent_names = parent_names; data->node = node; data->gpio_name = gpio_name; data->clk_register_get = clk_register_get; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] clk: gpio: Get parent clk names already in of_gpio_clk_setup()
Get parent clk names already in of_gpio_clk_setup() and store the names in struct clk_gpio_delayed_register_data. of_clk_get_parent_name() can not be called in struct of_clk_provider's get() callback since it may make a recursive call to of_clk_get_from_provider() and this in turn tries to recursively lock of_clk_mutex. Signed-off-by: Jyri Sarha <jsa...@ti.com> Cc: Sergej Sawazki <c...@gmx.de> --- Something has changed in Linux mainline so that getting the clk parent names in struct of_clk_provider's get() callback does not work anymore. This patch should fix the problem. drivers/clk/clk-gpio.c | 33 + 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 10819e2..335322d 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -209,6 +209,8 @@ EXPORT_SYMBOL_GPL(clk_register_gpio_mux); struct clk_gpio_delayed_register_data { const char *gpio_name; + int num_parents; + const char **parent_names; struct device_node *node; struct mutex lock; struct clk *clk; @@ -222,8 +224,6 @@ static struct clk *of_clk_gpio_delayed_register_get( { struct clk_gpio_delayed_register_data *data = _data; struct clk *clk; - const char **parent_names; - int i, num_parents; int gpio; enum of_gpio_flags of_flags; @@ -248,26 +248,14 @@ static struct clk *of_clk_gpio_delayed_register_get( return ERR_PTR(gpio); } - num_parents = of_clk_get_parent_count(data->node); - - parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); - if (!parent_names) { - clk = ERR_PTR(-ENOMEM); - goto out; - } - - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(data->node, i); - - clk = data->clk_register_get(data->node->name, parent_names, - num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); + clk = data->clk_register_get(data->node->name, data->parent_names, + data->num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); if (IS_ERR(clk)) goto out; data->clk = clk; out: mutex_unlock(>lock); - kfree(parent_names); return clk; } @@ -296,11 +284,24 @@ static void __init of_gpio_clk_setup(struct device_node *node, unsigned gpio, bool active_low)) { struct clk_gpio_delayed_register_data *data; + const char **parent_names; + int i, num_parents; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return; + num_parents = of_clk_get_parent_count(node); + + parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); + if (!parent_names) + return; + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(node, i); + + data->num_parents = num_parents; + data->parent_names = parent_names; data->node = node; data->gpio_name = gpio_name; data->clk_register_get = clk_register_get; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v2 0/2] Disable planes on blanked CRTC and enable on unblank
Since first RFC version: - Added "drm/atomic: Track drm_plane's active state"-patch We would need something like this to get rid off OMAPDSS somewhat messy runtime_resume code. How does this look, could this generic solution be refined to be acceptable for mainline, or should we start looking a local solution to omapdrm? Jyri Sarha (2): drm/atomic: Track drm_plane's active state drm/atomic: Disable planes on blanked CRTC and enable on unblank drivers/gpu/drm/drm_atomic_helper.c | 82 + drivers/gpu/drm/drm_plane_helper.c | 10 + include/drm/drm_atomic_helper.h | 39 +- include/drm/drm_crtc.h | 2 + 4 files changed, 70 insertions(+), 63 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v2 1/2] drm/atomic: Track drm_plane's active state
Track drm_plane's active state with a new boolean in struct drm_plane_state. The patch replaces drm_atomic_plane_disabling() with drm_atomic_helper_update_plane_state(). In addition to all the same things the drm_atomic_plane_disabling() used to do the new function updates the active-flag and calls atomic_update() or atomic_disable() from the plane's helper funcs as needed. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- drivers/gpu/drm/drm_atomic_helper.c | 63 - drivers/gpu/drm/drm_plane_helper.c | 10 +- include/drm/drm_atomic_helper.h | 39 ++- include/drm/drm_crtc.h | 2 ++ 4 files changed, 53 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index aecb5d6..d03e2ac 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1197,15 +1197,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, if (!funcs) continue; - /* -* Special-case disabling the plane if drivers support it. -*/ - if (drm_atomic_plane_disabling(plane, old_plane_state) && - funcs->atomic_disable) - funcs->atomic_disable(plane, old_plane_state); - else if (plane->state->crtc || -drm_atomic_plane_disabling(plane, old_plane_state)) - funcs->atomic_update(plane, old_plane_state); + drm_atomic_helper_update_plane_state(plane, old_plane_state); } for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { @@ -1266,12 +1258,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) WARN_ON(plane->state->crtc && plane->state->crtc != crtc); - if (drm_atomic_plane_disabling(plane, old_plane_state) && - plane_funcs->atomic_disable) - plane_funcs->atomic_disable(plane, old_plane_state); - else if (plane->state->crtc || -drm_atomic_plane_disabling(plane, old_plane_state)) - plane_funcs->atomic_update(plane, old_plane_state); + drm_atomic_helper_update_plane_state(plane, old_plane_state); } if (crtc_funcs && crtc_funcs->atomic_flush) @@ -1279,6 +1266,52 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) } EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc); +/* + * drm_atomic_helper_update_plane_state - update plane's atomic state + * @plane: plane object + * @old_state: previous atomic state + * + * Update plane's atomic state, disables it if that is required, and + * updates drm_palnes_state's active-flag. This also WARNs if it + * detects an invalid state (both CRTC and FB need to either both be + * NULL or both be non-NULL). + */ +void drm_atomic_helper_update_plane_state(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + const struct drm_plane_helper_funcs *funcs = plane->helper_private; + + /* +* When disabling a plane, CRTC and FB should always be NULL together. +* Anything else should be considered a bug in the atomic core, so we +* gently warn about it. +*/ + WARN_ON((plane->state->crtc == NULL && plane->state->fb != NULL) || + (plane->state->crtc != NULL && plane->state->fb == NULL)); + + if (!funcs) + return; + + /* +* The plane needs to be active only if it has an associated CRTC +* and the CRTC is active. Use atomic_disable() if available. +*/ + if (plane->state->active) { + if (!plane->state->crtc || !plane->state->crtc->state->active) { + plane->state->active = false; + if (funcs->atomic_disable) { + funcs->atomic_disable(plane, old_state); + return; + } + } + funcs->atomic_update(plane, old_state); + } else if (plane->state->crtc && plane->state->crtc->state->active) { + plane->state->active = true; + funcs->atomic_update(plane, old_state); + } +} +EXPORT_SYMBOL(drm_atomic_helper_update_plane_state); + /** * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit * @dev: DRM device diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 5e5a07a..93052de 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -440,
[PATCH RFC v2 2/2] drm/atomic: Disable planes on blanked CRTC and enable on unblank
Disable planes if they are on to be blanked CRTC and enable them when the CRTC is turned back on by DMPS. This is desirable on HW that loses its context on blanking. When planes are enabled and disabled with the associated CRTCs, there is no need to restore the plane context in runtime_resume callback. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- drivers/gpu/drm/drm_atomic_helper.c | 19 +-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index d03e2ac..5cd8016 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2027,8 +2027,8 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip); * * This is the main helper function provided by the atomic helper framework for * implementing the legacy DPMS connector interface. It computes the new desired - * ->active state for the corresponding CRTC (if the connector is enabled) and - * updates it. + * ->active state for the corresponding CRTC and planes on it (if the connector + * is enabled) and updates it. * * Returns: * Returns 0 on success, negative errno numbers on failure. @@ -2041,6 +2041,7 @@ int drm_atomic_helper_connector_dpms(struct drm_connector *connector, struct drm_crtc_state *crtc_state; struct drm_crtc *crtc; struct drm_connector *tmp_connector; + struct drm_plane *tmp_plane; int ret; bool active = false; int old_mode = connector->dpms; @@ -2079,6 +2080,20 @@ retry: } crtc_state->active = active; + /* Collect associated plane states to global state object. */ + list_for_each_entry(tmp_plane, >plane_list, head) { + struct drm_plane_state *plane_state; + + if (tmp_plane->state->crtc != crtc) + continue; + + plane_state = drm_atomic_get_plane_state(state, tmp_plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto fail; + } + } + ret = drm_atomic_commit(state); if (ret != 0) goto fail; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ASoC: davinci-mcasp: Fix TDM slot rx/tx mask associations
Reviewed-by: Jyri Sarha <jsa...@ti.com> For what little there is to review. I only had HW that worked with symmetric masks, so I did not hit this myself. Should have hacked something to codec end to be able to test asymetric masks at McASP end. Thanks, Jyri On 11/09/15 20:19, Andreas Dannenberg wrote: Fixes the associations between the tx_mask and rx_mask and the associated playback / capture streams during setting of the TDM slot. With this patch in place it is now possible for example to only populate tx_mask (leaving rx_mask as 0) for output-only codecs to control the TDM slot(s) the McASP serial port uses for transmit. Before that, this scenario would incorrectly rely on the rx_mask for this. Signed-off-by: Andreas Dannenberg <dannenb...@ti.com> --- sound/soc/davinci/davinci-mcasp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 4495a40..caa0beb 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -681,8 +681,8 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, } mcasp->tdm_slots = slots; - mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask; - mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask; + mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; + mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; mcasp->slot_width = slot_width; return davinci_mcasp_set_ch_constraints(mcasp); -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC] ASoC: simple-card: Update clocks binding for simple-card DAI subnodes
On 09/19/15 21:42, Mark Brown wrote: On Fri, Sep 11, 2015 at 04:18:02PM +0300, Jyri Sarha wrote: The updated binding provides a way to set clock-ID and direction parameters for DAI drivers set_sysclk() call back. I proposed something similar about a year ago, but Mark rejected that at the time. This RFC is to start that discussion again. This time before I do any code changes. What's the use case again? Can we address this by converting the relevant drivers to the clock API (or improving their clock API support)? Sorry, I forgot to reply this earlier. The reason why we need this is the way McASP driver uses and provides clocks for different purposes. The most pressing need is to be able to select if we want to use some external clock pin as an input for McASP clock divider that produces the i2s bit-clock or if we want to use McASP's internal clock source. There are several other things this binding would allow us, and others with flexible i2s HW, to do. Some TI codecs would also benefit from a flexible way of describing the used clock configuration, but Peter know that part better. I tried to make the binding as flexible and generic as possible. But I do not currently see any immediate need for more than one set_sysclk() call per dai. I just did not see any reason to not allow it either. Best regards, Jyri -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v4 3/8] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
On 09/28/15 12:01, Arnaud Pouliquen wrote: few questions/remarks BR, Arnaud +static void hdmi_codec_abort(struct device *dev) +{ +struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); + +dev_dbg(dev, "%s()\n", __func__); + +mutex_lock(>current_stream_lock); +if (hcp->current_stream && hcp->current_stream->runtime && +snd_pcm_running(hcp->current_stream)) { +dev_info(dev, "HDMI audio playback aborted\n"); +snd_pcm_stream_lock_irq(hcp->current_stream); +snd_pcm_stop(hcp->current_stream, SNDRV_PCM_STATE_DISCONNECTED); +snd_pcm_stream_unlock_irq(hcp->current_stream); +} +mutex_unlock(>current_stream_lock); +} Does driver should stop the stream in case of unplug? This could generate unexpected behavior at application level. Perhaps should be better if this part is managed in DRM driver. if HDMI master, I2S bus should be maintained ON to consume the audio stream until application action. The whole point of this abort callback is to provide the means for the video side to stop the audio playback in a clean way. The abort callback is given to the video side in startup() callback (ASoC side calls video side). If the video side sees that the playback can not go on it can call the abort callback and the audio playback will abort in standard ALSA way and a properly written applications should not get confused. Nothing is forcing the video side to call the callback ever, if so decided. But if for instance power management stops the i2s clocks when connector is unplugged, then the audio can not go on any more and it should be aborted (actually it would abort in a moment when ALSA realizes that the DMA is not running). + +static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params, +struct snd_soc_dai *dai) +{ +struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); +struct hdmi_codec_params hp = { +.iec = { +.status = { 0 }, +.subcode = { 0 }, +.pad = 0, +.dig_subframe = { 0 }, +} +}; +int ret; + +dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, +params_width(params), params_rate(params), +params_channels(params)); + +ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status, + sizeof(hp.iec.status)); Tell me if i am wrong, but in case of SPDIF format, IEC status is managed by cpu_dai not by the codec. To manage IEC61937 a control should be needed to update IEC status bits... AFAIK yes. However, the video side implementation is free to ignore status bits in the struct hdmi_codec_params and it should normally do so if the format is SPDIF. Of course I could save couple CPU cycles in the codec code if would not even produce the bits when the format is SPDIF. Best regards, Jyri +if (ret < 0) { +dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", +ret); +return ret; +} + +ret = hdmi_codec_new_stream(substream, dai); +if (ret) +return ret; + +hdmi_audio_infoframe_init(); +hp.cea.channels = params_channels(params); +hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; +hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; +hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; + +hp.sample_width = params_width(params); +hp.sample_rate = params_rate(params); +hp.channels = params_channels(params); + +return hcp->hcd.ops->hw_params(dai->dev->parent, >daifmt[dai->id], + ); +} + -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v4 3/8] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
On 09/21/15 12:31, Russell King - ARM Linux wrote: On Sat, Sep 19, 2015 at 10:54:51AM -0700, Mark Brown wrote: On Fri, Sep 18, 2015 at 02:06:40PM +0300, Jyri Sarha wrote: +#define SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ +SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ +SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ +SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) + +#define I2S_FORMATS(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ +SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE |\ +SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ +SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ +SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ +SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) I'm not sure how abstracted this I2S and S/PDIF DAI business is - it doesn't feel like something that's going to be a property of all HDMI devices, and the specific sets of formats above cause me to raise a bit of an eyebrow. Should this be an interface where the HDMI chip registers multiple interfaces if it has them instead of automatically getting this split as is? The inclusion of the 32-bit formats does raise an eyebrow here too. Audio transmission across the HDMI link is S/PDIF, supporting up to 24-bit uncompressed audio (aka L-PCM). The device may accept 32 bit I2S, but it would have to be truncated to 24 bit before transmitting it to the sink. This should be mentioned somewhere. There is ".sig_bits = 24" in hdmi_i2s_dai, but I can add an explicit comment about it. We needed 32bit format in practice until Peter got 24_LE properly working with McASP. I just thought the may still be some platforms out there that can not produce 24bit i2s samples for some reason, but work just fine with 32bit samples. Those platforms would be limited to less than 24bit precision without 32bit formats. But as said, it is not critical to us any more and I can drop the 32bit formats as well. BR, Jyri -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [alsa-devel] [PATCH RFC v4 2/8] ALSA: pcm: add IEC958 channel status helper for hw_params
On 09/21/15 18:08, Clemens Ladisch wrote: >But there is no downside in using prepare callback. The prepare callback also can be called multiple times. This certainly happens when the stream is stopped/restarted multiple times. If something does not need to be done again when a stream is restarted, then it should be done in the hw_params callback. Oh, forgot about that. This would suggest to keep the stream header configuration in the hw_params(). Thanks, Jyri -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v4 2/8] ALSA: pcm: add IEC958 channel status helper for hw_params
On 09/21/15 12:37, Russell King - ARM Linux wrote: On Fri, Sep 18, 2015 at 02:06:39PM +0300, Jyri Sarha wrote: Add IEC958 channel status helper that gets the audio properties from snd_pcm_hw_params instead of snd_pcm_runtime. This is needed to produce the channel status bits already in audio stream configuration phase. What is the reason for doing this early? After some thinking, there is no good reason. It makes the codec bit more complicated, but that is not a good reason. I'll change that and use the prepare callback. This patch can be dropped. ALSA documentation (which may be out of date) says that the hw_params callback can be called multiple times during stream setup. Do we want to be repeatedly programming the HDMI infoframe with different settings, potentially confusing the attached device, or would it be better to do it slightly later (in the prepare callback) after the parameters have been fully negotiated? If it is possible that hw_params() can be called multiple times, at least it does not happen very often. I wonder if it would ever happen again after a successful hw_params() call. But there is no downside in using prepare callback. I was just too much following the way ASoC codecs usually do the thing by writing everything to iron as the callbacks come in. Best regards, Jyri -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v4 7/8] drm/i2c: tda998x: Register ASoC HDMI codec for audio functionality
Register ASoC HDMI codec for audio functionality. This is an initial ASoC audio implementation for tda998x driver and it does not use all the features provided by hdmi-codec. HDMI audio info-frame and audio stream header is generated by the ASoC HDMI codec. The codec also applies constraints for available sample-rates. Implementation of audio_startup for hdmi_codec_ops would enable tda998x driver to abort ongoing playback if the HDMI cable is unplugged or re-plugged to a device without audio capability. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- drivers/gpu/drm/i2c/Kconfig | 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 181 +++--- include/drm/i2c/tda998x.h | 1 + 3 files changed, 150 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 22c7ed6..088f278 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -28,6 +28,7 @@ config DRM_I2C_SIL164 config DRM_I2C_NXP_TDA998X tristate "NXP Semiconductors TDA998X HDMI encoder" default m if DRM_TILCDC + select SND_SOC_HDMI_CODEC if SND_SOC help Support for NXP Semiconductors TDA998X HDMI encoders. diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 2fc6399..1a9bbf2 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -30,9 +31,9 @@ #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) -struct tda998x_audio { - u8 ports[2];/* AP value */ - u8 port_types[2]; /* AFMT_xxx */ +struct tda998x_audio_port { + u8 format; /* AFMT_xxx */ + u8 config; /* AP value */ }; struct tda998x_priv { @@ -49,11 +50,13 @@ struct tda998x_priv { u8 vip_cntrl_2; struct tda998x_audio_params audio_params; + struct platform_device *audio_pdev; + wait_queue_head_t wq_edid; volatile int wq_edid_wait; struct drm_encoder *encoder; - struct tda998x_audio audio; + struct tda998x_audio_port audio_port[2]; }; #define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) @@ -701,7 +704,7 @@ tda998x_configure_audio(struct tda998x_priv *priv, break; default: - BUG(); + dev_err(>hdmi->dev, "Unsupported I2S format\n"); return -EINVAL; } @@ -1028,7 +1031,7 @@ tda998x_encoder_mode_set(struct tda998x_priv *priv, tda998x_write_avi(priv, adjusted_mode); - if (priv->audio_params.config) { + if (priv->audio_params.format != AFMT_UNUSED) { tda998x_configure_audio(priv, >audio_params, adjusted_mode->clock); @@ -1124,6 +1127,8 @@ tda998x_encoder_get_modes(struct tda998x_priv *priv, drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); + drm_edid_to_eld(connector, edid); + kfree(edid); return n; @@ -1160,6 +1165,9 @@ static void tda998x_destroy(struct tda998x_priv *priv) } i2c_unregister_device(priv->cec); + + if (priv->audio_pdev) + platform_device_unregister(priv->audio_pdev); } /* Slave encoder support */ @@ -1234,6 +1242,133 @@ static struct drm_encoder_slave_funcs tda998x_encoder_slave_funcs = { .set_property = tda998x_encoder_set_property, }; +static int tda998x_audio_hw_params(struct device *dev, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct tda998x_priv *priv = dev_get_drvdata(dev); + int i, ret; + struct tda998x_audio_params audio = { + .sample_width = params->sample_width, + .sample_rate = params->sample_rate, + .cea = params->cea, + }; + + if (!priv->encoder->crtc) + return -ENODEV; + + memcpy(audio.status, params->iec.status, + min(sizeof(audio.status), sizeof(params->iec.status))); + + switch (daifmt->fmt) { + case HDMI_I2S: + if (daifmt->bit_clk_inv || daifmt->frame_clk_inv || + daifmt->bit_clk_master || daifmt->frame_clk_master) { + dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, + daifmt->bit_clk_inv, daifmt->frame_clk_inv, + daifmt->bit_clk_master, + daifmt-&
[PATCH RFC v4 3/8] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
The hdmi-codec is a platform device driver to be registered from drivers of external HDMI encoders with I2S and/or spdif interface. The driver in turn registers an ASoC codec for the HDMI encoder's audio functionality. The structures and definitions in the API header are mostly redundant copies of similar structures in ASoC headers. This is on purpose to avoid direct dependencies to ASoC structures in video side driver. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- include/sound/hdmi-codec.h| 104 +++ sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdmi-codec.c | 404 ++ 4 files changed, 516 insertions(+) create mode 100644 include/sound/hdmi-codec.h create mode 100644 sound/soc/codecs/hdmi-codec.c diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h new file mode 100644 index 000..15fe70f --- /dev/null +++ b/include/sound/hdmi-codec.h @@ -0,0 +1,104 @@ +/* + * hdmi-codec.h - HDMI Codec driver API + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Jyri Sarha <jsa...@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __HDMI_CODEC_H__ +#define __HDMI_CODEC_H__ + +#include +#include +#include +#include + +/* + * Protocol between ASoC cpu-dai and HDMI-encoder + */ +struct hdmi_codec_daifmt { + enum { + HDMI_I2S, + HDMI_RIGHT_J, + HDMI_LEFT_J, + HDMI_DSP_A, + HDMI_DSP_B, + HDMI_AC97, + HDMI_SPDIF, + } fmt; + int bit_clk_inv:1; + int frame_clk_inv:1; + int bit_clk_master:1; + int frame_clk_master:1; +}; + +/* + * HDMI audio parameters + */ +struct hdmi_codec_params { + struct hdmi_audio_infoframe cea; + struct snd_aes_iec958 iec; + int sample_rate; + int sample_width; + int channels; +}; + +struct hdmi_codec_ops { + /* +* Called when ASoC starts an audio stream setup. The call +* provides an audio abort callback for stoping an ongoing +* stream from video side driver if the HDMI audio becomes +* unavailable. +* Optional +*/ + int (*audio_startup)(struct device *dev, +void (*abort_cb)(struct device *dev)); + + /* +* Configures HDMI-encoder for audio stream. +* Mandatory +*/ + int (*hw_params)(struct device *dev, +struct hdmi_codec_daifmt *fmt, +struct hdmi_codec_params *hparms); + + /* +* Shuts down the audio stream. +* Mandatory +*/ + void (*audio_shutdown)(struct device *dev); + + /* +* Mute/unmute HDMI audio stream. +* Optional +*/ + int (*digital_mute)(struct device *dev, bool enable); + + /* +* Provides EDID-Like-Data from connected HDMI device. +* Optional +*/ + int (*get_eld)(struct device *dev, uint8_t *buf, size_t len); +}; + +/* HDMI codec initalization data */ +struct hdmi_codec_pdata { + const struct hdmi_codec_ops *ops; + uint i2s:1; + uint spdif:1; + int max_i2s_channels; +}; + +#define HDMI_CODEC_DRV_NAME "hdmi-audio-codec" + +#endif /* __HDMI_CODEC_H__ */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0142396..1e6c7e7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -79,6 +79,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C + select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 @@ -441,6 +442,11 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate +config SND_SOC_HDMI_CODEC + tristate + select SND_PCM_ELD + select SND_PCM_IEC958 + config SND_SOC_ES8328 tristate "Everest Semi ES8328 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7d7cc1b..068d483 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -72,6 +72,7 @@ snd-soc-max98925-objs := max98925.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o +snd-soc-hdmi-codec-objs := hdmi-codec.o snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm1792a-codec-objs := pcm1792a.o snd-soc-pcm3008-ob
[PATCH RFC v4 0/8] Implement generic ASoC HDMI codec and use it in tda998x
Changes since RFC v3, ASoC side: - Add "ALSA: pcm: add IEC958 channel status helper for hw_params" - Add "tda998x: Improve tda998x_configure_audio() audio related pdata" - use snd_pcm_create_iec958_consumer_hw_params() to construct the stream header - Remove set_clk() callback from hdmi-codec. It is not needed for now. - Refer to stream header in AIF as specified in HDMI standard - Set current_stream to NULL only after video side audio_shutdown() has been called. Avoid potential race if video side attempts to abort audio at the same time. - No need to have video side device pointer in the hdmi codec's pdata as it is found from dev->parent. - Fix hdmi-codec enum: DAI_ID_I2C > DAI_ID_I2S - Improve audio_startup API comment - Make improved checkpatch happy - BUG_ON > WARN_ON - put */ ending the block comment to a separate line DRM side: - Fix tda998x get_eld() locking - Change tda998x audio parameters in pdata to more generic, that can be readily used in tda998x_audio_config() - Rename and restructure audio port related private data members to be more descriptive - Require audio configuration trough ASoC hdmi-codec if HDMI audio is configured trough DT binding. DTS: - Increase McASP fifo usage form 1 to 32 The binding for tda998x is taken from Jean Francois' patch series[1] on the same subject. The implementation of the of-node parsing has some minor changes from my self. Here is what I think at least could or should still be done, but non of that stuff does not sounds critical right now. Missing from tda998x driver side - hdmi_codec_ops audio_startup() implementation for audio abort support - multi channel audio support (I would need specs and preferably some HW to test for this). Missing from ASoC side generic implementation: - channel_allocation handling is completely left for the video side driver, see if ASoC side could help in any way - snd_soc_jack functionality to handle hdmi cable plug/unplug events [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2015-July/095596.html Best regards, Jyri Jean-Francois Moine (1): drm/i2c: tda998x: Add support of a DT graph of ports Jyri Sarha (7): ASoC: hdmi: Remove obsolete dummy HDMI codec ALSA: pcm: add IEC958 channel status helper for hw_params ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders drm/i2c: tda998x: Remove include/sound/tda998x.h and fix graph parsing drm/i2c: tda998x: Improve tda998x_configure_audio() audio related pdata drm/i2c: tda998x: Register ASoC HDMI codec for audio functionality ARM: dts: am335x-boneblack: Add HDMI audio support .../devicetree/bindings/drm/i2c/tda998x.txt| 51 +++ arch/arm/boot/dts/am335x-boneblack.dts | 90 - drivers/gpu/drm/armada/armada_drv.c| 25 +- drivers/gpu/drm/i2c/Kconfig| 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 319 +--- include/drm/i2c/tda998x.h | 24 +- include/sound/hdmi-codec.h | 104 ++ include/sound/pcm_iec958.h | 2 + sound/core/pcm_iec958.c| 52 ++- sound/soc/codecs/Kconfig | 4 +- sound/soc/codecs/Makefile | 4 +- sound/soc/codecs/hdmi-codec.c | 404 + sound/soc/codecs/hdmi.c| 109 -- 13 files changed, 985 insertions(+), 204 deletions(-) create mode 100644 include/sound/hdmi-codec.h create mode 100644 sound/soc/codecs/hdmi-codec.c delete mode 100644 sound/soc/codecs/hdmi.c -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v4 1/8] ASoC: hdmi: Remove obsolete dummy HDMI codec
The hdmi stub codec has not been used since refactoring of OMAP HDMI audio support. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- sound/soc/codecs/Kconfig | 4 -- sound/soc/codecs/Makefile | 2 - sound/soc/codecs/hdmi.c | 109 -- 3 files changed, 115 deletions(-) delete mode 100644 sound/soc/codecs/hdmi.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0c9733e..0142396 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -79,7 +79,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C - select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 @@ -442,9 +441,6 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate -config SND_SOC_HDMI_CODEC - tristate "HDMI stub CODEC" - config SND_SOC_ES8328 tristate "Everest Semi ES8328 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4a32077..7d7cc1b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -72,7 +72,6 @@ snd-soc-max98925-objs := max98925.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o -snd-soc-hdmi-codec-objs := hdmi.o snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm1792a-codec-objs := pcm1792a.o snd-soc-pcm3008-objs := pcm3008.o @@ -264,7 +263,6 @@ obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o -obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c deleted file mode 100644 index bd42ad3..000 --- a/sound/soc/codecs/hdmi.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * ALSA SoC codec driver for HDMI audio codecs. - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Ricardo Neri <ricardo.n...@ti.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#include -#include -#include -#include - -#define DRV_NAME "hdmi-audio-codec" - -static const struct snd_soc_dapm_widget hdmi_widgets[] = { - SND_SOC_DAPM_INPUT("RX"), - SND_SOC_DAPM_OUTPUT("TX"), -}; - -static const struct snd_soc_dapm_route hdmi_routes[] = { - { "Capture", NULL, "RX" }, - { "TX", NULL, "Playback" }, -}; - -static struct snd_soc_dai_driver hdmi_codec_dai = { - .name = "hdmi-hifi", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 24, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, - -}; - -#ifdef CONFIG_OF -static const struct of_device_id hdmi_audio_codec_ids[] = { - { .compatible = "linux,hdmi-audio", }, - { } -}; -MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids); -#endif - -static struct snd_soc_codec_driver hdmi_codec = { - .dapm_widgets = hdmi_widgets, - .num_dapm_widgets = ARRAY_SIZE(hdmi_widge
[PATCH RFC v4 4/8] drm/i2c: tda998x: Add support of a DT graph of ports
From: Jean-Francois Moine <moin...@free.fr> Two kinds of ports may be declared in a DT graph of ports: video and audio. This patch accepts the port value from a video port as an alternative to the video-ports property. It also accepts audio ports in the case the transmitter is not used as a slave encoder. The new file include/sound/tda998x.h prepares to the definition of a tda998x CODEC. Signed-off-by: Jean-Francois Moine <moin...@free.fr> Signed-off-by: Jyri Sarha <jsa...@ti.com> --- .../devicetree/bindings/drm/i2c/tda998x.txt| 51 drivers/gpu/drm/i2c/tda998x_drv.c | 90 +++--- include/sound/tda998x.h| 8 ++ 3 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 include/sound/tda998x.h diff --git a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt index e9e4bce..35f6a80 100644 --- a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt +++ b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt @@ -16,6 +16,35 @@ Optional properties: - video-ports: 24 bits value which defines how the video controller output is wired to the TDA998x input - default: <0x230145> + This property is not used when ports are defined. + +Optional nodes: + + - port: up to three ports. + The ports are defined according to [1]. + +Video port. + There may be only one video port. + This one must contain the following property: + + - port-type: must be "rgb" + + and may contain the optional property: + + - reg: 24 bits value which defines how the video controller + output is wired to the TDA998x input (video pins) + When absent, the default value is <0x230145>. + +Audio ports. + There may be one or two audio ports. + These ones must contain the following properties: + + - port-type: must be "i2s" or "spdif" + + - reg: 8 bits value which defines how the audio controller + output is wired to the TDA998x input (audio pins) + +[1] Documentation/devicetree/bindings/graph.txt Example: @@ -26,4 +55,26 @@ Example: interrupts = <27 2>;/* falling edge */ pinctrl-0 = <_camera>; pinctrl-names = "default"; + + port@230145 { + port-type = "rgb"; + reg = <0x230145>; + hdmi_0: endpoint { + remote-endpoint = <_0>; + }; + }; + port@3 {/* AP1 = I2S */ + port-type = "i2s"; + reg = <0x03>; + tda998x_i2s: endpoint { + remote-endpoint = <_i2s>; + }; + }; + port@4 { /* AP2 = S/PDIF */ + port-type = "spdif"; + reg = <0x04>; + tda998x_spdif: endpoint { + remote-endpoint = <_spdif1>; + }; + }; }; diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 424228b..0952eac 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -27,6 +27,7 @@ #include #include #include +#include #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) @@ -47,6 +48,8 @@ struct tda998x_priv { wait_queue_head_t wq_edid; volatile int wq_edid_wait; struct drm_encoder *encoder; + + struct tda998x_audio audio; }; #define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) @@ -774,6 +777,8 @@ static void tda998x_encoder_set_config(struct tda998x_priv *priv, (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0); priv->params = *p; + priv->audio.port_types[0] = p->audio_format; + priv->audio.ports[0] = p->audio_cfg; } static void tda998x_encoder_dpms(struct tda998x_priv *priv, int mode) @@ -1230,9 +1235,57 @@ static struct drm_encoder_slave_funcs tda998x_encoder_slave_funcs = { /* I2C driver functions */ +static int tda998x_parse_ports(struct tda998x_priv *priv, + struct device_node *np) +{ + struct device_node *of_port; + const char *port_type; + int ret, audio_index, reg, afmt; + + audio_index = 0; + for_each_child_of_node(np, of_port) { + if (!of_port->name +|| of_node_cmp(of_port->name, "port") != 0) + continue; + ret = of_property_read_s
[PATCH RFC v4 2/8] ALSA: pcm: add IEC958 channel status helper for hw_params
Add IEC958 channel status helper that gets the audio properties from snd_pcm_hw_params instead of snd_pcm_runtime. This is needed to produce the channel status bits already in audio stream configuration phase. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- include/sound/pcm_iec958.h | 2 ++ sound/core/pcm_iec958.c| 52 +++--- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/include/sound/pcm_iec958.h b/include/sound/pcm_iec958.h index 0eed397..36f023a 100644 --- a/include/sound/pcm_iec958.h +++ b/include/sound/pcm_iec958.h @@ -6,4 +6,6 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, size_t len); +int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, +u8 *cs, size_t len); #endif diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index 36b2d7a..c9f8b66 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c @@ -9,30 +9,18 @@ #include #include #include +#include #include -/** - * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status - * @runtime: pcm runtime structure with ->rate filled in - * @cs: channel status buffer, at least four bytes - * @len: length of channel status buffer - * - * Create the consumer format channel status data in @cs of maximum size - * @len corresponding to the parameters of the PCM runtime @runtime. - * - * Drivers may wish to tweak the contents of the buffer after creation. - * - * Returns: length of buffer, or negative error code if something failed. - */ -int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, - size_t len) +static int create_iec958_consumer(uint rate, uint sample_width, + u8 *cs, size_t len) { unsigned int fs, ws; if (len < 4) return -EINVAL; - switch (runtime->rate) { + switch (rate) { case 32000: fs = IEC958_AES3_CON_FS_32000; break; @@ -59,7 +47,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, } if (len > 4) { - switch (snd_pcm_format_width(runtime->format)) { + switch (sample_width) { case 16: ws = IEC958_AES4_CON_WORDLEN_20_16; break; @@ -92,4 +80,34 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, return len; } + +/** + * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status + * @runtime: pcm runtime structure with ->rate filled in + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Create the consumer format channel status data in @cs of maximum size + * @len corresponding to the parameters of the PCM runtime @runtime. + * + * Drivers may wish to tweak the contents of the buffer after creation. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, + size_t len) +{ + return create_iec958_consumer(runtime->rate, + snd_pcm_format_width(runtime->format), + cs, len); +} EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); + + +int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, +u8 *cs, size_t len) +{ + return create_iec958_consumer(params_rate(params), params_width(params), + cs, len); +} +EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v4 5/8] drm/i2c: tda998x: Remove include/sound/tda998x.h and fix graph parsing
Move struct tda998x_audio definition to tda998x_drv.c and remove include/sound/tda998x.h. There is no external use for struct tda998x_audio. Fix graph parsing to allow ports to be inside a separate "ports"-node as specified in Documentation/devicetree/bindings/graph.txt. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- drivers/gpu/drm/i2c/tda998x_drv.c | 59 +-- include/sound/tda998x.h | 8 -- 2 files changed, 32 insertions(+), 35 deletions(-) delete mode 100644 include/sound/tda998x.h diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 0952eac..4dc2dc0 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -27,10 +27,14 @@ #include #include #include -#include #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) +struct tda998x_audio { + u8 ports[2];/* AP value */ + u8 port_types[2]; /* AFMT_xxx */ +}; + struct tda998x_priv { struct i2c_client *cec; struct i2c_client *hdmi; @@ -1240,9 +1244,10 @@ static int tda998x_parse_ports(struct tda998x_priv *priv, { struct device_node *of_port; const char *port_type; - int ret, audio_index, reg, afmt; + int ret, audio_index, reg, afmt, rgb_initialized; audio_index = 0; + rgb_initialized = 0; for_each_child_of_node(np, of_port) { if (!of_port->name || of_node_cmp(of_port->name, "port") != 0) @@ -1252,11 +1257,17 @@ static int tda998x_parse_ports(struct tda998x_priv *priv, if (ret < 0) continue; ret = of_property_read_u32(of_port, "reg", ); + if (ret < 0) { + dev_err(>hdmi->dev, "missing reg for %s\n", + port_type); + return ret; + } if (strcmp(port_type, "rgb") == 0) { if (!ret) { /* video reg is optional */ priv->vip_cntrl_0 = reg >> 16; priv->vip_cntrl_1 = reg >> 8; priv->vip_cntrl_2 = reg; + rgb_initialized = 1; } continue; } @@ -1266,11 +1277,6 @@ static int tda998x_parse_ports(struct tda998x_priv *priv, afmt = AFMT_SPDIF; else continue; - if (ret < 0) { - dev_err(>hdmi->dev, "missing reg for %s\n", - port_type); - return ret; - } if (audio_index >= ARRAY_SIZE(priv->audio.ports)) { dev_err(>hdmi->dev, "too many audio ports\n"); break; @@ -1279,13 +1285,13 @@ static int tda998x_parse_ports(struct tda998x_priv *priv, priv->audio.port_types[audio_index] = afmt; audio_index++; } - return 0; + return rgb_initialized; } static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) { struct device_node *np = client->dev.of_node; - struct device_node *of_port; + struct device_node *ports; u32 video; int rev_lo, rev_hi, ret; unsigned short cec_addr; @@ -1392,24 +1398,15 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) /* get the device tree parameters */ if (np) { - of_port = of_get_child_by_name(np, "port"); - if (of_port) { /* graph of ports */ - of_node_put(of_port); - ret = tda998x_parse_ports(priv, np); - if (ret < 0) - goto fail; - - /* initialize the default audio configuration */ - if (priv->audio.ports[0]) { - priv->params.audio_cfg = priv->audio.ports[0]; - priv->params.audio_format = - priv->audio.port_types[0]; - priv->params.audio_clk_cfg = - priv->params.audio_format == - AFMT_SPDIF ? 0 : 1; - } - } else { - + ports = of_get_child_by_name(np, "ports"); + if (!ports) + ports = of_node_get(np); + /* graph of ports */ + ret = tda998x_parse_ports(pr
[PATCH RFC v4 6/8] drm/i2c: tda998x: Improve tda998x_configure_audio() audio related pdata
Declare struct tda998x_audio_params in include/drm/i2c/tda998x.h and use it in pdata and for tda998x_configure_audio() parameters. Also updates tda998x_write_aif() to use hdmi_audio_infoframe_pack() and friends. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- drivers/gpu/drm/armada/armada_drv.c | 25 ++-- drivers/gpu/drm/i2c/tda998x_drv.c | 123 include/drm/i2c/tda998x.h | 23 --- 3 files changed, 102 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 225034b..d500840 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -20,6 +20,7 @@ #ifdef CONFIG_DRM_ARMADA_TDA1998X #include +#include #include "armada_slave.h" static struct tda998x_encoder_params params = { @@ -35,10 +36,26 @@ static struct tda998x_encoder_params params = { .swap_d = 5, .swap_e = 0, .swap_f = 1, - .audio_cfg = BIT(2), - .audio_frame[1] = 1, - .audio_format = AFMT_SPDIF, - .audio_sample_rate = 44100, + .audio = { + .config = BIT(2), + .format = AFMT_SPDIF, + .sample_width = 24, + .sample_rate = 44100, + .cea = { + .channels = 2, + .coding_type = HDMI_AUDIO_CODING_TYPE_STREAM, + .sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM, + .sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM, + }, + .status = { + IEC958_AES0_CON_NOT_COPYRIGHT, + IEC958_AES1_CON_GENERAL, + IEC958_AES2_CON_SOURCE_UNSPEC | + IEC958_AES2_CON_CHANNEL_UNSPEC, + IEC958_AES3_CON_CLOCK_1000PPM | + IEC958_AES3_CON_FS_NOTID, + }, + } }; static const struct armada_drm_slave_config tda19988_config = { diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 4dc2dc0..2fc6399 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -47,7 +47,7 @@ struct tda998x_priv { u8 vip_cntrl_0; u8 vip_cntrl_1; u8 vip_cntrl_2; - struct tda998x_encoder_params params; + struct tda998x_audio_params audio_params; wait_queue_head_t wq_edid; volatile int wq_edid_wait; @@ -597,15 +597,6 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data) return IRQ_HANDLED; } -static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes) -{ - int sum = 0; - - while (bytes--) - sum -= *buf++; - return sum; -} - #define HB(x) (x) #define PB(x) (HB(2) + 1 + (x)) @@ -618,24 +609,22 @@ tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr, reg_set(priv, REG_DIP_IF_FLAGS, bit); } -static void -tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p) +static int tda998x_write_aif(struct tda998x_priv *priv, +struct hdmi_audio_infoframe *cea) { - u8 buf[PB(HDMI_AUDIO_INFOFRAME_SIZE) + 1]; - - memset(buf, 0, sizeof(buf)); - buf[HB(0)] = HDMI_INFOFRAME_TYPE_AUDIO; - buf[HB(1)] = 0x01; - buf[HB(2)] = HDMI_AUDIO_INFOFRAME_SIZE; - buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */ - buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */ - buf[PB(4)] = p->audio_frame[4]; - buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */ + uint8_t buf[HDMI_INFOFRAME_SIZE(AUDIO)]; + int len; - buf[PB(0)] = tda998x_cksum(buf, sizeof(buf)); + len = hdmi_audio_infoframe_pack(cea, buf, sizeof(buf)); + if (len < 0) { + dev_err(>hdmi->dev, + "Failed to pack audio infoframe: %d\n", len); + return len; + } - tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf, -sizeof(buf)); + /* Write the audio information packet */ + tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf, len); + return 0; } static void @@ -670,19 +659,20 @@ static void tda998x_audio_mute(struct tda998x_priv *priv, bool on) } } -static void +static int tda998x_configure_audio(struct tda998x_priv *priv, - struct drm_display_mode *mode, struct tda998x_encoder_params *p) + struct tda998x_audio_params *params, + unsigned mode_clock) { uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv; uint32_t n; /* Enable audio ports */ - reg_write(priv, REG_ENA_AP, p->audio_cfg); - reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg); + reg_write(priv, REG_ENA_AP, params->config); + reg_write(priv, REG_ENA
[PATCH RFC v4 8/8] ARM: dts: am335x-boneblack: Add HDMI audio support
Add HDMI audio support. Adds mcasp0_pins, clk_mcasp0_fixed, clk_mcasp0, mcasp0, sound node, and updates the tda19988 node to follow the new binding. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- arch/arm/boot/dts/am335x-boneblack.dts | 90 -- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts index eadbba3..05347dc 100644 --- a/arch/arm/boot/dts/am335x-boneblack.dts +++ b/arch/arm/boot/dts/am335x-boneblack.dts @@ -64,6 +64,16 @@ 0x1b0 0x03 /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */ >; }; + + mcasp0_pins: mcasp0_pins { + pinctrl-single,pins = < + 0x1ac (PIN_INPUT_PULLUP | MUX_MODE0)/* mcasp0_ahclkx.mcasp0_ahclkx */ + 0x19c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2 */ + 0x194 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */ + 0x190 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */ + 0x06c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */ + >; + }; }; { @@ -76,17 +86,89 @@ }; { - tda19988 { + tda19988: tda19988 { compatible = "nxp,tda998x"; reg = <0x70>; + + #sound-dai-cells = <0>; + pinctrl-names = "default", "off"; pinctrl-0 = <_hdmi_bonelt_pins>; pinctrl-1 = <_hdmi_bonelt_off_pins>; - port { - hdmi_0: endpoint@0 { - remote-endpoint = <_0>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + port-type = "rgb"; + reg = <0x230145>; + hdmi_0: endpoint@0 { + remote-endpoint = <_0>; + }; }; + port@1 { + port-type = "i2s"; + reg = <0x03>; + tda19988_i2s: endpoint { + remote-endpoint = <_i2s>; + }; + }; + }; + }; +}; + + { + system-power-controller; +}; + +{ + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <_pins>; + status = "okay"; + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ + 0 0 1 0 + >; + tx-num-evt = <32>; + rx-num-evt = <32>; + + port { + mcasp0_i2s: endpoint { + remote-endpoint = <_i2s>; + }; + }; +}; + +/ { + clk_mcasp0_fixed: clk_mcasp0_fixed { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24576000>; + }; + + clk_mcasp0: clk_mcasp0 { + #clock-cells = <0>; + compatible = "gpio-gate-clock"; + clocks = <_mcasp0_fixed>; + enable-gpios = < 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */ + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "TI BeagleBone Black"; + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <_master>; + simple-audio-card,frame-master = <_master>; + + dailink0_master: simple-audio-card,cpu { + sound-dai = <>; + clocks = <_mcasp0>; + }; + + simple-audio-card,codec { + sound-dai = <>; }; }; }; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] ASoC: davinci-mcasp: Get rid of bclk_lrclk_ratio in private data
The slot_width is for essentially same thing. Instead of storing bclk_lrclk_ratio, just store the slot_width. Comments has been updated accordingly and some variable names changed to more descriptive. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- Added the missing __func__ to dev_warn() warn call in __davinci_mcasp_set_clkdiv(). sound/soc/davinci/davinci-mcasp.c | 56 ++- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index de1e3a8..9a9d633 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -87,7 +87,6 @@ struct davinci_mcasp { u8 *serial_dir; u8 version; u8 bclk_div; - u16 bclk_lrclk_ratio; int streams; u32 irq_request[2]; int dma_request[2]; @@ -558,8 +557,21 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, mcasp->bclk_div = div; break; - case 2: /* BCLK/LRCLK ratio */ - mcasp->bclk_lrclk_ratio = div; + case 2: /* +* BCLK/LRCLK ratio descries how many bit-clock cycles +* fit into one frame. The clock ratio is given for a +* full period of data (for I2S format both left and +* right channels), so it has to be divided by number +* of tdm-slots (for I2S - divided by 2). +* Instead of storing this ratio, we calculate a new +* tdm_slot width by dividing the the ratio by the +* number of configured tdm slots. +*/ + mcasp->slot_width = div / mcasp->tdm_slots; + if (div % mcasp->tdm_slots) + dev_warn(mcasp->dev, +"%s(): BCLK/LRCLK %d is not divisible by %d tdm slots", +__func__, div, mcasp->tdm_slots); break; default: @@ -682,11 +694,13 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, } static int davinci_config_channel_size(struct davinci_mcasp *mcasp, - int word_length) + int sample_width) { u32 fmt; - u32 tx_rotate = (word_length / 4) & 0x7; - u32 mask = (1ULL << word_length) - 1; + u32 tx_rotate = (sample_width / 4) & 0x7; + u32 mask = (1ULL << sample_width) - 1; + u32 slot_width = sample_width; + /* * For captured data we should not rotate, inversion and masking is * enoguh to get the data to the right position: @@ -699,31 +713,23 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, u32 rx_rotate = 0; /* -* if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() -* callback, take it into account here. That allows us to for example -* send 32 bits per channel to the codec, while only 16 of them carry -* audio payload. -* The clock ratio is given for a full period of data (for I2S format -* both left and right channels), so it has to be divided by number of -* tdm-slots (for I2S - divided by 2). +* Setting the tdm slot width either with set_clkdiv() or +* set_tdm_slot() allows us to for example send 32 bits per +* channel to the codec, while only 16 of them carry audio +* payload. */ - if (mcasp->bclk_lrclk_ratio) { - u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; - + if (mcasp->slot_width) { /* -* When we have more bclk then it is needed for the data, we -* need to use the rotation to move the received samples to have -* correct alignment. +* When we have more bclk then it is needed for the +* data, we need to use the rotation to move the +* received samples to have correct alignment. */ - rx_rotate = (slot_length - word_length) / 4; - word_length = slot_length; - } else if (mcasp->slot_width) { - rx_rotate = (mcasp->slot_width - word_length) / 4; - word_length = mcasp->slot_width; + slot_width = mcasp->slot_width; + rx_rotate = (slot_width - sample_width) / 4; } /* mapping of the XSSZ bit-field as described in the datasheet */ - fmt = (word_length >> 1) - 1; + fmt = (slot_width >> 1) - 1; if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), -- 1.9.1 -- To unsubscribe from this list: send the line "unsub
[PATCH] ASoC: soc-core: Fix sparse warning in be32_to_cpup() call
Signed-off-by: Jyri Sarha <jsa...@ti.com> --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1929f0e..614b831 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3301,7 +3301,7 @@ static int snd_soc_of_get_slot_mask(struct device_node *np, return 0; val /= sizeof(u32); for (i = 0; i < val; i++) - if (be32_to_cpup(_slot_mask[i])) + if (be32_to_cpup((__be32 *)_slot_mask[i])) *mask |= (1 << i); return val; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3] ASoC: soc-core: Fix sparse warning in be32_to_cpup() call
Store return value of of_get_property() to a pointer of __be32 type as device tree has big endian type. This fixes a sparse warning couple of lines later when be32_to_cpup() is used to convert from big endian to cpu endian. The whole conversion is not really necessary, as we are only checking if the value is zero or not, but I wanted to add it to remind in the future that the data has to be converted before use. Compiler should optimize the unnecessary operations away. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- Damn, I wrote description ready but forgot to produce the patch again. So here is a v3 of the same one liner patch. sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1929f0e..af4999c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3294,7 +3294,7 @@ static int snd_soc_of_get_slot_mask(struct device_node *np, unsigned int *mask) { u32 val; - const u32 *of_slot_mask = of_get_property(np, prop_name, ); + const __be32 *of_slot_mask = of_get_property(np, prop_name, ); int i; if (!of_slot_mask) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ASoC: soc-core: Fix sparse warning in be32_to_cpup() call
On 09/17/15 12:22, Mark Brown wrote: On Thu, Sep 17, 2015 at 11:02:57AM +0300, Jyri Sarha wrote: val /= sizeof(u32); for (i = 0; i < val; i++) - if (be32_to_cpup(_slot_mask[i])) + if (be32_to_cpup((__be32 *)_slot_mask[i])) *mask |= (1 << i); There was no changelog and this is setting off alarm bells since the cast just smashes warnings - are you sure we're not missing some other annotations and that a cast is the best thing here? You are right, I was a bit hasty. It is better to declare of_slot_mask to const __be32 * in the first place, instead of just const u32 * and then casting it to something else. I'll send a new patch shortly. BR, Jyri -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] ASoC: soc-core: Fix sparse warning in be32_to_cpup() call
Signed-off-by: Jyri Sarha <jsa...@ti.com> --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1929f0e..af4999c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3294,7 +3294,7 @@ static int snd_soc_of_get_slot_mask(struct device_node *np, unsigned int *mask) { u32 val; - const u32 *of_slot_mask = of_get_property(np, prop_name, ); + const __be32 *of_slot_mask = of_get_property(np, prop_name, ); int i; if (!of_slot_mask) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC] ASoC: simple-card: Update clocks binding for simple-card DAI subnodes
The updated binding provides a way to set clock-ID and direction parameters for DAI drivers set_sysclk() call back. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- I proposed something similar about a year ago, but Mark rejected that at the time. This RFC is to start that discussion again. This time before I do any code changes. Best regards, Jyri Documentation/devicetree/bindings/sound/simple-card.txt | 17 - 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index cf3979e..d10bf2d 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -76,6 +76,7 @@ Optional CPU/CODEC subnodes properties: - dai-tdm-slot-num : Please refer to tdm-slot.txt. - dai-tdm-slot-width : Please refer to tdm-slot.txt. - clocks / system-clock-frequency : specify subnode's clock if needed. + it can be specified via "clocks" if system has clock node (= common clock), or "system-clock-frequency" (if system doens't support common clock) @@ -83,7 +84,21 @@ Optional CPU/CODEC subnodes properties: enabled with clk_prepare_enable() in dai startup() and disabled with clk_disable_unprepare() in dai - shutdown(). + shutdown(). "system-clock-frequency" + can also be an array if more than one + clock is described. +- clock-ids: An array of clock ID integers, + preferrably defined in DT header. + Each entry corresponds to the same + index postion first in "clocks" and + after the end of clocks array to + "system-clock-frequency" array. +- clock-dirs : An array of integers describing + clock directions: CLK_IN (= 0) or + OUT (= 1). Entries in the array + refer to clocks in the same way as + in clock-ids property. + Example 1 - single DAI link: -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC 4/5] ASoC: davinci-mcasp: Get rid of bclk_lrclk_ratio in private data
On 09/09/15 21:27, Jyri Sarha wrote: The slot_width is for essentially same thing. Instead of storing bclk_lrclk_ratio, just store the slot_width. Comments has been updated accordingly and some variable names changed to more descriptive. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- sound/soc/davinci/davinci-mcasp.c | 56 ++- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index de1e3a8..25ff1fc 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -87,7 +87,6 @@ struct davinci_mcasp { u8 *serial_dir; u8 version; u8 bclk_div; - u16 bclk_lrclk_ratio; int streams; u32 irq_request[2]; int dma_request[2]; @@ -558,8 +557,21 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, mcasp->bclk_div = div; break; - case 2: /* BCLK/LRCLK ratio */ - mcasp->bclk_lrclk_ratio = div; + case 2: /* +* BCLK/LRCLK ratio descries how many bit-clock cycles +* fit into one frame. The clock ratio is given for a +* full period of data (for I2S format both left and +* right channels), so it has to be divided by number +* of tdm-slots (for I2S - divided by 2). +* Instead of storing this ratio, we calculate a new +* tdm_slot width by dividing the the ratio by the +* number of configured tdm slots. +*/ + mcasp->slot_width = div / mcasp->tdm_slots; + if (div % mcasp->tdm_slots) + dev_warn(mcasp->dev, +"%s(): BCLK/LRCLK %d is not divisible by %d tdm slots", +div, mcasp->tdm_slots); Oops, there is a __func__ missing here. break; default: @@ -682,11 +694,13 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, } static int davinci_config_channel_size(struct davinci_mcasp *mcasp, - int word_length) + int sample_width) { u32 fmt; - u32 tx_rotate = (word_length / 4) & 0x7; - u32 mask = (1ULL << word_length) - 1; + u32 tx_rotate = (sample_width / 4) & 0x7; + u32 mask = (1ULL << sample_width) - 1; + u32 slot_width = sample_width; + /* * For captured data we should not rotate, inversion and masking is * enoguh to get the data to the right position: @@ -699,31 +713,23 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, u32 rx_rotate = 0; /* -* if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() -* callback, take it into account here. That allows us to for example -* send 32 bits per channel to the codec, while only 16 of them carry -* audio payload. -* The clock ratio is given for a full period of data (for I2S format -* both left and right channels), so it has to be divided by number of -* tdm-slots (for I2S - divided by 2). +* Setting the tdm slot width either with set_clkdiv() or +* set_tdm_slot() allows us to for example send 32 bits per +* channel to the codec, while only 16 of them carry audio +* payload. */ - if (mcasp->bclk_lrclk_ratio) { - u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; - + if (mcasp->slot_width) { /* -* When we have more bclk then it is needed for the data, we -* need to use the rotation to move the received samples to have -* correct alignment. +* When we have more bclk then it is needed for the +* data, we need to use the rotation to move the +* received samples to have correct alignment. */ - rx_rotate = (slot_length - word_length) / 4; - word_length = slot_length; - } else if (mcasp->slot_width) { - rx_rotate = (mcasp->slot_width - word_length) / 4; - word_length = mcasp->slot_width; + slot_width = mcasp->slot_width; + rx_rotate = (slot_width - sample_width) / 4; } /* mapping of the XSSZ bit-field as described in the datasheet */ - fmt = (word_length >> 1) - 1; + fmt = (slot_width >> 1) - 1; if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in t
[PATCH RFC 3/5] ASoC: davinci-mcasp: Add set_tdm_slots() support
Implements set_tdm_slot() callback for mcasp. Channel constraints are updated according to the configured tdm mask and slots each time set_tdm_slot() is called. The special case when slot width is set to zero is allowed and it means that slot width is the same as the sample width. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- sound/soc/davinci/davinci-mcasp.c | 255 ++ 1 file changed, 174 insertions(+), 81 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index bbd1987..de1e3a8 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -80,6 +80,8 @@ struct davinci_mcasp { /* McASP specific data */ int tdm_slots; + u32 tdm_mask[2]; + int slot_width; u8 op_mode; u8 num_serializer; u8 *serial_dir; @@ -601,6 +603,84 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } +/* All serializers must have equal number of channels */ +static int davinci_mcasp_ch_constraint(struct davinci_mcasp *mcasp, int stream, + int serializers) +{ + struct snd_pcm_hw_constraint_list *cl = >chconstr[stream]; + unsigned int *list = (unsigned int *) cl->list; + int slots = mcasp->tdm_slots; + int i, count = 0; + + if (mcasp->tdm_mask[stream]) + slots = hweight32(mcasp->tdm_mask[stream]); + + for (i = 2; i <= slots; i++) + list[count++] = i; + + for (i = 2; i <= serializers; i++) + list[count++] = i*slots; + + cl->count = count; + + return 0; +} + +static int davinci_mcasp_set_ch_constraints(struct davinci_mcasp *mcasp) +{ + int rx_serializers = 0, tx_serializers = 0, ret, i; + + for (i = 0; i < mcasp->num_serializer; i++) + if (mcasp->serial_dir[i] == TX_MODE) + tx_serializers++; + else if (mcasp->serial_dir[i] == RX_MODE) + rx_serializers++; + + ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_PLAYBACK, + tx_serializers); + if (ret) + return ret; + + ret = davinci_mcasp_ch_constraint(mcasp, SNDRV_PCM_STREAM_CAPTURE, + rx_serializers); + + return ret; +} + + +static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, int slot_width) +{ + struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + + dev_dbg(mcasp->dev, +"%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n", +__func__, tx_mask, rx_mask, slots, slot_width); + + if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) { + dev_err(mcasp->dev, + "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n", + tx_mask, rx_mask, slots); + return -EINVAL; + } + + if (slot_width && + (slot_width < 8 || slot_width > 32 || slot_width % 4 != 0)) { + dev_err(mcasp->dev, "%s: Unsupported slot_width %d\n", + __func__, slot_width); + return -EINVAL; + } + + mcasp->tdm_slots = slots; + mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask; + mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask; + mcasp->slot_width = slot_width; + + return davinci_mcasp_set_ch_constraints(mcasp); +} + static int davinci_config_channel_size(struct davinci_mcasp *mcasp, int word_length) { @@ -637,6 +717,9 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, */ rx_rotate = (slot_length - word_length) / 4; word_length = slot_length; + } else if (mcasp->slot_width) { + rx_rotate = (mcasp->slot_width - word_length) / 4; + word_length = mcasp->slot_width; } /* mapping of the XSSZ bit-field as described in the datasheet */ @@ -782,33 +865,50 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, /* * If more than one serializer is needed, then use them with -* their specified tdm_slots count. Otherwise, one serializer -* can cope with the transaction using as many slots as channels -* in the stream, requires channels symmetry +* all the specified tdm_slots. Otherwise, one serializer can +* cope with the transaction using just as many slots as there +* are channels i
[PATCH RFC 2/5] ASoC: simple-card: Add tdm slot mask support to simple-card
Adds DT binding for explicitly choosing a tdm mask for DAI and uses it in simple-card. The API for snd_soc_of_parse_tdm_slot() has also been changed. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- .../devicetree/bindings/sound/tdm-slot.txt | 11 +- include/sound/simple_card.h| 2 ++ include/sound/soc.h| 2 ++ sound/soc/generic/simple-card.c| 8 +-- sound/soc/soc-core.c | 25 ++ 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt index 6a2c842..34cf70e 100644 --- a/Documentation/devicetree/bindings/sound/tdm-slot.txt +++ b/Documentation/devicetree/bindings/sound/tdm-slot.txt @@ -4,11 +4,15 @@ This specifies audio DAI's TDM slot. TDM slot properties: dai-tdm-slot-num : Number of slots in use. -dai-tdm-slot-width : Width in bits for each slot. +dai-tdm-slot-width : Width in bits for each slot. +dai-tdm-slot-tx-mask : Transmit direction slot mask, optional +dai-tdm-slot-rx-mask : Receive direction slot mask, optional For instance: dai-tdm-slot-num = <2>; dai-tdm-slot-width = <8>; + dai-tdm-slot-tx-mask = <0 1>; + dai-tdm-slot-rx-mask = <1 0>; And for each spcified driver, there could be one .of_xlate_tdm_slot_mask() to specify a explicit mapping of the channels and the slots. If it's absent @@ -18,3 +22,8 @@ tx and rx masks. For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit for an active slot as default, and the default active bits are at the LSB of the masks. + +The explicit masks are given as array of integers, where the first +number presents bit-0 (LSB), second presents bit-1, etc. Any non zero +number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask() +does not do anything, if either mask is set non zero value. diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h index b9b4f28..0399352 100644 --- a/include/sound/simple_card.h +++ b/include/sound/simple_card.h @@ -19,6 +19,8 @@ struct asoc_simple_dai { unsigned int sysclk; int slots; int slot_width; + unsigned int tx_slot_mask; + unsigned int rx_slot_mask; struct clk *clk; }; diff --git a/include/sound/soc.h b/include/sound/soc.h index 4cef20e..ca009bf 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1598,6 +1598,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, const char *propname); int snd_soc_of_parse_tdm_slot(struct device_node *np, + unsigned int *tx_mask, + unsigned int *rx_mask, unsigned int *slots, unsigned int *slot_width); void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 3ff76d4..54c3320 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -151,7 +151,9 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, } if (set->slots) { - ret = snd_soc_dai_set_tdm_slot(dai, 0, 0, + ret = snd_soc_dai_set_tdm_slot(dai, + set->tx_slot_mask, + set->rx_slot_mask, set->slots, set->slot_width); if (ret && ret != -ENOTSUPP) { @@ -243,7 +245,9 @@ asoc_simple_card_sub_parse_of(struct device_node *np, return ret; /* Parse TDM slot */ - ret = snd_soc_of_parse_tdm_slot(np, >slots, >slot_width); + ret = snd_soc_of_parse_tdm_slot(np, >tx_slot_mask, + >rx_slot_mask, + >slots, >slot_width); if (ret) return ret; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c81aec9..1929f0e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3289,13 +3289,38 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); +static int snd_soc_of_get_slot_mask(struct device_node *np, + const char *prop_name, + unsigned int *mask) +{ + u32 val; + const u32 *of_slot_mask = of_get_property(np, prop_name, ); + int i; + + if (!of_slot_mask) + return 0; + val /= sizeof(u32); + for (i = 0; i < val; i++) +
[PATCH RFC 1/5] ASoC: davinci-mcasp: Set .symmetric_rates = 1 in snd_soc_dai_driver
The TX and RX direction share the same bit clock and frame sync, so the samplerate must be the same to both directions. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- sound/soc/davinci/davinci-mcasp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index fa0511b..bbd1987 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1304,6 +1304,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { .ops= _mcasp_dai_ops, .symmetric_samplebits = 1, + .symmetric_rates= 1, }, { .name = "davinci-mcasp.1", -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC 4/5] ASoC: davinci-mcasp: Get rid of bclk_lrclk_ratio in private data
The slot_width is for essentially same thing. Instead of storing bclk_lrclk_ratio, just store the slot_width. Comments has been updated accordingly and some variable names changed to more descriptive. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- sound/soc/davinci/davinci-mcasp.c | 56 ++- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index de1e3a8..25ff1fc 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -87,7 +87,6 @@ struct davinci_mcasp { u8 *serial_dir; u8 version; u8 bclk_div; - u16 bclk_lrclk_ratio; int streams; u32 irq_request[2]; int dma_request[2]; @@ -558,8 +557,21 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, mcasp->bclk_div = div; break; - case 2: /* BCLK/LRCLK ratio */ - mcasp->bclk_lrclk_ratio = div; + case 2: /* +* BCLK/LRCLK ratio descries how many bit-clock cycles +* fit into one frame. The clock ratio is given for a +* full period of data (for I2S format both left and +* right channels), so it has to be divided by number +* of tdm-slots (for I2S - divided by 2). +* Instead of storing this ratio, we calculate a new +* tdm_slot width by dividing the the ratio by the +* number of configured tdm slots. +*/ + mcasp->slot_width = div / mcasp->tdm_slots; + if (div % mcasp->tdm_slots) + dev_warn(mcasp->dev, +"%s(): BCLK/LRCLK %d is not divisible by %d tdm slots", +div, mcasp->tdm_slots); break; default: @@ -682,11 +694,13 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai, } static int davinci_config_channel_size(struct davinci_mcasp *mcasp, - int word_length) + int sample_width) { u32 fmt; - u32 tx_rotate = (word_length / 4) & 0x7; - u32 mask = (1ULL << word_length) - 1; + u32 tx_rotate = (sample_width / 4) & 0x7; + u32 mask = (1ULL << sample_width) - 1; + u32 slot_width = sample_width; + /* * For captured data we should not rotate, inversion and masking is * enoguh to get the data to the right position: @@ -699,31 +713,23 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, u32 rx_rotate = 0; /* -* if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() -* callback, take it into account here. That allows us to for example -* send 32 bits per channel to the codec, while only 16 of them carry -* audio payload. -* The clock ratio is given for a full period of data (for I2S format -* both left and right channels), so it has to be divided by number of -* tdm-slots (for I2S - divided by 2). +* Setting the tdm slot width either with set_clkdiv() or +* set_tdm_slot() allows us to for example send 32 bits per +* channel to the codec, while only 16 of them carry audio +* payload. */ - if (mcasp->bclk_lrclk_ratio) { - u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; - + if (mcasp->slot_width) { /* -* When we have more bclk then it is needed for the data, we -* need to use the rotation to move the received samples to have -* correct alignment. +* When we have more bclk then it is needed for the +* data, we need to use the rotation to move the +* received samples to have correct alignment. */ - rx_rotate = (slot_length - word_length) / 4; - word_length = slot_length; - } else if (mcasp->slot_width) { - rx_rotate = (mcasp->slot_width - word_length) / 4; - word_length = mcasp->slot_width; + slot_width = mcasp->slot_width; + rx_rotate = (slot_width - sample_width) / 4; } /* mapping of the XSSZ bit-field as described in the datasheet */ - fmt = (word_length >> 1) - 1; + fmt = (slot_width >> 1) - 1; if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) { mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC 5/5] ASoC: tlv320aic3x: Improve tdm support
Before this patch the set_tdm_slots() callback did not store the value of slot width anywhere. The tdm support only worked if selected slot width was equal to the sample width. With this patch all sample widths that fit into the slot width are supported. There unused bits are filled unnecessarily in the capture direction, but the other end of the i2s bus should be able to ignore them. Signed-off-by: Jyri Sarha <jsa...@ti.com> --- sound/soc/codecs/tlv320aic3x.c | 30 ++ 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 1a82b19..f1c9fff 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -80,6 +80,7 @@ struct aic3x_priv { unsigned int sysclk; unsigned int dai_fmt; unsigned int tdm_delay; + unsigned int slot_width; struct list_head list; int master; int gpio_reset; @@ -1025,10 +1026,14 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; u16 d, pll_d = 1; int clk; + int width = aic3x->slot_width; + + if (!width) + width = params_width(params); /* select data word length */ data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); - switch (params_width(params)) { + switch (width) { case 16: break; case 20: @@ -1170,12 +1175,16 @@ static int aic3x_prepare(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int delay = 0; + int width = aic3x->slot_width; + + if (!width) + width = substream->runtime->sample_bits; /* TDM slot selection only valid in DSP_A/_B mode */ if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A) - delay += (aic3x->tdm_delay + 1); + delay += (aic3x->tdm_delay*width + 1); else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B) - delay += aic3x->tdm_delay; + delay += aic3x->tdm_delay*width; /* Configure data delay */ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); @@ -1296,7 +1305,20 @@ static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, return -EINVAL; } - aic3x->tdm_delay = lsb * slot_width; + switch (slot_width) { + case 16: + case 20: + case 24: + case 32: + break; + default: + dev_err(codec->dev, "Unsupported slot width %d\n", slot_width); + return -EINVAL; + } + + + aic3x->tdm_delay = lsb; + aic3x->slot_width = slot_width; /* DOUT in high-impedance on inactive bit clocks */ snd_soc_update_bits(codec, AIC3X_ASD_INTF_CTRLA, -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC 0/5] ASoC: TDM stuff for simple-card, mcasp, and tlv320aic3x
The first patch is an independent fix. The symmetric_samplebits constraint could probably be removed too (with some changes to mcasp code too), but as tlv320aic3x family codecs won't support it, I could not test it. Jyri Sarha (5): ASoC: davinci-mcasp: Set .symmetric_rates = 1 in snd_soc_dai_driver ASoC: simple-card: Add tdm slot mask support to simple-card ASoC: davinci-mcasp: Add set_tdm_slots() support ASoC: davinci-mcasp: Get rid of bclk_lrclk_ratio in private data ASoC: tlv320aic3x: Improve tdm support .../devicetree/bindings/sound/tdm-slot.txt | 11 +- include/sound/simple_card.h| 2 + include/sound/soc.h| 2 + sound/soc/codecs/tlv320aic3x.c | 30 +- sound/soc/davinci/davinci-mcasp.c | 306 ++--- sound/soc/generic/simple-card.c| 8 +- sound/soc/soc-core.c | 25 ++ 7 files changed, 274 insertions(+), 110 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled
On 08/28/15 13:37, Tomi Valkeinen wrote: On 26/08/15 16:11, Jyri Sarha wrote: diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c index 7f87578..f352c4b 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5.c @@ -352,6 +352,7 @@ static int read_edid(u8 *buf, int len) static int hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_dss_device *out = hdmi.output; + unsigned long flags; int r = 0; DSSDBG(ENTER hdmi_display_enable\n); @@ -370,7 +371,37 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } + if (hdmi.audio_configured) { + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + hdmi_wp_audio_core_req_enable(hdmi.wp, false); + hdmi_wp_audio_enable(hdmi.wp, false); + if (hdmi.wp_idlemode 0) + REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, + hdmi.wp_idlemode, 3, 2); + hdmi.wp_idlemode = -1; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); Here I think the audio HW is always disabled already. It has to be, because the whole HDMI IP has been off. So the above should not be needed. + + r = hdmi5_audio_config(hdmi.core, hdmi.wp, hdmi.audio_config, + hdmi.cfg.timings.pixelclock); + if (r) { + DSSERR(Error restoring audio configuration: %d, r); + hdmi.audio_abort_cb(hdmi.pdev-dev); + hdmi.audio_configured = false; + } + } + + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + if (hdmi.audio_configured hdmi.audio_playing) { + /* No-idle while playing audio, store the old value */ + hdmi.wp_idlemode = + REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); + REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); + + hdmi_wp_audio_enable(hdmi.wp, true); + hdmi_wp_audio_core_req_enable(hdmi.wp, true); + } hdmi.display_enabled = true; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); Maybe you've looked at the locking carefully, but it's not obvious to me. So is hdmi_audio_start and hdmi_audio_stop the only functions that are called from atomic context? Every other function is protected with the mutex? The idea is for the spinlock to make audio start, audio stop, and updates to hdmi.display_enabled and hdmi.audio_playing variable atomic. This is needed for the transitions from display enabled state (when audio start/stop commands can be written to HW) to display disabled state (when audio start/stop commands update only the hdmi.audio_playing variable) to always serialize correctly. IOW, the idea is to make sure the hdmi.audio_playing variable is always in sync with what is in the HW when hdmi.display_enabled == true. For example: when display is turned back on we take the spinlock and we can be sure that the audio start/stop status won't change while we update the HW according to current state and set hdmi.display_enabled to true. After releasing the lock hdmi.display_enabled is true and all audio_start and audio_stop commands write their stuff directly to HW. In theory, just making hdmi.display_enabled and hdmi.audio_playing atomic-variables and touching them always in correct oreder should be enough, but explaining the mechanism would then be even trickier. Cheers, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled
On 08/28/15 16:04, Tomi Valkeinen wrote: ... The question is (which was my point in the earlier mail), we already have mutex, so why a new spinlock? I think the answer is that audio start/stop (anything else?) are called in atomic context, so mutex cannot be used. Yes, that is correct. Also (not exactly related to this patch), if the audio callbacks must be atomic, could we use a workqueue to run the audio start/stop work in non-atomic context? Protecting the whole hdmi state with a single mutex would be much nicer. The reason why the audio start and stop are done in atomic context is for audio synchronization to other audio devices or video stream to be more accurate. I guess in theory a work queue could be used to serialize the audio commands, but that would ruin the whole point of why the start and stop commands are atomic in the first place. Cheers, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3] OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled
Reconfigure and restart audio when display is enabled, if audio playback was active before. This is needed in a situation when an audio+video stream application opens the audio stream before the video. When video stream is opened the display mode may change and that would aborted audio playback, because the display is momentarily turned off. The audio configuration is stored when it is successfully applied and a boolean is set when the audio playback is started and unset when stopped. This data is used to reconfigure the audio when display is re-enabled. The audio playback is aborted if the reconfiguration fails. A new spin lock is introduced in order to protect state variables related to audio playback status. This is needed for the transition from display enabled state (when audio start/stop commands can be written to HW) to display disabled state (when audio start/stop commands update only the hdmi.audio_playing variable) to always serialize correctly with the start/stop audio commands. The already existing mutex can not be used, because the audio start and stop commands are executed in atomic context. For example: when display is turned back on we take the spinlock and we can be sure that the audio start/stop status will not change while we update the HW according to hdmi.audio_playing state and set hdmi.display_enabled to true. After releasing the lock hdmi.display_enabled is true and all audio_start and audio_stop commands write their stuff directly to HW. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/hdmi.h | 9 - drivers/video/fbdev/omap2/dss/hdmi4.c | 66 +- drivers/video/fbdev/omap2/dss/hdmi5.c | 76 --- 3 files changed, 124 insertions(+), 27 deletions(-) diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h index e4a32fe..53616b0 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi.h +++ b/drivers/video/fbdev/omap2/dss/hdmi.h @@ -351,13 +351,20 @@ struct omap_hdmi { struct regulator *vdda_reg; bool core_enabled; - bool display_enabled; struct omap_dss_device output; struct platform_device *audio_pdev; void (*audio_abort_cb)(struct device *dev); int wp_idlemode; + + bool audio_configured; + struct omap_dss_audio audio_config; + + /* This lock should be taken when booleans bellow are touched. */ + spinlock_t audio_playing_lock; + bool audio_playing; + bool display_enabled; }; #endif diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index 6d3aa3f..94c8d55 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c @@ -321,9 +321,22 @@ static int read_edid(u8 *buf, int len) return r; } +static void hdmi_start_audio_stream(struct omap_hdmi *hd) +{ + hdmi_wp_audio_enable(hd-wp, true); + hdmi4_audio_start(hd-core, hd-wp); +} + +static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +{ + hdmi4_audio_stop(hd-core, hd-wp); + hdmi_wp_audio_enable(hd-wp, false); +} + static int hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_dss_device *out = hdmi.output; + unsigned long flags; int r = 0; DSSDBG(ENTER hdmi_display_enable\n); @@ -342,7 +355,21 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } + if (hdmi.audio_configured) { + r = hdmi4_audio_config(hdmi.core, hdmi.wp, hdmi.audio_config, + hdmi.cfg.timings.pixelclock); + if (r) { + DSSERR(Error restoring audio configuration: %d, r); + hdmi.audio_abort_cb(hdmi.pdev-dev); + hdmi.audio_configured = false; + } + } + + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + if (hdmi.audio_configured hdmi.audio_playing) + hdmi_start_audio_stream(hdmi); hdmi.display_enabled = true; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); mutex_unlock(hdmi.lock); return 0; @@ -354,17 +381,19 @@ err0: static void hdmi_display_disable(struct omap_dss_device *dssdev) { + unsigned long flags; + DSSDBG(Enter hdmi_display_disable\n); mutex_lock(hdmi.lock); - if (hdmi.audio_pdev hdmi.audio_abort_cb) - hdmi.audio_abort_cb(hdmi.audio_pdev-dev); + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + hdmi_stop_audio_stream(hdmi); + hdmi.display_enabled = false; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); hdmi_power_off_full(dssdev); - hdmi.display_enabled = false; - mutex_unlock(hdmi.lock); } @@ -568,6 +597,8 @@ static int hdmi_audio_shutdown(struct device *dev) mutex_lock(hd-lock); hd
[PATCH v2] OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled
Reconfigure and restart audio when display is enabled, if audio playback was active before. The audio configuration is stored when is is successfully applied and a boolean is set when playback has started and unset when stopped. This data is used to reconfigure the audio when display is re-enabled. Abort audio playback if reconfiguration fails. A new spin lock is introduced in order to protect state variables related to audio playback status. This is needed for the transitions from display enabled state (when audio start/stop commands can be written to HW) to display disabled state (when audio start/stop commands update only the hdmi.audio_playing variable) to always serialize correctly with the start/stop audio commands. For example: when display is turned back on we take the spinlock and we can be sure that the audio start/stop status won't change while we update the HW according to hdmi.audio_playing state and set hdmi.display_enabled to true. After releasing the lock hdmi.display_enabled is true and all audio_start and audio_stop commands write their stuff directly to HW. Signed-off-by: Jyri Sarha jsa...@ti.com --- I dropped the ASoC maintainers from the recipient list as this patch hardly concerns them. drivers/video/fbdev/omap2/dss/hdmi.h | 9 +++- drivers/video/fbdev/omap2/dss/hdmi4.c | 69 +- drivers/video/fbdev/omap2/dss/hdmi5.c | 79 --- 3 files changed, 130 insertions(+), 27 deletions(-) diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h index e4a32fe..e48aefd 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi.h +++ b/drivers/video/fbdev/omap2/dss/hdmi.h @@ -351,13 +351,20 @@ struct omap_hdmi { struct regulator *vdda_reg; bool core_enabled; - bool display_enabled; struct omap_dss_device output; struct platform_device *audio_pdev; void (*audio_abort_cb)(struct device *dev); int wp_idlemode; + + bool audio_configured; + struct omap_dss_audio audio_config; + + /* This lock should be taken when booleas bellow is touched. */ + spinlock_t audio_playing_lock; + bool audio_playing; + bool display_enabled; }; #endif diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index 6d3aa3f..6b9817a 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c @@ -321,9 +321,22 @@ static int read_edid(u8 *buf, int len) return r; } +static void hdmi_start_audio_stream(struct omap_hdmi *hd) +{ + hdmi_wp_audio_enable(hd-wp, true); + hdmi4_audio_start(hd-core, hd-wp); +} + +static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +{ + hdmi4_audio_stop(hd-core, hd-wp); + hdmi_wp_audio_enable(hd-wp, false); +} + static int hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_dss_device *out = hdmi.output; + unsigned long flags; int r = 0; DSSDBG(ENTER hdmi_display_enable\n); @@ -342,7 +355,21 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } + if (hdmi.audio_configured) { + r = hdmi4_audio_config(hdmi.core, hdmi.wp, hdmi.audio_config, + hdmi.cfg.timings.pixelclock); + if (r) { + DSSERR(Error restoring audio configuration: %d, r); + hdmi.audio_abort_cb(hdmi.pdev-dev); + hdmi.audio_configured = false; + } + } + + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + if (hdmi.audio_configured hdmi.audio_playing) + hdmi_start_audio_stream(hdmi); hdmi.display_enabled = true; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); mutex_unlock(hdmi.lock); return 0; @@ -354,17 +381,19 @@ err0: static void hdmi_display_disable(struct omap_dss_device *dssdev) { + unsigned long flags; + DSSDBG(Enter hdmi_display_disable\n); mutex_lock(hdmi.lock); - if (hdmi.audio_pdev hdmi.audio_abort_cb) - hdmi.audio_abort_cb(hdmi.audio_pdev-dev); + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + hdmi_stop_audio_stream(hdmi); + hdmi.display_enabled = false; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); hdmi_power_off_full(dssdev); - hdmi.display_enabled = false; - mutex_unlock(hdmi.lock); } @@ -565,9 +594,14 @@ out: static int hdmi_audio_shutdown(struct device *dev) { struct omap_hdmi *hd = dev_get_drvdata(dev); + unsigned long flags; mutex_lock(hd-lock); hd-audio_abort_cb = NULL; + hd-audio_configured = false; + spin_lock_irqsave(hd-audio_playing_lock, flags); + hd-audio_playing = false; + spin_unlock_irqrestore(hd-audio_playing_lock, flags
Re: [PATCH v2] OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled
On 08/28/15 15:24, Jyri Sarha wrote: @@ -565,9 +594,14 @@ out: static int hdmi_audio_shutdown(struct device *dev) { struct omap_hdmi *hd = dev_get_drvdata(dev); + unsigned long flags; mutex_lock(hd-lock); hd-audio_abort_cb = NULL; + hd-audio_configured = false; + spin_lock_irqsave(hd-audio_playing_lock, flags); + hd-audio_playing = false; + spin_unlock_irqrestore(hd-audio_playing_lock, flags); BTW, This extra locking (and the corresponding change in hdmi5.c) should not be needed. But it does not harm either. I'll fix that, but I'll wait first if there is anything else fix. Best regards, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4] OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled
Reconfigure and restart audio when display is enabled, if audio playback was active before. This is needed in a situation when an audio+video stream application opens the audio stream before the video. When video stream is opened the display mode may change and that aborts audio playback, because the display is momentarily turned off. The audio configuration is stored when it is successfully applied and a boolean is set when the audio playback is started and unset when stopped. This data is used to reconfigure the audio when display is re-enabled. The audio playback is aborted if the reconfiguration fails. A new spin lock is introduced in order to protect state variables related to audio playback status. This is needed for the transition from display enabled state (when audio start/stop commands can be written to HW) to display disabled state (when audio start/stop commands update only the hdmi.audio_playing variable) to always serialize correctly with the start/stop audio commands. The already existing mutex can not be used, because the audio start and stop commands are executed in atomic context. For example: when display is turned back on we take the spinlock and we can be sure that the audio start/stop status will not change while we update the HW according to hdmi.audio_playing state and set hdmi.display_enabled to true. After releasing the lock hdmi.display_enabled is true and all audio_start and audio_stop commands write their stuff directly to HW. Signed-off-by: Jyri Sarha jsa...@ti.com --- Fixed one bad sentece in the description. drivers/video/fbdev/omap2/dss/hdmi.h | 9 - drivers/video/fbdev/omap2/dss/hdmi4.c | 66 +- drivers/video/fbdev/omap2/dss/hdmi5.c | 76 --- 3 files changed, 124 insertions(+), 27 deletions(-) diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h index e4a32fe..53616b0 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi.h +++ b/drivers/video/fbdev/omap2/dss/hdmi.h @@ -351,13 +351,20 @@ struct omap_hdmi { struct regulator *vdda_reg; bool core_enabled; - bool display_enabled; struct omap_dss_device output; struct platform_device *audio_pdev; void (*audio_abort_cb)(struct device *dev); int wp_idlemode; + + bool audio_configured; + struct omap_dss_audio audio_config; + + /* This lock should be taken when booleans bellow are touched. */ + spinlock_t audio_playing_lock; + bool audio_playing; + bool display_enabled; }; #endif diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index 6d3aa3f..94c8d55 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c @@ -321,9 +321,22 @@ static int read_edid(u8 *buf, int len) return r; } +static void hdmi_start_audio_stream(struct omap_hdmi *hd) +{ + hdmi_wp_audio_enable(hd-wp, true); + hdmi4_audio_start(hd-core, hd-wp); +} + +static void hdmi_stop_audio_stream(struct omap_hdmi *hd) +{ + hdmi4_audio_stop(hd-core, hd-wp); + hdmi_wp_audio_enable(hd-wp, false); +} + static int hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_dss_device *out = hdmi.output; + unsigned long flags; int r = 0; DSSDBG(ENTER hdmi_display_enable\n); @@ -342,7 +355,21 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } + if (hdmi.audio_configured) { + r = hdmi4_audio_config(hdmi.core, hdmi.wp, hdmi.audio_config, + hdmi.cfg.timings.pixelclock); + if (r) { + DSSERR(Error restoring audio configuration: %d, r); + hdmi.audio_abort_cb(hdmi.pdev-dev); + hdmi.audio_configured = false; + } + } + + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + if (hdmi.audio_configured hdmi.audio_playing) + hdmi_start_audio_stream(hdmi); hdmi.display_enabled = true; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); mutex_unlock(hdmi.lock); return 0; @@ -354,17 +381,19 @@ err0: static void hdmi_display_disable(struct omap_dss_device *dssdev) { + unsigned long flags; + DSSDBG(Enter hdmi_display_disable\n); mutex_lock(hdmi.lock); - if (hdmi.audio_pdev hdmi.audio_abort_cb) - hdmi.audio_abort_cb(hdmi.audio_pdev-dev); + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + hdmi_stop_audio_stream(hdmi); + hdmi.display_enabled = false; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); hdmi_power_off_full(dssdev); - hdmi.display_enabled = false; - mutex_unlock(hdmi.lock); } @@ -568,6 +597,8 @@ static int hdmi_audio_shutdown(struct device *dev
[PATCH 1/2] OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled
Reconfigure and restart audio when display is enabled, if audio playback was active before. The audio configuration is stored when is is successfully applied and a boolean is set when playback has started and unset when stopped. This data is used to reconfigure the audio when display is re-enabled. Abort audio playback if reconfiguration fails. A new spin lock is introduced to in order protect state variables related to audio playback status. The wp_idlemode protection relies on PM not touching it after the original initialization. A power management API for controlling the idlemode would be needed for proper synchronization. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/hdmi.h | 10 +++- drivers/video/fbdev/omap2/dss/hdmi4.c | 65 - drivers/video/fbdev/omap2/dss/hdmi5.c | 89 +-- 3 files changed, 137 insertions(+), 27 deletions(-) diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h index e4a32fe..1e45b84 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi.h +++ b/drivers/video/fbdev/omap2/dss/hdmi.h @@ -351,12 +351,20 @@ struct omap_hdmi { struct regulator *vdda_reg; bool core_enabled; - bool display_enabled; struct omap_dss_device output; struct platform_device *audio_pdev; void (*audio_abort_cb)(struct device *dev); + + bool audio_configured; + struct omap_dss_audio audio_config; + + /* This lock should be taken when any one of the three + state variables bellow are touched. */ + spinlock_t audio_playing_lock; + bool audio_playing; + bool display_enabled; int wp_idlemode; }; diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index 6d3aa3f..ea1fa64 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c @@ -324,6 +324,7 @@ static int read_edid(u8 *buf, int len) static int hdmi_display_enable(struct omap_dss_device *dssdev) { struct omap_dss_device *out = hdmi.output; + unsigned long flags; int r = 0; DSSDBG(ENTER hdmi_display_enable\n); @@ -342,7 +343,26 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } + if (hdmi.audio_configured) { + hdmi4_audio_stop(hdmi.core, hdmi.wp); + hdmi_wp_audio_enable(hdmi.wp, false); + + r = hdmi4_audio_config(hdmi.core, hdmi.wp, hdmi.audio_config, + hdmi.cfg.timings.pixelclock); + if (r) { + DSSERR(Error restoring audio configuration: %d, r); + hdmi.audio_abort_cb(hdmi.pdev-dev); + hdmi.audio_configured = false; + } + } + + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + if (hdmi.audio_configured hdmi.audio_playing) { + hdmi_wp_audio_enable(hdmi.wp, true); + hdmi4_audio_start(hdmi.core, hdmi.wp); + } hdmi.display_enabled = true; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); mutex_unlock(hdmi.lock); return 0; @@ -354,17 +374,18 @@ err0: static void hdmi_display_disable(struct omap_dss_device *dssdev) { + unsigned long flags; + DSSDBG(Enter hdmi_display_disable\n); mutex_lock(hdmi.lock); - if (hdmi.audio_pdev hdmi.audio_abort_cb) - hdmi.audio_abort_cb(hdmi.audio_pdev-dev); + spin_lock_irqsave(hdmi.audio_playing_lock, flags); + hdmi.display_enabled = false; + spin_unlock_irqrestore(hdmi.audio_playing_lock, flags); hdmi_power_off_full(dssdev); - hdmi.display_enabled = false; - mutex_unlock(hdmi.lock); } @@ -565,9 +586,14 @@ out: static int hdmi_audio_shutdown(struct device *dev) { struct omap_hdmi *hd = dev_get_drvdata(dev); + unsigned long flags; mutex_lock(hd-lock); hd-audio_abort_cb = NULL; + hd-audio_configured = false; + spin_lock_irqsave(hd-audio_playing_lock, flags); + hd-audio_playing = false; + spin_unlock_irqrestore(hd-audio_playing_lock, flags); mutex_unlock(hd-lock); return 0; @@ -576,25 +602,38 @@ static int hdmi_audio_shutdown(struct device *dev) static int hdmi_audio_start(struct device *dev) { struct omap_hdmi *hd = dev_get_drvdata(dev); + unsigned long flags; WARN_ON(!hdmi_mode_has_audio(hd-cfg)); - WARN_ON(!hd-display_enabled); - hdmi_wp_audio_enable(hd-wp, true); - hdmi4_audio_start(hd-core, hd-wp); + spin_lock_irqsave(hd-audio_playing_lock, flags); + + if (hd-display_enabled) { + hdmi_wp_audio_enable(hd-wp, true); + hdmi4_audio_start(hd-core, hd-wp); + } + hd-audio_playing = true; + spin_unlock_irqrestore(hd
[PATCH 0/2] OMAPDSS: Couple of HDMI audio fixes
The first fix is a hairy one, but I think the locking is fool proof now. It is needed because there is no telling in which order user space starts an audio and video stream playback. If the audio is started first and the video mode is changed when video playback starts the audio setup needs to survive display turning off and back on again. After this patch the audio streams should survive a suspend-resume cycle too. The second one is a trivial work-around to a problem in ALSA constraint resolver code. The two fixes are totally independent and the video and audio side patches applied separately trough their own trees. Jyri Sarha (2): OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled ASoC: omap-hdmi-audio: Set buffer bytes step constraint to 128 drivers/video/fbdev/omap2/dss/hdmi.h | 10 +++- drivers/video/fbdev/omap2/dss/hdmi4.c | 65 - drivers/video/fbdev/omap2/dss/hdmi5.c | 89 +-- sound/soc/omap/omap-hdmi-audio.c | 10 +++- 4 files changed, 146 insertions(+), 28 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] ASoC: omap-hdmi-audio: Set buffer bytes step constraint to 128
Set buffer bytes step constraint to 128. A matching constraint has already been set to period size. This helps PCM setup to tolerate ALSA clients that set the PCM hw params in unusual order. Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/omap/omap-hdmi-audio.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index aeef25c..584b237 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -81,7 +81,15 @@ static int hdmi_dai_startup(struct snd_pcm_substream *substream, ret = snd_pcm_hw_constraint_step(substream-runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); if (ret 0) { - dev_err(dai-dev, could not apply constraint\n); + dev_err(dai-dev, Could not apply period constraint: %d\n, + ret); + return ret; + } + ret = snd_pcm_hw_constraint_step(substream-runtime, 0, +SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128); + if (ret 0) { + dev_err(dai-dev, Could not apply buffer constraint: %d\n, + ret); return ret; } -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v3 3/7] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
On 08/17/15 10:57, Jyri Sarha wrote: Missed one commet first time around... On 08/14/15 19:18, Mark Brown wrote: On Fri, Aug 14, 2015 at 12:30:41PM +0300, Jyri Sarha wrote: ... +/* HDMI codec initalization data */ +struct hdmi_codec_pdata { +struct device *dev; /* The HDMI encoder registering the codec */ Shouldn't this just be dev-parent? No. The HDMI encoder device is the parent for HDMI-codec. The patch you took in in the last round uses the ASoC component drivers parent's of-node if the component driver does not have one itself. In this case the phandle in the binding points to the HDMI encoder's node, which is the parent of the HDMI codec. After reading the comment again I see now what you meant. Yes, I can extract the encoder device from the dev-parent pointer. No need to have it in pdata. Thanks, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v3 6/7] drm/i2c: tda998x: Register ASoC HDMI codec for audio functionality
On 08/14/15 13:06, Russell King - ARM Linux wrote: On Fri, Aug 14, 2015 at 12:30:44PM +0300, Jyri Sarha wrote: +static int tda998x_write_aif(struct tda998x_priv *priv, +struct hdmi_audio_infoframe *cea) +{ + uint8_t buf[HDMI_INFOFRAME_SIZE(AUDIO)]; + int len; + + len = hdmi_audio_infoframe_pack(cea, buf, sizeof(buf)); + if (len 0) { + dev_err(priv-hdmi-dev, + Failed to pack audio infoframe: %d\n, len); + return len; + } + + /* Write the audio information packet */ + tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf, len); + return 0; +} + I have such a function already queued up, but I can't push it out at the moment because of too many conflicts across all my DRM work. I'm waiting for after 4.3-rc1 before publishing anything from or accepting anything else into DRM branches. Ok, is the code available some where? Could take a look so I can align my code to that. static void tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode) { @@ -670,19 +691,24 @@ static void tda998x_audio_mute(struct tda998x_priv *priv, bool on) } } -static void +static int tda998x_configure_audio(struct tda998x_priv *priv, - struct drm_display_mode *mode, struct tda998x_encoder_params *p) + int mode_clock, + int ena_ap, + int dai_format, + int sample_width, + int sample_rate, + const u8 *status) I don't think this is an improvement. Still it makes the function more generic and enables its usage in HDMI-codec API implementation. I'll try to make it look tidier. +static int tda998x_audio_get_eld(struct device *dev, uint8_t *buf, size_t len) +{ + struct tda998x_priv *priv = dev_get_drvdata(dev); + struct drm_mode_config *config = priv-encoder-dev-mode_config; + struct drm_connector *connector; + int ret = -ENODEV; + + mutex_lock(config.mutex); + list_for_each_entry(connector, config-connector_list, head) { + if (priv-encoder == connector-encoder) { + memcpy(buf, connector-eld, + min(sizeof(connector-eld), len)); + ret = 0; + } + } + mutex_unlock(config.mutex); Obviously untested. Should be config-mutex. Sorry. Should never do these last minute changes. I must have been compiling and testing different code version. I first had this function using config-connection_mutex, but then - after reading the eld related code - found that mode_config mutex should be used instead. But in any case, when I kill the DRM slave encoder code in here, this becomes unnecessary. Ok, The information from ELD needs be passed to audio side constraints somehow. I'd love to see the code you have in queue. Best regards, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v3 3/7] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
Missed one commet first time around... On 08/14/15 19:18, Mark Brown wrote: On Fri, Aug 14, 2015 at 12:30:41PM +0300, Jyri Sarha wrote: ... +/* HDMI codec initalization data */ +struct hdmi_codec_pdata { + struct device *dev; /* The HDMI encoder registering the codec */ Shouldn't this just be dev-parent? No. The HDMI encoder device is the parent for HDMI-codec. The patch you took in in the last round uses the ASoC component drivers parent's of-node if the component driver does not have one itself. In this case the phandle in the binding points to the HDMI encoder's node, which is the parent of the HDMI codec. Best regards, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v3 3/7] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
On 08/17/15 21:41, Mark Brown wrote: On Mon, Aug 17, 2015 at 10:07:55AM +0300, Jyri Sarha wrote: On 08/14/15 19:18, Mark Brown wrote: On Fri, Aug 14, 2015 at 12:30:41PM +0300, Jyri Sarha wrote: + /* Called when ASoC starts an audio stream setup. The call +* provides an audio abort callback for stoping an ongoing +* stream if the HDMI audio becomes unavailable. +* Optional */ + int (*audio_startup)(struct device *dev, +void (*abort_cb)(struct device *dev)); I'm a bit confused about what is going to use abort_cb() and why they wouldn't just call shutdown instead? audio_shutdown() is for ASoC side to tell video side that audio playback has stopped. The abort_cb() is for video side to inform ASoC that current audio stream can not continue anymore and it should be aborted. The similar mechanism is currently in use in sound/soc/omap/omap-hdmi-audio.c. Someone reading the code needs to be able to understand this. Ok, I'll improve the comment above. Thanks, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v3 3/7] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
On 08/14/15 12:57, Russell King - ARM Linux wrote: On Fri, Aug 14, 2015 at 12:30:41PM +0300, Jyri Sarha wrote: +static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + struct hdmi_codec_params hp = { + .cea = { 0 }, Unnecessary initialisation - because you are initialising this structure, all unnamed fields will be zeroed. True, I just tried to be explicit. + .iec = { + .status = { + IEC958_AES0_CON_NOT_COPYRIGHT, + IEC958_AES1_CON_GENERAL, + IEC958_AES2_CON_SOURCE_UNSPEC, + IEC958_AES3_CON_CLOCK_VARIABLE, + }, ... + hdmi_audio_infoframe_init(hp.cea); + hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_PCM; Something tells me here that you haven't read the HDMI specification. HDMI says that the coding type will be zero (refer to stream header). The same goes for much of the CEA audio infoframe. Please see the Audio InfoFrame details in the HDMI specification. Must admit, that I have not read it end to end. Obviously I have missed a relevant piece of information here. I'll fix that and check the related items too. + hp.cea.channels = params_channels(params); + + switch (params_width(params)) { + case 16: + hp.iec.status[4] |= IEC958_AES4_CON_WORDLEN_20_16; + hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; + break; + case 18: + hp.iec.status[4] |= IEC958_AES4_CON_WORDLEN_22_18; + hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; + break; + case 20: + hp.iec.status[4] |= IEC958_AES4_CON_WORDLEN_24_20; + hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; + break; + case 24: + case 32: + hp.iec.status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24 | + IEC958_AES4_CON_WORDLEN_24_20; Why not use the generic code to generate the AES channel status bits? See sound/core/pcm_iec958.c. Thanks, I did not know that exist. I'll make use of that. Best regards, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v3 2/7] ASoC: hdmi: Remove obsolete dummy HDMI codec
On 08/14/15 19:10, Mark Brown wrote: On Fri, Aug 14, 2015 at 12:30:40PM +0300, Jyri Sarha wrote: The hdmi stub codec has not been used since refactoring of OMAP HDMI audio support. grep tells me that the OMAP HDMI4 and HDMI5 drivers are still registering this device in -next... Really? My source trees for mainline and linux-next look like this: $ git grep hdmi-audio-codec sound/soc/codecs/hdmi.c:#define DRV_NAME hdmi-audio-codec Don't you mean omap-hdmi-audio, that is implemented in sound/soc/omap/omap-hdmi-audio.c ? That driver is bit different. It implements ASoC card and uses generic dummy codec. The hdmi-audio-codec has not been used for OMAP HDMI audio for several releases already. Best regards, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v3 3/7] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
On 08/14/15 19:18, Mark Brown wrote: On Fri, Aug 14, 2015 at 12:30:41PM +0300, Jyri Sarha wrote: +struct hdmi_codec_ops { + /* For runtime clock configuration from ASoC machine driver. +* A direct forward from set_sysclk in struct snd_soc_dai_ops. +* Optional */ + int (*set_clk)(struct device *dev, int clk_id, int freq); I'd be much happier if we were using the clock API as the external interface here, it's where we want to be internally too and it's going to be easier to not introduce any external dependencies on the ASoC internal stuff. Sounds better. I'll change that. + /* Called when ASoC starts an audio stream setup. The call +* provides an audio abort callback for stoping an ongoing +* stream if the HDMI audio becomes unavailable. +* Optional */ + int (*audio_startup)(struct device *dev, +void (*abort_cb)(struct device *dev)); I'm a bit confused about what is going to use abort_cb() and why they wouldn't just call shutdown instead? audio_shutdown() is for ASoC side to tell video side that audio playback has stopped. The abort_cb() is for video side to inform ASoC that current audio stream can not continue anymore and it should be aborted. The similar mechanism is currently in use in sound/soc/omap/omap-hdmi-audio.c. +/* HDMI codec initalization data */ +struct hdmi_codec_pdata { + struct device *dev; /* The HDMI encoder registering the codec */ Shouldn't this just be dev-parent? +enum { + DAI_ID_I2C = 0, + DAI_ID_SPDIF, +}; I2C? :P Right, should be I2S. Thanks! Best regards, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RFC v2 3/7] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
On 08/14/15 22:25, Mark Brown wrote: On Tue, May 26, 2015 at 09:59:07PM +0300, Jyri Sarha wrote: + + mutex_lock(hcp-current_stream_lock); + if (hcp-current_stream hcp-current_stream-runtime + snd_pcm_running(hcp-current_stream)) { + dev_info(dev, HDMI audio playback aborted\n); Does this really need to be dev_info()? No, I'll change that to debug level. + if (hcp-hcd.ops-get_eld) { + hcp-eld = hcp-hcd.ops-get_eld(hcp-hcd.dev); + + /* Call snd_pcm_hw_constraint_eld here */ + } ... + dev_dbg(dai-dev, %s()\n, __func__); + + mutex_lock(hcp-current_stream_lock); + BUG_ON(hcp-current_stream != substream); + hcp-current_stream = NULL; + mutex_unlock(hcp-current_stream_lock); + + hcp-hcd.ops-audio_shutdown(hcp-hcd.dev); Shouldn't the callback be in or before the lock? Otherwise we could potentially race with starting a new stream. Yes, it should be before it. I'll fix that. If it is inside, there is a possible deadlock warning (atleast in the similar place in omap-hdmi-audio there was) if those warnings are turned on and there is another lock that is taken in the video side callbacks. Thanks, Jyri -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v3 7/7] ARM: dts: am335x-boneblack: Add HDMI audio support
Add HDMI audio support. Adds mcasp0_pins, clk_mcasp0_fixed, clk_mcasp0, mcasp0, sound node, and updates the tda19988 node to follow the new binding. Signed-off-by: Jyri Sarha jsa...@ti.com --- arch/arm/boot/dts/am335x-boneblack.dts | 90 -- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts index eadbba3..7d3e899 100644 --- a/arch/arm/boot/dts/am335x-boneblack.dts +++ b/arch/arm/boot/dts/am335x-boneblack.dts @@ -64,6 +64,16 @@ 0x1b0 0x03 /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */ ; }; + + mcasp0_pins: mcasp0_pins { + pinctrl-single,pins = + 0x1ac (PIN_INPUT_PULLUP | MUX_MODE0)/* mcasp0_ahclkx.mcasp0_ahclkx */ + 0x19c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2 */ + 0x194 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */ + 0x190 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */ + 0x06c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */ + ; + }; }; lcdc { @@ -76,17 +86,89 @@ }; i2c0 { - tda19988 { + tda19988: tda19988 { compatible = nxp,tda998x; reg = 0x70; + + #sound-dai-cells = 0; + pinctrl-names = default, off; pinctrl-0 = nxp_hdmi_bonelt_pins; pinctrl-1 = nxp_hdmi_bonelt_off_pins; - port { - hdmi_0: endpoint@0 { - remote-endpoint = lcdc_0; + ports { + #address-cells = 1; + #size-cells = 0; + port@0 { + port-type = rgb; + reg = 0x230145; + hdmi_0: endpoint@0 { + remote-endpoint = lcdc_0; + }; }; + port@1 { + port-type = i2s; + reg = 0x03; + tda19988_i2s: endpoint { + remote-endpoint = mcasp0_i2s; + }; + }; + }; + }; +}; + +rtc { + system-power-controller; +}; + +mcasp0{ + #sound-dai-cells = 0; + pinctrl-names = default; + pinctrl-0 = mcasp0_pins; + status = okay; + op-mode = 0; /* MCASP_IIS_MODE */ + tdm-slots = 2; + serial-dir = /* 0: INACTIVE, 1: TX, 2: RX */ + 0 0 1 0 + ; + tx-num-evt = 1; + rx-num-evt = 1; + + port { + mcasp0_i2s: endpoint { + remote-endpoint = tda19988_i2s; + }; + }; +}; + +/ { + clk_mcasp0_fixed: clk_mcasp0_fixed { + #clock-cells = 0; + compatible = fixed-clock; + clock-frequency = 24576000; + }; + + clk_mcasp0: clk_mcasp0 { + #clock-cells = 0; + compatible = gpio-gate-clock; + clocks = clk_mcasp0_fixed; + enable-gpios = gpio1 27 0; /* BeagleBone Black Clk enable on GPIO1_27 */ + }; + + sound { + compatible = simple-audio-card; + simple-audio-card,name = TI BeagleBone Black; + simple-audio-card,format = i2s; + simple-audio-card,bitclock-master = dailink0_master; + simple-audio-card,frame-master = dailink0_master; + + dailink0_master: simple-audio-card,cpu { + sound-dai = mcasp0; + clocks = clk_mcasp0; + }; + + simple-audio-card,codec { + sound-dai = tda19988; }; }; }; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v3 4/7] drm/i2c: tda998x: Add support of a DT graph of ports
From: Jean-Francois Moine moin...@free.fr Two kinds of ports may be declared in a DT graph of ports: video and audio. This patch accepts the port value from a video port as an alternative to the video-ports property. It also accepts audio ports in the case the transmitter is not used as a slave encoder. The new file include/sound/tda998x.h prepares to the definition of a tda998x CODEC. Signed-off-by: Jean-Francois Moine moin...@free.fr Signed-off-by: Jyri Sarha jsa...@ti.com --- .../devicetree/bindings/drm/i2c/tda998x.txt| 51 drivers/gpu/drm/i2c/tda998x_drv.c | 90 +++--- include/sound/tda998x.h| 8 ++ 3 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 include/sound/tda998x.h diff --git a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt index e9e4bce..35f6a80 100644 --- a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt +++ b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt @@ -16,6 +16,35 @@ Optional properties: - video-ports: 24 bits value which defines how the video controller output is wired to the TDA998x input - default: 0x230145 + This property is not used when ports are defined. + +Optional nodes: + + - port: up to three ports. + The ports are defined according to [1]. + +Video port. + There may be only one video port. + This one must contain the following property: + + - port-type: must be rgb + + and may contain the optional property: + + - reg: 24 bits value which defines how the video controller + output is wired to the TDA998x input (video pins) + When absent, the default value is 0x230145. + +Audio ports. + There may be one or two audio ports. + These ones must contain the following properties: + + - port-type: must be i2s or spdif + + - reg: 8 bits value which defines how the audio controller + output is wired to the TDA998x input (audio pins) + +[1] Documentation/devicetree/bindings/graph.txt Example: @@ -26,4 +55,26 @@ Example: interrupts = 27 2;/* falling edge */ pinctrl-0 = pmx_camera; pinctrl-names = default; + + port@230145 { + port-type = rgb; + reg = 0x230145; + hdmi_0: endpoint { + remote-endpoint = lcd0_0; + }; + }; + port@3 {/* AP1 = I2S */ + port-type = i2s; + reg = 0x03; + tda998x_i2s: endpoint { + remote-endpoint = audio1_i2s; + }; + }; + port@4 { /* AP2 = S/PDIF */ + port-type = spdif; + reg = 0x04; + tda998x_spdif: endpoint { + remote-endpoint = audio1_spdif1; + }; + }; }; diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 424228b..0952eac 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -27,6 +27,7 @@ #include drm/drm_edid.h #include drm/drm_of.h #include drm/i2c/tda998x.h +#include sound/tda998x.h #define DBG(fmt, ...) DRM_DEBUG(fmt\n, ##__VA_ARGS__) @@ -47,6 +48,8 @@ struct tda998x_priv { wait_queue_head_t wq_edid; volatile int wq_edid_wait; struct drm_encoder *encoder; + + struct tda998x_audio audio; }; #define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)-slave_priv) @@ -774,6 +777,8 @@ static void tda998x_encoder_set_config(struct tda998x_priv *priv, (p-mirr_f ? VIP_CNTRL_2_MIRR_F : 0); priv-params = *p; + priv-audio.port_types[0] = p-audio_format; + priv-audio.ports[0] = p-audio_cfg; } static void tda998x_encoder_dpms(struct tda998x_priv *priv, int mode) @@ -1230,9 +1235,57 @@ static struct drm_encoder_slave_funcs tda998x_encoder_slave_funcs = { /* I2C driver functions */ +static int tda998x_parse_ports(struct tda998x_priv *priv, + struct device_node *np) +{ + struct device_node *of_port; + const char *port_type; + int ret, audio_index, reg, afmt; + + audio_index = 0; + for_each_child_of_node(np, of_port) { + if (!of_port-name +|| of_node_cmp(of_port-name, port) != 0) + continue; + ret = of_property_read_string(of_port, port-type, + port_type); + if (ret 0) + continue; + ret = of_property_read_u32(of_port
[PATCH RFC v3 0/7] Implement generic ASoC HDMI codec and use it in tda998x
This is my third RFC patch series on the subject. This time also the tda998x driver patches are a serious attempt to come up with an initial implementation for HDMI audio ASoC support. Russell's drm/edid: add function to help find SADs is here just to produce a working patch-set on top of mainline. It should be getting in trough drm-next at some point. The binding for tda998x is taken from Jean Francois' patch series[1] on the same subject. The implementation of the of-node parsing has some minor changes from my self. Here is what I think at least could or should still be done, but non of that stuff does not sounds critical right now. Missing from tda998x driver side - hdmi_codec_ops audio_startup() implementation for audio abort support - multi channel audio support (I would need specs and preferably some HW to test for this). Missing from ASoC side generic implementation: - channel_allocation handling is completely left for the video side driver, see if ASoC side could help in any way - snd_soc_jack functionality to handle hdmi cable plug/unplug events [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2015-July/095596.html Best regards, Jyri Jean-Francois Moine (1): drm/i2c: tda998x: Add support of a DT graph of ports Jyri Sarha (5): ASoC: hdmi: Remove obsolete dummy HDMI codec ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders drm/i2c: tda998x: Remove include/sound/tda998x.h and fix graph parsing drm/i2c: tda998x: Register ASoC HDMI codec for audio functionality ARM: dts: am335x-boneblack: Add HDMI audio support Russell King - ARM Linux (1): drm/edid: add function to help find SADs, DO NOT MERGE .../devicetree/bindings/drm/i2c/tda998x.txt| 51 +++ arch/arm/boot/dts/am335x-boneblack.dts | 90 +++- drivers/gpu/drm/i2c/Kconfig| 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 336 +-- include/drm/drm_edid.h | 19 + include/sound/hdmi-codec.h | 99 + sound/soc/codecs/Kconfig | 3 +- sound/soc/codecs/Makefile | 4 +- sound/soc/codecs/hdmi-codec.c | 467 + sound/soc/codecs/hdmi.c| 109 - 10 files changed, 1026 insertions(+), 153 deletions(-) create mode 100644 include/sound/hdmi-codec.h create mode 100644 sound/soc/codecs/hdmi-codec.c delete mode 100644 sound/soc/codecs/hdmi.c -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v3 6/7] drm/i2c: tda998x: Register ASoC HDMI codec for audio functionality
Register ASoC HDMI codec for audio functionality. This is an initial ASoC audio implementation for tda998x driver and it does not use all the features provided by hdmi-codec. HDMI audio info-frame and audio stream header is generated by the ASoC HDMI codec. The codec also applies constraints for available sample-rates. Implementation of audio_startup for hdmi_codec_ops would enable tda998x driver to abort ongoing playback if the HDMI cable is unplugged or re-plugged to a device without audio capability. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/i2c/Kconfig | 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 241 +- 2 files changed, 214 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 22c7ed6..088f278 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -28,6 +28,7 @@ config DRM_I2C_SIL164 config DRM_I2C_NXP_TDA998X tristate NXP Semiconductors TDA998X HDMI encoder default m if DRM_TILCDC + select SND_SOC_HDMI_CODEC if SND_SOC help Support for NXP Semiconductors TDA998X HDMI encoders. diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 4dc2dc0..8444e18 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -20,6 +20,7 @@ #include linux/module.h #include linux/irq.h #include sound/asoundef.h +#include sound/hdmi-codec.h #include drm/drmP.h #include drm/drm_crtc_helper.h @@ -49,6 +50,8 @@ struct tda998x_priv { u8 vip_cntrl_2; struct tda998x_encoder_params params; + struct platform_device *audio_pdev; + wait_queue_head_t wq_edid; volatile int wq_edid_wait; struct drm_encoder *encoder; @@ -435,7 +438,7 @@ out: } static void -reg_write_range(struct tda998x_priv *priv, uint16_t reg, uint8_t *p, int cnt) +reg_write_range(struct tda998x_priv *priv, uint16_t reg, const u8 *p, int cnt) { struct i2c_client *client = priv-hdmi; uint8_t buf[cnt+1]; @@ -619,7 +622,7 @@ tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr, } static void -tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p) +tda998x_write_raw_aif(struct tda998x_priv *priv, u8 *audio_frame) { u8 buf[PB(HDMI_AUDIO_INFOFRAME_SIZE) + 1]; @@ -627,10 +630,10 @@ tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p) buf[HB(0)] = HDMI_INFOFRAME_TYPE_AUDIO; buf[HB(1)] = 0x01; buf[HB(2)] = HDMI_AUDIO_INFOFRAME_SIZE; - buf[PB(1)] = p-audio_frame[1] 0x07; /* CC */ - buf[PB(2)] = p-audio_frame[2] 0x1c; /* SF */ - buf[PB(4)] = p-audio_frame[4]; - buf[PB(5)] = p-audio_frame[5] 0xf8; /* DM_INH + LSV */ + buf[PB(1)] = audio_frame[1] 0x07; /* CC */ + buf[PB(2)] = audio_frame[2] 0x1c; /* SF */ + buf[PB(4)] = audio_frame[4]; + buf[PB(5)] = audio_frame[5] 0xf8; /* DM_INH + LSV */ buf[PB(0)] = tda998x_cksum(buf, sizeof(buf)); @@ -638,6 +641,24 @@ tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p) sizeof(buf)); } +static int tda998x_write_aif(struct tda998x_priv *priv, +struct hdmi_audio_infoframe *cea) +{ + uint8_t buf[HDMI_INFOFRAME_SIZE(AUDIO)]; + int len; + + len = hdmi_audio_infoframe_pack(cea, buf, sizeof(buf)); + if (len 0) { + dev_err(priv-hdmi-dev, + Failed to pack audio infoframe: %d\n, len); + return len; + } + + /* Write the audio information packet */ + tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf, len); + return 0; +} + static void tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode) { @@ -670,19 +691,24 @@ static void tda998x_audio_mute(struct tda998x_priv *priv, bool on) } } -static void +static int tda998x_configure_audio(struct tda998x_priv *priv, - struct drm_display_mode *mode, struct tda998x_encoder_params *p) + int mode_clock, + int ena_ap, + int dai_format, + int sample_width, + int sample_rate, + const u8 *status) { uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv; uint32_t n; /* Enable audio ports */ - reg_write(priv, REG_ENA_AP, p-audio_cfg); - reg_write(priv, REG_ENA_ACLK, p-audio_clk_cfg); + reg_write(priv, REG_ENA_AP, ena_ap); + reg_write(priv, REG_ENA_ACLK, dai_format == AFMT_SPDIF ? 0 : 1); /* Set audio input source */ - switch (p-audio_format) { + switch (dai_format) { case AFMT_SPDIF: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF); clksel_aip
[PATCH RFC v3 5/7] drm/i2c: tda998x: Remove include/sound/tda998x.h and fix graph parsing
Move struct tda998x_audio definition to tda998x_drv.c and remove include/sound/tda998x.h. There is no external use for struct tda998x_audio. Fix graph parsing to allow ports to be inside a separate ports-node as specified in Documentation/devicetree/bindings/graph.txt. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/i2c/tda998x_drv.c | 59 +-- include/sound/tda998x.h | 8 -- 2 files changed, 32 insertions(+), 35 deletions(-) delete mode 100644 include/sound/tda998x.h diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 0952eac..4dc2dc0 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -27,10 +27,14 @@ #include drm/drm_edid.h #include drm/drm_of.h #include drm/i2c/tda998x.h -#include sound/tda998x.h #define DBG(fmt, ...) DRM_DEBUG(fmt\n, ##__VA_ARGS__) +struct tda998x_audio { + u8 ports[2];/* AP value */ + u8 port_types[2]; /* AFMT_xxx */ +}; + struct tda998x_priv { struct i2c_client *cec; struct i2c_client *hdmi; @@ -1240,9 +1244,10 @@ static int tda998x_parse_ports(struct tda998x_priv *priv, { struct device_node *of_port; const char *port_type; - int ret, audio_index, reg, afmt; + int ret, audio_index, reg, afmt, rgb_initialized; audio_index = 0; + rgb_initialized = 0; for_each_child_of_node(np, of_port) { if (!of_port-name || of_node_cmp(of_port-name, port) != 0) @@ -1252,11 +1257,17 @@ static int tda998x_parse_ports(struct tda998x_priv *priv, if (ret 0) continue; ret = of_property_read_u32(of_port, reg, reg); + if (ret 0) { + dev_err(priv-hdmi-dev, missing reg for %s\n, + port_type); + return ret; + } if (strcmp(port_type, rgb) == 0) { if (!ret) { /* video reg is optional */ priv-vip_cntrl_0 = reg 16; priv-vip_cntrl_1 = reg 8; priv-vip_cntrl_2 = reg; + rgb_initialized = 1; } continue; } @@ -1266,11 +1277,6 @@ static int tda998x_parse_ports(struct tda998x_priv *priv, afmt = AFMT_SPDIF; else continue; - if (ret 0) { - dev_err(priv-hdmi-dev, missing reg for %s\n, - port_type); - return ret; - } if (audio_index = ARRAY_SIZE(priv-audio.ports)) { dev_err(priv-hdmi-dev, too many audio ports\n); break; @@ -1279,13 +1285,13 @@ static int tda998x_parse_ports(struct tda998x_priv *priv, priv-audio.port_types[audio_index] = afmt; audio_index++; } - return 0; + return rgb_initialized; } static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) { struct device_node *np = client-dev.of_node; - struct device_node *of_port; + struct device_node *ports; u32 video; int rev_lo, rev_hi, ret; unsigned short cec_addr; @@ -1392,24 +1398,15 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) /* get the device tree parameters */ if (np) { - of_port = of_get_child_by_name(np, port); - if (of_port) { /* graph of ports */ - of_node_put(of_port); - ret = tda998x_parse_ports(priv, np); - if (ret 0) - goto fail; - - /* initialize the default audio configuration */ - if (priv-audio.ports[0]) { - priv-params.audio_cfg = priv-audio.ports[0]; - priv-params.audio_format = - priv-audio.port_types[0]; - priv-params.audio_clk_cfg = - priv-params.audio_format == - AFMT_SPDIF ? 0 : 1; - } - } else { - + ports = of_get_child_by_name(np, ports); + if (!ports) + ports = of_node_get(np); + /* graph of ports */ + ret = tda998x_parse_ports(priv, ports); + of_node_put(ports); + if (ret 0) + goto fail; + if (ret == 0) { /* optional video properties
[PATCH RFC v3 2/7] ASoC: hdmi: Remove obsolete dummy HDMI codec
The hdmi stub codec has not been used since refactoring of OMAP HDMI audio support. Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/codecs/Kconfig | 4 -- sound/soc/codecs/Makefile | 2 - sound/soc/codecs/hdmi.c | 109 -- 3 files changed, 115 deletions(-) delete mode 100644 sound/soc/codecs/hdmi.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce..fc8e729 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -76,7 +76,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C - select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 @@ -432,9 +431,6 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate -config SND_SOC_HDMI_CODEC - tristate HDMI stub CODEC - config SND_SOC_ES8328 tristate Everest Semi ES8328 CODEC diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d9..01b4601 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -69,7 +69,6 @@ snd-soc-max98925-objs := max98925.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o -snd-soc-hdmi-codec-objs := hdmi.o snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm1792a-codec-objs := pcm1792a.o snd-soc-pcm3008-objs := pcm3008.o @@ -256,7 +255,6 @@ obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o -obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c deleted file mode 100644 index bd42ad3..000 --- a/sound/soc/codecs/hdmi.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * ALSA SoC codec driver for HDMI audio codecs. - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Ricardo Neri ricardo.n...@ti.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#include linux/module.h -#include sound/soc.h -#include linux/of.h -#include linux/of_device.h - -#define DRV_NAME hdmi-audio-codec - -static const struct snd_soc_dapm_widget hdmi_widgets[] = { - SND_SOC_DAPM_INPUT(RX), - SND_SOC_DAPM_OUTPUT(TX), -}; - -static const struct snd_soc_dapm_route hdmi_routes[] = { - { Capture, NULL, RX }, - { TX, NULL, Playback }, -}; - -static struct snd_soc_dai_driver hdmi_codec_dai = { - .name = hdmi-hifi, - .playback = { - .stream_name = Playback, - .channels_min = 2, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 24, - }, - .capture = { - .stream_name = Capture, - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, - -}; - -#ifdef CONFIG_OF -static const struct of_device_id hdmi_audio_codec_ids[] = { - { .compatible = linux,hdmi-audio, }, - { } -}; -MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids); -#endif - -static struct snd_soc_codec_driver hdmi_codec = { - .dapm_widgets = hdmi_widgets, - .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), - .dapm_routes = hdmi_routes, - .num_dapm_routes = ARRAY_SIZE(hdmi_routes), - .ignore_pmdown_time
[PATCH RFC v3 3/7] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
The hdmi-codec is a platform device driver to be registered from drivers of external HDMI encoders with I2S and/or spdif interface. The driver in turn registers an ASoC codec for the HDMI encoder's audio functionality. The structures and definitions in the API header are mostly redundant copies of similar structures in ASoC headers. This is on purpose to avoid direct dependencies to ASoC structures in video side driver. Signed-off-by: Jyri Sarha jsa...@ti.com --- include/sound/hdmi-codec.h| 99 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdmi-codec.c | 467 ++ 4 files changed, 573 insertions(+) create mode 100644 include/sound/hdmi-codec.h create mode 100644 sound/soc/codecs/hdmi-codec.c diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h new file mode 100644 index 000..b8a90f7 --- /dev/null +++ b/include/sound/hdmi-codec.h @@ -0,0 +1,99 @@ +/* + * hdmi-codec.h - HDMI Codec driver API + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Jyri Sarha jsa...@ti.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __HDMI_CODEC_H__ +#define __HDMI_CODEC_H__ + +#include linux/hdmi.h +#include drm/drm_edid.h +#include sound/asoundef.h +#include uapi/sound/asound.h + +/* + * Protocol between ASoC cpu-dai and HDMI-encoder + */ +struct hdmi_codec_daifmt { + enum { + HDMI_I2S, + HDMI_RIGHT_J, + HDMI_LEFT_J, + HDMI_DSP_A, + HDMI_DSP_B, + HDMI_AC97, + HDMI_SPDIF, + } fmt; + int bit_clk_inv:1; + int frame_clk_inv:1; + int bit_clk_master:1; + int frame_clk_master:1; +}; + +/* + * HDMI audio parameters + */ +struct hdmi_codec_params { + struct hdmi_audio_infoframe cea; + struct snd_aes_iec958 iec; + int sample_rate; + int sample_width; + int channels; +}; + +struct hdmi_codec_ops { + /* For runtime clock configuration from ASoC machine driver. +* A direct forward from set_sysclk in struct snd_soc_dai_ops. +* Optional */ + int (*set_clk)(struct device *dev, int clk_id, int freq); + + /* Called when ASoC starts an audio stream setup. The call +* provides an audio abort callback for stoping an ongoing +* stream if the HDMI audio becomes unavailable. +* Optional */ + int (*audio_startup)(struct device *dev, +void (*abort_cb)(struct device *dev)); + + /* Configures HDMI-encoder for audio stream. +* Mandatory */ + int (*hw_params)(struct device *dev, +struct hdmi_codec_daifmt *fmt, +struct hdmi_codec_params *hparms); + + /* Shuts down the audio stream. +* Mandatory */ + void (*audio_shutdown)(struct device *dev); + + /* Mute/unmute HDMI audio stream. +* Optional */ + int (*digital_mute)(struct device *dev, bool enable); + + /* Provides EDID-Like-Data from connected HDMI device. +* Optional */ + int (*get_eld)(struct device *dev, uint8_t *buf, size_t len); +}; + +/* HDMI codec initalization data */ +struct hdmi_codec_pdata { + struct device *dev; /* The HDMI encoder registering the codec */ + const struct hdmi_codec_ops *ops; + uint i2s:1; + uint spdif:1; + int max_i2s_channels; +}; + +#define HDMI_CODEC_DRV_NAME hdmi-audio-codec + +#endif /* __HDMI_CODEC_H__ */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index fc8e729..a5cc574 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -76,6 +76,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C + select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 @@ -431,6 +432,10 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate +config SND_SOC_HDMI_CODEC + tristate + select SND_PCM_ELD + config SND_SOC_ES8328 tristate Everest Semi ES8328 CODEC diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 01b4601..0245e67 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -69,6 +69,7 @@ snd-soc-max98925-objs := max98925.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs
[PATCH RFC v3 1/7] drm/edid: add function to help find SADs, DO NOT MERGE
From: Russell King - ARM Linux li...@arm.linux.org.uk Add a function to find the start of the SADs in the ELD. This complements the helper to retrieve the SAD count. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk This should already be coming in from drm-next. Signed-off-by: Jyri Sarha jsa...@ti.com --- include/drm/drm_edid.h | 19 +++ 1 file changed, 19 insertions(+) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 7990501..53c53c4 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -348,6 +348,25 @@ static inline int drm_eld_mnl(const uint8_t *eld) } /** + * drm_eld_sad - Get ELD SAD structures. + * @eld: pointer to an eld memory structure with sad_count set + */ +static inline const uint8_t *drm_eld_sad(const uint8_t *eld) +{ + unsigned int ver, mnl; + + ver = (eld[DRM_ELD_VER] DRM_ELD_VER_MASK) DRM_ELD_VER_SHIFT; + if (ver != 2 ver != 31) + return NULL; + + mnl = drm_eld_mnl(eld); + if (mnl 16) + return NULL; + + return eld + DRM_ELD_CEA_SAD(mnl, 0); +} + +/** * drm_eld_sad_count - Get ELD SAD count. * @eld: pointer to an eld memory structure with sad_count set */ -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/2] OMAPDSS: Fix omap_dss_find_output_by_port_node() port refcount decrement
Fix omap_dss_find_output_by_port_node() port parameter refcount decrementation. The only user of dss_of_port_get_parent_device() function is omap_dss_find_output_by_port_node() and it assumes the refcount of the port parameter is not decremented by the call. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/dss-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c index ab6ef16..43f999d 100644 --- a/drivers/video/fbdev/omap2/dss/dss-of.c +++ b/drivers/video/fbdev/omap2/dss/dss-of.c @@ -95,7 +95,7 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port) if (!port) return NULL; - np = of_get_next_parent(port); + np = of_get_parent(port); for (i = 0; i 2 np; ++i) { struct property *prop; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/2] OMAPDSS: Fix node refcount leak in omapdss_of_get_next_port()
Fix node refcount leak in omapdss_of_get_next_port(). Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/dss-of.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c index 928ee63..ab6ef16 100644 --- a/drivers/video/fbdev/omap2/dss/dss-of.c +++ b/drivers/video/fbdev/omap2/dss/dss-of.c @@ -60,6 +60,7 @@ omapdss_of_get_next_port(const struct device_node *parent, } prev = port; } while (of_node_cmp(port-name, port) != 0); + of_node_put(ports); } return port; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/2] OMAPDSS: Fix of-node refcount issues
Changes since the first version: - Fix commit descriptions and subject according to Tomi's comments I found couple of refcounting issues related to OMAP DSS of-node handling. Second patch should fix the ERROR: Bad of_node_put() on /encoder@0/ports/port@1 -problem. In the long run it would make sense start using of_graph_*() functions in OMAP DSS too. However the semantics of of_graph_*() functions are quite different from omapdss_of_*() counterparts. So it better to just fix these bugs first. Jyri Sarha (2): OMAPDSS: Fix node refcount leak in omapdss_of_get_next_port() OMAPDSS: Fix omap_dss_find_output_by_port_node() port refcount decrement drivers/video/fbdev/omap2/dss/dss-of.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] OMAPDSS: dss-of: Fix node refcount leak in omapdss_of_get_next_port()
Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/dss-of.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c index 928ee63..ab6ef16 100644 --- a/drivers/video/fbdev/omap2/dss/dss-of.c +++ b/drivers/video/fbdev/omap2/dss/dss-of.c @@ -60,6 +60,7 @@ omapdss_of_get_next_port(const struct device_node *parent, } prev = port; } while (of_node_cmp(port-name, port) != 0); + of_node_put(ports); } return port; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/2] OMAPDSS: Fix of-node refcount issues
I found couple of refcounting issues related to OMAP DSS of-node handling. Second patch should fix the ERROR: Bad of_node_put() on /encoder@0/ports/port@1 -problem. In the long run it would make sense start using of_graph_*() functions in OMAP DSS too. However the semantics of of_graph_*() functions are quite different from omapdss_of_*() counterparts. So it better to just fix these bugs first. Jyri Sarha (2): OMAPDSS: dss-of: Fix node refcount leak in omapdss_of_get_next_port() OMAPDSS: of-dss: omap_dss_find_output_by_port_node() keep port refcount drivers/video/fbdev/omap2/dss/dss-of.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] OMAPDSS: of-dss: omap_dss_find_output_by_port_node() keep port refcount
The only user of dss_of_port_get_parent_device() function is omap_dss_find_output_by_port_node() and it assumes the refcount of the port parameter is not decremented by the call. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/dss-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c index ab6ef16..43f999d 100644 --- a/drivers/video/fbdev/omap2/dss/dss-of.c +++ b/drivers/video/fbdev/omap2/dss/dss-of.c @@ -95,7 +95,7 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port) if (!port) return NULL; - np = of_get_next_parent(port); + np = of_get_parent(port); for (i = 0; i 2 np; ++i) { struct property *prop; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] drm/tilcdc: Allocate register storage based on the actual number registers
Allocate suspend/resume register storage based on the actual number registers the driver is aware of. The static allocation for register storage had falen behind badly. Reported-by: Michael Bode mich...@bumbleb.de Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 20 +++- drivers/gpu/drm/tilcdc/tilcdc_drv.h | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 4908c1f..2f87263 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -139,11 +139,14 @@ static int tilcdc_unload(struct drm_device *dev) pm_runtime_disable(dev-dev); + kfree(priv-saved_register); kfree(priv); return 0; } +static size_t tilcdc_num_regs(void); + static int tilcdc_load(struct drm_device *dev, unsigned long flags) { struct platform_device *pdev = dev-platformdev; @@ -155,7 +158,11 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) int ret; priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { + if (priv) + priv-saved_register = kcalloc(sizeof(*priv-saved_register), + tilcdc_num_regs(), GFP_KERNEL); + if (!priv || !priv-saved_register) { + kfree(priv); dev_err(dev-dev, failed to allocate private data\n); return -ENOMEM; } @@ -345,6 +352,7 @@ fail_free_wq: fail_free_priv: dev-dev_private = NULL; + kfree(priv-saved_register); kfree(priv); return ret; } @@ -467,6 +475,16 @@ static const struct { REG(2, true, LCDC_INT_ENABLE_SET_REG), #undef REG }; + +static size_t tilcdc_num_regs(void) +{ + return ARRAY_SIZE(registers); +} +#else +static size_t tilcdc_num_regs(void) +{ + return 0; +} #endif #ifdef CONFIG_DEBUG_FS diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index e863ad0..bc94835 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -67,7 +67,7 @@ struct tilcdc_drm_private { uint32_t max_width; /* register contents saved across suspend/resume: */ - u32 saved_register[12]; + u32 *saved_register; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] drm/tilcdc: Implement dma-buf support for tilcdc
There is nothing special about tilcdc HW when the video memory is concerned. Just using the standard drm helpers for implementation is enough. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 0f283a3..4908c1f 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -553,7 +553,8 @@ static const struct file_operations fops = { }; static struct drm_driver tilcdc_driver = { - .driver_features= DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, + .driver_features= (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | + DRIVER_PRIME), .load = tilcdc_load, .unload = tilcdc_unload, .preclose = tilcdc_preclose, @@ -571,6 +572,16 @@ static struct drm_driver tilcdc_driver = { .dumb_create= drm_gem_cma_dumb_create, .dumb_map_offset= drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, #ifdef CONFIG_DEBUG_FS .debugfs_init = tilcdc_debugfs_init, .debugfs_cleanup= tilcdc_debugfs_cleanup, -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] drm/tilcdc: Fix bad if statement in tilcdc_get_external_components()
The if statement condition should have been !node || !of_device_is_available(node) ( changed to ||), but let's rewrite the whole inside of the loop for better readability. Reported-by: Dan Carpenter dan.carpen...@oracle.com Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/tilcdc/tilcdc_external.c | 19 --- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c index 03acb4f..a641808 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c @@ -142,19 +142,16 @@ int tilcdc_get_external_components(struct device *dev, int count = 0; while ((ep = of_graph_get_next_endpoint(dev-of_node, ep))) { - struct device_node *node; - - node = of_graph_get_remote_port_parent(ep); - if (!node !of_device_is_available(node)) { - of_node_put(node); - continue; + struct device_node *node = of_graph_get_remote_port_parent(ep); + + if (node of_device_is_available(node)) { + dev_dbg(dev, Subdevice node '%s' found\n, node-name); + if (match) + component_match_add(dev, match, dev_match_of, + node); + count++; } - - dev_dbg(dev, Subdevice node '%s' found\n, node-name); - if (match) - component_match_add(dev, match, dev_match_of, node); of_node_put(node); - count++; } if (count 1) { -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] ASoC: davinci-mcasp: Choose PCM driver based on configured DMA controller
Find the configured DMA controller by asking for a DMA channel in the probe phase and releasing it right after. The controller device can be found via the dma_chan struct and the controller is recognized from the compatible property of its device node. The patch assumes EDMA if there is no device node. Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/davinci/davinci-mcasp.c | 61 --- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index d793494..5bc2712 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1565,6 +1565,46 @@ static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp) return ret; } +enum { + MCASP_EDMA = 1, + MCASP_SDMA, +}; +static const char *sdma_prefix = ti,omap; + +static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) +{ + struct dma_chan *chan; + const char *tmp; + int ret = MCASP_EDMA; + + tmp = mcasp-dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; + chan = dma_request_slave_channel_reason(mcasp-dev, tmp); + if (IS_ERR(chan)) { + if (PTR_ERR(chan) != -EPROBE_DEFER) + dev_err(mcasp-dev, + Can't verify DMA configuration (%ld)\n, + PTR_ERR(chan)); + return PTR_ERR(chan); + } + BUG_ON(!chan-device || !chan-device-dev); + + if (chan-device-dev-of_node) + ret = of_property_read_string(chan-device-dev-of_node, + compatible, tmp); + else + dev_dbg(mcasp-dev, DMA controller has no of-node\n); + + dma_release_channel(chan); + if (ret) + return ret; + + dev_dbg(mcasp-dev, DMA controller compatible = \%s\\n, tmp); + if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) + return MCASP_SDMA; + + return MCASP_EDMA; +} + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -1763,27 +1803,28 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err; - switch (mcasp-version) { + ret = -EINVAL; + switch (davinci_mcasp_get_dma_type(mcasp)) { + case MCASP_EDMA: #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_EDMA_SOC)) - case MCASP_VERSION_1: - case MCASP_VERSION_2: - case MCASP_VERSION_3: ret = edma_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_EDMA_SOC\n); #endif + break; + case MCASP_SDMA: #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_OMAP_SOC)) - case MCASP_VERSION_4: ret = omap_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_SDMA_SOC\n); #endif + break; default: - dev_err(pdev-dev, Invalid McASP version: %d\n, - mcasp-version); - ret = -EINVAL; + dev_err(pdev-dev, No DMA controller found\n); break; } -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] ASoC: davinci-mcasp: Choose PCM driver based on configured DMA controller
On 06/02/15 19:16, Misael Lopez Cruz wrote: Jyri, On 06/02/2015 08:49 AM, Jyri Sarha wrote: Find the configured DMA controller by asking for a DMA channel in the probe phase and releasing it right after. The controller device can be found via the dma_chan struct and the controller is recognized from the compatible property of its device node. The patch assumes EDMA if there is no device node. Signed-off-by: Jyri Sarha jsa...@ti.com --- Changes since first patch version: - Change enum names from MCASP_?DMA to PCM_?DMA - Return PCM_EDMA if !mcasp-dev-of_node - Do not ignore possible error code returned by davinci_mcasp_get_dma_type() sound/soc/davinci/davinci-mcasp.c | 68 +-- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index d793494..3b78c3e 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1565,6 +1565,49 @@ static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp) return ret; } +enum { +PCM_EDMA, +PCM_SDMA, +}; +static const char *sdma_prefix = ti,omap; + +static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) +{ +struct dma_chan *chan; +const char *tmp; +int ret = PCM_EDMA; + +if (!mcasp-dev-of_node) +return PCM_EDMA; + +tmp = mcasp-dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; +chan = dma_request_slave_channel_reason(mcasp-dev, tmp); +if (IS_ERR(chan)) { +if (PTR_ERR(chan) != -EPROBE_DEFER) +dev_err(mcasp-dev, +Can't verify DMA configuration (%ld)\n, +PTR_ERR(chan)); +return PTR_ERR(chan); +} +BUG_ON(!chan-device || !chan-device-dev); + +if (chan-device-dev-of_node) +ret = of_property_read_string(chan-device-dev-of_node, + compatible, tmp); I wonder how this is going to play out when the DMA crossbar is present (i.e. dra7 family). In that case, isn't the 'compatible' string here that of the DMA crossbar (not the one from the DMA controller)? That is exactly why I am requesting a channel and going from there. The DMA router will do its thing in the middle and the device pointer found via the returned dma_chan is pointing at the actual DMA controller. I have tested the code on am57xx-beagle-x15, which is also using the DMA crossbar. +else +dev_dbg(mcasp-dev, DMA controller has no of-node\n); + +dma_release_channel(chan); +if (ret) +return ret; + +dev_dbg(mcasp-dev, DMA controller compatible = \%s\\n, tmp); +if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) +return PCM_SDMA; + +return PCM_EDMA; +} + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -1763,27 +1806,32 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err; -switch (mcasp-version) { +ret = davinci_mcasp_get_dma_type(mcasp); +switch (ret) { +case PCM_EDMA: #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_EDMA_SOC)) -case MCASP_VERSION_1: -case MCASP_VERSION_2: -case MCASP_VERSION_3: ret = edma_pcm_platform_register(pdev-dev); -break; +#else +dev_err(pdev-dev, Missing SND_EDMA_SOC\n); +ret = -EINVAL; #endif +break; +case PCM_SDMA: #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_OMAP_SOC)) -case MCASP_VERSION_4: ret = omap_pcm_platform_register(pdev-dev); -break; +#else +dev_err(pdev-dev, Missing SND_SDMA_SOC\n); +ret = -EINVAL; #endif +break; +case -EPROBE_DEFER: +break; default: -dev_err(pdev-dev, Invalid McASP version: %d\n, -mcasp-version); -ret = -EINVAL; +dev_err(pdev-dev, No DMA controller found (%d)\n, ret); break; } -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3] ASoC: davinci-mcasp: Choose PCM driver based on configured DMA controller
Find the configured DMA controller by asking for a DMA channel in the probe phase and releasing it right after. The controller device can be found via the dma_chan struct and the controller is recognized from the compatible property of its device node. The patch assumes EDMA if there is no device node. Signed-off-by: Jyri Sarha jsa...@ti.com --- Changes since v2: - Print only one error message if DMA probing fails and none in case of -EPROBE_DEFER Changes since first patch version: - Change enum names from MCASP_?DMA to PCM_?DMA - Return PCM_EDMA if !mcasp-dev-of_node - Do not ignore possible error code returned by davinci_mcasp_get_dma_type() sound/soc/davinci/davinci-mcasp.c | 70 +-- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index d793494..a73cd57 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1565,6 +1565,49 @@ static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp) return ret; } +enum { + PCM_EDMA, + PCM_SDMA, +}; +static const char *sdma_prefix = ti,omap; + +static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) +{ + struct dma_chan *chan; + const char *tmp; + int ret = PCM_EDMA; + + if (!mcasp-dev-of_node) + return PCM_EDMA; + + tmp = mcasp-dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; + chan = dma_request_slave_channel_reason(mcasp-dev, tmp); + if (IS_ERR(chan)) { + if (PTR_ERR(chan) != -EPROBE_DEFER) + dev_err(mcasp-dev, + Can't verify DMA configuration (%ld)\n, + PTR_ERR(chan)); + return PTR_ERR(chan); + } + BUG_ON(!chan-device || !chan-device-dev); + + if (chan-device-dev-of_node) + ret = of_property_read_string(chan-device-dev-of_node, + compatible, tmp); + else + dev_dbg(mcasp-dev, DMA controller has no of-node\n); + + dma_release_channel(chan); + if (ret) + return ret; + + dev_dbg(mcasp-dev, DMA controller compatible = \%s\\n, tmp); + if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) + return PCM_SDMA; + + return PCM_EDMA; +} + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -1763,27 +1806,34 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err; - switch (mcasp-version) { + ret = davinci_mcasp_get_dma_type(mcasp); + switch (ret) { + case PCM_EDMA: #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_EDMA_SOC)) - case MCASP_VERSION_1: - case MCASP_VERSION_2: - case MCASP_VERSION_3: ret = edma_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_EDMA_SOC\n); + ret = -EINVAL; + goto err; #endif + break; + case PCM_SDMA: #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_OMAP_SOC)) - case MCASP_VERSION_4: ret = omap_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_SDMA_SOC\n); + ret = -EINVAL; + goto err; #endif + break; default: - dev_err(pdev-dev, Invalid McASP version: %d\n, - mcasp-version); - ret = -EINVAL; + dev_err(pdev-dev, No DMA controller found (%d)\n, ret); + case -EPROBE_DEFER: + goto err; break; } -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ASoC: davinci-mcasp: Choose PCM driver based on configured DMA controller
On 06/02/15 13:31, Peter Ujfalusi wrote: On 06/02/2015 11:58 AM, Jyri Sarha wrote: Find the configured DMA controller by asking for a DMA channel in the probe phase and releasing it right after. The controller device can be found via the dma_chan struct and the controller is recognized from the compatible property of its device node. The patch assumes EDMA if there is no device node. Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/davinci/davinci-mcasp.c | 61 --- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index d793494..5bc2712 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1565,6 +1565,46 @@ static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp) return ret; } +enum { + MCASP_EDMA = 1, Why start from 1? This is just an implementation detail, for if statement below. Maybe I should restucture for better readability. I'm not sure about the name. It somehow implies that McASP has something to do with the dma engine. MCASP_SERVICED_BY_E/SDMA PLATFORM_USES_E/SDMA I can not come up with a decent name :( What about PCM_EDMA/PCM_SDMA? This is a local definition after all. + MCASP_SDMA, +}; +static const char *sdma_prefix = ti,omap; + +static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) +{ + struct dma_chan *chan; + const char *tmp; + int ret = MCASP_EDMA; + + tmp = mcasp-dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; + chan = dma_request_slave_channel_reason(mcasp-dev, tmp); this will return with error in case of !dev-of_node. The first check should be: if (!mcasp-dev-of_node) return MCASP_EDMA; since we can only boot in legacy mode with daVinci devices and they are using eDMA. + if (IS_ERR(chan)) { + if (PTR_ERR(chan) != -EPROBE_DEFER) + dev_err(mcasp-dev, + Can't verify DMA configuration (%ld)\n, + PTR_ERR(chan)); + return PTR_ERR(chan); + } + BUG_ON(!chan-device || !chan-device-dev); + + if (chan-device-dev-of_node) + ret = of_property_read_string(chan-device-dev-of_node, + compatible, tmp); + else + dev_dbg(mcasp-dev, DMA controller has no of-node\n); Now this is not likely to happen... Not having of_node happens on am335x, but not having compatible property is unlikely... + + dma_release_channel(chan); + if (ret) + return ret; + + dev_dbg(mcasp-dev, DMA controller compatible = \%s\\n, tmp); + if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) + return MCASP_SDMA; + + return MCASP_EDMA; +} + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -1763,27 +1803,28 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err; - switch (mcasp-version) { + ret = -EINVAL; Why? What was the problem with setting the ret in the default case? + switch (davinci_mcasp_get_dma_type(mcasp)) { + case MCASP_EDMA: #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_EDMA_SOC)) - case MCASP_VERSION_1: - case MCASP_VERSION_2: - case MCASP_VERSION_3: ret = edma_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_EDMA_SOC\n); #endif + break; + case MCASP_SDMA: #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_OMAP_SOC)) - case MCASP_VERSION_4: ret = omap_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_SDMA_SOC\n); #endif + break; default: - dev_err(pdev-dev, Invalid McASP version: %d\n, - mcasp-version); - ret = -EINVAL; + dev_err(pdev-dev, No DMA controller found\n); break; } -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ASoC: davinci-mcasp: Choose PCM driver based on configured DMA controller
I missed two comments first time around... On 06/02/15 13:31, Peter Ujfalusi wrote: On 06/02/2015 11:58 AM, Jyri Sarha wrote: Find the configured DMA controller by asking for a DMA channel in the probe phase and releasing it right after. The controller device can be found via the dma_chan struct and the controller is recognized from the compatible property of its device node. The patch assumes EDMA if there is no device node. Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/davinci/davinci-mcasp.c | 61 --- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index d793494..5bc2712 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1565,6 +1565,46 @@ static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp) return ret; } +enum { + MCASP_EDMA = 1, Why start from 1? I'm not sure about the name. It somehow implies that McASP has something to do with the dma engine. MCASP_SERVICED_BY_E/SDMA PLATFORM_USES_E/SDMA I can not come up with a decent name :( + MCASP_SDMA, +}; +static const char *sdma_prefix = ti,omap; + +static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) +{ + struct dma_chan *chan; + const char *tmp; + int ret = MCASP_EDMA; + + tmp = mcasp-dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; + chan = dma_request_slave_channel_reason(mcasp-dev, tmp); this will return with error in case of !dev-of_node. The first check should be: if (!mcasp-dev-of_node) return MCASP_EDMA; since we can only boot in legacy mode with daVinci devices and they are using eDMA. Yep, I'll add that back. I tought that I would not need it, but am not so familiar with the generic dmaengine pcm... + if (IS_ERR(chan)) { + if (PTR_ERR(chan) != -EPROBE_DEFER) + dev_err(mcasp-dev, + Can't verify DMA configuration (%ld)\n, + PTR_ERR(chan)); + return PTR_ERR(chan); + } + BUG_ON(!chan-device || !chan-device-dev); + + if (chan-device-dev-of_node) + ret = of_property_read_string(chan-device-dev-of_node, + compatible, tmp); + else + dev_dbg(mcasp-dev, DMA controller has no of-node\n); Now this is not likely to happen... + + dma_release_channel(chan); + if (ret) + return ret; + + dev_dbg(mcasp-dev, DMA controller compatible = \%s\\n, tmp); + if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) + return MCASP_SDMA; + + return MCASP_EDMA; +} + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -1763,27 +1803,28 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err; - switch (mcasp-version) { + ret = -EINVAL; Why? What was the problem with setting the ret in the default case? I would need to have that I three places now for the #else cases, when devicetree tries to configure pcm driver that has not been compiled. + switch (davinci_mcasp_get_dma_type(mcasp)) { + case MCASP_EDMA: #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_EDMA_SOC)) - case MCASP_VERSION_1: - case MCASP_VERSION_2: - case MCASP_VERSION_3: ret = edma_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_EDMA_SOC\n); #endif + break; + case MCASP_SDMA: #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_OMAP_SOC)) - case MCASP_VERSION_4: ret = omap_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_SDMA_SOC\n); #endif + break; default: - dev_err(pdev-dev, Invalid McASP version: %d\n, - mcasp-version); - ret = -EINVAL; + dev_err(pdev-dev, No DMA controller found\n); break; } -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] ASoC: davinci-mcasp: Choose PCM driver based on configured DMA controller
Find the configured DMA controller by asking for a DMA channel in the probe phase and releasing it right after. The controller device can be found via the dma_chan struct and the controller is recognized from the compatible property of its device node. The patch assumes EDMA if there is no device node. Signed-off-by: Jyri Sarha jsa...@ti.com --- Changes since first patch version: - Change enum names from MCASP_?DMA to PCM_?DMA - Return PCM_EDMA if !mcasp-dev-of_node - Do not ignore possible error code returned by davinci_mcasp_get_dma_type() sound/soc/davinci/davinci-mcasp.c | 68 +-- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index d793494..3b78c3e 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1565,6 +1565,49 @@ static int davinci_mcasp_init_ch_constraints(struct davinci_mcasp *mcasp) return ret; } +enum { + PCM_EDMA, + PCM_SDMA, +}; +static const char *sdma_prefix = ti,omap; + +static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) +{ + struct dma_chan *chan; + const char *tmp; + int ret = PCM_EDMA; + + if (!mcasp-dev-of_node) + return PCM_EDMA; + + tmp = mcasp-dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data; + chan = dma_request_slave_channel_reason(mcasp-dev, tmp); + if (IS_ERR(chan)) { + if (PTR_ERR(chan) != -EPROBE_DEFER) + dev_err(mcasp-dev, + Can't verify DMA configuration (%ld)\n, + PTR_ERR(chan)); + return PTR_ERR(chan); + } + BUG_ON(!chan-device || !chan-device-dev); + + if (chan-device-dev-of_node) + ret = of_property_read_string(chan-device-dev-of_node, + compatible, tmp); + else + dev_dbg(mcasp-dev, DMA controller has no of-node\n); + + dma_release_channel(chan); + if (ret) + return ret; + + dev_dbg(mcasp-dev, DMA controller compatible = \%s\\n, tmp); + if (!strncmp(tmp, sdma_prefix, strlen(sdma_prefix))) + return PCM_SDMA; + + return PCM_EDMA; +} + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -1763,27 +1806,32 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err; - switch (mcasp-version) { + ret = davinci_mcasp_get_dma_type(mcasp); + switch (ret) { + case PCM_EDMA: #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_EDMA_SOC)) - case MCASP_VERSION_1: - case MCASP_VERSION_2: - case MCASP_VERSION_3: ret = edma_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_EDMA_SOC\n); + ret = -EINVAL; #endif + break; + case PCM_SDMA: #if IS_BUILTIN(CONFIG_SND_OMAP_SOC) || \ (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) \ IS_MODULE(CONFIG_SND_OMAP_SOC)) - case MCASP_VERSION_4: ret = omap_pcm_platform_register(pdev-dev); - break; +#else + dev_err(pdev-dev, Missing SND_SDMA_SOC\n); + ret = -EINVAL; #endif + break; + case -EPROBE_DEFER: + break; default: - dev_err(pdev-dev, Invalid McASP version: %d\n, - mcasp-version); - ret = -EINVAL; + dev_err(pdev-dev, No DMA controller found (%d)\n, ret); break; } -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 3/7] drm/tilcdc: Add support for external tda998x encoder
Add support for an external compontised DRM encoder. The external encoder can be connected to tilcdc trough device tree graph binding. The binding document for tilcdc has been updated. The current implementation supports only tda998x encoder. To be able to filter out the unsupported video modes the tilcdc driver needs to hijack the external connectors helper functions. The tilcdc installes new helper functions that are otherwise identical to orignals, but the mode_valid() call-back check the mode first localy, before calling the original call-back. The tilcdc dirver restores the original helper functions before it is unbound from the external device. I got the idea and some lines of code from Jean-Francois Moine's drm/tilcdc: Change the interface with the tda998x driver-patch. Signed-off-by: Jyri Sarha jsa...@ti.com --- .../devicetree/bindings/drm/tilcdc/tilcdc.txt | 27 drivers/gpu/drm/tilcdc/Makefile| 1 + drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 33 drivers/gpu/drm/tilcdc/tilcdc_drv.c| 85 +-- drivers/gpu/drm/tilcdc/tilcdc_drv.h| 5 + drivers/gpu/drm/tilcdc/tilcdc_external.c | 166 + drivers/gpu/drm/tilcdc/tilcdc_external.h | 25 7 files changed, 329 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_external.c create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_external.h diff --git a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt index fff10da..2136ee8 100644 --- a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt +++ b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt @@ -18,6 +18,12 @@ Optional properties: - max-pixelclock: The maximum pixel clock that can be supported by the lcd controller in KHz. +Optional nodes: + + - port/ports: to describe a connection to an external encoder. The + binding follows Documentation/devicetree/bindings/graph.txt and + suppors a single port with a single endpoint. + Example: fb: fb@4830e000 { @@ -26,4 +32,25 @@ Example: interrupt-parent = intc; interrupts = 36; ti,hwmods = lcdc; + + port { + lcdc_0: endpoint@0 { + remote-endpoint = hdmi_0; + }; + }; + }; + + tda19988: tda19988 { + compatible = nxp,tda998x; + reg = 0x70; + + pinctrl-names = default, off; + pinctrl-0 = nxp_hdmi_bonelt_pins; + pinctrl-1 = nxp_hdmi_bonelt_off_pins; + + port { + hdmi_0: endpoint@0 { + remote-endpoint = lcdc_0; + }; + }; }; diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile index 44485f9..e1f738b 100644 --- a/drivers/gpu/drm/tilcdc/Makefile +++ b/drivers/gpu/drm/tilcdc/Makefile @@ -7,6 +7,7 @@ tilcdc-y := \ tilcdc_crtc.o \ tilcdc_tfp410.o \ tilcdc_panel.o \ + tilcdc_external.o \ tilcdc_drv.o obj-$(CONFIG_DRM_TILCDC) += tilcdc.o diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index c2d5980..7d07733 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -37,6 +37,9 @@ struct tilcdc_crtc { /* for deferred fb unref's: */ struct drm_flip_work unref_work; + + /* Only set if an external encoder is connected */ + bool simulate_vesa_sync; }; #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) @@ -214,6 +217,28 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); + + if (!tilcdc_crtc-simulate_vesa_sync) + return true; + + /* +* tilcdc does not generate VESA-compliant sync but aligns +* VS on the second edge of HS instead of first edge. +* We use adjusted_mode, to fixup sync by aligning both rising +* edges and add HSKEW offset to fix the sync. +*/ + adjusted_mode-hskew = mode-hsync_end - mode-hsync_start; + adjusted_mode-flags |= DRM_MODE_FLAG_HSKEW; + + if (mode-flags DRM_MODE_FLAG_NHSYNC) { + adjusted_mode-flags |= DRM_MODE_FLAG_PHSYNC; + adjusted_mode-flags = ~DRM_MODE_FLAG_NHSYNC; + } else { + adjusted_mode-flags |= DRM_MODE_FLAG_NHSYNC; + adjusted_mode-flags = ~DRM_MODE_FLAG_PHSYNC; + } + return true; } @@ -534,6 +559,14 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc, tilcdc_crtc-info = info; } +void
[PATCH v6 7/7] ARM: dts: am335x-boneblack: Use new binding for HDMI
Use new binding for the external tda19988 HDMI encoder. Signed-off-by: Jyri Sarha jsa...@ti.com --- arch/arm/boot/dts/am335x-boneblack.dts | 20 +++- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts index 5c42d25..eadbba3 100644 --- a/arch/arm/boot/dts/am335x-boneblack.dts +++ b/arch/arm/boot/dts/am335x-boneblack.dts @@ -68,16 +68,26 @@ lcdc { status = okay; + port { + lcdc_0: endpoint@0 { + remote-endpoint = hdmi_0; + }; + }; }; -/ { - hdmi { - compatible = ti,tilcdc,slave; - i2c = i2c0; +i2c0 { + tda19988 { + compatible = nxp,tda998x; + reg = 0x70; pinctrl-names = default, off; pinctrl-0 = nxp_hdmi_bonelt_pins; pinctrl-1 = nxp_hdmi_bonelt_off_pins; - status = okay; + + port { + hdmi_0: endpoint@0 { + remote-endpoint = lcdc_0; + }; + }; }; }; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 4/7] drm/tilcdc: use pm_runtime_irq_safe()
From: Tomi Valkeinen tomi.valkei...@ti.com tilcdc calls runtime PM get/put functions everywhere. Some of those places will be called in irq context, crashing the driver. As a quick fix, use pm_runtime_irq_safe() for tilcdc. Signed-off-by: Tomi Valkeinen tomi.valkei...@ti.com Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index fcc0508..0f283a3 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -227,6 +227,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) DBG(Maximum Pixel Clock Value %dKHz, priv-max_pixelclock); pm_runtime_enable(dev-dev); + pm_runtime_irq_safe(dev-dev); /* Determine LCD IP Version */ pm_runtime_get_sync(dev-dev); -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 5/7] drm/tilcdc: Add DRM_TILCDC_SLAVE_COMPAT for ti,tilcdc,slave binding support
Adds a CONFIG_DRM_TILCDC_SLAVE_COMPAT module for ti,tilcdc,slave node conversion. The implementation is in tilcdc_slave_compat.c and it uses tilcdc_slave_compat.dts as a basis for creating a DTS overlay. The DTS overlay adds an external tda998x encoder to tilcdc that corresponds to the old tda998x based slave encoder. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/tilcdc/Kconfig | 12 ++ drivers/gpu/drm/tilcdc/Makefile| 3 + drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 270 + drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts | 72 +++ drivers/gpu/drm/tilcdc/tilcdc_slave_compat.h | 25 +++ 5 files changed, 382 insertions(+) create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.h diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig index 8394a0b..78beafb 100644 --- a/drivers/gpu/drm/tilcdc/Kconfig +++ b/drivers/gpu/drm/tilcdc/Kconfig @@ -12,3 +12,15 @@ config DRM_TILCDC Choose this option if you have an TI SoC with LCDC display controller, for example AM33xx in beagle-bone, DA8xx, or OMAP-L1xx. This driver replaces the FB_DA8XX fbdev driver. + +config DRM_TILCDC_SLAVE_COMPAT + bool Support device tree blobs using TI LCDC Slave binding + depends on DRM_TILCDC + default y + select OF_RESOLVE + select OF_OVERLAY + help + Choose this option if you need a kernel that is compatible + with device tree blobs using the obsolete ti,tilcdc,slave + binding. If you find ti,tilcdc,slave-string from your DTB, + you probably need this. Otherwise you do not. diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile index e1f738b..deeca48 100644 --- a/drivers/gpu/drm/tilcdc/Makefile +++ b/drivers/gpu/drm/tilcdc/Makefile @@ -3,6 +3,9 @@ ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) ccflags-y += -Werror endif +obj-$(CONFIG_DRM_TILCDC_SLAVE_COMPAT) += tilcdc_slave_compat.o \ +tilcdc_slave_compat.dtb.o + tilcdc-y := \ tilcdc_crtc.o \ tilcdc_tfp410.o \ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c new file mode 100644 index 000..106679b --- /dev/null +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2015 Texas Instruments + * Author: Jyri Sarha jsa...@ti.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + */ + +/* + * To support the old ti,tilcdc,slave binding the binding has to be + * transformed to the new external encoder binding. + */ + +#include linux/kernel.h +#include linux/of.h +#include linux/of_graph.h +#include linux/of_fdt.h +#include linux/slab.h +#include linux/list.h + +#include tilcdc_slave_compat.h + +struct kfree_table { + int total; + int num; + void **table; +}; + +static int __init kfree_table_init(struct kfree_table *kft) +{ + kft-total = 32; + kft-num = 0; + kft-table = kmalloc(kft-total * sizeof(*kft-table), +GFP_KERNEL); + if (!kft-table) + return -ENOMEM; + + return 0; +} + +static int __init kfree_table_add(struct kfree_table *kft, void *p) +{ + if (kft-num == kft-total) { + void **old = kft-table; + + kft-total *= 2; + kft-table = krealloc(old, kft-total * sizeof(*kft-table), + GFP_KERNEL); + if (!kft-table) { + kft-table = old; + kfree(p); + return -ENOMEM; + } + } + kft-table[kft-num++] = p; + return 0; +} + +static void __init kfree_table_free(struct kfree_table *kft) +{ + int i; + + for (i = 0; i kft-num; i++) + kfree(kft-table[i]); + + kfree(kft-table); +} + +static +struct property * __init tilcdc_prop_dup(const struct property *prop, +struct kfree_table *kft) +{ + struct property *nprop; + + nprop = kzalloc(sizeof(*nprop), GFP_KERNEL); + if (!nprop || kfree_table_add(kft, nprop)) + return NULL; + + nprop-name = kstrdup(prop-name, GFP_KERNEL); + if (!nprop-name || kfree_table_add(kft, nprop-name)) + return NULL; + + nprop-value = kmemdup(prop-value, prop-length, GFP_KERNEL); + if (!nprop-value || kfree_table_add(kft, nprop-value)) + return NULL; + + nprop-length = prop-length; + + return nprop; +} + +static void __init tilcdc_copy_props(struct device_node *from
[PATCH v6 2/7] drm/tilcdc: Remove tilcdc slave support for tda998x driver
Remove tilcdc slave support for tda998x driver. The tilcdc slave support would conflicts with componentized use of tda998x. Signed-off-by: Jyri Sarha jsa...@ti.com --- .../devicetree/bindings/drm/tilcdc/slave.txt | 18 - drivers/gpu/drm/tilcdc/Makefile| 1 - drivers/gpu/drm/tilcdc/tilcdc_drv.c| 13 - drivers/gpu/drm/tilcdc/tilcdc_drv.h| 1 - drivers/gpu/drm/tilcdc/tilcdc_slave.c | 411 - drivers/gpu/drm/tilcdc/tilcdc_slave.h | 26 -- 6 files changed, 470 deletions(-) delete mode 100644 Documentation/devicetree/bindings/drm/tilcdc/slave.txt delete mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave.c delete mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave.h diff --git a/Documentation/devicetree/bindings/drm/tilcdc/slave.txt b/Documentation/devicetree/bindings/drm/tilcdc/slave.txt deleted file mode 100644 index 3d2c524..000 --- a/Documentation/devicetree/bindings/drm/tilcdc/slave.txt +++ /dev/null @@ -1,18 +0,0 @@ -Device-Tree bindings for tilcdc DRM encoder slave output driver - -Required properties: - - compatible: value should be ti,tilcdc,slave. - - i2c: the phandle for the i2c device the encoder slave is connected to - -Recommended properties: - - pinctrl-names, pinctrl-0: the pincontrol settings to configure - muxing properly for pins that connect to TFP410 device - -Example: - - hdmi { - compatible = ti,tilcdc,slave; - i2c = i2c0; - pinctrl-names = default; - pinctrl-0 = nxp_hdmi_bonelt_pins; - }; diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile index 7d2eefe..44485f9 100644 --- a/drivers/gpu/drm/tilcdc/Makefile +++ b/drivers/gpu/drm/tilcdc/Makefile @@ -6,7 +6,6 @@ endif tilcdc-y := \ tilcdc_crtc.o \ tilcdc_tfp410.o \ - tilcdc_slave.o \ tilcdc_panel.o \ tilcdc_drv.o diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 095fca9..0f1e099 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -20,13 +20,11 @@ #include tilcdc_drv.h #include tilcdc_regs.h #include tilcdc_tfp410.h -#include tilcdc_slave.h #include tilcdc_panel.h #include drm_fb_helper.h static LIST_HEAD(module_list); -static bool slave_probing; void tilcdc_module_init(struct tilcdc_module *mod, const char *name, const struct tilcdc_module_ops *funcs) @@ -42,11 +40,6 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) list_del(mod-list); } -void tilcdc_slave_probedefer(bool defered) -{ - slave_probing = defered; -} - static struct of_device_id tilcdc_of_match[]; static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, @@ -620,10 +613,6 @@ static int tilcdc_pdev_probe(struct platform_device *pdev) return -ENXIO; } - /* defer probing if slave is in deferred probing */ - if (slave_probing == true) - return -EPROBE_DEFER; - return drm_platform_init(tilcdc_driver, pdev); } @@ -654,7 +643,6 @@ static int __init tilcdc_drm_init(void) { DBG(init); tilcdc_tfp410_init(); - tilcdc_slave_init(); tilcdc_panel_init(); return platform_driver_register(tilcdc_platform_driver); } @@ -664,7 +652,6 @@ static void __exit tilcdc_drm_fini(void) DBG(fini); platform_driver_unregister(tilcdc_platform_driver); tilcdc_panel_fini(); - tilcdc_slave_fini(); tilcdc_tfp410_fini(); } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 7596c14..6336512 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -116,7 +116,6 @@ struct tilcdc_module { void tilcdc_module_init(struct tilcdc_module *mod, const char *name, const struct tilcdc_module_ops *funcs); void tilcdc_module_cleanup(struct tilcdc_module *mod); -void tilcdc_slave_probedefer(bool defered); /* Panel config that needs to be set in the crtc, but is not coming from * the mode timings. The display module is expected to call diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c deleted file mode 100644 index 3775fd4..000 --- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (C) 2012 Texas Instruments - * Author: Rob Clark robdcl...@gmail.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You
[PATCH v6 6/7] drm/tilcdc: Force building of DRM_TILCDC_SLAVE_COMPAT
If I read Documentation/kbuild/makefiles.txt section 3.6 right, this patch should not be needed. However, without this patch the objects needed for DRM_TILCDC_SLAVE_COMPAT are not linked, if DRM_TILCDC is built as module. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 7d4944e..6081fa6 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -60,7 +60,7 @@ obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ obj-$(CONFIG_DRM_OMAP) += omapdrm/ -obj-$(CONFIG_DRM_TILCDC) += tilcdc/ +obj-y += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ obj-$(CONFIG_DRM_BOCHS) += bochs/ obj-$(CONFIG_DRM_MSM) += msm/ -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 0/7] Use DRM component API in tilcdc to connect to tda998x
Like the last time, for all that I know this should be good for taking :). Changes since v5 * Move DRM_TILCDC_SLAVE_COMPAT after DRM_TILCDC in .../drm/tilcdc/Kconfig * Add drm/tilcdc: use pm_runtime_irq_safe()-patch Changes since v4 * Rebased on top linux-4.1-rc2 * Drop drm/tilcdc: Decrement refcount of ep-node from of_graph_get_next_... * Make connector_funcs const in struct tilcdc_drm_private because struct drm_connector's helper_private has been qualified as const in linux-4.1 * Check if a subcomponent has already triggered the unloading. - Fixes an oops if the external encoder is unloaded first and tilcdc after * Add comment to explain hijacking of external drm connectors helper hijacking Changes since v3 version of the patch-set: * drm/tilcdc: Add support for external tda998x encoder - Hijack external connectors helper functions - Remove select of nonexistent DRM_TILCDC_INIT in tilcdc Kconfig - Correct author mail address to tilcdc_exteral.h * drm/tilcdc: Add DRM_TILCDC_SLAVE_COMPAT for ti,tilcdc,slave binding - Add a header file for tilcdc_slave_compat.dtb symbol declarations Changes since v2 version of the patch-set: - use obj-y in Makefle for tilcdc subdir in: drm/tilcdc: Force building of DRM_TILCDC_SLAVE_COMPAT - move to last: drm/tilcdc: Decrement refcount of ep-node from of_graph_get_next_endpoint Changes since first version of the patch-set: - Rename DRM_TILCDC_INIT to DRM_TILCDC_SLAVE_COMPAT and make it visible - Add separate: drm/tilcdc: Decrement refcount of ep-node from of_graph_get_next_endpoint - Reduce info-level spam - Use component_master_add_with_match() - Be more explicit about tda998x being the only supported external encoder Remove tilcdc slave support and connect to tda998x trough its component DRM API. For dtb backward compatibility the code creates at boot time a DT overlay based on the earlier binding. The overlay conforms to the new graph based binding. The drm/tilcdc: Decrement refcount of ep-node from of_graph_get_next_endpoint should probably not be merged. The of: Decrement refcount of previous endpoint in of_graph_get_next_endpoint is eventually going to be merged and before that leaking of two of-node refcount increments each time the module is loaded is not that serious. The of-nodes live forever anyway. The merge of the dts patch can be delayed until the next merger window, when the other patches are already in. The DRM_TILCDC_SLAVE_COMPAT should keep the bbb HDMI operational until then. The first patch is just a bugfix and can be applied or dropped independently. Jyri Sarha (6): drm/tilcdc: Fix module unloading drm/tilcdc: Remove tilcdc slave support for tda998x driver drm/tilcdc: Add support for external tda998x encoder drm/tilcdc: Add DRM_TILCDC_SLAVE_COMPAT for ti,tilcdc,slave binding support drm/tilcdc: Force building of DRM_TILCDC_SLAVE_COMPAT ARM: dts: am335x-boneblack: Use new binding for HDMI Tomi Valkeinen (1): drm/tilcdc: use pm_runtime_irq_safe() .../devicetree/bindings/drm/tilcdc/slave.txt | 18 - .../devicetree/bindings/drm/tilcdc/tilcdc.txt | 27 ++ arch/arm/boot/dts/am335x-boneblack.dts | 20 +- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/tilcdc/Kconfig | 12 + drivers/gpu/drm/tilcdc/Makefile| 5 +- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 36 +- drivers/gpu/drm/tilcdc/tilcdc_drv.c| 99 +++-- drivers/gpu/drm/tilcdc/tilcdc_drv.h| 6 +- drivers/gpu/drm/tilcdc/tilcdc_external.c | 166 + drivers/gpu/drm/tilcdc/tilcdc_external.h | 25 ++ drivers/gpu/drm/tilcdc/tilcdc_slave.c | 411 - drivers/gpu/drm/tilcdc/tilcdc_slave.h | 26 -- drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 270 ++ drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts | 72 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.h | 25 ++ 16 files changed, 730 insertions(+), 490 deletions(-) delete mode 100644 Documentation/devicetree/bindings/drm/tilcdc/slave.txt create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_external.c create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_external.h delete mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave.c delete mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave.h create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.h -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 1/7] drm/tilcdc: Fix module unloading
Force crtc dpms off before destroying the crtc instead of just checking the dpms state. This fixes warning message and frozen picture after tilcdc module unloading. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index c735884..c2d5980 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -135,11 +135,12 @@ static void stop(struct drm_crtc *crtc) tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); } +static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode); static void tilcdc_crtc_destroy(struct drm_crtc *crtc) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); - WARN_ON(tilcdc_crtc-dpms == DRM_MODE_DPMS_ON); + tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); drm_crtc_cleanup(crtc); drm_flip_work_cleanup(tilcdc_crtc-unref_work); -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v2 4/7] ASoC: hdmi-codec: Add ELD based audio pcm rules DO NOT MERGE
This patch is mostly just a copy paste from Russel King's generic patchs[1] for the same thing. The patche is included only for testing purposes. Do not merge! [1] http://lists.freedesktop.org/archives/dri-devel/2015-April/080525.html Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/codecs/hdmi-codec.c | 104 +- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index c208cef..2d26ce8 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -78,6 +78,103 @@ static int hdmi_codec_new_stream(struct snd_pcm_substream *substream, return ret; } +static const uint8_t *eld_sad(const uint8_t *eld) +{ + unsigned int ver, mnl; + + ver = (eld[DRM_ELD_VER] DRM_ELD_VER_MASK) DRM_ELD_VER_SHIFT; + if (ver != 2 ver != 31) + return NULL; + + mnl = drm_eld_mnl(eld); + if (mnl 16) + return NULL; + + return eld + DRM_ELD_CEA_SAD(mnl, 0); +} + +static const unsigned int eld_rates[] = { + 32000, + 44100, + 48000, + 88200, + 96000, + 176400, + 192000, +}; + +static int eld_limit_rates(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *r = hw_param_interval(params, rule-var); + unsigned int rate_mask = 7, i; + const u8 *sad, *eld = rule-private; + + sad = eld_sad(eld); + if (sad) { + for (i = drm_eld_sad_count(eld); i 0; i--, sad += 3) { + unsigned channels = 1 + (sad[0] 7); + + /* +* Exclude SADs which do not include the +* requested number of channels. +*/ + if (params_channels(params) == channels) + rate_mask |= sad[1]; + } + } + + return snd_interval_list(r, ARRAY_SIZE(eld_rates), eld_rates, +rate_mask); +} + +static int eld_limit_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *var = hw_param_interval(params, rule-var); + struct snd_interval t = { .min = 1, .max = 2, .integer = 1, }; + unsigned int i, j; + const u8 *sad, *eld = rule-private; + int rate = params_rate(params); + + sad = eld_sad(eld); + if (!sad) + return 0; + + for (i = drm_eld_sad_count(eld); i 0; i--, sad += 3) { + for (j = 0; j ARRAY_SIZE(eld_rates); j++) { + if ((sad[1] (1j)) rate == eld_rates[j]) { + switch (sad[0] 0x78) { + case 0x08: + t.max = max(t.max, (sad[0] 7) + 1u); + break; + } + } + } + } + + return snd_interval_refine(var, t); +} + +static int hdmi_codec_constraint_eld(struct snd_pcm_runtime *runtime, void *eld) +{ + int ret; + + ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + eld_limit_rates, eld, + SNDRV_PCM_HW_PARAM_RATE, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret 0) + return ret; + + ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + eld_limit_channels, eld, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, -1); + + return ret; +} + static int hdmi_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -104,7 +201,12 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (hcp-hcd.ops-get_eld) { hcp-eld = hcp-hcd.ops-get_eld(hcp-hcd.dev); - /* Call snd_pcm_hw_constraint_eld here */ + if (hcp-eld) { + ret = hdmi_codec_constraint_eld(substream-runtime, + hcp-eld); + if (ret) + return ret; + } } return 0; } -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v2 3/7] ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders
The hdmi-codec is a platform device driver to be registered from drivers of external HDMI encoders with I2S and/or spdif interface. The driver in turn registers an ASoC codec for the encoder's audio functionality. The structures and definitions in the API header are mostly redundant copies of similar structures in ASoC headers. This is on purpose to avoid direct dependencies to ASoC structures in video side driver. Signed-off-by: Jyri Sarha jsa...@ti.com --- include/sound/hdmi-codec.h| 99 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdmi-codec.c | 458 ++ 4 files changed, 563 insertions(+) create mode 100644 include/sound/hdmi-codec.h create mode 100644 sound/soc/codecs/hdmi-codec.c diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h new file mode 100644 index 000..0632bcb --- /dev/null +++ b/include/sound/hdmi-codec.h @@ -0,0 +1,99 @@ +/* + * hdmi-codec.h - HDMI Codec driver API + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Jyri Sarha jsa...@ti.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __HDMI_CODEC_H__ +#define __HDMI_CODEC_H__ + +#include linux/hdmi.h +#include drm/drm_edid.h +#include sound/asoundef.h +#include uapi/sound/asound.h + +/* + * Protocol between ASoC cpu-dai and HDMI-encoder + */ +struct hdmi_codec_daifmt { + enum { + HDMI_I2S, + HDMI_RIGHT_J, + HDMI_LEFT_J, + HDMI_DSP_A, + HDMI_DSP_B, + HDMI_AC97, + HDMI_SPDIF, + } fmt; + int bit_clk_inv:1; + int frame_clk_inv:1; + int bit_clk_master:1; + int frame_clk_master:1; +}; + +/* + * HDMI audio parameters + */ +struct hdmi_codec_params { + struct hdmi_audio_infoframe cea; + struct snd_aes_iec958 iec; + int sample_rate; + int sample_width; + int channels; +}; + +struct hdmi_codec_ops { + /* For runtime clock configuration from ASoC machine driver. +* A direct forward from set_sysclk in struct snd_soc_dai_ops. +* Optional */ + int (*set_clk)(struct device *dev, int clk_id, int freq); + + /* Called when ASoC starts an audio stream setup. The call +* provides an audio abort callback for stoping an ongoing +* stream if the HDMI audio becomes unavailable. +* Optional */ + int (*audio_startup)(struct device *dev, +void (*abort_cb)(struct device *dev)); + + /* Configures HDMI-encoder for audio stream. +* Mandatory */ + int (*hw_params)(struct device *dev, +struct hdmi_codec_daifmt *fmt, +struct hdmi_codec_params *hparms); + + /* Shuts down the audio stream. +* Mandatory */ + void (*audio_shutdown)(struct device *dev); + + /* Mute/unmute HDMI audio stream. +* Optional */ + int (*digital_mute)(struct device *dev, bool enable); + + /* Provides EDID-Like-Data from connected HDMI device. +* Optional */ + uint8_t *(*get_eld)(struct device *dev); +}; + +/* HDMI codec initalization data */ +struct hdmi_codec_pdata { + struct device *dev; /* The HDMI encoder registering the codec */ + const struct hdmi_codec_ops *ops; + uint i2s:1; + uint spdif:1; + int max_i2s_channels; +}; + +#define HDMI_CODEC_DRV_NAME hdmi-audio-codec + +#endif /* __HDMI_CODEC_H__ */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index fb7f978..ef9646f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -76,6 +76,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C + select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 @@ -429,6 +430,9 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate +config SND_SOC_HDMI_CODEC + tristate + config SND_SOC_ES8328 tristate Everest Semi ES8328 CODEC diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4e5d17c..a128c2b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -69,6 +69,7 @@ snd-soc-max98925-objs := max98925.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o +snd-soc-hdmi-codec-objs := hdmi-codec.o
[PATCH RFC v2 6/7] drm/i2c: tda998x: Register ASoC HDMI codec for audio functionality DO NOT MERGE
This patch is here to demonstrate how to use the ASoC hdmi-codec to implement ASoC codec API in tda998x driver. I do not have proper documentation for tda998x family chips so I lack the necessary information for making a decent binding for audio part of the chip. In stead I use binding from Jean-Francois Moine's ASoC: tda998x: add a codec to the HDMI transmitter patch series. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/i2c/Kconfig | 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 238 ++ 2 files changed, 239 insertions(+) diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 22c7ed6..088f278 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -28,6 +28,7 @@ config DRM_I2C_SIL164 config DRM_I2C_NXP_TDA998X tristate NXP Semiconductors TDA998X HDMI encoder default m if DRM_TILCDC + select SND_SOC_HDMI_CODEC if SND_SOC help Support for NXP Semiconductors TDA998X HDMI encoders. diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index bcf96f7..3c38911 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -20,6 +20,7 @@ #include linux/module.h #include linux/irq.h #include sound/asoundef.h +#include sound/hdmi-codec.h #include drm/drmP.h #include drm/drm_crtc_helper.h @@ -45,6 +46,9 @@ struct tda998x_priv { u8 vip_cntrl_2; struct tda998x_encoder_params params; + struct platform_device *audio_pdev; + uint8_t eld[MAX_ELD_BYTES]; + wait_queue_head_t wq_edid; volatile int wq_edid_wait; struct drm_encoder *encoder; @@ -1120,6 +1124,9 @@ tda998x_encoder_get_modes(struct tda998x_priv *priv, drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); priv-is_hdmi_sink = drm_detect_hdmi_monitor(edid); + drm_edid_to_eld(connector, edid); + memcpy(priv-eld, connector-eld, sizeof(priv-eld)); + kfree(edid); return n; @@ -1156,6 +1163,9 @@ static void tda998x_destroy(struct tda998x_priv *priv) } i2c_unregister_device(priv-cec); + + if (priv-audio_pdev) + platform_device_unregister(priv-audio_pdev); } /* Slave encoder support */ @@ -1230,6 +1240,230 @@ static struct drm_encoder_slave_funcs tda998x_encoder_slave_funcs = { .set_property = tda998x_encoder_set_property, }; +static int +tda998x_configure_audio2(struct tda998x_priv *priv, + int mode_clock, + int ena_ap, + struct hdmi_codec_params *params, + struct hdmi_codec_daifmt *daifmt) +{ + uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv; + uint8_t infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; + int infoframe_len; + uint32_t n; + + infoframe_len = hdmi_audio_infoframe_pack(params-cea, infoframe_buf, + sizeof(infoframe_buf)); + if (infoframe_len 0) { + dev_err(priv-hdmi-dev, + Failed to pack audio infoframe: %d\n, + infoframe_len); + return infoframe_len; + } + + /* Enable audio ports */ + reg_write(priv, REG_ENA_AP, ena_ap); + reg_write(priv, REG_ENA_ACLK, daifmt-fmt == HDMI_SPDIF ? 0 : 1); + + /* Set audio input source */ + switch (daifmt-fmt) { + case HDMI_SPDIF: + reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF); + clksel_aip = AIP_CLKSEL_AIP_SPDIF; + clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; + cts_n = CTS_N_M(3) | CTS_N_K(3); + break; + + case HDMI_I2S: + reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); + clksel_aip = AIP_CLKSEL_AIP_I2S; + clksel_fs = AIP_CLKSEL_FS_ACLK; + switch (params-sample_width) { + case 16: + cts_n = CTS_N_M(3) | CTS_N_K(1); + break; + case 18: + case 20: + case 24: + cts_n = CTS_N_M(3) | CTS_N_K(2); + break; + default: + case 32: + cts_n = CTS_N_M(3) | CTS_N_K(3); + break; + } + break; + + default: + dev_err(priv-hdmi-dev, Unsupported I2S format\n); + return -EINVAL; + } + + reg_write(priv, REG_AIP_CLKSEL, clksel_aip); + reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT | + AIP_CNTRL_0_ACR_MAN); /* auto CTS */ + reg_write(priv, REG_CTS_N, cts_n); + + /* +* Audio input somehow depends on HDMI line rate which is +* related to pixclk. Testing showed that modes
[PATCH RFC v2 0/7] Implement generic ASoC HDMI codec
Only the first three patches are meant for serious review. The ASoC part should be ready for review in other respects but the EDID SADs handling is waiting for Russell King's DRM ELD helper patches. There is a copy-pasted not-to-be-merged patch with the same functionality in the patch series. The tda998x part is not complete and I do not think Jean-Francois' binding are ready as such either. At least the usage of reg property in a port node for something that is not an address or even guaranteed to be unique is not a good idea. Some documentation of how to configure AP0-AP4 pins (REG_ENA_AP?) would help in making a proper binding for the tda998x audio configuration. These patches, my tilcdc refactoring[1], and my latest BCLK fixes for davinci-mcasp driver [2], can be found in a branch that produces working HDMI audio on Beaglebone-Black here: https://github.com/jsarha/linux.git linux-master-bbb-hdmi-20150512 [1] http://lists.freedesktop.org/archives/dri-devel/2015-May/082537.html [2] http://mailman.alsa-project.org/pipermail/alsa-devel/2015-April/090974.html Jean-Francois Moine (1): drm/i2c: tda998x: Add support of a DT graph of ports DO NOT MERGE Jyri Sarha (6): ASoC: core: If component doesn't have of_node use parent's node instead ASoC: hdmi: Remove obsolete dummy HDMI codec ASoC: hdmi-codec: Add hdmi-codec for external HDMI-encoders ASoC: hdmi-codec: Add ELD based audio pcm rules DO NOT MERGE drm/i2c: tda998x: Register ASoC HDMI codec for audio functionality DO NOT MERGE ARM: dts: am335x-boneblack: Add HDMI audio support DO NOT MERGE .../devicetree/bindings/drm/i2c/tda998x.txt| 51 ++ arch/arm/boot/dts/am335x-boneblack.dts | 78 ++- drivers/gpu/drm/i2c/Kconfig| 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 328 +++- include/sound/hdmi-codec.h | 99 include/sound/tda998x.h| 8 + sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/Makefile | 4 +- sound/soc/codecs/hdmi-codec.c | 560 + sound/soc/codecs/hdmi.c| 109 sound/soc/soc-core.c | 14 +- 11 files changed, 1129 insertions(+), 125 deletions(-) create mode 100644 include/sound/hdmi-codec.h create mode 100644 include/sound/tda998x.h create mode 100644 sound/soc/codecs/hdmi-codec.c delete mode 100644 sound/soc/codecs/hdmi.c -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v2 1/7] ASoC: core: If component doesn't have of_node use parent's node instead
If an ASoC component device does not have a device tree node, use its parent's node instead, when looking for a matching DAI based on a device tree reference. This allows video device drivers to register a separate child device for their ASoC side audio functionality. Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/soc-core.c | 14 -- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2373252..b1bcff2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -904,12 +904,17 @@ static struct snd_soc_dai *snd_soc_find_dai( { struct snd_soc_component *component; struct snd_soc_dai *dai; + struct device_node *component_of_node; lockdep_assert_held(client_mutex); /* Find CPU DAI from registered DAIs*/ list_for_each_entry(component, component_list, list) { - if (dlc-of_node component-dev-of_node != dlc-of_node) + component_of_node = component-dev-of_node; + if (!component_of_node component-dev-parent) + component_of_node = component-dev-parent-of_node; + + if (dlc-of_node component_of_node != dlc-of_node) continue; if (dlc-name strcmp(component-name, dlc-name)) continue; @@ -3488,11 +3493,16 @@ static int snd_soc_get_dai_name(struct of_phandle_args *args, const char **dai_name) { struct snd_soc_component *pos; + struct device_node *component_of_node; int ret = -EPROBE_DEFER; mutex_lock(client_mutex); list_for_each_entry(pos, component_list, list) { - if (pos-dev-of_node != args-np) + component_of_node = pos-dev-of_node; + if (!component_of_node pos-dev-parent) + component_of_node = pos-dev-parent-of_node; + + if (component_of_node != args-np) continue; if (pos-driver-of_xlate_dai_name) { -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH RFC v2 2/7] ASoC: hdmi: Remove obsolete dummy HDMI codec
The hdmi stub codec has not been used since refactoring of OMAP HDMI audio support. Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/codecs/Kconfig | 4 -- sound/soc/codecs/Makefile | 2 - sound/soc/codecs/hdmi.c | 109 -- 3 files changed, 115 deletions(-) delete mode 100644 sound/soc/codecs/hdmi.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c465..fb7f978 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -76,7 +76,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C - select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C select SND_SOC_PCM1792A if SPI_MASTER select SND_SOC_PCM3008 @@ -430,9 +429,6 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate -config SND_SOC_HDMI_CODEC - tristate HDMI stub CODEC - config SND_SOC_ES8328 tristate Everest Semi ES8328 CODEC diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7e..4e5d17c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -69,7 +69,6 @@ snd-soc-max98925-objs := max98925.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o -snd-soc-hdmi-codec-objs := hdmi.o snd-soc-pcm1681-objs := pcm1681.o snd-soc-pcm1792a-codec-objs := pcm1792a.o snd-soc-pcm3008-objs := pcm3008.o @@ -254,7 +253,6 @@ obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o -obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c deleted file mode 100644 index bd42ad3..000 --- a/sound/soc/codecs/hdmi.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * ALSA SoC codec driver for HDMI audio codecs. - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Ricardo Neri ricardo.n...@ti.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#include linux/module.h -#include sound/soc.h -#include linux/of.h -#include linux/of_device.h - -#define DRV_NAME hdmi-audio-codec - -static const struct snd_soc_dapm_widget hdmi_widgets[] = { - SND_SOC_DAPM_INPUT(RX), - SND_SOC_DAPM_OUTPUT(TX), -}; - -static const struct snd_soc_dapm_route hdmi_routes[] = { - { Capture, NULL, RX }, - { TX, NULL, Playback }, -}; - -static struct snd_soc_dai_driver hdmi_codec_dai = { - .name = hdmi-hifi, - .playback = { - .stream_name = Playback, - .channels_min = 2, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 24, - }, - .capture = { - .stream_name = Capture, - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, - -}; - -#ifdef CONFIG_OF -static const struct of_device_id hdmi_audio_codec_ids[] = { - { .compatible = linux,hdmi-audio, }, - { } -}; -MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids); -#endif - -static struct snd_soc_codec_driver hdmi_codec = { - .dapm_widgets = hdmi_widgets, - .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), - .dapm_routes = hdmi_routes, - .num_dapm_routes = ARRAY_SIZE(hdmi_routes), - .ignore_pmdown_time
[PATCH RFC v2 5/7] drm/i2c: tda998x: Add support of a DT graph of ports DO NOT MERGE
From: Jean-Francois Moine moin...@free.fr Two kinds of ports may be declared in a DT graph of ports: video and audio. This patch accepts the port value from a video port as an alternative to the video-ports property. It also accepts audio ports in the case the transmitter is not used as a slave encoder. The new file include/sound/tda998x.h prepares to the definition of a tda998x CODEC. Signed-off-by: Jean-Francois Moine moin...@free.fr Signed-off-by: Jyri Sarha jsa...@ti.com --- .../devicetree/bindings/drm/i2c/tda998x.txt| 51 drivers/gpu/drm/i2c/tda998x_drv.c | 90 +++--- include/sound/tda998x.h| 8 ++ 3 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 include/sound/tda998x.h diff --git a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt index e9e4bce..386b6c3 100644 --- a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt +++ b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt @@ -16,6 +16,35 @@ Optional properties: - video-ports: 24 bits value which defines how the video controller output is wired to the TDA998x input - default: 0x230145 + This property is not used when ports are defined. + +Optional nodes: + + - port: up to three ports. + The ports are defined according to [1]. + +Video port. + There may be only one video port. + This one must contain the following property: + + - port-type: must be rgb + + and may contain the optional property: + + - reg: 24 bits value which defines how the video controller + output is wired to the TDA998x input (video pins) + When absent, the default value is 0x230145. + +Audio ports. + There may be one or two audio ports. + These ones must contain the following properties: + + - port-type: must be i2s or spdif + + - reg: 8 bits value which defines how the audio controller + output is wired to the TDA998x input (audio pins) + +[1] Documentation/devicetree/bindings/graph.txt Example: @@ -26,4 +55,26 @@ Example: interrupts = 27 2;/* falling edge */ pinctrl-0 = pmx_camera; pinctrl-names = default; + + port at 230145 { + port-type = rgb; + reg = 0x230145; + hdmi_0: endpoint { + remote-endpoint = lcd0_0; + }; + }; + port at 3 { /* AP1 = I2S */ + port-type = i2s; + reg = 0x03; + tda998x_i2s: endpoint { + remote-endpoint = audio1_i2s; + }; + }; + port at 4 { /* AP2 = S/PDIF */ + port-type = spdif; + reg = 0x04; + tda998x_spdif: endpoint { + remote-endpoint = audio1_spdif1; + }; + }; }; diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 5febffd..bcf96f7 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -27,6 +27,7 @@ #include drm/drm_edid.h #include drm/drm_of.h #include drm/i2c/tda998x.h +#include sound/tda998x.h #define DBG(fmt, ...) DRM_DEBUG(fmt\n, ##__VA_ARGS__) @@ -47,6 +48,8 @@ struct tda998x_priv { wait_queue_head_t wq_edid; volatile int wq_edid_wait; struct drm_encoder *encoder; + + struct tda998x_audio_s audio; }; #define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)-slave_priv) @@ -771,6 +774,8 @@ static void tda998x_encoder_set_config(struct tda998x_priv *priv, (p-mirr_f ? VIP_CNTRL_2_MIRR_F : 0); priv-params = *p; + priv-audio.port_types[0] = p-audio_format; + priv-audio.ports[0] = p-audio_cfg; } static void tda998x_encoder_dpms(struct tda998x_priv *priv, int mode) @@ -1227,9 +1232,57 @@ static struct drm_encoder_slave_funcs tda998x_encoder_slave_funcs = { /* I2C driver functions */ +static int tda998x_parse_ports(struct tda998x_priv *priv, + struct device_node *np) +{ + struct device_node *of_port; + const char *port_type; + int ret, audio_index, reg, afmt; + + audio_index = 0; + for_each_child_of_node(np, of_port) { + if (!of_port-name +|| of_node_cmp(of_port-name, port) != 0) + continue; + ret = of_property_read_string(of_port, port-type, + port_type); + if (ret 0) + continue; + ret = of_property_read_u32
[PATCH RFC v2 7/7] ARM: dts: am335x-boneblack: Add HDMI audio support DO NOT MERGE
This patch is here only to demonstrate HDMI codec functionality on Beaglebone-Black. Adds mcasp0_pins, clk_mcasp0_fixed, clk_mcasp0, mcasp0, sound node, and changes the tda19988 node to follow the new binding. Signed-off-by: Jyri Sarha jsa...@ti.com --- arch/arm/boot/dts/am335x-boneblack.dts | 78 +- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts index eadbba3..8a8abf5 100644 --- a/arch/arm/boot/dts/am335x-boneblack.dts +++ b/arch/arm/boot/dts/am335x-boneblack.dts @@ -64,6 +64,16 @@ 0x1b0 0x03 /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */ ; }; + + mcasp0_pins: mcasp0_pins { + pinctrl-single,pins = + 0x1ac (PIN_INPUT_PULLUP | MUX_MODE0)/* mcasp0_ahclkx.mcasp0_ahclkx */ + 0x19c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2 */ + 0x194 (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mcasp0_fsx.mcasp0_fsx */ + 0x190 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp0_aclkx.mcasp0_aclkx */ + 0x06c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a11.GPIO1_27 */ + ; + }; }; lcdc { @@ -76,21 +86,85 @@ }; i2c0 { - tda19988 { + tda19988: tda19988 { compatible = nxp,tda998x; reg = 0x70; + + #sound-dai-cells = 0; + pinctrl-names = default, off; pinctrl-0 = nxp_hdmi_bonelt_pins; pinctrl-1 = nxp_hdmi_bonelt_off_pins; - port { + port@0 { + port-type = rgb; + reg = 0x230145; hdmi_0: endpoint@0 { remote-endpoint = lcdc_0; }; }; + port@1 { + port-type = i2s; + reg = 0x03; + tda19988_i2s: endpoint { + remote-endpoint = mcasp0_i2s; + }; + }; }; }; rtc { system-power-controller; }; + +mcasp0{ + #sound-dai-cells = 0; + pinctrl-names = default; + pinctrl-0 = mcasp0_pins; + status = okay; + op-mode = 0; /* MCASP_IIS_MODE */ + tdm-slots = 2; + serial-dir = /* 0: INACTIVE, 1: TX, 2: RX */ + 0 0 1 0 + ; + tx-num-evt = 1; + rx-num-evt = 1; + + port { + mcasp0_i2s: endpoint { + remote-endpoint = tda19988_i2s; + }; + }; +}; + +/ { + clk_mcasp0_fixed: clk_mcasp0_fixed { + #clock-cells = 0; + compatible = fixed-clock; + clock-frequency = 24576000; + }; + + clk_mcasp0: clk_mcasp0 { + #clock-cells = 0; + compatible = gpio-gate-clock; + clocks = clk_mcasp0_fixed; + enable-gpios = gpio1 27 0; /* BeagleBone Black Clk enable on GPIO1_27 */ + }; + + sound { + compatible = simple-audio-card; + simple-audio-card,name = TI BeagleBone Black; + simple-audio-card,format = i2s; + simple-audio-card,bitclock-master = dailink0_master; + simple-audio-card,frame-master = dailink0_master; + + dailink0_master: simple-audio-card,cpu { + sound-dai = mcasp0; + clocks = clk_mcasp0; + }; + + simple-audio-card,codec { + sound-dai = tda19988; + }; + }; +}; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH early RFC 2/2] drm/i2c: tda998x: HACK Implement primitive HDMI audio with ASoC hdmi-code-lib
This patch is to demonstrate how to use the ASoC hdmi-codec-lib to implement ASoC codec API in tda998x driver. I do not have proper documentation for tda998x family chips so I lack the necessary information for making a proper binding for audio part of the chip. The configuration is hard coded to work on Beaglebone-Black. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/i2c/Kconfig | 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 238 ++ 2 files changed, 239 insertions(+) diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 22c7ed6..92302e9 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -28,6 +28,7 @@ config DRM_I2C_SIL164 config DRM_I2C_NXP_TDA998X tristate NXP Semiconductors TDA998X HDMI encoder default m if DRM_TILCDC + select SND_SOC_HDMI_CODEC_LIB if SND_SOC help Support for NXP Semiconductors TDA998X HDMI encoders. diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 5febffd..797b4d5 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -20,6 +20,7 @@ #include linux/module.h #include linux/irq.h #include sound/asoundef.h +#include sound/hdmi-codec-lib.h #include drm/drmP.h #include drm/drm_crtc_helper.h @@ -31,6 +32,7 @@ #define DBG(fmt, ...) DRM_DEBUG(fmt\n, ##__VA_ARGS__) struct tda998x_priv { + struct hdmi_codec_drvdata audio_data; struct i2c_client *cec; struct i2c_client *hdmi; struct mutex mutex; @@ -44,6 +46,10 @@ struct tda998x_priv { u8 vip_cntrl_2; struct tda998x_encoder_params params; + struct mutex sads_mutex; + struct cea_sad *sads; + int sads_count; + wait_queue_head_t wq_edid; volatile int wq_edid_wait; struct drm_encoder *encoder; @@ -1115,6 +1121,13 @@ tda998x_encoder_get_modes(struct tda998x_priv *priv, drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); priv-is_hdmi_sink = drm_detect_hdmi_monitor(edid); + + mutex_lock(priv-sads_mutex); + kfree(priv-sads); + priv-sads = NULL; + priv-sads_count = drm_edid_to_sad(edid, priv-sads); + mutex_unlock(priv-sads_mutex); + kfree(edid); return n; @@ -1151,6 +1164,14 @@ static void tda998x_destroy(struct tda998x_priv *priv) } i2c_unregister_device(priv-cec); + + asoc_hdmi_codec_unregister(priv-hdmi-dev); + + mutex_lock(priv-sads_mutex); + kfree(priv-sads); + priv-sads = NULL; + priv-sads_count = -ENODEV; + mutex_unlock(priv-sads_mutex); } /* Slave encoder support */ @@ -1225,6 +1246,217 @@ static struct drm_encoder_slave_funcs tda998x_encoder_slave_funcs = { .set_property = tda998x_encoder_set_property, }; +static int +tda998x_configure_audio2(struct tda998x_priv *priv, + int mode_clock, + int audio_ena, + struct hdmi_codec_params *params, + struct hdmi_codec_daifmt *daifmt) +{ + uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv; + uint8_t infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; + int infoframe_len; + uint32_t n; + + infoframe_len = hdmi_audio_infoframe_pack(params-cea, infoframe_buf, + sizeof(infoframe_buf)); + if (infoframe_len 0) { + dev_err(priv-hdmi-dev, + Failed to pack audio infoframe: %d\n, + infoframe_len); + return infoframe_len; + } + + /* Enable audio ports */ + reg_write(priv, REG_ENA_AP, audio_ena); + reg_write(priv, REG_ENA_ACLK, daifmt-fmt == HDMI_SPDIF ? 0 : 1); + + /* Set audio input source */ + switch (daifmt-fmt) { + case HDMI_SPDIF: + reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF); + clksel_aip = AIP_CLKSEL_AIP_SPDIF; + clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; + cts_n = CTS_N_M(3) | CTS_N_K(3); + break; + + case HDMI_I2S: + reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); + clksel_aip = AIP_CLKSEL_AIP_I2S; + clksel_fs = AIP_CLKSEL_FS_ACLK; + switch (params-sample_width) { + case 16: + cts_n = CTS_N_M(3) | CTS_N_K(1); + break; + case 18: + case 20: + case 24: + cts_n = CTS_N_M(3) | CTS_N_K(2); + break; + default: + case 32: + cts_n = CTS_N_M(3) | CTS_N_K(3); + break; + } + break; + + default: + dev_err(priv-hdmi-dev, Unsupported I2S format\n
[PATCH early RFC 0/2] Implement ASoC HDMI codec library
This is on early RFC and should not be merged yet. The idea is just to share my ideas early on as there has been a lot of development going on around HDMI audio. The I2S DAI of the ASoC side patch is usable already, the spdif support has not been tested and the EDID SADs handling should use Russel's DRM ELD helper when it is ready. The tda998x patch is just to demonstrate the usage of the HDMI-codec-lib. At least the audio related DT-bindings are missing completely and the configuration is hard coded to work on Beaglebone-Black. Jean-Francois, would you consider trying the generic ASoC patch with your HW, as I can not test the spdif functionality with mine? The library could also be implemented as a separate platform driver, but then adding a pointer for private data to struct snd_soc_dai_driver, snd_soc_codec, or to snd_soc_component would be of great help. These patches, my tilcdc refactoring[1], and my latest BCLK fixes for davinci-mcasp diver [2], can found in a branch that produces a working HDMI audio on Beaglebone-Black here: https://github.com/jsarha/linux.git linux-master-bbb-hdmi-20150512 [1] http://lists.freedesktop.org/archives/dri-devel/2015-May/082537.html [2] http://mailman.alsa-project.org/pipermail/alsa-devel/2015-April/090974.html Jyri Sarha (2): ASoC: hdmi-codec-lib: Add hdmi-codec-lib for external HDMI-encoders drm/i2c: tda998x: HACK Implement primitive HDMI audio with ASoC hdmi-code-lib drivers/gpu/drm/i2c/Kconfig | 1 + drivers/gpu/drm/i2c/tda998x_drv.c | 238 + include/sound/hdmi-codec-lib.h| 105 sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdmi-codec-lib.c | 536 ++ 6 files changed, 886 insertions(+) create mode 100644 include/sound/hdmi-codec-lib.h create mode 100644 sound/soc/codecs/hdmi-codec-lib.c -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 5/6] drm/tilcdc: Force building of DRM_TILCDC_SLAVE_COMPAT
If I read Documentation/kbuild/makefiles.txt section 3.6 right, this patch should not be needed. However, without this patch the objects needed for DRM_TILCDC_SLAVE_COMPAT are not linked, if DRM_TILCDC is built as module. Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/gpu/drm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 7d4944e..6081fa6 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -60,7 +60,7 @@ obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ obj-$(CONFIG_DRM_OMAP) += omapdrm/ -obj-$(CONFIG_DRM_TILCDC) += tilcdc/ +obj-y += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ obj-$(CONFIG_DRM_BOCHS) += bochs/ obj-$(CONFIG_DRM_MSM) += msm/ -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 0/7] Use DRM component API in tilcdc to connect to tda998x
On 05/07/15 12:44, Tomi Valkeinen wrote: On 01/04/15 11:49, Jyri Sarha wrote: Ok, let's do one more full review round. The mode filtering issue was the main reason for this new patch series version. However, I found couple other things to fix too after scrutinizing the patches once more. Changes since v3 version of the patch-set: * drm/tilcdc: Add support for external tda998x encoder - Hijack external connectors helper functions - Remove select of nonexistent DRM_TILCDC_INIT in tilcdc Kconfig - Correct author mail address to tilcdc_exteral.h * drm/tilcdc: Add DRM_TILCDC_SLAVE_COMPAT for ti,tilcdc,slave binding - Add a header file for tilcdc_slave_compat.dtb symbol declarations Changes since v2 version of the patch-set: - use obj-y in Makefle for tilcdc subdir in: drm/tilcdc: Force building of DRM_TILCDC_SLAVE_COMPAT - move to last: drm/tilcdc: Decrement refcount of ep-node from of_graph_get_next_endpoint Changes since first version of the patch-set: - Rename DRM_TILCDC_INIT to DRM_TILCDC_SLAVE_COMPAT and make it visible - Add separate: drm/tilcdc: Decrement refcount of ep-node from of_graph_get_next_endpoint - Reduce info-level spam - Use component_master_add_with_match() - Be more explicit about tda998x being the only supported external encoder Remove tilcdc slave support and connect to tda998x trough its component DRM API. For dtb backward compatibility the code creates at boot time a DT overlay based on the earlier binding. The overlay conforms to the new graph based binding. The drm/tilcdc: Decrement refcount of ep-node from of_graph_get_next_endpoint should probably not be merged. The of: Decrement refcount of previous endpoint in of_graph_get_next_endpoint is eventually going to be merged and before that leaking of two of-node refcount increments each time the module is loaded is not that serious. The of-nodes live forever anyway. The merge of the dts patch can be delayed until the next merger window, when the other patches are already in. The DRM_TILCDC_SLAVE_COMPAT should keep the bbb HDMI operational until then. I made a quick test on v4.1-rc2, and: What did you do to get this dump. The tilcdc driver has not done much at this point. There is basically noting before calling this function: int tilcdc_get_external_components(struct device *dev, struct component_match **match) { struct device_node *ep = NULL; int count = 0; while ((ep = of_graph_get_next_endpoint(dev-of_node, ep))) { struct device_node *node; node = of_graph_get_remote_port_parent(ep); if (!node !of_device_is_available(node)) { of_node_put(node); continue; } dev_dbg(dev, Subdevice node '%s' found\n, node-name); if (match) component_match_add(dev, match, dev_match_of, node); of_node_put(node); count++; } if (count 1) { dev_err(dev, Only one external encoder is supported\n); return -EINVAL; } return count; } If there is something wrong with the function I would certainly like to know what. Or is the bug somewhere else? Best regards, Jyri [ 15.199584] [drm] Initialized drm 1.1.0 20060810 [ 15.319496] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:616 [ 15.328339] in_atomic(): 1, irqs_disabled(): 128, pid: 130, name: insmod [ 15.335336] 3 locks held by insmod/130: [ 15.339339] #0: (dev-mutex){..}, at: [c044d8d0] __driver_attach+0x50/0xa0 [ 15.347389] #1: (dev-mutex){..}, at: [c044d8e0] __driver_attach+0x60/0xa0 [ 15.355420] #2: (devtree_lock){..}, at: [c05e2888] of_get_next_child+0x20/0x4c [ 15.363731] irq event stamp: 5750 [ 15.367189] hardirqs last enabled at (5749): [c0719f14] _raw_spin_unlock_irqrestore+0x38/0x64 [ 15.376377] hardirqs last disabled at (5750): [c0719730] _raw_spin_lock_irqsave+0x24/0x6c [ 15.385104] softirqs last enabled at (5200): [c004b7c8] __do_softirq+0x318/0x710 [ 15.393111] softirqs last disabled at (5147): [c004bf1c] irq_exit+0xc4/0x138 [ 15.400668] CPU: 0 PID: 130 Comm: insmod Not tainted 4.1.0-rc2-7-g877542591d33-dirty #22 [ 15.409477] Hardware name: Generic AM33XX (Flattened Device Tree) [ 15.415837] Backtrace: [ 15.418403] [c00140a8] (dump_backtrace) from [c0014244] (show_stack+0x18/0x1c) [ 15.426306] r6:c08d04b0 r5:dd652000 r4: r3: [ 15.432257] [c001422c] (show_stack) from [c0711b44] (dump_stack+0x94/0xc8) [ 15.439810] [c0711ab0] (dump_stack) from [c0070768] (___might_sleep+0x18c/0x294) [ 15.447893] r5:0268 r4: [ 15.451643] [c00705dc] (___might_sleep) from [c00708d4] (__might_sleep+0x64/0xa4) [ 15.459816] r7:dd119280 r6: r5:0268 r4:c08d04b0 [ 15.465759] [c0070870] (__might_sleep) from [c0715934
[PATCH 2/5] OMAPDSS: HDMI5: Set valid sample order
From: Misael Lopez Cruz misael.lo...@ti.com As per TRM, HDMI_WP_AUDIO_CFG[2] LEFT_BEFORE = 0 is reserved, so it must always be set to 1 (the first sample is the left). Signed-off-by: Misael Lopez Cruz misael.lo...@ti.com Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/hdmi5_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c index a3cfe3d..7a80beb 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c @@ -870,6 +870,7 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; + audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; /* only LPCM atm */ audio_format.type = HDMI_AUDIO_TYPE_LPCM; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/5] OMAPDSS: HDMI4: Set correct CC for 8-channels layout
From: Misael Lopez Cruz misael.lo...@ti.com OMAP4 HDMI IP uses the 8-channel layout with 8-channel speaker allocation mask when transmitting more than two channels. But the channel count field (CC) of the Audio InfoFrame's DB1 is not updated for 8-channels. As per HDMI Compliance Test 7.31 Audio InfoFrame, CC = 7 is required for 8-channels CA masks (0x13 and 0x1F). Signed-off-by: Misael Lopez Cruz misael.lo...@ti.com Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/hdmi4_core.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c index 7eafea5..2b8bd22 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c @@ -795,7 +795,9 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, /* * the HDMI IP needs to enable four stereo channels when transmitting -* more than 2 audio channels +* more than 2 audio channels. Similarly, the channel count in the +* Audio InfoFrame has to match the sample_present bits (some channels +* are padded with zeroes) */ if (channel_count == 2) { audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; @@ -807,6 +809,7 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN | HDMI_AUDIO_I2S_SD3_EN; acore.layout = HDMI_AUDIO_LAYOUT_8CH; + audio-cea-db1_ct_cc = 7; } acore.en_spdif = false; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/5] ASoC: omap-hdmi-audio: Fix invalid combination of DM_INH and CA
From: Misael Lopez Cruz misael.lo...@ti.com DM_INH = 1 (stereo downmix prohibited) and CA = 0x00 (Channel Allocation: FR, FL) is an invalid combination according to the HDMI Compliance Test 7.31 Audio InfoFrame. Signed-off-by: Misael Lopez Cruz misael.lo...@ti.com Signed-off-by: Jyri Sarha jsa...@ti.com --- sound/soc/omap/omap-hdmi-audio.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index 8df303f..aeef25c 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -217,7 +217,11 @@ static int hdmi_dai_hw_params(struct snd_pcm_substream *substream, else cea-db4_ca = 0x13; - cea-db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED; + if (cea-db4_ca == 0x00) + cea-db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED; + else + cea-db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED; + /* the expression is trivial but makes clear what we are doing */ cea-db5_dminh_lsv |= (0 CEA861_AUDIO_INFOFRAME_DB5_LSV); -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/5] OMAPDSS: HDMI audio compliance fixes
I have rebased these patches from ti-linux-3.14.y on top of Linux 4.0.0. I tested them briefly on OMAP4 and OMAP5 in my environment, but I could not test any channel count beyond stereo. However, there were no conflicts in the rebase and each fix makes sense when looking at the chip TRM and the relevant HDMI specs. All the changes are really minor, but most of them apply to OMAPDSS side, so it is probably best to merge them trough there. Best regards, Jyri Misael Lopez Cruz (5): OMAPDSS: HDMI4: Set correct CC for 8-channels layout OMAPDSS: HDMI5: Set valid sample order OMAPDSS: HDMI5: Fix AUDICONF3 bitfield offsets ASoC: omap-hdmi-audio: Force channel allocation only for OMAP4 ASoC: omap-hdmi-audio: Fix invalid combination of DM_INH and CA drivers/video/fbdev/omap2/dss/hdmi4_core.c | 12 +++- drivers/video/fbdev/omap2/dss/hdmi5_core.c | 5 - sound/soc/omap/omap-hdmi-audio.c | 12 +++- 3 files changed, 22 insertions(+), 7 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/5] OMAPDSS: HDMI5: Fix AUDICONF3 bitfield offsets
From: Misael Lopez Cruz misael.lo...@ti.com Downmix inhibit in HDMI_CORE_FC_AUDICONF3 register is in bit 4 while CEA861_AUDIO_INFOFRAME_DB5_DM_INH sets bit 7. Signed-off-by: Misael Lopez Cruz misael.lo...@ti.com Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/hdmi5_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c index 7a80beb..c3286bd 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c @@ -790,7 +790,9 @@ static void hdmi5_core_audio_infoframe_cfg(struct hdmi_core_data *core, hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF1, info_aud-db2_sf_ss); hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF2, info_aud-db4_ca); - hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF3, info_aud-db5_dminh_lsv); + hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF3, + (info_aud-db5_dminh_lsv CEA861_AUDIO_INFOFRAME_DB5_DM_INH) 3 | + (info_aud-db5_dminh_lsv CEA861_AUDIO_INFOFRAME_DB5_LSV)); } int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/5] ASoC: omap-hdmi-audio: Force channel allocation only for OMAP4
From: Misael Lopez Cruz misael.lo...@ti.com There is a constraint in the OMAP4 HDMI IP that requires to use the 8-channel code when transmitting more than two channels. The constraint doesn't apply for OMAP5 so don't force the channel allocation in the sound driver as it can be done specifically for OMAP4 later in the hdmi4 core. Signed-off-by: Misael Lopez Cruz misael.lo...@ti.com Signed-off-by: Jyri Sarha jsa...@ti.com --- drivers/video/fbdev/omap2/dss/hdmi4_core.c | 7 +++ sound/soc/omap/omap-hdmi-audio.c | 6 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c index 2b8bd22..fa72e73 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c @@ -654,6 +654,13 @@ static void hdmi_core_audio_infoframe_cfg(struct hdmi_core_data *core, hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud-db3); sum += info_aud-db3; + /* +* The OMAP HDMI IP requires to use the 8-channel channel code when +* transmitting more than two channels. +*/ + if (info_aud-db4_ca != 0x00) + info_aud-db4_ca = 0x13; + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud-db4_ca); sum += info_aud-db4_ca; diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index 4775da4..8df303f 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -210,12 +210,10 @@ static int hdmi_dai_hw_params(struct snd_pcm_substream *substream, cea-db3 = 0; /* not used, all zeros */ - /* -* The OMAP HDMI IP requires to use the 8-channel channel code when -* transmitting more than two channels. -*/ if (params_channels(params) == 2) cea-db4_ca = 0x0; + else if (params_channels(params) == 6) + cea-db4_ca = 0xb; else cea-db4_ca = 0x13; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html