All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio
@ 2016-03-05  2:50 Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 01/15] drm: i915: fix inversion of definitions for LPE_PIPE_A/B Pierre-Louis Bossart
                   ` (16 more replies)
  0 siblings, 17 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja

When HDaudio is not enabled or fused-out, an alternate hardware
interface can be used to provide audio data to the display/HDMI
controller on Atom platforms.  The code to control this interface was
never submitted upstream but has been used extensively in Android
programs on Medfield, Clovertrail, Merrifield, Moorefield, Baytrail-T
and CherryTrail-T, as well as the Baytrail Compute Stick w/ Ubuntu.

Jesse Barnes and others at Intel suggested the code be posted on the
intex-gfx mailing lists as an RFC for graphics and audio folks to start
the conversation on how to support this interface in the mainline
kernel. The initial patches used for the Baytrail Compute Stick were
split to make them more readable, with changes to drm/i915 and sound/
clearly separated out. A basic cleanup to make checkpatch happy was
done but the code needs further updates (we know...). The code was
rebased from 3.16 to drm/intel-nightly-build and tested on a Baytrail
Compute Stick. CherryTrail changes will be added shortly.

The main feedback expected in this RFC is on the interaction between
audio and display driver, specifically if we can wrap the interface
control with the component framework already used between i915 and
HDaudio. A short documentation was added to help explain how the
hardware works.

The first two patches fix issues that were identified during the
rebase process and could be merged without waiting for the interface
to be reworked.

Comments welcome!

David Henningsson (2):
  hdmi_audio: Improve position reporting
  hdmi_audio: Fixup some monitor

Pierre-Louis Bossart (10):
  drm: i915: fix inversion of definitions for LPE_PIPE_A/B
  drm: i915: remove intel_hdmi variable declaration
  Doc: sound: add description of Atom HDMI audio interface
  drm/i915: Add headers for non-HDAudio HDMI interface
  drm/i915: changes for non-HDAudio HDMI interface
  drm/i915: power-related changes non-HDAudio HDMI interface
  drm/i915: Add API code for non-HDAudio HDMI interface
  drm/i915: enable non-HDAudio HDMI interface Makefile
  ALSA: Intel: Atom: add Atom non-HDAudio HDMI interface
  add dependency on PM_RUNTIME

Toyo Abe (3):
  hdmi_audio: Fix mishandling of AUD_HDMI_STATUS_v2 register.
  i915: Enable LPE_PIPEA_Interrupt.
  i915: Fix typo in comment.

 Documentation/sound/alsa/Atom-hdmi-audio.txt |  241 +++
 drivers/gpu/drm/i915/Makefile                |    4 +-
 drivers/gpu/drm/i915/hdmi_audio_if.c         |  410 ++++++
 drivers/gpu/drm/i915/hdmi_audio_if.h         |  122 ++
 drivers/gpu/drm/i915/i915_drv.h              |   31 +
 drivers/gpu/drm/i915/i915_irq.c              |   87 ++
 drivers/gpu/drm/i915/i915_reg.h              |   11 +-
 drivers/gpu/drm/i915/i915_rpm.c              |  476 ++++++
 drivers/gpu/drm/i915/intel_display.c         |    8 +
 drivers/gpu/drm/i915/intel_drv.h             |   11 +
 drivers/gpu/drm/i915/intel_hdmi.c            |  185 ++-
 drivers/gpu/drm/i915/intel_pm.c              |   53 +
 sound/Kconfig                                |    9 +
 sound/Makefile                               |    1 +
 sound/hdmi_audio/Makefile                    |    9 +
 sound/hdmi_audio/intel_mid_hdmi_audio.c      | 2039 ++++++++++++++++++++++++++
 sound/hdmi_audio/intel_mid_hdmi_audio.h      |  740 ++++++++++
 sound/hdmi_audio/intel_mid_hdmi_audio_if.c   |  514 +++++++
 18 files changed, 4946 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/sound/alsa/Atom-hdmi-audio.txt
 create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.c
 create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.h
 create mode 100644 drivers/gpu/drm/i915/i915_rpm.c
 create mode 100644 sound/hdmi_audio/Makefile
 create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio.c
 create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio.h
 create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio_if.c

-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [RFC 01/15] drm: i915: fix inversion of definitions for LPE_PIPE_A/B
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05 13:27   ` Ville Syrjälä
  2016-03-05  2:50 ` [RFC 02/15] drm: i915: remove intel_hdmi variable declaration Pierre-Louis Bossart
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja

Definitions for I915_LPE_PIPE_A_INTERRUPT and I915_LPE_PIPE_B_INTERRUPT
are inverted.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 71abf57..228b22f 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2029,8 +2029,8 @@ enum skl_disp_power_wells {
 
 #define I915_PM_INTERRUPT				(1<<31)
 #define I915_ISP_INTERRUPT				(1<<22)
-#define I915_LPE_PIPE_B_INTERRUPT			(1<<21)
-#define I915_LPE_PIPE_A_INTERRUPT			(1<<20)
+#define I915_LPE_PIPE_A_INTERRUPT			(1<<21)
+#define I915_LPE_PIPE_B_INTERRUPT			(1<<20)
 #define I915_MIPIC_INTERRUPT				(1<<19)
 #define I915_MIPIA_INTERRUPT				(1<<18)
 #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT		(1<<18)
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 02/15] drm: i915: remove intel_hdmi variable declaration
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 01/15] drm: i915: fix inversion of definitions for LPE_PIPE_A/B Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-10 17:34   ` Ville Syrjälä
  2016-03-05  2:50 ` [RFC 03/15] Doc: sound: add description of Atom HDMI audio interface Pierre-Louis Bossart
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja

'intel_hdmi' variable is redeclared, use same variable declared in
function scope.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_hdmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index d8060e6..1beb155 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1418,7 +1418,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
 	intel_hdmi_unset_edid(connector);
 
 	if (intel_hdmi_set_edid(connector, live_status)) {
-		struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+		intel_hdmi = intel_attached_hdmi(connector);
 
 		hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
 		status = connector_status_connected;
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 03/15] Doc: sound: add description of Atom HDMI audio interface
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 01/15] drm: i915: fix inversion of definitions for LPE_PIPE_A/B Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 02/15] drm: i915: remove intel_hdmi variable declaration Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface Pierre-Louis Bossart
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja

Used when HDaudio is not enabled

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 Documentation/sound/alsa/Atom-hdmi-audio.txt | 241 +++++++++++++++++++++++++++
 1 file changed, 241 insertions(+)
 create mode 100644 Documentation/sound/alsa/Atom-hdmi-audio.txt

diff --git a/Documentation/sound/alsa/Atom-hdmi-audio.txt b/Documentation/sound/alsa/Atom-hdmi-audio.txt
new file mode 100644
index 0000000..bcc485c
--- /dev/null
+++ b/Documentation/sound/alsa/Atom-hdmi-audio.txt
@@ -0,0 +1,241 @@
+This short blurb describes the support for HDMI audio on Atom
+platforms with the DMA/register-based interface (non HDAudio).
+
+1.Overview
+
+The HDMI transmitter operates in an image-oriented fashion. The major
+part of each frame is used by pixel data; non-pixel data is inserted
+in the data islands in the vertical and horizontal blanking
+spaces. Null packets are transmitted to fill the gaps when no data is
+available.
+
+Non-pixel data is abstracted though the concept of ‘Data Island’ which
+includes packet types such as
+
+- Audio Clock Regeneration. This packet conveys the information needed
+for the receiver to reconstruct a valid audio clock; it is sent every
+other frame.
+
+- Audio data (Audio Sample Packet, One Bit Audio Sample Packet, DST
+Audio Packet, HBR Audio packet)
+
+- Audio InfoFrame. This packets conveys configuration information on
+formats, sample rate, channel allocation, etc.
+
+2 Hardware description
+
+Although the HDMI block reuses many elements from the ‘normal’
+HDAudio-based design, the insertion of audio and configuration data
+into the HDMI frame is done differently, spefically the data is
+provided to the display controller with a DMA (instead of a serial
+link) and the control interface is done through register access
+(instead of HDAudio verbs). The interaction between audio and display
+driver remains similar, e.g. to handle hot-plug or EDID information.
+
+2.1 Data flow
+
+The audio rate is derived from the video frame rate and software must
+program the values of N/CTS registers. In some cases the audio clock is
+approximated with an offset that remains within the acceptable bounds
+of the standard. Based on N and CTS values and the actual video clock,
+the transmitter determines how many audio sample packets need to be
+inserted per frame.  These packets are read from memory using a DMA
+interface and inserted in the data island. In case the display format
+or resolution changes the values for N and CTS need to be adjusted.
+
+2.2 Data formats
+
+The supported audio frequencies are 32, 44.1, 48, 88.2, 96, 176.4 and
+192 kHz. 64 kHz is not supported in the HDMI standard.
+
+Two to eight channels can be transmitted. Odd number of channels will
+required the insertion of an additional dummy channel. This insertion
+is handled by software.
+
+Each transmitted PCM word is represented on 28 bits as described in
+the IEC60958 standard. Each sample conveys 24 bits of audio data,
+along with 4 configuration bits.
+
+Unsupported features:
+One bit audio sample packet
+DST audio packet
+High Bit Rate packets
+
+2.3 DMA operation
+
+The HDMI audio DMA controller handles a single context. It supports a
+four-entry descriptor register for source buffers and handles a single
+destination. The address and size of the source buffers can be
+programmed in the descriptors.
+
+The DMA controller transfers bursts of 16 32-bit words from memory (64
+bytes). These bursts are initiated when its FIFO level falls below a
+programmable watermark threshold. It is required that the buffers are
+aligned on a 64-byte boundary and are allocated from contiguous
+physical memory. They also need to be multiples of 64 bytes.
+
+The DMA controller enables the addition of buffers in descriptor
+registers during playback and issues an interrupt when a Transfer
+Complete is reached. When it has finished playing a buffer, it will
+move to the next descriptor. If no valid descriptors are found after a
+complete loop on the 4 descriptors, the hardware will go to a wait
+mode and report an under-run condition. As soon as the driver enables
+a new transfer the hardware will wake up. Note: it is not possible to
+program the DMA to fetch data completely autonomously without
+interrupts, after the 4 descriptors are used they need to be
+re-enabled by software.
+
+Should an underflow occur, the hardware can raise an underflow
+interrupt, will not transmit any audio packets and will insert null
+packets instead. On the software side, the audio device should be
+closed and the application restarted from a known position.
+
+2.4 Data representation in RAM
+
+Linear or compressed data are represented in the 24 least significant
+bits of a 32-bit word. No overlap between words is allowed. The
+hardware assumes that the 32-bits are written in little-endian
+format. Software needs to take care of format conversions when playing
+16-bit PCM (shift-left by eight bits)
+
+Layout 0 is used for stereo data, with left and right channels
+interleaved in memory. This layout is also used when transmitting
+compressed data over HDMI in IEC format
+
+For multichannel, Layout 1 is used. The order of each channel is
+defined as per CEA-861D. Since this order does not correspond to the
+native order of any known decoder, the hardware provides a 3-bit
+register for each channel. The channel position is modulo-added to the
+register. This provides a direct means to change the channel
+order. Note that the channel swap configuration needs to be aligned
+with the CA code transmitted to the receiver. Alternatively the
+channel swaps can be done in software.
+
+Only even number of channels will be transmitted. The software will
+interleave a dummy channel if needed; the CA codec transmitted in
+InfoFrames will only correspond to even number of channels.
+
+PCM Multichannel files will be stored in memory using the interleaved
+mode (L0, R0, C0, LFE0, L1, R1, C1, LFE1). In Layout 1, the software
+will need to generate 2, 4, 6 or 8 channels. By the same token, stereo
+files will always provide a multiple of 4 samples to allow for the
+same simplification for Layout 0.
+
+3. Configuration bits
+
+The U bit is not handled, as there is no real way to align the user
+bits with the audio data.
+
+Only the first 40 bits of the channel status are meaningful. The HDMI
+interface provides a two-word register which will be written with the
+relevant values by software. For each block, the first 40 bits are
+inserted one at a time in each frame, the remaining 152 bits are
+zeroed.
+
+Note that the same C bit value is transmitted for each subframe of
+each sub-packet. In theory, each channel could have independent C bits
+and some of the information transmitted to the receiver may be
+incorrect (channel number). To avoid any ambiguity for the receiver,
+the source number and channel number will be set by the software to
+zero, which is specified as ‘Do not take into account’ in IEC60958-3
+
+For multichannel PCM transmitted using Layout1, the same C bit is
+inserted in all valid subpackets. The same simplification is made by
+zero-ing out source number and channel number by software.  The V bit
+is defined by a register as well. By default all samples are marked as
+valid. The option of transmitting invalid samples is only meaningful
+is there is a change in the type of data transmitted, or a change of
+sampling rate. This is unlikely to occur as the audio transfers would
+be stopped and restarted by the HDMI audio device driver.
+
+The parity bit is inserted by the hardware on-the-fly. The software is
+not involved at all.
+
+4. Preambles
+
+Note that HDMI does not encode the 4-bit preamble, which instead is
+replaced with a “B” bit (start-of-block) in each Audio Sample
+packet. This preamble is added on-the-fly by the hardware.  The
+start-of-block bit is set for the first subpacket transmitted after
+AUD_ENABLE is set. This B bit should always coincide with the start of
+a DMA transfer.
+
+5. Programming model
+
+HDMI audio open:
+A. reset the audio function in AUD_HDMI_STATUS register
+B. Get the audio and video latencies, compute the relevant delay from
+EDID information
+C. write AUD_CONFIG register, except AudioEnable (sets User, Validity,
+sample flat, block begin, number of channels, format, layout)
+D. program ChannelStatus bits
+E. unmask the relevant interrupts in PIPEBSTAT register
+F. get frame rate from video driver
+G. program N, CTS
+H. program the FIFO threshold in AUD_BUF_CONFIG register
+I. program the delay for lip-sync in AUD_BUF_CONFIG register
+J. program channel swaps if need be
+K. write Audio Infoframe in local memory (all the 28 bytes need to be
+written, zero-out reserved bits/bytes)
+L. signal location of Infoframe in AUD_CNTL_ST (how is frequency
+transmitted)
+
+HDMI audio start:
+
+A. Inset a set of buffers in the circular list and mark them as
+valid. Set interrupt flag on all or some buffers, choice left to the
+user.
+B. Enable the audio, which starts the DMA requests to fill the audio
+FIFO immediately. The audio packets will actually be inserted in the
+next video frame. There is no transmission before the next video
+frame.
+
+HDMI audio pause: audio disable (continues transmitting packets until
+the current video frame is complete)
+
+HDMI audio resume: audio enable (resumes at the next frame, pointers
+kept, nothing lost)
+
+HDMI audio stop:
+A. disable audio
+B. reset audio module (Function Reset bit in HDMI audio status)
+
+The HDMI audio driver will need to communicate with the display
+driver, so that the latter provides the following information:
+- Display frame rate
+- EDID
+- HDCP failure
+
+The audio driver can keep track of playback progress by setting the
+interrupt flag for each of the 4 buffers. Alternatively, for a finer
+control and lower latency, the driver can read the buffer
+AUD_BUF_X_LENGTH register, which is initialized by software with the
+number of bytes to be transmitted and updated by hardware during DMA
+reads.
+
+6. Known issues:
+
+HDMI receivers tend to ignore control (‘C’) bits and detect the
+content type by parsing incoming data. As a result, receivers with
+support for DolbyDigital, DTS, etc, tend to take around one or two
+seconds to reliably lock on a set of sync words and avoid false
+detections. When content is played on such receivers, the first
+seconds of audio will not be heard.
+
+The only solution consists in playing dummy silent data as soon as the
+HDMI cable is connected. This solution assumes that the system mixer
+always uses the same configuration and does not change
+sample-rates. In Baytrail and Cherrytrail the HDMI controller can keep
+the audio link active by pushing zeroes as soon as DMA transfers are
+complete.
+
+The hardware also provides a ‘stop’ bit to avoid waiting for the end
+of a period elapsed to stop a playback.
+
+6. Differences with digital ouputs with HDaudio
+
+The channel status bits are programmed separately through a separate
+register. Only 40 bits out of the 192 can be programmed
+the parity is computed in hardware
+the validity bit is inserted by hardware.
+The ‘hdmi’ alsa-lib plugin cannot be used with this interface.
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (2 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 03/15] Doc: sound: add description of Atom HDMI audio interface Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-10 17:54   ` Ville Syrjälä
  2016-03-10 18:00   ` Ville Syrjälä
  2016-03-05  2:50 ` [RFC 05/15] drm/i915: changes " Pierre-Louis Bossart
                   ` (12 subsequent siblings)
  16 siblings, 2 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, David Henningsson

Add header files for interface available on Baytrail and CherryTrail

Initial code was downloaded from https://github.com/01org/baytrailaudio/
...and had the changes to .config stripped and the revert on sound/init.c
done by David Henningson

Clean-up, port to 4.4 and intel-drm by Pierre Bossart

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/hdmi_audio_if.h | 122 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_drv.h      |  31 +++++++++
 drivers/gpu/drm/i915/i915_reg.h      |   7 ++
 drivers/gpu/drm/i915/intel_drv.h     |  11 ++++
 4 files changed, 171 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.h

diff --git a/drivers/gpu/drm/i915/hdmi_audio_if.h b/drivers/gpu/drm/i915/hdmi_audio_if.h
new file mode 100644
index 0000000..f968028
--- /dev/null
+++ b/drivers/gpu/drm/i915/hdmi_audio_if.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Authors:
+ *	jim liu <jim.liu@intel.com>
+ *	Uma Shankar <uma.shankar@intel.com>
+ */
+
+
+#ifndef __HDMI_AUDIO_IF_H
+#define __HDMI_AUDIO_IF_H
+
+#include <linux/types.h>
+#include <drm/drmP.h>
+
+/* HDMI AUDIO INTERRUPT TYPE */
+#define HDMI_AUDIO_UNDERRUN     (1UL<<0)
+#define HDMI_AUDIO_BUFFER_DONE  (1UL<<1)
+
+/* the monitor type HDMI or DVI */
+#define MONITOR_TYPE_HDMI 1
+#define MONITOR_TYPE_DVI  2
+
+extern int i915_hdmi_state;
+extern int i915_notify_had;
+
+enum had_caps_list {
+	HAD_GET_ELD = 1,
+	HAD_GET_SAMPLING_FREQ,
+	HAD_GET_DISPLAY_RATE,
+	HAD_GET_HDCP_STATUS,
+	HAD_GET_AUDIO_STATUS,
+	HAD_SET_ENABLE_AUDIO,
+	HAD_SET_DISABLE_AUDIO,
+	HAD_SET_ENABLE_AUDIO_INT,
+	HAD_SET_DISABLE_AUDIO_INT,
+	OTHERS_TBD,
+};
+
+enum had_event_type {
+	HAD_EVENT_HOT_PLUG = 1,
+	HAD_EVENT_HOT_UNPLUG,
+	HAD_EVENT_MODE_CHANGING,
+	HAD_EVENT_PM_CHANGING,
+	HAD_EVENT_AUDIO_BUFFER_DONE,
+	HAD_EVENT_AUDIO_BUFFER_UNDERRUN,
+	HAD_EVENT_QUERY_IS_AUDIO_BUSY,
+	HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED,
+};
+
+/*
+ * HDMI Display Controller Audio Interface
+ *
+ */
+typedef int (*had_event_call_back) (enum had_event_type event_type,
+		void *ctxt_info);
+
+struct hdmi_audio_registers_ops {
+	int (*hdmi_audio_read_register)(uint32_t reg_addr, uint32_t *data);
+	int (*hdmi_audio_write_register)(uint32_t reg_addr, uint32_t data);
+	int (*hdmi_audio_read_modify)(uint32_t reg_addr, uint32_t data,
+			uint32_t mask);
+};
+
+struct hdmi_audio_query_set_ops {
+	int (*hdmi_audio_get_caps)(enum had_caps_list query_element,
+			void *capabilties);
+	int (*hdmi_audio_set_caps)(enum had_caps_list set_element,
+			void *capabilties);
+};
+
+typedef struct hdmi_audio_event {
+	int type;
+} hdmi_audio_event_t;
+
+struct snd_intel_had_interface {
+	const char *name;
+	int (*query)(void *had_data, hdmi_audio_event_t event);
+	int (*suspend)(void *had_data, hdmi_audio_event_t event);
+	int (*resume)(void *had_data);
+};
+
+struct hdmi_audio_priv {
+	struct drm_device *dev;
+	u32 hdmib_reg;
+
+	bool is_hdcp_supported;
+	bool hdmi_hpd_connected;
+	int monitor_type;
+	void *context;
+};
+
+extern void i915_hdmi_audio_init(struct hdmi_audio_priv *p_hdmi_priv);
+
+extern bool mid_hdmi_audio_is_busy(struct drm_device *dev);
+extern bool mid_hdmi_audio_suspend(struct drm_device *dev);
+extern void mid_hdmi_audio_resume(struct drm_device *dev);
+extern void mid_hdmi_audio_signal_event(struct drm_device *dev,
+		enum had_event_type event);
+
+/* Added for HDMI Audio */
+extern void hdmi_get_eld(uint8_t *eld);
+extern int i915_enable_hdmi_audio_int(struct drm_device *dev);
+extern int i915_disable_hdmi_audio_int(struct drm_device *dev);
+extern int mid_hdmi_audio_setup(
+	had_event_call_back audio_callbacks,
+	struct hdmi_audio_registers_ops *reg_ops,
+	struct hdmi_audio_query_set_ops *query_ops);
+extern int mid_hdmi_audio_register(
+	struct snd_intel_had_interface *driver,
+	void *had_data);
+
+#endif /* __HDMI_AUDIO_IF_H */
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2cb0a41..5dceb5b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -53,6 +53,7 @@
 #include <linux/kref.h>
 #include <linux/pm_qos.h>
 #include "intel_guc.h"
+#include "hdmi_audio_if.h"
 
 /* General customization:
  */
@@ -1196,6 +1197,18 @@ struct intel_gen6_power_mgmt {
 	struct mutex hw_lock;
 };
 
+/* Runtime power management related */
+struct intel_gen7_rpm {
+	/* To track (num of get calls - num of put calls)
+	 * made by procfs
+	 */
+	atomic_t procfs_count;
+	/* To make sure ring get/put are in pair */
+	bool ring_active;
+	struct proc_dir_entry *i915_proc_dir;
+	struct proc_dir_entry *i915_proc_file;
+};
+
 /* defined intel_pm.c */
 extern spinlock_t mchdev_lock;
 
@@ -2018,6 +2031,19 @@ struct drm_i915_private {
 
 	struct intel_encoder *dig_port_map[I915_MAX_PORTS];
 
+	/* Added for HDMI Audio */
+	had_event_call_back had_event_callbacks;
+	struct snd_intel_had_interface *had_interface;
+	void *had_pvt_data;
+	int tmds_clock_speed;
+	int hdmi_audio_interrupt_mask;
+	struct work_struct hdmi_audio_wq;
+
+	u32 hotplug_status;
+
+	/* Runtime power management related */
+	struct intel_gen7_rpm rpm;
+
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
@@ -3537,6 +3563,11 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
 	} while (upper != old_upper && loop++ < 2);			\
 	(u64)upper << 32 | lower; })
 
+int i915_rpm_get_disp(struct drm_device *dev);
+int i915_rpm_put_disp(struct drm_device *dev);
+
+bool i915_is_device_active(struct drm_device *dev);
+
 #define POSTING_READ(reg)	(void)I915_READ_NOTRACE(reg)
 #define POSTING_READ16(reg)	(void)I915_READ16_NOTRACE(reg)
 
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 228b22f..370371c 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2062,7 +2062,12 @@ enum skl_disp_power_wells {
 #define I915_WINVALID_INTERRUPT				(1<<1)
 #define I915_USER_INTERRUPT				(1<<1)
 #define I915_ASLE_INTERRUPT				(1<<0)
+#define I915_LPE_AUDIO_HDMI_STATUS_A	_MMIO(dev_priv->info.display_mmio_offset + 0x65064)
+#define I915_LPE_AUDIO_HDMI_STATUS_B	_MMIO(dev_priv->info.display_mmio_offset + 0x65864)
+#define I915_HDMI_AUDIO_UNDERRUN			(1UL<<31)
+#define I915_HDMI_AUDIO_BUFFER_DONE			(1UL<<29)
 #define I915_BSD_USER_INTERRUPT				(1<<25)
+#define I915_HDMI_AUDIO_UNDERRUN_ENABLE			(1UL<<15)
 
 #define GEN6_BSD_RNCID			_MMIO(0x12198)
 
@@ -3364,6 +3369,7 @@ enum skl_disp_power_wells {
 #define _GEN3_SDVOC	0x61160
 #define GEN3_SDVOB	_MMIO(_GEN3_SDVOB)
 #define GEN3_SDVOC	_MMIO(_GEN3_SDVOC)
+#define HDMIB	(dev_priv->info.display_mmio_offset + 0x61140)
 #define GEN4_HDMIB	GEN3_SDVOB
 #define GEN4_HDMIC	GEN3_SDVOC
 #define VLV_HDMIB	_MMIO(VLV_DISPLAY_BASE + 0x61140)
@@ -3373,6 +3379,7 @@ enum skl_disp_power_wells {
 #define PCH_HDMIB	PCH_SDVOB
 #define PCH_HDMIC	_MMIO(0xe1150)
 #define PCH_HDMID	_MMIO(0xe1160)
+#define PORT_ENABLE	(1 << 31)
 
 #define PORT_DFT_I9XX				_MMIO(0x61150)
 #define   DC_BALANCE_RESET			(1 << 25)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cb413e2..adfd27c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -724,6 +724,14 @@ struct cxsr_latency {
 #define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base)
 #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
 
+/* HDMI bits are shared with the DP bits */
+#define   HDMIB_HOTPLUG_LIVE_STATUS             (1 << 29)
+#define   HDMIC_HOTPLUG_LIVE_STATUS             (1 << 28)
+#define   HDMID_HOTPLUG_LIVE_STATUS             (1 << 27)
+#define   HDMI_LIVE_STATUS_BASE			30
+#define   HDMI_LIVE_STATUS_DELAY_STEP		10
+#define   HDMI_EDID_RETRY_COUNT			3
+
 struct intel_hdmi {
 	i915_reg_t hdmi_reg;
 	int ddc_bus;
@@ -735,6 +743,9 @@ struct intel_hdmi {
 	bool rgb_quant_range_selectable;
 	enum hdmi_picture_aspect aspect_ratio;
 	struct intel_connector *attached_connector;
+	struct edid *edid;
+	uint32_t edid_mode_count;
+
 	void (*write_infoframe)(struct drm_encoder *encoder,
 				enum hdmi_infoframe_type type,
 				const void *frame, ssize_t len);
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 05/15] drm/i915: changes for non-HDAudio HDMI interface
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (3 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 06/15] drm/i915: power-related changes " Pierre-Louis Bossart
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, David Henningsson

Changes to existing code for interface available on Baytrail and
CherryTrail

This driver was downloaded from https://github.com/01org/baytrailaudio/

...and had the changes to .config stripped and the revert on sound/init.c

Cleanup, port to 4.4 and intel-drm by Pierre Bossart

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_irq.c      |  81 ++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c |   8 ++
 drivers/gpu/drm/i915/intel_hdmi.c    | 183 ++++++++++++++++++++++++++++++++++-
 3 files changed, 271 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d1a46ef..556fa80 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -603,6 +603,31 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 	__i915_disable_pipestat(dev_priv, pipe, enable_mask, status_mask);
 }
 
+/* Added for HDMI AUDIO */
+void
+i915_enable_lpe_pipestat(struct drm_i915_private *dev_priv, int pipe)
+{
+	u32 mask;
+
+	mask = dev_priv->hdmi_audio_interrupt_mask;
+	mask |= I915_HDMI_AUDIO_UNDERRUN | I915_HDMI_AUDIO_BUFFER_DONE;
+	/* Enable the interrupt, clear any pending status */
+	I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_A, mask);
+	POSTING_READ(I915_LPE_AUDIO_HDMI_STATUS_A);
+}
+
+void
+i915_disable_lpe_pipestat(struct drm_i915_private *dev_priv, int pipe)
+{
+	u32 mask;
+
+	mask = dev_priv->hdmi_audio_interrupt_mask;
+	mask |= I915_HDMI_AUDIO_UNDERRUN | I915_HDMI_AUDIO_BUFFER_DONE;
+	/* Disable the interrupt, clear any pending status */
+	I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_A, mask);
+	POSTING_READ(I915_LPE_AUDIO_HDMI_STATUS_A);
+}
+
 /**
  * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
  * @dev: drm device
@@ -1649,6 +1674,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pipe_stats[I915_MAX_PIPES] = { };
 	int pipe;
+	int lpe_stream;
 
 	spin_lock(&dev_priv->irq_lock);
 
@@ -1719,6 +1745,24 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
 			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
 	}
 
+	if (iir & I915_LPE_PIPE_A_INTERRUPT) {
+		lpe_stream = I915_READ(I915_LPE_AUDIO_HDMI_STATUS_A);
+		if (lpe_stream & I915_HDMI_AUDIO_UNDERRUN) {
+			I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_A,
+					lpe_stream);
+			mid_hdmi_audio_signal_event(dev,
+					HAD_EVENT_AUDIO_BUFFER_UNDERRUN);
+		}
+
+		lpe_stream = I915_READ(I915_LPE_AUDIO_HDMI_STATUS_A);
+		if (lpe_stream & I915_HDMI_AUDIO_BUFFER_DONE) {
+			I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_A,
+					lpe_stream);
+			mid_hdmi_audio_signal_event(dev,
+				HAD_EVENT_AUDIO_BUFFER_DONE);
+		}
+	}
+
 	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
 		gmbus_irq_handler(dev);
 }
@@ -2804,6 +2848,43 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
+/* Added fo HDMI AUdio */
+int i915_enable_hdmi_audio_int(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+	unsigned long irqflags;
+	u32 imr;
+	int pipe = 1;
+
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+	imr = I915_READ(VLV_IMR);
+	/* Audio is on Stream A */
+	imr &= ~I915_LPE_PIPE_A_INTERRUPT;
+	I915_WRITE(VLV_IMR, imr);
+	i915_enable_lpe_pipestat(dev_priv, pipe);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+	return 0;
+}
+
+/* Added for HDMI Audio */
+int i915_disable_hdmi_audio_int(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+	unsigned long irqflags;
+	u32 imr;
+	int pipe = 1;
+
+	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+	imr = I915_READ(VLV_IMR);
+	imr |= I915_LPE_PIPE_A_INTERRUPT;
+	I915_WRITE(VLV_IMR, imr);
+	i915_disable_lpe_pipestat(dev_priv, pipe);
+	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+	return 0;
+}
+
 static bool
 ring_idle(struct intel_engine_cs *ring, u32 seqno)
 {
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 44fcff0..5831af4 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8108,6 +8108,14 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
 				  num_connectors);
 	}
 
+	/* Added for HDMI Audio */
+	if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc,
+		INTEL_OUTPUT_HDMI)) {
+		dev_priv->tmds_clock_speed = crtc_state->port_clock;
+		mid_hdmi_audio_signal_event(dev_priv->dev,
+			HAD_EVENT_MODE_CHANGING);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 1beb155..8b6c31a 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1391,6 +1391,124 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force)
 	return connected;
 }
 
+static bool vlv_hdmi_live_status(struct drm_device *dev,
+			struct intel_hdmi *intel_hdmi)
+{
+	uint32_t bit;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_digital_port *intel_dig_port =
+					hdmi_to_dig_port(intel_hdmi);
+
+	DRM_DEBUG_KMS("Reading Live status");
+	switch (intel_dig_port->port) {
+	case PORT_B:
+		bit = HDMIB_HOTPLUG_LIVE_STATUS;
+		break;
+	case PORT_C:
+		bit = HDMIC_HOTPLUG_LIVE_STATUS;
+		break;
+	case PORT_D:
+		bit = HDMID_HOTPLUG_LIVE_STATUS;
+		break;
+	default:
+		bit = 0;
+	}
+
+	/* Return results in trems of connector */
+	return I915_READ(PORT_HOTPLUG_STAT) & bit;
+}
+
+
+/*
+ * intel_hdmi_live_status: detect live status of HDMI
+ * if device is gen 6 and above, read the live status reg
+ * else, do not block the detection, return true
+ */
+static bool intel_hdmi_live_status(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+
+	if (INTEL_INFO(dev)->gen > 6) {
+		/* Todo: Implement for other Gen 6+ archs*/
+		if (IS_VALLEYVIEW(dev))
+			return vlv_hdmi_live_status(dev, intel_hdmi);
+	}
+
+	return true;
+}
+
+/* Read DDC and get EDID */
+struct edid *intel_hdmi_get_edid(struct drm_connector *connector, bool force)
+{
+	bool current_state = false;
+	bool saved_state = false;
+
+	struct edid *new_edid = NULL;
+	struct i2c_adapter *adapter = NULL;
+	struct drm_device *dev = connector->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+	u32 hotplug_status = dev_priv->hotplug_status;
+	enum port hdmi_port = hdmi_to_dig_port(intel_hdmi)->port;
+	unsigned char retry = HDMI_EDID_RETRY_COUNT;
+
+	if (!intel_hdmi) {
+		DRM_ERROR("Invalid input to get hdmi\n");
+		return NULL;
+	}
+
+	/* Get the saved status from top half */
+	saved_state = hotplug_status & (1 << (HDMI_LIVE_STATUS_BASE - hdmi_port));
+
+	/*
+	 * Few monitors are slow to respond on EDID and live status,
+	 * so read live status multiple times within a max delay of 30ms
+	 */
+	do {
+		mdelay(HDMI_LIVE_STATUS_DELAY_STEP);
+		current_state = intel_hdmi_live_status(connector);
+		if (current_state)
+			break;
+	} while (retry--);
+
+	/* Compare current status, and saved status in top half */
+	if (current_state != saved_state)
+		DRM_DEBUG_DRIVER("Warning: Saved HDMI status != current status");
+
+	/* Read EDID if live status or saved status is up, or we are forced */
+	if (current_state || saved_state || force) {
+
+		adapter = intel_gmbus_get_adapter(dev_priv,
+					intel_hdmi->ddc_bus);
+		if (!adapter) {
+			DRM_ERROR("Get_hdmi cant get adapter\n");
+			return NULL;
+		}
+
+		/*
+		 * Few monitors issue EDID after some delay, so give them
+		 * some chances, but within 30ms
+		 */
+		retry = 3;
+READ_EDID:
+		new_edid = drm_get_edid(connector, adapter);
+		if (!new_edid) {
+			if (retry--) {
+				mdelay(HDMI_LIVE_STATUS_DELAY_STEP);
+				goto READ_EDID;
+			}
+
+			DRM_ERROR("Get_hdmi cant read edid\n");
+			return NULL;
+		}
+
+		DRM_DEBUG_KMS("Live status up, got EDID");
+	}
+
+	return new_edid;
+}
+
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
@@ -1399,6 +1517,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
 	bool live_status = false;
 	unsigned int try;
+	bool inform_audio = false;
+	struct drm_device *dev = connector->dev;
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
@@ -1427,6 +1547,26 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
 
 	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
 
+	/* Need to inform audio about the event */
+	intel_hdmi = intel_attached_hdmi(connector);
+	if (intel_hdmi->has_audio)
+		inform_audio = true;
+
+	if (status == connector_status_connected) {
+		if (intel_hdmi->has_audio)
+			i915_notify_had = 1;
+	} else {
+		/* Send a disconnect event to audio */
+		if (inform_audio) {
+			DRM_DEBUG_DRIVER("Sending event to audio");
+			mid_hdmi_audio_signal_event(dev_priv->dev,
+			HAD_EVENT_HOT_UNPLUG);
+		}
+	}
+
+	if (IS_VALLEYVIEW(dev))
+		i915_hdmi_state = status;
+
 	return status;
 }
 
@@ -1450,12 +1590,22 @@ intel_hdmi_force(struct drm_connector *connector)
 static int intel_hdmi_get_modes(struct drm_connector *connector)
 {
 	struct edid *edid;
+	int ret;
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
 	edid = to_intel_connector(connector)->detect_edid;
 	if (edid == NULL)
 		return 0;
 
-	return intel_connector_update_modes(connector, edid);
+	ret = intel_connector_update_modes(connector, edid);
+
+	if (i915_notify_had) {
+		mid_hdmi_audio_signal_event(dev_priv->dev,
+			HAD_EVENT_HOT_PLUG);
+		i915_notify_had = 0;
+	}
+
+	return ret;
 }
 
 static bool
@@ -2159,6 +2309,20 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
 		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
 	}
+
+	i915_notify_had = 1;
+}
+
+/* Added for HDMI Audio */
+void i915_had_wq(struct work_struct *work)
+{
+	struct drm_i915_private *dev_priv = container_of(work,
+		struct drm_i915_private, hdmi_audio_wq);
+
+	if (i915_hdmi_state == connector_status_connected) {
+		mid_hdmi_audio_signal_event(dev_priv->dev,
+			HAD_EVENT_HOT_PLUG);
+	}
 }
 
 void intel_hdmi_init(struct drm_device *dev,
@@ -2168,6 +2332,8 @@ void intel_hdmi_init(struct drm_device *dev,
 	struct intel_digital_port *intel_dig_port;
 	struct intel_encoder *intel_encoder;
 	struct intel_connector *intel_connector;
+	/* Added for HDMI Audio */
+	struct hdmi_audio_priv *hdmi_priv;
 
 	intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
 	if (!intel_dig_port)
@@ -2239,4 +2405,19 @@ void intel_hdmi_init(struct drm_device *dev,
 	intel_dig_port->max_lanes = 4;
 
 	intel_hdmi_init_connector(intel_dig_port, intel_connector);
+
+	/* Added for HDMI Audio */
+	/* HDMI private data */
+	INIT_WORK(&dev_priv->hdmi_audio_wq, i915_had_wq);
+	hdmi_priv = kzalloc(sizeof(struct hdmi_audio_priv), GFP_KERNEL);
+	if (!hdmi_priv) {
+		pr_err("failed to allocate memory");
+	} else {
+		hdmi_priv->dev = dev;
+		hdmi_priv->hdmib_reg = HDMIB;
+		hdmi_priv->monitor_type = MONITOR_TYPE_HDMI;
+		hdmi_priv->is_hdcp_supported = true;
+		i915_hdmi_audio_init(hdmi_priv);
+	}
+
 }
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 06/15] drm/i915: power-related changes non-HDAudio HDMI interface
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (4 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 05/15] drm/i915: changes " Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 07/15] drm/i915: Add API code for " Pierre-Louis Bossart
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, David Henningsson

PM and RPM changes for interface available on Baytrail and CherryTrail

This driver was downloaded from https://github.com/01org/baytrailaudio/

...and had the changes to .config stripped and the revert on sound/init.c

Clean-up, port to 4.4 and intel-drm by Pierre Bossart

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_rpm.c | 476 ++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_pm.c |  53 +++++
 2 files changed, 529 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_rpm.c

diff --git a/drivers/gpu/drm/i915/i915_rpm.c b/drivers/gpu/drm/i915/i915_rpm.c
new file mode 100644
index 0000000..511311c
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_rpm.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Naresh Kumar Kachhi <naresh.kumar.kachhi@intel.com>
+ */
+
+#include "i915_drv.h"
+#include "i915_reg.h"
+#include "intel_drv.h"
+#include <linux/console.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include <linux/proc_fs.h>  /* Needed for procfs access */
+#include <linux/fs.h>	    /* For the basic file system */
+#include <linux/kernel.h>
+
+#define RPM_AUTOSUSPEND_DELAY 500
+
+#ifdef CONFIG_PM_RUNTIME
+
+/**
+ * - Where should we use get/put?
+ *   Get/put should be used very carefully as we might end up in weird states
+ *   if not used properly (see the Note below). We want to cover all the
+ *   acesses that might result in accessing rings/display/registers/gtt etc
+ *   Mostly covering ioctls and drm callbacks should be enough. You can
+ *   avoid those which does not access any HW.
+ *
+ * - When should we avoid get/put?
+ *   WQ and interrupts should be taken care in suspend path. We should
+ *   disable all the interrupts and cancel any pending WQs. Never try to
+ *   cover interrupt/WQ with get/put unless you are sure about it.
+ *
+ * Note:Following scenarios should be strictly avoided while using get_sync
+ * 1. Calling get_sync with struct_mutex or mode_config.mutex locked
+ *    - we acquire these locks in runtime_resume, so any call to get_sync
+ *    with these mutex locked might end up in a dead lock.
+ *    check_mutex_current function can be used to debug this scenario.
+ *    - Or let's say thread1 has done get_sync and is currently executing
+ *    runtime_resume function. Before thread1 is able to acquire these
+ *    mutex, thread2 acquires the mutex and does a get_sync. Now thread1
+ *    is waiting for mutex and thread2 is waiting for dev->power.lock
+ *    resulting in a deadlock. Use check_mutex to debug this.
+ * 2. Calling get_sync from runtime_resume path
+ *    runtime_resume is called with dev->power.lock held. doing get_sync
+ *    in same path will end up in deadlock
+ */
+
+#define RPM_PROC_ENTRY_FILENAME		"i915_rpm_op"
+#define RPM_PROC_ENTRY_DIRECTORY	"driver/i915rpm"
+
+int i915_rpm_get_procfs(struct inode *inode, struct file *file);
+int i915_rpm_put_procfs(struct inode *inode, struct file *file);
+/* proc file operations supported */
+static const struct file_operations rpm_file_ops = {
+	.owner		= THIS_MODULE,
+	.open		= i915_rpm_get_procfs,
+	.release	= i915_rpm_put_procfs,
+};
+
+bool i915_pm_runtime_enabled(struct device *dev)
+{
+	return pm_runtime_enabled(dev);
+}
+
+void i915_rpm_enable(struct device *dev)
+{
+	int cur_status = pm_runtime_enabled(dev);
+
+	if (!cur_status) {
+		pm_runtime_enable(dev);
+		pm_runtime_allow(dev);
+	}
+}
+
+void i915_rpm_disable(struct drm_device *drm_dev)
+{
+	struct device *dev = drm_dev->dev;
+	int cur_status = pm_runtime_enabled(dev);
+
+	if (cur_status) {
+		pm_runtime_forbid(dev);
+		pm_runtime_disable(dev);
+	}
+}
+
+static int i915_rpm_procfs_init(struct drm_device *drm_dev)
+{
+	struct drm_i915_private *dev_priv = drm_dev->dev_private;
+
+	dev_priv->rpm.i915_proc_dir = NULL;
+	dev_priv->rpm.i915_proc_file = NULL;
+
+	/**
+	 * Create directory for rpm file(s)
+	 */
+	dev_priv->rpm.i915_proc_dir = proc_mkdir(RPM_PROC_ENTRY_DIRECTORY,
+						 NULL);
+	if (dev_priv->rpm.i915_proc_dir == NULL) {
+		DRM_ERROR("Could not initialize %s\n",
+				RPM_PROC_ENTRY_DIRECTORY);
+		return -ENOMEM;
+	}
+	/**
+	 * Create the /proc file
+	 */
+	dev_priv->rpm.i915_proc_file = proc_create_data(
+						RPM_PROC_ENTRY_FILENAME,
+						S_IRUGO | S_IWUSR,
+						dev_priv->rpm.i915_proc_dir,
+						&rpm_file_ops,
+						drm_dev);
+	/* check if file is created successfuly */
+	if (dev_priv->rpm.i915_proc_file == NULL) {
+		DRM_ERROR("Could not initialize %s/%s\n",
+			RPM_PROC_ENTRY_DIRECTORY, RPM_PROC_ENTRY_FILENAME);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static int i915_rpm_procfs_deinit(struct drm_device *drm_dev)
+{
+	struct drm_i915_private *dev_priv = drm_dev->dev_private;
+	/* Clean up proc file */
+	if (dev_priv->rpm.i915_proc_file) {
+		remove_proc_entry(RPM_PROC_ENTRY_FILENAME,
+				 dev_priv->rpm.i915_proc_dir);
+		dev_priv->rpm.i915_proc_file = NULL;
+	}
+	if (dev_priv->rpm.i915_proc_dir) {
+		remove_proc_entry(RPM_PROC_ENTRY_DIRECTORY, NULL);
+		dev_priv->rpm.i915_proc_dir = NULL;
+	}
+	return 0;
+}
+
+/* RPM init */
+int i915_rpm_init(struct drm_device *drm_dev)
+{
+	int ret = 0;
+	struct device *dev = drm_dev->dev;
+	struct drm_i915_private *dev_priv = drm_dev->dev_private;
+
+	ret = i915_rpm_procfs_init(drm_dev);
+	if (ret)
+		DRM_ERROR("unable to initialize procfs entry");
+	ret = pm_runtime_set_active(dev);
+	dev_priv->rpm.ring_active = false;
+	atomic_set(&dev_priv->rpm.procfs_count, 0);
+	pm_runtime_allow(dev);
+	/* enable Auto Suspend */
+	pm_runtime_set_autosuspend_delay(dev, RPM_AUTOSUSPEND_DELAY);
+	pm_runtime_use_autosuspend(dev);
+	if (dev->power.runtime_error)
+		DRM_ERROR("rpm init: error = %d\n", dev->power.runtime_error);
+
+	return ret;
+}
+
+int i915_rpm_deinit(struct drm_device *drm_dev)
+{
+	struct device *dev = drm_dev->dev;
+
+	pm_runtime_forbid(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_get_noresume(dev);
+	if (dev->power.runtime_error)
+		DRM_ERROR("rpm init: error = %d\n", dev->power.runtime_error);
+
+	i915_rpm_procfs_deinit(drm_dev);
+	return 0;
+}
+
+/**
+ * We have different flavour of get/put based on access type (ring/disp/
+ * vxd etc). this is done based on different requirements and to make
+ * debugging a little easier. Debugfs introduces separate counter for
+ * each type.
+ */
+
+/**
+ * Once we have scheduled commands on GPU, it might take a while GPU
+ * to execute them. Following is done to make sure Gfx is in D0i0 while
+ * GPU is executing the commands.
+ * 1. For IOCTLS make sure we are in D0i0 by calling "get_ioctl".
+ * 2. if IOCTL scheudles GPU commands using rings do the following
+ *  a. For all ring accesses make sure we add a request in the request
+ *     list and schedule a work item to track the "seq no". This
+ *     is done by using "i915_add_request" or "i915_add_request_no_flush"
+ *     functions.
+ *  b. If request list was empty, we do a "get_ring". This will increment
+ *     ref count to make sure GPU will be in D0 state.
+ *  c. Once the list becomes empty call put_ring
+ *
+ * Note: All the ring accesses are covered with struct_mutex. So we
+ * don't need any synchronization to protect ring_active.
+ */
+int i915_rpm_get_ring(struct drm_device *drm_dev)
+{
+	struct intel_engine_cs *ring;
+	struct drm_i915_private *dev_priv = drm_dev->dev_private;
+	int i;
+	bool idle = true;
+
+	for_each_ring(ring, dev_priv, i)
+		idle &= list_empty(&ring->request_list);
+
+	if (idle) {
+		if (!dev_priv->rpm.ring_active) {
+			dev_priv->rpm.ring_active = true;
+			pm_runtime_get_noresume(drm_dev->dev);
+		}
+	}
+
+	return 0;
+}
+
+int i915_rpm_put_ring(struct drm_device *drm_dev)
+{
+	struct drm_i915_private *dev_priv = drm_dev->dev_private;
+
+	if (dev_priv->rpm.ring_active) {
+		/* Mark last time it was busy and schedule a autosuspend */
+		pm_runtime_mark_last_busy(drm_dev->dev);
+		pm_runtime_put_autosuspend(drm_dev->dev);
+		dev_priv->rpm.ring_active = false;
+	}
+	return 0;
+}
+
+/**
+ * To cover the function pointers that are assigned to drm structures
+ * and can be called from drm
+ */
+int i915_rpm_get_callback(struct drm_device *drm_dev)
+{
+	return pm_runtime_get_sync(drm_dev->dev);
+}
+
+int i915_rpm_put_callback(struct drm_device *drm_dev)
+{
+	pm_runtime_mark_last_busy(drm_dev->dev);
+	return pm_runtime_put_autosuspend(drm_dev->dev);
+}
+
+/**
+ * early_suspend/DSR should call this function to notify PM Core about
+ * display idleness
+ */
+int i915_rpm_get_disp(struct drm_device *drm_dev)
+{
+	return pm_runtime_get_sync(drm_dev->dev);
+}
+
+int i915_rpm_put_disp(struct drm_device *drm_dev)
+{
+	pm_runtime_mark_last_busy(drm_dev->dev);
+	return pm_runtime_put_autosuspend(drm_dev->dev);
+}
+
+/** to cover the ioctls with get/put*/
+int i915_rpm_get_ioctl(struct drm_device *drm_dev)
+{
+	/* Don't do anything if device is not ready */
+	if (drm_device_is_unplugged(drm_dev))
+		return 0;
+
+	return pm_runtime_get_sync(drm_dev->dev);
+}
+
+int i915_rpm_put_ioctl(struct drm_device *drm_dev)
+{
+	/* Don't do anything if device is not ready */
+	if (drm_device_is_unplugged(drm_dev))
+		return 0;
+
+	pm_runtime_mark_last_busy(drm_dev->dev);
+	return pm_runtime_put_autosuspend(drm_dev->dev);
+}
+
+/* these operations are caled from user mode (CoreU) to make sure
+ * Gfx is up before register accesses from user mode
+ */
+int i915_rpm_get_procfs(struct inode *inode, struct file *file)
+{
+	struct drm_device *dev = PDE_DATA(inode);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	atomic_inc(&dev_priv->rpm.procfs_count);
+	pm_runtime_get_sync(dev->dev);
+	return 0;
+}
+
+int i915_rpm_put_procfs(struct inode *inode, struct file *file)
+{
+	struct drm_device *dev = PDE_DATA(inode);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	pm_runtime_mark_last_busy(dev->dev);
+	pm_runtime_put_autosuspend(dev->dev);
+	atomic_dec(&dev_priv->rpm.procfs_count);
+	return 0;
+}
+
+/**
+ * VXD driver need to call this to make sure Gfx is in D0i0
+ * while VXD is on
+ */
+#ifdef CONFIG_DRM_VXD_BYT
+int i915_rpm_get_vxd(struct drm_device *drm_dev)
+{
+	return pm_runtime_get_sync(drm_dev->dev);
+}
+EXPORT_SYMBOL(i915_rpm_get_vxd);
+
+/**
+ * VXD driver need to call this to notify Gfx that it is
+ * done with HW accesses
+ */
+int i915_rpm_put_vxd(struct drm_device *drm_dev)
+{
+	pm_runtime_mark_last_busy(drm_dev->dev);
+	return pm_runtime_put_autosuspend(drm_dev->dev);
+}
+EXPORT_SYMBOL(i915_rpm_put_vxd);
+#endif
+
+/* mainly for debug purpose, check if the access is valid */
+bool i915_rpm_access_check(struct drm_device *dev)
+{
+	if (dev->dev->power.runtime_status == RPM_SUSPENDED) {
+		DRM_ERROR("invalid access, will cause Hard Hang\n");
+		dump_stack();
+		return false;
+	}
+	return true;
+}
+
+/* mainly for debug purpose, check if mutex is locked by
+ * current thread
+ */
+int check_mutex_current(struct drm_device *drm_dev)
+{
+	int ret = 0;
+
+	if ((mutex_is_locked(&drm_dev->mode_config.mutex)) &&
+			(drm_dev->mode_config.mutex.owner == current)) {
+		DRM_ERROR("config mutex locked by current thread\n");
+		dump_stack();
+		ret = -1;
+	}
+	if ((mutex_is_locked(&drm_dev->struct_mutex)) &&
+			(drm_dev->struct_mutex.owner == current)) {
+		DRM_ERROR("struct mutex locked by current thread\n");
+		dump_stack();
+		ret = -2;
+	}
+	return ret;
+}
+
+int check_mutex(struct drm_device *drm_dev)
+{
+	int ret = 0;
+
+	if (mutex_is_locked(&drm_dev->mode_config.mutex)) {
+		DRM_ERROR("config mutex locked\n");
+		dump_stack();
+		ret = -1;
+	}
+	if (mutex_is_locked(&drm_dev->struct_mutex)) {
+		DRM_ERROR("struct mutex locked\n");
+		dump_stack();
+		ret = -2;
+	}
+	return ret;
+}
+
+/* Check for current runtime state */
+bool i915_is_device_active(struct drm_device *dev)
+{
+	return (dev->dev->power.runtime_status == RPM_ACTIVE);
+}
+
+bool i915_is_device_resuming(struct drm_device *dev)
+{
+	return (dev->dev->power.runtime_status == RPM_RESUMING);
+}
+
+bool i915_is_device_suspended(struct drm_device *dev)
+{
+	return (dev->dev->power.runtime_status == RPM_SUSPENDED);
+}
+
+bool i915_is_device_suspending(struct drm_device *dev)
+{
+	return (dev->dev->power.runtime_status == RPM_SUSPENDING);
+}
+
+#else /*CONFIG_PM_RUNTIME*/
+int i915_rpm_init(struct drm_device *dev) {return 0; }
+int i915_rpm_deinit(struct drm_device *dev) {return 0; }
+int i915_rpm_get(struct drm_device *dev, u32 flags) {return 0; }
+int i915_rpm_put(struct drm_device *dev, u32 flags) {return 0; }
+int i915_rpm_get_ring(struct drm_device *dev) {return 0; }
+int i915_rpm_put_ring(struct drm_device *dev) {return 0; }
+int i915_rpm_get_callback(struct drm_device *dev) {return 0; }
+int i915_rpm_put_callback(struct drm_device *dev) {return 0; }
+int i915_rpm_get_ioctl(struct drm_device *dev) {return 0; }
+int i915_rpm_put_ioctl(struct drm_device *dev) {return 0; }
+int i915_rpm_get_disp(struct drm_device *dev) {return 0; }
+int i915_rpm_put_disp(struct drm_device *dev) {return 0; }
+int i915_rpm_get_procfs(struct inode *inode,
+			      struct file *file) {return 0; }
+int i915_rpm_put_procfs(struct inode *inode,
+			      struct file *file) {return 0; }
+#ifdef CONFIG_DRM_VXD_BYT
+int i915_rpm_get_vxd(struct drm_device *dev) {return 0; }
+int i915_rpm_put_vxd(struct drm_device *dev) {return 0; }
+#endif
+
+bool i915_is_device_active(struct drm_device *dev)
+{
+	return true;
+}
+
+bool i915_is_device_resuming(struct drm_device *dev)
+{
+	return false;
+}
+
+bool i915_is_device_suspended(struct drm_device *dev)
+{
+	return false;
+}
+
+bool i915_is_device_suspending(struct drm_device *dev)
+{
+	return false;
+}
+
+bool i915_rpm_access_check(struct drm_device *dev)
+{
+	return true;
+}
+bool i915_pm_runtime_enabled(struct device *dev)
+{
+	return false;
+}
+
+void i915_rpm_enable(struct device *dev) {}
+
+void i915_rpm_disable(struct drm_device *drm_dev) {}
+
+#endif /*CONFIG_PM_RUNTIME*/
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index d33de95..dae77d1 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -31,6 +31,17 @@
 #include "../../../platform/x86/intel_ips.h"
 #include <linux/module.h>
 
+typedef enum _UHBUsage {
+	OSPM_UHB_ONLY_IF_ON = 0,
+	OSPM_UHB_FORCE_POWER_ON,
+} UHBUsage;
+
+static struct drm_device *gdev;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	#include <linux/earlysuspend.h>
+#endif
+
 /**
  * DOC: RC6
  *
@@ -7098,6 +7109,7 @@ void intel_suspend_hw(struct drm_device *dev)
 void intel_init_pm(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	gdev = dev;
 
 	intel_fbc_init(dev_priv);
 
@@ -7398,3 +7410,44 @@ void intel_pm_setup(struct drm_device *dev)
 	atomic_set(&dev_priv->pm.wakeref_count, 0);
 	atomic_set(&dev_priv->pm.atomic_seq, 0);
 }
+
+bool ospm_power_is_hw_on(int hw_islands)
+{
+#if 0
+	struct drm_device *drm_dev = gdev;
+	unsigned long flags;
+	bool ret = false;
+	struct drm_i915_private *dev_priv = drm_dev->dev_private;
+	u32 data = vlv_punit_read(dev_priv, VLV_IOSFSB_PWRGT_STATUS);
+
+	if ((VLV_POWER_GATE_DISPLAY_MASK & data)
+			== VLV_POWER_GATE_DISPLAY_MASK) {
+		DRM_ERROR("Display Island not ON\n");
+		return false;
+	} else {
+		return true;
+	}
+#endif
+	return true;
+}
+EXPORT_SYMBOL(ospm_power_is_hw_on);
+
+/* Dummy Function for HDMI Audio Power management.
+ * Will be updated once S0iX code is integrated
+ */
+bool ospm_power_using_hw_begin(int hw_island, UHBUsage usage)
+{
+	struct drm_device *drm_dev = gdev;
+
+	i915_rpm_get_disp(drm_dev);
+	return i915_is_device_active(drm_dev);
+}
+EXPORT_SYMBOL(ospm_power_using_hw_begin);
+
+void ospm_power_using_hw_end(int hw_island)
+{
+	struct drm_device *drm_dev = gdev;
+
+	i915_rpm_put_disp(drm_dev);
+}
+EXPORT_SYMBOL(ospm_power_using_hw_end);
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 07/15] drm/i915: Add API code for non-HDAudio HDMI interface
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (5 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 06/15] drm/i915: power-related changes " Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 08/15] drm/i915: enable non-HDAudio HDMI interface Makefile Pierre-Louis Bossart
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, David Henningsson

Add API code for interface available on Baytrail and CherryTrail

Initial code was downloaded from https://github.com/01org/baytrailaudio/
...and had the changes to .config stripped and the revert on sound/init.c
done by David Henningson

Clean-up, port to 4.4 and intel-drm by Pierre Bossart

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/hdmi_audio_if.c | 410 +++++++++++++++++++++++++++++++++++
 1 file changed, 410 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.c

diff --git a/drivers/gpu/drm/i915/hdmi_audio_if.c b/drivers/gpu/drm/i915/hdmi_audio_if.c
new file mode 100644
index 0000000..d198f39
--- /dev/null
+++ b/drivers/gpu/drm/i915/hdmi_audio_if.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2010, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * Authors:
+ *	jim liu <jim.liu@intel.com>
+ *	Uma Shankar <uma.shankar@intel.com>
+ */
+
+#include <drm/drmP.h>
+#include "hdmi_audio_if.h"
+#include "i915_drv.h"
+#include "i915_reg.h"
+
+#define CONFIG_SUPPORT_HDMI_AUDIO
+#ifdef CONFIG_SUPPORT_HDMI_AUDIO
+
+int i915_hdmi_state;
+int i915_notify_had;
+
+/*
+ * Audio register range 0x65000 to 0x65FFF
+ */
+
+#define IS_HDMI_AUDIO_I915(reg) ((reg >= 0x65000) && (reg < 0x65FFF))
+
+/* Added for HDMI Audio */
+#define HAD_MAX_ELD_BYTES 84
+uint8_t hdmi_eld[HAD_MAX_ELD_BYTES];
+
+static struct hdmi_audio_priv *hdmi_priv;
+
+void i915_hdmi_audio_init(struct hdmi_audio_priv *p_hdmi_priv)
+{
+	hdmi_priv = p_hdmi_priv;
+}
+
+/* Added for HDMI Audio */
+void hdmi_get_eld(uint8_t *eld)
+{
+	struct drm_device *dev = hdmi_priv->dev;
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	memcpy(hdmi_eld, eld, HAD_MAX_ELD_BYTES);
+	if (i915_notify_had) {
+		mid_hdmi_audio_signal_event(dev_priv->dev,
+			HAD_EVENT_HOT_PLUG);
+		i915_notify_had = 0;
+	}
+}
+
+static inline int android_hdmi_get_eld(struct drm_device *dev, void *eld)
+{
+	memcpy(eld, hdmi_eld, HAD_MAX_ELD_BYTES);
+	return 0;
+}
+
+/*
+ * return whether HDMI audio device is busy.
+ */
+bool mid_hdmi_audio_is_busy(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	int hdmi_audio_busy = 0;
+	hdmi_audio_event_t hdmi_audio_event;
+
+	if (i915_hdmi_state == connector_status_disconnected) {
+		/* HDMI is not connected, assuming audio device is idle. */
+		return false;
+	}
+
+	if (dev_priv->had_interface) {
+		hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY;
+		hdmi_audio_busy = dev_priv->had_interface->query(
+				dev_priv->had_pvt_data,
+				hdmi_audio_event);
+		return hdmi_audio_busy != 0;
+	}
+	return false;
+}
+
+/*
+ * return whether HDMI audio device is suspended.
+ */
+bool mid_hdmi_audio_suspend(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	hdmi_audio_event_t hdmi_audio_event;
+	int ret = 0;
+
+	if (i915_hdmi_state == connector_status_disconnected) {
+		/* HDMI is not connected, assuming audio device
+		 * is suspended already.
+		 */
+		return true;
+	}
+	DRM_DEBUG_DRIVER("%s: i915_hdmi_state %d", __func__,
+			i915_hdmi_state);
+
+	if (dev_priv->had_interface) {
+		hdmi_audio_event.type = 0;
+		ret = dev_priv->had_interface->suspend(dev_priv->had_pvt_data,
+				hdmi_audio_event);
+		return (ret == 0) ? true : false;
+	}
+	return true;
+}
+
+void mid_hdmi_audio_resume(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+
+	if (i915_hdmi_state == connector_status_disconnected) {
+		/* HDMI is not connected, there is no need
+		 * to resume audio device.
+		 */
+		return;
+	}
+	DRM_DEBUG_DRIVER("%s: i915_hdmi_state %d", __func__,
+				i915_hdmi_state);
+
+	if (dev_priv->had_interface)
+		dev_priv->had_interface->resume(dev_priv->had_pvt_data);
+}
+
+void mid_hdmi_audio_signal_event(struct drm_device *dev,
+		enum had_event_type event)
+{
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+
+	if (dev_priv->had_event_callbacks)
+		(*dev_priv->had_event_callbacks)(event,
+			dev_priv->had_pvt_data);
+}
+
+/**
+ * hdmi_audio_write:
+ * used to write into display controller HDMI audio registers.
+ *
+ */
+static int hdmi_audio_write(uint32_t reg, uint32_t val)
+{
+	struct drm_device *dev = hdmi_priv->dev;
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	int ret = 0;
+
+	if (hdmi_priv->monitor_type == MONITOR_TYPE_DVI)
+		return 0;
+
+	if (IS_HDMI_AUDIO_I915(reg))
+		I915_WRITE(_MMIO(VLV_DISPLAY_BASE + reg), val);
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/**
+ * hdmi_audio_read:
+ * used to get the register value read from
+ * display controller HDMI audio registers.
+ */
+static int hdmi_audio_read(uint32_t reg, uint32_t *val)
+{
+	struct drm_device *dev = hdmi_priv->dev;
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	int ret = 0;
+
+	if (hdmi_priv->monitor_type == MONITOR_TYPE_DVI)
+		return 0;
+
+	if (IS_HDMI_AUDIO_I915(reg))
+		*val = I915_READ(_MMIO(VLV_DISPLAY_BASE + reg));
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/**
+ * hdmi_audio_rmw:
+ * used to update the masked bits in display controller HDMI audio registers .
+ *
+ */
+static int hdmi_audio_rmw(uint32_t reg, uint32_t val, uint32_t mask)
+{
+	struct drm_device *dev = hdmi_priv->dev;
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	int ret = 0;
+	uint32_t val_tmp = 0;
+
+	if (IS_HDMI_AUDIO_I915(reg)) {
+		val_tmp = (val & mask) |
+			(I915_READ(_MMIO(VLV_DISPLAY_BASE + reg)) & ~mask);
+		I915_WRITE(_MMIO(VLV_DISPLAY_BASE + reg), val_tmp);
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * hdmi_audio_get_caps:
+ * used to return the HDMI audio capabilities.
+ * e.g. resolution, frame rate.
+ */
+static int hdmi_audio_get_caps(enum had_caps_list get_element,
+			void *capabilities)
+{
+	struct drm_device *dev = hdmi_priv->dev;
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	int ret = 0;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	switch (get_element) {
+	case HAD_GET_ELD:
+		ret = android_hdmi_get_eld(dev, capabilities);
+		break;
+	case HAD_GET_SAMPLING_FREQ:
+		/* ToDo: Verify if sampling freq logic is correct */
+		memcpy(capabilities, &(dev_priv->tmds_clock_speed),
+			sizeof(uint32_t));
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * hdmi_audio_set_caps:
+ * used to set the HDMI audio capabilities.
+ * e.g. Audio INT.
+ */
+static int hdmi_audio_set_caps(enum had_caps_list set_element,
+			void *capabilties)
+{
+	struct drm_device *dev = hdmi_priv->dev;
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	int ret = 0;
+	u32 hdmib;
+	u32 int_masks = 0;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	switch (set_element) {
+	case HAD_SET_ENABLE_AUDIO:
+		hdmib = I915_READ(_MMIO(hdmi_priv->hdmib_reg));
+		if (hdmib & PORT_ENABLE)
+			hdmib |= SDVO_AUDIO_ENABLE;
+
+		I915_WRITE(_MMIO(hdmi_priv->hdmib_reg), hdmib);
+		I915_READ(_MMIO(hdmi_priv->hdmib_reg));
+		break;
+	case HAD_SET_DISABLE_AUDIO:
+		hdmib = I915_READ(_MMIO(hdmi_priv->hdmib_reg)) &
+			~SDVO_AUDIO_ENABLE;
+		I915_WRITE(_MMIO(hdmi_priv->hdmib_reg), hdmib);
+		I915_READ(_MMIO(hdmi_priv->hdmib_reg));
+		break;
+
+	case HAD_SET_ENABLE_AUDIO_INT:
+		if (*((u32 *)capabilties) & HDMI_AUDIO_UNDERRUN)
+			int_masks |= I915_HDMI_AUDIO_UNDERRUN_ENABLE;
+		dev_priv->hdmi_audio_interrupt_mask |= int_masks;
+		i915_enable_hdmi_audio_int(dev);
+		break;
+	case HAD_SET_DISABLE_AUDIO_INT:
+		if (*((u32 *)capabilties) & HDMI_AUDIO_UNDERRUN)
+			int_masks |= I915_HDMI_AUDIO_UNDERRUN_ENABLE;
+		dev_priv->hdmi_audio_interrupt_mask &= ~int_masks;
+
+		if (dev_priv->hdmi_audio_interrupt_mask)
+			i915_enable_hdmi_audio_int(dev);
+		else
+			i915_disable_hdmi_audio_int(dev);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct  hdmi_audio_registers_ops hdmi_audio_reg_ops = {
+	.hdmi_audio_read_register = hdmi_audio_read,
+	.hdmi_audio_write_register = hdmi_audio_write,
+	.hdmi_audio_read_modify = hdmi_audio_rmw,
+};
+
+static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = {
+	.hdmi_audio_get_caps = hdmi_audio_get_caps,
+	.hdmi_audio_set_caps = hdmi_audio_set_caps,
+};
+
+int mid_hdmi_audio_setup(
+		had_event_call_back audio_callbacks,
+		struct hdmi_audio_registers_ops *reg_ops,
+		struct hdmi_audio_query_set_ops *query_ops)
+{
+	struct drm_device *dev = hdmi_priv->dev;
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	int ret = 0;
+
+	DRM_DEBUG_DRIVER("%s: called\n", __func__);
+
+	reg_ops->hdmi_audio_read_register =
+		(hdmi_audio_reg_ops.hdmi_audio_read_register);
+	reg_ops->hdmi_audio_write_register =
+		(hdmi_audio_reg_ops.hdmi_audio_write_register);
+	reg_ops->hdmi_audio_read_modify =
+		(hdmi_audio_reg_ops.hdmi_audio_read_modify);
+	query_ops->hdmi_audio_get_caps =
+		hdmi_audio_get_set_ops.hdmi_audio_get_caps;
+	query_ops->hdmi_audio_set_caps =
+		hdmi_audio_get_set_ops.hdmi_audio_set_caps;
+
+	dev_priv->had_event_callbacks = audio_callbacks;
+
+	return ret;
+}
+EXPORT_SYMBOL(mid_hdmi_audio_setup);
+
+int mid_hdmi_audio_register(struct snd_intel_had_interface *driver,
+				void *had_data)
+{
+	struct drm_device *dev = hdmi_priv->dev;
+	struct drm_i915_private *dev_priv =
+		(struct drm_i915_private *) dev->dev_private;
+	DRM_DEBUG_DRIVER("%s: called\n", __func__);
+	dev_priv->had_pvt_data = had_data;
+	dev_priv->had_interface = driver;
+
+	if (hdmi_priv->monitor_type == MONITOR_TYPE_DVI)
+		return 0;
+
+	/* The Audio driver is loading now and we need to notify
+	 * it if there is an HDMI device attached
+	 */
+	DRM_INFO("%s: Scheduling HDMI audio work queue\n", __func__);
+	schedule_work(&dev_priv->hdmi_audio_wq);
+
+	return 0;
+}
+EXPORT_SYMBOL(mid_hdmi_audio_register);
+#else
+bool hdmi_audio_is_busy(struct drm_device *dev)
+{
+	/* always in idle state */
+	return false;
+}
+
+bool hdmi_audio_suspend(struct drm_device *dev)
+{
+	/* always in suspend state */
+	return true;
+}
+
+void hdmi_audio_resume(struct drm_device *dev)
+{
+}
+
+void hdmi_audio_signal_event(struct drm_device *dev, enum had_event_type event)
+{
+}
+
+void i915_hdmi_audio_init(struct hdmi_audio_priv *hdmi_priv)
+{
+	DRM_INFO("%s: HDMI is not supported.\n", __func__);
+}
+
+int mid_hdmi_audio_setup(
+		had_event_call_back audio_callbacks,
+		struct hdmi_audio_registers_ops *reg_ops,
+		struct hdmi_audio_query_set_ops *query_ops)
+{
+	DRM_ERROR("%s: HDMI is not supported.\n", __func__);
+	return -ENODEV;
+}
+EXPORT_SYMBOL(mid_hdmi_audio_setup);
+
+int mid_hdmi_audio_register(struct snd_intel_had_interface *driver,
+			void *had_data)
+{
+	DRM_ERROR("%s: HDMI is not supported.\n", __func__);
+	return -ENODEV;
+}
+EXPORT_SYMBOL(mid_hdmi_audio_register);
+#endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 08/15] drm/i915: enable non-HDAudio HDMI interface Makefile
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (6 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 07/15] drm/i915: Add API code for " Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 09/15] ALSA: Intel: Atom: add Atom non-HDAudio HDMI interface Pierre-Louis Bossart
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, David Henningsson

Makefile for all previous patches

This driver was downloaded from https://github.com/01org/baytrailaudio/

...and had the changes to .config stripped and the revert on sound/init.c

clean-up, port to 4.4 and intel-drm by Pierre Bossart

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0851de07..b85d6c2 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -37,6 +37,7 @@ i915-y += i915_cmd_parser.o \
 	  i915_trace_points.o \
 	  intel_lrc.o \
 	  intel_mocs.o \
+	  i915_rpm.o \
 	  intel_ringbuffer.o \
 	  intel_uncore.o
 
@@ -89,7 +90,8 @@ i915-y += dvo_ch7017.o \
 	  intel_lvds.o \
 	  intel_panel.o \
 	  intel_sdvo.o \
-	  intel_tv.o
+	  intel_tv.o \
+	  hdmi_audio_if.o
 
 # virtual gpu code
 i915-y += i915_vgpu.o
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 09/15] ALSA: Intel: Atom: add Atom non-HDAudio HDMI interface
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (7 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 08/15] drm/i915: enable non-HDAudio HDMI interface Makefile Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 10/15] add dependency on PM_RUNTIME Pierre-Louis Bossart
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, David Henningsson

Add support interface available on Baytrail and CherryTrail

Initial code was downloaded from https://github.com/01org/baytrailaudio/
...and had the changes to .config stripped and the revert on sound/init.c
and printk->pr_debug done by David Henningson

Clean-up, port to 4.4 and intel-drm by Pierre Bossart

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/Kconfig                              |    8 +
 sound/Makefile                             |    1 +
 sound/hdmi_audio/Makefile                  |    9 +
 sound/hdmi_audio/intel_mid_hdmi_audio.c    | 2029 ++++++++++++++++++++++++++++
 sound/hdmi_audio/intel_mid_hdmi_audio.h    |  740 ++++++++++
 sound/hdmi_audio/intel_mid_hdmi_audio_if.c |  514 +++++++
 6 files changed, 3301 insertions(+)
 create mode 100644 sound/hdmi_audio/Makefile
 create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio.c
 create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio.h
 create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio_if.c

diff --git a/sound/Kconfig b/sound/Kconfig
index 5a240e0..75c679e 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -134,3 +134,11 @@ config AC97_BUS
 	  sound subsystem and other function drivers completely unrelated to
 	  sound although they're sharing the AC97 bus. Concerned drivers
 	  should "select" this.
+
+config SUPPORT_HDMI
+        bool "SUPPORT_HDMI"
+        depends on DRM_I915
+        default n
+        help
+          Choose this option to support HDMI.
+
diff --git a/sound/Makefile b/sound/Makefile
index 7732070..f2c5e82 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DMASOUND) += oss/
 obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
 	firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/
 obj-$(CONFIG_SND_AOA) += aoa/
+obj-$(CONFIG_SUPPORT_HDMI) += hdmi_audio/
 
 # This one must be compilable even if sound is configured out
 obj-$(CONFIG_AC97_BUS) += ac97_bus.o
diff --git a/sound/hdmi_audio/Makefile b/sound/hdmi_audio/Makefile
new file mode 100644
index 0000000..b28eb3b
--- /dev/null
+++ b/sound/hdmi_audio/Makefile
@@ -0,0 +1,9 @@
+DRIVER_NAME := hdmi_audio
+
+ccflags-y += -Idrivers/gpu/drm/i915
+
+$(DRIVER_NAME)-objs += \
+	intel_mid_hdmi_audio.o \
+	intel_mid_hdmi_audio_if.o
+
+obj-m += $(DRIVER_NAME).o
diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
new file mode 100644
index 0000000..f397435
--- /dev/null
+++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
@@ -0,0 +1,2029 @@
+/*
+ *   intel_mid_hdmi_audio.c - Intel HDMI audio driver for MID
+ *
+ *  Copyright (C) 2010 Intel Corp
+ *  Authors:	Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ *		Ramesh Babu K V	<ramesh.babu@intel.com>
+ *		Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver for Intel MID HDMI audio controller
+ */
+
+#define pr_fmt(fmt)	"had: " fmt
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <sound/pcm.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+#include "intel_mid_hdmi_audio.h"
+
+#define PCM_INDEX		0
+#define MAX_PB_STREAMS		1
+#define MAX_CAP_STREAMS		0
+#define HDMI_AUDIO_DRIVER	"hdmi-audio"
+static DEFINE_MUTEX(had_mutex);
+
+/*standard module options for ALSA. This module supports only one card*/
+static int hdmi_card_index = SNDRV_DEFAULT_IDX1;
+static char *hdmi_card_id = SNDRV_DEFAULT_STR1;
+static struct snd_intelhad *had_data;
+
+module_param(hdmi_card_index, int, 0444);
+MODULE_PARM_DESC(hdmi_card_index,
+		"Index value for INTEL Intel HDMI Audio controller.");
+module_param(hdmi_card_id, charp, 0444);
+MODULE_PARM_DESC(hdmi_card_id,
+		"ID string for INTEL Intel HDMI Audio controller.");
+MODULE_AUTHOR("Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>");
+MODULE_AUTHOR("Ramesh Babu K V <ramesh.babu@intel.com>");
+MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@intel.com>");
+MODULE_DESCRIPTION("Intel HDMI Audio driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{Intel,Intel_HAD}");
+MODULE_VERSION(HAD_DRIVER_VERSION);
+
+#define INFO_FRAME_WORD1	0x000a0184
+#define FIFO_THRESHOLD		0xFE
+#define DMA_FIFO_THRESHOLD	0x7
+#define BYTES_PER_WORD		0x4
+
+/* Sampling rate as per IEC60958 Ver 3 */
+#define CH_STATUS_MAP_32KHZ	0x3
+#define CH_STATUS_MAP_44KHZ	0x0
+#define CH_STATUS_MAP_48KHZ	0x2
+#define CH_STATUS_MAP_88KHZ	0x8
+#define CH_STATUS_MAP_96KHZ	0xA
+#define CH_STATUS_MAP_176KHZ	0xC
+#define CH_STATUS_MAP_192KHZ	0xE
+
+#define MAX_SMPL_WIDTH_20	0x0
+#define MAX_SMPL_WIDTH_24	0x1
+#define SMPL_WIDTH_16BITS	0x1
+#define SMPL_WIDTH_24BITS	0x5
+#define CHANNEL_ALLOCATION	0x1F
+#define MASK_BYTE0		0x000000FF
+#define VALID_DIP_WORDS		3
+#define LAYOUT0			0
+#define LAYOUT1			1
+#define SWAP_LFE_CENTER		0x00fac4c8
+#define AUD_CONFIG_CH_MASK_V2	0x70
+
+/*
+ * ELD SA bits in the CEA Speaker Allocation data block
+*/
+static int eld_speaker_allocation_bits[] = {
+	[0] = FL | FR,
+	[1] = LFE,
+	[2] = FC,
+	[3] = RL | RR,
+	[4] = RC,
+	[5] = FLC | FRC,
+	[6] = RLC | RRC,
+	/* the following are not defined in ELD yet */
+	[7] = 0,
+};
+
+/*
+ * This is an ordered list!
+ *
+ * The preceding ones have better chances to be selected by
+ * hdmi_channel_allocation().
+ */
+static struct cea_channel_speaker_allocation channel_allocations[] = {
+/*                        channel:   7     6    5    4    3     2    1    0  */
+{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
+				/* 2.1 */
+{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
+				/* Dolby Surround */
+{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
+				/* surround40 */
+{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
+				/* surround41 */
+{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
+				/* surround50 */
+{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
+				/* surround51 */
+{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
+				/* 6.1 */
+{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+				/* surround71 */
+{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+
+{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
+{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+};
+
+static struct channel_map_table map_tables[] = {
+	{ SNDRV_CHMAP_FL,       0x00,   FL },
+	{ SNDRV_CHMAP_FR,       0x01,   FR },
+	{ SNDRV_CHMAP_RL,       0x04,   RL },
+	{ SNDRV_CHMAP_RR,       0x05,   RR },
+	{ SNDRV_CHMAP_LFE,      0x02,   LFE },
+	{ SNDRV_CHMAP_FC,       0x03,   FC },
+	{ SNDRV_CHMAP_RLC,      0x06,   RLC },
+	{ SNDRV_CHMAP_RRC,      0x07,   RRC },
+	{} /* terminator */
+};
+
+/* hardware capability structure */
+static const struct snd_pcm_hardware snd_intel_hadstream = {
+	.info =	(SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_DOUBLE |
+		SNDRV_PCM_INFO_MMAP|
+		SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_BATCH),
+	.formats = (SNDRV_PCM_FMTBIT_S24 |
+		SNDRV_PCM_FMTBIT_U24),
+	.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,
+	.rate_min = HAD_MIN_RATE,
+	.rate_max = HAD_MAX_RATE,
+	.channels_min = HAD_MIN_CHANNEL,
+	.channels_max = HAD_MAX_CHANNEL,
+	.buffer_bytes_max = HAD_MAX_BUFFER,
+	.period_bytes_min = HAD_MIN_PERIOD_BYTES,
+	.period_bytes_max = HAD_MAX_PERIOD_BYTES,
+	.periods_min = HAD_MIN_PERIODS,
+	.periods_max = HAD_MAX_PERIODS,
+	.fifo_size = HAD_FIFO_SIZE,
+};
+
+/* Register access functions */
+
+inline int had_get_hwstate(struct snd_intelhad *intelhaddata)
+{
+	/* Check for device presence -SW state */
+	if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
+		pr_debug("%s:Device not connected:%d\n", __func__,
+				intelhaddata->drv_status);
+		return -ENODEV;
+	}
+
+	/* Check for device presence -HW state */
+	if (!ospm_power_is_hw_on(OSPM_DISPLAY_ISLAND)) {
+		pr_err("%s:Device not connected\n", __func__);
+		/* HOT_UNPLUG event can be sent to
+		 * maintain correct state within HAD
+		 * had_event_handler(HAD_EVENT_HOT_UNPLUG, intelhaddata);
+		 * Drop all acuired locks before executing this.
+		 */
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+inline int had_get_caps(enum had_caps_list query, void *caps)
+{
+	int retval;
+	struct snd_intelhad *intelhaddata = had_data;
+
+	retval = had_get_hwstate(intelhaddata);
+	if (!retval)
+		retval = intelhaddata->query_ops.hdmi_audio_get_caps(query,
+				caps);
+
+	return retval;
+}
+
+inline int had_set_caps(enum had_caps_list set_element, void *caps)
+{
+	int retval;
+	struct snd_intelhad *intelhaddata = had_data;
+
+	retval = had_get_hwstate(intelhaddata);
+	if (!retval)
+		retval = intelhaddata->query_ops.hdmi_audio_set_caps(
+				set_element, caps);
+
+	return retval;
+}
+
+inline int had_read_register(uint32_t offset, uint32_t *data)
+{
+	int retval;
+	struct snd_intelhad *intelhaddata = had_data;
+	u32 base_addr = intelhaddata->audio_reg_base;
+
+	retval = had_get_hwstate(intelhaddata);
+	if (!retval)
+		retval = intelhaddata->reg_ops.hdmi_audio_read_register(
+				base_addr + offset, data);
+
+	return retval;
+}
+
+inline int had_write_register(uint32_t offset, uint32_t data)
+{
+	int retval;
+	struct snd_intelhad *intelhaddata = had_data;
+	u32 base_addr = intelhaddata->audio_reg_base;
+
+	retval = had_get_hwstate(intelhaddata);
+	if (!retval)
+		retval = intelhaddata->reg_ops.hdmi_audio_write_register(
+				base_addr + offset, data);
+
+	return retval;
+}
+
+inline int had_read_modify(uint32_t offset, uint32_t data, uint32_t mask)
+{
+	int retval;
+	struct snd_intelhad *intelhaddata = had_data;
+	u32 base_addr = intelhaddata->audio_reg_base;
+
+	retval = had_get_hwstate(intelhaddata);
+	if (!retval)
+		retval = intelhaddata->reg_ops.hdmi_audio_read_modify(
+				base_addr + offset, data, mask);
+
+	return retval;
+}
+/**
+ * had_read_modify_aud_config_v2 - Specific function to read-modify AUD_CONFIG
+ * register on VLV2.The had_read_modify() function should not directly be used
+ * on VLV2 for updating AUD_CONFIG register.
+ * This is because:
+ * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2 HDMI IP.
+ * As a result a read-modify of AUD_CONFIG regiter will always clear bit6.
+ * AUD_CONFIG[6:4] represents the "channels" field of the register.
+ * This field should be 1xy binary for configuration with 6 or more channels.
+ * Read-modify of AUD_CONFIG (Eg. for enabling audio) causes the "channels" field
+ * to be updated as 0xy binary resulting in bad audio.
+ * The fix is to always write the AUD_CONFIG[6:4] with appropriate value when
+ * doing read-modify of AUD_CONFIG register.
+ *
+ * @substream: the current substream or NULL if no active substream
+ * @data : data to be written
+ * @mask : mask
+ *
+ */
+inline int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream,
+					uint32_t data, uint32_t mask)
+{
+	union aud_cfg cfg_val = {.cfg_regval = 0};
+	u8 channels;
+
+	/*
+	 * If substream is NULL, there is no active stream.
+	 * In this case just set channels to 2
+	 */
+	if (substream)
+		channels = substream->runtime->channels;
+	else
+		channels = 2;
+	cfg_val.cfg_regx_v2.num_ch = channels - 2;
+
+	data = data | cfg_val.cfg_regval;
+	mask = mask | AUD_CONFIG_CH_MASK_V2;
+
+	pr_debug("%s : data = %x, mask =%x\n", __func__, data, mask);
+
+	return had_read_modify(AUD_CONFIG, data, mask);
+}
+
+/**
+ * snd_intelhad_enable_audio_v1 - to enable audio
+ *
+ * @substream: Current substream or NULL if no active substream.
+ * @enable: 1 if audio is to be enabled; 0 if audio is to be disabled.
+ *
+ */
+static void snd_intelhad_enable_audio_v1(struct snd_pcm_substream *substream,
+					u8 enable)
+{
+	had_read_modify(AUD_CONFIG, enable, BIT(0));
+}
+
+/**
+ * snd_intelhad_enable_audio_v2 - to enable audio
+ *
+ * @substream: Current substream or NULL if no active substream.
+ * @enable: 1 if audio is to be enabled; 0 if audio is to be disabled.
+ */
+static void snd_intelhad_enable_audio_v2(struct snd_pcm_substream *substream,
+					u8 enable)
+{
+	had_read_modify_aud_config_v2(substream, enable, BIT(0));
+}
+
+/**
+ * snd_intelhad_reset_audio_v1 - to reset audio subsystem
+ *
+ * @reset: 1 to reset audio; 0 to bring audio out of reset.
+ *
+ */
+static void snd_intelhad_reset_audio_v1(u8 reset)
+{
+	had_write_register(AUD_HDMI_STATUS, reset);
+}
+
+/**
+ * snd_intelhad_reset_audio_v2 - to reset audio subsystem
+ *
+ * @reset: 1 to reset audio; 0 to bring audio out of reset.
+ *
+ */
+static void snd_intelhad_reset_audio_v2(u8 reset)
+{
+	had_write_register(AUD_HDMI_STATUS_v2, reset);
+}
+
+/**
+ * had_prog_status_reg - to initialize audio channel status registers
+ *
+ * @substream:substream for which the prepare function is called
+ * @intelhaddata:substream private data
+ *
+ * This function is called in the prepare callback
+ */
+static int had_prog_status_reg(struct snd_pcm_substream *substream,
+			struct snd_intelhad *intelhaddata)
+{
+	union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0};
+	union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0};
+	int format;
+
+	pr_debug("Entry %s\n", __func__);
+
+	ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits &
+						IEC958_AES0_NONAUDIO)>>1;
+	ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits &
+						IEC958_AES3_CON_CLOCK)>>4;
+	switch (substream->runtime->rate) {
+	case AUD_SAMPLE_RATE_32:
+		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ;
+		break;
+
+	case AUD_SAMPLE_RATE_44_1:
+		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_44KHZ;
+		break;
+	case AUD_SAMPLE_RATE_48:
+		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_48KHZ;
+		break;
+	case AUD_SAMPLE_RATE_88_2:
+		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_88KHZ;
+		break;
+	case AUD_SAMPLE_RATE_96:
+		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_96KHZ;
+		break;
+	case AUD_SAMPLE_RATE_176_4:
+		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_176KHZ;
+		break;
+	case AUD_SAMPLE_RATE_192:
+		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_192KHZ;
+		break;
+
+	default:
+		/* control should never come here */
+		return -EINVAL;
+	break;
+
+	}
+	had_write_register(AUD_CH_STATUS_0, ch_stat0.status_0_regval);
+
+	format = substream->runtime->format;
+
+	if (format == SNDRV_PCM_FORMAT_S16_LE) {
+		ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_20;
+		ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_16BITS;
+	} else if (format == SNDRV_PCM_FORMAT_S24_LE) {
+		ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_24;
+		ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_24BITS;
+	} else {
+		ch_stat1.status_1_regx.max_wrd_len = 0;
+		ch_stat1.status_1_regx.wrd_len = 0;
+	}
+	had_write_register(AUD_CH_STATUS_1, ch_stat1.status_1_regval);
+	return 0;
+}
+
+/**
+ * snd_intelhad_prog_audio_ctrl_v2 - to initialize audio
+ * registers and buffer confgiuration registers
+ *
+ * @substream:substream for which the prepare function is called
+ * @intelhaddata:substream private data
+ *
+ * This function is called in the prepare callback
+ */
+int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream,
+					struct snd_intelhad *intelhaddata)
+{
+	union aud_cfg cfg_val = {.cfg_regval = 0};
+	union aud_buf_config buf_cfg = {.buf_cfgval = 0};
+	u8 channels;
+
+	had_prog_status_reg(substream, intelhaddata);
+
+	buf_cfg.buf_cfg_regx_v2.audio_fifo_watermark = FIFO_THRESHOLD;
+	buf_cfg.buf_cfg_regx_v2.dma_fifo_watermark = DMA_FIFO_THRESHOLD;
+	buf_cfg.buf_cfg_regx_v2.aud_delay = 0;
+	had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval);
+
+	channels = substream->runtime->channels;
+	cfg_val.cfg_regx_v2.num_ch = channels - 2;
+	if (channels <= 2)
+		cfg_val.cfg_regx_v2.layout = LAYOUT0;
+	else
+		cfg_val.cfg_regx_v2.layout = LAYOUT1;
+
+	cfg_val.cfg_regx_v2.val_bit = 1;
+	had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
+	return 0;
+}
+
+/**
+ * snd_intelhad_prog_audio_ctrl_v1 - to initialize audio
+ * registers and buffer confgiuration registers
+ *
+ * @substream:substream for which the prepare function is called
+ * @intelhaddata:substream private data
+ *
+ * This function is called in the prepare callback
+ */
+int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream,
+					struct snd_intelhad *intelhaddata)
+{
+	union aud_cfg cfg_val = {.cfg_regval = 0};
+	union aud_buf_config buf_cfg = {.buf_cfgval = 0};
+	u8 channels;
+
+	had_prog_status_reg(substream, intelhaddata);
+
+	buf_cfg.buf_cfg_regx.fifo_width = FIFO_THRESHOLD;
+	buf_cfg.buf_cfg_regx.aud_delay = 0;
+	had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval);
+
+	channels = substream->runtime->channels;
+
+	switch (channels) {
+	case 1:
+	case 2:
+		cfg_val.cfg_regx.num_ch = CH_STEREO;
+		cfg_val.cfg_regx.layout = LAYOUT0;
+	break;
+
+	case 3:
+	case 4:
+		cfg_val.cfg_regx.num_ch = CH_THREE_FOUR;
+		cfg_val.cfg_regx.layout = LAYOUT1;
+	break;
+
+	case 5:
+	case 6:
+		cfg_val.cfg_regx.num_ch = CH_FIVE_SIX;
+		cfg_val.cfg_regx.layout = LAYOUT1;
+	break;
+
+	case 7:
+	case 8:
+		cfg_val.cfg_regx.num_ch = CH_SEVEN_EIGHT;
+		cfg_val.cfg_regx.layout = LAYOUT1;
+	break;
+
+	}
+
+	cfg_val.cfg_regx.val_bit = 1;
+	had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
+	return 0;
+}
+/*
+ * Compute derived values in channel_allocations[].
+ */
+static void init_channel_allocations(void)
+{
+	int i, j;
+	struct cea_channel_speaker_allocation *p;
+
+	pr_debug("%s: Enter\n", __func__);
+
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		p = channel_allocations + i;
+		p->channels = 0;
+		p->spk_mask = 0;
+		for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
+			if (p->speakers[j]) {
+				p->channels++;
+				p->spk_mask |= p->speakers[j];
+			}
+	}
+}
+
+/*
+ * The transformation takes two steps:
+ *
+ *      eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
+ *            spk_mask => (channel_allocations[])         => ai->CA
+ *
+ * TODO: it could select the wrong CA from multiple candidates.
+*/
+static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata,
+					int channels)
+{
+	int i;
+	int ca = 0;
+	int spk_mask = 0;
+
+	/*
+	* CA defaults to 0 for basic stereo audio
+	*/
+	if (channels <= 2)
+		return 0;
+
+	/*
+	* expand ELD's speaker allocation mask
+	*
+	* ELD tells the speaker mask in a compact(paired) form,
+	* expand ELD's notions to match the ones used by Audio InfoFrame.
+	*/
+
+	for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+		if (intelhaddata->eeld.speaker_allocation_block & (1 << i))
+			spk_mask |= eld_speaker_allocation_bits[i];
+	}
+
+	/* search for the first working match in the CA table */
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		if (channels == channel_allocations[i].channels &&
+		(spk_mask & channel_allocations[i].spk_mask) ==
+				channel_allocations[i].spk_mask) {
+			ca = channel_allocations[i].ca_index;
+			break;
+		}
+	}
+
+	pr_debug("HDMI: select CA 0x%x for %d\n", ca, channels);
+
+	return ca;
+}
+
+/* from speaker bit mask to ALSA API channel position */
+static int spk_to_chmap(int spk)
+{
+	struct channel_map_table *t = map_tables;
+
+	for (; t->map; t++) {
+		if (t->spk_mask == spk)
+			return t->map;
+	}
+	return 0;
+}
+
+void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
+{
+	int i = 0, c = 0;
+	int spk_mask = 0;
+	struct snd_pcm_chmap_elem *chmap;
+	uint8_t eld_high, eld_high_mask = 0xF0;
+	uint8_t high_msb;
+
+	chmap = kzalloc(sizeof(*chmap), GFP_KERNEL);
+	if (chmap == NULL) {
+		pr_err("kzalloc returned null in %s\n", __func__);
+		intelhaddata->chmap->chmap = NULL;
+		return;
+	}
+
+	had_get_caps(HAD_GET_ELD, &intelhaddata->eeld);
+
+	pr_debug("eeld.speaker_allocation_block = %x\n",
+			intelhaddata->eeld.speaker_allocation_block);
+
+	/* WA: Fix the max channel supported to 8 */
+
+	/*
+	 * Sink may support more than 8 channels, if eld_high has more than
+	 * one bit set. SOC supports max 8 channels.
+	 * Refer eld_speaker_allocation_bits, for sink speaker allocation
+	 */
+
+	/* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */
+	eld_high = intelhaddata->eeld.speaker_allocation_block & eld_high_mask;
+	if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) {
+		/* eld_high & (eld_high-1): if more than 1 bit set */
+		/* 0x1F: 7 channels */
+		for (i = 1; i < 4; i++) {
+			high_msb = eld_high & (0x80 >> i);
+			if (high_msb) {
+				intelhaddata->eeld.speaker_allocation_block &=
+					high_msb | 0xF;
+				break;
+			}
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+		if (intelhaddata->eeld.speaker_allocation_block & (1 << i))
+			spk_mask |= eld_speaker_allocation_bits[i];
+	}
+
+	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+		if (spk_mask == channel_allocations[i].spk_mask) {
+			for (c = 0; c < channel_allocations[i].channels; c++) {
+				chmap->map[c] = spk_to_chmap(
+					channel_allocations[i].speakers[(MAX_SPEAKERS - 1)-c]);
+			}
+			chmap->channels = channel_allocations[i].channels;
+			intelhaddata->chmap->chmap = chmap;
+			break;
+		}
+	}
+	if (i >= ARRAY_SIZE(channel_allocations))
+		kfree(chmap);
+}
+
+/*
+ ** ALSA API channel-map control callbacks
+ **/
+static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	struct snd_intelhad *intelhaddata = info->private_data;
+
+	if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED)
+		return -ENODEV;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = HAD_MAX_CHANNEL;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+	return 0;
+}
+
+#ifndef USE_ALSA_DEFAULT_TLV
+static int had_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+				unsigned int size, unsigned int __user *tlv)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	struct snd_intelhad *intelhaddata = info->private_data;
+
+	if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED)
+		return -ENODEV;
+
+	/* TODO: Fix for query channel map */
+	return -EPERM;
+}
+#endif
+
+static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+	struct snd_intelhad *intelhaddata = info->private_data;
+	int i = 0;
+	const struct snd_pcm_chmap_elem *chmap;
+
+	if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED)
+		return -ENODEV;
+	if (intelhaddata->chmap->chmap ==  NULL)
+		return -ENODATA;
+	chmap = intelhaddata->chmap->chmap;
+	for (i = 0; i < chmap->channels; i++) {
+		ucontrol->value.integer.value[i] = chmap->map[i];
+		pr_debug("chmap->map[%d] = %d\n", i, chmap->map[i]);
+	}
+
+	return 0;
+}
+
+static int had_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	/* TODO: Get channel map and set swap register */
+	return -EPERM;
+}
+
+static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata,
+						struct snd_pcm *pcm)
+{
+	int err = 0;
+
+	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			NULL, 0, (unsigned long)intelhaddata,
+			&intelhaddata->chmap);
+	if (err < 0)
+		return err;
+
+	intelhaddata->chmap->private_data = intelhaddata;
+	intelhaddata->kctl = intelhaddata->chmap->kctl;
+	intelhaddata->kctl->info = had_chmap_ctl_info;
+	intelhaddata->kctl->get = had_chmap_ctl_get;
+	intelhaddata->kctl->put = had_chmap_ctl_put;
+#ifndef USE_ALSA_DEFAULT_TLV
+	intelhaddata->kctl->tlv.c = had_chmap_ctl_tlv;
+#endif
+	intelhaddata->chmap->chmap = NULL;
+	return 0;
+}
+
+/**
+ * snd_intelhad_prog_dip_v1 - to initialize Data Island Packets registers
+ *
+ * @substream:substream for which the prepare function is called
+ * @intelhaddata:substream private data
+ *
+ * This function is called in the prepare callback
+ */
+static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream,
+				struct snd_intelhad *intelhaddata)
+{
+	int i;
+	union aud_ctrl_st ctrl_state = {.ctrl_val = 0};
+	union aud_info_frame2 frame2 = {.fr2_val = 0};
+	union aud_info_frame3 frame3 = {.fr3_val = 0};
+	u8 checksum = 0;
+	int channels;
+
+	channels = substream->runtime->channels;
+
+	had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
+
+	frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;
+
+	frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation(
+					intelhaddata, channels);
+
+	/*Calculte the byte wide checksum for all valid DIP words*/
+	for (i = 0; i < BYTES_PER_WORD; i++)
+		checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
+	for (i = 0; i < BYTES_PER_WORD; i++)
+		checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
+	for (i = 0; i < BYTES_PER_WORD; i++)
+		checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
+
+	frame2.fr2_regx.chksum = -(checksum);
+
+	had_write_register(AUD_HDMIW_INFOFR, INFO_FRAME_WORD1);
+	had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val);
+	had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val);
+
+	/* program remaining DIP words with zero */
+	for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
+		had_write_register(AUD_HDMIW_INFOFR, 0x0);
+
+	ctrl_state.ctrl_regx.dip_freq = 1;
+	ctrl_state.ctrl_regx.dip_en_sta = 1;
+	had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
+}
+
+/**
+ * snd_intelhad_prog_dip_v2 - to initialize Data Island Packets registers
+ *
+ * @substream:substream for which the prepare function is called
+ * @intelhaddata:substream private data
+ *
+ * This function is called in the prepare callback
+ */
+static void snd_intelhad_prog_dip_v2(struct snd_pcm_substream *substream,
+				struct snd_intelhad *intelhaddata)
+{
+	int i;
+	union aud_ctrl_st ctrl_state = {.ctrl_val = 0};
+	union aud_info_frame2 frame2 = {.fr2_val = 0};
+	union aud_info_frame3 frame3 = {.fr3_val = 0};
+	u8 checksum = 0;
+	int channels;
+
+	channels = substream->runtime->channels;
+
+	had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
+
+	frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;
+
+	frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation(
+					intelhaddata, channels);
+
+	/*Calculte the byte wide checksum for all valid DIP words*/
+	for (i = 0; i < BYTES_PER_WORD; i++)
+		checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
+	for (i = 0; i < BYTES_PER_WORD; i++)
+		checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
+	for (i = 0; i < BYTES_PER_WORD; i++)
+		checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
+
+	frame2.fr2_regx.chksum = -(checksum);
+
+	had_write_register(AUD_HDMIW_INFOFR_v2, INFO_FRAME_WORD1);
+	had_write_register(AUD_HDMIW_INFOFR_v2, frame2.fr2_val);
+	had_write_register(AUD_HDMIW_INFOFR_v2, frame3.fr3_val);
+
+	/* program remaining DIP words with zero */
+	for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
+		had_write_register(AUD_HDMIW_INFOFR_v2, 0x0);
+
+	ctrl_state.ctrl_regx.dip_freq = 1;
+	ctrl_state.ctrl_regx.dip_en_sta = 1;
+	had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
+}
+
+/**
+ * snd_intelhad_prog_buffer - programs buffer
+ * address and length registers
+ *
+ * @substream:substream for which the prepare function is called
+ * @intelhaddata:substream private data
+ *
+ * This function programs ring buffer address and length into registers.
+ */
+int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata,
+					int start, int end)
+{
+	u32 ring_buf_addr, ring_buf_size, period_bytes;
+	u8 i, num_periods;
+	struct snd_pcm_substream *substream;
+
+	substream = intelhaddata->stream_info.had_substream;
+	if (!substream) {
+		pr_err("substream is NULL\n");
+		dump_stack();
+		return 0;
+	}
+
+	ring_buf_addr = substream->runtime->dma_addr;
+	ring_buf_size = snd_pcm_lib_buffer_bytes(substream);
+	intelhaddata->stream_info.ring_buf_size = ring_buf_size;
+	period_bytes = frames_to_bytes(substream->runtime,
+				substream->runtime->period_size);
+	num_periods = substream->runtime->periods;
+
+	/*
+	 * buffer addr should  be 64 byte aligned, period bytes
+	 * will be used to calculate addr offset
+	 */
+	period_bytes &= ~0x3F;
+
+	/* Hardware supports MAX_PERIODS buffers */
+	if (end >= HAD_MAX_PERIODS)
+		return -EINVAL;
+
+	for (i = start; i <= end; i++) {
+		/* Program the buf registers with addr and len */
+		intelhaddata->buf_info[i].buf_addr = ring_buf_addr +
+							 (i * period_bytes);
+		if (i < num_periods-1)
+			intelhaddata->buf_info[i].buf_size = period_bytes;
+		else
+			intelhaddata->buf_info[i].buf_size = ring_buf_size -
+							(period_bytes*i);
+
+		had_write_register(AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH),
+					intelhaddata->buf_info[i].buf_addr |
+					BIT(0) | BIT(1));
+		had_write_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
+					period_bytes);
+		intelhaddata->buf_info[i].is_valid = true;
+	}
+	pr_debug("%s:buf[%d-%d] addr=%#x  and size=%d\n", __func__, start, end,
+			intelhaddata->buf_info[start].buf_addr,
+			intelhaddata->buf_info[start].buf_size);
+	intelhaddata->valid_buf_cnt = num_periods;
+	return 0;
+}
+
+inline int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
+{
+	int i, retval = 0;
+	u32 len[4];
+
+	for (i = 0; i < 4 ; i++) {
+		had_read_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
+					&len[i]);
+		if (!len[i])
+			retval++;
+	}
+	if (retval != 1) {
+		for (i = 0; i < 4 ; i++)
+			pr_debug("buf[%d] size=%d\n", i, len[i]);
+	}
+
+	return retval;
+}
+
+/**
+ * snd_intelhad_prog_cts_v1 - Program HDMI audio CTS value
+ *
+ * @aud_samp_freq: sampling frequency of audio data
+ * @tmds: sampling frequency of the display data
+ * @n_param: N value, depends on aud_samp_freq
+ * @intelhaddata:substream private data
+ *
+ * Program CTS register based on the audio and display sampling frequency
+ */
+static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param,
+				struct snd_intelhad *intelhaddata)
+{
+	u32 cts_val;
+	u64 dividend, divisor;
+
+	/* Calculate CTS according to HDMI 1.3a spec*/
+	dividend = (u64)tmds * n_param*1000;
+	divisor = 128 * aud_samp_freq;
+	cts_val = div64_u64(dividend, divisor);
+	pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n",
+			tmds, n_param, cts_val);
+	had_write_register(AUD_HDMI_CTS, (BIT(20) | cts_val));
+}
+
+/**
+ * snd_intelhad_prog_cts_v2 - Program HDMI audio CTS value
+ *
+ * @aud_samp_freq: sampling frequency of audio data
+ * @tmds: sampling frequency of the display data
+ * @n_param: N value, depends on aud_samp_freq
+ * @intelhaddata:substream private data
+ *
+ * Program CTS register based on the audio and display sampling frequency
+ */
+static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, u32 n_param,
+				struct snd_intelhad *intelhaddata)
+{
+	u32 cts_val;
+	u64 dividend, divisor;
+
+	/* Calculate CTS according to HDMI 1.3a spec*/
+	dividend = (u64)tmds * n_param*1000;
+	divisor = 128 * aud_samp_freq;
+	cts_val = div64_u64(dividend, divisor);
+	pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n",
+			tmds, n_param, cts_val);
+	had_write_register(AUD_HDMI_CTS, (BIT(24) | cts_val));
+}
+
+static int had_calculate_n_value(u32 aud_samp_freq)
+{
+	s32 n_val;
+
+	/* Select N according to HDMI 1.3a spec*/
+	switch (aud_samp_freq) {
+	case AUD_SAMPLE_RATE_32:
+		n_val = 4096;
+	break;
+
+	case AUD_SAMPLE_RATE_44_1:
+		n_val = 6272;
+	break;
+
+	case AUD_SAMPLE_RATE_48:
+		n_val = 6144;
+	break;
+
+	case AUD_SAMPLE_RATE_88_2:
+		n_val = 12544;
+	break;
+
+	case AUD_SAMPLE_RATE_96:
+		n_val = 12288;
+	break;
+
+	case AUD_SAMPLE_RATE_176_4:
+		n_val = 25088;
+	break;
+
+	case HAD_MAX_RATE:
+		n_val = 24576;
+	break;
+
+	default:
+		n_val = -EINVAL;
+	break;
+	}
+	return n_val;
+}
+
+/**
+ * snd_intelhad_prog_n_v1 - Program HDMI audio N value
+ *
+ * @aud_samp_freq: sampling frequency of audio data
+ * @n_param: N value, depends on aud_samp_freq
+ * @intelhaddata:substream private data
+ *
+ * This function is called in the prepare callback.
+ * It programs based on the audio and display sampling frequency
+ */
+static int snd_intelhad_prog_n_v1(u32 aud_samp_freq, u32 *n_param,
+				struct snd_intelhad *intelhaddata)
+{
+	s32 n_val;
+
+	n_val =	had_calculate_n_value(aud_samp_freq);
+
+	if (n_val < 0)
+		return n_val;
+
+	had_write_register(AUD_N_ENABLE, (BIT(20) | n_val));
+	*n_param = n_val;
+	return 0;
+}
+
+/**
+ * snd_intelhad_prog_n_v2 - Program HDMI audio N value
+ *
+ * @aud_samp_freq: sampling frequency of audio data
+ * @n_param: N value, depends on aud_samp_freq
+ * @intelhaddata:substream private data
+ *
+ * This function is called in the prepare callback.
+ * It programs based on the audio and display sampling frequency
+ */
+static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param,
+				struct snd_intelhad *intelhaddata)
+{
+	s32 n_val;
+
+	n_val =	had_calculate_n_value(aud_samp_freq);
+
+	if (n_val < 0)
+		return n_val;
+
+	had_write_register(AUD_N_ENABLE, (BIT(24) | n_val));
+	*n_param = n_val;
+	return 0;
+}
+
+static void had_clear_underrun_intr_v1(struct snd_intelhad *intelhaddata)
+{
+	u32 hdmi_status, i = 0;
+
+	/* Handle Underrun interrupt within Audio Unit */
+	had_write_register(AUD_CONFIG, 0);
+	/* Reset buffer pointers */
+	had_write_register(AUD_HDMI_STATUS, 1);
+	had_write_register(AUD_HDMI_STATUS, 0);
+	/**
+	 * The interrupt status 'sticky' bits might not be cleared by
+	 * setting '1' to that bit once...
+	 */
+	do { /* clear bit30, 31 AUD_HDMI_STATUS */
+		had_read_register(AUD_HDMI_STATUS, &hdmi_status);
+		pr_debug("HDMI status =0x%x\n", hdmi_status);
+		if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) {
+			i++;
+			hdmi_status &= (AUD_CONFIG_MASK_SRDBG |
+					AUD_CONFIG_MASK_FUNCRST);
+			hdmi_status |= ~AUD_CONFIG_MASK_UNDERRUN;
+			had_write_register(AUD_HDMI_STATUS, hdmi_status);
+		} else
+			break;
+	} while (i < MAX_CNT);
+	if (i >= MAX_CNT)
+		pr_err("Unable to clear UNDERRUN bits\n");
+}
+
+static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata)
+{
+	u32 hdmi_status, i = 0;
+
+	/* Handle Underrun interrupt within Audio Unit */
+	had_write_register(AUD_CONFIG, 0);
+	/* Reset buffer pointers */
+	had_write_register(AUD_HDMI_STATUS_v2, 1);
+	had_write_register(AUD_HDMI_STATUS_v2, 0);
+	/**
+	 * The interrupt status 'sticky' bits might not be cleared by
+	 * setting '1' to that bit once...
+	 */
+	do { /* clear bit30, 31 AUD_HDMI_STATUS */
+		had_read_register(AUD_HDMI_STATUS_v2, &hdmi_status);
+		pr_debug("HDMI status =0x%x\n", hdmi_status);
+		if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) {
+			i++;
+			hdmi_status &= ~AUD_CONFIG_MASK_UNDERRUN;
+			had_write_register(AUD_HDMI_STATUS_v2, hdmi_status);
+		} else
+			break;
+	} while (i < MAX_CNT);
+	if (i >= MAX_CNT)
+		pr_err("Unable to clear UNDERRUN bits\n");
+}
+
+/**
+* snd_intelhad_open - stream initializations are done here
+* @substream:substream for which the stream function is called
+*
+* This function is called whenever a PCM stream is opened
+*/
+static int snd_intelhad_open(struct snd_pcm_substream *substream)
+{
+	struct snd_intelhad *intelhaddata;
+	struct snd_pcm_runtime *runtime;
+	struct had_stream_pvt *stream;
+	struct had_pvt_data *had_stream;
+	int retval;
+
+	pr_debug("snd_intelhad_open called\n");
+	intelhaddata = snd_pcm_substream_chip(substream);
+	had_stream = intelhaddata->private_data;
+	runtime = substream->runtime;
+
+	pm_runtime_get(intelhaddata->dev);
+
+	/*
+	 * HDMI driver might suspend the device already,
+	 * so we return it on
+	 */
+	if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
+			OSPM_UHB_FORCE_POWER_ON)) {
+		pr_err("HDMI device can't be turned on\n");
+		retval = -ENODEV;
+		goto exit_put_handle;
+	}
+
+	if (had_get_hwstate(intelhaddata)) {
+		pr_err("%s: HDMI cable plugged-out\n", __func__);
+		retval = -ENODEV;
+		goto exit_ospm_handle;
+	}
+
+	/* Check, if device already in use */
+	if (runtime->private_data) {
+		pr_err("Device already in use\n");
+		retval = -EBUSY;
+		goto exit_ospm_handle;
+	}
+
+	/* set the runtime hw parameter with local snd_pcm_hardware struct */
+	runtime->hw = snd_intel_hadstream;
+
+	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+	if (!stream) {
+		retval = -ENOMEM;
+		goto exit_ospm_handle;
+	}
+	stream->stream_status = STREAM_INIT;
+	runtime->private_data = stream;
+
+	retval = snd_pcm_hw_constraint_integer(runtime,
+			 SNDRV_PCM_HW_PARAM_PERIODS);
+	if (retval < 0) {
+		goto exit_err;
+	}
+
+	/* Make sure, that the period size is always aligned
+	 * 64byte boundary
+	 */
+	retval = snd_pcm_hw_constraint_step(substream->runtime, 0,
+			SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
+	if (retval < 0) {
+		pr_err("%s:step_size=64 failed,err=%d\n", __func__, retval);
+		goto exit_err;
+	}
+
+	return retval;
+exit_err:
+	kfree(stream);
+exit_ospm_handle:
+	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
+exit_put_handle:
+	pm_runtime_put(intelhaddata->dev);
+	runtime->private_data = NULL;
+	return retval;
+}
+
+/**
+* had_period_elapsed - updates the hardware pointer status
+* @had_substream:substream for which the stream function is called
+*
+*/
+static void had_period_elapsed(void *had_substream)
+{
+	struct snd_pcm_substream *substream = had_substream;
+	struct had_stream_pvt *stream;
+
+	/* pr_debug("had_period_elapsed called\n"); */
+
+	if (!substream || !substream->runtime)
+		return;
+	stream = substream->runtime->private_data;
+	if (!stream)
+		return;
+
+	if (stream->stream_status != STREAM_RUNNING)
+		return;
+	snd_pcm_period_elapsed(substream);
+}
+
+/**
+* snd_intelhad_init_stream - internal function to initialize stream info
+* @substream:substream for which the stream function is called
+*
+*/
+static int snd_intelhad_init_stream(struct snd_pcm_substream *substream)
+{
+	struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream);
+
+	pr_debug("snd_intelhad_init_stream called\n");
+
+	pr_debug("setting buffer ptr param\n");
+	intelhaddata->stream_info.period_elapsed = had_period_elapsed;
+	intelhaddata->stream_info.had_substream = substream;
+	intelhaddata->stream_info.buffer_ptr = 0;
+	intelhaddata->stream_info.buffer_rendered = 0;
+	intelhaddata->stream_info.sfreq = substream->runtime->rate;
+	return 0;
+}
+
+/**
+ * snd_intelhad_close- to free parameteres when stream is stopped
+ *
+ * @substream:  substream for which the function is called
+ *
+ * This function is called by ALSA framework when stream is stopped
+ */
+static int snd_intelhad_close(struct snd_pcm_substream *substream)
+{
+	struct snd_intelhad *intelhaddata;
+	struct snd_pcm_runtime *runtime;
+
+	pr_debug("snd_intelhad_close called\n");
+
+	intelhaddata = snd_pcm_substream_chip(substream);
+	runtime = substream->runtime;
+
+	if (!runtime->private_data) {
+		pr_debug("close() might have called after failed open");
+		return 0;
+	}
+
+	intelhaddata->stream_info.buffer_rendered = 0;
+	intelhaddata->stream_info.buffer_ptr = 0;
+	intelhaddata->stream_info.str_id = 0;
+	intelhaddata->stream_info.had_substream = NULL;
+
+	/* Check if following drv_status modification is required - VA */
+	if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED)
+		intelhaddata->drv_status = HAD_DRV_CONNECTED;
+	kfree(runtime->private_data);
+	runtime->private_data = NULL;
+	ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
+	pm_runtime_put(intelhaddata->dev);
+	return 0;
+}
+
+/**
+ * snd_intelhad_hw_params- to setup the hardware parameters
+ * like allocating the buffers
+ *
+ * @substream:  substream for which the function is called
+ * @hw_params: hardware parameters
+ *
+ * This function is called by ALSA framework when hardware params are set
+ */
+static int snd_intelhad_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *hw_params)
+{
+	unsigned long addr;
+	int pages, buf_size, retval;
+
+	pr_debug("snd_intelhad_hw_params called\n");
+
+	BUG_ON(!hw_params);
+
+	buf_size = params_buffer_bytes(hw_params);
+	retval = snd_pcm_lib_malloc_pages(substream, buf_size);
+	if (retval < 0)
+		return retval;
+	pr_debug("%s:allocated memory = %d\n", __func__, buf_size);
+	/* mark the pages as uncached region */
+	addr = (unsigned long) substream->runtime->dma_area;
+	pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+	retval = set_memory_uc(addr, pages);
+	if (retval) {
+		pr_err("set_memory_uc failed.Error:%d\n", retval);
+		return retval;
+	}
+	memset(substream->runtime->dma_area, 0, buf_size);
+
+	return retval;
+}
+
+/**
+ * snd_intelhad_hw_free- to release the resources allocated during
+ * hardware params setup
+ *
+ * @substream:  substream for which the function is called
+ *
+ * This function is called by ALSA framework before close callback.
+ *
+ */
+static int snd_intelhad_hw_free(struct snd_pcm_substream *substream)
+{
+	unsigned long addr;
+	u32 pages;
+
+	pr_debug("snd_intelhad_hw_free called\n");
+
+	/* mark back the pages as cached/writeback region before the free */
+	if (substream->runtime->dma_area != NULL) {
+		addr = (unsigned long) substream->runtime->dma_area;
+		pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) /
+								PAGE_SIZE;
+		set_memory_wb(addr, pages);
+		return snd_pcm_lib_free_pages(substream);
+	}
+	return 0;
+}
+
+/**
+* snd_intelhad_pcm_trigger - stream activities are handled here
+* @substream:substream for which the stream function is called
+* @cmd:the stream commamd thats requested from upper layer
+* This function is called whenever an a stream activity is invoked
+*/
+static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream,
+					int cmd)
+{
+	int caps, retval = 0;
+	unsigned long flag_irq;
+	struct snd_intelhad *intelhaddata;
+	struct had_stream_pvt *stream;
+	struct had_pvt_data *had_stream;
+
+	pr_debug("snd_intelhad_pcm_trigger called\n");
+
+	intelhaddata = snd_pcm_substream_chip(substream);
+	stream = substream->runtime->private_data;
+	had_stream = intelhaddata->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		pr_debug("Trigger Start\n");
+
+		/* Disable local INTRs till register prgmng is done */
+		if (had_get_hwstate(intelhaddata)) {
+			pr_err("_START: HDMI cable plugged-out\n");
+			retval = -ENODEV;
+			break;
+		}
+		stream->stream_status = STREAM_RUNNING;
+
+		spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq);
+		had_stream->stream_type = HAD_RUNNING_STREAM;
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq);
+
+		/* Enable Audio */
+		/*
+		 * ToDo: Need to enable UNDERRUN interrupts as well
+		 *   caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
+		 */
+		caps = HDMI_AUDIO_BUFFER_DONE;
+		retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps);
+		retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL);
+		intelhaddata->ops->enable_audio(substream, 1);
+
+		pr_debug("Processed _Start\n");
+
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		pr_debug("Trigger Stop\n");
+		spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq);
+		intelhaddata->stream_info.str_id = 0;
+		intelhaddata->curr_buf = 0;
+
+		/* Stop reporting BUFFER_DONE/UNDERRUN to above layers*/
+
+		had_stream->stream_type = HAD_INIT;
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq);
+		/* Disable Audio */
+		/*
+		 * ToDo: Need to disable UNDERRUN interrupts as well
+		 *   caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
+		 */
+		caps = HDMI_AUDIO_BUFFER_DONE;
+		had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps);
+		intelhaddata->ops->enable_audio(substream, 0);
+		/* Reset buffer pointers */
+		intelhaddata->ops->reset_audio(1);
+		intelhaddata->ops->reset_audio(0);
+		stream->stream_status = STREAM_DROPPED;
+		had_set_caps(HAD_SET_DISABLE_AUDIO, NULL);
+		break;
+
+	default:
+		retval = -EINVAL;
+	}
+	return retval;
+}
+
+/**
+* snd_intelhad_pcm_prepare- internal preparation before starting a stream
+*
+* @substream:  substream for which the function is called
+*
+* This function is called when a stream is started for internal preparation.
+*/
+static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	int retval;
+	u32 disp_samp_freq, n_param;
+	struct snd_intelhad *intelhaddata;
+	struct snd_pcm_runtime *runtime;
+	struct had_pvt_data *had_stream;
+
+	pr_debug("snd_intelhad_pcm_prepare called\n");
+
+	intelhaddata = snd_pcm_substream_chip(substream);
+	runtime = substream->runtime;
+	had_stream = intelhaddata->private_data;
+
+	if (had_get_hwstate(intelhaddata)) {
+		pr_err("%s: HDMI cable plugged-out\n", __func__);
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+		retval = -ENODEV;
+		goto prep_end;
+	}
+
+	pr_debug("period_size=%d\n",
+				frames_to_bytes(runtime, runtime->period_size));
+	pr_debug("periods=%d\n", runtime->periods);
+	pr_debug("buffer_size=%d\n", snd_pcm_lib_buffer_bytes(substream));
+	pr_debug("rate=%d\n", runtime->rate);
+	pr_debug("channels=%d\n", runtime->channels);
+
+	if (intelhaddata->stream_info.str_id) {
+		pr_debug("_prepare is called for existing str_id#%d\n",
+					intelhaddata->stream_info.str_id);
+		retval = snd_intelhad_pcm_trigger(substream,
+						SNDRV_PCM_TRIGGER_STOP);
+		return retval;
+	}
+
+	retval = snd_intelhad_init_stream(substream);
+	if (retval)
+		goto prep_end;
+
+
+	/* Get N value in KHz */
+	retval = had_get_caps(HAD_GET_SAMPLING_FREQ, &disp_samp_freq);
+	if (retval) {
+		pr_err("querying display sampling freq failed %#x\n", retval);
+		goto prep_end;
+	}
+
+	had_get_caps(HAD_GET_ELD, &intelhaddata->eeld);
+
+	retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param,
+								intelhaddata);
+	if (retval) {
+		pr_err("programming N value failed %#x\n", retval);
+		goto prep_end;
+	}
+	intelhaddata->ops->prog_cts(substream->runtime->rate,
+					disp_samp_freq, n_param, intelhaddata);
+
+	intelhaddata->ops->prog_dip(substream, intelhaddata);
+
+	retval = intelhaddata->ops->audio_ctrl(substream, intelhaddata);
+
+	/* Prog buffer address */
+	retval = snd_intelhad_prog_buffer(intelhaddata,
+			HAD_BUF_TYPE_A, HAD_BUF_TYPE_D);
+
+	/*
+	 * Program channel mapping in following order:
+	 * FL, FR, C, LFE, RL, RR
+	 */
+
+	had_write_register(AUD_BUF_CH_SWAP, SWAP_LFE_CENTER);
+
+prep_end:
+	return retval;
+}
+
+/**
+ * snd_intelhad_pcm_pointer- to send the current buffer pointerprocessed by hw
+ *
+ * @substream:  substream for which the function is called
+ *
+ * This function is called by ALSA framework to get the current hw buffer ptr
+ * when a period is elapsed
+ */
+static snd_pcm_uframes_t snd_intelhad_pcm_pointer(
+					struct snd_pcm_substream *substream)
+{
+	struct snd_intelhad *intelhaddata;
+	u32 bytes_rendered = 0;
+
+	/* pr_debug("snd_intelhad_pcm_pointer called\n"); */
+
+	intelhaddata = snd_pcm_substream_chip(substream);
+
+	if (intelhaddata->flag_underrun) {
+		intelhaddata->flag_underrun = 0;
+		return SNDRV_PCM_POS_XRUN;
+	}
+
+	if (intelhaddata->stream_info.buffer_rendered)
+		div_u64_rem(intelhaddata->stream_info.buffer_rendered,
+			intelhaddata->stream_info.ring_buf_size,
+			&(bytes_rendered));
+
+	intelhaddata->stream_info.buffer_ptr = bytes_to_frames(
+						substream->runtime,
+						bytes_rendered);
+	return intelhaddata->stream_info.buffer_ptr;
+}
+
+/**
+* snd_intelhad_pcm_mmap- mmaps a kernel buffer to user space for copying data
+*
+* @substream:  substream for which the function is called
+* @vma:		struct instance of memory VMM memory area
+*
+* This function is called by OS when a user space component
+* tries to get mmap memory from driver
+*/
+static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+
+	pr_debug("snd_intelhad_pcm_mmap called\n");
+
+	pr_debug("entry with prot:%s\n", __func__);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return remap_pfn_range(vma, vma->vm_start,
+			substream->dma_buffer.addr >> PAGE_SHIFT,
+			vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+int hdmi_audio_mode_change(struct snd_pcm_substream *substream)
+{
+	int retval = 0;
+	u32 disp_samp_freq, n_param;
+	struct snd_intelhad *intelhaddata;
+
+	intelhaddata = snd_pcm_substream_chip(substream);
+
+	/* Disable Audio */
+	intelhaddata->ops->enable_audio(substream, 0);
+
+	/* Update CTS value */
+	retval = had_get_caps(HAD_GET_SAMPLING_FREQ, &disp_samp_freq);
+	if (retval) {
+		pr_err("querying display sampling freq failed %#x\n", retval);
+		goto out;
+	}
+
+	retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param,
+								intelhaddata);
+	if (retval) {
+		pr_err("programming N value failed %#x\n", retval);
+		goto out;
+	}
+	intelhaddata->ops->prog_cts(substream->runtime->rate,
+					disp_samp_freq, n_param, intelhaddata);
+
+	/* Enable Audio */
+	intelhaddata->ops->enable_audio(substream, 1);
+
+out:
+	return retval;
+}
+
+/*PCM operations structure and the calls back for the same */
+struct snd_pcm_ops snd_intelhad_playback_ops = {
+	.open =		snd_intelhad_open,
+	.close =	snd_intelhad_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_intelhad_hw_params,
+	.hw_free =	snd_intelhad_hw_free,
+	.prepare =	snd_intelhad_pcm_prepare,
+	.trigger =	snd_intelhad_pcm_trigger,
+	.pointer =	snd_intelhad_pcm_pointer,
+	.mmap =	snd_intelhad_pcm_mmap,
+};
+
+/**
+ * snd_intelhad_create - to crete alsa card instance
+ *
+ * @intelhaddata: pointer to internal context
+ * @card: pointer to card
+ *
+ * This function is called when the hdmi cable is plugged in
+ */
+static int snd_intelhad_create(
+		struct snd_intelhad *intelhaddata,
+		struct snd_card *card)
+{
+	int retval;
+	static struct snd_device_ops ops = {
+	};
+
+	BUG_ON(!intelhaddata);
+	/* ALSA api to register the device */
+	retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelhaddata, &ops);
+	return retval;
+}
+/**
+ * snd_intelhad_pcm_free - to free the memory allocated
+ *
+ * @pcm: pointer to pcm instance
+ * This function is called when the device is removed
+ */
+static void snd_intelhad_pcm_free(struct snd_pcm *pcm)
+{
+	pr_debug("Freeing PCM preallocated pages\n");
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int had_iec958_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int had_iec958_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff;
+	ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] =
+					(intelhaddata->aes_bits >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] =
+					(intelhaddata->aes_bits >> 24) & 0xff;
+	return 0;
+}
+static int had_iec958_mask_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.iec958.status[0] = 0xff;
+	ucontrol->value.iec958.status[1] = 0xff;
+	ucontrol->value.iec958.status[2] = 0xff;
+	ucontrol->value.iec958.status[3] = 0xff;
+	return 0;
+}
+static int had_iec958_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned int val;
+	struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
+
+	pr_debug("entered had_iec958_put\n");
+	val = (ucontrol->value.iec958.status[0] << 0) |
+		(ucontrol->value.iec958.status[1] << 8) |
+		(ucontrol->value.iec958.status[2] << 16) |
+		(ucontrol->value.iec958.status[3] << 24);
+	if (intelhaddata->aes_bits != val) {
+		intelhaddata->aes_bits = val;
+		return 1;
+	}
+	return 1;
+}
+
+static struct snd_kcontrol_new had_control_iec958_mask = {
+	.access =   SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =    SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+	.info =     had_iec958_info, /* shared */
+	.get =      had_iec958_mask_get,
+};
+
+static struct snd_kcontrol_new had_control_iec958 = {
+	.iface =    SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+	.info =         had_iec958_info,
+	.get =          had_iec958_get,
+	.put =          had_iec958_put
+};
+
+static struct snd_intel_had_interface had_interface = {
+	.name =         "hdmi-audio",
+	.query =        hdmi_audio_query,
+	.suspend =      hdmi_audio_suspend,
+	.resume =       hdmi_audio_resume,
+};
+
+static struct had_ops had_ops_v1 = {
+	.enable_audio = snd_intelhad_enable_audio_v1,
+	.reset_audio = snd_intelhad_reset_audio_v1,
+	.prog_n =	snd_intelhad_prog_n_v1,
+	.prog_cts =	snd_intelhad_prog_cts_v1,
+	.audio_ctrl =	snd_intelhad_prog_audio_ctrl_v1,
+	.prog_dip =	snd_intelhad_prog_dip_v1,
+	.handle_underrun =  had_clear_underrun_intr_v1,
+};
+
+static struct had_ops had_ops_v2 = {
+	.enable_audio = snd_intelhad_enable_audio_v2,
+	.reset_audio = snd_intelhad_reset_audio_v2,
+	.prog_n =	snd_intelhad_prog_n_v2,
+	.prog_cts =	snd_intelhad_prog_cts_v2,
+	.audio_ctrl =	snd_intelhad_prog_audio_ctrl_v2,
+	.prog_dip =	snd_intelhad_prog_dip_v2,
+	.handle_underrun = had_clear_underrun_intr_v2,
+};
+/**
+ * hdmi_audio_probe - to create sound card instance for HDMI audio playabck
+ *
+ *@haddata: pointer to HAD private data
+ *@card_id: card for which probe is called
+ *
+ * This function is called when the hdmi cable is plugged in. This function
+ * creates and registers the sound card with ALSA
+ */
+static int hdmi_audio_probe(struct platform_device *devptr)
+{
+
+	int retval;
+	struct snd_pcm *pcm;
+	struct snd_card *card;
+	struct had_callback_ops ops_cb;
+	struct snd_intelhad *intelhaddata;
+	struct had_pvt_data *had_stream;
+
+	pr_debug("Enter %s\n", __func__);
+
+	pr_debug("hdmi_audio_probe dma_mask: %d\n", devptr->dev.dma_mask);
+
+	/* allocate memory for saving internal context and working */
+	intelhaddata = kzalloc(sizeof(*intelhaddata), GFP_KERNEL);
+	if (!intelhaddata) {
+		pr_err("mem alloc failed\n");
+		return -ENOMEM;
+	}
+
+	had_stream = kzalloc(sizeof(*had_stream), GFP_KERNEL);
+	if (!had_stream) {
+		pr_err("mem alloc failed\n");
+		retval = -ENOMEM;
+		goto free_haddata;
+	}
+
+	had_data = intelhaddata;
+	ops_cb.intel_had_event_call_back = had_event_handler;
+
+	/* registering with display driver to get access to display APIs */
+
+	retval = mid_hdmi_audio_setup(
+			ops_cb.intel_had_event_call_back,
+			&(intelhaddata->reg_ops),
+			&(intelhaddata->query_ops));
+	if (retval) {
+		pr_err("querying display driver APIs failed %#x\n", retval);
+		goto free_hadstream;
+	}
+	mutex_lock(&had_mutex);
+	spin_lock_init(&intelhaddata->had_spinlock);
+	intelhaddata->drv_status = HAD_DRV_DISCONNECTED;
+	/* create a card instance with ALSA framework */
+	retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id,
+				THIS_MODULE, 0, &card);
+
+	if (retval)
+		goto unlock_mutex;
+	intelhaddata->card = card;
+	intelhaddata->card_id = hdmi_card_id;
+	intelhaddata->card_index = card->number;
+	intelhaddata->private_data = had_stream;
+	intelhaddata->flag_underrun = 0;
+	intelhaddata->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
+	strncpy(card->driver, INTEL_HAD, strlen(INTEL_HAD));
+	strncpy(card->shortname, INTEL_HAD, strlen(INTEL_HAD));
+
+	retval = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
+						MAX_CAP_STREAMS, &pcm);
+	if (retval)
+		goto err;
+
+	/* setup private data which can be retrieved when required */
+	pcm->private_data = intelhaddata;
+	pcm->private_free = snd_intelhad_pcm_free;
+	pcm->info_flags = 0;
+	strncpy(pcm->name, card->shortname, strlen(card->shortname));
+	/* setup the ops for palyabck */
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			    &snd_intelhad_playback_ops);
+	/* allocate dma pages for ALSA stream operations
+	 * memory allocated is based on size, not max value
+	 * thus using same argument for max & size
+	 */
+	retval = snd_pcm_lib_preallocate_pages_for_all(pcm,
+			SNDRV_DMA_TYPE_DEV, NULL,
+			HAD_MAX_BUFFER, HAD_MAX_BUFFER);
+
+	if (card->dev == NULL)
+		pr_debug("card->dev is NULL!!!!! Should not be this case\n");
+	else if (card->dev->dma_mask == NULL)
+		pr_debug("hdmi_audio_probe dma_mask is NULL!!!!!\n");
+	else
+		pr_debug("hdmi_audio_probe dma_mask is : %d\n", card->dev->dma_mask);
+
+	if (retval)
+		goto err;
+
+	/* internal function call to register device with ALSA */
+	retval = snd_intelhad_create(intelhaddata, card);
+	if (retval)
+		goto err;
+
+	card->private_data = &intelhaddata;
+	retval = snd_card_register(card);
+	if (retval)
+		goto err;
+
+	/* IEC958 controls */
+	retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask,
+						intelhaddata));
+	if (retval < 0)
+		goto err;
+	retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958,
+						intelhaddata));
+	if (retval < 0)
+		goto err;
+
+	init_channel_allocations();
+
+	/* Register channel map controls */
+	retval = had_register_chmap_ctls(intelhaddata, pcm);
+	if (retval < 0)
+		goto err;
+
+	intelhaddata->dev = &devptr->dev;
+	pm_runtime_set_active(intelhaddata->dev);
+	pm_runtime_enable(intelhaddata->dev);
+
+	mutex_unlock(&had_mutex);
+	retval = mid_hdmi_audio_register(&had_interface, intelhaddata);
+	if (retval) {
+		pr_err("registering with display driver failed %#x\n", retval);
+		snd_card_free(card);
+		goto free_hadstream;
+	}
+
+	intelhaddata->hw_silence = 1;
+	/* PIPE A is used for HDMI*/
+	intelhaddata->audio_reg_base = 0x65000;
+	intelhaddata->ops = &had_ops_v2;
+
+	return retval;
+err:
+	snd_card_free(card);
+unlock_mutex:
+	mutex_unlock(&had_mutex);
+free_hadstream:
+	kfree(had_stream);
+	pm_runtime_disable(intelhaddata->dev);
+	intelhaddata->dev = NULL;
+free_haddata:
+	kfree(intelhaddata);
+	intelhaddata = NULL;
+	pr_err("Error returned from %s api %#x\n", __func__, retval);
+	return retval;
+}
+
+/**
+ * hdmi_audio_remove - removes the alsa card
+ *
+ *@haddata: pointer to HAD private data
+ *
+ * This function is called when the hdmi cable is un-plugged. This function
+ * free the sound card.
+ */
+static int hdmi_audio_remove(struct platform_device *devptr)
+{
+	struct snd_intelhad *intelhaddata = had_data;
+	int caps;
+
+	pr_debug("Enter %s\n", __func__);
+
+	if (!intelhaddata)
+		return 0;
+
+	if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) {
+		caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
+		had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps);
+		had_set_caps(HAD_SET_DISABLE_AUDIO, NULL);
+	}
+	snd_card_free(intelhaddata->card);
+	kfree(intelhaddata->private_data);
+	kfree(intelhaddata);
+	return 0;
+}
+
+static int had_pm_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int had_pm_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+
+static int had_pm_runtime_idle(struct device *dev)
+{
+	return pm_schedule_suspend(dev, HAD_SUSPEND_DELAY);
+}
+
+const struct dev_pm_ops had_pm_ops = {
+	.runtime_idle = had_pm_runtime_idle,
+	.runtime_suspend = had_pm_runtime_suspend,
+	.runtime_resume = had_pm_runtime_resume,
+};
+
+static const struct acpi_device_id had_acpi_ids[] = {
+	{ "HAD0F28", 0 },
+	{ "HAD022A8", 0 },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, had_acpi_ids);
+
+static struct platform_driver had_driver = {
+	.probe =        hdmi_audio_probe,
+	.remove		= hdmi_audio_remove,
+	.suspend =      NULL,
+	.resume =       NULL,
+	.driver		= {
+		.name	= HDMI_AUDIO_DRIVER,
+#ifdef CONFIG_PM
+		.pm	= &had_pm_ops,
+#endif
+		.acpi_match_table = ACPI_PTR(had_acpi_ids),
+	},
+};
+
+/*
+* alsa_card_intelhad_init- driver init function
+* This function is called when driver module is inserted
+*/
+static int __init alsa_card_intelhad_init(void)
+{
+	int retval;
+
+	pr_debug("Enter %s\n", __func__);
+
+	pr_info("******** HAD DRIVER loading.. Ver: %s\n",
+					HAD_DRIVER_VERSION);
+
+	retval = platform_driver_register(&had_driver);
+	if (retval < 0) {
+		pr_err("Platform driver register failed\n");
+		return retval;
+	}
+
+	pr_debug("init complete\n");
+	return retval;
+}
+
+/**
+* alsa_card_intelhad_exit- driver exit function
+* This function is called when driver module is removed
+*/
+static void __exit alsa_card_intelhad_exit(void)
+{
+	pr_debug("had_exit called\n");
+	platform_driver_unregister(&had_driver);
+}
+late_initcall(alsa_card_intelhad_init);
+module_exit(alsa_card_intelhad_exit);
diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.h b/sound/hdmi_audio/intel_mid_hdmi_audio.h
new file mode 100644
index 0000000..7c54b97
--- /dev/null
+++ b/sound/hdmi_audio/intel_mid_hdmi_audio.h
@@ -0,0 +1,740 @@
+/*
+ *   intel_mid_hdmi_audio.h - Intel HDMI audio driver for MID
+ *
+ *  Copyright (C) 2010 Intel Corp
+ *  Authors:	Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ *		Ramesh Babu K V	<ramesh.babu@intel.com>
+ *		Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver for Intel MID HDMI audio controller
+ */
+#ifndef __INTEL_MID_HDMI_AUDIO_H
+#define __INTEL_MID_HDMI_AUDIO_H
+
+#include <linux/types.h>
+#include <sound/initval.h>
+#include <linux/version.h>
+#include <linux/pm_runtime.h>
+#include <sound/asoundef.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <hdmi_audio_if.h>
+
+#define OSPM_DISPLAY_ISLAND	0x40
+
+typedef enum _UHBUsage {
+	OSPM_UHB_ONLY_IF_ON = 0,
+	OSPM_UHB_FORCE_POWER_ON,
+} UHBUsage;
+
+bool ospm_power_using_hw_begin(int hw_island, UHBUsage usage);
+void ospm_power_using_hw_end(int hw_island);
+
+/*
+ * Use this function to do an instantaneous check for if the hw is on.
+ * Only use this in cases where you know the g_state_change_mutex
+ * is already held such as in irq install/uninstall and you need to
+ * prevent a deadlock situation.  Otherwise use ospm_power_using_hw_begin().
+ */
+bool ospm_power_is_hw_on(int hw_islands);
+
+#define HAD_DRIVER_VERSION	"0.01.003"
+#define HAD_MAX_DEVICES		1
+#define HAD_MIN_CHANNEL		2
+#define HAD_MAX_CHANNEL		8
+#define HAD_NUM_OF_RING_BUFS	4
+
+/* Assume 192KHz, 8channel, 25msec period */
+#define HAD_MAX_BUFFER		(600*1024)
+#define HAD_MIN_BUFFER		(32*1024)
+#define HAD_MAX_PERIODS		4
+#define HAD_MIN_PERIODS		4
+#define HAD_MAX_PERIOD_BYTES	(HAD_MAX_BUFFER/HAD_MIN_PERIODS)
+#define HAD_MIN_PERIOD_BYTES	256
+#define HAD_FIFO_SIZE		0 /* fifo not being used */
+#define MAX_SPEAKERS		8
+/* TODO: Add own tlv when channel map is ported for user space */
+#define USE_ALSA_DEFAULT_TLV
+
+#define AUD_SAMPLE_RATE_32	32000
+#define AUD_SAMPLE_RATE_44_1	44100
+#define AUD_SAMPLE_RATE_48	48000
+#define AUD_SAMPLE_RATE_88_2	88200
+#define AUD_SAMPLE_RATE_96	96000
+#define AUD_SAMPLE_RATE_176_4	176400
+#define AUD_SAMPLE_RATE_192	192000
+
+#define HAD_MIN_RATE		AUD_SAMPLE_RATE_32
+#define HAD_MAX_RATE		AUD_SAMPLE_RATE_192
+
+#define DRIVER_NAME		"intelmid_hdmi_audio"
+#define DIS_SAMPLE_RATE_25_2	25200
+#define DIS_SAMPLE_RATE_27	27000
+#define DIS_SAMPLE_RATE_54	54000
+#define DIS_SAMPLE_RATE_74_25	74250
+#define DIS_SAMPLE_RATE_148_5	148500
+#define HAD_REG_WIDTH		0x08
+#define HAD_MAX_HW_BUFS		0x04
+#define HAD_MAX_DIP_WORDS		16
+#define INTEL_HAD		"IntelHDMI"
+
+/* _AUD_CONFIG register MASK */
+#define AUD_CONFIG_MASK_UNDERRUN	0xC0000000
+#define AUD_CONFIG_MASK_SRDBG		0x00000002
+#define AUD_CONFIG_MASK_FUNCRST		0x00000001
+
+#define MAX_CNT			0xFF
+#define HAD_SUSPEND_DELAY	1000
+
+#define OTM_HDMI_ELD_SIZE 84
+
+typedef union {
+	uint8_t eld_data[OTM_HDMI_ELD_SIZE];
+	#pragma pack(1)
+	struct {
+		/* Byte[0] = ELD Version Number */
+		union {
+			uint8_t   byte0;
+			struct {
+				uint8_t reserved:3; /* Reserf */
+				uint8_t eld_ver:5; /* ELD Version Number */
+						/* 00000b - reserved
+						 * 00001b - first rev, obsoleted
+						 * 00010b - version 2, supporting CEA version 861D or below
+						 * 00011b:11111b - reserved
+						 * for future
+						 */
+			};
+		};
+
+		/* Byte[1] = Vendor Version Field */
+		union {
+			uint8_t vendor_version;
+			struct {
+				uint8_t reserved1:3;
+				uint8_t veld_ver:5; /* Version number of the ELD
+						     * extension. This value is
+						     * provisioned and unique to
+						     * each vendor.
+						     */
+			};
+		};
+
+		/* Byte[2] = Baseline Length field */
+		uint8_t baseline_eld_length; /* Length of the Baseline structure
+					      *	divided by Four.
+					      */
+
+		/* Byte [3] = Reserved for future use */
+		uint8_t byte3;
+
+		/* Starting of the BaseLine EELD structure
+		 * Byte[4] = Monitor Name Length
+		 */
+		union {
+			uint8_t byte4;
+			struct {
+				uint8_t mnl:5;
+				uint8_t cea_edid_rev_id:3;
+			};
+		};
+
+		/* Byte[5] = Capabilities */
+		union {
+			uint8_t capabilities;
+			struct {
+				uint8_t hdcp:1; /* HDCP support */
+				uint8_t ai_support:1;   /* AI support */
+				uint8_t connection_type:2; /* Connection type
+							    * 00 - HDMI
+							    * 01 - DP
+							    * 10 -11  Reserved
+							    * for future
+							    * connection types
+							    */
+				uint8_t sadc:4; /* Indicates number of 3 bytes
+						 * Short Audio Descriptors.
+						 */
+			};
+		};
+
+		/* Byte[6] = Audio Synch Delay */
+		uint8_t audio_synch_delay; /* Amount of time reported by the
+					    * sink that the video trails audio
+					    * in milliseconds.
+					    */
+
+		/* Byte[7] = Speaker Allocation Block */
+		union {
+			uint8_t speaker_allocation_block;
+			struct {
+				uint8_t flr:1; /*Front Left and Right channels*/
+				uint8_t lfe:1; /*Low Frequency Effect channel*/
+				uint8_t fc:1;  /*Center transmission channel*/
+				uint8_t rlr:1; /*Rear Left and Right channels*/
+				uint8_t rc:1; /*Rear Center channel*/
+				uint8_t flrc:1; /*Front left and Right of Center
+						 *transmission channels
+						 */
+				uint8_t rlrc:1; /*Rear left and Right of Center
+						 *transmission channels
+						 */
+				uint8_t reserved3:1; /* Reserved */
+			};
+		};
+
+		/* Byte[8 - 15] - 8 Byte port identification value */
+		uint8_t port_id_value[8];
+
+		/* Byte[16 - 17] - 2 Byte Manufacturer ID */
+		uint8_t manufacturer_id[2];
+
+		/* Byte[18 - 19] - 2 Byte Product ID */
+		uint8_t product_id[2];
+
+		/* Byte [20-83] - 64 Bytes of BaseLine Data */
+		uint8_t mn_sand_sads[64]; /* This will include
+					   * - ASCII string of Monitor name
+					   * - List of 3 byte SADs
+					   * - Zero padding
+					   */
+
+		/* Vendor ELD Block should continue here!
+		 * No Vendor ELD block defined as of now.
+		 */
+	};
+	#pragma pack()
+} otm_hdmi_eld_t;
+
+/**
+ * enum had_status - Audio stream states
+ *
+ * @STREAM_INIT: Stream initialized
+ * @STREAM_RUNNING: Stream running
+ * @STREAM_PAUSED: Stream paused
+ * @STREAM_DROPPED: Stream dropped
+ */
+enum had_stream_status {
+	STREAM_INIT = 0,
+	STREAM_RUNNING = 1,
+	STREAM_PAUSED = 2,
+	STREAM_DROPPED = 3
+};
+
+/**
+ * enum had_status_stream - HAD stream states
+ */
+enum had_status_stream {
+	HAD_INIT = 0,
+	HAD_RUNNING_STREAM,
+};
+
+enum had_drv_status {
+	HAD_DRV_CONNECTED,
+	HAD_DRV_RUNNING,
+	HAD_DRV_DISCONNECTED,
+	HAD_DRV_SUSPENDED,
+	HAD_DRV_ERR,
+};
+
+/* enum intel_had_aud_buf_type - HDMI controller ring buffer types */
+enum intel_had_aud_buf_type {
+	HAD_BUF_TYPE_A = 0,
+	HAD_BUF_TYPE_B = 1,
+	HAD_BUF_TYPE_C = 2,
+	HAD_BUF_TYPE_D = 3,
+};
+
+enum num_aud_ch {
+	CH_STEREO = 0,
+	CH_THREE_FOUR = 1,
+	CH_FIVE_SIX = 2,
+	CH_SEVEN_EIGHT = 3
+};
+
+
+/* HDMI controller register offsets */
+enum hdmi_ctrl_reg_offset_v1 {
+	AUD_CONFIG		= 0x0,
+	AUD_CH_STATUS_0		= 0x08,
+	AUD_CH_STATUS_1		= 0x0C,
+	AUD_HDMI_CTS		= 0x10,
+	AUD_N_ENABLE		= 0x14,
+	AUD_SAMPLE_RATE		= 0x18,
+	AUD_BUF_CONFIG		= 0x20,
+	AUD_BUF_CH_SWAP		= 0x24,
+	AUD_BUF_A_ADDR		= 0x40,
+	AUD_BUF_A_LENGTH	= 0x44,
+	AUD_BUF_B_ADDR		= 0x48,
+	AUD_BUF_B_LENGTH	= 0x4c,
+	AUD_BUF_C_ADDR		= 0x50,
+	AUD_BUF_C_LENGTH	= 0x54,
+	AUD_BUF_D_ADDR		= 0x58,
+	AUD_BUF_D_LENGTH	= 0x5c,
+	AUD_CNTL_ST		= 0x60,
+	AUD_HDMI_STATUS		= 0x68,
+	AUD_HDMIW_INFOFR	= 0x114,
+};
+
+/*
+ * Delta changes in HDMI controller register offsets
+ * compare to v1 version
+ */
+
+enum hdmi_ctrl_reg_offset_v2 {
+	AUD_HDMI_STATUS_v2	= 0x64,
+	AUD_HDMIW_INFOFR_v2	= 0x68,
+};
+
+/*
+ * CEA speaker placement:
+ *
+ *  FL  FLC   FC   FRC   FR
+ *
+ *                         LFE
+ *
+ *  RL  RLC   RC   RRC   RR
+ *
+ * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
+ * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
+ */
+enum cea_speaker_placement {
+	FL  = (1 <<  0),        /* Front Left           */
+	FC  = (1 <<  1),        /* Front Center         */
+	FR  = (1 <<  2),        /* Front Right          */
+	FLC = (1 <<  3),        /* Front Left Center    */
+	FRC = (1 <<  4),        /* Front Right Center   */
+	RL  = (1 <<  5),        /* Rear Left            */
+	RC  = (1 <<  6),        /* Rear Center          */
+	RR  = (1 <<  7),        /* Rear Right           */
+	RLC = (1 <<  8),        /* Rear Left Center     */
+	RRC = (1 <<  9),        /* Rear Right Center    */
+	LFE = (1 << 10),        /* Low Frequency Effect */
+};
+
+struct cea_channel_speaker_allocation {
+	int ca_index;
+	int speakers[8];
+
+	/* derived values, just for convenience */
+	int channels;
+	int spk_mask;
+};
+
+struct channel_map_table {
+	unsigned char map;              /* ALSA API channel map position */
+	unsigned char cea_slot;         /* CEA slot value */
+	int spk_mask;                   /* speaker position bit mask */
+};
+
+/**
+ * union aud_cfg - Audio configuration
+ *
+ * @cfg_regx: individual register bits
+ * @cfg_regval: full register value
+ *
+ */
+union aud_cfg {
+	struct {
+		u32 aud_en:1;
+		u32 layout:1;
+		u32 fmt:2;
+		u32 num_ch:2;
+		u32 rsvd0:1;
+		u32 set:1;
+		u32 flat:1;
+		u32 val_bit:1;
+		u32 user_bit:1;
+		u32 underrun:1;
+		u32 rsvd1:20;
+	} cfg_regx;
+	struct {
+		u32 aud_en:1;
+		u32 layout:1;
+		u32 fmt:2;
+		u32 num_ch:3;
+		u32 set:1;
+		u32 flat:1;
+		u32 val_bit:1;
+		u32 user_bit:1;
+		u32 underrun:1;
+		u32 packet_mode:1;
+		u32 left_align:1;
+		u32 bogus_sample:1;
+		u32 dp_modei:1;
+		u32 rsvd:16;
+	} cfg_regx_v2;
+	u32 cfg_regval;
+};
+
+/**
+ * union aud_ch_status_0 - Audio Channel Status 0 Attributes
+ *
+ * @status_0_regx:individual register bits
+ * @status_0_regval:full register value
+ *
+ */
+union aud_ch_status_0 {
+	struct {
+		u32 ch_status:1;
+		u32 lpcm_id:1;
+		u32 cp_info:1;
+		u32 format:3;
+		u32 mode:2;
+		u32 ctg_code:8;
+		u32 src_num:4;
+		u32 ch_num:4;
+		u32 samp_freq:4;
+		u32 clk_acc:2;
+		u32 rsvd:2;
+	} status_0_regx;
+	u32 status_0_regval;
+};
+
+/**
+ * union aud_ch_status_1 - Audio Channel Status 1 Attributes
+ *
+ * @status_1_regx: individual register bits
+ * @status_1_regval: full register value
+ *
+ */
+union aud_ch_status_1 {
+	struct {
+		u32 max_wrd_len:1;
+		u32 wrd_len:3;
+		u32 rsvd:28;
+		} status_1_regx;
+	u32 status_1_regval;
+};
+
+/**
+ * union aud_hdmi_cts - CTS register
+ *
+ * @cts_regx: individual register bits
+ * @cts_regval: full register value
+ *
+ */
+union aud_hdmi_cts {
+	struct {
+		u32 cts_val:20;
+		u32 en_cts_prog:1;
+		u32 rsvd:11;
+	} cts_regx;
+	struct {
+		u32 cts_val:24;
+		u32 en_cts_prog:1;
+		u32 rsvd:7;
+	} cts_regx_v2;
+	u32 cts_regval;
+};
+
+/**
+ * union aud_hdmi_n_enable - N register
+ *
+ * @n_regx: individual register bits
+ * @n_regval: full register value
+ *
+ */
+union aud_hdmi_n_enable {
+	struct {
+		u32 n_val:20;
+		u32 en_n_prog:1;
+		u32 rsvd:11;
+	} n_regx;
+	struct {
+		u32 n_val:24;
+		u32 en_n_prog:1;
+		u32 rsvd:7;
+	} n_regx_v2;
+	u32 n_regval;
+};
+
+/**
+ * union aud_buf_config -  Audio Buffer configurations
+ *
+ * @buf_cfg_regx: individual register bits
+ * @buf_cfgval: full register value
+ *
+ */
+union aud_buf_config {
+	struct {
+		u32 fifo_width:8;
+		u32 rsvd0:8;
+		u32 aud_delay:8;
+		u32 rsvd1:8;
+	} buf_cfg_regx;
+	struct {
+		u32 audio_fifo_watermark:8;
+		u32 dma_fifo_watermark:3;
+		u32 rsvd0:5;
+		u32 aud_delay:8;
+		u32 rsvd1:8;
+	} buf_cfg_regx_v2;
+	u32 buf_cfgval;
+};
+
+/**
+ * union aud_buf_ch_swap - Audio Sample Swapping offset
+ *
+ * @buf_ch_swap_regx: individual register bits
+ * @buf_ch_swap_val: full register value
+ *
+ */
+union aud_buf_ch_swap {
+	struct {
+		u32 first_0:3;
+		u32 second_0:3;
+		u32 first_1:3;
+		u32 second_1:3;
+		u32 first_2:3;
+		u32 second_2:3;
+		u32 first_3:3;
+		u32 second_3:3;
+		u32 rsvd:8;
+	} buf_ch_swap_regx;
+	u32 buf_ch_swap_val;
+};
+
+/**
+ * union aud_buf_addr - Address for Audio Buffer
+ *
+ * @buf_addr_regx: individual register bits
+ * @buf_addr_val: full register value
+ *
+ */
+union aud_buf_addr {
+	struct {
+		u32 valid:1;
+		u32 intr_en:1;
+		u32 rsvd:4;
+		u32 addr:26;
+	} buf_addr_regx;
+	u32 buf_addr_val;
+};
+
+/**
+ * union aud_buf_len - Length of Audio Buffer
+ *
+ * @buf_len_regx: individual register bits
+ * @buf_len_val: full register value
+ *
+ */
+union aud_buf_len {
+	struct {
+		u32 buf_len:20;
+		u32 rsvd:12;
+	} buf_len_regx;
+	u32 buf_len_val;
+};
+
+/**
+ * union aud_ctrl_st - Audio Control State Register offset
+ *
+ * @ctrl_regx: individual register bits
+ * @ctrl_val: full register value
+ *
+ */
+union aud_ctrl_st {
+	struct {
+		u32 ram_addr:4;
+		u32 eld_ack:1;
+		u32 eld_addr:4;
+		u32 eld_buf_size:5;
+		u32 eld_valid:1;
+		u32 cp_ready:1;
+		u32 dip_freq:2;
+		u32 dip_idx:3;
+		u32 dip_en_sta:4;
+		u32 rsvd:7;
+	} ctrl_regx;
+	u32 ctrl_val;
+};
+
+/**
+ * union aud_info_frame1 - Audio HDMI Widget Data Island Packet offset
+ *
+ * @fr1_regx: individual register bits
+ * @fr1_val: full register value
+ *
+ */
+union aud_info_frame1 {
+	struct {
+		u32 pkt_type:8;
+		u32 ver_num:8;
+		u32 len:5;
+		u32 rsvd:11;
+	} fr1_regx;
+	u32 fr1_val;
+};
+
+/**
+ * union aud_info_frame2 - DIP frame 2
+ *
+ * @fr2_regx: individual register bits
+ * @fr2_val: full register value
+ *
+ */
+union aud_info_frame2 {
+	struct {
+		u32 chksum:8;
+		u32 chnl_cnt:3;
+		u32 rsvd0:1;
+		u32 coding_type:4;
+		u32 smpl_size:2;
+		u32 smpl_freq:3;
+		u32 rsvd1:3;
+		u32 format:8;
+	} fr2_regx;
+	u32 fr2_val;
+};
+
+/**
+ * union aud_info_frame3 - DIP frame 3
+ *
+ * @fr3_regx: individual register bits
+ * @fr3_val: full register value
+ *
+ */
+union aud_info_frame3 {
+	struct {
+		u32 chnl_alloc:8;
+		u32 rsvd0:3;
+		u32 lsv:4;
+		u32 dm_inh:1;
+		u32 rsvd1:16;
+	} fr3_regx;
+	u32 fr3_val;
+};
+
+
+struct pcm_stream_info {
+	int		str_id;
+	void		*had_substream;
+	void		(*period_elapsed)(void *had_substream);
+	u32		buffer_ptr;
+	u64		buffer_rendered;
+	u32		ring_buf_size;
+	int		sfreq;
+};
+
+struct ring_buf_info {
+	uint32_t	buf_addr;
+	uint32_t	buf_size;
+	uint8_t		is_valid;
+};
+
+struct had_stream_pvt {
+	enum had_stream_status		stream_status;
+	int				stream_ops;
+	ssize_t				dbg_cum_bytes;
+};
+
+struct had_pvt_data {
+	enum had_status_stream		stream_type;
+};
+
+struct had_callback_ops {
+	had_event_call_back intel_had_event_call_back;
+};
+
+/**
+ * struct snd_intelhad - intelhad driver structure
+ *
+ * @card: ptr to hold card details
+ * @card_index: sound card index
+ * @card_id: detected sound card id
+ * @reg_ops: register operations to program registers
+ * @query_ops: caps call backs for get/set operations
+ * @drv_status: driver status
+ * @buf_info: ring buffer info
+ * @stream_info: stream information
+ * @eeld: holds EELD info
+ * @curr_buf: pointer to hold current active ring buf
+ * @valid_buf_cnt: ring buffer count for stream
+ * @had_spinlock: driver lock
+ * @aes_bits: IEC958 status bits
+ * @buff_done: id of current buffer done intr
+ * @dev: platoform device handle
+ * @kctl: holds kctl ptrs used for channel map
+ * @chmap: holds channel map info
+ * @audio_reg_base: hdmi audio register base offset
+ * @hw_silence: flag indicates SoC support for HW silence/Keep alive
+ * @ops: holds ops functions based on platform
+ */
+struct snd_intelhad {
+	struct snd_card	*card;
+	int		card_index;
+	char		*card_id;
+	struct hdmi_audio_registers_ops	reg_ops;
+	struct hdmi_audio_query_set_ops	query_ops;
+	enum had_drv_status	drv_status;
+	struct		ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS];
+	struct		pcm_stream_info stream_info;
+	otm_hdmi_eld_t	eeld;
+	enum		intel_had_aud_buf_type curr_buf;
+	int		valid_buf_cnt;
+	unsigned int	aes_bits;
+	int flag_underrun;
+	struct had_pvt_data *private_data;
+	spinlock_t had_spinlock;
+	enum		intel_had_aud_buf_type buff_done;
+	struct device *dev;
+	struct snd_kcontrol *kctl;
+	struct snd_pcm_chmap *chmap;
+	unsigned int	audio_reg_base;
+	bool		hw_silence;
+	struct had_ops	*ops;
+};
+
+struct had_ops {
+	void (*enable_audio)(struct snd_pcm_substream *substream,
+			u8 enable);
+	void (*reset_audio)(u8 reset);
+	int (*prog_n)(u32 aud_samp_freq, u32 *n_param,
+			struct snd_intelhad *intelhaddata);
+	void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 n_param,
+			struct snd_intelhad *intelhaddata);
+	int (*audio_ctrl)(struct snd_pcm_substream *substream,
+				struct snd_intelhad *intelhaddata);
+	void (*prog_dip)(struct snd_pcm_substream *substream,
+				struct snd_intelhad *intelhaddata);
+	void (*handle_underrun)(struct snd_intelhad *intelhaddata);
+};
+
+
+int had_event_handler(enum had_event_type event_type, void *data);
+
+int hdmi_audio_query(void *drv_data, hdmi_audio_event_t event);
+int hdmi_audio_suspend(void *drv_data, hdmi_audio_event_t event);
+int hdmi_audio_resume(void *drv_data);
+int hdmi_audio_mode_change(struct snd_pcm_substream *substream);
+extern struct snd_pcm_ops snd_intelhad_playback_ops;
+
+int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream,
+					struct snd_intelhad *intelhaddata,
+					int flag_silence);
+int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata,
+					int start, int end);
+int snd_intelhad_invd_buffer(int start, int end);
+inline int snd_intelhad_read_len(struct snd_intelhad *intelhaddata);
+void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata);
+
+/* Register access functions */
+inline int had_get_hwstate(struct snd_intelhad *intelhaddata);
+inline int had_get_caps(enum had_caps_list query_element, void *capabilties);
+inline int had_set_caps(enum had_caps_list set_element, void *capabilties);
+inline int had_read_register(uint32_t reg_addr, uint32_t *data);
+inline int had_write_register(uint32_t reg_addr, uint32_t data);
+inline int had_read_modify(uint32_t reg_addr, uint32_t data, uint32_t mask);
+#endif
diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio_if.c b/sound/hdmi_audio/intel_mid_hdmi_audio_if.c
new file mode 100644
index 0000000..9631642
--- /dev/null
+++ b/sound/hdmi_audio/intel_mid_hdmi_audio_if.c
@@ -0,0 +1,514 @@
+/*
+ *   intel_mid_hdmi_audio_if.c - Intel HDMI audio driver for MID
+ *
+ *  Copyright (C) 2010 Intel Corp
+ *  Authors:	Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ *		Ramesh Babu K V <ramesh.babu@intel.com>
+ *		Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver for Intel MID HDMI audio controller.  This file contains
+ * interface functions exposed to HDMI Display driver and code to register
+ * with ALSA framework..
+ */
+
+#define pr_fmt(fmt)		"had: " fmt
+
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <sound/pcm.h>
+#include <sound/core.h>
+#include "intel_mid_hdmi_audio.h"
+
+
+/**
+ * hdmi_audio_query - hdmi audio query function
+ *
+ *@haddata: pointer to HAD private data
+ *@event: audio event for which this method is invoked
+ *
+ * This function is called by client driver to query the
+ * hdmi audio.
+ */
+int hdmi_audio_query(void *haddata, hdmi_audio_event_t event)
+{
+	struct snd_pcm_substream *substream = NULL;
+	struct had_pvt_data *had_stream;
+	unsigned long flag_irqs;
+	struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata;
+
+	if (intelhaddata->stream_info.had_substream)
+		substream = intelhaddata->stream_info.had_substream;
+	had_stream = intelhaddata->private_data;
+	switch (event.type) {
+	case HAD_EVENT_QUERY_IS_AUDIO_BUSY:
+		spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+
+		if ((had_stream->stream_type == HAD_RUNNING_STREAM) ||
+			substream) {
+			spin_unlock_irqrestore(&intelhaddata->had_spinlock,
+						flag_irqs);
+			pr_debug("Audio stream active\n");
+			return -EBUSY;
+		}
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+	break;
+
+	case HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED:
+		spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+		if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) {
+			spin_unlock_irqrestore(&intelhaddata->had_spinlock,
+						flag_irqs);
+			pr_debug("Audio is suspended\n");
+			return 1;
+		}
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+	break;
+
+	default:
+		pr_debug("error un-handled event !!\n");
+		return -EINVAL;
+	break;
+
+	}
+
+	return 0;
+}
+
+/**
+ * hdmi_audio_suspend - power management suspend function
+ *
+ *@haddata: pointer to HAD private data
+ *@event: pm event for which this method is invoked
+ *
+ * This function is called by client driver to suspend the
+ * hdmi audio.
+ */
+int hdmi_audio_suspend(void *haddata, hdmi_audio_event_t event)
+{
+	int caps, retval = 0;
+	struct had_pvt_data *had_stream;
+	unsigned long flag_irqs;
+	struct snd_pcm_substream *substream;
+	struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata;
+
+	pr_debug("Enter:%s", __func__);
+
+	had_stream = intelhaddata->private_data;
+	substream = intelhaddata->stream_info.had_substream;
+
+	if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) {
+		pr_err("audio stream is active\n");
+		return -EAGAIN;
+	}
+
+
+	spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+	if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		pr_debug("had not connected\n");
+		return retval;
+	}
+
+	if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) {
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		pr_debug("had already suspended\n");
+		return retval;
+	}
+
+	intelhaddata->drv_status = HAD_DRV_SUSPENDED;
+	spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+	/*
+	 * ToDo: Need to disable UNDERRUN interrupts as well
+	 *  caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
+	 */
+	caps = HDMI_AUDIO_BUFFER_DONE;
+	had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps);
+	had_set_caps(HAD_SET_DISABLE_AUDIO, NULL);
+	pr_debug("Exit:%s", __func__);
+	return retval;
+}
+
+/**
+ * hdmi_audio_resume - power management resume function
+ *
+ *@haddata: pointer to HAD private data
+ *
+ * This function is called by client driver to resume the
+ * hdmi audio.
+ */
+int hdmi_audio_resume(void *haddata)
+{
+	int caps, retval = 0;
+	struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata;
+	unsigned long flag_irqs;
+
+	pr_debug("Enter:%s", __func__);
+
+	spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+	if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		pr_debug("had not connected\n");
+		return 0;
+	}
+
+	if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) {
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		pr_err("had is not in suspended state\n");
+		return 0;
+	}
+
+	if (had_get_hwstate(intelhaddata)) {
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		pr_err("Failed to resume. Device not accessible\n");
+		return -ENODEV;
+	}
+
+	intelhaddata->drv_status = HAD_DRV_CONNECTED;
+	spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+	/*
+	 * ToDo: Need to enable UNDERRUN interrupts as well
+	 * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
+	 */
+	caps = HDMI_AUDIO_BUFFER_DONE;
+	retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps);
+	retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL);
+	pr_debug("Exit:%s", __func__);
+	return retval;
+}
+
+static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata,
+		enum intel_had_aud_buf_type buf_id)
+{
+	int i, intr_count = 0;
+	enum intel_had_aud_buf_type buff_done;
+	u32 buf_size, buf_addr;
+	struct had_pvt_data *had_stream;
+	unsigned long flag_irqs;
+
+	had_stream = intelhaddata->private_data;
+
+	buff_done = buf_id;
+
+	intr_count = snd_intelhad_read_len(intelhaddata);
+	if (intr_count > 1) {
+		/* In case of active playback */
+		pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n",
+				(intr_count - 1));
+		if (intr_count > 3)
+			return intr_count;
+
+		buf_id += (intr_count - 1);
+		/* Reprogram registers*/
+		for (i = buff_done; i < buf_id; i++) {
+			int j = i % 4;
+
+			buf_size = intelhaddata->buf_info[j].buf_size;
+			buf_addr = intelhaddata->buf_info[j].buf_addr;
+			had_write_register(AUD_BUF_A_LENGTH +
+					(j * HAD_REG_WIDTH), buf_size);
+			had_write_register(
+					AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH),
+					(buf_addr | BIT(0) | BIT(1)));
+		}
+		buf_id = buf_id % 4;
+		spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+		intelhaddata->buff_done = buf_id;
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+	}
+
+	return intr_count;
+}
+
+int had_process_buffer_done(struct snd_intelhad *intelhaddata)
+{
+	int retval = 0;
+	u32 len = 1;
+	enum intel_had_aud_buf_type buf_id;
+	enum intel_had_aud_buf_type buff_done;
+	struct pcm_stream_info *stream;
+	u32 buf_size;
+	struct had_pvt_data *had_stream;
+	int intr_count;
+	enum had_status_stream		stream_type;
+	unsigned long flag_irqs;
+
+	had_stream = intelhaddata->private_data;
+	stream = &intelhaddata->stream_info;
+	intr_count = 1;
+
+	spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+	if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		pr_err("%s:Device already disconnected\n", __func__);
+		return retval;
+	}
+	buf_id = intelhaddata->curr_buf;
+	intelhaddata->buff_done = buf_id;
+	buff_done = intelhaddata->buff_done;
+	buf_size = intelhaddata->buf_info[buf_id].buf_size;
+	stream_type = had_stream->stream_type;
+
+	pr_debug("Enter:%s buf_id=%d", __func__, buf_id);
+
+	/* Every debug statement has an implication
+	 * of ~5msec. Thus, avoid having >3 debug statements
+	 * for each buffer_done handling.
+	 */
+
+	/* Check for any intr_miss in case of active playback */
+	if (had_stream->stream_type == HAD_RUNNING_STREAM) {
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		intr_count = had_chk_intrmiss(intelhaddata, buf_id);
+		if (!intr_count || (intr_count > 3)) {
+			pr_err("HAD SW state in non-recoverable!!! mode\n");
+			pr_err("Already played stale data\n");
+			return retval;
+		}
+		buf_id += (intr_count - 1);
+		buf_id = buf_id % 4;
+		spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+	}
+
+	intelhaddata->buf_info[buf_id].is_valid = true;
+	if (intelhaddata->valid_buf_cnt-1 == buf_id) {
+		if (had_stream->stream_type >= HAD_RUNNING_STREAM)
+			intelhaddata->curr_buf = HAD_BUF_TYPE_A;
+	} else
+		intelhaddata->curr_buf = buf_id + 1;
+
+	spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+
+	if (had_get_hwstate(intelhaddata)) {
+		pr_err("HDMI cable plugged-out\n");
+		return retval;
+	}
+
+	/*Reprogram the registers with addr and length*/
+	had_write_register(AUD_BUF_A_LENGTH +
+			(buf_id * HAD_REG_WIDTH), buf_size);
+	had_write_register(AUD_BUF_A_ADDR+(buf_id * HAD_REG_WIDTH),
+			intelhaddata->buf_info[buf_id].buf_addr|
+			BIT(0) | BIT(1));
+
+	had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH),
+					&len);
+	pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id);
+
+	/* In case of actual data,
+	 * report buffer_done to above ALSA layer
+	 */
+	buf_size =  intelhaddata->buf_info[buf_id].buf_size;
+	if (stream_type >= HAD_RUNNING_STREAM) {
+		intelhaddata->stream_info.buffer_rendered +=
+			(intr_count * buf_size);
+		stream->period_elapsed(stream->had_substream);
+	}
+
+	return retval;
+}
+
+int had_process_buffer_underrun(struct snd_intelhad *intelhaddata)
+{
+	int retval = 0;
+	enum intel_had_aud_buf_type buf_id;
+	struct pcm_stream_info *stream;
+	struct had_pvt_data *had_stream;
+	enum had_status_stream stream_type;
+	unsigned long flag_irqs;
+	int drv_status;
+
+	had_stream = intelhaddata->private_data;
+	stream = &intelhaddata->stream_info;
+
+	spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+	buf_id = intelhaddata->curr_buf;
+	stream_type = had_stream->stream_type;
+	intelhaddata->buff_done = buf_id;
+	drv_status = intelhaddata->drv_status;
+	if (stream_type == HAD_RUNNING_STREAM)
+		intelhaddata->curr_buf = HAD_BUF_TYPE_A;
+
+	spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+
+	pr_debug("Enter:%s buf_id=%d, stream_type=%d\n",
+			__func__, buf_id, stream_type);
+
+	intelhaddata->ops->handle_underrun(intelhaddata);
+
+	if (drv_status == HAD_DRV_DISCONNECTED) {
+		pr_err("%s:Device already disconnected\n", __func__);
+		return retval;
+	}
+
+	if (stream_type == HAD_RUNNING_STREAM) {
+		/* Report UNDERRUN error to above layers */
+		intelhaddata->flag_underrun = 1;
+		stream->period_elapsed(stream->had_substream);
+	}
+
+	return retval;
+}
+
+int had_process_hot_plug(struct snd_intelhad *intelhaddata)
+{
+	int retval = 0;
+	enum intel_had_aud_buf_type buf_id;
+	struct snd_pcm_substream *substream;
+	struct had_pvt_data *had_stream;
+	unsigned long flag_irqs;
+
+	pr_debug("Enter:%s", __func__);
+
+	substream = intelhaddata->stream_info.had_substream;
+	had_stream = intelhaddata->private_data;
+
+	spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+	if (intelhaddata->drv_status == HAD_DRV_CONNECTED) {
+		pr_debug("Device already connected\n");
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		return retval;
+	}
+	buf_id = intelhaddata->curr_buf;
+	intelhaddata->buff_done = buf_id;
+	intelhaddata->drv_status = HAD_DRV_CONNECTED;
+	spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+
+	pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id);
+
+	/* Safety check */
+	if (substream) {
+		pr_debug("There should not be active PB from ALSA\n");
+		pr_debug("Signifies, cable is plugged-in even before\n");
+		pr_debug("processing snd_pcm_disconnect\n");
+		/* Set runtime->state to hw_params done */
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+	}
+
+	had_build_channel_allocation_map(intelhaddata);
+
+	return retval;
+}
+
+int had_process_hot_unplug(struct snd_intelhad *intelhaddata)
+{
+	int caps, retval = 0;
+	enum intel_had_aud_buf_type buf_id;
+	struct had_pvt_data *had_stream;
+	unsigned long flag_irqs;
+
+	pr_debug("Enter:%s", __func__);
+
+	had_stream = intelhaddata->private_data;
+	buf_id = intelhaddata->curr_buf;
+
+	spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+	if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
+		pr_debug("Device already disconnected\n");
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		return retval;
+	} else {
+		/* Disable Audio */
+		caps = HDMI_AUDIO_BUFFER_DONE;
+		retval = had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps);
+		retval = had_set_caps(HAD_SET_DISABLE_AUDIO, NULL);
+		intelhaddata->ops->enable_audio(intelhaddata->stream_info.had_substream, 0);
+	}
+
+	intelhaddata->drv_status = HAD_DRV_DISCONNECTED;
+	/* Report to above ALSA layer */
+	if (intelhaddata->stream_info.had_substream != NULL) {
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__);
+		snd_pcm_stop(intelhaddata->stream_info.had_substream,
+				SNDRV_PCM_STATE_DISCONNECTED);
+		spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+	}
+
+	had_stream->stream_type = HAD_INIT;
+	spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+	kfree(intelhaddata->chmap->chmap);
+	intelhaddata->chmap->chmap = NULL;
+	pr_debug("%s: unlocked -> returned\n", __func__);
+
+	return retval;
+}
+
+/**
+ * had_event_handler - Call back function to handle events
+ *
+ * @event_type: Event type to handle
+ * @data: data related to the event_type
+ *
+ * This function is invoked to handle HDMI events from client driver.
+ */
+int had_event_handler(enum had_event_type event_type, void *data)
+{
+	int retval = 0;
+	struct snd_intelhad *intelhaddata = data;
+	enum intel_had_aud_buf_type buf_id;
+	struct snd_pcm_substream *substream;
+	struct had_pvt_data *had_stream;
+	unsigned long flag_irqs;
+
+	buf_id = intelhaddata->curr_buf;
+	had_stream = intelhaddata->private_data;
+
+	/* Switching to a function can drop atomicity even in INTR context.
+	 * Thus, a big lock is acquired to maintain atomicity.
+	 * This can be optimized later.
+	 * Currently, only buffer_done/_underrun executes in INTR context.
+	 * Also, locking is implemented separately to avoid real contention
+	 * of data(struct intelhaddata) between IRQ/SOFT_IRQ/PROCESS context.
+	 */
+	substream = intelhaddata->stream_info.had_substream;
+	switch (event_type) {
+	case HAD_EVENT_AUDIO_BUFFER_DONE:
+		retval = had_process_buffer_done(intelhaddata);
+	break;
+
+	case HAD_EVENT_AUDIO_BUFFER_UNDERRUN:
+		retval = had_process_buffer_underrun(intelhaddata);
+	break;
+
+	case HAD_EVENT_HOT_PLUG:
+		retval = had_process_hot_plug(intelhaddata);
+	break;
+
+	case HAD_EVENT_HOT_UNPLUG:
+		retval = had_process_hot_unplug(intelhaddata);
+	break;
+
+	case HAD_EVENT_MODE_CHANGING:
+		pr_debug(" called _event_handler with _MODE_CHANGE event\n");
+		/* Process only if stream is active & cable Plugged-in */
+		spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
+		if (intelhaddata->drv_status >= HAD_DRV_DISCONNECTED) {
+			spin_unlock_irqrestore(&intelhaddata->had_spinlock,
+					flag_irqs);
+			break;
+		}
+		spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
+		if ((had_stream->stream_type == HAD_RUNNING_STREAM)
+				&& substream)
+			retval = hdmi_audio_mode_change(substream);
+	break;
+
+	default:
+		pr_debug("error un-handled event !!\n");
+		retval = -EINVAL;
+	break;
+
+	}
+	return retval;
+}
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 10/15] add dependency on PM_RUNTIME
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (8 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 09/15] ALSA: Intel: Atom: add Atom non-HDAudio HDMI interface Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 11/15] hdmi_audio: Improve position reporting Pierre-Louis Bossart
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/Kconfig b/sound/Kconfig
index 75c679e..b8b4fce 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -138,6 +138,7 @@ config AC97_BUS
 config SUPPORT_HDMI
         bool "SUPPORT_HDMI"
         depends on DRM_I915
+	select PM_RUNTIME
         default n
         help
           Choose this option to support HDMI.
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 11/15] hdmi_audio: Improve position reporting
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (9 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 10/15] add dependency on PM_RUNTIME Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 12/15] hdmi_audio: Fixup some monitor Pierre-Louis Bossart
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, David Henningsson

From: David Henningsson <david.henningsson@canonical.com>

Using a hw register to calculate sub-period position reports.

This makes PulseAudio happier.

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/hdmi_audio/intel_mid_hdmi_audio.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
index f397435..611c51c 100644
--- a/sound/hdmi_audio/intel_mid_hdmi_audio.c
+++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
@@ -1550,6 +1550,8 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer(
 {
 	struct snd_intelhad *intelhaddata;
 	u32 bytes_rendered = 0;
+	u32 t;
+	int buf_id;
 
 	/* pr_debug("snd_intelhad_pcm_pointer called\n"); */
 
@@ -1560,6 +1562,14 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer(
 		return SNDRV_PCM_POS_XRUN;
 	}
 
+	buf_id = intelhaddata->curr_buf % 4;
+	had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t);
+	if (t == 0) {
+		pr_debug("discovered buffer done for buf %d\n", buf_id);
+		/* had_process_buffer_done(intelhaddata); */
+	}
+	t = intelhaddata->buf_info[buf_id].buf_size - t;
+
 	if (intelhaddata->stream_info.buffer_rendered)
 		div_u64_rem(intelhaddata->stream_info.buffer_rendered,
 			intelhaddata->stream_info.ring_buf_size,
@@ -1567,7 +1577,7 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer(
 
 	intelhaddata->stream_info.buffer_ptr = bytes_to_frames(
 						substream->runtime,
-						bytes_rendered);
+						bytes_rendered + t);
 	return intelhaddata->stream_info.buffer_ptr;
 }
 
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 12/15] hdmi_audio: Fixup some monitor
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (10 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 11/15] hdmi_audio: Improve position reporting Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 13/15] hdmi_audio: Fix mishandling of AUD_HDMI_STATUS_v2 register Pierre-Louis Bossart
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, David Henningsson

From: David Henningsson <david.henningsson@canonical.com>

I think this change was given to us, and they claimed it fixed an issue
on some monitor brand. I'm not sure what this patch actually does.

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/hdmi_audio/intel_mid_hdmi_audio.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
index 611c51c..e696c80 100644
--- a/sound/hdmi_audio/intel_mid_hdmi_audio.c
+++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
@@ -386,6 +386,7 @@ static void snd_intelhad_reset_audio_v2(u8 reset)
 static int had_prog_status_reg(struct snd_pcm_substream *substream,
 			struct snd_intelhad *intelhaddata)
 {
+	union aud_cfg cfg_val = {.cfg_regval = 0};
 	union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0};
 	union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0};
 	int format;
@@ -396,6 +397,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream,
 						IEC958_AES0_NONAUDIO)>>1;
 	ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits &
 						IEC958_AES3_CON_CLOCK)>>4;
+	cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id;
+
 	switch (substream->runtime->rate) {
 	case AUD_SAMPLE_RATE_32:
 		ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ;
@@ -474,7 +477,6 @@ int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream,
 	else
 		cfg_val.cfg_regx_v2.layout = LAYOUT1;
 
-	cfg_val.cfg_regx_v2.val_bit = 1;
 	had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
 	return 0;
 }
@@ -530,7 +532,6 @@ int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream,
 
 	}
 
-	cfg_val.cfg_regx.val_bit = 1;
 	had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
 	return 0;
 }
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 13/15] hdmi_audio: Fix mishandling of AUD_HDMI_STATUS_v2 register.
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (11 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 12/15] hdmi_audio: Fixup some monitor Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 14/15] i915: Enable LPE_PIPEA_Interrupt Pierre-Louis Bossart
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, Toyo Abe

From: Toyo Abe <toyo.abe@gmail.com>

According to the datasheet, write one to clear these UNDERRUN flag bits.
This fixes the following warning in dmesg.

[15357.574902] had: Unable to clear UNDERRUN bits

Signed-off-by: Toyo Abe <toyo.abe@gmail.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/hdmi_audio/intel_mid_hdmi_audio.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
index e696c80..b86c37a 100644
--- a/sound/hdmi_audio/intel_mid_hdmi_audio.c
+++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
@@ -1135,7 +1135,6 @@ static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata)
 		pr_debug("HDMI status =0x%x\n", hdmi_status);
 		if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) {
 			i++;
-			hdmi_status &= ~AUD_CONFIG_MASK_UNDERRUN;
 			had_write_register(AUD_HDMI_STATUS_v2, hdmi_status);
 		} else
 			break;
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 14/15] i915: Enable LPE_PIPEA_Interrupt.
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (12 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 13/15] hdmi_audio: Fix mishandling of AUD_HDMI_STATUS_v2 register Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05  2:50 ` [RFC 15/15] i915: Fix typo in comment Pierre-Louis Bossart
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, Toyo Abe

