daily pastebin goal
0%
SHARE
TWEET

Untitled

a guest Apr 19th, 2016 3,657 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. From 47d52268958e8a93b7e5ccfc22f83c82e13e1f6f Mon Sep 17 00:00:00 2001
  2. From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  3. Date: Wed, 2 Mar 2016 14:30:44 -0600
  4. Subject: [PATCH 01/12] drm: i915: remove intel_hdmi variable declaration
  5.  
  6. 'intel_hdmi' variable is redeclared, use same variable declared in
  7. function scope.
  8.  
  9. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  10. ---
  11.  drivers/gpu/drm/i915/intel_hdmi.c | 2 +-
  12.  1 file changed, 1 insertion(+), 1 deletion(-)
  13.  
  14. diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
  15. index 616108c..3b362ddb 100644
  16. --- a/drivers/gpu/drm/i915/intel_hdmi.c
  17. +++ b/drivers/gpu/drm/i915/intel_hdmi.c
  18. @@ -1413,7 +1413,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
  19.     intel_hdmi_unset_edid(connector);
  20.  
  21.     if (intel_hdmi_set_edid(connector, live_status)) {
  22. -       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
  23. +       intel_hdmi = intel_attached_hdmi(connector);
  24.  
  25.         hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
  26.         status = connector_status_connected;
  27.  
  28. From 146a6648f67ce715e90bbd122c509aa26247a8e4 Mon Sep 17 00:00:00 2001
  29. From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  30. Date: Tue, 1 Mar 2016 16:25:04 -0600
  31. Subject: [PATCH 02/12] drm/i915: Add headers for non-HDAudio HDMI interface
  32.  
  33. Add header files for interface available on Baytrail and CherryTrail
  34.  
  35. Initial code was downloaded from https://github.com/01org/baytrailaudio/
  36. ...and had the changes to .config stripped and the revert on sound/init.c
  37. done by David Henningson
  38.  
  39. Clean-up, port to 4.5 and intel-drm by Pierre Bossart
  40. CherryTrail support by Jerome Anand
  41.  
  42. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
  43. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  44. ---
  45.  drivers/gpu/drm/i915/hdmi_audio_if.h | 125 +++++++++++++++++++++++++++++++++++
  46.  drivers/gpu/drm/i915/i915_drv.h      |  31 +++++++++
  47.  drivers/gpu/drm/i915/i915_reg.h      |  22 ++++++
  48.  drivers/gpu/drm/i915/intel_drv.h     |  13 ++++
  49.  4 files changed, 191 insertions(+)
  50.  create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.h
  51.  
  52. diff --git a/drivers/gpu/drm/i915/hdmi_audio_if.h b/drivers/gpu/drm/i915/hdmi_audio_if.h
  53. new file mode 100644
  54. index 0000000..165bba5
  55. --- /dev/null
  56. +++ b/drivers/gpu/drm/i915/hdmi_audio_if.h
  57. @@ -0,0 +1,125 @@
  58. +/*
  59. + * Copyright (c) 2010, Intel Corporation.
  60. + *
  61. + * This program is free software; you can redistribute it and/or modify it
  62. + * under the terms and conditions of the GNU General Public License,
  63. + * version 2, as published by the Free Software Foundation.
  64. + *
  65. + * This program is distributed in the hope it will be useful, but WITHOUT
  66. + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  67. + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  68. + * more details.
  69. + *
  70. + * Authors:
  71. + * jim liu <jim.liu@intel.com>
  72. + * Uma Shankar <uma.shankar@intel.com>
  73. + */
  74. +
  75. +
  76. +#ifndef __HDMI_AUDIO_IF_H
  77. +#define __HDMI_AUDIO_IF_H
  78. +
  79. +#include <linux/types.h>
  80. +#include <drm/drmP.h>
  81. +
  82. +/* HDMI AUDIO INTERRUPT TYPE */
  83. +#define HDMI_AUDIO_UNDERRUN     (1UL<<0)
  84. +#define HDMI_AUDIO_BUFFER_DONE  (1UL<<1)
  85. +
  86. +/* the monitor type HDMI or DVI */
  87. +#define MONITOR_TYPE_HDMI 1
  88. +#define MONITOR_TYPE_DVI  2
  89. +
  90. +extern int i915_hdmi_state;
  91. +
  92. +enum had_caps_list {
  93. +   HAD_GET_ELD = 1,
  94. +   HAD_GET_SAMPLING_FREQ,
  95. +   HAD_GET_DISPLAY_RATE,
  96. +   HAD_GET_HDCP_STATUS,
  97. +   HAD_GET_AUDIO_STATUS,
  98. +   HAD_SET_ENABLE_AUDIO,
  99. +   HAD_SET_DISABLE_AUDIO,
  100. +   HAD_SET_ENABLE_AUDIO_INT,
  101. +   HAD_SET_DISABLE_AUDIO_INT,
  102. +   OTHERS_TBD,
  103. +};
  104. +
  105. +enum had_event_type {
  106. +   HAD_EVENT_HOT_PLUG = 1,
  107. +   HAD_EVENT_HOT_UNPLUG,
  108. +   HAD_EVENT_MODE_CHANGING,
  109. +   HAD_EVENT_PM_CHANGING,
  110. +   HAD_EVENT_AUDIO_BUFFER_DONE,
  111. +   HAD_EVENT_AUDIO_BUFFER_UNDERRUN,
  112. +   HAD_EVENT_QUERY_IS_AUDIO_BUSY,
  113. +   HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED,
  114. +};
  115. +
  116. +/*
  117. + * HDMI Display Controller Audio Interface
  118. + *
  119. + */
  120. +typedef int (*had_event_call_back) (enum had_event_type event_type,
  121. +       void *ctxt_info);
  122. +
  123. +struct hdmi_audio_registers_ops {
  124. +   int (*hdmi_audio_get_register_base)(uint32_t *reg_base);
  125. +   int (*hdmi_audio_read_register)(uint32_t reg_addr, uint32_t *data);
  126. +   int (*hdmi_audio_write_register)(uint32_t reg_addr, uint32_t data);
  127. +   int (*hdmi_audio_read_modify)(uint32_t reg_addr, uint32_t data,
  128. +           uint32_t mask);
  129. +};
  130. +
  131. +struct hdmi_audio_query_set_ops {
  132. +   int (*hdmi_audio_get_caps)(enum had_caps_list query_element,
  133. +           void *capabilties);
  134. +   int (*hdmi_audio_set_caps)(enum had_caps_list set_element,
  135. +           void *capabilties);
  136. +};
  137. +
  138. +typedef struct hdmi_audio_event {
  139. +   int type;
  140. +} hdmi_audio_event_t;
  141. +
  142. +struct snd_intel_had_interface {
  143. +   const char *name;
  144. +   int (*query)(void *had_data, hdmi_audio_event_t event);
  145. +   int (*suspend)(void *had_data, hdmi_audio_event_t event);
  146. +   int (*resume)(void *had_data);
  147. +};
  148. +
  149. +struct hdmi_audio_priv {
  150. +   struct drm_device *dev;
  151. +   u32 hdmi_reg;
  152. +   u32 hdmi_lpe_audio_reg;
  153. +   bool is_hdcp_supported;
  154. +   bool hdmi_hpd_connected;
  155. +   int monitor_type;
  156. +   void *context;
  157. +   int pipe;
  158. +};
  159. +
  160. +extern void i915_hdmi_audio_init(struct hdmi_audio_priv *p_hdmi_priv);
  161. +
  162. +extern bool mid_hdmi_audio_is_busy(struct drm_device *dev);
  163. +extern bool mid_hdmi_audio_suspend(struct drm_device *dev);
  164. +extern void mid_hdmi_audio_resume(struct drm_device *dev);
  165. +extern void mid_hdmi_audio_signal_event(struct drm_device *dev,
  166. +       enum had_event_type event);
  167. +
  168. +/* Added for HDMI Audio */
  169. +extern void hdmi_get_eld(uint8_t *eld);
  170. +extern struct hdmi_audio_priv *get_hdmi_priv(void);
  171. +extern void hdmi_get_eld(uint8_t *eld);
  172. +extern int i915_enable_hdmi_audio_int(struct drm_device *dev);
  173. +extern int i915_disable_hdmi_audio_int(struct drm_device *dev);
  174. +extern int mid_hdmi_audio_setup(
  175. +   had_event_call_back audio_callbacks,
  176. +   struct hdmi_audio_registers_ops *reg_ops,
  177. +   struct hdmi_audio_query_set_ops *query_ops);
  178. +extern int mid_hdmi_audio_register(
  179. +   struct snd_intel_had_interface *driver,
  180. +   void *had_data);
  181. +
  182. +#endif /* __HDMI_AUDIO_IF_H */
  183. diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
  184. index b0847b9..b700adc 100644
  185. --- a/drivers/gpu/drm/i915/i915_drv.h
  186. +++ b/drivers/gpu/drm/i915/i915_drv.h
  187. @@ -52,6 +52,7 @@
  188.  #include <linux/kref.h>
  189.  #include <linux/pm_qos.h>
  190.  #include "intel_guc.h"
  191. +#include "hdmi_audio_if.h"
  192.  
  193.  /* General customization:
  194.   */
  195. @@ -1153,6 +1154,18 @@ struct intel_gen6_power_mgmt {
  196.     struct mutex hw_lock;
  197.  };
  198.  
  199. +/* Runtime power management related */
  200. +struct intel_gen7_rpm {
  201. +   /* To track (num of get calls - num of put calls)
  202. +    * made by procfs
  203. +    */
  204. +   atomic_t procfs_count;
  205. +   /* To make sure ring get/put are in pair */
  206. +   bool ring_active;
  207. +   struct proc_dir_entry *i915_proc_dir;
  208. +   struct proc_dir_entry *i915_proc_file;
  209. +};
  210. +
  211.  /* defined intel_pm.c */
  212.  extern spinlock_t mchdev_lock;
  213.  
  214. @@ -1953,6 +1966,19 @@ struct drm_i915_private {
  215.  
  216.     struct intel_encoder *dig_port_map[I915_MAX_PORTS];
  217.  
  218. +   /* Added for HDMI Audio */
  219. +   had_event_call_back had_event_callbacks;
  220. +   struct snd_intel_had_interface *had_interface;
  221. +   void *had_pvt_data;
  222. +   int tmds_clock_speed;
  223. +   int hdmi_audio_interrupt_mask;
  224. +   struct work_struct hdmi_audio_wq;
  225. +
  226. +   u32 hotplug_status;
  227. +
  228. +   /* Runtime power management related */
  229. +   struct intel_gen7_rpm rpm;
  230. +
  231.     /*
  232.      * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
  233.      * will be rejected. Instead look for a better place.
  234. @@ -3509,6 +3535,11 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
  235.     } while (upper != old_upper && loop++ < 2);         \
  236.     (u64)upper << 32 | lower; })
  237.  
  238. +int i915_rpm_get_disp(struct drm_device *dev);
  239. +int i915_rpm_put_disp(struct drm_device *dev);
  240. +
  241. +bool i915_is_device_active(struct drm_device *dev);
  242. +
  243.  #define POSTING_READ(reg)  (void)I915_READ_NOTRACE(reg)
  244.  #define POSTING_READ16(reg)    (void)I915_READ16_NOTRACE(reg)
  245.  
  246. diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
  247. index 4897728..713a0173 100644
  248. --- a/drivers/gpu/drm/i915/i915_reg.h
  249. +++ b/drivers/gpu/drm/i915/i915_reg.h
  250. @@ -2053,7 +2053,25 @@ enum skl_disp_power_wells {
  251.  #define I915_WINVALID_INTERRUPT                (1<<1)
  252.  #define I915_USER_INTERRUPT                (1<<1)
  253.  #define I915_ASLE_INTERRUPT                (1<<0)
  254. +#define I915_LPE_AUDIO_HDMI_STATUS_A   _MMIO(dev_priv->info.display_mmio_offset + 0x65064)
  255. +#define I915_LPE_AUDIO_HDMI_STATUS_B   _MMIO(dev_priv->info.display_mmio_offset + 0x65864)
  256. +#define I915_LPE_AUDIO_HDMI_STATUS_C   _MMIO(dev_priv->info.display_mmio_offset + 0x65964)
  257. +#define I915_HDMI_AUDIO_UNDERRUN           (1UL<<31)
  258. +#define I915_HDMI_AUDIO_BUFFER_DONE            (1UL<<29)
  259.  #define I915_BSD_USER_INTERRUPT                (1<<25)
  260. +#define I915_HDMI_AUDIO_UNDERRUN_ENABLE            (1UL<<15)
  261. +
  262. +#define I915_HDMI_AUDIO_LPE_C_CONFIG           0x65900
  263. +#define I915_HDMI_AUDIO_LPE_B_CONFIG           0x65800
  264. +#define I915_HDMI_AUDIO_LPE_A_CONFIG           0x65000
  265. +
  266. +#define HDMI_LPE_AUDIO_PIPE_OFFSET         0x100
  267. +#define HDMI_LPE_AUDIO_PIPE_BC_OFFSET(pipe) \
  268. +   (I915_LPE_AUDIO_HDMI_STATUS_B + \
  269. +   (pipe - 1) * HDMI_LPE_AUDIO_PIPE_OFFSET)
  270. +#define I915_LPE_AUDIO_HDMI_STATUS(pipe) \
  271. +   (pipe ? (HDMI_LPE_AUDIO_PIPE_BC_OFFSET(pipe)) : \
  272. +   I915_LPE_AUDIO_HDMI_STATUS_A)
  273.  
  274.  #define GEN6_BSD_RNCID         _MMIO(0x12198)
  275.  
  276. @@ -3355,6 +3373,9 @@ enum skl_disp_power_wells {
  277.  #define _GEN3_SDVOC    0x61160
  278.  #define GEN3_SDVOB _MMIO(_GEN3_SDVOB)
  279.  #define GEN3_SDVOC _MMIO(_GEN3_SDVOC)
  280. +#define HDMIB  (dev_priv->info.display_mmio_offset + 0x61140)
  281. +#define HDMIC  (dev_priv->info.display_mmio_offset + 0x61160)
  282. +#define HDMID  (dev_priv->info.display_mmio_offset + 0x6116C)
  283.  #define GEN4_HDMIB GEN3_SDVOB
  284.  #define GEN4_HDMIC GEN3_SDVOC
  285.  #define VLV_HDMIB  _MMIO(VLV_DISPLAY_BASE + 0x61140)
  286. @@ -3364,6 +3385,7 @@ enum skl_disp_power_wells {
  287.  #define PCH_HDMIB  PCH_SDVOB
  288.  #define PCH_HDMIC  _MMIO(0xe1150)
  289.  #define PCH_HDMID  _MMIO(0xe1160)
  290. +#define PORT_ENABLE    (1 << 31)
  291.  
  292.  #define PORT_DFT_I9XX              _MMIO(0x61150)
  293.  #define   DC_BALANCE_RESET         (1 << 25)
  294. diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
  295. index df7f3cb..12cd13e 100644
  296. --- a/drivers/gpu/drm/i915/intel_drv.h
  297. +++ b/drivers/gpu/drm/i915/intel_drv.h
  298. @@ -695,6 +695,14 @@ struct cxsr_latency {
  299.  #define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base)
  300.  #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
  301.  
  302. +/* HDMI bits are shared with the DP bits */
  303. +#define   HDMIB_HOTPLUG_LIVE_STATUS             (1 << 29)
  304. +#define   HDMIC_HOTPLUG_LIVE_STATUS             (1 << 28)
  305. +#define   HDMID_HOTPLUG_LIVE_STATUS             (1 << 27)
  306. +#define   HDMI_LIVE_STATUS_BASE            30
  307. +#define   HDMI_LIVE_STATUS_DELAY_STEP      10
  308. +#define   HDMI_EDID_RETRY_COUNT            3
  309. +
  310.  struct intel_hdmi {
  311.     i915_reg_t hdmi_reg;
  312.     int ddc_bus;
  313. @@ -706,6 +714,9 @@ struct intel_hdmi {
  314.     bool rgb_quant_range_selectable;
  315.     enum hdmi_picture_aspect aspect_ratio;
  316.     struct intel_connector *attached_connector;
  317. +   struct edid *edid;
  318. +   uint32_t edid_mode_count;
  319. +
  320.     void (*write_infoframe)(struct drm_encoder *encoder,
  321.                 enum hdmi_infoframe_type type,
  322.                 const void *frame, ssize_t len);
  323. @@ -1138,6 +1149,8 @@ intel_rotation_90_or_270(unsigned int rotation)
  324.  
  325.  void intel_create_rotation_property(struct drm_device *dev,
  326.                     struct intel_plane *plane);
  327. +void chv_set_lpe_audio_reg_pipe(struct drm_device *dev,
  328. +               int encoder_type, enum port port);
  329.  
  330.  /* shared dpll functions */
  331.  struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
  332.  
  333. From 1cab896a5981554dc754f6279a675a67fc9adf16 Mon Sep 17 00:00:00 2001
  334. From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  335. Date: Tue, 1 Mar 2016 16:25:04 -0600
  336. Subject: [PATCH 03/12] drm/i915: changes for non-HDAudio HDMI interface
  337.  
  338. Changes to existing code for interface available on Baytrail and
  339. CherryTrail
  340.  
  341. This driver was downloaded from https://github.com/01org/baytrailaudio/
  342.  
  343. ...and had the changes to .config stripped and the revert on sound/init.c
  344.  
  345. Also squashed change from Toyo Abe to fix typos and underrun issues
  346. To enable interrupt, IER, IIR, and IMR must be configured appropriately.
  347. IER setting for hdmi_audio was missing.
  348. This fixes the following warning in dmesg.
  349. [  302.369965] had: Driver detected 2 missed buffer done interrupt(s)!!!!
  350.  
  351. Cleanup, correction for PIPE_A/PIPE_B inversions,
  352. port to 4.5 and intel-drm by Pierre Bossart
  353. CherryTrail support by Jerome Anand
  354.  
  355. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
  356. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  357. Signed-off-by: Toyo Abe <toyo.abe@gmail.com>
  358. ---
  359.  drivers/gpu/drm/i915/i915_irq.c      | 151 +++++++++++++++++++++++++
  360.  drivers/gpu/drm/i915/intel_display.c |  86 ++++++++++++++
  361.  drivers/gpu/drm/i915/intel_hdmi.c    | 211 ++++++++++++++++++++++++++++++++++-
  362.  3 files changed, 446 insertions(+), 2 deletions(-)
  363.  
  364. diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
  365. index fa8afa7..59f4eaa 100644
  366. --- a/drivers/gpu/drm/i915/i915_irq.c
  367. +++ b/drivers/gpu/drm/i915/i915_irq.c
  368. @@ -603,6 +603,42 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
  369.     __i915_disable_pipestat(dev_priv, pipe, enable_mask, status_mask);
  370.  }
  371.  
  372. +/* Added for HDMI AUDIO */
  373. +void
  374. +i915_enable_lpe_pipestat(struct drm_i915_private *dev_priv, int pipe)
  375. +{
  376. +   u32 mask;
  377. +
  378. +   mask = dev_priv->hdmi_audio_interrupt_mask;
  379. +   mask |= I915_HDMI_AUDIO_UNDERRUN | I915_HDMI_AUDIO_BUFFER_DONE;
  380. +   /* Enable the interrupt, clear any pending status */
  381. +   if (IS_CHERRYVIEW(dev_priv->dev)) {
  382. +       I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_C, mask);
  383. +       POSTING_READ(I915_LPE_AUDIO_HDMI_STATUS_C);
  384. +   } else {
  385. +       I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_A, mask);
  386. +       POSTING_READ(I915_LPE_AUDIO_HDMI_STATUS_A);
  387. +   }
  388. +}
  389. +
  390. +void
  391. +i915_disable_lpe_pipestat(struct drm_i915_private *dev_priv, int pipe)
  392. +{
  393. +   u32 mask;
  394. +
  395. +   mask = dev_priv->hdmi_audio_interrupt_mask;
  396. +   mask |= I915_HDMI_AUDIO_UNDERRUN | I915_HDMI_AUDIO_BUFFER_DONE;
  397. +   /* Disable the interrupt, clear any pending status */
  398. +   if (IS_CHERRYVIEW(dev_priv->dev)) {
  399. +       I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_C, mask);
  400. +       POSTING_READ(I915_LPE_AUDIO_HDMI_STATUS_C);
  401. +
  402. +   } else {
  403. +       I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_A, mask);
  404. +       POSTING_READ(I915_LPE_AUDIO_HDMI_STATUS_A);
  405. +   }
  406. +}
  407. +
  408.  /**
  409.   * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
  410.   * @dev: drm device
  411. @@ -1644,6 +1680,24 @@ static bool intel_pipe_handle_vblank(struct drm_device *dev, enum pipe pipe)
  412.     return true;
  413.  }
  414.  
  415. +static inline
  416. +void i915_notify_audio_buffer_status(struct drm_device *dev, const i915_reg_t reg)
  417. +{
  418. +   u32 lpe_stream = 0;
  419. +   struct drm_i915_private *dev_priv = dev->dev_private;
  420. +   lpe_stream = I915_READ(reg);
  421. +   if (lpe_stream & I915_HDMI_AUDIO_UNDERRUN) {
  422. +       I915_WRITE(reg, I915_HDMI_AUDIO_UNDERRUN);
  423. +       mid_hdmi_audio_signal_event(dev,
  424. +           HAD_EVENT_AUDIO_BUFFER_UNDERRUN);
  425. +   }
  426. +   if (lpe_stream & I915_HDMI_AUDIO_BUFFER_DONE) {
  427. +       I915_WRITE(reg, I915_HDMI_AUDIO_BUFFER_DONE);
  428. +       mid_hdmi_audio_signal_event(dev,
  429. +           HAD_EVENT_AUDIO_BUFFER_DONE);
  430. +   }
  431. +}
  432. +
  433.  static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
  434.  {
  435.     struct drm_i915_private *dev_priv = dev->dev_private;
  436. @@ -1713,6 +1767,23 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
  437.             intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
  438.     }
  439.  
  440. +   if (IS_CHERRYVIEW(dev)) {
  441. +       // FIXME: plb: why are pipes and status mapped this way?
  442. +       if (iir & I915_LPE_PIPE_C_INTERRUPT)
  443. +           i915_notify_audio_buffer_status(dev,
  444. +                       I915_LPE_AUDIO_HDMI_STATUS_C);
  445. +       if (iir & I915_LPE_PIPE_B_INTERRUPT)
  446. +           i915_notify_audio_buffer_status(dev,
  447. +                       I915_LPE_AUDIO_HDMI_STATUS_B);
  448. +       if (iir & I915_LPE_PIPE_A_INTERRUPT)
  449. +           i915_notify_audio_buffer_status(dev,
  450. +                       I915_LPE_AUDIO_HDMI_STATUS_A);
  451. +   } else {
  452. +       if (iir & I915_LPE_PIPE_B_INTERRUPT)
  453. +           i915_notify_audio_buffer_status(dev,
  454. +                       I915_LPE_AUDIO_HDMI_STATUS_A);
  455. +   }
  456. +
  457.     if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
  458.         gmbus_irq_handler(dev);
  459.  }
  460. @@ -2790,6 +2861,72 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
  461.     spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  462.  }
  463.  
  464. +/* Added for HDMI Audio */
  465. +int i915_enable_hdmi_audio_int(struct drm_device *dev)
  466. +{
  467. +   struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
  468. +   unsigned long irqflags;
  469. +   u32 imr, int_bit;
  470. +   int pipe = 1;
  471. +
  472. +   spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
  473. +   i915_enable_lpe_pipestat(dev_priv, pipe);
  474. +
  475. +   imr = I915_READ(VLV_IMR);
  476. +
  477. +   if (IS_CHERRYVIEW(dev_priv->dev)) {
  478. +       // FIXME: plb: looks wrong
  479. +
  480. +       //imr &= ~I915_LPE_PIPE_C_INTERRUPT;
  481. +       int_bit = (pipe ? (I915_LPE_PIPE_B_INTERRUPT >>
  482. +                   ((pipe - 1) * 9)) :
  483. +                   I915_LPE_PIPE_A_INTERRUPT);
  484. +       imr &= ~int_bit;
  485. +   } else {
  486. +       /* Audio is on Stream A but uses HDMI PIPE B */
  487. +       imr &= ~I915_LPE_PIPE_B_INTERRUPT;
  488. +   }
  489. +
  490. +   I915_WRITE(VLV_IMR, imr);
  491. +   I915_WRITE(VLV_IER, ~imr);
  492. +   POSTING_READ(VLV_IER);
  493. +   spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  494. +
  495. +   return 0;
  496. +}
  497. +
  498. +/* Added for HDMI Audio */
  499. +int i915_disable_hdmi_audio_int(struct drm_device *dev)
  500. +{
  501. +   struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
  502. +   unsigned long irqflags;
  503. +   u32 imr, int_bit;
  504. +   int pipe = 1;
  505. +
  506. +   spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
  507. +   imr = I915_READ(VLV_IMR);
  508. +
  509. +   if (IS_CHERRYVIEW(dev_priv->dev)) {
  510. +       // FIXME: plb: looks wrong, should have other interrupts as well?
  511. +       //imr |= I915_LPE_PIPE_C_INTERRUPT;
  512. +       int_bit = (pipe ? (I915_LPE_PIPE_B_INTERRUPT >>
  513. +                   ((pipe - 1) * 9)) :
  514. +                   I915_LPE_PIPE_A_INTERRUPT);
  515. +       imr |= int_bit;
  516. +   }
  517. +   else
  518. +       imr |= I915_LPE_PIPE_B_INTERRUPT;
  519. +
  520. +   I915_WRITE(VLV_IER, ~imr);
  521. +   I915_WRITE(VLV_IMR, imr);
  522. +   POSTING_READ(VLV_IMR);
  523. +
  524. +   i915_disable_lpe_pipestat(dev_priv, pipe);
  525. +   spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  526. +
  527. +   return 0;
  528. +}
  529. +
  530.  static bool
  531.  ring_idle(struct intel_engine_cs *ring, u32 seqno)
  532.  {
  533. @@ -3539,6 +3676,7 @@ static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv)
  534.     u32 pipestat_mask;
  535.     u32 iir_mask;
  536.     enum pipe pipe;
  537. +   u32 lpe_status_clear;
  538.  
  539.     pipestat_mask = PIPESTAT_INT_STATUS_MASK |
  540.             PIPE_FIFO_UNDERRUN_STATUS;
  541. @@ -3559,12 +3697,25 @@ static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv)
  542.            I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
  543.     if (IS_CHERRYVIEW(dev_priv))
  544.         iir_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
  545. +
  546. +   if (IS_CHERRYVIEW(dev_priv->dev))
  547. +       // FIXME: plb: looks wrong: what about other interrupts
  548. +       iir_mask |= I915_LPE_PIPE_C_INTERRUPT;
  549. +
  550.     dev_priv->irq_mask &= ~iir_mask;
  551.  
  552.     I915_WRITE(VLV_IIR, iir_mask);
  553.     I915_WRITE(VLV_IIR, iir_mask);
  554.     I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
  555.     I915_WRITE(VLV_IMR, dev_priv->irq_mask);
  556. +
  557. +   lpe_status_clear = I915_HDMI_AUDIO_UNDERRUN |
  558. +           I915_HDMI_AUDIO_BUFFER_DONE;
  559. +   I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_A, lpe_status_clear);
  560. +   I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_B, lpe_status_clear);
  561. +   if (IS_CHERRYVIEW(dev_priv->dev))
  562. +       I915_WRITE(I915_LPE_AUDIO_HDMI_STATUS_C, lpe_status_clear);
  563. +
  564.     POSTING_READ(VLV_IMR);
  565.  }
  566.  
  567. diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
  568. index 46947ff..ca212bb 100644
  569. --- a/drivers/gpu/drm/i915/intel_display.c
  570. +++ b/drivers/gpu/drm/i915/intel_display.c
  571. @@ -8010,6 +8010,16 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
  572.                   num_connectors);
  573.     }
  574.  
  575. +   /* Added for HDMI Audio */
  576. +   if ((IS_CHERRYVIEW(dev)) || (IS_VALLEYVIEW(dev))) {
  577. +       if(intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) {
  578. +           dev_priv->tmds_clock_speed = crtc_state->port_clock;
  579. +
  580. +           mid_hdmi_audio_signal_event(dev_priv->dev,
  581. +               HAD_EVENT_MODE_CHANGING);
  582. +       }
  583. +   }
  584. +
  585.     return 0;
  586.  }
  587.  
  588. @@ -14606,6 +14616,82 @@ static void intel_setup_outputs(struct drm_device *dev)
  589.     drm_helper_move_panel_connectors_to_head(dev);
  590.  }
  591.  
  592. +void chv_set_lpe_audio_reg_pipe(struct drm_device *dev,
  593. +               int encoder_type, enum port port)
  594. +{
  595. +   struct drm_i915_private *dev_priv = dev->dev_private;
  596. +   struct intel_encoder *intel_encoder;
  597. +   struct hdmi_audio_priv *hdmi_priv = get_hdmi_priv();
  598. +
  599. +   if(!hdmi_priv) {
  600. +       DRM_DEBUG_KMS("hdmi_priv was never allocated\n");
  601. +       return;
  602. +   }
  603. +
  604. +   /*
  605. +    * Due to hardware limitaion, Port D will always
  606. +    * be driven by Pipe C. So Port B and Port C will
  607. +    * be driven by either Pipe A or PipeB, depending
  608. +    * on whether the LFP is MIPI or EDP.
  609. +    */
  610. +
  611. +   if (port == PORT_D) {
  612. +       hdmi_priv->hdmi_lpe_audio_reg =
  613. +           I915_HDMI_AUDIO_LPE_C_CONFIG;
  614. +       hdmi_priv->pipe = PIPE_C;
  615. +       if (encoder_type == INTEL_OUTPUT_HDMI)
  616. +           hdmi_priv->hdmi_reg = HDMID;
  617. +       //else
  618. +       //  hdmi_priv->hdmi_reg = CHV_DP_D;
  619. +   } else {
  620. +       list_for_each_entry(intel_encoder, &dev->
  621. +           mode_config.encoder_list, base.head) {
  622. +
  623. +           /*
  624. +            * MIPI always comes on Pipe A or Pipe B
  625. +            * depending on Port A or Port C and EDP
  626. +            * comes on Pipe B. So the other pipe
  627. +            * will only be able to drive the DP.
  628. +            * MIPI on Port A is driven by Pipe A
  629. +            * and MIPI on Port C is driven by
  630. +            * Pipe B. So the other pipe will
  631. +            * drive DP.
  632. +            */
  633. +
  634. +           if (intel_encoder->type == INTEL_OUTPUT_EDP) {
  635. +               hdmi_priv->hdmi_lpe_audio_reg =
  636. +                   I915_HDMI_AUDIO_LPE_A_CONFIG;
  637. +               hdmi_priv->pipe = PIPE_A;
  638. +               break;
  639. +           } else if (intel_encoder->type == INTEL_OUTPUT_DSI &&
  640. +               dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) {
  641. +               hdmi_priv->hdmi_lpe_audio_reg =
  642. +                   I915_HDMI_AUDIO_LPE_B_CONFIG;
  643. +               hdmi_priv->pipe = PIPE_B;
  644. +               break;
  645. +           } else if (intel_encoder->type == INTEL_OUTPUT_DSI &&
  646. +               dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) {
  647. +               hdmi_priv->hdmi_lpe_audio_reg =
  648. +                   I915_HDMI_AUDIO_LPE_A_CONFIG;
  649. +               hdmi_priv->pipe = PIPE_A;
  650. +               break;
  651. +           }
  652. +       }
  653. +
  654. +       if (port == PORT_B) {
  655. +           if (encoder_type == INTEL_OUTPUT_HDMI)
  656. +               hdmi_priv->hdmi_reg = HDMIB;
  657. +           //else
  658. +           //  hdmi_priv->hdmi_reg = VLV_DP_B;
  659. +       } else {
  660. +           if (encoder_type == INTEL_OUTPUT_HDMI)
  661. +               hdmi_priv->hdmi_reg = HDMIC;
  662. +           //else
  663. +           //  hdmi_priv->hdmi_reg = VLV_DP_C;
  664. +       }
  665. +   }
  666. +}
  667. +
  668.  static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
  669.  {
  670.     struct drm_device *dev = fb->dev;
  671. diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
  672. index 3b362ddb..dd289b7 100644
  673. --- a/drivers/gpu/drm/i915/intel_hdmi.c
  674. +++ b/drivers/gpu/drm/i915/intel_hdmi.c
  675. @@ -38,6 +38,8 @@
  676.  #include <drm/i915_drm.h>
  677.  #include "i915_drv.h"
  678.  
  679. +static int i915_notify_had;
  680. +
  681.  static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
  682.  {
  683.     return hdmi_to_dig_port(intel_hdmi)->base.base.dev;
  684. @@ -1386,6 +1388,124 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force)
  685.     return connected;
  686.  }
  687.  
  688. +static bool vlv_hdmi_live_status(struct drm_device *dev,
  689. +           struct intel_hdmi *intel_hdmi)
  690. +{
  691. +   uint32_t bit;
  692. +   struct drm_i915_private *dev_priv = dev->dev_private;
  693. +   struct intel_digital_port *intel_dig_port =
  694. +                   hdmi_to_dig_port(intel_hdmi);
  695. +
  696. +   DRM_DEBUG_KMS("Reading Live status");
  697. +   switch (intel_dig_port->port) {
  698. +   case PORT_B:
  699. +       bit = HDMIB_HOTPLUG_LIVE_STATUS;
  700. +       break;
  701. +   case PORT_C:
  702. +       bit = HDMIC_HOTPLUG_LIVE_STATUS;
  703. +       break;
  704. +   case PORT_D:
  705. +       bit = HDMID_HOTPLUG_LIVE_STATUS;
  706. +       break;
  707. +   default:
  708. +       bit = 0;
  709. +   }
  710. +
  711. +   /* Return results in trems of connector */
  712. +   return I915_READ(PORT_HOTPLUG_STAT) & bit;
  713. +}
  714. +
  715. +
  716. +/*
  717. + * intel_hdmi_live_status: detect live status of HDMI
  718. + * if device is gen 6 and above, read the live status reg
  719. + * else, do not block the detection, return true
  720. + */
  721. +static bool intel_hdmi_live_status(struct drm_connector *connector)
  722. +{
  723. +   struct drm_device *dev = connector->dev;
  724. +   struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
  725. +
  726. +   if (INTEL_INFO(dev)->gen > 6) {
  727. +       /* Todo: Implement for other Gen 6+ archs*/
  728. +       if (IS_VALLEYVIEW(dev))
  729. +           return vlv_hdmi_live_status(dev, intel_hdmi);
  730. +   }
  731. +
  732. +   return true;
  733. +}
  734. +
  735. +/* Read DDC and get EDID */
  736. +struct edid *intel_hdmi_get_edid(struct drm_connector *connector, bool force)
  737. +{
  738. +   bool current_state = false;
  739. +   bool saved_state = false;
  740. +
  741. +   struct edid *new_edid = NULL;
  742. +   struct i2c_adapter *adapter = NULL;
  743. +   struct drm_device *dev = connector->dev;
  744. +   struct drm_i915_private *dev_priv = dev->dev_private;
  745. +   struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
  746. +   u32 hotplug_status = dev_priv->hotplug_status;
  747. +   enum port hdmi_port = hdmi_to_dig_port(intel_hdmi)->port;
  748. +   unsigned char retry = HDMI_EDID_RETRY_COUNT;
  749. +
  750. +   if (!intel_hdmi) {
  751. +       DRM_ERROR("Invalid input to get hdmi\n");
  752. +       return NULL;
  753. +   }
  754. +
  755. +   /* Get the saved status from top half */
  756. +   saved_state = hotplug_status & (1 << (HDMI_LIVE_STATUS_BASE - hdmi_port));
  757. +
  758. +   /*
  759. +    * Few monitors are slow to respond on EDID and live status,
  760. +    * so read live status multiple times within a max delay of 30ms
  761. +    */
  762. +   do {
  763. +       mdelay(HDMI_LIVE_STATUS_DELAY_STEP);
  764. +       current_state = intel_hdmi_live_status(connector);
  765. +       if (current_state)
  766. +           break;
  767. +   } while (retry--);
  768. +
  769. +   /* Compare current status, and saved status in top half */
  770. +   if (current_state != saved_state)
  771. +       DRM_DEBUG_DRIVER("Warning: Saved HDMI status != current status");
  772. +
  773. +   /* Read EDID if live status or saved status is up, or we are forced */
  774. +   if (current_state || saved_state || force) {
  775. +
  776. +       adapter = intel_gmbus_get_adapter(dev_priv,
  777. +                   intel_hdmi->ddc_bus);
  778. +       if (!adapter) {
  779. +           DRM_ERROR("Get_hdmi cant get adapter\n");
  780. +           return NULL;
  781. +       }
  782. +
  783. +       /*
  784. +        * Few monitors issue EDID after some delay, so give them
  785. +        * some chances, but within 30ms
  786. +        */
  787. +       retry = 3;
  788. +READ_EDID:
  789. +       new_edid = drm_get_edid(connector, adapter);
  790. +       if (!new_edid) {
  791. +           if (retry--) {
  792. +               mdelay(HDMI_LIVE_STATUS_DELAY_STEP);
  793. +               goto READ_EDID;
  794. +           }
  795. +
  796. +           DRM_ERROR("Get_hdmi cant read edid\n");
  797. +           return NULL;
  798. +       }
  799. +
  800. +       DRM_DEBUG_KMS("Live status up, got EDID");
  801. +   }
  802. +
  803. +   return new_edid;
  804. +}
  805. +
  806.  static enum drm_connector_status
  807.  intel_hdmi_detect(struct drm_connector *connector, bool force)
  808.  {
  809. @@ -1394,6 +1514,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
  810.     struct drm_i915_private *dev_priv = to_i915(connector->dev);
  811.     bool live_status = false;
  812.     unsigned int try;
  813. +   bool inform_audio = false;
  814. +   struct drm_device *dev = connector->dev;
  815.  
  816.     DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
  817.               connector->base.id, connector->name);
  818. @@ -1422,6 +1544,31 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
  819.  
  820.     intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
  821.  
  822. +   /* Need to inform audio about the event */
  823. +   intel_hdmi = intel_attached_hdmi(connector);
  824. +   if (intel_hdmi->has_audio)
  825. +       inform_audio = true;
  826. +
  827. +   if (status == connector_status_connected) {
  828. +       if (intel_hdmi->has_audio)
  829. +           i915_notify_had = 1;
  830. +   } else {
  831. +       struct intel_digital_port *intel_dig_port =
  832. +               hdmi_to_dig_port(intel_hdmi);
  833. +
  834. +       chv_set_lpe_audio_reg_pipe(dev, INTEL_OUTPUT_HDMI,
  835. +                   intel_dig_port->port);
  836. +       /* Send a disconnect event to audio */
  837. +       if (inform_audio) {
  838. +           DRM_DEBUG_DRIVER("Sending event to audio");
  839. +           mid_hdmi_audio_signal_event(dev_priv->dev,
  840. +           HAD_EVENT_HOT_UNPLUG);
  841. +       }
  842. +   }
  843. +
  844. +   if (IS_VALLEYVIEW(dev))
  845. +       i915_hdmi_state = status;
  846. +
  847.     return status;
  848.  }
  849.  
  850. @@ -1445,12 +1592,29 @@ intel_hdmi_force(struct drm_connector *connector)
  851.  static int intel_hdmi_get_modes(struct drm_connector *connector)
  852.  {
  853.     struct edid *edid;
  854. +   struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
  855. +   struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
  856. +   struct intel_digital_port *intel_dig_port =
  857. +               hdmi_to_dig_port(intel_hdmi);
  858. +   struct drm_device *dev = connector->dev;
  859. +   int ret;
  860. +   struct drm_i915_private *dev_priv = connector->dev->dev_private;
  861.  
  862.     edid = to_intel_connector(connector)->detect_edid;
  863.     if (edid == NULL)
  864.         return 0;
  865.  
  866. -   return intel_connector_update_modes(connector, edid);
  867. +   ret = intel_connector_update_modes(connector, edid);
  868. +
  869. +   if (i915_notify_had) {
  870. +       chv_set_lpe_audio_reg_pipe(dev, INTEL_OUTPUT_HDMI,
  871. +                   intel_dig_port->port);
  872. +       mid_hdmi_audio_signal_event(dev_priv->dev,
  873. +           HAD_EVENT_HOT_PLUG);
  874. +       i915_notify_had = 0;
  875. +   }
  876. +
  877. +   return ret;
  878.  }
  879.  
  880.  static bool
  881. @@ -2149,6 +2313,20 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
  882.         u32 temp = I915_READ(PEG_BAND_GAP_DATA);
  883.         I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
  884.     }
  885. +
  886. +   i915_notify_had = 1;
  887. +}
  888. +
  889. +/* Added for HDMI Audio */
  890. +void i915_had_wq(struct work_struct *work)
  891. +{
  892. +   struct drm_i915_private *dev_priv = container_of(work,
  893. +       struct drm_i915_private, hdmi_audio_wq);
  894. +
  895. +   if (i915_hdmi_state == connector_status_connected) {
  896. +       mid_hdmi_audio_signal_event(dev_priv->dev,
  897. +           HAD_EVENT_HOT_PLUG);
  898. +   }
  899.  }
  900.  
  901.  void intel_hdmi_init(struct drm_device *dev,
  902. @@ -2157,7 +2335,10 @@ void intel_hdmi_init(struct drm_device *dev,
  903.     struct intel_digital_port *intel_dig_port;
  904.     struct intel_encoder *intel_encoder;
  905.     struct intel_connector *intel_connector;
  906. -
  907. +   /* Added for HDMI Audio */
  908. +   struct hdmi_audio_priv *hdmi_priv;
  909. +   struct drm_i915_private *dev_priv = dev->dev_private;
  910. +  
  911.     intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
  912.     if (!intel_dig_port)
  913.         return;
  914. @@ -2168,6 +2349,7 @@ void intel_hdmi_init(struct drm_device *dev,
  915.         return;
  916.     }
  917.  
  918. +
  919.     intel_encoder = &intel_dig_port->base;
  920.  
  921.     drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
  922. @@ -2226,4 +2408,29 @@ void intel_hdmi_init(struct drm_device *dev,
  923.     intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
  924.  
  925.     intel_hdmi_init_connector(intel_dig_port, intel_connector);
  926. +
  927. +   /* Added for HDMI Audio */
  928. +   /* HDMI private data */
  929. +   INIT_WORK(&dev_priv->hdmi_audio_wq, i915_had_wq);
  930. +   hdmi_priv = kzalloc(sizeof(struct hdmi_audio_priv), GFP_KERNEL);
  931. +   if (!hdmi_priv) {
  932. +       pr_err("failed to allocate memory");
  933. +   } else {
  934. +       hdmi_priv->dev = dev;
  935. +       if (IS_CHERRYVIEW(dev)) {
  936. +           // FIXME: plb: looks wrong
  937. +           // mapping between stream and Hdmi port ?
  938. +           hdmi_priv->hdmi_reg = HDMIC;
  939. +           hdmi_priv->hdmi_lpe_audio_reg =
  940. +                   I915_HDMI_AUDIO_LPE_C_CONFIG;
  941. +       } else {
  942. +           hdmi_priv->hdmi_reg = HDMIB;
  943. +           hdmi_priv->hdmi_lpe_audio_reg =
  944. +                   I915_HDMI_AUDIO_LPE_A_CONFIG;
  945. +       }
  946. +       hdmi_priv->monitor_type = MONITOR_TYPE_HDMI;
  947. +       hdmi_priv->is_hdcp_supported = true;
  948. +       i915_hdmi_audio_init(hdmi_priv);
  949. +   }
  950. +
  951.  }
  952.  
  953. From b009763ab63002ca2b6d2e5ca8764d2e93a1fcee Mon Sep 17 00:00:00 2001
  954. From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  955. Date: Tue, 1 Mar 2016 16:25:04 -0600
  956. Subject: [PATCH 04/12] drm/i915: power-related changes non-HDAudio HDMI
  957.  interface
  958.  
  959. PM and RPM changes for interface available on Baytrail and CherryTrail
  960.  
  961. This driver was downloaded from https://github.com/01org/baytrailaudio/
  962.  
  963. ...and had the changes to .config stripped and the revert on sound/init.c
  964.  
  965. Clean-up, port to 4.4 and intel-drm by Pierre Bossart
  966.  
  967. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
  968. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  969. ---
  970.  drivers/gpu/drm/i915/i915_rpm.c | 476 ++++++++++++++++++++++++++++++++++++++++
  971.  drivers/gpu/drm/i915/intel_pm.c |  53 +++++
  972.  2 files changed, 529 insertions(+)
  973.  create mode 100644 drivers/gpu/drm/i915/i915_rpm.c
  974.  
  975. diff --git a/drivers/gpu/drm/i915/i915_rpm.c b/drivers/gpu/drm/i915/i915_rpm.c
  976. new file mode 100644
  977. index 0000000..511311c
  978. --- /dev/null
  979. +++ b/drivers/gpu/drm/i915/i915_rpm.c
  980. @@ -0,0 +1,476 @@
  981. +/*
  982. + * Copyright 2013 Intel Corporation
  983. + *
  984. + * Permission is hereby granted, free of charge, to any person obtaining a
  985. + * copy of this software and associated documentation files (the "Software"),
  986. + * to deal in the Software without restriction, including without limitation
  987. + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  988. + * and/or sell copies of the Software, and to permit persons to whom the
  989. + * Software is furnished to do so, subject to the following conditions:
  990. + *
  991. + * The above copyright notice and this permission notice (including the next
  992. + * paragraph) shall be included in all copies or substantial portions of the
  993. + * Software.
  994. + *
  995. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  996. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  997. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  998. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  999. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  1000. + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  1001. + * DEALINGS IN THE SOFTWARE.
  1002. + *
  1003. + * Author:
  1004. + * Naresh Kumar Kachhi <naresh.kumar.kachhi@intel.com>
  1005. + */
  1006. +
  1007. +#include "i915_drv.h"
  1008. +#include "i915_reg.h"
  1009. +#include "intel_drv.h"
  1010. +#include <linux/console.h>
  1011. +#ifdef CONFIG_PM_RUNTIME
  1012. +#include <linux/pm_runtime.h>
  1013. +#endif
  1014. +#include <linux/proc_fs.h>  /* Needed for procfs access */
  1015. +#include <linux/fs.h>      /* For the basic file system */
  1016. +#include <linux/kernel.h>
  1017. +
  1018. +#define RPM_AUTOSUSPEND_DELAY 500
  1019. +
  1020. +#ifdef CONFIG_PM_RUNTIME
  1021. +
  1022. +/**
  1023. + * - Where should we use get/put?
  1024. + *   Get/put should be used very carefully as we might end up in weird states
  1025. + *   if not used properly (see the Note below). We want to cover all the
  1026. + *   acesses that might result in accessing rings/display/registers/gtt etc
  1027. + *   Mostly covering ioctls and drm callbacks should be enough. You can
  1028. + *   avoid those which does not access any HW.
  1029. + *
  1030. + * - When should we avoid get/put?
  1031. + *   WQ and interrupts should be taken care in suspend path. We should
  1032. + *   disable all the interrupts and cancel any pending WQs. Never try to
  1033. + *   cover interrupt/WQ with get/put unless you are sure about it.
  1034. + *
  1035. + * Note:Following scenarios should be strictly avoided while using get_sync
  1036. + * 1. Calling get_sync with struct_mutex or mode_config.mutex locked
  1037. + *    - we acquire these locks in runtime_resume, so any call to get_sync
  1038. + *    with these mutex locked might end up in a dead lock.
  1039. + *    check_mutex_current function can be used to debug this scenario.
  1040. + *    - Or let's say thread1 has done get_sync and is currently executing
  1041. + *    runtime_resume function. Before thread1 is able to acquire these
  1042. + *    mutex, thread2 acquires the mutex and does a get_sync. Now thread1
  1043. + *    is waiting for mutex and thread2 is waiting for dev->power.lock
  1044. + *    resulting in a deadlock. Use check_mutex to debug this.
  1045. + * 2. Calling get_sync from runtime_resume path
  1046. + *    runtime_resume is called with dev->power.lock held. doing get_sync
  1047. + *    in same path will end up in deadlock
  1048. + */
  1049. +
  1050. +#define RPM_PROC_ENTRY_FILENAME        "i915_rpm_op"
  1051. +#define RPM_PROC_ENTRY_DIRECTORY   "driver/i915rpm"
  1052. +
  1053. +int i915_rpm_get_procfs(struct inode *inode, struct file *file);
  1054. +int i915_rpm_put_procfs(struct inode *inode, struct file *file);
  1055. +/* proc file operations supported */
  1056. +static const struct file_operations rpm_file_ops = {
  1057. +   .owner      = THIS_MODULE,
  1058. +   .open       = i915_rpm_get_procfs,
  1059. +   .release    = i915_rpm_put_procfs,
  1060. +};
  1061. +
  1062. +bool i915_pm_runtime_enabled(struct device *dev)
  1063. +{
  1064. +   return pm_runtime_enabled(dev);
  1065. +}
  1066. +
  1067. +void i915_rpm_enable(struct device *dev)
  1068. +{
  1069. +   int cur_status = pm_runtime_enabled(dev);
  1070. +
  1071. +   if (!cur_status) {
  1072. +       pm_runtime_enable(dev);
  1073. +       pm_runtime_allow(dev);
  1074. +   }
  1075. +}
  1076. +
  1077. +void i915_rpm_disable(struct drm_device *drm_dev)
  1078. +{
  1079. +   struct device *dev = drm_dev->dev;
  1080. +   int cur_status = pm_runtime_enabled(dev);
  1081. +
  1082. +   if (cur_status) {
  1083. +       pm_runtime_forbid(dev);
  1084. +       pm_runtime_disable(dev);
  1085. +   }
  1086. +}
  1087. +
  1088. +static int i915_rpm_procfs_init(struct drm_device *drm_dev)
  1089. +{
  1090. +   struct drm_i915_private *dev_priv = drm_dev->dev_private;
  1091. +
  1092. +   dev_priv->rpm.i915_proc_dir = NULL;
  1093. +   dev_priv->rpm.i915_proc_file = NULL;
  1094. +
  1095. +   /**
  1096. +    * Create directory for rpm file(s)
  1097. +    */
  1098. +   dev_priv->rpm.i915_proc_dir = proc_mkdir(RPM_PROC_ENTRY_DIRECTORY,
  1099. +                        NULL);
  1100. +   if (dev_priv->rpm.i915_proc_dir == NULL) {
  1101. +       DRM_ERROR("Could not initialize %s\n",
  1102. +               RPM_PROC_ENTRY_DIRECTORY);
  1103. +       return -ENOMEM;
  1104. +   }
  1105. +   /**
  1106. +    * Create the /proc file
  1107. +    */
  1108. +   dev_priv->rpm.i915_proc_file = proc_create_data(
  1109. +                       RPM_PROC_ENTRY_FILENAME,
  1110. +                       S_IRUGO | S_IWUSR,
  1111. +                       dev_priv->rpm.i915_proc_dir,
  1112. +                       &rpm_file_ops,
  1113. +                       drm_dev);
  1114. +   /* check if file is created successfuly */
  1115. +   if (dev_priv->rpm.i915_proc_file == NULL) {
  1116. +       DRM_ERROR("Could not initialize %s/%s\n",
  1117. +           RPM_PROC_ENTRY_DIRECTORY, RPM_PROC_ENTRY_FILENAME);
  1118. +       return -ENOMEM;
  1119. +   }
  1120. +   return 0;
  1121. +}
  1122. +
  1123. +static int i915_rpm_procfs_deinit(struct drm_device *drm_dev)
  1124. +{
  1125. +   struct drm_i915_private *dev_priv = drm_dev->dev_private;
  1126. +   /* Clean up proc file */
  1127. +   if (dev_priv->rpm.i915_proc_file) {
  1128. +       remove_proc_entry(RPM_PROC_ENTRY_FILENAME,
  1129. +                dev_priv->rpm.i915_proc_dir);
  1130. +       dev_priv->rpm.i915_proc_file = NULL;
  1131. +   }
  1132. +   if (dev_priv->rpm.i915_proc_dir) {
  1133. +       remove_proc_entry(RPM_PROC_ENTRY_DIRECTORY, NULL);
  1134. +       dev_priv->rpm.i915_proc_dir = NULL;
  1135. +   }
  1136. +   return 0;
  1137. +}
  1138. +
  1139. +/* RPM init */
  1140. +int i915_rpm_init(struct drm_device *drm_dev)
  1141. +{
  1142. +   int ret = 0;
  1143. +   struct device *dev = drm_dev->dev;
  1144. +   struct drm_i915_private *dev_priv = drm_dev->dev_private;
  1145. +
  1146. +   ret = i915_rpm_procfs_init(drm_dev);
  1147. +   if (ret)
  1148. +       DRM_ERROR("unable to initialize procfs entry");
  1149. +   ret = pm_runtime_set_active(dev);
  1150. +   dev_priv->rpm.ring_active = false;
  1151. +   atomic_set(&dev_priv->rpm.procfs_count, 0);
  1152. +   pm_runtime_allow(dev);
  1153. +   /* enable Auto Suspend */
  1154. +   pm_runtime_set_autosuspend_delay(dev, RPM_AUTOSUSPEND_DELAY);
  1155. +   pm_runtime_use_autosuspend(dev);
  1156. +   if (dev->power.runtime_error)
  1157. +       DRM_ERROR("rpm init: error = %d\n", dev->power.runtime_error);
  1158. +
  1159. +   return ret;
  1160. +}
  1161. +
  1162. +int i915_rpm_deinit(struct drm_device *drm_dev)
  1163. +{
  1164. +   struct device *dev = drm_dev->dev;
  1165. +
  1166. +   pm_runtime_forbid(dev);
  1167. +   pm_runtime_set_suspended(dev);
  1168. +   pm_runtime_get_noresume(dev);
  1169. +   if (dev->power.runtime_error)
  1170. +       DRM_ERROR("rpm init: error = %d\n", dev->power.runtime_error);
  1171. +
  1172. +   i915_rpm_procfs_deinit(drm_dev);
  1173. +   return 0;
  1174. +}
  1175. +
  1176. +/**
  1177. + * We have different flavour of get/put based on access type (ring/disp/
  1178. + * vxd etc). this is done based on different requirements and to make
  1179. + * debugging a little easier. Debugfs introduces separate counter for
  1180. + * each type.
  1181. + */
  1182. +
  1183. +/**
  1184. + * Once we have scheduled commands on GPU, it might take a while GPU
  1185. + * to execute them. Following is done to make sure Gfx is in D0i0 while
  1186. + * GPU is executing the commands.
  1187. + * 1. For IOCTLS make sure we are in D0i0 by calling "get_ioctl".
  1188. + * 2. if IOCTL scheudles GPU commands using rings do the following
  1189. + *  a. For all ring accesses make sure we add a request in the request
  1190. + *     list and schedule a work item to track the "seq no". This
  1191. + *     is done by using "i915_add_request" or "i915_add_request_no_flush"
  1192. + *     functions.
  1193. + *  b. If request list was empty, we do a "get_ring". This will increment
  1194. + *     ref count to make sure GPU will be in D0 state.
  1195. + *  c. Once the list becomes empty call put_ring
  1196. + *
  1197. + * Note: All the ring accesses are covered with struct_mutex. So we
  1198. + * don't need any synchronization to protect ring_active.
  1199. + */
  1200. +int i915_rpm_get_ring(struct drm_device *drm_dev)
  1201. +{
  1202. +   struct intel_engine_cs *ring;
  1203. +   struct drm_i915_private *dev_priv = drm_dev->dev_private;
  1204. +   int i;
  1205. +   bool idle = true;
  1206. +
  1207. +   for_each_ring(ring, dev_priv, i)
  1208. +       idle &= list_empty(&ring->request_list);
  1209. +
  1210. +   if (idle) {
  1211. +       if (!dev_priv->rpm.ring_active) {
  1212. +           dev_priv->rpm.ring_active = true;
  1213. +           pm_runtime_get_noresume(drm_dev->dev);
  1214. +       }
  1215. +   }
  1216. +
  1217. +   return 0;
  1218. +}
  1219. +
  1220. +int i915_rpm_put_ring(struct drm_device *drm_dev)
  1221. +{
  1222. +   struct drm_i915_private *dev_priv = drm_dev->dev_private;
  1223. +
  1224. +   if (dev_priv->rpm.ring_active) {
  1225. +       /* Mark last time it was busy and schedule a autosuspend */
  1226. +       pm_runtime_mark_last_busy(drm_dev->dev);
  1227. +       pm_runtime_put_autosuspend(drm_dev->dev);
  1228. +       dev_priv->rpm.ring_active = false;
  1229. +   }
  1230. +   return 0;
  1231. +}
  1232. +
  1233. +/**
  1234. + * To cover the function pointers that are assigned to drm structures
  1235. + * and can be called from drm
  1236. + */
  1237. +int i915_rpm_get_callback(struct drm_device *drm_dev)
  1238. +{
  1239. +   return pm_runtime_get_sync(drm_dev->dev);
  1240. +}
  1241. +
  1242. +int i915_rpm_put_callback(struct drm_device *drm_dev)
  1243. +{
  1244. +   pm_runtime_mark_last_busy(drm_dev->dev);
  1245. +   return pm_runtime_put_autosuspend(drm_dev->dev);
  1246. +}
  1247. +
  1248. +/**
  1249. + * early_suspend/DSR should call this function to notify PM Core about
  1250. + * display idleness
  1251. + */
  1252. +int i915_rpm_get_disp(struct drm_device *drm_dev)
  1253. +{
  1254. +   return pm_runtime_get_sync(drm_dev->dev);
  1255. +}
  1256. +
  1257. +int i915_rpm_put_disp(struct drm_device *drm_dev)
  1258. +{
  1259. +   pm_runtime_mark_last_busy(drm_dev->dev);
  1260. +   return pm_runtime_put_autosuspend(drm_dev->dev);
  1261. +}
  1262. +
  1263. +/** to cover the ioctls with get/put*/
  1264. +int i915_rpm_get_ioctl(struct drm_device *drm_dev)
  1265. +{
  1266. +   /* Don't do anything if device is not ready */
  1267. +   if (drm_device_is_unplugged(drm_dev))
  1268. +       return 0;
  1269. +
  1270. +   return pm_runtime_get_sync(drm_dev->dev);
  1271. +}
  1272. +
  1273. +int i915_rpm_put_ioctl(struct drm_device *drm_dev)
  1274. +{
  1275. +   /* Don't do anything if device is not ready */
  1276. +   if (drm_device_is_unplugged(drm_dev))
  1277. +       return 0;
  1278. +
  1279. +   pm_runtime_mark_last_busy(drm_dev->dev);
  1280. +   return pm_runtime_put_autosuspend(drm_dev->dev);
  1281. +}
  1282. +
  1283. +/* these operations are caled from user mode (CoreU) to make sure
  1284. + * Gfx is up before register accesses from user mode
  1285. + */
  1286. +int i915_rpm_get_procfs(struct inode *inode, struct file *file)
  1287. +{
  1288. +   struct drm_device *dev = PDE_DATA(inode);
  1289. +   struct drm_i915_private *dev_priv = dev->dev_private;
  1290. +
  1291. +   atomic_inc(&dev_priv->rpm.procfs_count);
  1292. +   pm_runtime_get_sync(dev->dev);
  1293. +   return 0;
  1294. +}
  1295. +
  1296. +int i915_rpm_put_procfs(struct inode *inode, struct file *file)
  1297. +{
  1298. +   struct drm_device *dev = PDE_DATA(inode);
  1299. +   struct drm_i915_private *dev_priv = dev->dev_private;
  1300. +
  1301. +   pm_runtime_mark_last_busy(dev->dev);
  1302. +   pm_runtime_put_autosuspend(dev->dev);
  1303. +   atomic_dec(&dev_priv->rpm.procfs_count);
  1304. +   return 0;
  1305. +}
  1306. +
  1307. +/**
  1308. + * VXD driver need to call this to make sure Gfx is in D0i0
  1309. + * while VXD is on
  1310. + */
  1311. +#ifdef CONFIG_DRM_VXD_BYT
  1312. +int i915_rpm_get_vxd(struct drm_device *drm_dev)
  1313. +{
  1314. +   return pm_runtime_get_sync(drm_dev->dev);
  1315. +}
  1316. +EXPORT_SYMBOL(i915_rpm_get_vxd);
  1317. +
  1318. +/**
  1319. + * VXD driver need to call this to notify Gfx that it is
  1320. + * done with HW accesses
  1321. + */
  1322. +int i915_rpm_put_vxd(struct drm_device *drm_dev)
  1323. +{
  1324. +   pm_runtime_mark_last_busy(drm_dev->dev);
  1325. +   return pm_runtime_put_autosuspend(drm_dev->dev);
  1326. +}
  1327. +EXPORT_SYMBOL(i915_rpm_put_vxd);
  1328. +#endif
  1329. +
  1330. +/* mainly for debug purpose, check if the access is valid */
  1331. +bool i915_rpm_access_check(struct drm_device *dev)
  1332. +{
  1333. +   if (dev->dev->power.runtime_status == RPM_SUSPENDED) {
  1334. +       DRM_ERROR("invalid access, will cause Hard Hang\n");
  1335. +       dump_stack();
  1336. +       return false;
  1337. +   }
  1338. +   return true;
  1339. +}
  1340. +
  1341. +/* mainly for debug purpose, check if mutex is locked by
  1342. + * current thread
  1343. + */
  1344. +int check_mutex_current(struct drm_device *drm_dev)
  1345. +{
  1346. +   int ret = 0;
  1347. +
  1348. +   if ((mutex_is_locked(&drm_dev->mode_config.mutex)) &&
  1349. +           (drm_dev->mode_config.mutex.owner == current)) {
  1350. +       DRM_ERROR("config mutex locked by current thread\n");
  1351. +       dump_stack();
  1352. +       ret = -1;
  1353. +   }
  1354. +   if ((mutex_is_locked(&drm_dev->struct_mutex)) &&
  1355. +           (drm_dev->struct_mutex.owner == current)) {
  1356. +       DRM_ERROR("struct mutex locked by current thread\n");
  1357. +       dump_stack();
  1358. +       ret = -2;
  1359. +   }
  1360. +   return ret;
  1361. +}
  1362. +
  1363. +int check_mutex(struct drm_device *drm_dev)
  1364. +{
  1365. +   int ret = 0;
  1366. +
  1367. +   if (mutex_is_locked(&drm_dev->mode_config.mutex)) {
  1368. +       DRM_ERROR("config mutex locked\n");
  1369. +       dump_stack();
  1370. +       ret = -1;
  1371. +   }
  1372. +   if (mutex_is_locked(&drm_dev->struct_mutex)) {
  1373. +       DRM_ERROR("struct mutex locked\n");
  1374. +       dump_stack();
  1375. +       ret = -2;
  1376. +   }
  1377. +   return ret;
  1378. +}
  1379. +
  1380. +/* Check for current runtime state */
  1381. +bool i915_is_device_active(struct drm_device *dev)
  1382. +{
  1383. +   return (dev->dev->power.runtime_status == RPM_ACTIVE);
  1384. +}
  1385. +
  1386. +bool i915_is_device_resuming(struct drm_device *dev)
  1387. +{
  1388. +   return (dev->dev->power.runtime_status == RPM_RESUMING);
  1389. +}
  1390. +
  1391. +bool i915_is_device_suspended(struct drm_device *dev)
  1392. +{
  1393. +   return (dev->dev->power.runtime_status == RPM_SUSPENDED);
  1394. +}
  1395. +
  1396. +bool i915_is_device_suspending(struct drm_device *dev)
  1397. +{
  1398. +   return (dev->dev->power.runtime_status == RPM_SUSPENDING);
  1399. +}
  1400. +
  1401. +#else /*CONFIG_PM_RUNTIME*/
  1402. +int i915_rpm_init(struct drm_device *dev) {return 0; }
  1403. +int i915_rpm_deinit(struct drm_device *dev) {return 0; }
  1404. +int i915_rpm_get(struct drm_device *dev, u32 flags) {return 0; }
  1405. +int i915_rpm_put(struct drm_device *dev, u32 flags) {return 0; }
  1406. +int i915_rpm_get_ring(struct drm_device *dev) {return 0; }
  1407. +int i915_rpm_put_ring(struct drm_device *dev) {return 0; }
  1408. +int i915_rpm_get_callback(struct drm_device *dev) {return 0; }
  1409. +int i915_rpm_put_callback(struct drm_device *dev) {return 0; }
  1410. +int i915_rpm_get_ioctl(struct drm_device *dev) {return 0; }
  1411. +int i915_rpm_put_ioctl(struct drm_device *dev) {return 0; }
  1412. +int i915_rpm_get_disp(struct drm_device *dev) {return 0; }
  1413. +int i915_rpm_put_disp(struct drm_device *dev) {return 0; }
  1414. +int i915_rpm_get_procfs(struct inode *inode,
  1415. +                 struct file *file) {return 0; }
  1416. +int i915_rpm_put_procfs(struct inode *inode,
  1417. +                 struct file *file) {return 0; }
  1418. +#ifdef CONFIG_DRM_VXD_BYT
  1419. +int i915_rpm_get_vxd(struct drm_device *dev) {return 0; }
  1420. +int i915_rpm_put_vxd(struct drm_device *dev) {return 0; }
  1421. +#endif
  1422. +
  1423. +bool i915_is_device_active(struct drm_device *dev)
  1424. +{
  1425. +   return true;
  1426. +}
  1427. +
  1428. +bool i915_is_device_resuming(struct drm_device *dev)
  1429. +{
  1430. +   return false;
  1431. +}
  1432. +
  1433. +bool i915_is_device_suspended(struct drm_device *dev)
  1434. +{
  1435. +   return false;
  1436. +}
  1437. +
  1438. +bool i915_is_device_suspending(struct drm_device *dev)
  1439. +{
  1440. +   return false;
  1441. +}
  1442. +
  1443. +bool i915_rpm_access_check(struct drm_device *dev)
  1444. +{
  1445. +   return true;
  1446. +}
  1447. +bool i915_pm_runtime_enabled(struct device *dev)
  1448. +{
  1449. +   return false;
  1450. +}
  1451. +
  1452. +void i915_rpm_enable(struct device *dev) {}
  1453. +
  1454. +void i915_rpm_disable(struct drm_device *drm_dev) {}
  1455. +
  1456. +#endif /*CONFIG_PM_RUNTIME*/
  1457. diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
  1458. index b28c29f..916c1b1 100644
  1459. --- a/drivers/gpu/drm/i915/intel_pm.c
  1460. +++ b/drivers/gpu/drm/i915/intel_pm.c
  1461. @@ -31,6 +31,17 @@
  1462.  #include "../../../platform/x86/intel_ips.h"
  1463.  #include <linux/module.h>
  1464.  
  1465. +typedef enum _UHBUsage {
  1466. +   OSPM_UHB_ONLY_IF_ON = 0,
  1467. +   OSPM_UHB_FORCE_POWER_ON,
  1468. +} UHBUsage;
  1469. +
  1470. +static struct drm_device *gdev;
  1471. +
  1472. +#ifdef CONFIG_HAS_EARLYSUSPEND
  1473. +   #include <linux/earlysuspend.h>
  1474. +#endif
  1475. +
  1476.  /**
  1477.   * RC6 is a special power stage which allows the GPU to enter an very
  1478.   * low-voltage mode when idle, using down to 0V while at this stage.  This
  1479. @@ -6964,6 +6975,7 @@ void intel_suspend_hw(struct drm_device *dev)
  1480.  void intel_init_pm(struct drm_device *dev)
  1481.  {
  1482.     struct drm_i915_private *dev_priv = dev->dev_private;
  1483. +   gdev = dev;
  1484.  
  1485.     intel_fbc_init(dev_priv);
  1486.  
  1487. @@ -7257,3 +7269,44 @@ void intel_pm_setup(struct drm_device *dev)
  1488.     atomic_set(&dev_priv->pm.wakeref_count, 0);
  1489.     atomic_set(&dev_priv->pm.atomic_seq, 0);
  1490.  }
  1491. +
  1492. +bool ospm_power_is_hw_on(int hw_islands)
  1493. +{
  1494. +#if 0
  1495. +   struct drm_device *drm_dev = gdev;
  1496. +   unsigned long flags;
  1497. +   bool ret = false;
  1498. +   struct drm_i915_private *dev_priv = drm_dev->dev_private;
  1499. +   u32 data = vlv_punit_read(dev_priv, VLV_IOSFSB_PWRGT_STATUS);
  1500. +
  1501. +   if ((VLV_POWER_GATE_DISPLAY_MASK & data)
  1502. +           == VLV_POWER_GATE_DISPLAY_MASK) {
  1503. +       DRM_ERROR("Display Island not ON\n");
  1504. +       return false;
  1505. +   } else {
  1506. +       return true;
  1507. +   }
  1508. +#endif
  1509. +   return true;
  1510. +}
  1511. +EXPORT_SYMBOL(ospm_power_is_hw_on);
  1512. +
  1513. +/* Dummy Function for HDMI Audio Power management.
  1514. + * Will be updated once S0iX code is integrated
  1515. + */
  1516. +bool ospm_power_using_hw_begin(int hw_island, UHBUsage usage)
  1517. +{
  1518. +   struct drm_device *drm_dev = gdev;
  1519. +
  1520. +   i915_rpm_get_disp(drm_dev);
  1521. +   return i915_is_device_active(drm_dev);
  1522. +}
  1523. +EXPORT_SYMBOL(ospm_power_using_hw_begin);
  1524. +
  1525. +void ospm_power_using_hw_end(int hw_island)
  1526. +{
  1527. +   struct drm_device *drm_dev = gdev;
  1528. +
  1529. +   i915_rpm_put_disp(drm_dev);
  1530. +}
  1531. +EXPORT_SYMBOL(ospm_power_using_hw_end);
  1532.  
  1533. From 360a6900efb298201fc2f44b991f1a7d2c422ecb Mon Sep 17 00:00:00 2001
  1534. From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  1535. Date: Thu, 3 Mar 2016 11:08:10 -0600
  1536. Subject: [PATCH 05/12] drm/i915: Add API code for non-HDAudio HDMI interface
  1537.  
  1538. Add API code for interface available on Baytrail and CherryTrail
  1539.  
  1540. Initial code was downloaded from https://github.com/01org/baytrailaudio/
  1541. ...and had the changes to .config stripped and the revert on sound/init.c
  1542. done by David Henningson
  1543.  
  1544. Clean-up, port to 4.5 and intel-drm by Pierre Bossart
  1545. CherryTrail support by Jerome Anand
  1546.  
  1547. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
  1548. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  1549. ---
  1550.  drivers/gpu/drm/i915/hdmi_audio_if.c | 425 +++++++++++++++++++++++++++++++++++
  1551.  1 file changed, 425 insertions(+)
  1552.  create mode 100644 drivers/gpu/drm/i915/hdmi_audio_if.c
  1553.  
  1554. diff --git a/drivers/gpu/drm/i915/hdmi_audio_if.c b/drivers/gpu/drm/i915/hdmi_audio_if.c
  1555. new file mode 100644
  1556. index 0000000..c7c5f8f
  1557. --- /dev/null
  1558. +++ b/drivers/gpu/drm/i915/hdmi_audio_if.c
  1559. @@ -0,0 +1,425 @@
  1560. +/*
  1561. + * Copyright (c) 2010, Intel Corporation.
  1562. + *
  1563. + * This program is free software; you can redistribute it and/or modify it
  1564. + * under the terms and conditions of the GNU General Public License,
  1565. + * version 2, as published by the Free Software Foundation.
  1566. + *
  1567. + * This program is distributed in the hope it will be useful, but WITHOUT
  1568. + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  1569. + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  1570. + * more details.
  1571. + *
  1572. + * Authors:
  1573. + * jim liu <jim.liu@intel.com>
  1574. + * Uma Shankar <uma.shankar@intel.com>
  1575. + */
  1576. +
  1577. +#include <drm/drmP.h>
  1578. +#include "hdmi_audio_if.h"
  1579. +#include "i915_drv.h"
  1580. +#include "i915_reg.h"
  1581. +
  1582. +#define CONFIG_SUPPORT_HDMI_AUDIO
  1583. +#ifdef CONFIG_SUPPORT_HDMI_AUDIO
  1584. +
  1585. +int i915_hdmi_state;
  1586. +
  1587. +/*
  1588. + * Audio register range 0x65000 to 0x65FFF
  1589. + */
  1590. +
  1591. +#define IS_HDMI_AUDIO_I915(reg) ((reg >= 0x65000) && (reg < 0x65FFF))
  1592. +
  1593. +/* Added for HDMI Audio */
  1594. +#define HAD_MAX_ELD_BYTES 84
  1595. +uint8_t hdmi_eld[HAD_MAX_ELD_BYTES];
  1596. +
  1597. +static struct hdmi_audio_priv *hdmi_priv;
  1598. +
  1599. +void i915_hdmi_audio_init(struct hdmi_audio_priv *p_hdmi_priv)
  1600. +{
  1601. +   hdmi_priv = p_hdmi_priv;
  1602. +}
  1603. +
  1604. +/* Added for HDMI Audio */
  1605. +void hdmi_get_eld(uint8_t *eld)
  1606. +{
  1607. +   struct drm_device *dev = hdmi_priv->dev;
  1608. +   struct drm_i915_private *dev_priv =
  1609. +       (struct drm_i915_private *) dev->dev_private;
  1610. +   memcpy(hdmi_eld, eld, HAD_MAX_ELD_BYTES);
  1611. +   mid_hdmi_audio_signal_event(dev_priv->dev, HAD_EVENT_HOT_PLUG);
  1612. +}
  1613. +
  1614. +static inline int android_hdmi_get_eld(struct drm_device *dev, void *eld)
  1615. +{
  1616. +   memcpy(eld, hdmi_eld, HAD_MAX_ELD_BYTES);
  1617. +   return 0;
  1618. +}
  1619. +
  1620. +struct hdmi_audio_priv *get_hdmi_priv()
  1621. +{
  1622. +   return hdmi_priv;
  1623. +}
  1624. +
  1625. +/*
  1626. + * return whether HDMI audio device is busy.
  1627. + */
  1628. +bool mid_hdmi_audio_is_busy(struct drm_device *dev)
  1629. +{
  1630. +   struct drm_i915_private *dev_priv =
  1631. +       (struct drm_i915_private *) dev->dev_private;
  1632. +   int hdmi_audio_busy = 0;
  1633. +   hdmi_audio_event_t hdmi_audio_event;
  1634. +
  1635. +   if (i915_hdmi_state == connector_status_disconnected) {
  1636. +       /* HDMI is not connected, assuming audio device is idle. */
  1637. +       return false;
  1638. +   }
  1639. +
  1640. +   if (dev_priv->had_interface) {
  1641. +       hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY;
  1642. +       hdmi_audio_busy = dev_priv->had_interface->query(
  1643. +               dev_priv->had_pvt_data,
  1644. +               hdmi_audio_event);
  1645. +       return hdmi_audio_busy != 0;
  1646. +   }
  1647. +   return false;
  1648. +}
  1649. +
  1650. +/*
  1651. + * return whether HDMI audio device is suspended.
  1652. + */
  1653. +bool mid_hdmi_audio_suspend(struct drm_device *dev)
  1654. +{
  1655. +   struct drm_i915_private *dev_priv =
  1656. +       (struct drm_i915_private *) dev->dev_private;
  1657. +   hdmi_audio_event_t hdmi_audio_event;
  1658. +   int ret = 0;
  1659. +
  1660. +   if (i915_hdmi_state == connector_status_disconnected) {
  1661. +       /* HDMI is not connected, assuming audio device
  1662. +        * is suspended already.
  1663. +        */
  1664. +       return true;
  1665. +   }
  1666. +   DRM_DEBUG_DRIVER("%s: i915_hdmi_state %d", __func__,
  1667. +           i915_hdmi_state);
  1668. +
  1669. +   if (dev_priv->had_interface) {
  1670. +       hdmi_audio_event.type = 0;
  1671. +       ret = dev_priv->had_interface->suspend(dev_priv->had_pvt_data,
  1672. +               hdmi_audio_event);
  1673. +       return (ret == 0) ? true : false;
  1674. +   }
  1675. +   return true;
  1676. +}
  1677. +
  1678. +void mid_hdmi_audio_resume(struct drm_device *dev)
  1679. +{
  1680. +   struct drm_i915_private *dev_priv =
  1681. +       (struct drm_i915_private *) dev->dev_private;
  1682. +
  1683. +   if (i915_hdmi_state == connector_status_disconnected) {
  1684. +       /* HDMI is not connected, there is no need
  1685. +        * to resume audio device.
  1686. +        */
  1687. +       return;
  1688. +   }
  1689. +   DRM_DEBUG_DRIVER("%s: i915_hdmi_state %d", __func__,
  1690. +               i915_hdmi_state);
  1691. +
  1692. +   if (dev_priv->had_interface)
  1693. +       dev_priv->had_interface->resume(dev_priv->had_pvt_data);
  1694. +}
  1695. +
  1696. +void mid_hdmi_audio_signal_event(struct drm_device *dev,
  1697. +       enum had_event_type event)
  1698. +{
  1699. +   struct drm_i915_private *dev_priv =
  1700. +       (struct drm_i915_private *) dev->dev_private;
  1701. +
  1702. +   if (dev_priv->had_event_callbacks)
  1703. +       (*dev_priv->had_event_callbacks)(event,
  1704. +           dev_priv->had_pvt_data);
  1705. +}
  1706. +
  1707. +/**
  1708. + * hdmi_audio_write:
  1709. + * used to write into display controller HDMI audio registers.
  1710. + *
  1711. + */
  1712. +static int hdmi_audio_write(uint32_t reg, uint32_t val)
  1713. +{
  1714. +   struct drm_device *dev = hdmi_priv->dev;
  1715. +   struct drm_i915_private *dev_priv =
  1716. +       (struct drm_i915_private *) dev->dev_private;
  1717. +   int ret = 0;
  1718. +
  1719. +   if (hdmi_priv->monitor_type == MONITOR_TYPE_DVI)
  1720. +       return 0;
  1721. +
  1722. +   if (IS_HDMI_AUDIO_I915(reg))
  1723. +       I915_WRITE(_MMIO(VLV_DISPLAY_BASE + reg), val);
  1724. +   else
  1725. +       ret = -EINVAL;
  1726. +
  1727. +   return ret;
  1728. +}
  1729. +
  1730. +/**
  1731. + * hdmi_audio_read:
  1732. + * used to get the register value read from
  1733. + * display controller HDMI audio registers.
  1734. + */
  1735. +static int hdmi_audio_read(uint32_t reg, uint32_t *val)
  1736. +{
  1737. +   struct drm_device *dev = hdmi_priv->dev;
  1738. +   struct drm_i915_private *dev_priv =
  1739. +       (struct drm_i915_private *) dev->dev_private;
  1740. +   int ret = 0;
  1741. +
  1742. +   if (hdmi_priv->monitor_type == MONITOR_TYPE_DVI)
  1743. +       return 0;
  1744. +
  1745. +   if (IS_HDMI_AUDIO_I915(reg))
  1746. +       *val = I915_READ(_MMIO(VLV_DISPLAY_BASE + reg));
  1747. +   else
  1748. +       ret = -EINVAL;
  1749. +
  1750. +   return ret;
  1751. +}
  1752. +
  1753. +/**
  1754. + * hdmi_audio_rmw:
  1755. + * used to update the masked bits in display controller HDMI audio registers .
  1756. + *
  1757. + */
  1758. +static int hdmi_audio_rmw(uint32_t reg, uint32_t val, uint32_t mask)
  1759. +{
  1760. +   struct drm_device *dev = hdmi_priv->dev;
  1761. +   struct drm_i915_private *dev_priv =
  1762. +       (struct drm_i915_private *) dev->dev_private;
  1763. +   int ret = 0;
  1764. +   uint32_t val_tmp = 0;
  1765. +
  1766. +   if (IS_HDMI_AUDIO_I915(reg)) {
  1767. +       val_tmp = (val & mask) |
  1768. +           (I915_READ(_MMIO(VLV_DISPLAY_BASE + reg)) & ~mask);
  1769. +       I915_WRITE(_MMIO(VLV_DISPLAY_BASE + reg), val_tmp);
  1770. +   } else {
  1771. +       ret = -EINVAL;
  1772. +   }
  1773. +
  1774. +   return ret;
  1775. +}
  1776. +
  1777. +/**
  1778. + * hdmi_audio_get_caps:
  1779. + * used to return the HDMI audio capabilities.
  1780. + * e.g. resolution, frame rate.
  1781. + */
  1782. +static int hdmi_audio_get_caps(enum had_caps_list get_element,
  1783. +           void *capabilities)
  1784. +{
  1785. +   struct drm_device *dev = hdmi_priv->dev;
  1786. +   struct drm_i915_private *dev_priv =
  1787. +       (struct drm_i915_private *) dev->dev_private;
  1788. +   int ret = 0;
  1789. +
  1790. +   DRM_DEBUG_DRIVER("\n");
  1791. +
  1792. +   switch (get_element) {
  1793. +   case HAD_GET_ELD:
  1794. +       ret = android_hdmi_get_eld(dev, capabilities);
  1795. +       break;
  1796. +   case HAD_GET_SAMPLING_FREQ:
  1797. +       /* ToDo: Verify if sampling freq logic is correct */
  1798. +       memcpy(capabilities, &(dev_priv->tmds_clock_speed),
  1799. +           sizeof(uint32_t));
  1800. +       break;
  1801. +   default:
  1802. +       break;
  1803. +   }
  1804. +
  1805. +   return ret;
  1806. +}
  1807. +
  1808. +/**
  1809. + * hdmi_audio_get_register_base
  1810. + * used to get the current hdmi base address
  1811. + */
  1812. +int hdmi_audio_get_register_base(uint32_t *reg_base)
  1813. +{
  1814. +   *reg_base = hdmi_priv->hdmi_lpe_audio_reg;
  1815. +   return 0;
  1816. +}
  1817. +
  1818. +/**
  1819. + * hdmi_audio_set_caps:
  1820. + * used to set the HDMI audio capabilities.
  1821. + * e.g. Audio INT.
  1822. + */
  1823. +static int hdmi_audio_set_caps(enum had_caps_list set_element,
  1824. +           void *capabilties)
  1825. +{
  1826. +   struct drm_device *dev = hdmi_priv->dev;
  1827. +   struct drm_i915_private *dev_priv =
  1828. +       (struct drm_i915_private *) dev->dev_private;
  1829. +   int ret = 0;
  1830. +   u32 hdmi_reg;
  1831. +   u32 int_masks = 0;
  1832. +
  1833. +   DRM_DEBUG_DRIVER("\n");
  1834. +
  1835. +   switch (set_element) {
  1836. +   case HAD_SET_ENABLE_AUDIO:
  1837. +       hdmi_reg = I915_READ(_MMIO(hdmi_priv->hdmi_reg));
  1838. +       if (hdmi_reg & PORT_ENABLE)
  1839. +           hdmi_reg |= SDVO_AUDIO_ENABLE;
  1840. +
  1841. +       I915_WRITE(_MMIO(hdmi_priv->hdmi_reg), hdmi_reg);
  1842. +       I915_READ(_MMIO(hdmi_priv->hdmi_reg));
  1843. +       break;
  1844. +   case HAD_SET_DISABLE_AUDIO:
  1845. +       hdmi_reg = I915_READ(_MMIO(hdmi_priv->hdmi_reg)) &
  1846. +           ~SDVO_AUDIO_ENABLE;
  1847. +       I915_WRITE(_MMIO(hdmi_priv->hdmi_reg), hdmi_reg);
  1848. +       I915_READ(_MMIO(hdmi_priv->hdmi_reg));
  1849. +       break;
  1850. +
  1851. +   case HAD_SET_ENABLE_AUDIO_INT:
  1852. +       if (*((u32 *)capabilties) & HDMI_AUDIO_UNDERRUN)
  1853. +           int_masks |= I915_HDMI_AUDIO_UNDERRUN_ENABLE;
  1854. +       dev_priv->hdmi_audio_interrupt_mask |= int_masks;
  1855. +       i915_enable_hdmi_audio_int(dev);
  1856. +       break;
  1857. +   case HAD_SET_DISABLE_AUDIO_INT:
  1858. +       if (*((u32 *)capabilties) & HDMI_AUDIO_UNDERRUN)
  1859. +           int_masks |= I915_HDMI_AUDIO_UNDERRUN_ENABLE;
  1860. +       dev_priv->hdmi_audio_interrupt_mask &= ~int_masks;
  1861. +
  1862. +       i915_disable_hdmi_audio_int(dev);
  1863. +       break;
  1864. +   default:
  1865. +       break;
  1866. +   }
  1867. +
  1868. +   return ret;
  1869. +}
  1870. +
  1871. +static struct  hdmi_audio_registers_ops hdmi_audio_reg_ops = {
  1872. +   .hdmi_audio_get_register_base = hdmi_audio_get_register_base,
  1873. +   .hdmi_audio_read_register = hdmi_audio_read,
  1874. +   .hdmi_audio_write_register = hdmi_audio_write,
  1875. +   .hdmi_audio_read_modify = hdmi_audio_rmw,
  1876. +};
  1877. +
  1878. +static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = {
  1879. +   .hdmi_audio_get_caps = hdmi_audio_get_caps,
  1880. +   .hdmi_audio_set_caps = hdmi_audio_set_caps,
  1881. +};
  1882. +
  1883. +int mid_hdmi_audio_setup(
  1884. +       had_event_call_back audio_callbacks,
  1885. +       struct hdmi_audio_registers_ops *reg_ops,
  1886. +       struct hdmi_audio_query_set_ops *query_ops)
  1887. +{
  1888. +   struct drm_device *dev = hdmi_priv->dev;
  1889. +   struct drm_i915_private *dev_priv =
  1890. +       (struct drm_i915_private *) dev->dev_private;
  1891. +   int ret = 0;
  1892. +
  1893. +   DRM_DEBUG_DRIVER("%s: called\n", __func__);
  1894. +
  1895. +   reg_ops->hdmi_audio_get_register_base =
  1896. +       (hdmi_audio_reg_ops.hdmi_audio_get_register_base);
  1897. +   reg_ops->hdmi_audio_read_register =
  1898. +       (hdmi_audio_reg_ops.hdmi_audio_read_register);
  1899. +   reg_ops->hdmi_audio_write_register =
  1900. +       (hdmi_audio_reg_ops.hdmi_audio_write_register);
  1901. +   reg_ops->hdmi_audio_read_modify =
  1902. +       (hdmi_audio_reg_ops.hdmi_audio_read_modify);
  1903. +   query_ops->hdmi_audio_get_caps =
  1904. +       hdmi_audio_get_set_ops.hdmi_audio_get_caps;
  1905. +   query_ops->hdmi_audio_set_caps =
  1906. +       hdmi_audio_get_set_ops.hdmi_audio_set_caps;
  1907. +
  1908. +   dev_priv->had_event_callbacks = audio_callbacks;
  1909. +
  1910. +   return ret;
  1911. +}
  1912. +EXPORT_SYMBOL(mid_hdmi_audio_setup);
  1913. +
  1914. +int mid_hdmi_audio_register(struct snd_intel_had_interface *driver,
  1915. +               void *had_data)
  1916. +{
  1917. +   struct drm_device *dev;
  1918. +   struct drm_i915_private *dev_priv;
  1919. +
  1920. +   DRM_DEBUG_DRIVER("%s: called\n", __func__);
  1921. +   if (!hdmi_priv)
  1922. +       return -ENODEV;
  1923. +
  1924. +   dev = hdmi_priv->dev;
  1925. +   dev_priv = (struct drm_i915_private *) dev->dev_private;
  1926. +   dev_priv->had_pvt_data = had_data;
  1927. +   dev_priv->had_interface = driver;
  1928. +
  1929. +   if (hdmi_priv->monitor_type == MONITOR_TYPE_DVI)
  1930. +       return 0;
  1931. +
  1932. +   /* The Audio driver is loading now and we need to notify
  1933. +    * it if there is an HDMI device attached
  1934. +    */
  1935. +   DRM_INFO("%s: Scheduling HDMI audio work queue\n", __func__);
  1936. +   schedule_work(&dev_priv->hdmi_audio_wq);
  1937. +
  1938. +   return 0;
  1939. +}
  1940. +EXPORT_SYMBOL(mid_hdmi_audio_register);
  1941. +#else
  1942. +bool hdmi_audio_is_busy(struct drm_device *dev)
  1943. +{
  1944. +   /* always in idle state */
  1945. +   return false;
  1946. +}
  1947. +
  1948. +bool hdmi_audio_suspend(struct drm_device *dev)
  1949. +{
  1950. +   /* always in suspend state */
  1951. +   return true;
  1952. +}
  1953. +
  1954. +void hdmi_audio_resume(struct drm_device *dev)
  1955. +{
  1956. +}
  1957. +
  1958. +void hdmi_audio_signal_event(struct drm_device *dev, enum had_event_type event)
  1959. +{
  1960. +}
  1961. +
  1962. +void i915_hdmi_audio_init(struct hdmi_audio_priv *hdmi_priv)
  1963. +{
  1964. +   DRM_INFO("%s: HDMI is not supported.\n", __func__);
  1965. +}
  1966. +
  1967. +int mid_hdmi_audio_setup(
  1968. +       had_event_call_back audio_callbacks,
  1969. +       struct hdmi_audio_registers_ops *reg_ops,
  1970. +       struct hdmi_audio_query_set_ops *query_ops)
  1971. +{
  1972. +   DRM_ERROR("%s: HDMI is not supported.\n", __func__);
  1973. +   return -ENODEV;
  1974. +}
  1975. +EXPORT_SYMBOL(mid_hdmi_audio_setup);
  1976. +
  1977. +int mid_hdmi_audio_register(struct snd_intel_had_interface *driver,
  1978. +           void *had_data)
  1979. +{
  1980. +   DRM_ERROR("%s: HDMI is not supported.\n", __func__);
  1981. +   return -ENODEV;
  1982. +}
  1983. +EXPORT_SYMBOL(mid_hdmi_audio_register);
  1984. +#endif
  1985.  
  1986. From 62adc203bbd9556c97ff848906f2f76f1cf5d1f0 Mon Sep 17 00:00:00 2001
  1987. From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  1988. Date: Tue, 1 Mar 2016 16:25:04 -0600
  1989. Subject: [PATCH 06/12] drm/i915: enable non-HDAudio HDMI interface Makefile
  1990.  
  1991. Makefile for all previous patches
  1992.  
  1993. This driver was downloaded from https://github.com/01org/baytrailaudio/
  1994.  
  1995. ...and had the changes to .config stripped and the revert on sound/init.c
  1996.  
  1997. clean-up, port to 4.5 and intel-drm by Pierre Bossart
  1998.  
  1999. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
  2000. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  2001. ---
  2002.  drivers/gpu/drm/i915/Makefile | 4 +++-
  2003.  1 file changed, 3 insertions(+), 1 deletion(-)
  2004.  
  2005. diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
  2006. index 0851de07..2432085 100644
  2007. --- a/drivers/gpu/drm/i915/Makefile
  2008. +++ b/drivers/gpu/drm/i915/Makefile
  2009. @@ -12,7 +12,8 @@ i915-y := i915_drv.o \
  2010.       i915_sysfs.o \
  2011.       intel_csr.o \
  2012.       intel_pm.o \
  2013. -     intel_runtime_pm.o
  2014. +     intel_runtime_pm.o \
  2015. +     hdmi_audio_if.o
  2016.  
  2017.  i915-$(CONFIG_COMPAT)   += i915_ioc32.o
  2018.  i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
  2019. @@ -37,6 +38,7 @@ i915-y += i915_cmd_parser.o \
  2020.       i915_trace_points.o \
  2021.       intel_lrc.o \
  2022.       intel_mocs.o \
  2023. +     i915_rpm.o \
  2024.       intel_ringbuffer.o \
  2025.       intel_uncore.o
  2026.  
  2027.  
  2028. From 45ff48a26a923af4de33d810848e5cf7b1a00e68 Mon Sep 17 00:00:00 2001
  2029. From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  2030. Date: Thu, 3 Mar 2016 11:09:26 -0600
  2031. Subject: [PATCH 07/12] ALSA: Intel: Atom: add Atom non-HDAudio HDMI interface
  2032.  
  2033. Add support interface available on Baytrail and CherryTrail
  2034.  
  2035. Initial code was downloaded from https://github.com/01org/baytrailaudio/
  2036. ...and had the changes to .config stripped and the revert on sound/init.c
  2037. and printk->pr_debug done by David Henningson
  2038.  
  2039. Clean-up, port to 4.5 and intel-drm by Pierre Bossart
  2040. CherryTrail support by Jerome Anand
  2041.  
  2042. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
  2043. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  2044. ---
  2045.  sound/Kconfig                              |    8 +
  2046.  sound/Makefile                             |    1 +
  2047.  sound/hdmi_audio/Makefile                  |    9 +
  2048.  sound/hdmi_audio/intel_mid_hdmi_audio.c    | 2027 ++++++++++++++++++++++++++++
  2049.  sound/hdmi_audio/intel_mid_hdmi_audio.h    |  740 ++++++++++
  2050.  sound/hdmi_audio/intel_mid_hdmi_audio_if.c |  533 ++++++++
  2051.  6 files changed, 3318 insertions(+)
  2052.  create mode 100644 sound/hdmi_audio/Makefile
  2053.  create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio.c
  2054.  create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio.h
  2055.  create mode 100644 sound/hdmi_audio/intel_mid_hdmi_audio_if.c
  2056.  
  2057. diff --git a/sound/Kconfig b/sound/Kconfig
  2058. index 5a240e0..75c679e 100644
  2059. --- a/sound/Kconfig
  2060. +++ b/sound/Kconfig
  2061. @@ -134,3 +134,11 @@ config AC97_BUS
  2062.       sound subsystem and other function drivers completely unrelated to
  2063.       sound although they're sharing the AC97 bus. Concerned drivers
  2064.       should "select" this.
  2065. +
  2066. +config SUPPORT_HDMI
  2067. +        bool "SUPPORT_HDMI"
  2068. +        depends on DRM_I915
  2069. +        default n
  2070. +        help
  2071. +          Choose this option to support HDMI.
  2072. +
  2073. diff --git a/sound/Makefile b/sound/Makefile
  2074. index 7732070..f2c5e82 100644
  2075. --- a/sound/Makefile
  2076. +++ b/sound/Makefile
  2077. @@ -8,6 +8,7 @@ obj-$(CONFIG_DMASOUND) += oss/
  2078.  obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
  2079.     firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/
  2080.  obj-$(CONFIG_SND_AOA) += aoa/
  2081. +obj-$(CONFIG_SUPPORT_HDMI) += hdmi_audio/
  2082.  
  2083.  # This one must be compilable even if sound is configured out
  2084.  obj-$(CONFIG_AC97_BUS) += ac97_bus.o
  2085. diff --git a/sound/hdmi_audio/Makefile b/sound/hdmi_audio/Makefile
  2086. new file mode 100644
  2087. index 0000000..b28eb3b
  2088. --- /dev/null
  2089. +++ b/sound/hdmi_audio/Makefile
  2090. @@ -0,0 +1,9 @@
  2091. +DRIVER_NAME := hdmi_audio
  2092. +
  2093. +ccflags-y += -Idrivers/gpu/drm/i915
  2094. +
  2095. +$(DRIVER_NAME)-objs += \
  2096. +   intel_mid_hdmi_audio.o \
  2097. +   intel_mid_hdmi_audio_if.o
  2098. +
  2099. +obj-m += $(DRIVER_NAME).o
  2100. diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  2101. new file mode 100644
  2102. index 0000000..d8c5574
  2103. --- /dev/null
  2104. +++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  2105. @@ -0,0 +1,2027 @@
  2106. +/*
  2107. + *   intel_mid_hdmi_audio.c - Intel HDMI audio driver for MID
  2108. + *
  2109. + *  Copyright (C) 2010 Intel Corp
  2110. + *  Authors:   Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
  2111. + *     Ramesh Babu K V <ramesh.babu@intel.com>
  2112. + *     Vaibhav Agarwal <vaibhav.agarwal@intel.com>
  2113. + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2114. + *
  2115. + *  This program is free software; you can redistribute it and/or modify
  2116. + *  it under the terms of the GNU General Public License as published by
  2117. + *  the Free Software Foundation; version 2 of the License.
  2118. + *
  2119. + *  This program is distributed in the hope that it will be useful, but
  2120. + *  WITHOUT ANY WARRANTY; without even the implied warranty of
  2121. + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  2122. + *  General Public License for more details.
  2123. + *
  2124. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2125. + * ALSA driver for Intel MID HDMI audio controller
  2126. + */
  2127. +
  2128. +#define pr_fmt(fmt)    "had: " fmt
  2129. +
  2130. +#include <linux/platform_device.h>
  2131. +#include <linux/io.h>
  2132. +#include <linux/slab.h>
  2133. +#include <linux/module.h>
  2134. +#include <linux/acpi.h>
  2135. +#include <sound/pcm.h>
  2136. +#include <sound/core.h>
  2137. +#include <sound/pcm_params.h>
  2138. +#include <sound/initval.h>
  2139. +#include <sound/control.h>
  2140. +#include <sound/initval.h>
  2141. +
  2142. +#include "intel_mid_hdmi_audio.h"
  2143. +
  2144. +#define PCM_INDEX      0
  2145. +#define MAX_PB_STREAMS     1
  2146. +#define MAX_CAP_STREAMS        0
  2147. +#define HDMI_AUDIO_DRIVER  "hdmi-audio"
  2148. +static DEFINE_MUTEX(had_mutex);
  2149. +
  2150. +/*standard module options for ALSA. This module supports only one card*/
  2151. +static int hdmi_card_index = SNDRV_DEFAULT_IDX1;
  2152. +static char *hdmi_card_id = SNDRV_DEFAULT_STR1;
  2153. +static struct snd_intelhad *had_data;
  2154. +
  2155. +module_param(hdmi_card_index, int, 0444);
  2156. +MODULE_PARM_DESC(hdmi_card_index,
  2157. +       "Index value for INTEL Intel HDMI Audio controller.");
  2158. +module_param(hdmi_card_id, charp, 0444);
  2159. +MODULE_PARM_DESC(hdmi_card_id,
  2160. +       "ID string for INTEL Intel HDMI Audio controller.");
  2161. +MODULE_AUTHOR("Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>");
  2162. +MODULE_AUTHOR("Ramesh Babu K V <ramesh.babu@intel.com>");
  2163. +MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@intel.com>");
  2164. +MODULE_DESCRIPTION("Intel HDMI Audio driver");
  2165. +MODULE_LICENSE("GPL v2");
  2166. +MODULE_SUPPORTED_DEVICE("{Intel,Intel_HAD}");
  2167. +MODULE_VERSION(HAD_DRIVER_VERSION);
  2168. +
  2169. +#define INFO_FRAME_WORD1   0x000a0184
  2170. +#define FIFO_THRESHOLD     0xFE
  2171. +#define DMA_FIFO_THRESHOLD 0x7
  2172. +#define BYTES_PER_WORD     0x4
  2173. +
  2174. +/* Sampling rate as per IEC60958 Ver 3 */
  2175. +#define CH_STATUS_MAP_32KHZ    0x3
  2176. +#define CH_STATUS_MAP_44KHZ    0x0
  2177. +#define CH_STATUS_MAP_48KHZ    0x2
  2178. +#define CH_STATUS_MAP_88KHZ    0x8
  2179. +#define CH_STATUS_MAP_96KHZ    0xA
  2180. +#define CH_STATUS_MAP_176KHZ   0xC
  2181. +#define CH_STATUS_MAP_192KHZ   0xE
  2182. +
  2183. +#define MAX_SMPL_WIDTH_20  0x0
  2184. +#define MAX_SMPL_WIDTH_24  0x1
  2185. +#define SMPL_WIDTH_16BITS  0x1
  2186. +#define SMPL_WIDTH_24BITS  0x5
  2187. +#define CHANNEL_ALLOCATION 0x1F
  2188. +#define MASK_BYTE0     0x000000FF
  2189. +#define VALID_DIP_WORDS        3
  2190. +#define LAYOUT0            0
  2191. +#define LAYOUT1            1
  2192. +#define SWAP_LFE_CENTER        0x00fac4c8
  2193. +#define AUD_CONFIG_CH_MASK_V2  0x70
  2194. +
  2195. +/*
  2196. + * ELD SA bits in the CEA Speaker Allocation data block
  2197. +*/
  2198. +static int eld_speaker_allocation_bits[] = {
  2199. +   [0] = FL | FR,
  2200. +   [1] = LFE,
  2201. +   [2] = FC,
  2202. +   [3] = RL | RR,
  2203. +   [4] = RC,
  2204. +   [5] = FLC | FRC,
  2205. +   [6] = RLC | RRC,
  2206. +   /* the following are not defined in ELD yet */
  2207. +   [7] = 0,
  2208. +};
  2209. +
  2210. +/*
  2211. + * This is an ordered list!
  2212. + *
  2213. + * The preceding ones have better chances to be selected by
  2214. + * hdmi_channel_allocation().
  2215. + */
  2216. +static struct cea_channel_speaker_allocation channel_allocations[] = {
  2217. +/*                        channel:   7     6    5    4    3     2    1    0  */
  2218. +{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
  2219. +               /* 2.1 */
  2220. +{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
  2221. +               /* Dolby Surround */
  2222. +{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
  2223. +               /* surround40 */
  2224. +{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
  2225. +               /* surround41 */
  2226. +{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
  2227. +               /* surround50 */
  2228. +{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
  2229. +               /* surround51 */
  2230. +{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
  2231. +               /* 6.1 */
  2232. +{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
  2233. +               /* surround71 */
  2234. +{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
  2235. +
  2236. +{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
  2237. +{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
  2238. +{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
  2239. +{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
  2240. +{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
  2241. +{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
  2242. +{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
  2243. +{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
  2244. +{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
  2245. +{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
  2246. +{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
  2247. +{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
  2248. +{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
  2249. +{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
  2250. +{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
  2251. +{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
  2252. +{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
  2253. +{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
  2254. +{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
  2255. +{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
  2256. +{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
  2257. +{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
  2258. +{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
  2259. +};
  2260. +
  2261. +static struct channel_map_table map_tables[] = {
  2262. +   { SNDRV_CHMAP_FL,       0x00,   FL },
  2263. +   { SNDRV_CHMAP_FR,       0x01,   FR },
  2264. +   { SNDRV_CHMAP_RL,       0x04,   RL },
  2265. +   { SNDRV_CHMAP_RR,       0x05,   RR },
  2266. +   { SNDRV_CHMAP_LFE,      0x02,   LFE },
  2267. +   { SNDRV_CHMAP_FC,       0x03,   FC },
  2268. +   { SNDRV_CHMAP_RLC,      0x06,   RLC },
  2269. +   { SNDRV_CHMAP_RRC,      0x07,   RRC },
  2270. +   {} /* terminator */
  2271. +};
  2272. +
  2273. +/* hardware capability structure */
  2274. +static const struct snd_pcm_hardware snd_intel_hadstream = {
  2275. +   .info = (SNDRV_PCM_INFO_INTERLEAVED |
  2276. +       SNDRV_PCM_INFO_DOUBLE |
  2277. +       SNDRV_PCM_INFO_MMAP|
  2278. +       SNDRV_PCM_INFO_MMAP_VALID |
  2279. +       SNDRV_PCM_INFO_BATCH),
  2280. +   .formats = (SNDRV_PCM_FMTBIT_S24 |
  2281. +       SNDRV_PCM_FMTBIT_U24),
  2282. +   .rates = SNDRV_PCM_RATE_32000 |
  2283. +       SNDRV_PCM_RATE_44100 |
  2284. +       SNDRV_PCM_RATE_48000 |
  2285. +       SNDRV_PCM_RATE_88200 |
  2286. +       SNDRV_PCM_RATE_96000 |
  2287. +       SNDRV_PCM_RATE_176400 |
  2288. +       SNDRV_PCM_RATE_192000,
  2289. +   .rate_min = HAD_MIN_RATE,
  2290. +   .rate_max = HAD_MAX_RATE,
  2291. +   .channels_min = HAD_MIN_CHANNEL,
  2292. +   .channels_max = HAD_MAX_CHANNEL,
  2293. +   .buffer_bytes_max = HAD_MAX_BUFFER,
  2294. +   .period_bytes_min = HAD_MIN_PERIOD_BYTES,
  2295. +   .period_bytes_max = HAD_MAX_PERIOD_BYTES,
  2296. +   .periods_min = HAD_MIN_PERIODS,
  2297. +   .periods_max = HAD_MAX_PERIODS,
  2298. +   .fifo_size = HAD_FIFO_SIZE,
  2299. +};
  2300. +
  2301. +/* Register access functions */
  2302. +
  2303. +inline int had_get_hwstate(struct snd_intelhad *intelhaddata)
  2304. +{
  2305. +   /* Check for device presence -SW state */
  2306. +   if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
  2307. +       pr_debug("%s:Device not connected:%d\n", __func__,
  2308. +               intelhaddata->drv_status);
  2309. +       return -ENODEV;
  2310. +   }
  2311. +
  2312. +   /* Check for device presence -HW state */
  2313. +   if (!ospm_power_is_hw_on(OSPM_DISPLAY_ISLAND)) {
  2314. +       pr_err("%s:Device not connected\n", __func__);
  2315. +       /* HOT_UNPLUG event can be sent to
  2316. +        * maintain correct state within HAD
  2317. +        * had_event_handler(HAD_EVENT_HOT_UNPLUG, intelhaddata);
  2318. +        * Drop all acuired locks before executing this.
  2319. +        */
  2320. +       return -ENODEV;
  2321. +   }
  2322. +
  2323. +   return 0;
  2324. +}
  2325. +
  2326. +inline int had_get_caps(enum had_caps_list query, void *caps)
  2327. +{
  2328. +   int retval;
  2329. +   struct snd_intelhad *intelhaddata = had_data;
  2330. +
  2331. +   retval = had_get_hwstate(intelhaddata);
  2332. +   if (!retval)
  2333. +       retval = intelhaddata->query_ops.hdmi_audio_get_caps(query,
  2334. +               caps);
  2335. +
  2336. +   return retval;
  2337. +}
  2338. +
  2339. +inline int had_set_caps(enum had_caps_list set_element, void *caps)
  2340. +{
  2341. +   int retval;
  2342. +   struct snd_intelhad *intelhaddata = had_data;
  2343. +
  2344. +   retval = had_get_hwstate(intelhaddata);
  2345. +   if (!retval)
  2346. +       retval = intelhaddata->query_ops.hdmi_audio_set_caps(
  2347. +               set_element, caps);
  2348. +
  2349. +   return retval;
  2350. +}
  2351. +
  2352. +inline int had_read_register(uint32_t offset, uint32_t *data)
  2353. +{
  2354. +   int retval;
  2355. +   struct snd_intelhad *intelhaddata = had_data;
  2356. +   u32 base_addr = intelhaddata->audio_reg_base;
  2357. +
  2358. +   retval = had_get_hwstate(intelhaddata);
  2359. +   if (!retval)
  2360. +       retval = intelhaddata->reg_ops.hdmi_audio_read_register(
  2361. +               base_addr + offset, data);
  2362. +
  2363. +   return retval;
  2364. +}
  2365. +
  2366. +inline int had_write_register(uint32_t offset, uint32_t data)
  2367. +{
  2368. +   int retval;
  2369. +   struct snd_intelhad *intelhaddata = had_data;
  2370. +   u32 base_addr = intelhaddata->audio_reg_base;
  2371. +
  2372. +   retval = had_get_hwstate(intelhaddata);
  2373. +   if (!retval)
  2374. +       retval = intelhaddata->reg_ops.hdmi_audio_write_register(
  2375. +               base_addr + offset, data);
  2376. +
  2377. +   return retval;
  2378. +}
  2379. +
  2380. +inline int had_read_modify(uint32_t offset, uint32_t data, uint32_t mask)
  2381. +{
  2382. +   int retval;
  2383. +   struct snd_intelhad *intelhaddata = had_data;
  2384. +   u32 base_addr = intelhaddata->audio_reg_base;
  2385. +
  2386. +   retval = had_get_hwstate(intelhaddata);
  2387. +   if (!retval)
  2388. +       retval = intelhaddata->reg_ops.hdmi_audio_read_modify(
  2389. +               base_addr + offset, data, mask);
  2390. +
  2391. +   return retval;
  2392. +}
  2393. +/**
  2394. + * had_read_modify_aud_config_v2 - Specific function to read-modify AUD_CONFIG
  2395. + * register on VLV2.The had_read_modify() function should not directly be used
  2396. + * on VLV2 for updating AUD_CONFIG register.
  2397. + * This is because:
  2398. + * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2 HDMI IP.
  2399. + * As a result a read-modify of AUD_CONFIG regiter will always clear bit6.
  2400. + * AUD_CONFIG[6:4] represents the "channels" field of the register.
  2401. + * This field should be 1xy binary for configuration with 6 or more channels.
  2402. + * Read-modify of AUD_CONFIG (Eg. for enabling audio) causes the "channels" field
  2403. + * to be updated as 0xy binary resulting in bad audio.
  2404. + * The fix is to always write the AUD_CONFIG[6:4] with appropriate value when
  2405. + * doing read-modify of AUD_CONFIG register.
  2406. + *
  2407. + * @substream: the current substream or NULL if no active substream
  2408. + * @data : data to be written
  2409. + * @mask : mask
  2410. + *
  2411. + */
  2412. +inline int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream,
  2413. +                   uint32_t data, uint32_t mask)
  2414. +{
  2415. +   union aud_cfg cfg_val = {.cfg_regval = 0};
  2416. +   u8 channels;
  2417. +
  2418. +   /*
  2419. +    * If substream is NULL, there is no active stream.
  2420. +    * In this case just set channels to 2
  2421. +    */
  2422. +   if (substream)
  2423. +       channels = substream->runtime->channels;
  2424. +   else
  2425. +       channels = 2;
  2426. +   cfg_val.cfg_regx_v2.num_ch = channels - 2;
  2427. +
  2428. +   data = data | cfg_val.cfg_regval;
  2429. +   mask = mask | AUD_CONFIG_CH_MASK_V2;
  2430. +
  2431. +   pr_debug("%s : data = %x, mask =%x\n", __func__, data, mask);
  2432. +
  2433. +   return had_read_modify(AUD_CONFIG, data, mask);
  2434. +}
  2435. +
  2436. +/**
  2437. + * snd_intelhad_enable_audio_v1 - to enable audio
  2438. + *
  2439. + * @substream: Current substream or NULL if no active substream.
  2440. + * @enable: 1 if audio is to be enabled; 0 if audio is to be disabled.
  2441. + *
  2442. + */
  2443. +static void snd_intelhad_enable_audio_v1(struct snd_pcm_substream *substream,
  2444. +                   u8 enable)
  2445. +{
  2446. +   had_read_modify(AUD_CONFIG, enable, BIT(0));
  2447. +}
  2448. +
  2449. +/**
  2450. + * snd_intelhad_enable_audio_v2 - to enable audio
  2451. + *
  2452. + * @substream: Current substream or NULL if no active substream.
  2453. + * @enable: 1 if audio is to be enabled; 0 if audio is to be disabled.
  2454. + */
  2455. +static void snd_intelhad_enable_audio_v2(struct snd_pcm_substream *substream,
  2456. +                   u8 enable)
  2457. +{
  2458. +   had_read_modify_aud_config_v2(substream, enable, BIT(0));
  2459. +}
  2460. +
  2461. +/**
  2462. + * snd_intelhad_reset_audio_v1 - to reset audio subsystem
  2463. + *
  2464. + * @reset: 1 to reset audio; 0 to bring audio out of reset.
  2465. + *
  2466. + */
  2467. +static void snd_intelhad_reset_audio_v1(u8 reset)
  2468. +{
  2469. +   had_write_register(AUD_HDMI_STATUS, reset);
  2470. +}
  2471. +
  2472. +/**
  2473. + * snd_intelhad_reset_audio_v2 - to reset audio subsystem
  2474. + *
  2475. + * @reset: 1 to reset audio; 0 to bring audio out of reset.
  2476. + *
  2477. + */
  2478. +static void snd_intelhad_reset_audio_v2(u8 reset)
  2479. +{
  2480. +   had_write_register(AUD_HDMI_STATUS_v2, reset);
  2481. +}
  2482. +
  2483. +/**
  2484. + * had_prog_status_reg - to initialize audio channel status registers
  2485. + *
  2486. + * @substream:substream for which the prepare function is called
  2487. + * @intelhaddata:substream private data
  2488. + *
  2489. + * This function is called in the prepare callback
  2490. + */
  2491. +static int had_prog_status_reg(struct snd_pcm_substream *substream,
  2492. +           struct snd_intelhad *intelhaddata)
  2493. +{
  2494. +   union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0};
  2495. +   union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0};
  2496. +   int format;
  2497. +
  2498. +   pr_debug("Entry %s\n", __func__);
  2499. +
  2500. +   ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits &
  2501. +                       IEC958_AES0_NONAUDIO)>>1;
  2502. +   ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits &
  2503. +                       IEC958_AES3_CON_CLOCK)>>4;
  2504. +   switch (substream->runtime->rate) {
  2505. +   case AUD_SAMPLE_RATE_32:
  2506. +       ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ;
  2507. +       break;
  2508. +
  2509. +   case AUD_SAMPLE_RATE_44_1:
  2510. +       ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_44KHZ;
  2511. +       break;
  2512. +   case AUD_SAMPLE_RATE_48:
  2513. +       ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_48KHZ;
  2514. +       break;
  2515. +   case AUD_SAMPLE_RATE_88_2:
  2516. +       ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_88KHZ;
  2517. +       break;
  2518. +   case AUD_SAMPLE_RATE_96:
  2519. +       ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_96KHZ;
  2520. +       break;
  2521. +   case AUD_SAMPLE_RATE_176_4:
  2522. +       ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_176KHZ;
  2523. +       break;
  2524. +   case AUD_SAMPLE_RATE_192:
  2525. +       ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_192KHZ;
  2526. +       break;
  2527. +
  2528. +   default:
  2529. +       /* control should never come here */
  2530. +       return -EINVAL;
  2531. +   break;
  2532. +
  2533. +   }
  2534. +   had_write_register(AUD_CH_STATUS_0, ch_stat0.status_0_regval);
  2535. +
  2536. +   format = substream->runtime->format;
  2537. +
  2538. +   if (format == SNDRV_PCM_FORMAT_S16_LE) {
  2539. +       ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_20;
  2540. +       ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_16BITS;
  2541. +   } else if (format == SNDRV_PCM_FORMAT_S24_LE) {
  2542. +       ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_24;
  2543. +       ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_24BITS;
  2544. +   } else {
  2545. +       ch_stat1.status_1_regx.max_wrd_len = 0;
  2546. +       ch_stat1.status_1_regx.wrd_len = 0;
  2547. +   }
  2548. +   had_write_register(AUD_CH_STATUS_1, ch_stat1.status_1_regval);
  2549. +   return 0;
  2550. +}
  2551. +
  2552. +/**
  2553. + * snd_intelhad_prog_audio_ctrl_v2 - to initialize audio
  2554. + * registers and buffer confgiuration registers
  2555. + *
  2556. + * @substream:substream for which the prepare function is called
  2557. + * @intelhaddata:substream private data
  2558. + *
  2559. + * This function is called in the prepare callback
  2560. + */
  2561. +int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream,
  2562. +                   struct snd_intelhad *intelhaddata)
  2563. +{
  2564. +   union aud_cfg cfg_val = {.cfg_regval = 0};
  2565. +   union aud_buf_config buf_cfg = {.buf_cfgval = 0};
  2566. +   u8 channels;
  2567. +
  2568. +   had_prog_status_reg(substream, intelhaddata);
  2569. +
  2570. +   buf_cfg.buf_cfg_regx_v2.audio_fifo_watermark = FIFO_THRESHOLD;
  2571. +   buf_cfg.buf_cfg_regx_v2.dma_fifo_watermark = DMA_FIFO_THRESHOLD;
  2572. +   buf_cfg.buf_cfg_regx_v2.aud_delay = 0;
  2573. +   had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval);
  2574. +
  2575. +   channels = substream->runtime->channels;
  2576. +   cfg_val.cfg_regx_v2.num_ch = channels - 2;
  2577. +   if (channels <= 2)
  2578. +       cfg_val.cfg_regx_v2.layout = LAYOUT0;
  2579. +   else
  2580. +       cfg_val.cfg_regx_v2.layout = LAYOUT1;
  2581. +
  2582. +   cfg_val.cfg_regx_v2.val_bit = 1;
  2583. +   had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
  2584. +   return 0;
  2585. +}
  2586. +
  2587. +/**
  2588. + * snd_intelhad_prog_audio_ctrl_v1 - to initialize audio
  2589. + * registers and buffer confgiuration registers
  2590. + *
  2591. + * @substream:substream for which the prepare function is called
  2592. + * @intelhaddata:substream private data
  2593. + *
  2594. + * This function is called in the prepare callback
  2595. + */
  2596. +int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream,
  2597. +                   struct snd_intelhad *intelhaddata)
  2598. +{
  2599. +   union aud_cfg cfg_val = {.cfg_regval = 0};
  2600. +   union aud_buf_config buf_cfg = {.buf_cfgval = 0};
  2601. +   u8 channels;
  2602. +
  2603. +   had_prog_status_reg(substream, intelhaddata);
  2604. +
  2605. +   buf_cfg.buf_cfg_regx.fifo_width = FIFO_THRESHOLD;
  2606. +   buf_cfg.buf_cfg_regx.aud_delay = 0;
  2607. +   had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval);
  2608. +
  2609. +   channels = substream->runtime->channels;
  2610. +
  2611. +   switch (channels) {
  2612. +   case 1:
  2613. +   case 2:
  2614. +       cfg_val.cfg_regx.num_ch = CH_STEREO;
  2615. +       cfg_val.cfg_regx.layout = LAYOUT0;
  2616. +   break;
  2617. +
  2618. +   case 3:
  2619. +   case 4:
  2620. +       cfg_val.cfg_regx.num_ch = CH_THREE_FOUR;
  2621. +       cfg_val.cfg_regx.layout = LAYOUT1;
  2622. +   break;
  2623. +
  2624. +   case 5:
  2625. +   case 6:
  2626. +       cfg_val.cfg_regx.num_ch = CH_FIVE_SIX;
  2627. +       cfg_val.cfg_regx.layout = LAYOUT1;
  2628. +   break;
  2629. +
  2630. +   case 7:
  2631. +   case 8:
  2632. +       cfg_val.cfg_regx.num_ch = CH_SEVEN_EIGHT;
  2633. +       cfg_val.cfg_regx.layout = LAYOUT1;
  2634. +   break;
  2635. +
  2636. +   }
  2637. +
  2638. +   cfg_val.cfg_regx.val_bit = 1;
  2639. +   had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
  2640. +   return 0;
  2641. +}
  2642. +/*
  2643. + * Compute derived values in channel_allocations[].
  2644. + */
  2645. +static void init_channel_allocations(void)
  2646. +{
  2647. +   int i, j;
  2648. +   struct cea_channel_speaker_allocation *p;
  2649. +
  2650. +   pr_debug("%s: Enter\n", __func__);
  2651. +
  2652. +   for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
  2653. +       p = channel_allocations + i;
  2654. +       p->channels = 0;
  2655. +       p->spk_mask = 0;
  2656. +       for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
  2657. +           if (p->speakers[j]) {
  2658. +               p->channels++;
  2659. +               p->spk_mask |= p->speakers[j];
  2660. +           }
  2661. +   }
  2662. +}
  2663. +
  2664. +/*
  2665. + * The transformation takes two steps:
  2666. + *
  2667. + *      eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
  2668. + *            spk_mask => (channel_allocations[])         => ai->CA
  2669. + *
  2670. + * TODO: it could select the wrong CA from multiple candidates.
  2671. +*/
  2672. +static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata,
  2673. +                   int channels)
  2674. +{
  2675. +   int i;
  2676. +   int ca = 0;
  2677. +   int spk_mask = 0;
  2678. +
  2679. +   /*
  2680. +   * CA defaults to 0 for basic stereo audio
  2681. +   */
  2682. +   if (channels <= 2)
  2683. +       return 0;
  2684. +
  2685. +   /*
  2686. +   * expand ELD's speaker allocation mask
  2687. +   *
  2688. +   * ELD tells the speaker mask in a compact(paired) form,
  2689. +   * expand ELD's notions to match the ones used by Audio InfoFrame.
  2690. +   */
  2691. +
  2692. +   for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
  2693. +       if (intelhaddata->eeld.speaker_allocation_block & (1 << i))
  2694. +           spk_mask |= eld_speaker_allocation_bits[i];
  2695. +   }
  2696. +
  2697. +   /* search for the first working match in the CA table */
  2698. +   for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
  2699. +       if (channels == channel_allocations[i].channels &&
  2700. +       (spk_mask & channel_allocations[i].spk_mask) ==
  2701. +               channel_allocations[i].spk_mask) {
  2702. +           ca = channel_allocations[i].ca_index;
  2703. +           break;
  2704. +       }
  2705. +   }
  2706. +
  2707. +   pr_debug("HDMI: select CA 0x%x for %d\n", ca, channels);
  2708. +
  2709. +   return ca;
  2710. +}
  2711. +
  2712. +/* from speaker bit mask to ALSA API channel position */
  2713. +static int spk_to_chmap(int spk)
  2714. +{
  2715. +   struct channel_map_table *t = map_tables;
  2716. +
  2717. +   for (; t->map; t++) {
  2718. +       if (t->spk_mask == spk)
  2719. +           return t->map;
  2720. +   }
  2721. +   return 0;
  2722. +}
  2723. +
  2724. +void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
  2725. +{
  2726. +   int i = 0, c = 0;
  2727. +   int spk_mask = 0;
  2728. +   struct snd_pcm_chmap_elem *chmap;
  2729. +   uint8_t eld_high, eld_high_mask = 0xF0;
  2730. +   uint8_t high_msb;
  2731. +
  2732. +   chmap = kzalloc(sizeof(*chmap), GFP_KERNEL);
  2733. +   if (chmap == NULL) {
  2734. +       pr_err("kzalloc returned null in %s\n", __func__);
  2735. +       intelhaddata->chmap->chmap = NULL;
  2736. +       return;
  2737. +   }
  2738. +
  2739. +   had_get_caps(HAD_GET_ELD, &intelhaddata->eeld);
  2740. +
  2741. +   pr_debug("eeld.speaker_allocation_block = %x\n",
  2742. +           intelhaddata->eeld.speaker_allocation_block);
  2743. +
  2744. +   /* WA: Fix the max channel supported to 8 */
  2745. +
  2746. +   /*
  2747. +    * Sink may support more than 8 channels, if eld_high has more than
  2748. +    * one bit set. SOC supports max 8 channels.
  2749. +    * Refer eld_speaker_allocation_bits, for sink speaker allocation
  2750. +    */
  2751. +
  2752. +   /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */
  2753. +   eld_high = intelhaddata->eeld.speaker_allocation_block & eld_high_mask;
  2754. +   if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) {
  2755. +       /* eld_high & (eld_high-1): if more than 1 bit set */
  2756. +       /* 0x1F: 7 channels */
  2757. +       for (i = 1; i < 4; i++) {
  2758. +           high_msb = eld_high & (0x80 >> i);
  2759. +           if (high_msb) {
  2760. +               intelhaddata->eeld.speaker_allocation_block &=
  2761. +                   high_msb | 0xF;
  2762. +               break;
  2763. +           }
  2764. +       }
  2765. +   }
  2766. +
  2767. +   for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
  2768. +       if (intelhaddata->eeld.speaker_allocation_block & (1 << i))
  2769. +           spk_mask |= eld_speaker_allocation_bits[i];
  2770. +   }
  2771. +
  2772. +   for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
  2773. +       if (spk_mask == channel_allocations[i].spk_mask) {
  2774. +           for (c = 0; c < channel_allocations[i].channels; c++) {
  2775. +               chmap->map[c] = spk_to_chmap(
  2776. +                   channel_allocations[i].speakers[(MAX_SPEAKERS - 1)-c]);
  2777. +           }
  2778. +           chmap->channels = channel_allocations[i].channels;
  2779. +           intelhaddata->chmap->chmap = chmap;
  2780. +           break;
  2781. +       }
  2782. +   }
  2783. +   if (i >= ARRAY_SIZE(channel_allocations))
  2784. +       kfree(chmap);
  2785. +}
  2786. +
  2787. +/*
  2788. + ** ALSA API channel-map control callbacks
  2789. + **/
  2790. +static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol,
  2791. +               struct snd_ctl_elem_info *uinfo)
  2792. +{
  2793. +   struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
  2794. +   struct snd_intelhad *intelhaddata = info->private_data;
  2795. +
  2796. +   if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED)
  2797. +       return -ENODEV;
  2798. +   uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  2799. +   uinfo->count = HAD_MAX_CHANNEL;
  2800. +   uinfo->value.integer.min = 0;
  2801. +   uinfo->value.integer.max = SNDRV_CHMAP_LAST;
  2802. +   return 0;
  2803. +}
  2804. +
  2805. +#ifndef USE_ALSA_DEFAULT_TLV
  2806. +static int had_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
  2807. +               unsigned int size, unsigned int __user *tlv)
  2808. +{
  2809. +   struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
  2810. +   struct snd_intelhad *intelhaddata = info->private_data;
  2811. +
  2812. +   if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED)
  2813. +       return -ENODEV;
  2814. +
  2815. +   /* TODO: Fix for query channel map */
  2816. +   return -EPERM;
  2817. +}
  2818. +#endif
  2819. +
  2820. +static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol,
  2821. +               struct snd_ctl_elem_value *ucontrol)
  2822. +{
  2823. +   struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
  2824. +   struct snd_intelhad *intelhaddata = info->private_data;
  2825. +   int i = 0;
  2826. +   const struct snd_pcm_chmap_elem *chmap;
  2827. +
  2828. +   if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED)
  2829. +       return -ENODEV;
  2830. +   if (intelhaddata->chmap->chmap ==  NULL)
  2831. +       return -ENODATA;
  2832. +   chmap = intelhaddata->chmap->chmap;
  2833. +   for (i = 0; i < chmap->channels; i++) {
  2834. +       ucontrol->value.integer.value[i] = chmap->map[i];
  2835. +       pr_debug("chmap->map[%d] = %d\n", i, chmap->map[i]);
  2836. +   }
  2837. +
  2838. +   return 0;
  2839. +}
  2840. +
  2841. +static int had_chmap_ctl_put(struct snd_kcontrol *kcontrol,
  2842. +               struct snd_ctl_elem_value *ucontrol)
  2843. +{
  2844. +   /* TODO: Get channel map and set swap register */
  2845. +   return -EPERM;
  2846. +}
  2847. +
  2848. +static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata,
  2849. +                       struct snd_pcm *pcm)
  2850. +{
  2851. +   int err = 0;
  2852. +
  2853. +   err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  2854. +           NULL, 0, (unsigned long)intelhaddata,
  2855. +           &intelhaddata->chmap);
  2856. +   if (err < 0)
  2857. +       return err;
  2858. +
  2859. +   intelhaddata->chmap->private_data = intelhaddata;
  2860. +   intelhaddata->kctl = intelhaddata->chmap->kctl;
  2861. +   intelhaddata->kctl->info = had_chmap_ctl_info;
  2862. +   intelhaddata->kctl->get = had_chmap_ctl_get;
  2863. +   intelhaddata->kctl->put = had_chmap_ctl_put;
  2864. +#ifndef USE_ALSA_DEFAULT_TLV
  2865. +   intelhaddata->kctl->tlv.c = had_chmap_ctl_tlv;
  2866. +#endif
  2867. +   intelhaddata->chmap->chmap = NULL;
  2868. +   return 0;
  2869. +}
  2870. +
  2871. +/**
  2872. + * snd_intelhad_prog_dip_v1 - to initialize Data Island Packets registers
  2873. + *
  2874. + * @substream:substream for which the prepare function is called
  2875. + * @intelhaddata:substream private data
  2876. + *
  2877. + * This function is called in the prepare callback
  2878. + */
  2879. +static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream,
  2880. +               struct snd_intelhad *intelhaddata)
  2881. +{
  2882. +   int i;
  2883. +   union aud_ctrl_st ctrl_state = {.ctrl_val = 0};
  2884. +   union aud_info_frame2 frame2 = {.fr2_val = 0};
  2885. +   union aud_info_frame3 frame3 = {.fr3_val = 0};
  2886. +   u8 checksum = 0;
  2887. +   int channels;
  2888. +
  2889. +   channels = substream->runtime->channels;
  2890. +
  2891. +   had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
  2892. +
  2893. +   frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;
  2894. +
  2895. +   frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation(
  2896. +                   intelhaddata, channels);
  2897. +
  2898. +   /*Calculte the byte wide checksum for all valid DIP words*/
  2899. +   for (i = 0; i < BYTES_PER_WORD; i++)
  2900. +       checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
  2901. +   for (i = 0; i < BYTES_PER_WORD; i++)
  2902. +       checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
  2903. +   for (i = 0; i < BYTES_PER_WORD; i++)
  2904. +       checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
  2905. +
  2906. +   frame2.fr2_regx.chksum = -(checksum);
  2907. +
  2908. +   had_write_register(AUD_HDMIW_INFOFR, INFO_FRAME_WORD1);
  2909. +   had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val);
  2910. +   had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val);
  2911. +
  2912. +   /* program remaining DIP words with zero */
  2913. +   for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
  2914. +       had_write_register(AUD_HDMIW_INFOFR, 0x0);
  2915. +
  2916. +   ctrl_state.ctrl_regx.dip_freq = 1;
  2917. +   ctrl_state.ctrl_regx.dip_en_sta = 1;
  2918. +   had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
  2919. +}
  2920. +
  2921. +/**
  2922. + * snd_intelhad_prog_dip_v2 - to initialize Data Island Packets registers
  2923. + *
  2924. + * @substream:substream for which the prepare function is called
  2925. + * @intelhaddata:substream private data
  2926. + *
  2927. + * This function is called in the prepare callback
  2928. + */
  2929. +static void snd_intelhad_prog_dip_v2(struct snd_pcm_substream *substream,
  2930. +               struct snd_intelhad *intelhaddata)
  2931. +{
  2932. +   int i;
  2933. +   union aud_ctrl_st ctrl_state = {.ctrl_val = 0};
  2934. +   union aud_info_frame2 frame2 = {.fr2_val = 0};
  2935. +   union aud_info_frame3 frame3 = {.fr3_val = 0};
  2936. +   u8 checksum = 0;
  2937. +   int channels;
  2938. +
  2939. +   channels = substream->runtime->channels;
  2940. +
  2941. +   had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
  2942. +
  2943. +   frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1;
  2944. +
  2945. +   frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation(
  2946. +                   intelhaddata, channels);
  2947. +
  2948. +   /*Calculte the byte wide checksum for all valid DIP words*/
  2949. +   for (i = 0; i < BYTES_PER_WORD; i++)
  2950. +       checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0;
  2951. +   for (i = 0; i < BYTES_PER_WORD; i++)
  2952. +       checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
  2953. +   for (i = 0; i < BYTES_PER_WORD; i++)
  2954. +       checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0;
  2955. +
  2956. +   frame2.fr2_regx.chksum = -(checksum);
  2957. +
  2958. +   had_write_register(AUD_HDMIW_INFOFR_v2, INFO_FRAME_WORD1);
  2959. +   had_write_register(AUD_HDMIW_INFOFR_v2, frame2.fr2_val);
  2960. +   had_write_register(AUD_HDMIW_INFOFR_v2, frame3.fr3_val);
  2961. +
  2962. +   /* program remaining DIP words with zero */
  2963. +   for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
  2964. +       had_write_register(AUD_HDMIW_INFOFR_v2, 0x0);
  2965. +
  2966. +   ctrl_state.ctrl_regx.dip_freq = 1;
  2967. +   ctrl_state.ctrl_regx.dip_en_sta = 1;
  2968. +   had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val);
  2969. +}
  2970. +
  2971. +/**
  2972. + * snd_intelhad_prog_buffer - programs buffer
  2973. + * address and length registers
  2974. + *
  2975. + * @substream:substream for which the prepare function is called
  2976. + * @intelhaddata:substream private data
  2977. + *
  2978. + * This function programs ring buffer address and length into registers.
  2979. + */
  2980. +int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata,
  2981. +                   int start, int end)
  2982. +{
  2983. +   u32 ring_buf_addr, ring_buf_size, period_bytes;
  2984. +   u8 i, num_periods;
  2985. +   struct snd_pcm_substream *substream;
  2986. +
  2987. +   substream = intelhaddata->stream_info.had_substream;
  2988. +   if (!substream) {
  2989. +       pr_err("substream is NULL\n");
  2990. +       dump_stack();
  2991. +       return 0;
  2992. +   }
  2993. +
  2994. +   ring_buf_addr = substream->runtime->dma_addr;
  2995. +   ring_buf_size = snd_pcm_lib_buffer_bytes(substream);
  2996. +   intelhaddata->stream_info.ring_buf_size = ring_buf_size;
  2997. +   period_bytes = frames_to_bytes(substream->runtime,
  2998. +               substream->runtime->period_size);
  2999. +   num_periods = substream->runtime->periods;
  3000. +
  3001. +   /*
  3002. +    * buffer addr should  be 64 byte aligned, period bytes
  3003. +    * will be used to calculate addr offset
  3004. +    */
  3005. +   period_bytes &= ~0x3F;
  3006. +
  3007. +   /* Hardware supports MAX_PERIODS buffers */
  3008. +   if (end >= HAD_MAX_PERIODS)
  3009. +       return -EINVAL;
  3010. +
  3011. +   for (i = start; i <= end; i++) {
  3012. +       /* Program the buf registers with addr and len */
  3013. +       intelhaddata->buf_info[i].buf_addr = ring_buf_addr +
  3014. +                            (i * period_bytes);
  3015. +       if (i < num_periods-1)
  3016. +           intelhaddata->buf_info[i].buf_size = period_bytes;
  3017. +       else
  3018. +           intelhaddata->buf_info[i].buf_size = ring_buf_size -
  3019. +                           (period_bytes*i);
  3020. +
  3021. +       had_write_register(AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH),
  3022. +                   intelhaddata->buf_info[i].buf_addr |
  3023. +                   BIT(0) | BIT(1));
  3024. +       had_write_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
  3025. +                   period_bytes);
  3026. +       intelhaddata->buf_info[i].is_valid = true;
  3027. +   }
  3028. +   pr_debug("%s:buf[%d-%d] addr=%#x  and size=%d\n", __func__, start, end,
  3029. +           intelhaddata->buf_info[start].buf_addr,
  3030. +           intelhaddata->buf_info[start].buf_size);
  3031. +   intelhaddata->valid_buf_cnt = num_periods;
  3032. +   return 0;
  3033. +}
  3034. +
  3035. +inline int snd_intelhad_read_len(struct snd_intelhad *intelhaddata)
  3036. +{
  3037. +   int i, retval = 0;
  3038. +   u32 len[4];
  3039. +
  3040. +   for (i = 0; i < 4 ; i++) {
  3041. +       had_read_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH),
  3042. +                   &len[i]);
  3043. +       if (!len[i])
  3044. +           retval++;
  3045. +   }
  3046. +   if (retval != 1) {
  3047. +       for (i = 0; i < 4 ; i++)
  3048. +           pr_debug("buf[%d] size=%d\n", i, len[i]);
  3049. +   }
  3050. +
  3051. +   return retval;
  3052. +}
  3053. +
  3054. +/**
  3055. + * snd_intelhad_prog_cts_v1 - Program HDMI audio CTS value
  3056. + *
  3057. + * @aud_samp_freq: sampling frequency of audio data
  3058. + * @tmds: sampling frequency of the display data
  3059. + * @n_param: N value, depends on aud_samp_freq
  3060. + * @intelhaddata:substream private data
  3061. + *
  3062. + * Program CTS register based on the audio and display sampling frequency
  3063. + */
  3064. +static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param,
  3065. +               struct snd_intelhad *intelhaddata)
  3066. +{
  3067. +   u32 cts_val;
  3068. +   u64 dividend, divisor;
  3069. +
  3070. +   /* Calculate CTS according to HDMI 1.3a spec*/
  3071. +   dividend = (u64)tmds * n_param*1000;
  3072. +   divisor = 128 * aud_samp_freq;
  3073. +   cts_val = div64_u64(dividend, divisor);
  3074. +   pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n",
  3075. +           tmds, n_param, cts_val);
  3076. +   had_write_register(AUD_HDMI_CTS, (BIT(20) | cts_val));
  3077. +}
  3078. +
  3079. +/**
  3080. + * snd_intelhad_prog_cts_v2 - Program HDMI audio CTS value
  3081. + *
  3082. + * @aud_samp_freq: sampling frequency of audio data
  3083. + * @tmds: sampling frequency of the display data
  3084. + * @n_param: N value, depends on aud_samp_freq
  3085. + * @intelhaddata:substream private data
  3086. + *
  3087. + * Program CTS register based on the audio and display sampling frequency
  3088. + */
  3089. +static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, u32 n_param,
  3090. +               struct snd_intelhad *intelhaddata)
  3091. +{
  3092. +   u32 cts_val;
  3093. +   u64 dividend, divisor;
  3094. +
  3095. +   /* Calculate CTS according to HDMI 1.3a spec*/
  3096. +   dividend = (u64)tmds * n_param*1000;
  3097. +   divisor = 128 * aud_samp_freq;
  3098. +   cts_val = div64_u64(dividend, divisor);
  3099. +   pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n",
  3100. +           tmds, n_param, cts_val);
  3101. +   had_write_register(AUD_HDMI_CTS, (BIT(24) | cts_val));
  3102. +}
  3103. +
  3104. +static int had_calculate_n_value(u32 aud_samp_freq)
  3105. +{
  3106. +   s32 n_val;
  3107. +
  3108. +   /* Select N according to HDMI 1.3a spec*/
  3109. +   switch (aud_samp_freq) {
  3110. +   case AUD_SAMPLE_RATE_32:
  3111. +       n_val = 4096;
  3112. +   break;
  3113. +
  3114. +   case AUD_SAMPLE_RATE_44_1:
  3115. +       n_val = 6272;
  3116. +   break;
  3117. +
  3118. +   case AUD_SAMPLE_RATE_48:
  3119. +       n_val = 6144;
  3120. +   break;
  3121. +
  3122. +   case AUD_SAMPLE_RATE_88_2:
  3123. +       n_val = 12544;
  3124. +   break;
  3125. +
  3126. +   case AUD_SAMPLE_RATE_96:
  3127. +       n_val = 12288;
  3128. +   break;
  3129. +
  3130. +   case AUD_SAMPLE_RATE_176_4:
  3131. +       n_val = 25088;
  3132. +   break;
  3133. +
  3134. +   case HAD_MAX_RATE:
  3135. +       n_val = 24576;
  3136. +   break;
  3137. +
  3138. +   default:
  3139. +       n_val = -EINVAL;
  3140. +   break;
  3141. +   }
  3142. +   return n_val;
  3143. +}
  3144. +
  3145. +/**
  3146. + * snd_intelhad_prog_n_v1 - Program HDMI audio N value
  3147. + *
  3148. + * @aud_samp_freq: sampling frequency of audio data
  3149. + * @n_param: N value, depends on aud_samp_freq
  3150. + * @intelhaddata:substream private data
  3151. + *
  3152. + * This function is called in the prepare callback.
  3153. + * It programs based on the audio and display sampling frequency
  3154. + */
  3155. +static int snd_intelhad_prog_n_v1(u32 aud_samp_freq, u32 *n_param,
  3156. +               struct snd_intelhad *intelhaddata)
  3157. +{
  3158. +   s32 n_val;
  3159. +
  3160. +   n_val = had_calculate_n_value(aud_samp_freq);
  3161. +
  3162. +   if (n_val < 0)
  3163. +       return n_val;
  3164. +
  3165. +   had_write_register(AUD_N_ENABLE, (BIT(20) | n_val));
  3166. +   *n_param = n_val;
  3167. +   return 0;
  3168. +}
  3169. +
  3170. +/**
  3171. + * snd_intelhad_prog_n_v2 - Program HDMI audio N value
  3172. + *
  3173. + * @aud_samp_freq: sampling frequency of audio data
  3174. + * @n_param: N value, depends on aud_samp_freq
  3175. + * @intelhaddata:substream private data
  3176. + *
  3177. + * This function is called in the prepare callback.
  3178. + * It programs based on the audio and display sampling frequency
  3179. + */
  3180. +static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param,
  3181. +               struct snd_intelhad *intelhaddata)
  3182. +{
  3183. +   s32 n_val;
  3184. +
  3185. +   n_val = had_calculate_n_value(aud_samp_freq);
  3186. +
  3187. +   if (n_val < 0)
  3188. +       return n_val;
  3189. +
  3190. +   had_write_register(AUD_N_ENABLE, (BIT(24) | n_val));
  3191. +   *n_param = n_val;
  3192. +   return 0;
  3193. +}
  3194. +
  3195. +static void had_clear_underrun_intr_v1(struct snd_intelhad *intelhaddata)
  3196. +{
  3197. +   u32 hdmi_status, i = 0;
  3198. +
  3199. +   /* Handle Underrun interrupt within Audio Unit */
  3200. +   had_write_register(AUD_CONFIG, 0);
  3201. +   /* Reset buffer pointers */
  3202. +   had_write_register(AUD_HDMI_STATUS, 1);
  3203. +   had_write_register(AUD_HDMI_STATUS, 0);
  3204. +   /**
  3205. +    * The interrupt status 'sticky' bits might not be cleared by
  3206. +    * setting '1' to that bit once...
  3207. +    */
  3208. +   do { /* clear bit30, 31 AUD_HDMI_STATUS */
  3209. +       had_read_register(AUD_HDMI_STATUS, &hdmi_status);
  3210. +       pr_debug("HDMI status =0x%x\n", hdmi_status);
  3211. +       if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) {
  3212. +           i++;
  3213. +           hdmi_status &= (AUD_CONFIG_MASK_SRDBG |
  3214. +                   AUD_CONFIG_MASK_FUNCRST);
  3215. +           hdmi_status |= ~AUD_CONFIG_MASK_UNDERRUN;
  3216. +           had_write_register(AUD_HDMI_STATUS, hdmi_status);
  3217. +       } else
  3218. +           break;
  3219. +   } while (i < MAX_CNT);
  3220. +   if (i >= MAX_CNT)
  3221. +       pr_err("Unable to clear UNDERRUN bits\n");
  3222. +}
  3223. +
  3224. +static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata)
  3225. +{
  3226. +   u32 hdmi_status, i = 0;
  3227. +
  3228. +   /* Handle Underrun interrupt within Audio Unit */
  3229. +   had_write_register(AUD_CONFIG, 0);
  3230. +   /* Reset buffer pointers */
  3231. +   had_write_register(AUD_HDMI_STATUS_v2, 1);
  3232. +   had_write_register(AUD_HDMI_STATUS_v2, 0);
  3233. +   /**
  3234. +    * The interrupt status 'sticky' bits might not be cleared by
  3235. +    * setting '1' to that bit once...
  3236. +    */
  3237. +   do { /* clear bit30, 31 AUD_HDMI_STATUS */
  3238. +       had_read_register(AUD_HDMI_STATUS_v2, &hdmi_status);
  3239. +       pr_debug("HDMI status =0x%x\n", hdmi_status);
  3240. +       if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) {
  3241. +           i++;
  3242. +           hdmi_status &= ~AUD_CONFIG_MASK_UNDERRUN;
  3243. +           had_write_register(AUD_HDMI_STATUS_v2, hdmi_status);
  3244. +       } else
  3245. +           break;
  3246. +   } while (i < MAX_CNT);
  3247. +   if (i >= MAX_CNT)
  3248. +       pr_err("Unable to clear UNDERRUN bits\n");
  3249. +}
  3250. +
  3251. +/**
  3252. +* snd_intelhad_open - stream initializations are done here
  3253. +* @substream:substream for which the stream function is called
  3254. +*
  3255. +* This function is called whenever a PCM stream is opened
  3256. +*/
  3257. +static int snd_intelhad_open(struct snd_pcm_substream *substream)
  3258. +{
  3259. +   struct snd_intelhad *intelhaddata;
  3260. +   struct snd_pcm_runtime *runtime;
  3261. +   struct had_stream_pvt *stream;
  3262. +   struct had_pvt_data *had_stream;
  3263. +   int retval;
  3264. +
  3265. +   pr_debug("snd_intelhad_open called\n");
  3266. +   intelhaddata = snd_pcm_substream_chip(substream);
  3267. +   had_stream = intelhaddata->private_data;
  3268. +   runtime = substream->runtime;
  3269. +
  3270. +   pm_runtime_get(intelhaddata->dev);
  3271. +
  3272. +   /*
  3273. +    * HDMI driver might suspend the device already,
  3274. +    * so we return it on
  3275. +    */
  3276. +   if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
  3277. +           OSPM_UHB_FORCE_POWER_ON)) {
  3278. +       pr_err("HDMI device can't be turned on\n");
  3279. +       retval = -ENODEV;
  3280. +       goto exit_put_handle;
  3281. +   }
  3282. +
  3283. +   if (had_get_hwstate(intelhaddata)) {
  3284. +       pr_err("%s: HDMI cable plugged-out\n", __func__);
  3285. +       retval = -ENODEV;
  3286. +       goto exit_ospm_handle;
  3287. +   }
  3288. +
  3289. +   /* Check, if device already in use */
  3290. +   if (runtime->private_data) {
  3291. +       pr_err("Device already in use\n");
  3292. +       retval = -EBUSY;
  3293. +       goto exit_ospm_handle;
  3294. +   }
  3295. +
  3296. +   /* set the runtime hw parameter with local snd_pcm_hardware struct */
  3297. +   runtime->hw = snd_intel_hadstream;
  3298. +
  3299. +   stream = kzalloc(sizeof(*stream), GFP_KERNEL);
  3300. +   if (!stream) {
  3301. +       retval = -ENOMEM;
  3302. +       goto exit_ospm_handle;
  3303. +   }
  3304. +   stream->stream_status = STREAM_INIT;
  3305. +   runtime->private_data = stream;
  3306. +
  3307. +   retval = snd_pcm_hw_constraint_integer(runtime,
  3308. +            SNDRV_PCM_HW_PARAM_PERIODS);
  3309. +   if (retval < 0) {
  3310. +       goto exit_err;
  3311. +   }
  3312. +
  3313. +   /* Make sure, that the period size is always aligned
  3314. +    * 64byte boundary
  3315. +    */
  3316. +   retval = snd_pcm_hw_constraint_step(substream->runtime, 0,
  3317. +           SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
  3318. +   if (retval < 0) {
  3319. +       pr_err("%s:step_size=64 failed,err=%d\n", __func__, retval);
  3320. +       goto exit_err;
  3321. +   }
  3322. +
  3323. +   return retval;
  3324. +exit_err:
  3325. +   kfree(stream);
  3326. +exit_ospm_handle:
  3327. +   ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
  3328. +exit_put_handle:
  3329. +   pm_runtime_put(intelhaddata->dev);
  3330. +   runtime->private_data = NULL;
  3331. +   return retval;
  3332. +}
  3333. +
  3334. +/**
  3335. +* had_period_elapsed - updates the hardware pointer status
  3336. +* @had_substream:substream for which the stream function is called
  3337. +*
  3338. +*/
  3339. +static void had_period_elapsed(void *had_substream)
  3340. +{
  3341. +   struct snd_pcm_substream *substream = had_substream;
  3342. +   struct had_stream_pvt *stream;
  3343. +
  3344. +   /* pr_debug("had_period_elapsed called\n"); */
  3345. +
  3346. +   if (!substream || !substream->runtime)
  3347. +       return;
  3348. +   stream = substream->runtime->private_data;
  3349. +   if (!stream)
  3350. +       return;
  3351. +
  3352. +   if (stream->stream_status != STREAM_RUNNING)
  3353. +       return;
  3354. +   snd_pcm_period_elapsed(substream);
  3355. +}
  3356. +
  3357. +/**
  3358. +* snd_intelhad_init_stream - internal function to initialize stream info
  3359. +* @substream:substream for which the stream function is called
  3360. +*
  3361. +*/
  3362. +static int snd_intelhad_init_stream(struct snd_pcm_substream *substream)
  3363. +{
  3364. +   struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream);
  3365. +
  3366. +   pr_debug("snd_intelhad_init_stream called\n");
  3367. +
  3368. +   pr_debug("setting buffer ptr param\n");
  3369. +   intelhaddata->stream_info.period_elapsed = had_period_elapsed;
  3370. +   intelhaddata->stream_info.had_substream = substream;
  3371. +   intelhaddata->stream_info.buffer_ptr = 0;
  3372. +   intelhaddata->stream_info.buffer_rendered = 0;
  3373. +   intelhaddata->stream_info.sfreq = substream->runtime->rate;
  3374. +   return 0;
  3375. +}
  3376. +
  3377. +/**
  3378. + * snd_intelhad_close- to free parameteres when stream is stopped
  3379. + *
  3380. + * @substream:  substream for which the function is called
  3381. + *
  3382. + * This function is called by ALSA framework when stream is stopped
  3383. + */
  3384. +static int snd_intelhad_close(struct snd_pcm_substream *substream)
  3385. +{
  3386. +   struct snd_intelhad *intelhaddata;
  3387. +   struct snd_pcm_runtime *runtime;
  3388. +
  3389. +   pr_debug("snd_intelhad_close called\n");
  3390. +
  3391. +   intelhaddata = snd_pcm_substream_chip(substream);
  3392. +   runtime = substream->runtime;
  3393. +
  3394. +   if (!runtime->private_data) {
  3395. +       pr_debug("close() might have called after failed open");
  3396. +       return 0;
  3397. +   }
  3398. +
  3399. +   intelhaddata->stream_info.buffer_rendered = 0;
  3400. +   intelhaddata->stream_info.buffer_ptr = 0;
  3401. +   intelhaddata->stream_info.str_id = 0;
  3402. +   intelhaddata->stream_info.had_substream = NULL;
  3403. +
  3404. +   /* Check if following drv_status modification is required - VA */
  3405. +   if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED)
  3406. +       intelhaddata->drv_status = HAD_DRV_CONNECTED;
  3407. +   kfree(runtime->private_data);
  3408. +   runtime->private_data = NULL;
  3409. +   ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
  3410. +   pm_runtime_put(intelhaddata->dev);
  3411. +   return 0;
  3412. +}
  3413. +
  3414. +/**
  3415. + * snd_intelhad_hw_params- to setup the hardware parameters
  3416. + * like allocating the buffers
  3417. + *
  3418. + * @substream:  substream for which the function is called
  3419. + * @hw_params: hardware parameters
  3420. + *
  3421. + * This function is called by ALSA framework when hardware params are set
  3422. + */
  3423. +static int snd_intelhad_hw_params(struct snd_pcm_substream *substream,
  3424. +                   struct snd_pcm_hw_params *hw_params)
  3425. +{
  3426. +   unsigned long addr;
  3427. +   int pages, buf_size, retval;
  3428. +
  3429. +   pr_debug("snd_intelhad_hw_params called\n");
  3430. +
  3431. +   BUG_ON(!hw_params);
  3432. +
  3433. +   buf_size = params_buffer_bytes(hw_params);
  3434. +   retval = snd_pcm_lib_malloc_pages(substream, buf_size);
  3435. +   if (retval < 0)
  3436. +       return retval;
  3437. +   pr_debug("%s:allocated memory = %d\n", __func__, buf_size);
  3438. +   /* mark the pages as uncached region */
  3439. +   addr = (unsigned long) substream->runtime->dma_area;
  3440. +   pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
  3441. +   retval = set_memory_uc(addr, pages);
  3442. +   if (retval) {
  3443. +       pr_err("set_memory_uc failed.Error:%d\n", retval);
  3444. +       return retval;
  3445. +   }
  3446. +   memset(substream->runtime->dma_area, 0, buf_size);
  3447. +
  3448. +   return retval;
  3449. +}
  3450. +
  3451. +/**
  3452. + * snd_intelhad_hw_free- to release the resources allocated during
  3453. + * hardware params setup
  3454. + *
  3455. + * @substream:  substream for which the function is called
  3456. + *
  3457. + * This function is called by ALSA framework before close callback.
  3458. + *
  3459. + */
  3460. +static int snd_intelhad_hw_free(struct snd_pcm_substream *substream)
  3461. +{
  3462. +   unsigned long addr;
  3463. +   u32 pages;
  3464. +
  3465. +   pr_debug("snd_intelhad_hw_free called\n");
  3466. +
  3467. +   /* mark back the pages as cached/writeback region before the free */
  3468. +   if (substream->runtime->dma_area != NULL) {
  3469. +       addr = (unsigned long) substream->runtime->dma_area;
  3470. +       pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) /
  3471. +                               PAGE_SIZE;
  3472. +       set_memory_wb(addr, pages);
  3473. +       return snd_pcm_lib_free_pages(substream);
  3474. +   }
  3475. +   return 0;
  3476. +}
  3477. +
  3478. +/**
  3479. +* snd_intelhad_pcm_trigger - stream activities are handled here
  3480. +* @substream:substream for which the stream function is called
  3481. +* @cmd:the stream commamd thats requested from upper layer
  3482. +* This function is called whenever an a stream activity is invoked
  3483. +*/
  3484. +static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream,
  3485. +                   int cmd)
  3486. +{
  3487. +   int caps, retval = 0;
  3488. +   unsigned long flag_irq;
  3489. +   struct snd_intelhad *intelhaddata;
  3490. +   struct had_stream_pvt *stream;
  3491. +   struct had_pvt_data *had_stream;
  3492. +
  3493. +   pr_debug("snd_intelhad_pcm_trigger called\n");
  3494. +
  3495. +   intelhaddata = snd_pcm_substream_chip(substream);
  3496. +   stream = substream->runtime->private_data;
  3497. +   had_stream = intelhaddata->private_data;
  3498. +
  3499. +   switch (cmd) {
  3500. +   case SNDRV_PCM_TRIGGER_START:
  3501. +       pr_debug("Trigger Start\n");
  3502. +
  3503. +       /* Disable local INTRs till register prgmng is done */
  3504. +       if (had_get_hwstate(intelhaddata)) {
  3505. +           pr_err("_START: HDMI cable plugged-out\n");
  3506. +           retval = -ENODEV;
  3507. +           break;
  3508. +       }
  3509. +       stream->stream_status = STREAM_RUNNING;
  3510. +
  3511. +       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq);
  3512. +       had_stream->stream_type = HAD_RUNNING_STREAM;
  3513. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq);
  3514. +
  3515. +       /* Enable Audio */
  3516. +       /*
  3517. +        * ToDo: Need to enable UNDERRUN interrupts as well
  3518. +        *   caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
  3519. +        */
  3520. +       caps = HDMI_AUDIO_BUFFER_DONE;
  3521. +       retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps);
  3522. +       retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL);
  3523. +       intelhaddata->ops->enable_audio(substream, 1);
  3524. +
  3525. +       pr_debug("Processed _Start\n");
  3526. +
  3527. +       break;
  3528. +
  3529. +   case SNDRV_PCM_TRIGGER_STOP:
  3530. +       pr_debug("Trigger Stop\n");
  3531. +       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq);
  3532. +       intelhaddata->stream_info.str_id = 0;
  3533. +       intelhaddata->curr_buf = 0;
  3534. +
  3535. +       /* Stop reporting BUFFER_DONE/UNDERRUN to above layers*/
  3536. +
  3537. +       had_stream->stream_type = HAD_INIT;
  3538. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq);
  3539. +       /* Disable Audio */
  3540. +       /*
  3541. +        * ToDo: Need to disable UNDERRUN interrupts as well
  3542. +        *   caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
  3543. +        */
  3544. +       caps = HDMI_AUDIO_BUFFER_DONE;
  3545. +       had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps);
  3546. +       intelhaddata->ops->enable_audio(substream, 0);
  3547. +       /* Reset buffer pointers */
  3548. +       intelhaddata->ops->reset_audio(1);
  3549. +       intelhaddata->ops->reset_audio(0);
  3550. +       stream->stream_status = STREAM_DROPPED;
  3551. +       had_set_caps(HAD_SET_DISABLE_AUDIO, NULL);
  3552. +       break;
  3553. +
  3554. +   default:
  3555. +       retval = -EINVAL;
  3556. +   }
  3557. +   return retval;
  3558. +}
  3559. +
  3560. +/**
  3561. +* snd_intelhad_pcm_prepare- internal preparation before starting a stream
  3562. +*
  3563. +* @substream:  substream for which the function is called
  3564. +*
  3565. +* This function is called when a stream is started for internal preparation.
  3566. +*/
  3567. +static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
  3568. +{
  3569. +   int retval;
  3570. +   u32 disp_samp_freq, n_param;
  3571. +   struct snd_intelhad *intelhaddata;
  3572. +   struct snd_pcm_runtime *runtime;
  3573. +   struct had_pvt_data *had_stream;
  3574. +
  3575. +   pr_debug("snd_intelhad_pcm_prepare called\n");
  3576. +
  3577. +   intelhaddata = snd_pcm_substream_chip(substream);
  3578. +   runtime = substream->runtime;
  3579. +   had_stream = intelhaddata->private_data;
  3580. +
  3581. +   if (had_get_hwstate(intelhaddata)) {
  3582. +       pr_err("%s: HDMI cable plugged-out\n", __func__);
  3583. +       snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
  3584. +       retval = -ENODEV;
  3585. +       goto prep_end;
  3586. +   }
  3587. +
  3588. +   pr_debug("period_size=%d\n",
  3589. +               frames_to_bytes(runtime, runtime->period_size));
  3590. +   pr_debug("periods=%d\n", runtime->periods);
  3591. +   pr_debug("buffer_size=%d\n", snd_pcm_lib_buffer_bytes(substream));
  3592. +   pr_debug("rate=%d\n", runtime->rate);
  3593. +   pr_debug("channels=%d\n", runtime->channels);
  3594. +
  3595. +   if (intelhaddata->stream_info.str_id) {
  3596. +       pr_debug("_prepare is called for existing str_id#%d\n",
  3597. +                   intelhaddata->stream_info.str_id);
  3598. +       retval = snd_intelhad_pcm_trigger(substream,
  3599. +                       SNDRV_PCM_TRIGGER_STOP);
  3600. +       return retval;
  3601. +   }
  3602. +
  3603. +   retval = snd_intelhad_init_stream(substream);
  3604. +   if (retval)
  3605. +       goto prep_end;
  3606. +
  3607. +
  3608. +   /* Get N value in KHz */
  3609. +   retval = had_get_caps(HAD_GET_SAMPLING_FREQ, &disp_samp_freq);
  3610. +   if (retval) {
  3611. +       pr_err("querying display sampling freq failed %#x\n", retval);
  3612. +       goto prep_end;
  3613. +   }
  3614. +
  3615. +   had_get_caps(HAD_GET_ELD, &intelhaddata->eeld);
  3616. +
  3617. +   retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param,
  3618. +                               intelhaddata);
  3619. +   if (retval) {
  3620. +       pr_err("programming N value failed %#x\n", retval);
  3621. +       goto prep_end;
  3622. +   }
  3623. +   intelhaddata->ops->prog_cts(substream->runtime->rate,
  3624. +                   disp_samp_freq, n_param, intelhaddata);
  3625. +
  3626. +   intelhaddata->ops->prog_dip(substream, intelhaddata);
  3627. +
  3628. +   retval = intelhaddata->ops->audio_ctrl(substream, intelhaddata);
  3629. +
  3630. +   /* Prog buffer address */
  3631. +   retval = snd_intelhad_prog_buffer(intelhaddata,
  3632. +           HAD_BUF_TYPE_A, HAD_BUF_TYPE_D);
  3633. +
  3634. +   /*
  3635. +    * Program channel mapping in following order:
  3636. +    * FL, FR, C, LFE, RL, RR
  3637. +    */
  3638. +
  3639. +   had_write_register(AUD_BUF_CH_SWAP, SWAP_LFE_CENTER);
  3640. +
  3641. +prep_end:
  3642. +   return retval;
  3643. +}
  3644. +
  3645. +/**
  3646. + * snd_intelhad_pcm_pointer- to send the current buffer pointerprocessed by hw
  3647. + *
  3648. + * @substream:  substream for which the function is called
  3649. + *
  3650. + * This function is called by ALSA framework to get the current hw buffer ptr
  3651. + * when a period is elapsed
  3652. + */
  3653. +static snd_pcm_uframes_t snd_intelhad_pcm_pointer(
  3654. +                   struct snd_pcm_substream *substream)
  3655. +{
  3656. +   struct snd_intelhad *intelhaddata;
  3657. +   u32 bytes_rendered = 0;
  3658. +
  3659. +   /* pr_debug("snd_intelhad_pcm_pointer called\n"); */
  3660. +
  3661. +   intelhaddata = snd_pcm_substream_chip(substream);
  3662. +
  3663. +   if (intelhaddata->flag_underrun) {
  3664. +       intelhaddata->flag_underrun = 0;
  3665. +       return SNDRV_PCM_POS_XRUN;
  3666. +   }
  3667. +
  3668. +   if (intelhaddata->stream_info.buffer_rendered)
  3669. +       div_u64_rem(intelhaddata->stream_info.buffer_rendered,
  3670. +           intelhaddata->stream_info.ring_buf_size,
  3671. +           &(bytes_rendered));
  3672. +
  3673. +   intelhaddata->stream_info.buffer_ptr = bytes_to_frames(
  3674. +                       substream->runtime,
  3675. +                       bytes_rendered);
  3676. +   return intelhaddata->stream_info.buffer_ptr;
  3677. +}
  3678. +
  3679. +/**
  3680. +* snd_intelhad_pcm_mmap- mmaps a kernel buffer to user space for copying data
  3681. +*
  3682. +* @substream:  substream for which the function is called
  3683. +* @vma:        struct instance of memory VMM memory area
  3684. +*
  3685. +* This function is called by OS when a user space component
  3686. +* tries to get mmap memory from driver
  3687. +*/
  3688. +static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream,
  3689. +   struct vm_area_struct *vma)
  3690. +{
  3691. +
  3692. +   pr_debug("snd_intelhad_pcm_mmap called\n");
  3693. +
  3694. +   pr_debug("entry with prot:%s\n", __func__);
  3695. +   vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  3696. +   return remap_pfn_range(vma, vma->vm_start,
  3697. +           substream->dma_buffer.addr >> PAGE_SHIFT,
  3698. +           vma->vm_end - vma->vm_start, vma->vm_page_prot);
  3699. +}
  3700. +
  3701. +int hdmi_audio_mode_change(struct snd_pcm_substream *substream)
  3702. +{
  3703. +   int retval = 0;
  3704. +   u32 disp_samp_freq, n_param;
  3705. +   struct snd_intelhad *intelhaddata;
  3706. +
  3707. +   intelhaddata = snd_pcm_substream_chip(substream);
  3708. +
  3709. +   /* Disable Audio */
  3710. +   intelhaddata->ops->enable_audio(substream, 0);
  3711. +
  3712. +   /* Update CTS value */
  3713. +   retval = had_get_caps(HAD_GET_SAMPLING_FREQ, &disp_samp_freq);
  3714. +   if (retval) {
  3715. +       pr_err("querying display sampling freq failed %#x\n", retval);
  3716. +       goto out;
  3717. +   }
  3718. +
  3719. +   retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param,
  3720. +                               intelhaddata);
  3721. +   if (retval) {
  3722. +       pr_err("programming N value failed %#x\n", retval);
  3723. +       goto out;
  3724. +   }
  3725. +   intelhaddata->ops->prog_cts(substream->runtime->rate,
  3726. +                   disp_samp_freq, n_param, intelhaddata);
  3727. +
  3728. +   /* Enable Audio */
  3729. +   intelhaddata->ops->enable_audio(substream, 1);
  3730. +
  3731. +out:
  3732. +   return retval;
  3733. +}
  3734. +
  3735. +/*PCM operations structure and the calls back for the same */
  3736. +struct snd_pcm_ops snd_intelhad_playback_ops = {
  3737. +   .open =     snd_intelhad_open,
  3738. +   .close =    snd_intelhad_close,
  3739. +   .ioctl =    snd_pcm_lib_ioctl,
  3740. +   .hw_params =    snd_intelhad_hw_params,
  3741. +   .hw_free =  snd_intelhad_hw_free,
  3742. +   .prepare =  snd_intelhad_pcm_prepare,
  3743. +   .trigger =  snd_intelhad_pcm_trigger,
  3744. +   .pointer =  snd_intelhad_pcm_pointer,
  3745. +   .mmap = snd_intelhad_pcm_mmap,
  3746. +};
  3747. +
  3748. +/**
  3749. + * snd_intelhad_create - to crete alsa card instance
  3750. + *
  3751. + * @intelhaddata: pointer to internal context
  3752. + * @card: pointer to card
  3753. + *
  3754. + * This function is called when the hdmi cable is plugged in
  3755. + */
  3756. +static int snd_intelhad_create(
  3757. +       struct snd_intelhad *intelhaddata,
  3758. +       struct snd_card *card)
  3759. +{
  3760. +   int retval;
  3761. +   static struct snd_device_ops ops = {
  3762. +   };
  3763. +
  3764. +   BUG_ON(!intelhaddata);
  3765. +   /* ALSA api to register the device */
  3766. +   retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelhaddata, &ops);
  3767. +   return retval;
  3768. +}
  3769. +/**
  3770. + * snd_intelhad_pcm_free - to free the memory allocated
  3771. + *
  3772. + * @pcm: pointer to pcm instance
  3773. + * This function is called when the device is removed
  3774. + */
  3775. +static void snd_intelhad_pcm_free(struct snd_pcm *pcm)
  3776. +{
  3777. +   pr_debug("Freeing PCM preallocated pages\n");
  3778. +   snd_pcm_lib_preallocate_free_for_all(pcm);
  3779. +}
  3780. +
  3781. +static int had_iec958_info(struct snd_kcontrol *kcontrol,
  3782. +               struct snd_ctl_elem_info *uinfo)
  3783. +{
  3784. +   uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
  3785. +   uinfo->count = 1;
  3786. +   return 0;
  3787. +}
  3788. +
  3789. +static int had_iec958_get(struct snd_kcontrol *kcontrol,
  3790. +               struct snd_ctl_elem_value *ucontrol)
  3791. +{
  3792. +   struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
  3793. +
  3794. +   ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff;
  3795. +   ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff;
  3796. +   ucontrol->value.iec958.status[2] =
  3797. +                   (intelhaddata->aes_bits >> 16) & 0xff;
  3798. +   ucontrol->value.iec958.status[3] =
  3799. +                   (intelhaddata->aes_bits >> 24) & 0xff;
  3800. +   return 0;
  3801. +}
  3802. +static int had_iec958_mask_get(struct snd_kcontrol *kcontrol,
  3803. +               struct snd_ctl_elem_value *ucontrol)
  3804. +{
  3805. +   ucontrol->value.iec958.status[0] = 0xff;
  3806. +   ucontrol->value.iec958.status[1] = 0xff;
  3807. +   ucontrol->value.iec958.status[2] = 0xff;
  3808. +   ucontrol->value.iec958.status[3] = 0xff;
  3809. +   return 0;
  3810. +}
  3811. +static int had_iec958_put(struct snd_kcontrol *kcontrol,
  3812. +               struct snd_ctl_elem_value *ucontrol)
  3813. +{
  3814. +   unsigned int val;
  3815. +   struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
  3816. +
  3817. +   pr_debug("entered had_iec958_put\n");
  3818. +   val = (ucontrol->value.iec958.status[0] << 0) |
  3819. +       (ucontrol->value.iec958.status[1] << 8) |
  3820. +       (ucontrol->value.iec958.status[2] << 16) |
  3821. +       (ucontrol->value.iec958.status[3] << 24);
  3822. +   if (intelhaddata->aes_bits != val) {
  3823. +       intelhaddata->aes_bits = val;
  3824. +       return 1;
  3825. +   }
  3826. +   return 1;
  3827. +}
  3828. +
  3829. +static struct snd_kcontrol_new had_control_iec958_mask = {
  3830. +   .access =   SNDRV_CTL_ELEM_ACCESS_READ,
  3831. +   .iface =    SNDRV_CTL_ELEM_IFACE_PCM,
  3832. +   .name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
  3833. +   .info =     had_iec958_info, /* shared */
  3834. +   .get =      had_iec958_mask_get,
  3835. +};
  3836. +
  3837. +static struct snd_kcontrol_new had_control_iec958 = {
  3838. +   .iface =    SNDRV_CTL_ELEM_IFACE_PCM,
  3839. +   .name =         SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
  3840. +   .info =         had_iec958_info,
  3841. +   .get =          had_iec958_get,
  3842. +   .put =          had_iec958_put
  3843. +};
  3844. +
  3845. +static struct snd_intel_had_interface had_interface = {
  3846. +   .name =         "hdmi-audio",
  3847. +   .query =        hdmi_audio_query,
  3848. +   .suspend =      hdmi_audio_suspend,
  3849. +   .resume =       hdmi_audio_resume,
  3850. +};
  3851. +
  3852. +static struct had_ops had_ops_v1 = {
  3853. +   .enable_audio = snd_intelhad_enable_audio_v1,
  3854. +   .reset_audio = snd_intelhad_reset_audio_v1,
  3855. +   .prog_n =   snd_intelhad_prog_n_v1,
  3856. +   .prog_cts = snd_intelhad_prog_cts_v1,
  3857. +   .audio_ctrl =   snd_intelhad_prog_audio_ctrl_v1,
  3858. +   .prog_dip = snd_intelhad_prog_dip_v1,
  3859. +   .handle_underrun =  had_clear_underrun_intr_v1,
  3860. +};
  3861. +
  3862. +static struct had_ops had_ops_v2 = {
  3863. +   .enable_audio = snd_intelhad_enable_audio_v2,
  3864. +   .reset_audio = snd_intelhad_reset_audio_v2,
  3865. +   .prog_n =   snd_intelhad_prog_n_v2,
  3866. +   .prog_cts = snd_intelhad_prog_cts_v2,
  3867. +   .audio_ctrl =   snd_intelhad_prog_audio_ctrl_v2,
  3868. +   .prog_dip = snd_intelhad_prog_dip_v2,
  3869. +   .handle_underrun = had_clear_underrun_intr_v2,
  3870. +};
  3871. +/**
  3872. + * hdmi_audio_probe - to create sound card instance for HDMI audio playabck
  3873. + *
  3874. + *@haddata: pointer to HAD private data
  3875. + *@card_id: card for which probe is called
  3876. + *
  3877. + * This function is called when the hdmi cable is plugged in. This function
  3878. + * creates and registers the sound card with ALSA
  3879. + */
  3880. +static int hdmi_audio_probe(struct platform_device *devptr)
  3881. +{
  3882. +
  3883. +   int retval;
  3884. +   struct snd_pcm *pcm;
  3885. +   struct snd_card *card;
  3886. +   struct had_callback_ops ops_cb;
  3887. +   struct snd_intelhad *intelhaddata;
  3888. +   struct had_pvt_data *had_stream;
  3889. +
  3890. +   pr_debug("Enter %s\n", __func__);
  3891. +
  3892. +   pr_debug("hdmi_audio_probe dma_mask: %d\n", devptr->dev.dma_mask);
  3893. +
  3894. +   /* allocate memory for saving internal context and working */
  3895. +   intelhaddata = kzalloc(sizeof(*intelhaddata), GFP_KERNEL);
  3896. +   if (!intelhaddata) {
  3897. +       pr_err("mem alloc failed\n");
  3898. +       return -ENOMEM;
  3899. +   }
  3900. +
  3901. +   had_stream = kzalloc(sizeof(*had_stream), GFP_KERNEL);
  3902. +   if (!had_stream) {
  3903. +       pr_err("mem alloc failed\n");
  3904. +       retval = -ENOMEM;
  3905. +       goto free_haddata;
  3906. +   }
  3907. +
  3908. +   had_data = intelhaddata;
  3909. +   ops_cb.intel_had_event_call_back = had_event_handler;
  3910. +
  3911. +   /* registering with display driver to get access to display APIs */
  3912. +
  3913. +   retval = mid_hdmi_audio_setup(
  3914. +           ops_cb.intel_had_event_call_back,
  3915. +           &(intelhaddata->reg_ops),
  3916. +           &(intelhaddata->query_ops));
  3917. +   if (retval) {
  3918. +       pr_err("querying display driver APIs failed %#x\n", retval);
  3919. +       goto free_hadstream;
  3920. +   }
  3921. +   mutex_lock(&had_mutex);
  3922. +   spin_lock_init(&intelhaddata->had_spinlock);
  3923. +   intelhaddata->drv_status = HAD_DRV_DISCONNECTED;
  3924. +   /* create a card instance with ALSA framework */
  3925. +   retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id,
  3926. +               THIS_MODULE, 0, &card);
  3927. +
  3928. +   if (retval)
  3929. +       goto unlock_mutex;
  3930. +   intelhaddata->card = card;
  3931. +   intelhaddata->card_id = hdmi_card_id;
  3932. +   intelhaddata->card_index = card->number;
  3933. +   intelhaddata->private_data = had_stream;
  3934. +   intelhaddata->flag_underrun = 0;
  3935. +   intelhaddata->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
  3936. +   strncpy(card->driver, INTEL_HAD, strlen(INTEL_HAD));
  3937. +   strncpy(card->shortname, INTEL_HAD, strlen(INTEL_HAD));
  3938. +
  3939. +   retval = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
  3940. +                       MAX_CAP_STREAMS, &pcm);
  3941. +   if (retval)
  3942. +       goto err;
  3943. +
  3944. +   /* setup private data which can be retrieved when required */
  3945. +   pcm->private_data = intelhaddata;
  3946. +   pcm->private_free = snd_intelhad_pcm_free;
  3947. +   pcm->info_flags = 0;
  3948. +   strncpy(pcm->name, card->shortname, strlen(card->shortname));
  3949. +   /* setup the ops for palyabck */
  3950. +   snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
  3951. +               &snd_intelhad_playback_ops);
  3952. +   /* allocate dma pages for ALSA stream operations
  3953. +    * memory allocated is based on size, not max value
  3954. +    * thus using same argument for max & size
  3955. +    */
  3956. +   retval = snd_pcm_lib_preallocate_pages_for_all(pcm,
  3957. +           SNDRV_DMA_TYPE_DEV, NULL,
  3958. +           HAD_MAX_BUFFER, HAD_MAX_BUFFER);
  3959. +
  3960. +   if (card->dev == NULL)
  3961. +       pr_debug("card->dev is NULL!!!!! Should not be this case\n");
  3962. +   else if (card->dev->dma_mask == NULL)
  3963. +       pr_debug("hdmi_audio_probe dma_mask is NULL!!!!!\n");
  3964. +   else
  3965. +       pr_debug("hdmi_audio_probe dma_mask is : %d\n", card->dev->dma_mask);
  3966. +
  3967. +   if (retval)
  3968. +       goto err;
  3969. +
  3970. +   /* internal function call to register device with ALSA */
  3971. +   retval = snd_intelhad_create(intelhaddata, card);
  3972. +   if (retval)
  3973. +       goto err;
  3974. +
  3975. +   card->private_data = &intelhaddata;
  3976. +   retval = snd_card_register(card);
  3977. +   if (retval)
  3978. +       goto err;
  3979. +
  3980. +   /* IEC958 controls */
  3981. +   retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask,
  3982. +                       intelhaddata));
  3983. +   if (retval < 0)
  3984. +       goto err;
  3985. +   retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958,
  3986. +                       intelhaddata));
  3987. +   if (retval < 0)
  3988. +       goto err;
  3989. +
  3990. +   init_channel_allocations();
  3991. +
  3992. +   /* Register channel map controls */
  3993. +   retval = had_register_chmap_ctls(intelhaddata, pcm);
  3994. +   if (retval < 0)
  3995. +       goto err;
  3996. +
  3997. +   intelhaddata->dev = &devptr->dev;
  3998. +   pm_runtime_set_active(intelhaddata->dev);
  3999. +   pm_runtime_enable(intelhaddata->dev);
  4000. +
  4001. +   mutex_unlock(&had_mutex);
  4002. +   retval = mid_hdmi_audio_register(&had_interface, intelhaddata);
  4003. +   if (retval) {
  4004. +       pr_err("registering with display driver failed %#x\n", retval);
  4005. +       snd_card_free(card);
  4006. +       goto free_hadstream;
  4007. +   }
  4008. +
  4009. +   intelhaddata->hw_silence = 1;
  4010. +   intelhaddata->ops = &had_ops_v2;
  4011. +
  4012. +   return retval;
  4013. +err:
  4014. +   snd_card_free(card);
  4015. +unlock_mutex:
  4016. +   mutex_unlock(&had_mutex);
  4017. +free_hadstream:
  4018. +   kfree(had_stream);
  4019. +   pm_runtime_disable(intelhaddata->dev);
  4020. +   intelhaddata->dev = NULL;
  4021. +free_haddata:
  4022. +   kfree(intelhaddata);
  4023. +   intelhaddata = NULL;
  4024. +   pr_err("Error returned from %s api %#x\n", __func__, retval);
  4025. +   return retval;
  4026. +}
  4027. +
  4028. +/**
  4029. + * hdmi_audio_remove - removes the alsa card
  4030. + *
  4031. + *@haddata: pointer to HAD private data
  4032. + *
  4033. + * This function is called when the hdmi cable is un-plugged. This function
  4034. + * free the sound card.
  4035. + */
  4036. +static int hdmi_audio_remove(struct platform_device *devptr)
  4037. +{
  4038. +   struct snd_intelhad *intelhaddata = had_data;
  4039. +   int caps;
  4040. +
  4041. +   pr_debug("Enter %s\n", __func__);
  4042. +
  4043. +   if (!intelhaddata)
  4044. +       return 0;
  4045. +
  4046. +   if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) {
  4047. +       caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
  4048. +       had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps);
  4049. +       had_set_caps(HAD_SET_DISABLE_AUDIO, NULL);
  4050. +   }
  4051. +   snd_card_free(intelhaddata->card);
  4052. +   kfree(intelhaddata->private_data);
  4053. +   kfree(intelhaddata);
  4054. +   return 0;
  4055. +}
  4056. +
  4057. +static int had_pm_runtime_suspend(struct device *dev)
  4058. +{
  4059. +   return 0;
  4060. +}
  4061. +
  4062. +static int had_pm_runtime_resume(struct device *dev)
  4063. +{
  4064. +   return 0;
  4065. +}
  4066. +
  4067. +static int had_pm_runtime_idle(struct device *dev)
  4068. +{
  4069. +   return pm_schedule_suspend(dev, HAD_SUSPEND_DELAY);
  4070. +}
  4071. +
  4072. +const struct dev_pm_ops had_pm_ops = {
  4073. +   .runtime_idle = had_pm_runtime_idle,
  4074. +   .runtime_suspend = had_pm_runtime_suspend,
  4075. +   .runtime_resume = had_pm_runtime_resume,
  4076. +};
  4077. +
  4078. +static const struct acpi_device_id had_acpi_ids[] = {
  4079. +   { "HAD0F28", 0 },
  4080. +   { "HAD022A8", 0 },
  4081. +   {},
  4082. +};
  4083. +MODULE_DEVICE_TABLE(acpi, had_acpi_ids);
  4084. +
  4085. +static struct platform_driver had_driver = {
  4086. +   .probe =        hdmi_audio_probe,
  4087. +   .remove     = hdmi_audio_remove,
  4088. +   .suspend =      NULL,
  4089. +   .resume =       NULL,
  4090. +   .driver     = {
  4091. +       .name   = HDMI_AUDIO_DRIVER,
  4092. +#ifdef CONFIG_PM
  4093. +       .pm = &had_pm_ops,
  4094. +#endif
  4095. +       .acpi_match_table = ACPI_PTR(had_acpi_ids),
  4096. +   },
  4097. +};
  4098. +
  4099. +/*
  4100. +* alsa_card_intelhad_init- driver init function
  4101. +* This function is called when driver module is inserted
  4102. +*/
  4103. +static int __init alsa_card_intelhad_init(void)
  4104. +{
  4105. +   int retval;
  4106. +
  4107. +   pr_debug("Enter %s\n", __func__);
  4108. +
  4109. +   pr_info("******** HAD DRIVER loading.. Ver: %s\n",
  4110. +                   HAD_DRIVER_VERSION);
  4111. +
  4112. +   retval = platform_driver_register(&had_driver);
  4113. +   if (retval < 0) {
  4114. +       pr_err("Platform driver register failed\n");
  4115. +       return retval;
  4116. +   }
  4117. +
  4118. +   pr_debug("init complete\n");
  4119. +   return retval;
  4120. +}
  4121. +
  4122. +/**
  4123. +* alsa_card_intelhad_exit- driver exit function
  4124. +* This function is called when driver module is removed
  4125. +*/
  4126. +static void __exit alsa_card_intelhad_exit(void)
  4127. +{
  4128. +   pr_debug("had_exit called\n");
  4129. +   platform_driver_unregister(&had_driver);
  4130. +}
  4131. +late_initcall(alsa_card_intelhad_init);
  4132. +module_exit(alsa_card_intelhad_exit);
  4133. diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.h b/sound/hdmi_audio/intel_mid_hdmi_audio.h
  4134. new file mode 100644
  4135. index 0000000..7c54b97
  4136. --- /dev/null
  4137. +++ b/sound/hdmi_audio/intel_mid_hdmi_audio.h
  4138. @@ -0,0 +1,740 @@
  4139. +/*
  4140. + *   intel_mid_hdmi_audio.h - Intel HDMI audio driver for MID
  4141. + *
  4142. + *  Copyright (C) 2010 Intel Corp
  4143. + *  Authors:   Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
  4144. + *     Ramesh Babu K V <ramesh.babu@intel.com>
  4145. + *     Vaibhav Agarwal <vaibhav.agarwal@intel.com>
  4146. + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4147. + *
  4148. + *  This program is free software; you can redistribute it and/or modify
  4149. + *  it under the terms of the GNU General Public License as published by
  4150. + *  the Free Software Foundation; version 2 of the License.
  4151. + *
  4152. + *  This program is distributed in the hope that it will be useful, but
  4153. + *  WITHOUT ANY WARRANTY; without even the implied warranty of
  4154. + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  4155. + *  General Public License for more details.
  4156. + *
  4157. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4158. + * ALSA driver for Intel MID HDMI audio controller
  4159. + */
  4160. +#ifndef __INTEL_MID_HDMI_AUDIO_H
  4161. +#define __INTEL_MID_HDMI_AUDIO_H
  4162. +
  4163. +#include <linux/types.h>
  4164. +#include <sound/initval.h>
  4165. +#include <linux/version.h>
  4166. +#include <linux/pm_runtime.h>
  4167. +#include <sound/asoundef.h>
  4168. +#include <sound/control.h>
  4169. +#include <sound/pcm.h>
  4170. +#include <hdmi_audio_if.h>
  4171. +
  4172. +#define OSPM_DISPLAY_ISLAND    0x40
  4173. +
  4174. +typedef enum _UHBUsage {
  4175. +   OSPM_UHB_ONLY_IF_ON = 0,
  4176. +   OSPM_UHB_FORCE_POWER_ON,
  4177. +} UHBUsage;
  4178. +
  4179. +bool ospm_power_using_hw_begin(int hw_island, UHBUsage usage);
  4180. +void ospm_power_using_hw_end(int hw_island);
  4181. +
  4182. +/*
  4183. + * Use this function to do an instantaneous check for if the hw is on.
  4184. + * Only use this in cases where you know the g_state_change_mutex
  4185. + * is already held such as in irq install/uninstall and you need to
  4186. + * prevent a deadlock situation.  Otherwise use ospm_power_using_hw_begin().
  4187. + */
  4188. +bool ospm_power_is_hw_on(int hw_islands);
  4189. +
  4190. +#define HAD_DRIVER_VERSION "0.01.003"
  4191. +#define HAD_MAX_DEVICES        1
  4192. +#define HAD_MIN_CHANNEL        2
  4193. +#define HAD_MAX_CHANNEL        8
  4194. +#define HAD_NUM_OF_RING_BUFS   4
  4195. +
  4196. +/* Assume 192KHz, 8channel, 25msec period */
  4197. +#define HAD_MAX_BUFFER     (600*1024)
  4198. +#define HAD_MIN_BUFFER     (32*1024)
  4199. +#define HAD_MAX_PERIODS        4
  4200. +#define HAD_MIN_PERIODS        4
  4201. +#define HAD_MAX_PERIOD_BYTES   (HAD_MAX_BUFFER/HAD_MIN_PERIODS)
  4202. +#define HAD_MIN_PERIOD_BYTES   256
  4203. +#define HAD_FIFO_SIZE      0 /* fifo not being used */
  4204. +#define MAX_SPEAKERS       8
  4205. +/* TODO: Add own tlv when channel map is ported for user space */
  4206. +#define USE_ALSA_DEFAULT_TLV
  4207. +
  4208. +#define AUD_SAMPLE_RATE_32 32000
  4209. +#define AUD_SAMPLE_RATE_44_1   44100
  4210. +#define AUD_SAMPLE_RATE_48 48000
  4211. +#define AUD_SAMPLE_RATE_88_2   88200
  4212. +#define AUD_SAMPLE_RATE_96 96000
  4213. +#define AUD_SAMPLE_RATE_176_4  176400
  4214. +#define AUD_SAMPLE_RATE_192    192000
  4215. +
  4216. +#define HAD_MIN_RATE       AUD_SAMPLE_RATE_32
  4217. +#define HAD_MAX_RATE       AUD_SAMPLE_RATE_192
  4218. +
  4219. +#define DRIVER_NAME        "intelmid_hdmi_audio"
  4220. +#define DIS_SAMPLE_RATE_25_2   25200
  4221. +#define DIS_SAMPLE_RATE_27 27000
  4222. +#define DIS_SAMPLE_RATE_54 54000
  4223. +#define DIS_SAMPLE_RATE_74_25  74250
  4224. +#define DIS_SAMPLE_RATE_148_5  148500
  4225. +#define HAD_REG_WIDTH      0x08
  4226. +#define HAD_MAX_HW_BUFS        0x04
  4227. +#define HAD_MAX_DIP_WORDS      16
  4228. +#define INTEL_HAD      "IntelHDMI"
  4229. +
  4230. +/* _AUD_CONFIG register MASK */
  4231. +#define AUD_CONFIG_MASK_UNDERRUN   0xC0000000
  4232. +#define AUD_CONFIG_MASK_SRDBG      0x00000002
  4233. +#define AUD_CONFIG_MASK_FUNCRST        0x00000001
  4234. +
  4235. +#define MAX_CNT            0xFF
  4236. +#define HAD_SUSPEND_DELAY  1000
  4237. +
  4238. +#define OTM_HDMI_ELD_SIZE 84
  4239. +
  4240. +typedef union {
  4241. +   uint8_t eld_data[OTM_HDMI_ELD_SIZE];
  4242. +   #pragma pack(1)
  4243. +   struct {
  4244. +       /* Byte[0] = ELD Version Number */
  4245. +       union {
  4246. +           uint8_t   byte0;
  4247. +           struct {
  4248. +               uint8_t reserved:3; /* Reserf */
  4249. +               uint8_t eld_ver:5; /* ELD Version Number */
  4250. +                       /* 00000b - reserved
  4251. +                        * 00001b - first rev, obsoleted
  4252. +                        * 00010b - version 2, supporting CEA version 861D or below
  4253. +                        * 00011b:11111b - reserved
  4254. +                        * for future
  4255. +                        */
  4256. +           };
  4257. +       };
  4258. +
  4259. +       /* Byte[1] = Vendor Version Field */
  4260. +       union {
  4261. +           uint8_t vendor_version;
  4262. +           struct {
  4263. +               uint8_t reserved1:3;
  4264. +               uint8_t veld_ver:5; /* Version number of the ELD
  4265. +                            * extension. This value is
  4266. +                            * provisioned and unique to
  4267. +                            * each vendor.
  4268. +                            */
  4269. +           };
  4270. +       };
  4271. +
  4272. +       /* Byte[2] = Baseline Length field */
  4273. +       uint8_t baseline_eld_length; /* Length of the Baseline structure
  4274. +                         * divided by Four.
  4275. +                         */
  4276. +
  4277. +       /* Byte [3] = Reserved for future use */
  4278. +       uint8_t byte3;
  4279. +
  4280. +       /* Starting of the BaseLine EELD structure
  4281. +        * Byte[4] = Monitor Name Length
  4282. +        */
  4283. +       union {
  4284. +           uint8_t byte4;
  4285. +           struct {
  4286. +               uint8_t mnl:5;
  4287. +               uint8_t cea_edid_rev_id:3;
  4288. +           };
  4289. +       };
  4290. +
  4291. +       /* Byte[5] = Capabilities */
  4292. +       union {
  4293. +           uint8_t capabilities;
  4294. +           struct {
  4295. +               uint8_t hdcp:1; /* HDCP support */
  4296. +               uint8_t ai_support:1;   /* AI support */
  4297. +               uint8_t connection_type:2; /* Connection type
  4298. +                               * 00 - HDMI
  4299. +                               * 01 - DP
  4300. +                               * 10 -11  Reserved
  4301. +                               * for future
  4302. +                               * connection types
  4303. +                               */
  4304. +               uint8_t sadc:4; /* Indicates number of 3 bytes
  4305. +                        * Short Audio Descriptors.
  4306. +                        */
  4307. +           };
  4308. +       };
  4309. +
  4310. +       /* Byte[6] = Audio Synch Delay */
  4311. +       uint8_t audio_synch_delay; /* Amount of time reported by the
  4312. +                       * sink that the video trails audio
  4313. +                       * in milliseconds.
  4314. +                       */
  4315. +
  4316. +       /* Byte[7] = Speaker Allocation Block */
  4317. +       union {
  4318. +           uint8_t speaker_allocation_block;
  4319. +           struct {
  4320. +               uint8_t flr:1; /*Front Left and Right channels*/
  4321. +               uint8_t lfe:1; /*Low Frequency Effect channel*/
  4322. +               uint8_t fc:1;  /*Center transmission channel*/
  4323. +               uint8_t rlr:1; /*Rear Left and Right channels*/
  4324. +               uint8_t rc:1; /*Rear Center channel*/
  4325. +               uint8_t flrc:1; /*Front left and Right of Center
  4326. +                        *transmission channels
  4327. +                        */
  4328. +               uint8_t rlrc:1; /*Rear left and Right of Center
  4329. +                        *transmission channels
  4330. +                        */
  4331. +               uint8_t reserved3:1; /* Reserved */
  4332. +           };
  4333. +       };
  4334. +
  4335. +       /* Byte[8 - 15] - 8 Byte port identification value */
  4336. +       uint8_t port_id_value[8];
  4337. +
  4338. +       /* Byte[16 - 17] - 2 Byte Manufacturer ID */
  4339. +       uint8_t manufacturer_id[2];
  4340. +
  4341. +       /* Byte[18 - 19] - 2 Byte Product ID */
  4342. +       uint8_t product_id[2];
  4343. +
  4344. +       /* Byte [20-83] - 64 Bytes of BaseLine Data */
  4345. +       uint8_t mn_sand_sads[64]; /* This will include
  4346. +                      * - ASCII string of Monitor name
  4347. +                      * - List of 3 byte SADs
  4348. +                      * - Zero padding
  4349. +                      */
  4350. +
  4351. +       /* Vendor ELD Block should continue here!
  4352. +        * No Vendor ELD block defined as of now.
  4353. +        */
  4354. +   };
  4355. +   #pragma pack()
  4356. +} otm_hdmi_eld_t;
  4357. +
  4358. +/**
  4359. + * enum had_status - Audio stream states
  4360. + *
  4361. + * @STREAM_INIT: Stream initialized
  4362. + * @STREAM_RUNNING: Stream running
  4363. + * @STREAM_PAUSED: Stream paused
  4364. + * @STREAM_DROPPED: Stream dropped
  4365. + */
  4366. +enum had_stream_status {
  4367. +   STREAM_INIT = 0,
  4368. +   STREAM_RUNNING = 1,
  4369. +   STREAM_PAUSED = 2,
  4370. +   STREAM_DROPPED = 3
  4371. +};
  4372. +
  4373. +/**
  4374. + * enum had_status_stream - HAD stream states
  4375. + */
  4376. +enum had_status_stream {
  4377. +   HAD_INIT = 0,
  4378. +   HAD_RUNNING_STREAM,
  4379. +};
  4380. +
  4381. +enum had_drv_status {
  4382. +   HAD_DRV_CONNECTED,
  4383. +   HAD_DRV_RUNNING,
  4384. +   HAD_DRV_DISCONNECTED,
  4385. +   HAD_DRV_SUSPENDED,
  4386. +   HAD_DRV_ERR,
  4387. +};
  4388. +
  4389. +/* enum intel_had_aud_buf_type - HDMI controller ring buffer types */
  4390. +enum intel_had_aud_buf_type {
  4391. +   HAD_BUF_TYPE_A = 0,
  4392. +   HAD_BUF_TYPE_B = 1,
  4393. +   HAD_BUF_TYPE_C = 2,
  4394. +   HAD_BUF_TYPE_D = 3,
  4395. +};
  4396. +
  4397. +enum num_aud_ch {
  4398. +   CH_STEREO = 0,
  4399. +   CH_THREE_FOUR = 1,
  4400. +   CH_FIVE_SIX = 2,
  4401. +   CH_SEVEN_EIGHT = 3
  4402. +};
  4403. +
  4404. +
  4405. +/* HDMI controller register offsets */
  4406. +enum hdmi_ctrl_reg_offset_v1 {
  4407. +   AUD_CONFIG      = 0x0,
  4408. +   AUD_CH_STATUS_0     = 0x08,
  4409. +   AUD_CH_STATUS_1     = 0x0C,
  4410. +   AUD_HDMI_CTS        = 0x10,
  4411. +   AUD_N_ENABLE        = 0x14,
  4412. +   AUD_SAMPLE_RATE     = 0x18,
  4413. +   AUD_BUF_CONFIG      = 0x20,
  4414. +   AUD_BUF_CH_SWAP     = 0x24,
  4415. +   AUD_BUF_A_ADDR      = 0x40,
  4416. +   AUD_BUF_A_LENGTH    = 0x44,
  4417. +   AUD_BUF_B_ADDR      = 0x48,
  4418. +   AUD_BUF_B_LENGTH    = 0x4c,
  4419. +   AUD_BUF_C_ADDR      = 0x50,
  4420. +   AUD_BUF_C_LENGTH    = 0x54,
  4421. +   AUD_BUF_D_ADDR      = 0x58,
  4422. +   AUD_BUF_D_LENGTH    = 0x5c,
  4423. +   AUD_CNTL_ST     = 0x60,
  4424. +   AUD_HDMI_STATUS     = 0x68,
  4425. +   AUD_HDMIW_INFOFR    = 0x114,
  4426. +};
  4427. +
  4428. +/*
  4429. + * Delta changes in HDMI controller register offsets
  4430. + * compare to v1 version
  4431. + */
  4432. +
  4433. +enum hdmi_ctrl_reg_offset_v2 {
  4434. +   AUD_HDMI_STATUS_v2  = 0x64,
  4435. +   AUD_HDMIW_INFOFR_v2 = 0x68,
  4436. +};
  4437. +
  4438. +/*
  4439. + * CEA speaker placement:
  4440. + *
  4441. + *  FL  FLC   FC   FRC   FR
  4442. + *
  4443. + *                         LFE
  4444. + *
  4445. + *  RL  RLC   RC   RRC   RR
  4446. + *
  4447. + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
  4448. + * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
  4449. + */
  4450. +enum cea_speaker_placement {
  4451. +   FL  = (1 <<  0),        /* Front Left           */
  4452. +   FC  = (1 <<  1),        /* Front Center         */
  4453. +   FR  = (1 <<  2),        /* Front Right          */
  4454. +   FLC = (1 <<  3),        /* Front Left Center    */
  4455. +   FRC = (1 <<  4),        /* Front Right Center   */
  4456. +   RL  = (1 <<  5),        /* Rear Left            */
  4457. +   RC  = (1 <<  6),        /* Rear Center          */
  4458. +   RR  = (1 <<  7),        /* Rear Right           */
  4459. +   RLC = (1 <<  8),        /* Rear Left Center     */
  4460. +   RRC = (1 <<  9),        /* Rear Right Center    */
  4461. +   LFE = (1 << 10),        /* Low Frequency Effect */
  4462. +};
  4463. +
  4464. +struct cea_channel_speaker_allocation {
  4465. +   int ca_index;
  4466. +   int speakers[8];
  4467. +
  4468. +   /* derived values, just for convenience */
  4469. +   int channels;
  4470. +   int spk_mask;
  4471. +};
  4472. +
  4473. +struct channel_map_table {
  4474. +   unsigned char map;              /* ALSA API channel map position */
  4475. +   unsigned char cea_slot;         /* CEA slot value */
  4476. +   int spk_mask;                   /* speaker position bit mask */
  4477. +};
  4478. +
  4479. +/**
  4480. + * union aud_cfg - Audio configuration
  4481. + *
  4482. + * @cfg_regx: individual register bits
  4483. + * @cfg_regval: full register value
  4484. + *
  4485. + */
  4486. +union aud_cfg {
  4487. +   struct {
  4488. +       u32 aud_en:1;
  4489. +       u32 layout:1;
  4490. +       u32 fmt:2;
  4491. +       u32 num_ch:2;
  4492. +       u32 rsvd0:1;
  4493. +       u32 set:1;
  4494. +       u32 flat:1;
  4495. +       u32 val_bit:1;
  4496. +       u32 user_bit:1;
  4497. +       u32 underrun:1;
  4498. +       u32 rsvd1:20;
  4499. +   } cfg_regx;
  4500. +   struct {
  4501. +       u32 aud_en:1;
  4502. +       u32 layout:1;
  4503. +       u32 fmt:2;
  4504. +       u32 num_ch:3;
  4505. +       u32 set:1;
  4506. +       u32 flat:1;
  4507. +       u32 val_bit:1;
  4508. +       u32 user_bit:1;
  4509. +       u32 underrun:1;
  4510. +       u32 packet_mode:1;
  4511. +       u32 left_align:1;
  4512. +       u32 bogus_sample:1;
  4513. +       u32 dp_modei:1;
  4514. +       u32 rsvd:16;
  4515. +   } cfg_regx_v2;
  4516. +   u32 cfg_regval;
  4517. +};
  4518. +
  4519. +/**
  4520. + * union aud_ch_status_0 - Audio Channel Status 0 Attributes
  4521. + *
  4522. + * @status_0_regx:individual register bits
  4523. + * @status_0_regval:full register value
  4524. + *
  4525. + */
  4526. +union aud_ch_status_0 {
  4527. +   struct {
  4528. +       u32 ch_status:1;
  4529. +       u32 lpcm_id:1;
  4530. +       u32 cp_info:1;
  4531. +       u32 format:3;
  4532. +       u32 mode:2;
  4533. +       u32 ctg_code:8;
  4534. +       u32 src_num:4;
  4535. +       u32 ch_num:4;
  4536. +       u32 samp_freq:4;
  4537. +       u32 clk_acc:2;
  4538. +       u32 rsvd:2;
  4539. +   } status_0_regx;
  4540. +   u32 status_0_regval;
  4541. +};
  4542. +
  4543. +/**
  4544. + * union aud_ch_status_1 - Audio Channel Status 1 Attributes
  4545. + *
  4546. + * @status_1_regx: individual register bits
  4547. + * @status_1_regval: full register value
  4548. + *
  4549. + */
  4550. +union aud_ch_status_1 {
  4551. +   struct {
  4552. +       u32 max_wrd_len:1;
  4553. +       u32 wrd_len:3;
  4554. +       u32 rsvd:28;
  4555. +       } status_1_regx;
  4556. +   u32 status_1_regval;
  4557. +};
  4558. +
  4559. +/**
  4560. + * union aud_hdmi_cts - CTS register
  4561. + *
  4562. + * @cts_regx: individual register bits
  4563. + * @cts_regval: full register value
  4564. + *
  4565. + */
  4566. +union aud_hdmi_cts {
  4567. +   struct {
  4568. +       u32 cts_val:20;
  4569. +       u32 en_cts_prog:1;
  4570. +       u32 rsvd:11;
  4571. +   } cts_regx;
  4572. +   struct {
  4573. +       u32 cts_val:24;
  4574. +       u32 en_cts_prog:1;
  4575. +       u32 rsvd:7;
  4576. +   } cts_regx_v2;
  4577. +   u32 cts_regval;
  4578. +};
  4579. +
  4580. +/**
  4581. + * union aud_hdmi_n_enable - N register
  4582. + *
  4583. + * @n_regx: individual register bits
  4584. + * @n_regval: full register value
  4585. + *
  4586. + */
  4587. +union aud_hdmi_n_enable {
  4588. +   struct {
  4589. +       u32 n_val:20;
  4590. +       u32 en_n_prog:1;
  4591. +       u32 rsvd:11;
  4592. +   } n_regx;
  4593. +   struct {
  4594. +       u32 n_val:24;
  4595. +       u32 en_n_prog:1;
  4596. +       u32 rsvd:7;
  4597. +   } n_regx_v2;
  4598. +   u32 n_regval;
  4599. +};
  4600. +
  4601. +/**
  4602. + * union aud_buf_config -  Audio Buffer configurations
  4603. + *
  4604. + * @buf_cfg_regx: individual register bits
  4605. + * @buf_cfgval: full register value
  4606. + *
  4607. + */
  4608. +union aud_buf_config {
  4609. +   struct {
  4610. +       u32 fifo_width:8;
  4611. +       u32 rsvd0:8;
  4612. +       u32 aud_delay:8;
  4613. +       u32 rsvd1:8;
  4614. +   } buf_cfg_regx;
  4615. +   struct {
  4616. +       u32 audio_fifo_watermark:8;
  4617. +       u32 dma_fifo_watermark:3;
  4618. +       u32 rsvd0:5;
  4619. +       u32 aud_delay:8;
  4620. +       u32 rsvd1:8;
  4621. +   } buf_cfg_regx_v2;
  4622. +   u32 buf_cfgval;
  4623. +};
  4624. +
  4625. +/**
  4626. + * union aud_buf_ch_swap - Audio Sample Swapping offset
  4627. + *
  4628. + * @buf_ch_swap_regx: individual register bits
  4629. + * @buf_ch_swap_val: full register value
  4630. + *
  4631. + */
  4632. +union aud_buf_ch_swap {
  4633. +   struct {
  4634. +       u32 first_0:3;
  4635. +       u32 second_0:3;
  4636. +       u32 first_1:3;
  4637. +       u32 second_1:3;
  4638. +       u32 first_2:3;
  4639. +       u32 second_2:3;
  4640. +       u32 first_3:3;
  4641. +       u32 second_3:3;
  4642. +       u32 rsvd:8;
  4643. +   } buf_ch_swap_regx;
  4644. +   u32 buf_ch_swap_val;
  4645. +};
  4646. +
  4647. +/**
  4648. + * union aud_buf_addr - Address for Audio Buffer
  4649. + *
  4650. + * @buf_addr_regx: individual register bits
  4651. + * @buf_addr_val: full register value
  4652. + *
  4653. + */
  4654. +union aud_buf_addr {
  4655. +   struct {
  4656. +       u32 valid:1;
  4657. +       u32 intr_en:1;
  4658. +       u32 rsvd:4;
  4659. +       u32 addr:26;
  4660. +   } buf_addr_regx;
  4661. +   u32 buf_addr_val;
  4662. +};
  4663. +
  4664. +/**
  4665. + * union aud_buf_len - Length of Audio Buffer
  4666. + *
  4667. + * @buf_len_regx: individual register bits
  4668. + * @buf_len_val: full register value
  4669. + *
  4670. + */
  4671. +union aud_buf_len {
  4672. +   struct {
  4673. +       u32 buf_len:20;
  4674. +       u32 rsvd:12;
  4675. +   } buf_len_regx;
  4676. +   u32 buf_len_val;
  4677. +};
  4678. +
  4679. +/**
  4680. + * union aud_ctrl_st - Audio Control State Register offset
  4681. + *
  4682. + * @ctrl_regx: individual register bits
  4683. + * @ctrl_val: full register value
  4684. + *
  4685. + */
  4686. +union aud_ctrl_st {
  4687. +   struct {
  4688. +       u32 ram_addr:4;
  4689. +       u32 eld_ack:1;
  4690. +       u32 eld_addr:4;
  4691. +       u32 eld_buf_size:5;
  4692. +       u32 eld_valid:1;
  4693. +       u32 cp_ready:1;
  4694. +       u32 dip_freq:2;
  4695. +       u32 dip_idx:3;
  4696. +       u32 dip_en_sta:4;
  4697. +       u32 rsvd:7;
  4698. +   } ctrl_regx;
  4699. +   u32 ctrl_val;
  4700. +};
  4701. +
  4702. +/**
  4703. + * union aud_info_frame1 - Audio HDMI Widget Data Island Packet offset
  4704. + *
  4705. + * @fr1_regx: individual register bits
  4706. + * @fr1_val: full register value
  4707. + *
  4708. + */
  4709. +union aud_info_frame1 {
  4710. +   struct {
  4711. +       u32 pkt_type:8;
  4712. +       u32 ver_num:8;
  4713. +       u32 len:5;
  4714. +       u32 rsvd:11;
  4715. +   } fr1_regx;
  4716. +   u32 fr1_val;
  4717. +};
  4718. +
  4719. +/**
  4720. + * union aud_info_frame2 - DIP frame 2
  4721. + *
  4722. + * @fr2_regx: individual register bits
  4723. + * @fr2_val: full register value
  4724. + *
  4725. + */
  4726. +union aud_info_frame2 {
  4727. +   struct {
  4728. +       u32 chksum:8;
  4729. +       u32 chnl_cnt:3;
  4730. +       u32 rsvd0:1;
  4731. +       u32 coding_type:4;
  4732. +       u32 smpl_size:2;
  4733. +       u32 smpl_freq:3;
  4734. +       u32 rsvd1:3;
  4735. +       u32 format:8;
  4736. +   } fr2_regx;
  4737. +   u32 fr2_val;
  4738. +};
  4739. +
  4740. +/**
  4741. + * union aud_info_frame3 - DIP frame 3
  4742. + *
  4743. + * @fr3_regx: individual register bits
  4744. + * @fr3_val: full register value
  4745. + *
  4746. + */
  4747. +union aud_info_frame3 {
  4748. +   struct {
  4749. +       u32 chnl_alloc:8;
  4750. +       u32 rsvd0:3;
  4751. +       u32 lsv:4;
  4752. +       u32 dm_inh:1;
  4753. +       u32 rsvd1:16;
  4754. +   } fr3_regx;
  4755. +   u32 fr3_val;
  4756. +};
  4757. +
  4758. +
  4759. +struct pcm_stream_info {
  4760. +   int     str_id;
  4761. +   void        *had_substream;
  4762. +   void        (*period_elapsed)(void *had_substream);
  4763. +   u32     buffer_ptr;
  4764. +   u64     buffer_rendered;
  4765. +   u32     ring_buf_size;
  4766. +   int     sfreq;
  4767. +};
  4768. +
  4769. +struct ring_buf_info {
  4770. +   uint32_t    buf_addr;
  4771. +   uint32_t    buf_size;
  4772. +   uint8_t     is_valid;
  4773. +};
  4774. +
  4775. +struct had_stream_pvt {
  4776. +   enum had_stream_status      stream_status;
  4777. +   int             stream_ops;
  4778. +   ssize_t             dbg_cum_bytes;
  4779. +};
  4780. +
  4781. +struct had_pvt_data {
  4782. +   enum had_status_stream      stream_type;
  4783. +};
  4784. +
  4785. +struct had_callback_ops {
  4786. +   had_event_call_back intel_had_event_call_back;
  4787. +};
  4788. +
  4789. +/**
  4790. + * struct snd_intelhad - intelhad driver structure
  4791. + *
  4792. + * @card: ptr to hold card details
  4793. + * @card_index: sound card index
  4794. + * @card_id: detected sound card id
  4795. + * @reg_ops: register operations to program registers
  4796. + * @query_ops: caps call backs for get/set operations
  4797. + * @drv_status: driver status
  4798. + * @buf_info: ring buffer info
  4799. + * @stream_info: stream information
  4800. + * @eeld: holds EELD info
  4801. + * @curr_buf: pointer to hold current active ring buf
  4802. + * @valid_buf_cnt: ring buffer count for stream
  4803. + * @had_spinlock: driver lock
  4804. + * @aes_bits: IEC958 status bits
  4805. + * @buff_done: id of current buffer done intr
  4806. + * @dev: platoform device handle
  4807. + * @kctl: holds kctl ptrs used for channel map
  4808. + * @chmap: holds channel map info
  4809. + * @audio_reg_base: hdmi audio register base offset
  4810. + * @hw_silence: flag indicates SoC support for HW silence/Keep alive
  4811. + * @ops: holds ops functions based on platform
  4812. + */
  4813. +struct snd_intelhad {
  4814. +   struct snd_card *card;
  4815. +   int     card_index;
  4816. +   char        *card_id;
  4817. +   struct hdmi_audio_registers_ops reg_ops;
  4818. +   struct hdmi_audio_query_set_ops query_ops;
  4819. +   enum had_drv_status drv_status;
  4820. +   struct      ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS];
  4821. +   struct      pcm_stream_info stream_info;
  4822. +   otm_hdmi_eld_t  eeld;
  4823. +   enum        intel_had_aud_buf_type curr_buf;
  4824. +   int     valid_buf_cnt;
  4825. +   unsigned int    aes_bits;
  4826. +   int flag_underrun;
  4827. +   struct had_pvt_data *private_data;
  4828. +   spinlock_t had_spinlock;
  4829. +   enum        intel_had_aud_buf_type buff_done;
  4830. +   struct device *dev;
  4831. +   struct snd_kcontrol *kctl;
  4832. +   struct snd_pcm_chmap *chmap;
  4833. +   unsigned int    audio_reg_base;
  4834. +   bool        hw_silence;
  4835. +   struct had_ops  *ops;
  4836. +};
  4837. +
  4838. +struct had_ops {
  4839. +   void (*enable_audio)(struct snd_pcm_substream *substream,
  4840. +           u8 enable);
  4841. +   void (*reset_audio)(u8 reset);
  4842. +   int (*prog_n)(u32 aud_samp_freq, u32 *n_param,
  4843. +           struct snd_intelhad *intelhaddata);
  4844. +   void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 n_param,
  4845. +           struct snd_intelhad *intelhaddata);
  4846. +   int (*audio_ctrl)(struct snd_pcm_substream *substream,
  4847. +               struct snd_intelhad *intelhaddata);
  4848. +   void (*prog_dip)(struct snd_pcm_substream *substream,
  4849. +               struct snd_intelhad *intelhaddata);
  4850. +   void (*handle_underrun)(struct snd_intelhad *intelhaddata);
  4851. +};
  4852. +
  4853. +
  4854. +int had_event_handler(enum had_event_type event_type, void *data);
  4855. +
  4856. +int hdmi_audio_query(void *drv_data, hdmi_audio_event_t event);
  4857. +int hdmi_audio_suspend(void *drv_data, hdmi_audio_event_t event);
  4858. +int hdmi_audio_resume(void *drv_data);
  4859. +int hdmi_audio_mode_change(struct snd_pcm_substream *substream);
  4860. +extern struct snd_pcm_ops snd_intelhad_playback_ops;
  4861. +
  4862. +int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream,
  4863. +                   struct snd_intelhad *intelhaddata,
  4864. +                   int flag_silence);
  4865. +int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata,
  4866. +                   int start, int end);
  4867. +int snd_intelhad_invd_buffer(int start, int end);
  4868. +inline int snd_intelhad_read_len(struct snd_intelhad *intelhaddata);
  4869. +void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata);
  4870. +
  4871. +/* Register access functions */
  4872. +inline int had_get_hwstate(struct snd_intelhad *intelhaddata);
  4873. +inline int had_get_caps(enum had_caps_list query_element, void *capabilties);
  4874. +inline int had_set_caps(enum had_caps_list set_element, void *capabilties);
  4875. +inline int had_read_register(uint32_t reg_addr, uint32_t *data);
  4876. +inline int had_write_register(uint32_t reg_addr, uint32_t data);
  4877. +inline int had_read_modify(uint32_t reg_addr, uint32_t data, uint32_t mask);
  4878. +#endif
  4879. diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio_if.c b/sound/hdmi_audio/intel_mid_hdmi_audio_if.c
  4880. new file mode 100644
  4881. index 0000000..acc407d
  4882. --- /dev/null
  4883. +++ b/sound/hdmi_audio/intel_mid_hdmi_audio_if.c
  4884. @@ -0,0 +1,533 @@
  4885. +/*
  4886. + *   intel_mid_hdmi_audio_if.c - Intel HDMI audio driver for MID
  4887. + *
  4888. + *  Copyright (C) 2010 Intel Corp
  4889. + *  Authors:   Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
  4890. + *     Ramesh Babu K V <ramesh.babu@intel.com>
  4891. + *     Vaibhav Agarwal <vaibhav.agarwal@intel.com>
  4892. + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4893. + *
  4894. + *  This program is free software; you can redistribute it and/or modify
  4895. + *  it under the terms of the GNU General Public License as published by
  4896. + *  the Free Software Foundation; version 2 of the License.
  4897. + *
  4898. + *  This program is distributed in the hope that it will be useful, but
  4899. + *  WITHOUT ANY WARRANTY; without even the implied warranty of
  4900. + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  4901. + *  General Public License for more details.
  4902. + *
  4903. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4904. + * ALSA driver for Intel MID HDMI audio controller.  This file contains
  4905. + * interface functions exposed to HDMI Display driver and code to register
  4906. + * with ALSA framework..
  4907. + */
  4908. +
  4909. +#define pr_fmt(fmt)        "had: " fmt
  4910. +
  4911. +#include <linux/io.h>
  4912. +#include <linux/jiffies.h>
  4913. +#include <sound/pcm.h>
  4914. +#include <sound/core.h>
  4915. +#include "intel_mid_hdmi_audio.h"
  4916. +
  4917. +
  4918. +/**
  4919. + * hdmi_audio_query - hdmi audio query function
  4920. + *
  4921. + *@haddata: pointer to HAD private data
  4922. + *@event: audio event for which this method is invoked
  4923. + *
  4924. + * This function is called by client driver to query the
  4925. + * hdmi audio.
  4926. + */
  4927. +int hdmi_audio_query(void *haddata, hdmi_audio_event_t event)
  4928. +{
  4929. +   struct snd_pcm_substream *substream = NULL;
  4930. +   struct had_pvt_data *had_stream;
  4931. +   unsigned long flag_irqs;
  4932. +   struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata;
  4933. +
  4934. +   if (intelhaddata->stream_info.had_substream)
  4935. +       substream = intelhaddata->stream_info.had_substream;
  4936. +   had_stream = intelhaddata->private_data;
  4937. +   switch (event.type) {
  4938. +   case HAD_EVENT_QUERY_IS_AUDIO_BUSY:
  4939. +       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  4940. +
  4941. +       if ((had_stream->stream_type == HAD_RUNNING_STREAM) ||
  4942. +           substream) {
  4943. +           spin_unlock_irqrestore(&intelhaddata->had_spinlock,
  4944. +                       flag_irqs);
  4945. +           pr_debug("Audio stream active\n");
  4946. +           return -EBUSY;
  4947. +       }
  4948. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  4949. +   break;
  4950. +
  4951. +   case HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED:
  4952. +       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  4953. +       if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) {
  4954. +           spin_unlock_irqrestore(&intelhaddata->had_spinlock,
  4955. +                       flag_irqs);
  4956. +           pr_debug("Audio is suspended\n");
  4957. +           return 1;
  4958. +       }
  4959. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  4960. +   break;
  4961. +
  4962. +   default:
  4963. +       pr_debug("error un-handled event !!\n");
  4964. +       return -EINVAL;
  4965. +   break;
  4966. +
  4967. +   }
  4968. +
  4969. +   return 0;
  4970. +}
  4971. +
  4972. +/**
  4973. + * hdmi_audio_suspend - power management suspend function
  4974. + *
  4975. + *@haddata: pointer to HAD private data
  4976. + *@event: pm event for which this method is invoked
  4977. + *
  4978. + * This function is called by client driver to suspend the
  4979. + * hdmi audio.
  4980. + */
  4981. +int hdmi_audio_suspend(void *haddata, hdmi_audio_event_t event)
  4982. +{
  4983. +   int caps, retval = 0;
  4984. +   struct had_pvt_data *had_stream;
  4985. +   unsigned long flag_irqs;
  4986. +   struct snd_pcm_substream *substream;
  4987. +   struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata;
  4988. +
  4989. +   pr_debug("Enter:%s", __func__);
  4990. +
  4991. +   had_stream = intelhaddata->private_data;
  4992. +   substream = intelhaddata->stream_info.had_substream;
  4993. +
  4994. +   if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) {
  4995. +       pr_err("audio stream is active\n");
  4996. +       return -EAGAIN;
  4997. +   }
  4998. +
  4999. +
  5000. +   spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5001. +   if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
  5002. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5003. +       pr_debug("had not connected\n");
  5004. +       return retval;
  5005. +   }
  5006. +
  5007. +   if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) {
  5008. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5009. +       pr_debug("had already suspended\n");
  5010. +       return retval;
  5011. +   }
  5012. +
  5013. +   intelhaddata->drv_status = HAD_DRV_SUSPENDED;
  5014. +   spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5015. +   /*
  5016. +    * ToDo: Need to disable UNDERRUN interrupts as well
  5017. +    *  caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
  5018. +    */
  5019. +   caps = HDMI_AUDIO_BUFFER_DONE;
  5020. +   had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps);
  5021. +   had_set_caps(HAD_SET_DISABLE_AUDIO, NULL);
  5022. +   pr_debug("Exit:%s", __func__);
  5023. +   return retval;
  5024. +}
  5025. +
  5026. +/**
  5027. + * hdmi_audio_resume - power management resume function
  5028. + *
  5029. + *@haddata: pointer to HAD private data
  5030. + *
  5031. + * This function is called by client driver to resume the
  5032. + * hdmi audio.
  5033. + */
  5034. +int hdmi_audio_resume(void *haddata)
  5035. +{
  5036. +   int caps, retval = 0;
  5037. +   struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata;
  5038. +   unsigned long flag_irqs;
  5039. +
  5040. +   pr_debug("Enter:%s", __func__);
  5041. +
  5042. +   spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5043. +   if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
  5044. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5045. +       pr_debug("had not connected\n");
  5046. +       return 0;
  5047. +   }
  5048. +
  5049. +   if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) {
  5050. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5051. +       pr_err("had is not in suspended state\n");
  5052. +       return 0;
  5053. +   }
  5054. +
  5055. +   if (had_get_hwstate(intelhaddata)) {
  5056. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5057. +       pr_err("Failed to resume. Device not accessible\n");
  5058. +       return -ENODEV;
  5059. +   }
  5060. +
  5061. +   intelhaddata->drv_status = HAD_DRV_CONNECTED;
  5062. +   spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5063. +   /*
  5064. +    * ToDo: Need to enable UNDERRUN interrupts as well
  5065. +    * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
  5066. +    */
  5067. +   caps = HDMI_AUDIO_BUFFER_DONE;
  5068. +   retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps);
  5069. +   retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL);
  5070. +   pr_debug("Exit:%s", __func__);
  5071. +   return retval;
  5072. +}
  5073. +
  5074. +static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata,
  5075. +       enum intel_had_aud_buf_type buf_id)
  5076. +{
  5077. +   int i, intr_count = 0;
  5078. +   enum intel_had_aud_buf_type buff_done;
  5079. +   u32 buf_size, buf_addr;
  5080. +   struct had_pvt_data *had_stream;
  5081. +   unsigned long flag_irqs;
  5082. +
  5083. +   had_stream = intelhaddata->private_data;
  5084. +
  5085. +   buff_done = buf_id;
  5086. +
  5087. +   intr_count = snd_intelhad_read_len(intelhaddata);
  5088. +   if (intr_count > 1) {
  5089. +       /* In case of active playback */
  5090. +       pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n",
  5091. +               (intr_count - 1));
  5092. +       if (intr_count > 3)
  5093. +           return intr_count;
  5094. +
  5095. +       buf_id += (intr_count - 1);
  5096. +       /* Reprogram registers*/
  5097. +       for (i = buff_done; i < buf_id; i++) {
  5098. +           int j = i % 4;
  5099. +
  5100. +           buf_size = intelhaddata->buf_info[j].buf_size;
  5101. +           buf_addr = intelhaddata->buf_info[j].buf_addr;
  5102. +           had_write_register(AUD_BUF_A_LENGTH +
  5103. +                   (j * HAD_REG_WIDTH), buf_size);
  5104. +           had_write_register(
  5105. +                   AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH),
  5106. +                   (buf_addr | BIT(0) | BIT(1)));
  5107. +       }
  5108. +       buf_id = buf_id % 4;
  5109. +       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5110. +       intelhaddata->buff_done = buf_id;
  5111. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5112. +   }
  5113. +
  5114. +   return intr_count;
  5115. +}
  5116. +
  5117. +int had_process_buffer_done(struct snd_intelhad *intelhaddata)
  5118. +{
  5119. +   int retval = 0;
  5120. +   u32 len = 1;
  5121. +   enum intel_had_aud_buf_type buf_id;
  5122. +   enum intel_had_aud_buf_type buff_done;
  5123. +   struct pcm_stream_info *stream;
  5124. +   u32 buf_size;
  5125. +   struct had_pvt_data *had_stream;
  5126. +   int intr_count;
  5127. +   enum had_status_stream      stream_type;
  5128. +   unsigned long flag_irqs;
  5129. +
  5130. +   had_stream = intelhaddata->private_data;
  5131. +   stream = &intelhaddata->stream_info;
  5132. +   intr_count = 1;
  5133. +
  5134. +   spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5135. +   if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
  5136. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5137. +       pr_err("%s:Device already disconnected\n", __func__);
  5138. +       return retval;
  5139. +   }
  5140. +   buf_id = intelhaddata->curr_buf;
  5141. +   intelhaddata->buff_done = buf_id;
  5142. +   buff_done = intelhaddata->buff_done;
  5143. +   buf_size = intelhaddata->buf_info[buf_id].buf_size;
  5144. +   stream_type = had_stream->stream_type;
  5145. +
  5146. +   pr_debug("Enter:%s buf_id=%d", __func__, buf_id);
  5147. +
  5148. +   /* Every debug statement has an implication
  5149. +    * of ~5msec. Thus, avoid having >3 debug statements
  5150. +    * for each buffer_done handling.
  5151. +    */
  5152. +
  5153. +   /* Check for any intr_miss in case of active playback */
  5154. +   if (had_stream->stream_type == HAD_RUNNING_STREAM) {
  5155. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5156. +       intr_count = had_chk_intrmiss(intelhaddata, buf_id);
  5157. +       if (!intr_count || (intr_count > 3)) {
  5158. +           pr_err("HAD SW state in non-recoverable!!! mode\n");
  5159. +           pr_err("Already played stale data\n");
  5160. +           return retval;
  5161. +       }
  5162. +       buf_id += (intr_count - 1);
  5163. +       buf_id = buf_id % 4;
  5164. +       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5165. +   }
  5166. +
  5167. +   intelhaddata->buf_info[buf_id].is_valid = true;
  5168. +   if (intelhaddata->valid_buf_cnt-1 == buf_id) {
  5169. +       if (had_stream->stream_type >= HAD_RUNNING_STREAM)
  5170. +           intelhaddata->curr_buf = HAD_BUF_TYPE_A;
  5171. +   } else
  5172. +       intelhaddata->curr_buf = buf_id + 1;
  5173. +
  5174. +   spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5175. +
  5176. +   if (had_get_hwstate(intelhaddata)) {
  5177. +       pr_err("HDMI cable plugged-out\n");
  5178. +       return retval;
  5179. +   }
  5180. +
  5181. +   /*Reprogram the registers with addr and length*/
  5182. +   had_write_register(AUD_BUF_A_LENGTH +
  5183. +           (buf_id * HAD_REG_WIDTH), buf_size);
  5184. +   had_write_register(AUD_BUF_A_ADDR+(buf_id * HAD_REG_WIDTH),
  5185. +           intelhaddata->buf_info[buf_id].buf_addr|
  5186. +           BIT(0) | BIT(1));
  5187. +
  5188. +   had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH),
  5189. +                   &len);
  5190. +   pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id);
  5191. +
  5192. +   /* In case of actual data,
  5193. +    * report buffer_done to above ALSA layer
  5194. +    */
  5195. +   buf_size =  intelhaddata->buf_info[buf_id].buf_size;
  5196. +   if (stream_type >= HAD_RUNNING_STREAM) {
  5197. +       intelhaddata->stream_info.buffer_rendered +=
  5198. +           (intr_count * buf_size);
  5199. +       stream->period_elapsed(stream->had_substream);
  5200. +   }
  5201. +
  5202. +   return retval;
  5203. +}
  5204. +
  5205. +int had_process_buffer_underrun(struct snd_intelhad *intelhaddata)
  5206. +{
  5207. +   int retval = 0;
  5208. +   enum intel_had_aud_buf_type buf_id;
  5209. +   struct pcm_stream_info *stream;
  5210. +   struct had_pvt_data *had_stream;
  5211. +   enum had_status_stream stream_type;
  5212. +   unsigned long flag_irqs;
  5213. +   int drv_status;
  5214. +
  5215. +   had_stream = intelhaddata->private_data;
  5216. +   stream = &intelhaddata->stream_info;
  5217. +
  5218. +   spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5219. +   buf_id = intelhaddata->curr_buf;
  5220. +   stream_type = had_stream->stream_type;
  5221. +   intelhaddata->buff_done = buf_id;
  5222. +   drv_status = intelhaddata->drv_status;
  5223. +   if (stream_type == HAD_RUNNING_STREAM)
  5224. +       intelhaddata->curr_buf = HAD_BUF_TYPE_A;
  5225. +
  5226. +   spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5227. +
  5228. +   pr_debug("Enter:%s buf_id=%d, stream_type=%d\n",
  5229. +           __func__, buf_id, stream_type);
  5230. +
  5231. +   intelhaddata->ops->handle_underrun(intelhaddata);
  5232. +
  5233. +   if (drv_status == HAD_DRV_DISCONNECTED) {
  5234. +       pr_err("%s:Device already disconnected\n", __func__);
  5235. +       return retval;
  5236. +   }
  5237. +
  5238. +   if (stream_type == HAD_RUNNING_STREAM) {
  5239. +       /* Report UNDERRUN error to above layers */
  5240. +       intelhaddata->flag_underrun = 1;
  5241. +       stream->period_elapsed(stream->had_substream);
  5242. +   }
  5243. +
  5244. +   return retval;
  5245. +}
  5246. +
  5247. +int had_process_hot_plug(struct snd_intelhad *intelhaddata)
  5248. +{
  5249. +   int retval = 0;
  5250. +   enum intel_had_aud_buf_type buf_id;
  5251. +   struct snd_pcm_substream *substream;
  5252. +   struct had_pvt_data *had_stream;
  5253. +   unsigned long flag_irqs;
  5254. +
  5255. +   pr_debug("Enter:%s", __func__);
  5256. +
  5257. +   substream = intelhaddata->stream_info.had_substream;
  5258. +   had_stream = intelhaddata->private_data;
  5259. +
  5260. +   spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5261. +   if (intelhaddata->drv_status == HAD_DRV_CONNECTED) {
  5262. +       pr_debug("Device already connected\n");
  5263. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5264. +       return retval;
  5265. +   }
  5266. +   buf_id = intelhaddata->curr_buf;
  5267. +   intelhaddata->buff_done = buf_id;
  5268. +   intelhaddata->drv_status = HAD_DRV_CONNECTED;
  5269. +   spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5270. +
  5271. +   pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id);
  5272. +
  5273. +    /* Query display driver for audio register base */
  5274. +   if (intelhaddata->reg_ops.hdmi_audio_get_register_base
  5275. +       (&intelhaddata->audio_reg_base)) {
  5276. +           pr_err("Unable to get audio reg base from Display driver\n");
  5277. +           goto err;
  5278. +   }
  5279. +   if(intelhaddata->audio_reg_base == 0){
  5280. +       pr_err("audio reg base value is NULL\n");
  5281. +       goto err;
  5282. +   }
  5283. +
  5284. +   pr_debug("%s audio_reg_base = %x\n",__func__, intelhaddata->audio_reg_base);
  5285. +
  5286. +   /* Safety check */
  5287. +   if (substream) {
  5288. +       pr_debug("There should not be active PB from ALSA\n");
  5289. +       pr_debug("Signifies, cable is plugged-in even before\n");
  5290. +       pr_debug("processing snd_pcm_disconnect\n");
  5291. +       /* Set runtime->state to hw_params done */
  5292. +       snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
  5293. +   }
  5294. +
  5295. +   had_build_channel_allocation_map(intelhaddata);
  5296. +
  5297. +   return retval;
  5298. +
  5299. +err:
  5300. +   pm_runtime_disable(intelhaddata->dev);
  5301. +   intelhaddata->dev = NULL;
  5302. +   return retval;
  5303. +}
  5304. +
  5305. +int had_process_hot_unplug(struct snd_intelhad *intelhaddata)
  5306. +{
  5307. +   int caps, retval = 0;
  5308. +   enum intel_had_aud_buf_type buf_id;
  5309. +   struct had_pvt_data *had_stream;
  5310. +   unsigned long flag_irqs;
  5311. +
  5312. +   pr_debug("Enter:%s", __func__);
  5313. +
  5314. +   had_stream = intelhaddata->private_data;
  5315. +   buf_id = intelhaddata->curr_buf;
  5316. +
  5317. +   spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5318. +   if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) {
  5319. +       pr_debug("Device already disconnected\n");
  5320. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5321. +       return retval;
  5322. +   } else {
  5323. +       /* Disable Audio */
  5324. +       caps = HDMI_AUDIO_BUFFER_DONE;
  5325. +       retval = had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps);
  5326. +       retval = had_set_caps(HAD_SET_DISABLE_AUDIO, NULL);
  5327. +       intelhaddata->ops->enable_audio(intelhaddata->stream_info.had_substream, 0);
  5328. +   }
  5329. +
  5330. +   intelhaddata->drv_status = HAD_DRV_DISCONNECTED;
  5331. +   /* Report to above ALSA layer */
  5332. +   if (intelhaddata->stream_info.had_substream != NULL) {
  5333. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5334. +       pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__);
  5335. +       snd_pcm_stop(intelhaddata->stream_info.had_substream,
  5336. +               SNDRV_PCM_STATE_DISCONNECTED);
  5337. +       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5338. +   }
  5339. +
  5340. +   had_stream->stream_type = HAD_INIT;
  5341. +   spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5342. +   kfree(intelhaddata->chmap->chmap);
  5343. +   intelhaddata->chmap->chmap = NULL;
  5344. +   intelhaddata->audio_reg_base = 0;
  5345. +   pr_debug("%s: unlocked -> returned\n", __func__);
  5346. +
  5347. +   return retval;
  5348. +}
  5349. +
  5350. +/**
  5351. + * had_event_handler - Call back function to handle events
  5352. + *
  5353. + * @event_type: Event type to handle
  5354. + * @data: data related to the event_type
  5355. + *
  5356. + * This function is invoked to handle HDMI events from client driver.
  5357. + */
  5358. +int had_event_handler(enum had_event_type event_type, void *data)
  5359. +{
  5360. +   int retval = 0;
  5361. +   struct snd_intelhad *intelhaddata = data;
  5362. +   enum intel_had_aud_buf_type buf_id;
  5363. +   struct snd_pcm_substream *substream;
  5364. +   struct had_pvt_data *had_stream;
  5365. +   unsigned long flag_irqs;
  5366. +
  5367. +   buf_id = intelhaddata->curr_buf;
  5368. +   had_stream = intelhaddata->private_data;
  5369. +
  5370. +   /* Switching to a function can drop atomicity even in INTR context.
  5371. +    * Thus, a big lock is acquired to maintain atomicity.
  5372. +    * This can be optimized later.
  5373. +    * Currently, only buffer_done/_underrun executes in INTR context.
  5374. +    * Also, locking is implemented separately to avoid real contention
  5375. +    * of data(struct intelhaddata) between IRQ/SOFT_IRQ/PROCESS context.
  5376. +    */
  5377. +   substream = intelhaddata->stream_info.had_substream;
  5378. +   switch (event_type) {
  5379. +   case HAD_EVENT_AUDIO_BUFFER_DONE:
  5380. +       retval = had_process_buffer_done(intelhaddata);
  5381. +   break;
  5382. +
  5383. +   case HAD_EVENT_AUDIO_BUFFER_UNDERRUN:
  5384. +       retval = had_process_buffer_underrun(intelhaddata);
  5385. +   break;
  5386. +
  5387. +   case HAD_EVENT_HOT_PLUG:
  5388. +       retval = had_process_hot_plug(intelhaddata);
  5389. +   break;
  5390. +
  5391. +   case HAD_EVENT_HOT_UNPLUG:
  5392. +       retval = had_process_hot_unplug(intelhaddata);
  5393. +   break;
  5394. +
  5395. +   case HAD_EVENT_MODE_CHANGING:
  5396. +       pr_debug(" called _event_handler with _MODE_CHANGE event\n");
  5397. +       /* Process only if stream is active & cable Plugged-in */
  5398. +       spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs);
  5399. +       if (intelhaddata->drv_status >= HAD_DRV_DISCONNECTED) {
  5400. +           spin_unlock_irqrestore(&intelhaddata->had_spinlock,
  5401. +                   flag_irqs);
  5402. +           break;
  5403. +       }
  5404. +       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs);
  5405. +       if ((had_stream->stream_type == HAD_RUNNING_STREAM)
  5406. +               && substream)
  5407. +           retval = hdmi_audio_mode_change(substream);
  5408. +   break;
  5409. +
  5410. +   default:
  5411. +       pr_debug("error un-handled event !!\n");
  5412. +       retval = -EINVAL;
  5413. +   break;
  5414. +
  5415. +   }
  5416. +   return retval;
  5417. +}
  5418.  
  5419. From 62d0281f3f491572b2426e66c31184394b31a1bd Mon Sep 17 00:00:00 2001
  5420. From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  5421. Date: Sat, 20 Feb 2016 18:08:41 -0600
  5422. Subject: [PATCH 08/12] add dependency on PM_RUNTIME
  5423.  
  5424. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  5425. ---
  5426.  sound/Kconfig | 1 +
  5427.  1 file changed, 1 insertion(+)
  5428.  
  5429. diff --git a/sound/Kconfig b/sound/Kconfig
  5430. index 75c679e..b8b4fce 100644
  5431. --- a/sound/Kconfig
  5432. +++ b/sound/Kconfig
  5433. @@ -138,6 +138,7 @@ config AC97_BUS
  5434.  config SUPPORT_HDMI
  5435.          bool "SUPPORT_HDMI"
  5436.          depends on DRM_I915
  5437. +   select PM_RUNTIME
  5438.          default n
  5439.          help
  5440.            Choose this option to support HDMI.
  5441.  
  5442. From 9302f62e2eb342f57f3d79ebf5b3b890619b9ce9 Mon Sep 17 00:00:00 2001
  5443. From: David Henningsson <david.henningsson@canonical.com>
  5444. Date: Fri, 21 Aug 2015 11:08:47 +0200
  5445. Subject: [PATCH 09/12] hdmi_audio: Improve position reporting
  5446.  
  5447. Using a hw register to calculate sub-period position reports.
  5448.  
  5449. This makes PulseAudio happier.
  5450.  
  5451. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
  5452. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  5453. ---
  5454.  sound/hdmi_audio/intel_mid_hdmi_audio.c | 12 +++++++++++-
  5455.  1 file changed, 11 insertions(+), 1 deletion(-)
  5456.  
  5457. diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5458. index d8c5574..b2337c3 100644
  5459. --- a/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5460. +++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5461. @@ -1550,6 +1550,8 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer(
  5462.  {
  5463.     struct snd_intelhad *intelhaddata;
  5464.     u32 bytes_rendered = 0;
  5465. +   u32 t;
  5466. +   int buf_id;
  5467.  
  5468.     /* pr_debug("snd_intelhad_pcm_pointer called\n"); */
  5469.  
  5470. @@ -1560,6 +1562,14 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer(
  5471.         return SNDRV_PCM_POS_XRUN;
  5472.     }
  5473.  
  5474. +   buf_id = intelhaddata->curr_buf % 4;
  5475. +   had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t);
  5476. +   if (t == 0) {
  5477. +       pr_debug("discovered buffer done for buf %d\n", buf_id);
  5478. +       /* had_process_buffer_done(intelhaddata); */
  5479. +   }
  5480. +   t = intelhaddata->buf_info[buf_id].buf_size - t;
  5481. +
  5482.     if (intelhaddata->stream_info.buffer_rendered)
  5483.         div_u64_rem(intelhaddata->stream_info.buffer_rendered,
  5484.             intelhaddata->stream_info.ring_buf_size,
  5485. @@ -1567,7 +1577,7 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer(
  5486.  
  5487.     intelhaddata->stream_info.buffer_ptr = bytes_to_frames(
  5488.                         substream->runtime,
  5489. -                       bytes_rendered);
  5490. +                       bytes_rendered + t);
  5491.     return intelhaddata->stream_info.buffer_ptr;
  5492.  }
  5493.  
  5494.  
  5495. From da71a0a7f01f07365a1e0c927625e5507aee32a7 Mon Sep 17 00:00:00 2001
  5496. From: David Henningsson <david.henningsson@canonical.com>
  5497. Date: Fri, 21 Aug 2015 11:18:19 +0200
  5498. Subject: [PATCH 10/12] hdmi_audio: Fixup some monitor
  5499.  
  5500. I think this change was given to us, and they claimed it fixed an issue
  5501. on some monitor brand. I'm not sure what this patch actually does.
  5502.  
  5503. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
  5504. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  5505. ---
  5506.  sound/hdmi_audio/intel_mid_hdmi_audio.c | 5 +++--
  5507.  1 file changed, 3 insertions(+), 2 deletions(-)
  5508.  
  5509. diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5510. index b2337c3..1667748 100644
  5511. --- a/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5512. +++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5513. @@ -386,6 +386,7 @@ static void snd_intelhad_reset_audio_v2(u8 reset)
  5514.  static int had_prog_status_reg(struct snd_pcm_substream *substream,
  5515.             struct snd_intelhad *intelhaddata)
  5516.  {
  5517. +   union aud_cfg cfg_val = {.cfg_regval = 0};
  5518.     union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0};
  5519.     union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0};
  5520.     int format;
  5521. @@ -396,6 +397,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream,
  5522.                         IEC958_AES0_NONAUDIO)>>1;
  5523.     ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits &
  5524.                         IEC958_AES3_CON_CLOCK)>>4;
  5525. +   cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id;
  5526. +
  5527.     switch (substream->runtime->rate) {
  5528.     case AUD_SAMPLE_RATE_32:
  5529.         ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ;
  5530. @@ -474,7 +477,6 @@ int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream,
  5531.     else
  5532.         cfg_val.cfg_regx_v2.layout = LAYOUT1;
  5533.  
  5534. -   cfg_val.cfg_regx_v2.val_bit = 1;
  5535.     had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
  5536.     return 0;
  5537.  }
  5538. @@ -530,7 +532,6 @@ int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream,
  5539.  
  5540.     }
  5541.  
  5542. -   cfg_val.cfg_regx.val_bit = 1;
  5543.     had_write_register(AUD_CONFIG, cfg_val.cfg_regval);
  5544.     return 0;
  5545.  }
  5546.  
  5547. From 2c20a521494d0b547282d0fb7d9b7d8ad84dbc81 Mon Sep 17 00:00:00 2001
  5548. From: Toyo Abe <toyo.abe@gmail.com>
  5549. Date: Thu, 3 Mar 2016 12:57:41 +0900
  5550. Subject: [PATCH 11/12] hdmi_audio: Fix mishandling of AUD_HDMI_STATUS_v2
  5551.  register.
  5552.  
  5553. According to the datasheet, write one to clear these UNDERRUN flag bits.
  5554. This fixes the following warning in dmesg.
  5555.  
  5556. [15357.574902] had: Unable to clear UNDERRUN bits
  5557.  
  5558. Signed-off-by: Toyo Abe <toyo.abe@gmail.com>
  5559. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  5560. ---
  5561.  sound/hdmi_audio/intel_mid_hdmi_audio.c | 1 -
  5562.  1 file changed, 1 deletion(-)
  5563.  
  5564. diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5565. index 1667748..86db38e 100644
  5566. --- a/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5567. +++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5568. @@ -1135,7 +1135,6 @@ static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata)
  5569.         pr_debug("HDMI status =0x%x\n", hdmi_status);
  5570.         if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) {
  5571.             i++;
  5572. -           hdmi_status &= ~AUD_CONFIG_MASK_UNDERRUN;
  5573.             had_write_register(AUD_HDMI_STATUS_v2, hdmi_status);
  5574.         } else
  5575.             break;
  5576.  
  5577. From 2b24782107f1ad3a2522fd172e847686c337202b Mon Sep 17 00:00:00 2001
  5578. From: Jerome Anand <jerome.anand@intel.com>
  5579. Date: Fri, 1 Apr 2016 11:07:48 +0530
  5580. Subject: [PATCH 12/12] Create a platform device for hdmi audio driver and
  5581.  allocate full resources
  5582.  
  5583. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
  5584. ---
  5585.  sound/hdmi_audio/intel_mid_hdmi_audio.c | 22 +++++++++++++++++++---
  5586.  1 file changed, 19 insertions(+), 3 deletions(-)
  5587.  
  5588. diff --git a/sound/hdmi_audio/intel_mid_hdmi_audio.c b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5589. index 86db38e..6497b6f 100644
  5590. --- a/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5591. +++ b/sound/hdmi_audio/intel_mid_hdmi_audio.c
  5592. @@ -47,6 +47,8 @@ static int hdmi_card_index = SNDRV_DEFAULT_IDX1;
  5593.  static char *hdmi_card_id = SNDRV_DEFAULT_STR1;
  5594.  static struct snd_intelhad *had_data;
  5595.  
  5596. +struct platform_device *gpdev;
  5597. +
  5598.  module_param(hdmi_card_index, int, 0444);
  5599.  MODULE_PARM_DESC(hdmi_card_index,
  5600.         "Index value for INTEL Intel HDMI Audio controller.");
  5601. @@ -1481,9 +1483,9 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
  5602.     }
  5603.  
  5604.     pr_debug("period_size=%d\n",
  5605. -               frames_to_bytes(runtime, runtime->period_size));
  5606. +               (int)frames_to_bytes(runtime, runtime->period_size));
  5607.     pr_debug("periods=%d\n", runtime->periods);
  5608. -   pr_debug("buffer_size=%d\n", snd_pcm_lib_buffer_bytes(substream));
  5609. +   pr_debug("buffer_size=%d\n", (int)snd_pcm_lib_buffer_bytes(substream));
  5610.     pr_debug("rate=%d\n", runtime->rate);
  5611.     pr_debug("channels=%d\n", runtime->channels);
  5612.  
  5613. @@ -1997,10 +1999,16 @@ static struct platform_driver had_driver = {
  5614.  #ifdef CONFIG_PM
  5615.         .pm = &had_pm_ops,
  5616.  #endif
  5617. -       .acpi_match_table = ACPI_PTR(had_acpi_ids),
  5618. +       //.acpi_match_table = ACPI_PTR(had_acpi_ids),
  5619.     },
  5620.  };
  5621.  
  5622. +static const struct platform_device_info hdmi_audio_dev_info = {
  5623. +   .name = HDMI_AUDIO_DRIVER,
  5624. +   .id = -1,
  5625. +   .dma_mask = DMA_BIT_MASK(32),
  5626. +};
  5627. +
  5628.  /*
  5629.  * alsa_card_intelhad_init- driver init function
  5630.  * This function is called when driver module is inserted
  5631. @@ -2020,6 +2028,13 @@ static int __init alsa_card_intelhad_init(void)
  5632.         return retval;
  5633.     }
  5634.  
  5635. +   //gpdev = platform_device_register_simple(HDMI_AUDIO_DRIVER, -1, NULL, 0);
  5636. +   gpdev = platform_device_register_full(&hdmi_audio_dev_info);
  5637. +   if (!gpdev) {
  5638. +       pr_err("[jerome] Failed to register platform device \n");
  5639. +       return -1;
  5640. +   }
  5641. +
  5642.     pr_debug("init complete\n");
  5643.     return retval;
  5644.  }
  5645. @@ -2032,6 +2047,7 @@ static void __exit alsa_card_intelhad_exit(void)
  5646.  {
  5647.     pr_debug("had_exit called\n");
  5648.     platform_driver_unregister(&had_driver);
  5649. +   platform_device_unregister(gpdev);
  5650.  }
  5651.  late_initcall(alsa_card_intelhad_init);
  5652.  module_exit(alsa_card_intelhad_exit);
RAW Paste Data
Top