patch_intelhdmi.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. *
  3. * patch_intelhdmi.c - Patch for Intel HDMI codecs
  4. *
  5. * Copyright(c) 2008 Intel Corporation. All rights reserved.
  6. *
  7. * Authors:
  8. * Jiang Zhe <zhe.jiang@intel.com>
  9. * Wu Fengguang <wfg@linux.intel.com>
  10. *
  11. * Maintained by:
  12. * Wu Fengguang <wfg@linux.intel.com>
  13. *
  14. * This program is free software; you can redistribute it and/or modify it
  15. * under the terms of the GNU General Public License as published by the Free
  16. * Software Foundation; either version 2 of the License, or (at your option)
  17. * any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful, but
  20. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  21. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  22. * for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software Foundation,
  26. * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  27. */
  28. #include <linux/init.h>
  29. #include <linux/delay.h>
  30. #include <linux/slab.h>
  31. #include <sound/core.h>
  32. #include "hda_codec.h"
  33. #include "hda_local.h"
  34. #include "hda_patch.h"
  35. #define CVT_NID 0x02 /* audio converter */
  36. #define PIN_NID 0x03 /* HDMI output pin */
  37. #define INTEL_HDMI_EVENT_TAG 0x08
  38. struct intel_hdmi_spec {
  39. struct hda_multi_out multiout;
  40. struct hda_pcm pcm_rec;
  41. struct sink_eld sink;
  42. };
  43. static struct hda_verb pinout_enable_verb[] = {
  44. {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
  45. {} /* terminator */
  46. };
  47. static struct hda_verb pinout_disable_verb[] = {
  48. {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},
  49. {}
  50. };
  51. static struct hda_verb unsolicited_response_verb[] = {
  52. {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN |
  53. INTEL_HDMI_EVENT_TAG},
  54. {}
  55. };
  56. static struct hda_verb def_chan_map[] = {
  57. {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00},
  58. {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11},
  59. {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22},
  60. {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33},
  61. {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44},
  62. {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55},
  63. {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66},
  64. {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77},
  65. {}
  66. };
  67. struct hdmi_audio_infoframe {
  68. u8 type; /* 0x84 */
  69. u8 ver; /* 0x01 */
  70. u8 len; /* 0x0a */
  71. u8 checksum; /* PB0 */
  72. u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */
  73. u8 SS01_SF24;
  74. u8 CXT04;
  75. u8 CA;
  76. u8 LFEPBL01_LSV36_DM_INH7;
  77. u8 reserved[5]; /* PB6 - PB10 */
  78. };
  79. /*
  80. * HDMI routines
  81. */
  82. #ifdef BE_PARANOID
  83. static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid,
  84. int *packet_index, int *byte_index)
  85. {
  86. int val;
  87. val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0);
  88. *packet_index = val >> 5;
  89. *byte_index = val & 0x1f;
  90. }
  91. #endif
  92. static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid,
  93. int packet_index, int byte_index)
  94. {
  95. int val;
  96. val = (packet_index << 5) | (byte_index & 0x1f);
  97. snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
  98. }
  99. static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid,
  100. unsigned char val)
  101. {
  102. snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
  103. }
  104. static void hdmi_enable_output(struct hda_codec *codec)
  105. {
  106. /* Enable Audio InfoFrame Transmission */
  107. hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
  108. snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
  109. AC_DIPXMIT_BEST);
  110. /* Unmute */
  111. if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
  112. snd_hda_codec_write(codec, PIN_NID, 0,
  113. AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
  114. /* Enable pin out */
  115. snd_hda_sequence_write(codec, pinout_enable_verb);
  116. }
  117. static void hdmi_disable_output(struct hda_codec *codec)
  118. {
  119. snd_hda_sequence_write(codec, pinout_disable_verb);
  120. if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
  121. snd_hda_codec_write(codec, PIN_NID, 0,
  122. AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
  123. /*
  124. * FIXME: noises may arise when playing music after reloading the
  125. * kernel module, until the next X restart or monitor repower.
  126. */
  127. }
  128. static int hdmi_get_channel_count(struct hda_codec *codec)
  129. {
  130. return 1 + snd_hda_codec_read(codec, CVT_NID, 0,
  131. AC_VERB_GET_CVT_CHAN_COUNT, 0);
  132. }
  133. static void hdmi_set_channel_count(struct hda_codec *codec, int chs)
  134. {
  135. snd_hda_codec_write(codec, CVT_NID, 0,
  136. AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
  137. if (chs != hdmi_get_channel_count(codec))
  138. snd_printd(KERN_INFO "Channel count expect=%d, real=%d\n",
  139. chs, hdmi_get_channel_count(codec));
  140. }
  141. static void hdmi_debug_slot_mapping(struct hda_codec *codec)
  142. {
  143. #ifdef CONFIG_SND_DEBUG_VERBOSE
  144. int i;
  145. int slot;
  146. for (i = 0; i < 8; i++) {
  147. slot = snd_hda_codec_read(codec, CVT_NID, 0,
  148. AC_VERB_GET_HDMI_CHAN_SLOT, i);
  149. printk(KERN_DEBUG "ASP channel %d => slot %d\n",
  150. slot >> 4, slot & 0x7);
  151. }
  152. #endif
  153. }
  154. static void hdmi_setup_channel_mapping(struct hda_codec *codec)
  155. {
  156. snd_hda_sequence_write(codec, def_chan_map);
  157. hdmi_debug_slot_mapping(codec);
  158. }
  159. static void hdmi_parse_eld(struct hda_codec *codec)
  160. {
  161. struct intel_hdmi_spec *spec = codec->spec;
  162. struct sink_eld *eld = &spec->sink;
  163. if (!snd_hdmi_get_eld(eld, codec, PIN_NID))
  164. snd_hdmi_show_eld(eld);
  165. }
  166. /*
  167. * Audio Infoframe routines
  168. */
  169. static void hdmi_debug_dip_size(struct hda_codec *codec)
  170. {
  171. #ifdef CONFIG_SND_DEBUG_VERBOSE
  172. int i;
  173. int size;
  174. size = snd_hdmi_get_eld_size(codec, PIN_NID);
  175. printk(KERN_DEBUG "ELD buf size is %d\n", size);
  176. for (i = 0; i < 8; i++) {
  177. size = snd_hda_codec_read(codec, PIN_NID, 0,
  178. AC_VERB_GET_HDMI_DIP_SIZE, i);
  179. printk(KERN_DEBUG "DIP GP[%d] buf size is %d\n", i, size);
  180. }
  181. #endif
  182. }
  183. static void hdmi_clear_dip_buffers(struct hda_codec *codec)
  184. {
  185. #ifdef BE_PARANOID
  186. int i, j;
  187. int size;
  188. int pi, bi;
  189. for (i = 0; i < 8; i++) {
  190. size = snd_hda_codec_read(codec, PIN_NID, 0,
  191. AC_VERB_GET_HDMI_DIP_SIZE, i);
  192. if (size == 0)
  193. continue;
  194. hdmi_set_dip_index(codec, PIN_NID, i, 0x0);
  195. for (j = 1; j < 1000; j++) {
  196. hdmi_write_dip_byte(codec, PIN_NID, 0x0);
  197. hdmi_get_dip_index(codec, PIN_NID, &pi, &bi);
  198. if (pi != i)
  199. snd_printd(KERN_INFO "dip index %d: %d != %d\n",
  200. bi, pi, i);
  201. if (bi == 0) /* byte index wrapped around */
  202. break;
  203. }
  204. snd_printd(KERN_INFO
  205. "DIP GP[%d] buf reported size=%d, written=%d\n",
  206. i, size, j);
  207. }
  208. #endif
  209. }
  210. static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
  211. struct snd_pcm_substream *substream)
  212. {
  213. struct hdmi_audio_infoframe audio_infoframe = {
  214. .type = 0x84,
  215. .ver = 0x01,
  216. .len = 0x0a,
  217. .CC02_CT47 = substream->runtime->channels - 1,
  218. };
  219. u8 *params = (u8 *)&audio_infoframe;
  220. int i;
  221. hdmi_debug_dip_size(codec);
  222. hdmi_clear_dip_buffers(codec); /* be paranoid */
  223. hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
  224. for (i = 0; i < sizeof(audio_infoframe); i++)
  225. hdmi_write_dip_byte(codec, PIN_NID, params[i]);
  226. }
  227. /*
  228. * Unsolicited events
  229. */
  230. static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
  231. {
  232. int pind = !!(res & AC_UNSOL_RES_PD);
  233. int eldv = !!(res & AC_UNSOL_RES_ELDV);
  234. printk(KERN_INFO "HDMI intrinsic event: PD=%d ELDV=%d\n", pind, eldv);
  235. if (pind && eldv) {
  236. hdmi_parse_eld(codec);
  237. /* TODO: do real things about ELD */
  238. }
  239. }
  240. static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
  241. {
  242. int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
  243. int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
  244. int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
  245. printk(KERN_INFO "HDMI non-intrinsic event: "
  246. "SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
  247. subtag,
  248. cp_state,
  249. cp_ready);
  250. /* who cares? */
  251. if (cp_state)
  252. ;
  253. if (cp_ready)
  254. ;
  255. }
  256. static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
  257. {
  258. int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
  259. int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
  260. if (tag != INTEL_HDMI_EVENT_TAG) {
  261. snd_printd(KERN_INFO
  262. "Unexpected HDMI unsolicited event tag 0x%x\n",
  263. tag);
  264. return;
  265. }
  266. if (subtag == 0)
  267. hdmi_intrinsic_event(codec, res);
  268. else
  269. hdmi_non_intrinsic_event(codec, res);
  270. }
  271. /*
  272. * Callbacks
  273. */
  274. static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo,
  275. struct hda_codec *codec,
  276. struct snd_pcm_substream *substream)
  277. {
  278. struct intel_hdmi_spec *spec = codec->spec;
  279. return snd_hda_multi_out_dig_open(codec, &spec->multiout);
  280. }
  281. static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo,
  282. struct hda_codec *codec,
  283. struct snd_pcm_substream *substream)
  284. {
  285. struct intel_hdmi_spec *spec = codec->spec;
  286. hdmi_disable_output(codec);
  287. return snd_hda_multi_out_dig_close(codec, &spec->multiout);
  288. }
  289. static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
  290. struct hda_codec *codec,
  291. unsigned int stream_tag,
  292. unsigned int format,
  293. struct snd_pcm_substream *substream)
  294. {
  295. struct intel_hdmi_spec *spec = codec->spec;
  296. snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
  297. format, substream);
  298. hdmi_set_channel_count(codec, substream->runtime->channels);
  299. /* wfg: channel mapping not supported by DEVCTG */
  300. hdmi_setup_channel_mapping(codec);
  301. hdmi_setup_audio_infoframe(codec, substream);
  302. hdmi_enable_output(codec);
  303. return 0;
  304. }
  305. static struct hda_pcm_stream intel_hdmi_pcm_playback = {
  306. .substreams = 1,
  307. .channels_min = 2,
  308. .channels_max = 8,
  309. .nid = CVT_NID, /* NID to query formats and rates and setup streams */
  310. .ops = {
  311. .open = intel_hdmi_playback_pcm_open,
  312. .close = intel_hdmi_playback_pcm_close,
  313. .prepare = intel_hdmi_playback_pcm_prepare
  314. },
  315. };
  316. static int intel_hdmi_build_pcms(struct hda_codec *codec)
  317. {
  318. struct intel_hdmi_spec *spec = codec->spec;
  319. struct hda_pcm *info = &spec->pcm_rec;
  320. codec->num_pcms = 1;
  321. codec->pcm_info = info;
  322. info->name = "INTEL HDMI";
  323. info->pcm_type = HDA_PCM_TYPE_HDMI;
  324. info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback;
  325. return 0;
  326. }
  327. static int intel_hdmi_build_controls(struct hda_codec *codec)
  328. {
  329. struct intel_hdmi_spec *spec = codec->spec;
  330. int err;
  331. err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
  332. if (err < 0)
  333. return err;
  334. return 0;
  335. }
  336. static int intel_hdmi_init(struct hda_codec *codec)
  337. {
  338. /* disable audio output as early as possible */
  339. hdmi_disable_output(codec);
  340. snd_hda_sequence_write(codec, unsolicited_response_verb);
  341. return 0;
  342. }
  343. static void intel_hdmi_free(struct hda_codec *codec)
  344. {
  345. kfree(codec->spec);
  346. }
  347. static struct hda_codec_ops intel_hdmi_patch_ops = {
  348. .init = intel_hdmi_init,
  349. .free = intel_hdmi_free,
  350. .build_pcms = intel_hdmi_build_pcms,
  351. .build_controls = intel_hdmi_build_controls,
  352. .unsol_event = intel_hdmi_unsol_event,
  353. };
  354. static int patch_intel_hdmi(struct hda_codec *codec)
  355. {
  356. struct intel_hdmi_spec *spec;
  357. spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  358. if (spec == NULL)
  359. return -ENOMEM;
  360. spec->multiout.num_dacs = 0; /* no analog */
  361. spec->multiout.max_channels = 8;
  362. spec->multiout.dig_out_nid = CVT_NID;
  363. codec->spec = spec;
  364. codec->patch_ops = intel_hdmi_patch_ops;
  365. snd_hda_eld_proc_new(codec, &spec->sink);
  366. return 0;
  367. }
  368. struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
  369. { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi },
  370. { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi },
  371. { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi },
  372. { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi },
  373. { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
  374. {} /* terminator */
  375. };