From: Toyo Abe <toyo.abe@gmail.com>

To enable interrupt, IER, IIR, and IMR must be configured appropriately.
IER setting for hdmi_audio was missing.
This fixes the following warning in dmesg.

[  302.369965] had: Driver detected 2 missed buffer done interrupt(s)!!!!

Signed-off-by: Toyo Abe <toyo.abe@gmail.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_irq.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 556fa80..dcc1564 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2857,11 +2857,14 @@ int i915_enable_hdmi_audio_int(struct drm_device *dev)
 	int pipe = 1;
 
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+	i915_enable_lpe_pipestat(dev_priv, pipe);
+
 	imr = I915_READ(VLV_IMR);
 	/* Audio is on Stream A */
 	imr &= ~I915_LPE_PIPE_A_INTERRUPT;
 	I915_WRITE(VLV_IMR, imr);
-	i915_enable_lpe_pipestat(dev_priv, pipe);
+	I915_WRITE(VLV_IER, ~imr);
+	POSTING_READ(VLV_IER);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
 	return 0;
@@ -2878,7 +2881,10 @@ int i915_disable_hdmi_audio_int(struct drm_device *dev)
 	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 	imr = I915_READ(VLV_IMR);
 	imr |= I915_LPE_PIPE_A_INTERRUPT;
