tsync.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. #include <linux/module.h>
  2. #include <linux/spinlock.h>
  3. #include <linux/kernel.h>
  4. #include <linux/platform_device.h>
  5. #include <linux/amports/timestamp.h>
  6. #include <linux/amports/tsync.h>
  7. #include <linux/amports/ptsserv.h>
  8. #include "vdec_reg.h"
  9. #include "amvdec.h"
  10. #ifdef CONFIG_ARCH_MESON6
  11. //TODO: for stream buffer register bit define only
  12. #include "streambuf_reg.h"
  13. #endif
  14. #ifdef ARC_700
  15. #include <asm/arch/am_regs.h>
  16. #else
  17. #include <mach/am_regs.h>
  18. #endif
  19. #if !defined(CONFIG_PREEMPT)
  20. #define CONFIG_AM_TIMESYNC_LOG
  21. #endif
  22. #ifdef CONFIG_AM_TIMESYNC_LOG
  23. #define AMLOG
  24. #define LOG_LEVEL_ERROR 0
  25. #define LOG_LEVEL_ATTENTION 1
  26. #define LOG_LEVEL_INFO 2
  27. #define LOG_LEVEL_VAR amlog_level_tsync
  28. #define LOG_MASK_VAR amlog_mask_tsync
  29. #endif
  30. #include <linux/amlog.h>
  31. MODULE_AMLOG(AMLOG_DEFAULT_LEVEL, 0, LOG_DEFAULT_LEVEL_DESC, LOG_DEFAULT_MASK_DESC);
  32. //#define DEBUG
  33. #define AVEVENT_FLAG_PARAM 0x01
  34. //#define TSYNC_SLOW_SYNC
  35. #define PCR_CHECK_INTERVAL (HZ * 5)
  36. #define PCR_DETECT_MARGIN_SHIFT_AUDIO_HI 7
  37. #define PCR_DETECT_MARGIN_SHIFT_AUDIO_LO 7
  38. #define PCR_DETECT_MARGIN_SHIFT_VIDEO_HI 4
  39. #define PCR_DETECT_MARGIN_SHIFT_VIDEO_LO 4
  40. #define PCR_MAINTAIN_MARGIN_SHIFT_AUDIO 4
  41. #define PCR_MAINTAIN_MARGIN_SHIFT_VIDEO 1
  42. #define PCR_RECOVER_PCR_ADJ 15
  43. enum {
  44. PCR_SYNC_UNSET,
  45. PCR_SYNC_HI,
  46. PCR_SYNC_LO,
  47. };
  48. enum {
  49. PCR_TRIGGER_AUDIO,
  50. PCR_TRIGGER_VIDEO
  51. };
  52. typedef enum {
  53. TSYNC_STAT_PCRSCR_SETUP_NONE,
  54. TSYNC_STAT_PCRSCR_SETUP_VIDEO,
  55. TSYNC_STAT_PCRSCR_SETUP_AUDIO
  56. } tsync_stat_t;
  57. enum {
  58. TOGGLE_MODE_FIXED = 0, // Fixed: use the Nominal M/N values
  59. TOGGLE_MODE_NORMAL_LOW, // Toggle between the Nominal M/N values and the Low M/N values
  60. TOGGLE_MODE_NORMAL_HIGH, // Toggle between the Nominal M/N values and the High M/N values
  61. TOGGLE_MODE_LOW_HIGH, // Toggle between the Low M/N values and the High M/N Values
  62. };
  63. const static struct {
  64. const char *token;
  65. const u32 token_size;
  66. const avevent_t event;
  67. const u32 flag;
  68. } avevent_token[] = {
  69. {"VIDEO_START", 11, VIDEO_START, AVEVENT_FLAG_PARAM},
  70. {"VIDEO_STOP", 10, VIDEO_STOP, 0},
  71. {"VIDEO_PAUSE", 11, VIDEO_PAUSE, AVEVENT_FLAG_PARAM},
  72. {"VIDEO_TSTAMP_DISCONTINUITY", 26, VIDEO_TSTAMP_DISCONTINUITY, AVEVENT_FLAG_PARAM},
  73. {"AUDIO_START", 11, AUDIO_START, AVEVENT_FLAG_PARAM},
  74. {"AUDIO_RESUME", 12, AUDIO_RESUME, 0},
  75. {"AUDIO_STOP", 10, AUDIO_STOP, 0},
  76. {"AUDIO_PAUSE", 11, AUDIO_PAUSE, 0},
  77. {"AUDIO_TSTAMP_DISCONTINUITY", 26, AUDIO_TSTAMP_DISCONTINUITY, AVEVENT_FLAG_PARAM},
  78. };
  79. const static char *tsync_mode_str[] = {
  80. "vmaster", "amaster"
  81. };
  82. static DEFINE_SPINLOCK(lock);
  83. static tsync_mode_t tsync_mode = TSYNC_MODE_AMASTER;
  84. static tsync_stat_t tsync_stat = TSYNC_STAT_PCRSCR_SETUP_NONE;
  85. static int tsync_enable = 0; //1;
  86. static int apts_discontinue = 0;
  87. static int vpts_discontinue = 0;
  88. static int pts_discontinue = 0;
  89. static int tsync_abreak = 0;
  90. static bool tsync_pcr_recover_enable = false;
  91. static int pcr_sync_stat = PCR_SYNC_UNSET;
  92. static int pcr_recover_trigger = 0;
  93. static struct timer_list tsync_pcr_recover_timer;
  94. static int tsync_trickmode = 0;
  95. static int vpause_flag = 0;
  96. static unsigned int tsync_av_thresh = AV_DISCONTINUE_THREDHOLD;
  97. static unsigned int tsync_syncthresh = 1;
  98. static int tsync_dec_reset_flag = 0;
  99. static int tsync_dec_reset_video_start = 0;
  100. #define M_HIGH_DIFF 2
  101. #define M_LOW_DIFF 2
  102. #define PLL_FACTOR 10000
  103. #define LOW_TOGGLE_TIME 99
  104. #define NORMAL_TOGGLE_TIME 499
  105. #define HIGH_TOGGLE_TIME 99
  106. #define PTS_CACHED_LO_NORMAL_TIME (90000)
  107. #define PTS_CACHED_NORMAL_LO_TIME (45000)
  108. #define PTS_CACHED_HI_NORMAL_TIME (135000)
  109. #define PTS_CACHED_NORMAL_HI_TIME (180000)
  110. #ifdef MODIFY_TIMESTAMP_INC_WITH_PLL
  111. extern void set_timestamp_inc_factor(u32 factor);
  112. #endif
  113. #ifdef CALC_CACHED_TIME
  114. extern int pts_cached_time(u8 type);
  115. #endif
  116. static void tsync_pcr_recover_with_audio(void)
  117. {
  118. #ifndef CONFIG_ARCH_MESON6
  119. u32 ab_level = READ_MPEG_REG(AIU_MEM_AIFIFO_LEVEL);
  120. u32 ab_size = READ_MPEG_REG(AIU_MEM_AIFIFO_END_PTR)
  121. - READ_MPEG_REG(AIU_MEM_AIFIFO_START_PTR) + 8;
  122. u32 vb_level = READ_VREG(VLD_MEM_VIFIFO_LEVEL);
  123. u32 vb_size = READ_VREG(VLD_MEM_VIFIFO_END_PTR)
  124. - READ_VREG(VLD_MEM_VIFIFO_START_PTR) + 8;
  125. if ((READ_MPEG_REG(AIU_MEM_I2S_CONTROL) &
  126. (MEM_CTRL_EMPTY_EN | MEM_CTRL_EMPTY_EN)) == 0) {
  127. return;
  128. }
  129. //printk("ab_size:%d ab_level:%d vb_size:%d vb_level:%d\n", ab_size, ab_level, vb_size, vb_level);
  130. //printk("vpts diff %d apts diff %d vlevel %d alevel %d\n", pts_cached_time(PTS_TYPE_VIDEO), pts_cached_time(PTS_TYPE_AUDIO), vb_level, ab_level);
  131. if ((unlikely(pcr_sync_stat != PCR_SYNC_LO)) &&
  132. #ifndef CALC_CACHED_TIME
  133. ((ab_level < (ab_size >> PCR_DETECT_MARGIN_SHIFT_AUDIO_LO)) ||
  134. (vb_level < (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_LO)))
  135. #else
  136. (pts_cached_time(PTS_TYPE_VIDEO)<PTS_CACHED_NORMAL_LO_TIME) && (pts_cached_time(PTS_TYPE_AUDIO)<PTS_CACHED_NORMAL_LO_TIME)
  137. #endif
  138. ) {
  139. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) &
  140. (~((1 << 31) | (TOGGLE_MODE_LOW_HIGH << 28))));
  141. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) | (TOGGLE_MODE_NORMAL_LOW << 28));
  142. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) | (1 << 31));
  143. #ifdef MODIFY_TIMESTAMP_INC_WITH_PLL
  144. {
  145. u32 inc, M_nom, N_nom;
  146. M_nom = READ_MPEG_REG(HHI_AUD_PLL_CNTL) & 0x1ff;
  147. N_nom = (READ_MPEG_REG(HHI_AUD_PLL_CNTL) >> 9) & 0x1f;
  148. inc = (M_nom*(NORMAL_TOGGLE_TIME+1)+(M_nom-M_LOW_DIFF)*(LOW_TOGGLE_TIME+1))*PLL_FACTOR/((NORMAL_TOGGLE_TIME+LOW_TOGGLE_TIME+2)*M_nom);
  149. set_timestamp_inc_factor(inc);
  150. printk("pll low inc: %d factor: %d\n", inc, PLL_FACTOR);
  151. }
  152. #endif
  153. pcr_sync_stat = PCR_SYNC_LO;
  154. printk("pcr_sync_stat = PCR_SYNC_LO\n");
  155. if (ab_level < (ab_size >> PCR_DETECT_MARGIN_SHIFT_AUDIO_LO)) {
  156. pcr_recover_trigger |= (1 << PCR_TRIGGER_AUDIO);
  157. printk("audio: 0x%x < 0x%x, vb_level 0x%x\n", ab_level, (ab_size >> PCR_DETECT_MARGIN_SHIFT_AUDIO_LO), vb_level);
  158. }
  159. if (vb_level < (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_LO)) {
  160. pcr_recover_trigger |= (1 << PCR_TRIGGER_VIDEO);
  161. printk("video: 0x%x < 0x%x, ab_level 0x%x\n", vb_level, (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_LO), ab_level);
  162. }
  163. } else if ((unlikely(pcr_sync_stat != PCR_SYNC_HI)) &&
  164. #ifndef CALC_CACHED_TIME
  165. ((((ab_level + (ab_size >> PCR_DETECT_MARGIN_SHIFT_AUDIO_HI)) > ab_size) ||
  166. ((vb_level + (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_HI)) > vb_size)))
  167. #else
  168. ((pts_cached_time(PTS_TYPE_VIDEO)>=PTS_CACHED_NORMAL_HI_TIME) && (pts_cached_time(PTS_TYPE_AUDIO)>=PTS_CACHED_NORMAL_HI_TIME))
  169. #endif
  170. ) {
  171. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) &
  172. (~((1 << 31) | (TOGGLE_MODE_LOW_HIGH << 28))));
  173. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) | (TOGGLE_MODE_NORMAL_HIGH << 28));
  174. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) | (1 << 31));
  175. #ifdef MODIFY_TIMESTAMP_INC_WITH_PLL
  176. {
  177. u32 inc, M_nom, N_nom;
  178. M_nom = READ_MPEG_REG(HHI_AUD_PLL_CNTL) & 0x1ff;
  179. N_nom = (READ_MPEG_REG(HHI_AUD_PLL_CNTL) >> 9) & 0x1f;
  180. inc = (M_nom*(NORMAL_TOGGLE_TIME+1)+(M_nom+M_HIGH_DIFF)*(HIGH_TOGGLE_TIME+1))*PLL_FACTOR/((NORMAL_TOGGLE_TIME+HIGH_TOGGLE_TIME+2)*M_nom);
  181. set_timestamp_inc_factor(inc);
  182. printk("pll high inc: %d factor: %d\n", inc, PLL_FACTOR);
  183. }
  184. #endif
  185. pcr_sync_stat = PCR_SYNC_HI;
  186. printk("pcr_sync_stat = PCR_SYNC_HI\n");
  187. if ((ab_level + (ab_size >> PCR_DETECT_MARGIN_SHIFT_AUDIO_HI)) > ab_size) {
  188. pcr_recover_trigger |= (1 << PCR_TRIGGER_AUDIO);
  189. printk("audio: 0x%x+0x%x > 0x%x, vb_level 0x%x\n", ab_level, (ab_size >> PCR_DETECT_MARGIN_SHIFT_AUDIO_HI), ab_size, vb_level);
  190. }
  191. if ((vb_level + (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_HI)) > vb_size) {
  192. pcr_recover_trigger |= (1 << PCR_TRIGGER_VIDEO);
  193. printk("video: 0x%x+0x%x > 0x%x, ab_level 0x%x\n", vb_level, (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_HI), vb_size, ab_level);
  194. }
  195. } else if (
  196. ((pcr_sync_stat == PCR_SYNC_LO) &&
  197. #ifndef CALC_CACHED_TIME
  198. (((!(pcr_recover_trigger & (1 << PCR_TRIGGER_AUDIO))) || (ab_level > (ab_size >> PCR_MAINTAIN_MARGIN_SHIFT_AUDIO)))
  199. &&
  200. ((!(pcr_recover_trigger & (1 << PCR_TRIGGER_VIDEO))) || ((vb_level + (vb_size >> PCR_MAINTAIN_MARGIN_SHIFT_VIDEO)) > vb_size)))
  201. #else
  202. ((pts_cached_time(PTS_TYPE_VIDEO)>=PTS_CACHED_LO_NORMAL_TIME) || (pts_cached_time(PTS_TYPE_AUDIO)>=PTS_CACHED_LO_NORMAL_TIME))
  203. #endif
  204. )
  205. ||
  206. ((pcr_sync_stat == PCR_SYNC_HI) &&
  207. #ifndef CALC_CACHED_TIME
  208. ((!(pcr_recover_trigger & (1 << PCR_TRIGGER_AUDIO))) || ((ab_level + (ab_size >> PCR_MAINTAIN_MARGIN_SHIFT_AUDIO)) < ab_size))
  209. &&
  210. ((!(pcr_recover_trigger & (1 << PCR_TRIGGER_VIDEO))) || (vb_level < (vb_size >> PCR_MAINTAIN_MARGIN_SHIFT_VIDEO)))
  211. #else
  212. ((pts_cached_time(PTS_TYPE_VIDEO)<PTS_CACHED_HI_NORMAL_TIME) || (pts_cached_time(PTS_TYPE_AUDIO)<PTS_CACHED_HI_NORMAL_TIME))
  213. #endif
  214. )) {
  215. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) &
  216. (~((1 << 31) | (TOGGLE_MODE_LOW_HIGH << 28))));
  217. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) | (TOGGLE_MODE_FIXED << 28));
  218. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) | (1 << 31));
  219. #ifdef MODIFY_TIMESTAMP_INC_WITH_PLL
  220. {
  221. set_timestamp_inc_factor(PLL_FACTOR);
  222. printk("pll normal inc:%d\n", PLL_FACTOR);
  223. }
  224. #endif
  225. pcr_sync_stat = PCR_SYNC_UNSET;
  226. pcr_recover_trigger = 0;
  227. printk("pcr_sync_stat = PCR_SYNC_UNSET ab_level: 0x%x, vb_level: 0x%x\n", ab_level, vb_level);
  228. }
  229. #endif
  230. }
  231. static void tsync_pcr_recover_with_video(void)
  232. {
  233. u32 vb_level = READ_VREG(VLD_MEM_VIFIFO_LEVEL);
  234. u32 vb_size = READ_VREG(VLD_MEM_VIFIFO_END_PTR)
  235. - READ_VREG(VLD_MEM_VIFIFO_START_PTR) + 8;
  236. if (vb_level < (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_LO)) {
  237. timestamp_pcrscr_set_adj(-PCR_RECOVER_PCR_ADJ);
  238. printk(" timestamp_pcrscr_set_adj(-%d);\n", PCR_RECOVER_PCR_ADJ);
  239. } else if ((vb_level + (vb_size >> PCR_DETECT_MARGIN_SHIFT_VIDEO_HI)) > vb_size) {
  240. timestamp_pcrscr_set_adj(PCR_RECOVER_PCR_ADJ);
  241. printk(" timestamp_pcrscr_set_adj(%d);\n", PCR_RECOVER_PCR_ADJ);
  242. } else if ((vb_level > (vb_size >> PCR_MAINTAIN_MARGIN_SHIFT_VIDEO)) ||
  243. (vb_level < (vb_size - (vb_size >> PCR_MAINTAIN_MARGIN_SHIFT_VIDEO)))) {
  244. timestamp_pcrscr_set_adj(0);
  245. }
  246. }
  247. static bool tsync_pcr_recover_use_video(void)
  248. {
  249. /* This is just a hacking to use audio output enable
  250. * as the flag to check if this is a video only playback.
  251. * Such processing can not handle an audio output with a
  252. * mixer so audio playback has no direct relationship with
  253. * applications. TODO.
  254. */
  255. return ((READ_MPEG_REG(AIU_MEM_I2S_CONTROL) &
  256. (MEM_CTRL_EMPTY_EN | MEM_CTRL_EMPTY_EN)) == 0);
  257. }
  258. static void tsync_pcr_recover_timer_real(void)
  259. {
  260. ulong flags;
  261. spin_lock_irqsave(&lock, flags);
  262. if (tsync_pcr_recover_enable) {
  263. if (tsync_pcr_recover_use_video()) {
  264. tsync_pcr_recover_with_video();
  265. } else {
  266. timestamp_pcrscr_set_adj(0);
  267. tsync_pcr_recover_with_audio();
  268. }
  269. }
  270. spin_unlock_irqrestore(&lock, flags);
  271. }
  272. static void tsync_pcr_recover_timer_func(unsigned long arg)
  273. {
  274. tsync_pcr_recover_timer_real();
  275. tsync_pcr_recover_timer.expires = jiffies + PCR_CHECK_INTERVAL;
  276. add_timer(&tsync_pcr_recover_timer);
  277. }
  278. void tsync_avevent_locked(avevent_t event, u32 param)
  279. {
  280. u32 t;
  281. switch (event) {
  282. case VIDEO_START:
  283. if (tsync_enable) {
  284. tsync_mode = TSYNC_MODE_AMASTER;
  285. } else {
  286. tsync_mode = TSYNC_MODE_VMASTER;
  287. }
  288. if (tsync_dec_reset_flag) {
  289. tsync_dec_reset_video_start = 1;
  290. }
  291. #ifndef TSYNC_SLOW_SYNC
  292. if (tsync_stat == TSYNC_STAT_PCRSCR_SETUP_NONE)
  293. #endif
  294. {
  295. #ifndef TSYNC_SLOW_SYNC
  296. if (tsync_syncthresh && (tsync_mode == TSYNC_MODE_AMASTER)) {
  297. timestamp_pcrscr_set(param - VIDEO_HOLD_THRESHOLD);
  298. } else {
  299. timestamp_pcrscr_set(param);
  300. }
  301. #else
  302. timestamp_pcrscr_set(param);
  303. #endif
  304. tsync_stat = TSYNC_STAT_PCRSCR_SETUP_VIDEO;
  305. amlog_level(LOG_LEVEL_INFO, "vpts to scr, apts = 0x%x, vpts = 0x%x\n",
  306. timestamp_apts_get(),
  307. timestamp_vpts_get());
  308. }
  309. if (tsync_stat == TSYNC_STAT_PCRSCR_SETUP_AUDIO) {
  310. t = timestamp_pcrscr_get();
  311. if (abs(param - t) > tsync_av_thresh) {
  312. /* if this happens, then play */
  313. tsync_stat = TSYNC_STAT_PCRSCR_SETUP_VIDEO;
  314. timestamp_pcrscr_set(param);
  315. }
  316. }
  317. if (/*tsync_mode == TSYNC_MODE_VMASTER && */!vpause_flag) {
  318. timestamp_pcrscr_enable(1);
  319. }
  320. break;
  321. case VIDEO_STOP:
  322. tsync_stat = TSYNC_STAT_PCRSCR_SETUP_NONE;
  323. timestamp_vpts_set(0);
  324. timestamp_pcrscr_enable(0);
  325. break;
  326. /* Note:
  327. * Video and audio PTS discontinue happens typically with a loopback playback,
  328. * with same bit stream play in loop and PTS wrap back from start point.
  329. * When VIDEO_TSTAMP_DISCONTINUITY happens early, PCRSCR is set immedately to
  330. * make video still keep running in VMATSER mode. This mode is restored to
  331. * AMASTER mode when AUDIO_TSTAMP_DISCONTINUITY reports, or apts is close to
  332. * scr later.
  333. * When AUDIO_TSTAMP_DISCONTINUITY happens early, VMASTER mode is set to make
  334. * video still keep running w/o setting PCRSCR. This mode is restored to
  335. * AMASTER mode when VIDEO_TSTAMP_DISCONTINUITY reports, and scr is restored
  336. * along with new video time stamp also.
  337. */
  338. case VIDEO_TSTAMP_DISCONTINUITY:
  339. t = timestamp_pcrscr_get();
  340. if (abs(param - t) > AV_DISCONTINUE_THREDHOLD) {
  341. if ((tsync_mode == TSYNC_MODE_VMASTER) && (tsync_enable))
  342. /* restore to AMASTER mode when both video and audio
  343. * send discontinue event
  344. */
  345. {
  346. tsync_mode = TSYNC_MODE_AMASTER;
  347. } else
  348. /* make system time updated by itself. */
  349. {
  350. tsync_mode = TSYNC_MODE_VMASTER;
  351. }
  352. tsync_stat = TSYNC_STAT_PCRSCR_SETUP_VIDEO;
  353. timestamp_vpts_set(param);
  354. timestamp_pcrscr_set(param);
  355. vpts_discontinue = 1;
  356. printk("video pts discontinue, set pts_discontinue");
  357. amlog_level(LOG_LEVEL_ATTENTION, "reset scr from vpts to 0x%x\n", param);
  358. }
  359. break;
  360. case AUDIO_TSTAMP_DISCONTINUITY:
  361. timestamp_apts_set(param);
  362. amlog_level(LOG_LEVEL_ATTENTION, "audio discontinue, reset apts, 0x%x\n", param);
  363. if (!tsync_enable) {
  364. break;
  365. }
  366. t = timestamp_pcrscr_get();
  367. amlog_level(LOG_LEVEL_ATTENTION, "AUDIO_TSTAMP_DISCONTINUITY, 0x%x, 0x%x\n", t, param);
  368. if (abs(param - t) > AV_DISCONTINUE_THREDHOLD) {
  369. /* switch tsync mode to free run mode,
  370. * making system time updated by itself.
  371. */
  372. tsync_mode = TSYNC_MODE_VMASTER;
  373. timestamp_apts_set(param);
  374. apts_discontinue = 1;
  375. printk("audio pts discontinue, set pts_discontinue");
  376. amlog_level(LOG_LEVEL_ATTENTION, "apts interrupt: 0x%x\n", param);
  377. } else {
  378. tsync_mode = TSYNC_MODE_AMASTER;
  379. }
  380. break;
  381. case AUDIO_START:
  382. timestamp_apts_set(param);
  383. amlog_level(LOG_LEVEL_INFO, "audio start, reset apts = 0x%x\n", param);
  384. timestamp_apts_enable(1);
  385. if (!tsync_enable) {
  386. break;
  387. }
  388. t = timestamp_pcrscr_get();
  389. amlog_level(LOG_LEVEL_INFO, "[%s]param %d, t %d, tsync_abreak %d\n",
  390. __FUNCTION__, param, t, tsync_abreak);
  391. if (tsync_abreak && (abs(param - t) > TIME_UNIT90K / 10)) { // 100ms, then wait to match
  392. break;
  393. }
  394. tsync_abreak = 0;
  395. if (tsync_dec_reset_flag) { // after reset, video should be played first
  396. int vpts = timestamp_vpts_get();
  397. if ((param < vpts) || (!tsync_dec_reset_video_start)) {
  398. timestamp_pcrscr_set(param);
  399. } else {
  400. timestamp_pcrscr_set(vpts);
  401. }
  402. tsync_dec_reset_flag = 0;
  403. tsync_dec_reset_video_start = 0;
  404. } else {
  405. timestamp_pcrscr_set(param);
  406. }
  407. tsync_stat = TSYNC_STAT_PCRSCR_SETUP_AUDIO;
  408. amlog_level(LOG_LEVEL_INFO, "apts reset scr = 0x%x\n", param);
  409. timestamp_pcrscr_enable(1);
  410. break;
  411. case AUDIO_RESUME:
  412. timestamp_apts_enable(1);
  413. if (!tsync_enable) {
  414. break;
  415. }
  416. timestamp_pcrscr_enable(1);
  417. break;
  418. case AUDIO_STOP:
  419. timestamp_apts_enable(0);
  420. timestamp_apts_set(-1);
  421. tsync_abreak = 0;
  422. if (tsync_trickmode) {
  423. tsync_stat = TSYNC_STAT_PCRSCR_SETUP_VIDEO;
  424. } else {
  425. tsync_stat = TSYNC_STAT_PCRSCR_SETUP_NONE;
  426. }
  427. break;
  428. case AUDIO_PAUSE:
  429. timestamp_apts_enable(0);
  430. if (!tsync_enable) {
  431. break;
  432. }
  433. timestamp_pcrscr_enable(0);
  434. break;
  435. case VIDEO_PAUSE:
  436. if (param == 1) {
  437. vpause_flag = 1;
  438. } else {
  439. vpause_flag = 0;
  440. }
  441. if(param == 1){
  442. timestamp_pcrscr_enable(0);
  443. amlog_level(LOG_LEVEL_INFO, "video pause!\n");
  444. }else{
  445. timestamp_pcrscr_enable(1);
  446. amlog_level(LOG_LEVEL_INFO, "video resume\n");
  447. }
  448. break;
  449. default:
  450. break;
  451. }
  452. switch (event) {
  453. case VIDEO_START:
  454. case AUDIO_START:
  455. case AUDIO_RESUME:
  456. amvdev_resume();
  457. break;
  458. case VIDEO_STOP:
  459. case AUDIO_STOP:
  460. case AUDIO_PAUSE:
  461. amvdev_pause();
  462. break;
  463. case VIDEO_PAUSE:
  464. if (vpause_flag)
  465. amvdev_pause();
  466. else
  467. amvdev_resume();
  468. break;
  469. default:
  470. break;
  471. }
  472. }
  473. EXPORT_SYMBOL(tsync_avevent_locked);
  474. void tsync_avevent(avevent_t event, u32 param)
  475. {
  476. ulong flags;
  477. ulong fiq_flag;
  478. amlog_level(LOG_LEVEL_INFO, "[%s]event:%d, param %d\n",
  479. __FUNCTION__, event, param);
  480. spin_lock_irqsave(&lock, flags);
  481. raw_local_save_flags(fiq_flag);
  482. local_fiq_disable();
  483. tsync_avevent_locked(event, param);
  484. raw_local_irq_restore(fiq_flag);
  485. spin_unlock_irqrestore(&lock, flags);
  486. }
  487. EXPORT_SYMBOL(tsync_avevent);
  488. void tsync_audio_break(int audio_break)
  489. {
  490. tsync_abreak = audio_break;
  491. return;
  492. }
  493. EXPORT_SYMBOL(tsync_audio_break);
  494. void tsync_trick_mode(int trick_mode)
  495. {
  496. tsync_trickmode = trick_mode;
  497. return;
  498. }
  499. EXPORT_SYMBOL(tsync_trick_mode);
  500. void tsync_set_avthresh(unsigned int av_thresh)
  501. {
  502. tsync_av_thresh = av_thresh;
  503. return;
  504. }
  505. EXPORT_SYMBOL(tsync_set_avthresh);
  506. void tsync_set_syncthresh(unsigned int sync_thresh)
  507. {
  508. tsync_syncthresh = sync_thresh;
  509. return;
  510. }
  511. EXPORT_SYMBOL(tsync_set_syncthresh);
  512. void tsync_set_dec_reset(void)
  513. {
  514. tsync_dec_reset_flag = 1;
  515. }
  516. EXPORT_SYMBOL(tsync_set_dec_reset);
  517. void tsync_set_enable(int enable)
  518. {
  519. tsync_enable = enable;
  520. }
  521. EXPORT_SYMBOL(tsync_set_enable);
  522. int tsync_get_sync_adiscont(void)
  523. {
  524. return apts_discontinue;
  525. }
  526. EXPORT_SYMBOL(tsync_get_sync_adiscont);
  527. int tsync_get_sync_vdiscont(void)
  528. {
  529. return vpts_discontinue;
  530. }
  531. EXPORT_SYMBOL(tsync_get_sync_vdiscont);
  532. void tsync_set_sync_adiscont(int syncdiscont)
  533. {
  534. apts_discontinue = syncdiscont;
  535. }
  536. EXPORT_SYMBOL(tsync_set_sync_adiscont);
  537. void tsync_set_sync_vdiscont(int syncdiscont)
  538. {
  539. vpts_discontinue = syncdiscont;
  540. }
  541. EXPORT_SYMBOL(tsync_set_sync_vdiscont);
  542. int tsync_set_apts(unsigned pts)
  543. {
  544. unsigned t;
  545. //ssize_t r;
  546. timestamp_apts_set(pts);
  547. if (tsync_abreak) {
  548. tsync_abreak = 0;
  549. }
  550. if (!tsync_enable) {
  551. return 0;
  552. }
  553. t = timestamp_pcrscr_get();
  554. if (tsync_mode == TSYNC_MODE_AMASTER) {
  555. if (abs(pts - t) > tsync_av_thresh) {
  556. tsync_mode = TSYNC_MODE_VMASTER;
  557. amlog_level(LOG_LEVEL_INFO, "apts 0x%x shift scr 0x%x too much, switch to TSYNC_MODE_VMASTER\n",
  558. pts, t);
  559. } else {
  560. #ifndef USE_VMASTER_MODE
  561. timestamp_pcrscr_set(pts);
  562. #else
  563. if(!tsync_pcr_recover_enable){
  564. timestamp_pcrscr_set(pts);
  565. }
  566. #endif
  567. amlog_level(LOG_LEVEL_INFO, "apts set to scr 0x%x->0x%x\n", t, pts);
  568. }
  569. } else {
  570. if (abs(pts - t) <= tsync_av_thresh) {
  571. tsync_mode = TSYNC_MODE_AMASTER;
  572. amlog_level(LOG_LEVEL_INFO, "switch to TSYNC_MODE_AMASTER\n");
  573. timestamp_pcrscr_set(pts);
  574. }
  575. }
  576. return 0;
  577. }
  578. EXPORT_SYMBOL(tsync_set_apts);
  579. /*********************************************************/
  580. static ssize_t show_pcr_recover(struct class *class,
  581. struct class_attribute *attr,
  582. char *buf)
  583. {
  584. return sprintf(buf, "%s %s\n", ((tsync_pcr_recover_enable) ? "on" : "off"), ((pcr_sync_stat == PCR_SYNC_UNSET) ? ("UNSET") : ((pcr_sync_stat == PCR_SYNC_LO) ? "LO" : "HI")));
  585. }
  586. void tsync_pcr_recover(void)
  587. {
  588. #ifndef CONFIG_ARCH_MESON6
  589. unsigned long M_nom, N_nom;
  590. if (tsync_pcr_recover_enable) {
  591. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_LOW_TCNT, LOW_TOGGLE_TIME); // Set low toggle time (oscillator clock cycles)
  592. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_NOM_TCNT, NORMAL_TOGGLE_TIME); // Set nominal toggle time (oscillator clock cycles)
  593. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_HIGH_TCNT, HIGH_TOGGLE_TIME); // Set high toggle time (oscillator clock cycles)
  594. M_nom = READ_MPEG_REG(HHI_AUD_PLL_CNTL) & 0x1ff;
  595. N_nom = (READ_MPEG_REG(HHI_AUD_PLL_CNTL) >> 9) & 0x1f;
  596. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, (0 << 31) |
  597. (TOGGLE_MODE_FIXED << 28) | // Toggle mode
  598. (N_nom << 23) | // N high value (not used)
  599. ((M_nom + M_HIGH_DIFF) << 14) | // M high value
  600. (N_nom << 9) | // N low value (not used)
  601. ((M_nom - M_LOW_DIFF) << 0)); // M low value
  602. pcr_sync_stat = PCR_SYNC_UNSET;
  603. pcr_recover_trigger = 0;
  604. tsync_pcr_recover_timer_real();
  605. }
  606. #endif
  607. }
  608. EXPORT_SYMBOL(tsync_pcr_recover);
  609. static ssize_t store_pcr_recover(struct class *class,
  610. struct class_attribute *attr,
  611. const char *buf,
  612. size_t size)
  613. {
  614. #ifndef CONFIG_ARCH_MESON6
  615. unsigned val;
  616. unsigned long M_nom, N_nom;
  617. ssize_t r;
  618. r = sscanf(buf, "%d", &val);
  619. if (r != 1) {
  620. return -EINVAL;
  621. }
  622. if (tsync_pcr_recover_enable == (val != 0)) {
  623. return size;
  624. }
  625. tsync_pcr_recover_enable = (val != 0);
  626. if (tsync_pcr_recover_enable) {
  627. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_LOW_TCNT, LOW_TOGGLE_TIME); // Set low toggle time (oscillator clock cycles)
  628. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_NOM_TCNT, NORMAL_TOGGLE_TIME); // Set nominal toggle time (oscillator clock cycles)
  629. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_HIGH_TCNT, HIGH_TOGGLE_TIME); // Set high toggle time (oscillator clock cycles)
  630. M_nom = READ_MPEG_REG(HHI_AUD_PLL_CNTL) & 0x1ff;
  631. N_nom = (READ_MPEG_REG(HHI_AUD_PLL_CNTL) >> 9) & 0x1f;
  632. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, (0 << 31) |
  633. (TOGGLE_MODE_FIXED << 28) | // Toggle mode
  634. (N_nom << 23) | // N high value (not used)
  635. ((M_nom + M_HIGH_DIFF) << 14) | // M high value
  636. (N_nom << 9) | // N low value (not used)
  637. ((M_nom - M_LOW_DIFF) << 0)); // M low value
  638. pcr_sync_stat = PCR_SYNC_UNSET;
  639. pcr_recover_trigger = 0;
  640. tsync_pcr_recover_timer_real();
  641. } else {
  642. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) &
  643. (~((1 << 31) | (TOGGLE_MODE_LOW_HIGH << 28))));
  644. WRITE_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0, READ_MPEG_REG(HHI_AUD_PLL_MOD_CNTL0) | (TOGGLE_MODE_FIXED << 28));
  645. pcr_sync_stat = PCR_SYNC_UNSET;
  646. pcr_recover_trigger = 0;
  647. }
  648. #endif
  649. return size;
  650. }
  651. static ssize_t show_vpts(struct class *class,
  652. struct class_attribute *attr,
  653. char *buf)
  654. {
  655. return sprintf(buf, "0x%x\n", timestamp_vpts_get());
  656. }
  657. static ssize_t store_vpts(struct class *class,
  658. struct class_attribute *attr,
  659. const char *buf,
  660. size_t size)
  661. {
  662. unsigned pts;
  663. ssize_t r;
  664. r = sscanf(buf, "0x%x", &pts);
  665. if (r != 1) {
  666. return -EINVAL;
  667. }
  668. timestamp_vpts_set(pts);
  669. return size;
  670. }
  671. static ssize_t show_apts(struct class *class,
  672. struct class_attribute *attr,
  673. char *buf)
  674. {
  675. return sprintf(buf, "0x%x\n", timestamp_apts_get());
  676. }
  677. static ssize_t store_apts(struct class *class,
  678. struct class_attribute *attr,
  679. const char *buf,
  680. size_t size)
  681. {
  682. unsigned pts, t;
  683. ssize_t r;
  684. r = sscanf(buf, "0x%x", &pts);
  685. if (r != 1) {
  686. return -EINVAL;
  687. }
  688. timestamp_apts_set(pts);
  689. if (tsync_abreak) {
  690. tsync_abreak = 0;
  691. }
  692. if (!tsync_enable) {
  693. return size;
  694. }
  695. t = timestamp_pcrscr_get();
  696. if (tsync_mode == TSYNC_MODE_AMASTER) {
  697. if (abs(pts - t) > tsync_av_thresh) {
  698. tsync_mode = TSYNC_MODE_VMASTER;
  699. amlog_level(LOG_LEVEL_INFO, "apts 0x%x shift scr 0x%x too much, switch to TSYNC_MODE_VMASTER\n",
  700. pts, t);
  701. } else {
  702. #ifndef USE_VMASTER_MODE
  703. timestamp_pcrscr_set(pts);
  704. #else
  705. if(!tsync_pcr_recover_enable){
  706. timestamp_pcrscr_set(pts);
  707. }
  708. #endif
  709. amlog_level(LOG_LEVEL_INFO, "apts set to scr 0x%x->0x%x\n", t, pts);
  710. }
  711. } else {
  712. if (abs(pts - t) <= tsync_av_thresh) {
  713. tsync_mode = TSYNC_MODE_AMASTER;
  714. amlog_level(LOG_LEVEL_INFO, "switch to TSYNC_MODE_AMASTER\n");
  715. timestamp_pcrscr_set(pts);
  716. }
  717. }
  718. return size;
  719. }
  720. static ssize_t show_pcrscr(struct class *class,
  721. struct class_attribute *attr,
  722. char *buf)
  723. {
  724. return sprintf(buf, "0x%x\n", timestamp_pcrscr_get());
  725. }
  726. static ssize_t store_pcrscr(struct class *class,
  727. struct class_attribute *attr,
  728. const char *buf,
  729. size_t size)
  730. {
  731. unsigned pts;
  732. ssize_t r;
  733. r = sscanf(buf, "0x%x", &pts);
  734. if (r != 1) {
  735. return -EINVAL;
  736. }
  737. timestamp_pcrscr_set(pts);
  738. return size;
  739. }
  740. static ssize_t store_event(struct class *class,
  741. struct class_attribute *attr,
  742. const char *buf,
  743. size_t size)
  744. {
  745. int i;
  746. for (i = 0; i < ARRAY_SIZE(avevent_token); i++) {
  747. if (strncmp(avevent_token[i].token, buf, avevent_token[i].token_size) == 0) {
  748. if (avevent_token[i].flag & AVEVENT_FLAG_PARAM) {
  749. char *param_str = strchr(buf, ':');
  750. if (!param_str) {
  751. return -EINVAL;
  752. }
  753. tsync_avevent(avevent_token[i].event,
  754. simple_strtoul(param_str + 1, NULL, 16));
  755. } else {
  756. tsync_avevent(avevent_token[i].event, 0);
  757. }
  758. return size;
  759. }
  760. }
  761. return -EINVAL;
  762. }
  763. static ssize_t show_mode(struct class *class,
  764. struct class_attribute *attr,
  765. char *buf)
  766. {
  767. if (tsync_mode <= TSYNC_MODE_AMASTER) {
  768. return sprintf(buf, "%d: %s\n", tsync_mode, tsync_mode_str[tsync_mode]);
  769. }
  770. return sprintf(buf, "invalid mode");
  771. }
  772. static ssize_t show_enable(struct class *class,
  773. struct class_attribute *attr,
  774. char *buf)
  775. {
  776. if (tsync_enable) {
  777. return sprintf(buf, "1: enabled\n");
  778. }
  779. return sprintf(buf, "0: disabled\n");
  780. }
  781. static ssize_t store_enable(struct class *class,
  782. struct class_attribute *attr,
  783. const char *buf,
  784. size_t size)
  785. {
  786. unsigned mode;
  787. ssize_t r;
  788. r = sscanf(buf, "%d", &mode);
  789. if ((r != 1)) {
  790. return -EINVAL;
  791. }
  792. tsync_enable = mode ? 1 : 0;
  793. return size;
  794. }
  795. static ssize_t show_discontinue(struct class *class,
  796. struct class_attribute *attr,
  797. char *buf)
  798. {
  799. pts_discontinue = vpts_discontinue || apts_discontinue;
  800. if (pts_discontinue) {
  801. return sprintf(buf, "1: pts_discontinue\n");
  802. }
  803. return sprintf(buf, "0: pts_continue\n");
  804. }
  805. static ssize_t store_discontinue(struct class *class,
  806. struct class_attribute *attr,
  807. const char *buf,
  808. size_t size)
  809. {
  810. unsigned discontinue;
  811. ssize_t r;
  812. r = sscanf(buf, "%d", &discontinue);
  813. if ((r != 1)) {
  814. return -EINVAL;
  815. }
  816. pts_discontinue = discontinue ? 1 : 0;
  817. return size;
  818. }
  819. static struct class_attribute tsync_class_attrs[] = {
  820. __ATTR(pts_video, S_IRUGO | S_IWUSR, show_vpts, store_vpts),
  821. __ATTR(pts_audio, S_IRUGO | S_IWUSR, show_apts, store_apts),
  822. __ATTR(pts_pcrscr, S_IRUGO | S_IWUSR, show_pcrscr, store_pcrscr),
  823. __ATTR(event, S_IRUGO | S_IWUSR, NULL, store_event),
  824. __ATTR(mode, S_IRUGO | S_IWUSR, show_mode, NULL),
  825. __ATTR(enable, S_IRUGO | S_IWUSR, show_enable, store_enable),
  826. __ATTR(pcr_recover, S_IRUGO | S_IWUSR, show_pcr_recover, store_pcr_recover),
  827. __ATTR(discontinue, S_IRUGO | S_IWUSR, show_discontinue, store_discontinue),
  828. __ATTR_NULL
  829. };
  830. static struct class tsync_class = {
  831. .name = "tsync",
  832. .class_attrs = tsync_class_attrs,
  833. };
  834. static int __init tsync_init(void)
  835. {
  836. int r;
  837. r = class_register(&tsync_class);
  838. if (r) {
  839. amlog_level(LOG_LEVEL_ERROR, "tsync class create fail.\n");
  840. return r;
  841. }
  842. /* init audio pts to -1, others to 0 */
  843. timestamp_apts_set(-1);
  844. timestamp_vpts_set(0);
  845. timestamp_pcrscr_set(0);
  846. init_timer(&tsync_pcr_recover_timer);
  847. tsync_pcr_recover_timer.function = tsync_pcr_recover_timer_func;
  848. tsync_pcr_recover_timer.expires = jiffies + PCR_CHECK_INTERVAL;
  849. pcr_sync_stat = PCR_SYNC_UNSET;
  850. pcr_recover_trigger = 0;
  851. add_timer(&tsync_pcr_recover_timer);
  852. return (0);
  853. }
  854. static void __exit tsync_exit(void)
  855. {
  856. del_timer_sync(&tsync_pcr_recover_timer);
  857. class_unregister(&tsync_class);
  858. }
  859. module_init(tsync_init);
  860. module_exit(tsync_exit);
  861. MODULE_DESCRIPTION("AMLOGIC time sync management driver");
  862. MODULE_LICENSE("GPL");
  863. MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");