Guest User

Untitled

a guest
Apr 19th, 2016
4,886
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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×