+	I915_WRITE(VLV_IER, ~imr);
 	I915_WRITE(VLV_IMR, imr);
+	POSTING_READ(VLV_IMR);
+
 	i915_disable_lpe_pipestat(dev_priv, pipe);
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [RFC 15/15] i915: Fix typo in comment.
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (13 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 14/15] i915: Enable LPE_PIPEA_Interrupt Pierre-Louis Bossart
@ 2016-03-05  2:50 ` Pierre-Louis Bossart
  2016-03-05 13:42 ` [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Ville Syrjälä
  2016-03-07 12:04 ` ✗ Fi.CI.BAT: failure for " Patchwork
  16 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-05  2:50 UTC (permalink / raw)
  To: intel-gfx
  Cc: mengdong.lin, tiwai, liam.r.girdwood, vinod.koul, broonie,
	rakesh.a.ughreja, Toyo Abe

From: Toyo Abe <toyo.abe@gmail.com>

Signed-off-by: Toyo Abe <toyo.abe@gmail.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_irq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index dcc1564..25c2d41 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2848,7 +2848,7 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-/* Added fo HDMI AUdio */
+/* Added for HDMI Audio */
 int i915_enable_hdmi_audio_int(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [RFC 01/15] drm: i915: fix inversion of definitions for LPE_PIPE_A/B
  2016-03-05  2:50 ` [RFC 01/15] drm: i915: fix inversion of definitions for LPE_PIPE_A/B Pierre-Louis Bossart
@ 2016-03-05 13:27   ` Ville Syrjälä
  2016-03-07 18:00     ` Pierre-Louis Bossart
  0 siblings, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-05 13:27 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja

On Fri, Mar 04, 2016 at 08:50:38PM -0600, Pierre-Louis Bossart wrote:
> Definitions for I915_LPE_PIPE_A_INTERRUPT and I915_LPE_PIPE_B_INTERRUPT
> are inverted.

Not according to the docs. Are the docs wrong?

> 
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_reg.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 71abf57..228b22f 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -2029,8 +2029,8 @@ enum skl_disp_power_wells {
>  
>  #define I915_PM_INTERRUPT				(1<<31)
>  #define I915_ISP_INTERRUPT				(1<<22)
> -#define I915_LPE_PIPE_B_INTERRUPT			(1<<21)
> -#define I915_LPE_PIPE_A_INTERRUPT			(1<<20)
> +#define I915_LPE_PIPE_A_INTERRUPT			(1<<21)
> +#define I915_LPE_PIPE_B_INTERRUPT			(1<<20)
>  #define I915_MIPIC_INTERRUPT				(1<<19)
>  #define I915_MIPIA_INTERRUPT				(1<<18)
>  #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT		(1<<18)
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (14 preceding siblings ...)
  2016-03-05  2:50 ` [RFC 15/15] i915: Fix typo in comment Pierre-Louis Bossart
@ 2016-03-05 13:42 ` Ville Syrjälä
  2016-03-07 17:54   ` Pierre-Louis Bossart
  2016-03-07 12:04 ` ✗ Fi.CI.BAT: failure for " Patchwork
  16 siblings, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-05 13:42 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja

On Fri, Mar 04, 2016 at 08:50:37PM -0600, Pierre-Louis Bossart wrote:
> When HDaudio is not enabled or fused-out, an alternate hardware
> interface can be used to provide audio data to the display/HDMI
> controller on Atom platforms.  The code to control this interface was
> never submitted upstream but has been used extensively in Android
> programs on Medfield, Clovertrail, Merrifield, Moorefield, Baytrail-T
> and CherryTrail-T, as well as the Baytrail Compute Stick w/ Ubuntu.

Not sure why you skirt around calling the thing by its name. It's
called LPE isn't it?

> Jesse Barnes and others at Intel suggested the code be posted on the
> intex-gfx mailing lists as an RFC for graphics and audio folks to start
> the conversation on how to support this interface in the mainline
> kernel. The initial patches used for the Baytrail Compute Stick were
> split to make them more readable, with changes to drm/i915 and sound/
> clearly separated out. A basic cleanup to make checkpatch happy was
> done but the code needs further updates (we know...). The code was
> rebased from 3.16 to drm/intel-nightly-build and tested on a Baytrail
> Compute Stick. CherryTrail changes will be added shortly.
> 
> The main feedback expected in this RFC is on the interaction between
> audio and display driver, specifically if we can wrap the interface
> control with the component framework already used between i915 and
> HDaudio. A short documentation was added to help explain how the
> hardware works.

Yes, using/extending the already existing audio component stuff was
my first though when I did a preliminary scan of the patches. I didn't
look too closely at what's needed hardware wise, so can't get into
details yet.

Some other peculiar things that caught my eye:
- adds some HDMI live status stuff etc. which we already have
- missing pipe C for CHV?
- no clue what that procfs/rpm patch was about

Anyway, I'll try to take a better look at it next week,

>
> 
> The first two patches fix issues that were identified during the
> rebase process and could be merged without waiting for the interface
> to be reworked.
> 
> Comments welcome!
> 
> David Henningsson (2):
>   hdmi_audio: Improve position reporting
>   hdmi_audio: Fixup some monitor
> 
> Pierre-Louis Bossart (10):
>   drm: i915: fix inversion of definitions for LPE_PIPE_A/B
>   drm: i915: remove intel_hdmi variable declaration
>   Doc: sound: add description of Atom HDMI audio interface
>   drm/i915: Add headers for non-HDAudio HDMI interface
>   drm/i915: changes for non-HDAudio HDMI interface
>   drm/i915: power-related changes non-HDAudio HDMI interface
>   drm/i915: Add API code for non-HDAudio HDMI interface
>   drm/i915: enable non-HDAudio HDMI interface Makefile
>   ALSA: Intel: Atom: add Atom non-HDAudio HDMI interface
>   add dependency on PM_RUNTIME
> 
> Toyo Abe (3):
>   hdmi_audio: Fix mishandling of AUD_HDMI_STATUS_v2 register.
>   i915: Enable LPE_PIPEA_Interrupt.
>   i915: Fix typo in comment.
> 
>  Documentation/sound/alsa/Atom-hdmi-audio.txt |  241 +++
>  drivers/gpu/drm/i915/Makefile                |    4 +-
>  drivers/gpu/drm/i915/hdmi_audio_if.c         |  410 ++++++
>  drivers/gpu/drm/i915/hdmi_audio_if.h         |  122 ++
>  drivers/gpu/drm/i915/i915_drv.h              |   31 +
>  drivers/gpu/drm/i915/i915_irq.c              |   87 ++
>  drivers/gpu/drm/i915/i915_reg.h              |   11 +-
>  drivers/gpu/drm/i915/i915_rpm.c              |  476 ++++++
>  drivers/gpu/drm/i915/intel_display.c         |    8 +
>  drivers/gpu/drm/i915/intel_drv.h             |   11 +
>  drivers/gpu/drm/i915/intel_hdmi.c            |  185 ++-
>  drivers/gpu/drm/i915/intel_pm.c              |   53 +
>  sound/Kconfig                                |    9 +
>  sound/Makefile                               |    1 +
>  sound/hdmi_audio/Makefile                    |    9 +
>  sound/hdmi_audio/intel_mid_hdmi_audio.c      | 2039 ++++++++++++++++++++++++++
>  sound/hdmi_audio/intel_mid_hdmi_audio.h      |  740 ++++++++++
>  sound/hdmi_audio/intel_mid_hdmi_audio_if.c   |  514 +++++++
>  18 files changed, 4946 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/sound/alsa/Atom-hdmi-audio.txt
>  create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.c
>  create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.h
>  create mode 100644 drivers/gpu/drm/i915/i915_rpm.c
>  create mode 100644 sound/hdmi_audio/Makefile
>  create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio.c
>  create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio.h
>  create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio_if.c
> 
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* ✗ Fi.CI.BAT: failure for HDMI Audio support on Atom w/o HDAUdio
  2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
                   ` (15 preceding siblings ...)
  2016-03-05 13:42 ` [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Ville Syrjälä
@ 2016-03-07 12:04 ` Patchwork
  16 siblings, 0 replies; 47+ messages in thread
From: Patchwork @ 2016-03-07 12:04 UTC (permalink / raw)
  To: Pierre-Louis Bossart; +Cc: intel-gfx

== Series Details ==

Series: HDMI Audio support on Atom w/o HDAUdio
URL   : https://patchwork.freedesktop.org/series/4142/
State : failure

== Summary ==

Series 4142v1 HDMI Audio support on Atom w/o HDAUdio
http://patchwork.freedesktop.org/api/1.0/series/4142/revisions/1/mbox/

Test kms_flip:
        Subgroup basic-flip-vs-wf_vblank:
                fail       -> PASS       (bsw-nuc-2)
                pass       -> DMESG-WARN (hsw-gt2)
                pass       -> DMESG-WARN (hsw-brixbox)
        Subgroup basic-plain-flip:
                dmesg-warn -> PASS       (hsw-gt2)
Test kms_pipe_crc_basic:
        Subgroup read-crc-pipe-c:
                dmesg-warn -> PASS       (hsw-gt2)
        Subgroup suspend-read-crc-pipe-a:
                dmesg-warn -> PASS       (skl-i5k-2)
                skip       -> PASS       (hsw-brixbox)

bdw-nuci7        total:183  pass:172  dwarn:0   dfail:0   fail:0   skip:11 
bdw-ultra        total:183  pass:165  dwarn:0   dfail:0   fail:0   skip:18 
bsw-nuc-2        total:183  pass:149  dwarn:0   dfail:0   fail:0   skip:34 
hsw-brixbox      total:183  pass:163  dwarn:1   dfail:0   fail:0   skip:19 
hsw-gt2          total:183  pass:168  dwarn:1   dfail:0   fail:0   skip:14 
ilk-hp8440p      total:183  pass:125  dwarn:0   dfail:0   fail:0   skip:58 
ivb-t430s        total:183  pass:162  dwarn:0   dfail:0   fail:0   skip:21 
skl-i5k-2        total:183  pass:163  dwarn:0   dfail:0   fail:0   skip:20 
skl-i7k-2        total:183  pass:163  dwarn:0   dfail:0   fail:0   skip:20 
snb-dellxps      total:183  pass:153  dwarn:1   dfail:0   fail:0   skip:29 
snb-x220t        total:183  pass:154  dwarn:0   dfail:0   fail:1   skip:28 

Results at /archive/results/CI_IGT_test/Patchwork_1533/

d369e0096716c6000139162b3b340f684f0a51da drm-intel-nightly: 2016y-03m-04d-17h-18m-08s UTC integration manifest
c25eb0ab293ef80c5aaa81f4437d3067783df872 i915: Fix typo in comment.
a282eb1ea3cda677d8b587d4b5834ccfdf54f84d i915: Enable LPE_PIPEA_Interrupt.
1354f0d168f2514eafe005bc9d24d1344349bf82 hdmi_audio: Fix mishandling of AUD_HDMI_STATUS_v2 register.
38867a009c77f16716d1e5770f321486ed624262 hdmi_audio: Fixup some monitor
b27ff354cca12cc2e1aaddd0edcef9a72d41438b hdmi_audio: Improve position reporting
2c9fb15d0dc1eeaecd28c7d77663519b34d9fde6 add dependency on PM_RUNTIME
99ec465f29e78645283558ea31c0c23dc4d06f28 ALSA: Intel: Atom: add Atom non-HDAudio HDMI interface
73815086797fb4ecf96ebda4577236de6bd44e72 drm/i915: enable non-HDAudio HDMI interface Makefile
a6a992a33e678bf1cbabf2b2a6e9f1a56f1ec8f5 drm/i915: Add API code for non-HDAudio HDMI interface
e1173f471cfd3be31f7456ff98deab01fb1d4c30 drm/i915: power-related changes non-HDAudio HDMI interface
c24599a16693719cbdab36ffcff893bbeff38efb drm/i915: changes for non-HDAudio HDMI interface
ed06d43e30dec2d045523e32f80b44dd8b70ff33 drm/i915: Add headers for non-HDAudio HDMI interface
a31ad258d7e01d850dea7f6f69451aa6f55afc97 Doc: sound: add description of Atom HDMI audio interface
10eacb1a81f71f7549ce776d01f6b8d53c3a074b drm: i915: remove intel_hdmi variable declaration
339bc5c75e8398ac3c200ee64a40688a80d10df5 drm: i915: fix inversion of definitions for LPE_PIPE_A/B

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio
  2016-03-05 13:42 ` [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Ville Syrjälä
@ 2016-03-07 17:54   ` Pierre-Louis Bossart
  2016-03-07 18:02     ` Ville Syrjälä
  0 siblings, 1 reply; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-07 17:54 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja

On 3/5/16 7:42 AM, Ville Syrjälä wrote:
> On Fri, Mar 04, 2016 at 08:50:37PM -0600, Pierre-Louis Bossart wrote:
>> When HDaudio is not enabled or fused-out, an alternate hardware
>> interface can be used to provide audio data to the display/HDMI
>> controller on Atom platforms.  The code to control this interface was
>> never submitted upstream but has been used extensively in Android
>> programs on Medfield, Clovertrail, Merrifield, Moorefield, Baytrail-T
>> and CherryTrail-T, as well as the Baytrail Compute Stick w/ Ubuntu.
>
> Not sure why you skirt around calling the thing by its name. It's
> called LPE isn't it?

No. LPE aka SST is the path to the audio dsp subsystem.
This path to HDMI has nothing to do with the audio dsp. Not a single 
gate is shared.
In most Android implementations this driver is probed using a dedicated 
ACPI _HID different from the LPEA one. For upstream and machines that 
don't have this specific device in the BIOS we may piggyback on the LPEA 
device to complete the probe (that's how it's done on Windows apparently).

>> The main feedback expected in this RFC is on the interaction between
>> audio and display driver, specifically if we can wrap the interface
>> control with the component framework already used between i915 and
>> HDaudio. A short documentation was added to help explain how the
>> hardware works.
>
> Yes, using/extending the already existing audio component stuff was
> my first though when I did a preliminary scan of the patches. I didn't
> look too closely at what's needed hardware wise, so can't get into
> details yet.
>
> Some other peculiar things that caught my eye:
> - adds some HDMI live status stuff etc. which we already have

if we can reuse existing parts we can prune this driver.

> - missing pipe C for CHV?

yes, none of the CHT changes are included for now.

> - no clue what that procfs/rpm patch was about

it's very likely legacy code, i don't know if it's needed any longer.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 01/15] drm: i915: fix inversion of definitions for LPE_PIPE_A/B
  2016-03-05 13:27   ` Ville Syrjälä
@ 2016-03-07 18:00     ` Pierre-Louis Bossart
  0 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-07 18:00 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja

On 3/5/16 7:27 AM, Ville Syrjälä wrote:
> On Fri, Mar 04, 2016 at 08:50:38PM -0600, Pierre-Louis Bossart wrote:
>> Definitions for I915_LPE_PIPE_A_INTERRUPT and I915_LPE_PIPE_B_INTERRUPT
>> are inverted.
>
> Not according to the docs. Are the docs wrong?

Possibly. I compared with the Android code and flagged this conflict, I 
didn't dig deeper.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio
  2016-03-07 17:54   ` Pierre-Louis Bossart
@ 2016-03-07 18:02     ` Ville Syrjälä
  2016-03-07 18:12       ` Pierre-Louis Bossart
  0 siblings, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-07 18:02 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja

On Mon, Mar 07, 2016 at 11:54:28AM -0600, Pierre-Louis Bossart wrote:
> On 3/5/16 7:42 AM, Ville Syrjälä wrote:
> > On Fri, Mar 04, 2016 at 08:50:37PM -0600, Pierre-Louis Bossart wrote:
> >> When HDaudio is not enabled or fused-out, an alternate hardware
> >> interface can be used to provide audio data to the display/HDMI
> >> controller on Atom platforms.  The code to control this interface was
> >> never submitted upstream but has been used extensively in Android
> >> programs on Medfield, Clovertrail, Merrifield, Moorefield, Baytrail-T
> >> and CherryTrail-T, as well as the Baytrail Compute Stick w/ Ubuntu.
> >
> > Not sure why you skirt around calling the thing by its name. It's
> > called LPE isn't it?
> 
> No. LPE aka SST is the path to the audio dsp subsystem.
> This path to HDMI has nothing to do with the audio dsp. Not a single 
> gate is shared.

The why are the interrupt bits called LPE_somethingsomething?
And what generates the audio data then?

> In most Android implementations this driver is probed using a dedicated 
> ACPI _HID different from the LPEA one. For upstream and machines that 
> don't have this specific device in the BIOS we may piggyback on the LPEA 
> device to complete the probe (that's how it's done on Windows apparently).

Hmm. So it's a third audio controller or something? Just someone named
the display related bits as LPE just to confuse people on purpose?

> 
> >> The main feedback expected in this RFC is on the interaction between
> >> audio and display driver, specifically if we can wrap the interface
> >> control with the component framework already used between i915 and
> >> HDaudio. A short documentation was added to help explain how the
> >> hardware works.
> >
> > Yes, using/extending the already existing audio component stuff was
> > my first though when I did a preliminary scan of the patches. I didn't
> > look too closely at what's needed hardware wise, so can't get into
> > details yet.
> >
> > Some other peculiar things that caught my eye:
> > - adds some HDMI live status stuff etc. which we already have
> 
> if we can reuse existing parts we can prune this driver.
> 
> > - missing pipe C for CHV?
> 
> yes, none of the CHT changes are included for now.
> 
> > - no clue what that procfs/rpm patch was about
> 
> it's very likely legacy code, i don't know if it's needed any longer.

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio
  2016-03-07 18:02     ` Ville Syrjälä
@ 2016-03-07 18:12       ` Pierre-Louis Bossart
  2016-03-07 18:29         ` Ville Syrjälä
  0 siblings, 1 reply; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-07 18:12 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja


>>> Not sure why you skirt around calling the thing by its name. It's
>>> called LPE isn't it?
>>
>> No. LPE aka SST is the path to the audio dsp subsystem.
>> This path to HDMI has nothing to do with the audio dsp. Not a single
>> gate is shared.
>
> The why are the interrupt bits called LPE_somethingsomething?
> And what generates the audio data then?

I don't think the HAS ever mentioned LPE, it's really unrelated to LPE. 
LPE cannot even get the interrupts or access the registers.
The audio data is generated by the application, written to a ring buffer 
and fetch by the DMA before they are inserted in the audio islands

>
>> In most Android implementations this driver is probed using a dedicated
>> ACPI _HID different from the LPEA one. For upstream and machines that
>> don't have this specific device in the BIOS we may piggyback on the LPEA
>> device to complete the probe (that's how it's done on Windows apparently).
>
> Hmm. So it's a third audio controller or something? Just someone named
> the display related bits as LPE just to confuse people on purpose?

it's really an interface to the display controller, not a new hardware 
part. Everything called LPE should be renamed to avoid this confusion.

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio
  2016-03-07 18:12       ` Pierre-Louis Bossart
@ 2016-03-07 18:29         ` Ville Syrjälä
  0 siblings, 0 replies; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-07 18:29 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja

On Mon, Mar 07, 2016 at 12:12:32PM -0600, Pierre-Louis Bossart wrote:
> 
> >>> Not sure why you skirt around calling the thing by its name. It's
> >>> called LPE isn't it?
> >>
> >> No. LPE aka SST is the path to the audio dsp subsystem.
> >> This path to HDMI has nothing to do with the audio dsp. Not a single
> >> gate is shared.
> >
> > The why are the interrupt bits called LPE_somethingsomething?
> > And what generates the audio data then?
> 
> I don't think the HAS ever mentioned LPE, it's really unrelated to LPE. 

The display cluster HAS calls it LPE. It does say though that it's more
or less just the display controller DMAing stuff in. We should definitely
add a note somewhere explaining that it's not really related to the other
LPE, other than by being enabled at the same time. Or can we actually use
the display engine LPE even if HDA is enabled and the other LPE is
disabled?

> LPE cannot even get the interrupts or access the registers.
> The audio data is generated by the application, written to a ring buffer 
> and fetch by the DMA before they are inserted in the audio islands
> 
> >
> >> In most Android implementations this driver is probed using a dedicated
> >> ACPI _HID different from the LPEA one. For upstream and machines that
> >> don't have this specific device in the BIOS we may piggyback on the LPEA
> >> device to complete the probe (that's how it's done on Windows apparently).
> >
> > Hmm. So it's a third audio controller or something? Just someone named
> > the display related bits as LPE just to confuse people on purpose?
> 
> it's really an interface to the display controller, not a new hardware 
> part. Everything called LPE should be renamed to avoid this confusion.

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 02/15] drm: i915: remove intel_hdmi variable declaration
  2016-03-05  2:50 ` [RFC 02/15] drm: i915: remove intel_hdmi variable declaration Pierre-Louis Bossart
@ 2016-03-10 17:34   ` Ville Syrjälä
  2016-03-11 17:08     ` Pierre-Louis Bossart
  0 siblings, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-10 17:34 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja

On Fri, Mar 04, 2016 at 08:50:39PM -0600, Pierre-Louis Bossart wrote:
> 'intel_hdmi' variable is redeclared, use same variable declared in
> function scope.
> 
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_hdmi.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index d8060e6..1beb155 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -1418,7 +1418,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
>  	intel_hdmi_unset_edid(connector);
>  
>  	if (intel_hdmi_set_edid(connector, live_status)) {
> -		struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
> +		intel_hdmi = intel_attached_hdmi(connector);

We're still going to get the same answer,
so you can just kill the assignment as well.

>  
>  		hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
>  		status = connector_status_connected;
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-05  2:50 ` [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface Pierre-Louis Bossart
@ 2016-03-10 17:54   ` Ville Syrjälä
  2016-03-10 18:00   ` Ville Syrjälä
  1 sibling, 0 replies; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-10 17:54 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Fri, Mar 04, 2016 at 08:50:41PM -0600, Pierre-Louis Bossart wrote:
> Add header files for interface available on Baytrail and CherryTrail
> 
> Initial code was downloaded from https://github.com/01org/baytrailaudio/
> ...and had the changes to .config stripped and the revert on sound/init.c
> done by David Henningson
> 
> Clean-up, port to 4.4 and intel-drm by Pierre Bossart
> 
> Signed-off-by: David Henningsson <david.henningsson@canonical.com>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/hdmi_audio_if.h | 122 +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/i915_drv.h      |  31 +++++++++
>  drivers/gpu/drm/i915/i915_reg.h      |   7 ++
>  drivers/gpu/drm/i915/intel_drv.h     |  11 ++++
>  4 files changed, 171 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.h
> 
> diff --git a/drivers/gpu/drm/i915/hdmi_audio_if.h b/drivers/gpu/drm/i915/hdmi_audio_if.h
> new file mode 100644
> index 0000000..f968028
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/hdmi_audio_if.h
> @@ -0,0 +1,122 @@
> +/*
> + * Copyright (c) 2010, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * Authors:
> + *	jim liu <jim.liu@intel.com>
> + *	Uma Shankar <uma.shankar@intel.com>
> + */
> +
> +
> +#ifndef __HDMI_AUDIO_IF_H
> +#define __HDMI_AUDIO_IF_H
> +
> +#include <linux/types.h>
> +#include <drm/drmP.h>
> +
> +/* HDMI AUDIO INTERRUPT TYPE */
> +#define HDMI_AUDIO_UNDERRUN     (1UL<<0)
> +#define HDMI_AUDIO_BUFFER_DONE  (1UL<<1)
> +
> +/* the monitor type HDMI or DVI */
> +#define MONITOR_TYPE_HDMI 1
> +#define MONITOR_TYPE_DVI  2
> +
> +extern int i915_hdmi_state;
> +extern int i915_notify_had;
> +
> +enum had_caps_list {
> +	HAD_GET_ELD = 1,
> +	HAD_GET_SAMPLING_FREQ,
> +	HAD_GET_DISPLAY_RATE,
> +	HAD_GET_HDCP_STATUS,
> +	HAD_GET_AUDIO_STATUS,
> +	HAD_SET_ENABLE_AUDIO,
> +	HAD_SET_DISABLE_AUDIO,
> +	HAD_SET_ENABLE_AUDIO_INT,
> +	HAD_SET_DISABLE_AUDIO_INT,
> +	OTHERS_TBD,
> +};
> +
> +enum had_event_type {
> +	HAD_EVENT_HOT_PLUG = 1,
> +	HAD_EVENT_HOT_UNPLUG,
> +	HAD_EVENT_MODE_CHANGING,
> +	HAD_EVENT_PM_CHANGING,
> +	HAD_EVENT_AUDIO_BUFFER_DONE,
> +	HAD_EVENT_AUDIO_BUFFER_UNDERRUN,
> +	HAD_EVENT_QUERY_IS_AUDIO_BUSY,
> +	HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED,
> +};
> +
> +/*
> + * HDMI Display Controller Audio Interface
> + *
> + */
> +typedef int (*had_event_call_back) (enum had_event_type event_type,
> +		void *ctxt_info);
> +
> +struct hdmi_audio_registers_ops {
> +	int (*hdmi_audio_read_register)(uint32_t reg_addr, uint32_t *data);
> +	int (*hdmi_audio_write_register)(uint32_t reg_addr, uint32_t data);
> +	int (*hdmi_audio_read_modify)(uint32_t reg_addr, uint32_t data,
> +			uint32_t mask);
> +};

Do all the register actually live within the device 2 mmio bar? If so
I think what we might want to do here is go for a proper subdevice
approach like we tried to do for the VED on BYT. VED sort of dried up
and no one cared (not sure the userspae part was even published), but
I think the approach was sane. See here:
https://lists.freedesktop.org/archives/intel-gfx/2015-January/058137.html

> +
> +struct hdmi_audio_query_set_ops {
> +	int (*hdmi_audio_get_caps)(enum had_caps_list query_element,
> +			void *capabilties);
> +	int (*hdmi_audio_set_caps)(enum had_caps_list set_element,
> +			void *capabilties);
> +};
> +
> +typedef struct hdmi_audio_event {
> +	int type;
> +} hdmi_audio_event_t;
> +
> +struct snd_intel_had_interface {
> +	const char *name;
> +	int (*query)(void *had_data, hdmi_audio_event_t event);
> +	int (*suspend)(void *had_data, hdmi_audio_event_t event);
> +	int (*resume)(void *had_data);
> +};
> +
> +struct hdmi_audio_priv {
> +	struct drm_device *dev;
> +	u32 hdmib_reg;
> +
> +	bool is_hdcp_supported;
> +	bool hdmi_hpd_connected;
> +	int monitor_type;
> +	void *context;
> +};
> +
> +extern void i915_hdmi_audio_init(struct hdmi_audio_priv *p_hdmi_priv);
> +
> +extern bool mid_hdmi_audio_is_busy(struct drm_device *dev);
> +extern bool mid_hdmi_audio_suspend(struct drm_device *dev);
> +extern void mid_hdmi_audio_resume(struct drm_device *dev);
> +extern void mid_hdmi_audio_signal_event(struct drm_device *dev,
> +		enum had_event_type event);
> +
> +/* Added for HDMI Audio */
> +extern void hdmi_get_eld(uint8_t *eld);
> +extern int i915_enable_hdmi_audio_int(struct drm_device *dev);
> +extern int i915_disable_hdmi_audio_int(struct drm_device *dev);
> +extern int mid_hdmi_audio_setup(
> +	had_event_call_back audio_callbacks,
> +	struct hdmi_audio_registers_ops *reg_ops,
> +	struct hdmi_audio_query_set_ops *query_ops);
> +extern int mid_hdmi_audio_register(
> +	struct snd_intel_had_interface *driver,
> +	void *had_data);
> +
> +#endif /* __HDMI_AUDIO_IF_H */
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 2cb0a41..5dceb5b 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -53,6 +53,7 @@
>  #include <linux/kref.h>
>  #include <linux/pm_qos.h>
>  #include "intel_guc.h"
> +#include "hdmi_audio_if.h"
>  
>  /* General customization:
>   */
> @@ -1196,6 +1197,18 @@ struct intel_gen6_power_mgmt {
>  	struct mutex hw_lock;
>  };
>  
> +/* Runtime power management related */
> +struct intel_gen7_rpm {
> +	/* To track (num of get calls - num of put calls)
> +	 * made by procfs
> +	 */
> +	atomic_t procfs_count;
> +	/* To make sure ring get/put are in pair */
> +	bool ring_active;
> +	struct proc_dir_entry *i915_proc_dir;
> +	struct proc_dir_entry *i915_proc_file;
> +};
> +
>  /* defined intel_pm.c */
>  extern spinlock_t mchdev_lock;
>  
> @@ -2018,6 +2031,19 @@ struct drm_i915_private {
>  
>  	struct intel_encoder *dig_port_map[I915_MAX_PORTS];
>  
> +	/* Added for HDMI Audio */
> +	had_event_call_back had_event_callbacks;
> +	struct snd_intel_had_interface *had_interface;
> +	void *had_pvt_data;
> +	int tmds_clock_speed;
> +	int hdmi_audio_interrupt_mask;
> +	struct work_struct hdmi_audio_wq;
> +
> +	u32 hotplug_status;
> +
> +	/* Runtime power management related */
> +	struct intel_gen7_rpm rpm;
> +
>  	/*
>  	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
>  	 * will be rejected. Instead look for a better place.
> @@ -3537,6 +3563,11 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
>  	} while (upper != old_upper && loop++ < 2);			\
>  	(u64)upper << 32 | lower; })
>  
> +int i915_rpm_get_disp(struct drm_device *dev);
> +int i915_rpm_put_disp(struct drm_device *dev);
> +
> +bool i915_is_device_active(struct drm_device *dev);
> +
>  #define POSTING_READ(reg)	(void)I915_READ_NOTRACE(reg)
>  #define POSTING_READ16(reg)	(void)I915_READ16_NOTRACE(reg)
>  
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 228b22f..370371c 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -2062,7 +2062,12 @@ enum skl_disp_power_wells {
>  #define I915_WINVALID_INTERRUPT				(1<<1)
>  #define I915_USER_INTERRUPT				(1<<1)
>  #define I915_ASLE_INTERRUPT				(1<<0)
> +#define I915_LPE_AUDIO_HDMI_STATUS_A	_MMIO(dev_priv->info.display_mmio_offset + 0x65064)
> +#define I915_LPE_AUDIO_HDMI_STATUS_B	_MMIO(dev_priv->info.display_mmio_offset + 0x65864)
> +#define I915_HDMI_AUDIO_UNDERRUN			(1UL<<31)
> +#define I915_HDMI_AUDIO_BUFFER_DONE			(1UL<<29)
>  #define I915_BSD_USER_INTERRUPT				(1<<25)
> +#define I915_HDMI_AUDIO_UNDERRUN_ENABLE			(1UL<<15)
>  
>  #define GEN6_BSD_RNCID			_MMIO(0x12198)
>  
> @@ -3364,6 +3369,7 @@ enum skl_disp_power_wells {
>  #define _GEN3_SDVOC	0x61160
>  #define GEN3_SDVOB	_MMIO(_GEN3_SDVOB)
>  #define GEN3_SDVOC	_MMIO(_GEN3_SDVOC)
> +#define HDMIB	(dev_priv->info.display_mmio_offset + 0x61140)
>  #define GEN4_HDMIB	GEN3_SDVOB
>  #define GEN4_HDMIC	GEN3_SDVOC
>  #define VLV_HDMIB	_MMIO(VLV_DISPLAY_BASE + 0x61140)
> @@ -3373,6 +3379,7 @@ enum skl_disp_power_wells {
>  #define PCH_HDMIB	PCH_SDVOB
>  #define PCH_HDMIC	_MMIO(0xe1150)
>  #define PCH_HDMID	_MMIO(0xe1160)
> +#define PORT_ENABLE	(1 << 31)
>  
>  #define PORT_DFT_I9XX				_MMIO(0x61150)
>  #define   DC_BALANCE_RESET			(1 << 25)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index cb413e2..adfd27c 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -724,6 +724,14 @@ struct cxsr_latency {
>  #define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base)
>  #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
>  
> +/* HDMI bits are shared with the DP bits */
> +#define   HDMIB_HOTPLUG_LIVE_STATUS             (1 << 29)
> +#define   HDMIC_HOTPLUG_LIVE_STATUS             (1 << 28)
> +#define   HDMID_HOTPLUG_LIVE_STATUS             (1 << 27)
> +#define   HDMI_LIVE_STATUS_BASE			30
> +#define   HDMI_LIVE_STATUS_DELAY_STEP		10
> +#define   HDMI_EDID_RETRY_COUNT			3
> +
>  struct intel_hdmi {
>  	i915_reg_t hdmi_reg;
>  	int ddc_bus;
> @@ -735,6 +743,9 @@ struct intel_hdmi {
>  	bool rgb_quant_range_selectable;
>  	enum hdmi_picture_aspect aspect_ratio;
>  	struct intel_connector *attached_connector;
> +	struct edid *edid;
> +	uint32_t edid_mode_count;
> +
>  	void (*write_infoframe)(struct drm_encoder *encoder,
>  				enum hdmi_infoframe_type type,
>  				const void *frame, ssize_t len);
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-05  2:50 ` [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface Pierre-Louis Bossart
  2016-03-10 17:54   ` Ville Syrjälä
@ 2016-03-10 18:00   ` Ville Syrjälä
  2016-03-11 17:27     ` Pierre-Louis Bossart
  1 sibling, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-10 18:00 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Fri, Mar 04, 2016 at 08:50:41PM -0600, Pierre-Louis Bossart wrote:
> Add header files for interface available on Baytrail and CherryTrail
> 
> Initial code was downloaded from https://github.com/01org/baytrailaudio/
> ...and had the changes to .config stripped and the revert on sound/init.c
> done by David Henningson
> 
> Clean-up, port to 4.4 and intel-drm by Pierre Bossart
> 
> Signed-off-by: David Henningsson <david.henningsson@canonical.com>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/hdmi_audio_if.h | 122 +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/i915_drv.h      |  31 +++++++++
>  drivers/gpu/drm/i915/i915_reg.h      |   7 ++
>  drivers/gpu/drm/i915/intel_drv.h     |  11 ++++
>  4 files changed, 171 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.h
> 
> diff --git a/drivers/gpu/drm/i915/hdmi_audio_if.h b/drivers/gpu/drm/i915/hdmi_audio_if.h
> new file mode 100644
> index 0000000..f968028
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/hdmi_audio_if.h
> @@ -0,0 +1,122 @@
> +/*
> + * Copyright (c) 2010, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * Authors:
> + *	jim liu <jim.liu@intel.com>
> + *	Uma Shankar <uma.shankar@intel.com>
> + */
> +
> +
> +#ifndef __HDMI_AUDIO_IF_H
> +#define __HDMI_AUDIO_IF_H
> +
> +#include <linux/types.h>
> +#include <drm/drmP.h>
> +
> +/* HDMI AUDIO INTERRUPT TYPE */
> +#define HDMI_AUDIO_UNDERRUN     (1UL<<0)
> +#define HDMI_AUDIO_BUFFER_DONE  (1UL<<1)
> +
> +/* the monitor type HDMI or DVI */
> +#define MONITOR_TYPE_HDMI 1
> +#define MONITOR_TYPE_DVI  2
> +
> +extern int i915_hdmi_state;
> +extern int i915_notify_had;
> +
> +enum had_caps_list {
> +	HAD_GET_ELD = 1,
> +	HAD_GET_SAMPLING_FREQ,
> +	HAD_GET_DISPLAY_RATE,
> +	HAD_GET_HDCP_STATUS,
> +	HAD_GET_AUDIO_STATUS,
> +	HAD_SET_ENABLE_AUDIO,
> +	HAD_SET_DISABLE_AUDIO,
> +	HAD_SET_ENABLE_AUDIO_INT,
> +	HAD_SET_DISABLE_AUDIO_INT,
> +	OTHERS_TBD,
> +};
> +
> +enum had_event_type {
> +	HAD_EVENT_HOT_PLUG = 1,
> +	HAD_EVENT_HOT_UNPLUG,
> +	HAD_EVENT_MODE_CHANGING,
> +	HAD_EVENT_PM_CHANGING,
> +	HAD_EVENT_AUDIO_BUFFER_DONE,
> +	HAD_EVENT_AUDIO_BUFFER_UNDERRUN,
> +	HAD_EVENT_QUERY_IS_AUDIO_BUSY,
> +	HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED,

Kinda hard to see where everything gets used due to the way the patches
are split up.

At least the hotplug/mode change events are not needed. We only have the
two points where i915 should inform the audio driver about this stuff,
and those are the intel_audio_code_enable/disable(). For that we
already have the .pin_eld_notify() hook.

The interrupt stuff should mostly vanish from i915 with the subdevice
approach. As in i915 would just call the interrupt handler of the audio
driver based on the LPE bits in IIR, and the audio driver can then do
whatever it wants based on its own status register.

> +};
> +
> +/*
> + * HDMI Display Controller Audio Interface
> + *
> + */
> +typedef int (*had_event_call_back) (enum had_event_type event_type,
> +		void *ctxt_info);
> +
> +struct hdmi_audio_registers_ops {
> +	int (*hdmi_audio_read_register)(uint32_t reg_addr, uint32_t *data);
> +	int (*hdmi_audio_write_register)(uint32_t reg_addr, uint32_t data);
> +	int (*hdmi_audio_read_modify)(uint32_t reg_addr, uint32_t data,
> +			uint32_t mask);
> +};
> +
> +struct hdmi_audio_query_set_ops {
> +	int (*hdmi_audio_get_caps)(enum had_caps_list query_element,
> +			void *capabilties);
> +	int (*hdmi_audio_set_caps)(enum had_caps_list set_element,
> +			void *capabilties);
> +};
> +
> +typedef struct hdmi_audio_event {
> +	int type;
> +} hdmi_audio_event_t;
> +
> +struct snd_intel_had_interface {
> +	const char *name;
> +	int (*query)(void *had_data, hdmi_audio_event_t event);
> +	int (*suspend)(void *had_data, hdmi_audio_event_t event);
> +	int (*resume)(void *had_data);
> +};
> +
> +struct hdmi_audio_priv {
> +	struct drm_device *dev;
> +	u32 hdmib_reg;
> +
> +	bool is_hdcp_supported;
> +	bool hdmi_hpd_connected;
> +	int monitor_type;
> +	void *context;
> +};
> +
> +extern void i915_hdmi_audio_init(struct hdmi_audio_priv *p_hdmi_priv);
> +
> +extern bool mid_hdmi_audio_is_busy(struct drm_device *dev);
> +extern bool mid_hdmi_audio_suspend(struct drm_device *dev);
> +extern void mid_hdmi_audio_resume(struct drm_device *dev);
> +extern void mid_hdmi_audio_signal_event(struct drm_device *dev,
> +		enum had_event_type event);
> +
> +/* Added for HDMI Audio */
> +extern void hdmi_get_eld(uint8_t *eld);
> +extern int i915_enable_hdmi_audio_int(struct drm_device *dev);
> +extern int i915_disable_hdmi_audio_int(struct drm_device *dev);
> +extern int mid_hdmi_audio_setup(
> +	had_event_call_back audio_callbacks,
> +	struct hdmi_audio_registers_ops *reg_ops,
> +	struct hdmi_audio_query_set_ops *query_ops);
> +extern int mid_hdmi_audio_register(
> +	struct snd_intel_had_interface *driver,
> +	void *had_data);
> +
> +#endif /* __HDMI_AUDIO_IF_H */
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 2cb0a41..5dceb5b 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -53,6 +53,7 @@
>  #include <linux/kref.h>
>  #include <linux/pm_qos.h>
>  #include "intel_guc.h"
> +#include "hdmi_audio_if.h"
>  
>  /* General customization:
>   */
> @@ -1196,6 +1197,18 @@ struct intel_gen6_power_mgmt {
>  	struct mutex hw_lock;
>  };
>  
> +/* Runtime power management related */
> +struct intel_gen7_rpm {
> +	/* To track (num of get calls - num of put calls)
> +	 * made by procfs
> +	 */
> +	atomic_t procfs_count;
> +	/* To make sure ring get/put are in pair */
> +	bool ring_active;
> +	struct proc_dir_entry *i915_proc_dir;
> +	struct proc_dir_entry *i915_proc_file;
> +};
> +
>  /* defined intel_pm.c */
>  extern spinlock_t mchdev_lock;
>  
> @@ -2018,6 +2031,19 @@ struct drm_i915_private {
>  
>  	struct intel_encoder *dig_port_map[I915_MAX_PORTS];
>  
> +	/* Added for HDMI Audio */
> +	had_event_call_back had_event_callbacks;
> +	struct snd_intel_had_interface *had_interface;
> +	void *had_pvt_data;
> +	int tmds_clock_speed;
> +	int hdmi_audio_interrupt_mask;
> +	struct work_struct hdmi_audio_wq;
> +
> +	u32 hotplug_status;
> +
> +	/* Runtime power management related */
> +	struct intel_gen7_rpm rpm;
> +
>  	/*
>  	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
>  	 * will be rejected. Instead look for a better place.
> @@ -3537,6 +3563,11 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
>  	} while (upper != old_upper && loop++ < 2);			\
>  	(u64)upper << 32 | lower; })
>  
> +int i915_rpm_get_disp(struct drm_device *dev);
> +int i915_rpm_put_disp(struct drm_device *dev);
> +
> +bool i915_is_device_active(struct drm_device *dev);
> +
>  #define POSTING_READ(reg)	(void)I915_READ_NOTRACE(reg)
>  #define POSTING_READ16(reg)	(void)I915_READ16_NOTRACE(reg)
>  
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 228b22f..370371c 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -2062,7 +2062,12 @@ enum skl_disp_power_wells {
>  #define I915_WINVALID_INTERRUPT				(1<<1)
>  #define I915_USER_INTERRUPT				(1<<1)
>  #define I915_ASLE_INTERRUPT				(1<<0)
> +#define I915_LPE_AUDIO_HDMI_STATUS_A	_MMIO(dev_priv->info.display_mmio_offset + 0x65064)
> +#define I915_LPE_AUDIO_HDMI_STATUS_B	_MMIO(dev_priv->info.display_mmio_offset + 0x65864)
> +#define I915_HDMI_AUDIO_UNDERRUN			(1UL<<31)
> +#define I915_HDMI_AUDIO_BUFFER_DONE			(1UL<<29)
>  #define I915_BSD_USER_INTERRUPT				(1<<25)
> +#define I915_HDMI_AUDIO_UNDERRUN_ENABLE			(1UL<<15)
>  
>  #define GEN6_BSD_RNCID			_MMIO(0x12198)
>  
> @@ -3364,6 +3369,7 @@ enum skl_disp_power_wells {
>  #define _GEN3_SDVOC	0x61160
>  #define GEN3_SDVOB	_MMIO(_GEN3_SDVOB)
>  #define GEN3_SDVOC	_MMIO(_GEN3_SDVOC)
> +#define HDMIB	(dev_priv->info.display_mmio_offset + 0x61140)
>  #define GEN4_HDMIB	GEN3_SDVOB
>  #define GEN4_HDMIC	GEN3_SDVOC
>  #define VLV_HDMIB	_MMIO(VLV_DISPLAY_BASE + 0x61140)
> @@ -3373,6 +3379,7 @@ enum skl_disp_power_wells {
>  #define PCH_HDMIB	PCH_SDVOB
>  #define PCH_HDMIC	_MMIO(0xe1150)
>  #define PCH_HDMID	_MMIO(0xe1160)
> +#define PORT_ENABLE	(1 << 31)
>  
>  #define PORT_DFT_I9XX				_MMIO(0x61150)
>  #define   DC_BALANCE_RESET			(1 << 25)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index cb413e2..adfd27c 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -724,6 +724,14 @@ struct cxsr_latency {
>  #define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base)
>  #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
>  
> +/* HDMI bits are shared with the DP bits */
> +#define   HDMIB_HOTPLUG_LIVE_STATUS             (1 << 29)
> +#define   HDMIC_HOTPLUG_LIVE_STATUS             (1 << 28)
> +#define   HDMID_HOTPLUG_LIVE_STATUS             (1 << 27)
> +#define   HDMI_LIVE_STATUS_BASE			30
> +#define   HDMI_LIVE_STATUS_DELAY_STEP		10
> +#define   HDMI_EDID_RETRY_COUNT			3
> +
>  struct intel_hdmi {
>  	i915_reg_t hdmi_reg;
>  	int ddc_bus;
> @@ -735,6 +743,9 @@ struct intel_hdmi {
>  	bool rgb_quant_range_selectable;
>  	enum hdmi_picture_aspect aspect_ratio;
>  	struct intel_connector *attached_connector;
> +	struct edid *edid;
> +	uint32_t edid_mode_count;
> +
>  	void (*write_infoframe)(struct drm_encoder *encoder,
>  				enum hdmi_infoframe_type type,
>  				const void *frame, ssize_t len);
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 02/15] drm: i915: remove intel_hdmi variable declaration
  2016-03-10 17:34   ` Ville Syrjälä
@ 2016-03-11 17:08     ` Pierre-Louis Bossart
  0 siblings, 0 replies; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-11 17:08 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja

On 3/10/16 11:34 AM, Ville Syrjälä wrote:
> On Fri, Mar 04, 2016 at 08:50:39PM -0600, Pierre-Louis Bossart wrote:
>> 'intel_hdmi' variable is redeclared, use same variable declared in
>> function scope.
>>
>> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
>> ---
>>   drivers/gpu/drm/i915/intel_hdmi.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
>> index d8060e6..1beb155 100644
>> --- a/drivers/gpu/drm/i915/intel_hdmi.c
>> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
>> @@ -1418,7 +1418,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
>>   	intel_hdmi_unset_edid(connector);
>>
>>   	if (intel_hdmi_set_edid(connector, live_status)) {
>> -		struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
>> +		intel_hdmi = intel_attached_hdmi(connector);
>
> We're still going to get the same answer,
> so you can just kill the assignment as well.

Thanks. I wasn't sure if the set_edid would have side effects. Will 
resend this one.

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-10 18:00   ` Ville Syrjälä
@ 2016-03-11 17:27     ` Pierre-Louis Bossart
  2016-03-11 19:09       ` Ville Syrjälä
  0 siblings, 1 reply; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-11 17:27 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

Thanks for the review Ville

[snip]

> Kinda hard to see where everything gets used due to the way the patches
> are split up.

Yes, it's far from great...

> At least the hotplug/mode change events are not needed. We only have the
> two points where i915 should inform the audio driver about this stuff,
> and those are the intel_audio_code_enable/disable(). For that we
> already have the .pin_eld_notify() hook.
>
> The interrupt stuff should mostly vanish from i915 with the subdevice
> approach. As in i915 would just call the interrupt handler of the audio
> driver based on the LPE bits in IIR, and the audio driver can then do
> whatever it wants based on its own status register.

Are you saying that the subdevice would provide a read/write interface 
for the audio driver to look at display registers, and the i915 driver 
would only provide a notification interface (EDID and interrupts) to the 
audio driver?
If yes, would there be two component framework links, one between 
i915/audio driver and one between subdevice/audio driver.
I am way beyond my comfort zone, bear with me if this is silly.
Thanks.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-11 17:27     ` Pierre-Louis Bossart
@ 2016-03-11 19:09       ` Ville Syrjälä
  2016-03-14  9:04         ` Daniel Vetter
  2016-03-14 15:13         ` Pierre-Louis Bossart
  0 siblings, 2 replies; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-11 19:09 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> Thanks for the review Ville
> 
> [snip]
> 
> > Kinda hard to see where everything gets used due to the way the patches
> > are split up.
> 
> Yes, it's far from great...
> 
> > At least the hotplug/mode change events are not needed. We only have the
> > two points where i915 should inform the audio driver about this stuff,
> > and those are the intel_audio_code_enable/disable(). For that we
> > already have the .pin_eld_notify() hook.
> >
> > The interrupt stuff should mostly vanish from i915 with the subdevice
> > approach. As in i915 would just call the interrupt handler of the audio
> > driver based on the LPE bits in IIR, and the audio driver can then do
> > whatever it wants based on its own status register.
> 
> Are you saying that the subdevice would provide a read/write interface 
> for the audio driver to look at display registers, and the i915 driver 
> would only provide a notification interface (EDID and interrupts) to the 
> audio driver?

The audio driver would simply ioremap the appropriate range of
registers itself.

> If yes, would there be two component framework links, one between 
> i915/audio driver and one between subdevice/audio driver.

Yeah sort of. i915 registers the platform device for the audio, the
audio driver can then bind to the device via the platform driver .probe
callback. It can then register with the audio component stuff at some
point to get the relevant notifications on the display state. When
i915 gets unloaded we remove the platform device, at which point the
audio driver's platform driver .remove() callback gets invoked and
it should unregister/cleanup everything.

I just tried to frob around with the VED code a bit, and got it to load
at least. It's not quite happy about reloading i915 while the ipvr
driver was loaded though. Not sure what's going on there, but I do
think this approach should work. So the VED patch could serve as a
decent enough model to follow.

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-11 19:09       ` Ville Syrjälä
@ 2016-03-14  9:04         ` Daniel Vetter
  2016-03-14 14:20           ` Ville Syrjälä
  2016-03-15  8:36           ` Daniel Vetter
  2016-03-14 15:13         ` Pierre-Louis Bossart
  1 sibling, 2 replies; 47+ messages in thread
From: Daniel Vetter @ 2016-03-14  9:04 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Fri, Mar 11, 2016 at 09:09:12PM +0200, Ville Syrjälä wrote:
> On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > Thanks for the review Ville
> > 
> > [snip]
> > 
> > > Kinda hard to see where everything gets used due to the way the patches
> > > are split up.
> > 
> > Yes, it's far from great...
> > 
> > > At least the hotplug/mode change events are not needed. We only have the
> > > two points where i915 should inform the audio driver about this stuff,
> > > and those are the intel_audio_code_enable/disable(). For that we
> > > already have the .pin_eld_notify() hook.
> > >
> > > The interrupt stuff should mostly vanish from i915 with the subdevice
> > > approach. As in i915 would just call the interrupt handler of the audio
> > > driver based on the LPE bits in IIR, and the audio driver can then do
> > > whatever it wants based on its own status register.
> > 
> > Are you saying that the subdevice would provide a read/write interface 
> > for the audio driver to look at display registers, and the i915 driver 
> > would only provide a notification interface (EDID and interrupts) to the 
> > audio driver?
> 
> The audio driver would simply ioremap the appropriate range of
> registers itself.
> 
> > If yes, would there be two component framework links, one between 
> > i915/audio driver and one between subdevice/audio driver.
> 
> Yeah sort of. i915 registers the platform device for the audio, the
> audio driver can then bind to the device via the platform driver .probe
> callback. It can then register with the audio component stuff at some
> point to get the relevant notifications on the display state. When
> i915 gets unloaded we remove the platform device, at which point the
> audio driver's platform driver .remove() callback gets invoked and
> it should unregister/cleanup everything.
> 
> I just tried to frob around with the VED code a bit, and got it to load
> at least. It's not quite happy about reloading i915 while the ipvr
> driver was loaded though. Not sure what's going on there, but I do
> think this approach should work. So the VED patch could serve as a
> decent enough model to follow.

platform devices registerd by modules are apparently inherently racy and
in an unfixable way. At least I remember something like that from VED
discussion.

In short you _must_ unload VED manually before unloading i915, or it all
goes boom. If this is the only thing that went boom it's acceptable.

Another bit we didn't fully do for VED is abstracting away the dma mapping
stuff, because x86 dma abstraction sucks (compared to arm). Not sure, but
this might have been fixed meanwhile - if we can set up a dma_ops that the
subdevice would use, we should do so (instead of the page_to_pfn hacks VED
used).
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-14  9:04         ` Daniel Vetter
@ 2016-03-14 14:20           ` Ville Syrjälä
  2016-03-15  8:35             ` Daniel Vetter
  2016-03-15  8:36           ` Daniel Vetter
  1 sibling, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-14 14:20 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Mon, Mar 14, 2016 at 10:04:00AM +0100, Daniel Vetter wrote:
> On Fri, Mar 11, 2016 at 09:09:12PM +0200, Ville Syrjälä wrote:
> > On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > > Thanks for the review Ville
> > > 
> > > [snip]
> > > 
> > > > Kinda hard to see where everything gets used due to the way the patches
> > > > are split up.
> > > 
> > > Yes, it's far from great...
> > > 
> > > > At least the hotplug/mode change events are not needed. We only have the
> > > > two points where i915 should inform the audio driver about this stuff,
> > > > and those are the intel_audio_code_enable/disable(). For that we
> > > > already have the .pin_eld_notify() hook.
> > > >
> > > > The interrupt stuff should mostly vanish from i915 with the subdevice
> > > > approach. As in i915 would just call the interrupt handler of the audio
> > > > driver based on the LPE bits in IIR, and the audio driver can then do
> > > > whatever it wants based on its own status register.
> > > 
> > > Are you saying that the subdevice would provide a read/write interface 
> > > for the audio driver to look at display registers, and the i915 driver 
> > > would only provide a notification interface (EDID and interrupts) to the 
> > > audio driver?
> > 
> > The audio driver would simply ioremap the appropriate range of
> > registers itself.
> > 
> > > If yes, would there be two component framework links, one between 
> > > i915/audio driver and one between subdevice/audio driver.
> > 
> > Yeah sort of. i915 registers the platform device for the audio, the
> > audio driver can then bind to the device via the platform driver .probe
> > callback. It can then register with the audio component stuff at some
> > point to get the relevant notifications on the display state. When
> > i915 gets unloaded we remove the platform device, at which point the
> > audio driver's platform driver .remove() callback gets invoked and
> > it should unregister/cleanup everything.
> > 
> > I just tried to frob around with the VED code a bit, and got it to load
> > at least. It's not quite happy about reloading i915 while the ipvr
> > driver was loaded though. Not sure what's going on there, but I do
> > think this approach should work. So the VED patch could serve as a
> > decent enough model to follow.
> 
> platform devices registerd by modules are apparently inherently racy and
> in an unfixable way. At least I remember something like that from VED
> discussion.
> 
> In short you _must_ unload VED manually before unloading i915, or it all
> goes boom. If this is the only thing that went boom it's acceptable.

VED goes boom due drm_global_mutex deadlock at least if you load
i915 while ipvr is already loaded. I didn't check to hard if there
were any booms on pure unload so far.

Anyways, I was a bit worried about the races so I did a pair of 
small test modules to try out this model, and to me it looked to
work so far. I just unregistered the platform device from the parent
pci driver .remove() hook, and it got blocked until the platform
driver's .remove() hook was done.

In any case if this is broken, then I assume mfd must be broken. And
that thing is at least used quite extensively.

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-11 19:09       ` Ville Syrjälä
  2016-03-14  9:04         ` Daniel Vetter
@ 2016-03-14 15:13         ` Pierre-Louis Bossart
  2016-03-14 15:21           ` Ville Syrjälä
  1 sibling, 1 reply; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-14 15:13 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On 3/11/16 1:09 PM, Ville Syrjälä wrote:
> On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
>> Thanks for the review Ville
>>
>> [snip]
>>
>>> Kinda hard to see where everything gets used due to the way the patches
>>> are split up.
>>
>> Yes, it's far from great...
>>
>>> At least the hotplug/mode change events are not needed. We only have the
>>> two points where i915 should inform the audio driver about this stuff,
>>> and those are the intel_audio_code_enable/disable(). For that we
>>> already have the .pin_eld_notify() hook.
>>>
>>> The interrupt stuff should mostly vanish from i915 with the subdevice
>>> approach. As in i915 would just call the interrupt handler of the audio
>>> driver based on the LPE bits in IIR, and the audio driver can then do
>>> whatever it wants based on its own status register.
>>
>> Are you saying that the subdevice would provide a read/write interface
>> for the audio driver to look at display registers, and the i915 driver
>> would only provide a notification interface (EDID and interrupts) to the
>> audio driver?
>
> The audio driver would simply ioremap the appropriate range of
> registers itself.
>
>> If yes, would there be two component framework links, one between
>> i915/audio driver and one between subdevice/audio driver.
>
> Yeah sort of. i915 registers the platform device for the audio, the
> audio driver can then bind to the device via the platform driver .probe
> callback. It can then register with the audio component stuff at some
> point to get the relevant notifications on the display state. When
> i915 gets unloaded we remove the platform device, at which point the
> audio driver's platform driver .remove() callback gets invoked and
> it should unregister/cleanup everything.

we don't want to expose this interface when HDAudio is present and 
enabled so we would need to add a test for this.
Also it looks like you want the creation of the platform device done in 
i915, we were thinking of doing this as part of the audio drivers but in 
the end this looks equivalent. In both cases we would end-up ignoring 
the HAD022A8 HID and not use acpi for this extension

> I just tried to frob around with the VED code a bit, and got it to load
> at least. It's not quite happy about reloading i915 while the ipvr
> driver was loaded though. Not sure what's going on there, but I do
> think this approach should work. So the VED patch could serve as a
> decent enough model to follow.
>

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-14 15:13         ` Pierre-Louis Bossart
@ 2016-03-14 15:21           ` Ville Syrjälä
  2016-03-14 15:30             ` Ville Syrjälä
  0 siblings, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-14 15:21 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Mon, Mar 14, 2016 at 10:13:58AM -0500, Pierre-Louis Bossart wrote:
> On 3/11/16 1:09 PM, Ville Syrjälä wrote:
> > On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> >> Thanks for the review Ville
> >>
> >> [snip]
> >>
> >>> Kinda hard to see where everything gets used due to the way the patches
> >>> are split up.
> >>
> >> Yes, it's far from great...
> >>
> >>> At least the hotplug/mode change events are not needed. We only have the
> >>> two points where i915 should inform the audio driver about this stuff,
> >>> and those are the intel_audio_code_enable/disable(). For that we
> >>> already have the .pin_eld_notify() hook.
> >>>
> >>> The interrupt stuff should mostly vanish from i915 with the subdevice
> >>> approach. As in i915 would just call the interrupt handler of the audio
> >>> driver based on the LPE bits in IIR, and the audio driver can then do
> >>> whatever it wants based on its own status register.
> >>
> >> Are you saying that the subdevice would provide a read/write interface
> >> for the audio driver to look at display registers, and the i915 driver
> >> would only provide a notification interface (EDID and interrupts) to the
> >> audio driver?
> >
> > The audio driver would simply ioremap the appropriate range of
> > registers itself.
> >
> >> If yes, would there be two component framework links, one between
> >> i915/audio driver and one between subdevice/audio driver.
> >
> > Yeah sort of. i915 registers the platform device for the audio, the
> > audio driver can then bind to the device via the platform driver .probe
> > callback. It can then register with the audio component stuff at some
> > point to get the relevant notifications on the display state. When
> > i915 gets unloaded we remove the platform device, at which point the
> > audio driver's platform driver .remove() callback gets invoked and
> > it should unregister/cleanup everything.
> 
> we don't want to expose this interface when HDAudio is present and 
> enabled so we would need to add a test for this.
> Also it looks like you want the creation of the platform device done in 
> i915, we were thinking of doing this as part of the audio drivers but in 
> the end this looks equivalent. In both cases we would end-up ignoring 
> the HAD022A8 HID and not use acpi for this extension

Well, if you have a device you can hang off from then i915 should need
to register it I suppose. Though that would make the interrupt
forwarding perhaps less nice. There's also the suspend/resume order
dependency to deal with if there's no parent/child relationship between
the devices.

> 
> > I just tried to frob around with the VED code a bit, and got it to load
> > at least. It's not quite happy about reloading i915 while the ipvr
> > driver was loaded though. Not sure what's going on there, but I do
> > think this approach should work. So the VED patch could serve as a
> > decent enough model to follow.
> >

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-14 15:21           ` Ville Syrjälä
@ 2016-03-14 15:30             ` Ville Syrjälä
  2016-03-14 17:27               ` Pierre-Louis Bossart
  0 siblings, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-14 15:30 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Mon, Mar 14, 2016 at 05:21:54PM +0200, Ville Syrjälä wrote:
> On Mon, Mar 14, 2016 at 10:13:58AM -0500, Pierre-Louis Bossart wrote:
> > On 3/11/16 1:09 PM, Ville Syrjälä wrote:
> > > On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > >> Thanks for the review Ville
> > >>
> > >> [snip]
> > >>
> > >>> Kinda hard to see where everything gets used due to the way the patches
> > >>> are split up.
> > >>
> > >> Yes, it's far from great...
> > >>
> > >>> At least the hotplug/mode change events are not needed. We only have the
> > >>> two points where i915 should inform the audio driver about this stuff,
> > >>> and those are the intel_audio_code_enable/disable(). For that we
> > >>> already have the .pin_eld_notify() hook.
> > >>>
> > >>> The interrupt stuff should mostly vanish from i915 with the subdevice
> > >>> approach. As in i915 would just call the interrupt handler of the audio
> > >>> driver based on the LPE bits in IIR, and the audio driver can then do
> > >>> whatever it wants based on its own status register.
> > >>
> > >> Are you saying that the subdevice would provide a read/write interface
> > >> for the audio driver to look at display registers, and the i915 driver
> > >> would only provide a notification interface (EDID and interrupts) to the
> > >> audio driver?
> > >
> > > The audio driver would simply ioremap the appropriate range of
> > > registers itself.
> > >
> > >> If yes, would there be two component framework links, one between
> > >> i915/audio driver and one between subdevice/audio driver.
> > >
> > > Yeah sort of. i915 registers the platform device for the audio, the
> > > audio driver can then bind to the device via the platform driver .probe
> > > callback. It can then register with the audio component stuff at some
> > > point to get the relevant notifications on the display state. When
> > > i915 gets unloaded we remove the platform device, at which point the
> > > audio driver's platform driver .remove() callback gets invoked and
> > > it should unregister/cleanup everything.
> > 
> > we don't want to expose this interface when HDAudio is present and 
> > enabled so we would need to add a test for this.
> > Also it looks like you want the creation of the platform device done in 
> > i915, we were thinking of doing this as part of the audio drivers but in 
> > the end this looks equivalent. In both cases we would end-up ignoring 
> > the HAD022A8 HID and not use acpi for this extension
> 
> Well, if you have a device you can hang off from then i915 should need
> to register it I suppose. Though that would make the interrupt
> forwarding perhaps less nice. There's also the suspend/resume order
> dependency to deal with if there's no parent/child relationship between
> the devices.

Oh and I suppose you'd end up ioremapping part of the pci dev2 mmio bar
to get at the registers, which would look a bit funkly at least.

> 
> > 
> > > I just tried to frob around with the VED code a bit, and got it to load
> > > at least. It's not quite happy about reloading i915 while the ipvr
> > > driver was loaded though. Not sure what's going on there, but I do
> > > think this approach should work. So the VED patch could serve as a
> > > decent enough model to follow.
> > >
> 
> -- 
> Ville Syrjälä
> Intel OTC
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-14 15:30             ` Ville Syrjälä
@ 2016-03-14 17:27               ` Pierre-Louis Bossart
  2016-03-15  8:39                 ` Daniel Vetter
  0 siblings, 1 reply; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-14 17:27 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On 3/14/16 10:30 AM, Ville Syrjälä wrote:
> On Mon, Mar 14, 2016 at 05:21:54PM +0200, Ville Syrjälä wrote:
>> On Mon, Mar 14, 2016 at 10:13:58AM -0500, Pierre-Louis Bossart wrote:
>>> On 3/11/16 1:09 PM, Ville Syrjälä wrote:
>>>> On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
>>>>> Thanks for the review Ville
>>>>>
>>>>> [snip]
>>>>>
>>>>>> Kinda hard to see where everything gets used due to the way the patches
>>>>>> are split up.
>>>>>
>>>>> Yes, it's far from great...
>>>>>
>>>>>> At least the hotplug/mode change events are not needed. We only have the
>>>>>> two points where i915 should inform the audio driver about this stuff,
>>>>>> and those are the intel_audio_code_enable/disable(). For that we
>>>>>> already have the .pin_eld_notify() hook.
>>>>>>
>>>>>> The interrupt stuff should mostly vanish from i915 with the subdevice
>>>>>> approach. As in i915 would just call the interrupt handler of the audio
>>>>>> driver based on the LPE bits in IIR, and the audio driver can then do
>>>>>> whatever it wants based on its own status register.
>>>>>
>>>>> Are you saying that the subdevice would provide a read/write interface
>>>>> for the audio driver to look at display registers, and the i915 driver
>>>>> would only provide a notification interface (EDID and interrupts) to the
>>>>> audio driver?
>>>>
>>>> The audio driver would simply ioremap the appropriate range of
>>>> registers itself.
>>>>
>>>>> If yes, would there be two component framework links, one between
>>>>> i915/audio driver and one between subdevice/audio driver.
>>>>
>>>> Yeah sort of. i915 registers the platform device for the audio, the
>>>> audio driver can then bind to the device via the platform driver .probe
>>>> callback. It can then register with the audio component stuff at some
>>>> point to get the relevant notifications on the display state. When
>>>> i915 gets unloaded we remove the platform device, at which point the
>>>> audio driver's platform driver .remove() callback gets invoked and
>>>> it should unregister/cleanup everything.
>>>
>>> we don't want to expose this interface when HDAudio is present and
>>> enabled so we would need to add a test for this.
>>> Also it looks like you want the creation of the platform device done in
>>> i915, we were thinking of doing this as part of the audio drivers but in
>>> the end this looks equivalent. In both cases we would end-up ignoring
>>> the HAD022A8 HID and not use acpi for this extension
>>
>> Well, if you have a device you can hang off from then i915 should need
>> to register it I suppose. Though that would make the interrupt
>> forwarding perhaps less nice. There's also the suspend/resume order
>> dependency to deal with if there's no parent/child relationship between
>> the devices.
>
> Oh and I suppose you'd end up ioremapping part of the pci dev2 mmio bar
> to get at the registers, which would look a bit funkly at least.

I understand the benefits of a parent/child device/subdevice model. What 
I don't see is whether we need the component framework at all here?
It was used in the case of HDaudio since both i915 and HDaudio 
controllers get probed at different times, here the HDMI interface is 
just a bunch of registers/DMA from the same hardware so the whole 
master/client interface exposed by the component framework to 'bind' 
independent drivers is a bit overkill?

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-14 14:20           ` Ville Syrjälä
@ 2016-03-15  8:35             ` Daniel Vetter
  2016-03-15 13:30               ` Ville Syrjälä
  0 siblings, 1 reply; 47+ messages in thread
From: Daniel Vetter @ 2016-03-15  8:35 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Mon, Mar 14, 2016 at 04:20:19PM +0200, Ville Syrjälä wrote:
> On Mon, Mar 14, 2016 at 10:04:00AM +0100, Daniel Vetter wrote:
> > On Fri, Mar 11, 2016 at 09:09:12PM +0200, Ville Syrjälä wrote:
> > > On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > > > Thanks for the review Ville
> > > > 
> > > > [snip]
> > > > 
> > > > > Kinda hard to see where everything gets used due to the way the patches
> > > > > are split up.
> > > > 
> > > > Yes, it's far from great...
> > > > 
> > > > > At least the hotplug/mode change events are not needed. We only have the
> > > > > two points where i915 should inform the audio driver about this stuff,
> > > > > and those are the intel_audio_code_enable/disable(). For that we
> > > > > already have the .pin_eld_notify() hook.
> > > > >
> > > > > The interrupt stuff should mostly vanish from i915 with the subdevice
> > > > > approach. As in i915 would just call the interrupt handler of the audio
> > > > > driver based on the LPE bits in IIR, and the audio driver can then do
> > > > > whatever it wants based on its own status register.
> > > > 
> > > > Are you saying that the subdevice would provide a read/write interface 
> > > > for the audio driver to look at display registers, and the i915 driver 
> > > > would only provide a notification interface (EDID and interrupts) to the 
> > > > audio driver?
> > > 
> > > The audio driver would simply ioremap the appropriate range of
> > > registers itself.
> > > 
> > > > If yes, would there be two component framework links, one between 
> > > > i915/audio driver and one between subdevice/audio driver.
> > > 
> > > Yeah sort of. i915 registers the platform device for the audio, the
> > > audio driver can then bind to the device via the platform driver .probe
> > > callback. It can then register with the audio component stuff at some
> > > point to get the relevant notifications on the display state. When
> > > i915 gets unloaded we remove the platform device, at which point the
> > > audio driver's platform driver .remove() callback gets invoked and
> > > it should unregister/cleanup everything.
> > > 
> > > I just tried to frob around with the VED code a bit, and got it to load
> > > at least. It's not quite happy about reloading i915 while the ipvr
> > > driver was loaded though. Not sure what's going on there, but I do
> > > think this approach should work. So the VED patch could serve as a
> > > decent enough model to follow.
> > 
> > platform devices registerd by modules are apparently inherently racy and
> > in an unfixable way. At least I remember something like that from VED
> > discussion.
> > 
> > In short you _must_ unload VED manually before unloading i915, or it all
> > goes boom. If this is the only thing that went boom it's acceptable.
> 
> VED goes boom due drm_global_mutex deadlock at least if you load
> i915 while ipvr is already loaded. I didn't check to hard if there
> were any booms on pure unload so far.

Oh right another boom that happened, but can be avoided by dropping the
->load callback and directly calling drm_dev_alloc/register. Shouldn't be
a problem with a non-drm driver though.

> Anyways, I was a bit worried about the races so I did a pair of 
> small test modules to try out this model, and to me it looked to
> work so far. I just unregistered the platform device from the parent
> pci driver .remove() hook, and it got blocked until the platform
> driver's .remove() hook was done.
> 
> In any case if this is broken, then I assume mfd must be broken. And
> that thing is at least used quite extensively.

Hm, I don't remember the exact details, but iirc the problem was that the
struct device is refcounted, but you can't add a module ref for the vtable
is has (specifically the final release method) since that would result in
a ref-loop. Usually it works, but if someone keeps the device alive
(through sysfs or whatever) and you manage to unload everything before
that last ref gets dropped it goes boom.

So "works", but not in a safe way.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-14  9:04         ` Daniel Vetter
  2016-03-14 14:20           ` Ville Syrjälä
@ 2016-03-15  8:36           ` Daniel Vetter
  1 sibling, 0 replies; 47+ messages in thread
From: Daniel Vetter @ 2016-03-15  8:36 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Mon, Mar 14, 2016 at 10:04:00AM +0100, Daniel Vetter wrote:
> On Fri, Mar 11, 2016 at 09:09:12PM +0200, Ville Syrjälä wrote:
> > On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > > Thanks for the review Ville
> > > 
> > > [snip]
> > > 
> > > > Kinda hard to see where everything gets used due to the way the patches
> > > > are split up.
> > > 
> > > Yes, it's far from great...
> > > 
> > > > At least the hotplug/mode change events are not needed. We only have the
> > > > two points where i915 should inform the audio driver about this stuff,
> > > > and those are the intel_audio_code_enable/disable(). For that we
> > > > already have the .pin_eld_notify() hook.
> > > >
> > > > The interrupt stuff should mostly vanish from i915 with the subdevice
> > > > approach. As in i915 would just call the interrupt handler of the audio
> > > > driver based on the LPE bits in IIR, and the audio driver can then do
> > > > whatever it wants based on its own status register.
> > > 
> > > Are you saying that the subdevice would provide a read/write interface 
> > > for the audio driver to look at display registers, and the i915 driver 
> > > would only provide a notification interface (EDID and interrupts) to the 
> > > audio driver?
> > 
> > The audio driver would simply ioremap the appropriate range of
> > registers itself.
> > 
> > > If yes, would there be two component framework links, one between 
> > > i915/audio driver and one between subdevice/audio driver.
> > 
> > Yeah sort of. i915 registers the platform device for the audio, the
> > audio driver can then bind to the device via the platform driver .probe
> > callback. It can then register with the audio component stuff at some
> > point to get the relevant notifications on the display state. When
> > i915 gets unloaded we remove the platform device, at which point the
> > audio driver's platform driver .remove() callback gets invoked and
> > it should unregister/cleanup everything.
> > 
> > I just tried to frob around with the VED code a bit, and got it to load
> > at least. It's not quite happy about reloading i915 while the ipvr
> > driver was loaded though. Not sure what's going on there, but I do
> > think this approach should work. So the VED patch could serve as a
> > decent enough model to follow.
> 
> platform devices registerd by modules are apparently inherently racy and
> in an unfixable way. At least I remember something like that from VED
> discussion.
> 
> In short you _must_ unload VED manually before unloading i915, or it all
> goes boom. If this is the only thing that went boom it's acceptable.
> 
> Another bit we didn't fully do for VED is abstracting away the dma mapping
> stuff, because x86 dma abstraction sucks (compared to arm). Not sure, but
> this might have been fixed meanwhile - if we can set up a dma_ops that the
> subdevice would use, we should do so (instead of the page_to_pfn hacks VED
> used).

This one might be a bit a problem - on byt we got away with pfn_to_page
because no iommu at all, but that's not a good idea really. Definitely
need to reevaluate this again. Iirc there's been some talk of just walking
up a chain of platform devices until the core x86 dma code finds something
with dma support, then use that.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-14 17:27               ` Pierre-Louis Bossart
@ 2016-03-15  8:39                 ` Daniel Vetter
  2016-03-15 13:35                   ` Ville Syrjälä
  0 siblings, 1 reply; 47+ messages in thread
From: Daniel Vetter @ 2016-03-15  8:39 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Mon, Mar 14, 2016 at 12:27:51PM -0500, Pierre-Louis Bossart wrote:
> On 3/14/16 10:30 AM, Ville Syrjälä wrote:
> >On Mon, Mar 14, 2016 at 05:21:54PM +0200, Ville Syrjälä wrote:
> >>On Mon, Mar 14, 2016 at 10:13:58AM -0500, Pierre-Louis Bossart wrote:
> >>>On 3/11/16 1:09 PM, Ville Syrjälä wrote:
> >>>>On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> >>>>>Thanks for the review Ville
> >>>>>
> >>>>>[snip]
> >>>>>
> >>>>>>Kinda hard to see where everything gets used due to the way the patches
> >>>>>>are split up.
> >>>>>
> >>>>>Yes, it's far from great...
> >>>>>
> >>>>>>At least the hotplug/mode change events are not needed. We only have the
> >>>>>>two points where i915 should inform the audio driver about this stuff,
> >>>>>>and those are the intel_audio_code_enable/disable(). For that we
> >>>>>>already have the .pin_eld_notify() hook.
> >>>>>>
> >>>>>>The interrupt stuff should mostly vanish from i915 with the subdevice
> >>>>>>approach. As in i915 would just call the interrupt handler of the audio
> >>>>>>driver based on the LPE bits in IIR, and the audio driver can then do
> >>>>>>whatever it wants based on its own status register.
> >>>>>
> >>>>>Are you saying that the subdevice would provide a read/write interface
> >>>>>for the audio driver to look at display registers, and the i915 driver
> >>>>>would only provide a notification interface (EDID and interrupts) to the
> >>>>>audio driver?
> >>>>
> >>>>The audio driver would simply ioremap the appropriate range of
> >>>>registers itself.
> >>>>
> >>>>>If yes, would there be two component framework links, one between
> >>>>>i915/audio driver and one between subdevice/audio driver.
> >>>>
> >>>>Yeah sort of. i915 registers the platform device for the audio, the
> >>>>audio driver can then bind to the device via the platform driver .probe
> >>>>callback. It can then register with the audio component stuff at some
> >>>>point to get the relevant notifications on the display state. When
> >>>>i915 gets unloaded we remove the platform device, at which point the
> >>>>audio driver's platform driver .remove() callback gets invoked and
> >>>>it should unregister/cleanup everything.
> >>>
> >>>we don't want to expose this interface when HDAudio is present and
> >>>enabled so we would need to add a test for this.
> >>>Also it looks like you want the creation of the platform device done in
> >>>i915, we were thinking of doing this as part of the audio drivers but in
> >>>the end this looks equivalent. In both cases we would end-up ignoring
> >>>the HAD022A8 HID and not use acpi for this extension
> >>
> >>Well, if you have a device you can hang off from then i915 should need
> >>to register it I suppose. Though that would make the interrupt
> >>forwarding perhaps less nice. There's also the suspend/resume order
> >>dependency to deal with if there's no parent/child relationship between
> >>the devices.
> >
> >Oh and I suppose you'd end up ioremapping part of the pci dev2 mmio bar
> >to get at the registers, which would look a bit funkly at least.
> 
> I understand the benefits of a parent/child device/subdevice model. What I
> don't see is whether we need the component framework at all here?
> It was used in the case of HDaudio since both i915 and HDaudio controllers
> get probed at different times, here the HDMI interface is just a bunch of
> registers/DMA from the same hardware so the whole master/client interface
> exposed by the component framework to 'bind' independent drivers is a bit
> overkill?

I haven't read the patches, but using component.c when you instead can
model it with parent/child smells like abuse. Component.c is meant for
when you have multiple devices all over the device tree that in aggregate
constitute the overall logical driver. This doesn't seem to be the case
here.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-15  8:35             ` Daniel Vetter
@ 2016-03-15 13:30               ` Ville Syrjälä
  2016-03-16 16:43                 ` Ville Syrjälä
  0 siblings, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-15 13:30 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Tue, Mar 15, 2016 at 09:35:26AM +0100, Daniel Vetter wrote:
> On Mon, Mar 14, 2016 at 04:20:19PM +0200, Ville Syrjälä wrote:
> > On Mon, Mar 14, 2016 at 10:04:00AM +0100, Daniel Vetter wrote:
> > > On Fri, Mar 11, 2016 at 09:09:12PM +0200, Ville Syrjälä wrote:
> > > > On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > > > > Thanks for the review Ville
> > > > > 
> > > > > [snip]
> > > > > 
> > > > > > Kinda hard to see where everything gets used due to the way the patches
> > > > > > are split up.
> > > > > 
> > > > > Yes, it's far from great...
> > > > > 
> > > > > > At least the hotplug/mode change events are not needed. We only have the
> > > > > > two points where i915 should inform the audio driver about this stuff,
> > > > > > and those are the intel_audio_code_enable/disable(). For that we
> > > > > > already have the .pin_eld_notify() hook.
> > > > > >
> > > > > > The interrupt stuff should mostly vanish from i915 with the subdevice
> > > > > > approach. As in i915 would just call the interrupt handler of the audio
> > > > > > driver based on the LPE bits in IIR, and the audio driver can then do
> > > > > > whatever it wants based on its own status register.
> > > > > 
> > > > > Are you saying that the subdevice would provide a read/write interface 
> > > > > for the audio driver to look at display registers, and the i915 driver 
> > > > > would only provide a notification interface (EDID and interrupts) to the 
> > > > > audio driver?
> > > > 
> > > > The audio driver would simply ioremap the appropriate range of
> > > > registers itself.
> > > > 
> > > > > If yes, would there be two component framework links, one between 
> > > > > i915/audio driver and one between subdevice/audio driver.
> > > > 
> > > > Yeah sort of. i915 registers the platform device for the audio, the
> > > > audio driver can then bind to the device via the platform driver .probe
> > > > callback. It can then register with the audio component stuff at some
> > > > point to get the relevant notifications on the display state. When
> > > > i915 gets unloaded we remove the platform device, at which point the
> > > > audio driver's platform driver .remove() callback gets invoked and
> > > > it should unregister/cleanup everything.
> > > > 
> > > > I just tried to frob around with the VED code a bit, and got it to load
> > > > at least. It's not quite happy about reloading i915 while the ipvr
> > > > driver was loaded though. Not sure what's going on there, but I do
> > > > think this approach should work. So the VED patch could serve as a
> > > > decent enough model to follow.
> > > 
> > > platform devices registerd by modules are apparently inherently racy and
> > > in an unfixable way. At least I remember something like that from VED
> > > discussion.
> > > 
> > > In short you _must_ unload VED manually before unloading i915, or it all
> > > goes boom. If this is the only thing that went boom it's acceptable.
> > 
> > VED goes boom due drm_global_mutex deadlock at least if you load
> > i915 while ipvr is already loaded. I didn't check to hard if there
> > were any booms on pure unload so far.
> 
> Oh right another boom that happened, but can be avoided by dropping the
> ->load callback and directly calling drm_dev_alloc/register. Shouldn't be
> a problem with a non-drm driver though.
> 
> > Anyways, I was a bit worried about the races so I did a pair of 
> > small test modules to try out this model, and to me it looked to
> > work so far. I just unregistered the platform device from the parent
> > pci driver .remove() hook, and it got blocked until the platform
> > driver's .remove() hook was done.
> > 
> > In any case if this is broken, then I assume mfd must be broken. And
> > that thing is at least used quite extensively.
> 
> Hm, I don't remember the exact details, but iirc the problem was that the
> struct device is refcounted, but you can't add a module ref for the vtable
> is has (specifically the final release method) since that would result in
> a ref-loop. Usually it works, but if someone keeps the device alive
> (through sysfs or whatever) and you manage to unload everything before
> that last ref gets dropped it goes boom.
> 
> So "works", but not in a safe way.

I was worried that it's something like that. I guess I'll need to try
grab a ref on something in my test module and see how it fares.

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-15  8:39                 ` Daniel Vetter
@ 2016-03-15 13:35                   ` Ville Syrjälä
  2016-03-15 13:43                     ` Daniel Vetter
  2016-03-15 16:21                     ` Vinod Koul
  0 siblings, 2 replies; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-15 13:35 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Tue, Mar 15, 2016 at 09:39:48AM +0100, Daniel Vetter wrote:
> On Mon, Mar 14, 2016 at 12:27:51PM -0500, Pierre-Louis Bossart wrote:
> > On 3/14/16 10:30 AM, Ville Syrjälä wrote:
> > >On Mon, Mar 14, 2016 at 05:21:54PM +0200, Ville Syrjälä wrote:
> > >>On Mon, Mar 14, 2016 at 10:13:58AM -0500, Pierre-Louis Bossart wrote:
> > >>>On 3/11/16 1:09 PM, Ville Syrjälä wrote:
> > >>>>On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > >>>>>Thanks for the review Ville
> > >>>>>
> > >>>>>[snip]
> > >>>>>
> > >>>>>>Kinda hard to see where everything gets used due to the way the patches
> > >>>>>>are split up.
> > >>>>>
> > >>>>>Yes, it's far from great...
> > >>>>>
> > >>>>>>At least the hotplug/mode change events are not needed. We only have the
> > >>>>>>two points where i915 should inform the audio driver about this stuff,
> > >>>>>>and those are the intel_audio_code_enable/disable(). For that we
> > >>>>>>already have the .pin_eld_notify() hook.
> > >>>>>>
> > >>>>>>The interrupt stuff should mostly vanish from i915 with the subdevice
> > >>>>>>approach. As in i915 would just call the interrupt handler of the audio
> > >>>>>>driver based on the LPE bits in IIR, and the audio driver can then do
> > >>>>>>whatever it wants based on its own status register.
> > >>>>>
> > >>>>>Are you saying that the subdevice would provide a read/write interface
> > >>>>>for the audio driver to look at display registers, and the i915 driver
> > >>>>>would only provide a notification interface (EDID and interrupts) to the
> > >>>>>audio driver?
> > >>>>
> > >>>>The audio driver would simply ioremap the appropriate range of
> > >>>>registers itself.
> > >>>>
> > >>>>>If yes, would there be two component framework links, one between
> > >>>>>i915/audio driver and one between subdevice/audio driver.
> > >>>>
> > >>>>Yeah sort of. i915 registers the platform device for the audio, the
> > >>>>audio driver can then bind to the device via the platform driver .probe
> > >>>>callback. It can then register with the audio component stuff at some
> > >>>>point to get the relevant notifications on the display state. When
> > >>>>i915 gets unloaded we remove the platform device, at which point the
> > >>>>audio driver's platform driver .remove() callback gets invoked and
> > >>>>it should unregister/cleanup everything.
> > >>>
> > >>>we don't want to expose this interface when HDAudio is present and
> > >>>enabled so we would need to add a test for this.
> > >>>Also it looks like you want the creation of the platform device done in
> > >>>i915, we were thinking of doing this as part of the audio drivers but in
> > >>>the end this looks equivalent. In both cases we would end-up ignoring
> > >>>the HAD022A8 HID and not use acpi for this extension
> > >>
> > >>Well, if you have a device you can hang off from then i915 should need
> > >>to register it I suppose. Though that would make the interrupt
> > >>forwarding perhaps less nice. There's also the suspend/resume order
> > >>dependency to deal with if there's no parent/child relationship between
> > >>the devices.
> > >
> > >Oh and I suppose you'd end up ioremapping part of the pci dev2 mmio bar
> > >to get at the registers, which would look a bit funkly at least.
> > 
> > I understand the benefits of a parent/child device/subdevice model. What I
> > don't see is whether we need the component framework at all here?
> > It was used in the case of HDaudio since both i915 and HDaudio controllers
> > get probed at different times, here the HDMI interface is just a bunch of
> > registers/DMA from the same hardware so the whole master/client interface
> > exposed by the component framework to 'bind' independent drivers is a bit
> > overkill?
> 
> I haven't read the patches, but using component.c when you instead can
> model it with parent/child smells like abuse. Component.c is meant for
> when you have multiple devices all over the device tree that in aggregate
> constitute the overall logical driver. This doesn't seem to be the case
> here.

We still need the eld notify hooks so that i915 can inform the audio
driver about the state of the display. Whether that's best done via
the component stuff or something else I don't know.

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-15 13:35                   ` Ville Syrjälä
@ 2016-03-15 13:43                     ` Daniel Vetter
  2016-03-15 16:21                     ` Vinod Koul
  1 sibling, 0 replies; 47+ messages in thread
From: Daniel Vetter @ 2016-03-15 13:43 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Tue, Mar 15, 2016 at 03:35:45PM +0200, Ville Syrjälä wrote:
> On Tue, Mar 15, 2016 at 09:39:48AM +0100, Daniel Vetter wrote:
> > On Mon, Mar 14, 2016 at 12:27:51PM -0500, Pierre-Louis Bossart wrote:
> > > On 3/14/16 10:30 AM, Ville Syrjälä wrote:
> > > >On Mon, Mar 14, 2016 at 05:21:54PM +0200, Ville Syrjälä wrote:
> > > >>On Mon, Mar 14, 2016 at 10:13:58AM -0500, Pierre-Louis Bossart wrote:
> > > >>>On 3/11/16 1:09 PM, Ville Syrjälä wrote:
> > > >>>>On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > > >>>>>Thanks for the review Ville
> > > >>>>>
> > > >>>>>[snip]
> > > >>>>>
> > > >>>>>>Kinda hard to see where everything gets used due to the way the patches
> > > >>>>>>are split up.
> > > >>>>>
> > > >>>>>Yes, it's far from great...
> > > >>>>>
> > > >>>>>>At least the hotplug/mode change events are not needed. We only have the
> > > >>>>>>two points where i915 should inform the audio driver about this stuff,
> > > >>>>>>and those are the intel_audio_code_enable/disable(). For that we
> > > >>>>>>already have the .pin_eld_notify() hook.
> > > >>>>>>
> > > >>>>>>The interrupt stuff should mostly vanish from i915 with the subdevice
> > > >>>>>>approach. As in i915 would just call the interrupt handler of the audio
> > > >>>>>>driver based on the LPE bits in IIR, and the audio driver can then do
> > > >>>>>>whatever it wants based on its own status register.
> > > >>>>>
> > > >>>>>Are you saying that the subdevice would provide a read/write interface
> > > >>>>>for the audio driver to look at display registers, and the i915 driver
> > > >>>>>would only provide a notification interface (EDID and interrupts) to the
> > > >>>>>audio driver?
> > > >>>>
> > > >>>>The audio driver would simply ioremap the appropriate range of
> > > >>>>registers itself.
> > > >>>>
> > > >>>>>If yes, would there be two component framework links, one between
> > > >>>>>i915/audio driver and one between subdevice/audio driver.
> > > >>>>
> > > >>>>Yeah sort of. i915 registers the platform device for the audio, the
> > > >>>>audio driver can then bind to the device via the platform driver .probe
> > > >>>>callback. It can then register with the audio component stuff at some
> > > >>>>point to get the relevant notifications on the display state. When
> > > >>>>i915 gets unloaded we remove the platform device, at which point the
> > > >>>>audio driver's platform driver .remove() callback gets invoked and
> > > >>>>it should unregister/cleanup everything.
> > > >>>
> > > >>>we don't want to expose this interface when HDAudio is present and
> > > >>>enabled so we would need to add a test for this.
> > > >>>Also it looks like you want the creation of the platform device done in
> > > >>>i915, we were thinking of doing this as part of the audio drivers but in
> > > >>>the end this looks equivalent. In both cases we would end-up ignoring
> > > >>>the HAD022A8 HID and not use acpi for this extension
> > > >>
> > > >>Well, if you have a device you can hang off from then i915 should need
> > > >>to register it I suppose. Though that would make the interrupt
> > > >>forwarding perhaps less nice. There's also the suspend/resume order
> > > >>dependency to deal with if there's no parent/child relationship between
> > > >>the devices.
> > > >
> > > >Oh and I suppose you'd end up ioremapping part of the pci dev2 mmio bar
> > > >to get at the registers, which would look a bit funkly at least.
> > > 
> > > I understand the benefits of a parent/child device/subdevice model. What I
> > > don't see is whether we need the component framework at all here?
> > > It was used in the case of HDaudio since both i915 and HDaudio controllers
> > > get probed at different times, here the HDMI interface is just a bunch of
> > > registers/DMA from the same hardware so the whole master/client interface
> > > exposed by the component framework to 'bind' independent drivers is a bit
> > > overkill?
> > 
> > I haven't read the patches, but using component.c when you instead can
> > model it with parent/child smells like abuse. Component.c is meant for
> > when you have multiple devices all over the device tree that in aggregate
> > constitute the overall logical driver. This doesn't seem to be the case
> > here.
> 
> We still need the eld notify hooks so that i915 can inform the audio
> driver about the state of the display. Whether that's best done via
> the component stuff or something else I don't know.

Hm right. I guess we could stuff it into the platform data stuff maybe
instead, so the driver could get at the i915/snd interface directly?
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-15 13:35                   ` Ville Syrjälä
  2016-03-15 13:43                     ` Daniel Vetter
@ 2016-03-15 16:21                     ` Vinod Koul
  2016-03-15 21:14                       ` Pierre-Louis Bossart
  1 sibling, 1 reply; 47+ messages in thread
From: Vinod Koul @ 2016-03-15 16:21 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, broonie,
	rakesh.a.ughreja, David Henningsson

On Tue, Mar 15, 2016 at 03:35:45PM +0200, Ville Syrjälä wrote:
> > > I understand the benefits of a parent/child device/subdevice model. What I
> > > don't see is whether we need the component framework at all here?
> > > It was used in the case of HDaudio since both i915 and HDaudio controllers
> > > get probed at different times, here the HDMI interface is just a bunch of
> > > registers/DMA from the same hardware so the whole master/client interface
> > > exposed by the component framework to 'bind' independent drivers is a bit
> > > overkill?
> > 
> > I haven't read the patches, but using component.c when you instead can
> > model it with parent/child smells like abuse. Component.c is meant for
> > when you have multiple devices all over the device tree that in aggregate
> > constitute the overall logical driver. This doesn't seem to be the case
> > here.

Right I do think that might be the case.

> We still need the eld notify hooks so that i915 can inform the audio
> driver about the state of the display. Whether that's best done via
> the component stuff or something else I don't know.

There is already work ongoing by ARM folks for the interface, should we
reuse that [1]. I would certainly argue reusing rather than redfeining a
new one would be better.

Btw this interface seems to rely on display side implemting these ops.

Thanks
-- 
~Vinod

[1]: http://mailman.alsa-project.org/pipermail/alsa-devel/2016-March/105526.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-15 16:21                     ` Vinod Koul
@ 2016-03-15 21:14                       ` Pierre-Louis Bossart
  2016-03-16  3:09                         ` Vinod Koul
  0 siblings, 1 reply; 47+ messages in thread
From: Pierre-Louis Bossart @ 2016-03-15 21:14 UTC (permalink / raw)
  To: Vinod Koul, Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, broonie,
	rakesh.a.ughreja, David Henningsson

On 3/15/16 11:21 AM, Vinod Koul wrote:
> On Tue, Mar 15, 2016 at 03:35:45PM +0200, Ville Syrjälä wrote:
>>>> I understand the benefits of a parent/child device/subdevice model. What I
>>>> don't see is whether we need the component framework at all here?
>>>> It was used in the case of HDaudio since both i915 and HDaudio controllers
>>>> get probed at different times, here the HDMI interface is just a bunch of
>>>> registers/DMA from the same hardware so the whole master/client interface
>>>> exposed by the component framework to 'bind' independent drivers is a bit
>>>> overkill?
>>>
>>> I haven't read the patches, but using component.c when you instead can
>>> model it with parent/child smells like abuse. Component.c is meant for
>>> when you have multiple devices all over the device tree that in aggregate
>>> constitute the overall logical driver. This doesn't seem to be the case
>>> here.
>
> Right I do think that might be the case.
>
>> We still need the eld notify hooks so that i915 can inform the audio
>> driver about the state of the display. Whether that's best done via
>> the component stuff or something else I don't know.
>
> There is already work ongoing by ARM folks for the interface, should we
> reuse that [1]. I would certainly argue reusing rather than redfeining a
> new one would be better.
>
> Btw this interface seems to rely on display side implemting these ops.

My understanding is that it's an interface for external encoders that 
have an I2S or S/PDIF link. Such external encoders appear as ASoC codecs 
that can be bound to the SoC with DT bindings. I don't see what we could 
reuse here?

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-15 21:14                       ` Pierre-Louis Bossart
@ 2016-03-16  3:09                         ` Vinod Koul
  0 siblings, 0 replies; 47+ messages in thread
From: Vinod Koul @ 2016-03-16  3:09 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, broonie,
	rakesh.a.ughreja, David Henningsson

On Tue, Mar 15, 2016 at 04:14:19PM -0500, Pierre-Louis Bossart wrote:
> On 3/15/16 11:21 AM, Vinod Koul wrote:
> >On Tue, Mar 15, 2016 at 03:35:45PM +0200, Ville Syrjälä wrote:
> >>>>I understand the benefits of a parent/child device/subdevice model. What I
> >>>>don't see is whether we need the component framework at all here?
> >>>>It was used in the case of HDaudio since both i915 and HDaudio controllers
> >>>>get probed at different times, here the HDMI interface is just a bunch of
> >>>>registers/DMA from the same hardware so the whole master/client interface
> >>>>exposed by the component framework to 'bind' independent drivers is a bit
> >>>>overkill?
> >>>
> >>>I haven't read the patches, but using component.c when you instead can
> >>>model it with parent/child smells like abuse. Component.c is meant for
> >>>when you have multiple devices all over the device tree that in aggregate
> >>>constitute the overall logical driver. This doesn't seem to be the case
> >>>here.
> >
> >Right I do think that might be the case.
> >
> >>We still need the eld notify hooks so that i915 can inform the audio
> >>driver about the state of the display. Whether that's best done via
> >>the component stuff or something else I don't know.
> >
> >There is already work ongoing by ARM folks for the interface, should we
> >reuse that [1]. I would certainly argue reusing rather than redfeining a
> >new one would be better.
> >
> >Btw this interface seems to rely on display side implemting these ops.
> 
> My understanding is that it's an interface for external encoders
> that have an I2S or S/PDIF link. Such external encoders appear as
> ASoC codecs that can be bound to the SoC with DT bindings. I don't
> see what we could reuse here?

That is one of the intended usages. Right now three folks are developing
on that, TI which seems to be encoder case, then sti (don't know if that
off chip or not) and mediatek.

The point here is that we can use the same interface here too if we are
not going i915 way. Possibly we might want to modify or add to this and
not make it ASoC dependent as this driver won't be an ASoC one. But yes
I haven't looked closely enough to say that if this should be the way or
not. I wanted to pint our an alternate interface being developed which
can be possible reused in non i915 case

Thanks
-- 
~Vinod
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-15 13:30               ` Ville Syrjälä
@ 2016-03-16 16:43                 ` Ville Syrjälä
  2016-03-21  8:35                   ` Daniel Vetter
  0 siblings, 1 reply; 47+ messages in thread
From: Ville Syrjälä @ 2016-03-16 16:43 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Tue, Mar 15, 2016 at 03:30:55PM +0200, Ville Syrjälä wrote:
> On Tue, Mar 15, 2016 at 09:35:26AM +0100, Daniel Vetter wrote:
> > On Mon, Mar 14, 2016 at 04:20:19PM +0200, Ville Syrjälä wrote:
> > > On Mon, Mar 14, 2016 at 10:04:00AM +0100, Daniel Vetter wrote:
> > > > On Fri, Mar 11, 2016 at 09:09:12PM +0200, Ville Syrjälä wrote:
> > > > > On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > > > > > Thanks for the review Ville
> > > > > > 
> > > > > > [snip]
> > > > > > 
> > > > > > > Kinda hard to see where everything gets used due to the way the patches
> > > > > > > are split up.
> > > > > > 
> > > > > > Yes, it's far from great...
> > > > > > 
> > > > > > > At least the hotplug/mode change events are not needed. We only have the
> > > > > > > two points where i915 should inform the audio driver about this stuff,
> > > > > > > and those are the intel_audio_code_enable/disable(). For that we
> > > > > > > already have the .pin_eld_notify() hook.
> > > > > > >
> > > > > > > The interrupt stuff should mostly vanish from i915 with the subdevice
> > > > > > > approach. As in i915 would just call the interrupt handler of the audio
> > > > > > > driver based on the LPE bits in IIR, and the audio driver can then do
> > > > > > > whatever it wants based on its own status register.
> > > > > > 
> > > > > > Are you saying that the subdevice would provide a read/write interface 
> > > > > > for the audio driver to look at display registers, and the i915 driver 
> > > > > > would only provide a notification interface (EDID and interrupts) to the 
> > > > > > audio driver?
> > > > > 
> > > > > The audio driver would simply ioremap the appropriate range of
> > > > > registers itself.
> > > > > 
> > > > > > If yes, would there be two component framework links, one between 
> > > > > > i915/audio driver and one between subdevice/audio driver.
> > > > > 
> > > > > Yeah sort of. i915 registers the platform device for the audio, the
> > > > > audio driver can then bind to the device via the platform driver .probe
> > > > > callback. It can then register with the audio component stuff at some
> > > > > point to get the relevant notifications on the display state. When
> > > > > i915 gets unloaded we remove the platform device, at which point the
> > > > > audio driver's platform driver .remove() callback gets invoked and
> > > > > it should unregister/cleanup everything.
> > > > > 
> > > > > I just tried to frob around with the VED code a bit, and got it to load
> > > > > at least. It's not quite happy about reloading i915 while the ipvr
> > > > > driver was loaded though. Not sure what's going on there, but I do
> > > > > think this approach should work. So the VED patch could serve as a
> > > > > decent enough model to follow.
> > > > 
> > > > platform devices registerd by modules are apparently inherently racy and
> > > > in an unfixable way. At least I remember something like that from VED
> > > > discussion.
> > > > 
> > > > In short you _must_ unload VED manually before unloading i915, or it all
> > > > goes boom. If this is the only thing that went boom it's acceptable.
> > > 
> > > VED goes boom due drm_global_mutex deadlock at least if you load
> > > i915 while ipvr is already loaded. I didn't check to hard if there
> > > were any booms on pure unload so far.
> > 
> > Oh right another boom that happened, but can be avoided by dropping the
> > ->load callback and directly calling drm_dev_alloc/register. Shouldn't be
> > a problem with a non-drm driver though.
> > 
> > > Anyways, I was a bit worried about the races so I did a pair of 
> > > small test modules to try out this model, and to me it looked to
> > > work so far. I just unregistered the platform device from the parent
> > > pci driver .remove() hook, and it got blocked until the platform
> > > driver's .remove() hook was done.
> > > 
> > > In any case if this is broken, then I assume mfd must be broken. And
> > > that thing is at least used quite extensively.
> > 
> > Hm, I don't remember the exact details, but iirc the problem was that the
> > struct device is refcounted, but you can't add a module ref for the vtable
> > is has (specifically the final release method) since that would result in
> > a ref-loop. Usually it works, but if someone keeps the device alive
> > (through sysfs or whatever) and you manage to unload everything before
> > that last ref gets dropped it goes boom.
> > 
> > So "works", but not in a safe way.
> 
> I was worried that it's something like that. I guess I'll need to try
> grab a ref on something in my test module and see how it fares.

At least a sysfs attribute on the child device didn't cause any
explosions in my tests. I slept for a while in the sysfs store function,
and while doing that removed the module for the parent device. The
platform_device_unregister() in the parent .remove() blocked until the
sysfs store was done.

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface
  2016-03-16 16:43                 ` Ville Syrjälä
@ 2016-03-21  8:35                   ` Daniel Vetter
  0 siblings, 0 replies; 47+ messages in thread
From: Daniel Vetter @ 2016-03-21  8:35 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: mengdong.lin, tiwai, intel-gfx, liam.r.girdwood, vinod.koul,
	broonie, rakesh.a.ughreja, David Henningsson

On Wed, Mar 16, 2016 at 06:43:38PM +0200, Ville Syrjälä wrote:
> On Tue, Mar 15, 2016 at 03:30:55PM +0200, Ville Syrjälä wrote:
> > On Tue, Mar 15, 2016 at 09:35:26AM +0100, Daniel Vetter wrote:
> > > On Mon, Mar 14, 2016 at 04:20:19PM +0200, Ville Syrjälä wrote:
> > > > On Mon, Mar 14, 2016 at 10:04:00AM +0100, Daniel Vetter wrote:
> > > > > On Fri, Mar 11, 2016 at 09:09:12PM +0200, Ville Syrjälä wrote:
> > > > > > On Fri, Mar 11, 2016 at 11:27:13AM -0600, Pierre-Louis Bossart wrote:
> > > > > > > Thanks for the review Ville
> > > > > > > 
> > > > > > > [snip]
> > > > > > > 
> > > > > > > > Kinda hard to see where everything gets used due to the way the patches
> > > > > > > > are split up.
> > > > > > > 
> > > > > > > Yes, it's far from great...
> > > > > > > 
> > > > > > > > At least the hotplug/mode change events are not needed. We only have the
> > > > > > > > two points where i915 should inform the audio driver about this stuff,
> > > > > > > > and those are the intel_audio_code_enable/disable(). For that we
> > > > > > > > already have the .pin_eld_notify() hook.
> > > > > > > >
> > > > > > > > The interrupt stuff should mostly vanish from i915 with the subdevice
> > > > > > > > approach. As in i915 would just call the interrupt handler of the audio
> > > > > > > > driver based on the LPE bits in IIR, and the audio driver can then do
> > > > > > > > whatever it wants based on its own status register.
> > > > > > > 
> > > > > > > Are you saying that the subdevice would provide a read/write interface 
> > > > > > > for the audio driver to look at display registers, and the i915 driver 
> > > > > > > would only provide a notification interface (EDID and interrupts) to the 
> > > > > > > audio driver?
> > > > > > 
> > > > > > The audio driver would simply ioremap the appropriate range of
> > > > > > registers itself.
> > > > > > 
> > > > > > > If yes, would there be two component framework links, one between 
> > > > > > > i915/audio driver and one between subdevice/audio driver.
> > > > > > 
> > > > > > Yeah sort of. i915 registers the platform device for the audio, the
> > > > > > audio driver can then bind to the device via the platform driver .probe
> > > > > > callback. It can then register with the audio component stuff at some
> > > > > > point to get the relevant notifications on the display state. When
> > > > > > i915 gets unloaded we remove the platform device, at which point the
> > > > > > audio driver's platform driver .remove() callback gets invoked and
> > > > > > it should unregister/cleanup everything.
> > > > > > 
> > > > > > I just tried to frob around with the VED code a bit, and got it to load
> > > > > > at least. It's not quite happy about reloading i915 while the ipvr
> > > > > > driver was loaded though. Not sure what's going on there, but I do
> > > > > > think this approach should work. So the VED patch could serve as a
> > > > > > decent enough model to follow.
> > > > > 
> > > > > platform devices registerd by modules are apparently inherently racy and
> > > > > in an unfixable way. At least I remember something like that from VED
> > > > > discussion.
> > > > > 
> > > > > In short you _must_ unload VED manually before unloading i915, or it all
> > > > > goes boom. If this is the only thing that went boom it's acceptable.
> > > > 
> > > > VED goes boom due drm_global_mutex deadlock at least if you load
> > > > i915 while ipvr is already loaded. I didn't check to hard if there
> > > > were any booms on pure unload so far.
> > > 
> > > Oh right another boom that happened, but can be avoided by dropping the
> > > ->load callback and directly calling drm_dev_alloc/register. Shouldn't be
> > > a problem with a non-drm driver though.
> > > 
> > > > Anyways, I was a bit worried about the races so I did a pair of 
> > > > small test modules to try out this model, and to me it looked to
> > > > work so far. I just unregistered the platform device from the parent
> > > > pci driver .remove() hook, and it got blocked until the platform
> > > > driver's .remove() hook was done.
> > > > 
> > > > In any case if this is broken, then I assume mfd must be broken. And
> > > > that thing is at least used quite extensively.
> > > 
> > > Hm, I don't remember the exact details, but iirc the problem was that the
> > > struct device is refcounted, but you can't add a module ref for the vtable
> > > is has (specifically the final release method) since that would result in
> > > a ref-loop. Usually it works, but if someone keeps the device alive
> > > (through sysfs or whatever) and you manage to unload everything before
> > > that last ref gets dropped it goes boom.
> > > 
> > > So "works", but not in a safe way.
> > 
> > I was worried that it's something like that. I guess I'll need to try
> > grab a ref on something in my test module and see how it fares.
> 
> At least a sysfs attribute on the child device didn't cause any
> explosions in my tests. I slept for a while in the sysfs store function,
> and while doing that removed the module for the parent device. The
> platform_device_unregister() in the parent .remove() blocked until the
> sysfs store was done.

Hm, maybe it's been fixed by now, that discussion about platform devices
created by modules was a while ago.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2016-03-21  8:34 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-05  2:50 [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 01/15] drm: i915: fix inversion of definitions for LPE_PIPE_A/B Pierre-Louis Bossart
2016-03-05 13:27   ` Ville Syrjälä
2016-03-07 18:00     ` Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 02/15] drm: i915: remove intel_hdmi variable declaration Pierre-Louis Bossart
2016-03-10 17:34   ` Ville Syrjälä
2016-03-11 17:08     ` Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 03/15] Doc: sound: add description of Atom HDMI audio interface Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 04/15] drm/i915: Add headers for non-HDAudio HDMI interface Pierre-Louis Bossart
2016-03-10 17:54   ` Ville Syrjälä
2016-03-10 18:00   ` Ville Syrjälä
2016-03-11 17:27     ` Pierre-Louis Bossart
2016-03-11 19:09       ` Ville Syrjälä
2016-03-14  9:04         ` Daniel Vetter
2016-03-14 14:20           ` Ville Syrjälä
2016-03-15  8:35             ` Daniel Vetter
2016-03-15 13:30               ` Ville Syrjälä
2016-03-16 16:43                 ` Ville Syrjälä
2016-03-21  8:35                   ` Daniel Vetter
2016-03-15  8:36           ` Daniel Vetter
2016-03-14 15:13         ` Pierre-Louis Bossart
2016-03-14 15:21           ` Ville Syrjälä
2016-03-14 15:30             ` Ville Syrjälä
2016-03-14 17:27               ` Pierre-Louis Bossart
2016-03-15  8:39                 ` Daniel Vetter
2016-03-15 13:35                   ` Ville Syrjälä
2016-03-15 13:43                     ` Daniel Vetter
2016-03-15 16:21                     ` Vinod Koul
2016-03-15 21:14                       ` Pierre-Louis Bossart
2016-03-16  3:09                         ` Vinod Koul
2016-03-05  2:50 ` [RFC 05/15] drm/i915: changes " Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 06/15] drm/i915: power-related changes " Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 07/15] drm/i915: Add API code for " Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 08/15] drm/i915: enable non-HDAudio HDMI interface Makefile Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 09/15] ALSA: Intel: Atom: add Atom non-HDAudio HDMI interface Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 10/15] add dependency on PM_RUNTIME Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 11/15] hdmi_audio: Improve position reporting Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 12/15] hdmi_audio: Fixup some monitor Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 13/15] hdmi_audio: Fix mishandling of AUD_HDMI_STATUS_v2 register Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 14/15] i915: Enable LPE_PIPEA_Interrupt Pierre-Louis Bossart
2016-03-05  2:50 ` [RFC 15/15] i915: Fix typo in comment Pierre-Louis Bossart
2016-03-05 13:42 ` [RFC 00/15] HDMI Audio support on Atom w/o HDAUdio Ville Syrjälä
2016-03-07 17:54   ` Pierre-Louis Bossart
2016-03-07 18:02     ` Ville Syrjälä
2016-03-07 18:12       ` Pierre-Louis Bossart
2016-03-07 18:29         ` Ville Syrjälä
2016-03-07 12:04 ` ✗ Fi.CI.BAT: failure for " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.