cx18-mailbox.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /*
  2. * cx18 mailbox functions
  3. *
  4. * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  19. * 02111-1307 USA
  20. */
  21. #include <stdarg.h>
  22. #include "cx18-driver.h"
  23. #include "cx18-scb.h"
  24. #include "cx18-irq.h"
  25. #include "cx18-mailbox.h"
  26. #define API_FAST (1 << 2) /* Short timeout */
  27. #define API_SLOW (1 << 3) /* Additional 300ms timeout */
  28. #define APU 0
  29. #define CPU 1
  30. #define EPU 2
  31. #define HPU 3
  32. struct cx18_api_info {
  33. u32 cmd;
  34. u8 flags; /* Flags, see above */
  35. u8 rpu; /* Processing unit */
  36. const char *name; /* The name of the command */
  37. };
  38. #define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x }
  39. static const struct cx18_api_info api_info[] = {
  40. /* MPEG encoder API */
  41. API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
  42. API_ENTRY(CPU, CX18_EPU_DEBUG, 0),
  43. API_ENTRY(CPU, CX18_CREATE_TASK, 0),
  44. API_ENTRY(CPU, CX18_DESTROY_TASK, 0),
  45. API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW),
  46. API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW),
  47. API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0),
  48. API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0),
  49. API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
  50. API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0),
  51. API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0),
  52. API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0),
  53. API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0),
  54. API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0),
  55. API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0),
  56. API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0),
  57. API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0),
  58. API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0),
  59. API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0),
  60. API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0),
  61. API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0),
  62. API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW),
  63. API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0),
  64. API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0),
  65. API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0),
  66. API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0),
  67. API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0),
  68. API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0),
  69. API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0),
  70. API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0),
  71. API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0),
  72. API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
  73. API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
  74. API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
  75. API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
  76. API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
  77. API_ENTRY(0, 0, 0),
  78. };
  79. static const struct cx18_api_info *find_api_info(u32 cmd)
  80. {
  81. int i;
  82. for (i = 0; api_info[i].cmd; i++)
  83. if (api_info[i].cmd == cmd)
  84. return &api_info[i];
  85. return NULL;
  86. }
  87. static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
  88. u32 *state, u32 *irq, u32 *req)
  89. {
  90. struct cx18_mailbox *mb = NULL;
  91. int wait_count = 0;
  92. u32 ack;
  93. switch (rpu) {
  94. case APU:
  95. mb = &cx->scb->epu2apu_mb;
  96. *state = readl(&cx->scb->apu_state);
  97. *irq = readl(&cx->scb->epu2apu_irq);
  98. break;
  99. case CPU:
  100. mb = &cx->scb->epu2cpu_mb;
  101. *state = readl(&cx->scb->cpu_state);
  102. *irq = readl(&cx->scb->epu2cpu_irq);
  103. break;
  104. case HPU:
  105. mb = &cx->scb->epu2hpu_mb;
  106. *state = readl(&cx->scb->hpu_state);
  107. *irq = readl(&cx->scb->epu2hpu_irq);
  108. break;
  109. }
  110. if (mb == NULL)
  111. return mb;
  112. do {
  113. *req = readl(&mb->request);
  114. ack = readl(&mb->ack);
  115. wait_count++;
  116. } while (*req != ack && wait_count < 600);
  117. if (*req == ack) {
  118. (*req)++;
  119. if (*req == 0 || *req == 0xffffffff)
  120. *req = 1;
  121. return mb;
  122. }
  123. return NULL;
  124. }
  125. long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
  126. {
  127. const struct cx18_api_info *info = find_api_info(mb->cmd);
  128. struct cx18_mailbox *ack_mb;
  129. u32 ack_irq;
  130. u8 rpu = CPU;
  131. if (info == NULL && mb->cmd) {
  132. CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
  133. return -EINVAL;
  134. }
  135. if (info)
  136. rpu = info->rpu;
  137. switch (rpu) {
  138. case HPU:
  139. ack_irq = IRQ_EPU_TO_HPU_ACK;
  140. ack_mb = &cx->scb->hpu2epu_mb;
  141. break;
  142. case APU:
  143. ack_irq = IRQ_EPU_TO_APU_ACK;
  144. ack_mb = &cx->scb->apu2epu_mb;
  145. break;
  146. case CPU:
  147. ack_irq = IRQ_EPU_TO_CPU_ACK;
  148. ack_mb = &cx->scb->cpu2epu_mb;
  149. break;
  150. default:
  151. CX18_WARN("Unknown RPU for command %x\n", mb->cmd);
  152. return -EINVAL;
  153. }
  154. setup_page(SCB_OFFSET);
  155. write_sync(mb->request, &ack_mb->ack);
  156. write_reg(ack_irq, SW2_INT_SET);
  157. return 0;
  158. }
  159. static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
  160. {
  161. const struct cx18_api_info *info = find_api_info(cmd);
  162. u32 state = 0, irq = 0, req, oldreq, err;
  163. struct cx18_mailbox *mb;
  164. wait_queue_head_t *waitq;
  165. int timeout = 100;
  166. int cnt = 0;
  167. int sig = 0;
  168. int i;
  169. if (info == NULL) {
  170. CX18_WARN("unknown cmd %x\n", cmd);
  171. return -EINVAL;
  172. }
  173. if (cmd == CX18_CPU_DE_SET_MDL)
  174. CX18_DEBUG_HI_API("%s\n", info->name);
  175. else
  176. CX18_DEBUG_API("%s\n", info->name);
  177. setup_page(SCB_OFFSET);
  178. mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
  179. if (mb == NULL) {
  180. CX18_ERR("mb %s busy\n", info->name);
  181. return -EBUSY;
  182. }
  183. oldreq = req - 1;
  184. writel(cmd, &mb->cmd);
  185. for (i = 0; i < args; i++)
  186. writel(data[i], &mb->args[i]);
  187. writel(0, &mb->error);
  188. writel(req, &mb->request);
  189. switch (info->rpu) {
  190. case APU: waitq = &cx->mb_apu_waitq; break;
  191. case CPU: waitq = &cx->mb_cpu_waitq; break;
  192. case EPU: waitq = &cx->mb_epu_waitq; break;
  193. case HPU: waitq = &cx->mb_hpu_waitq; break;
  194. default: return -EINVAL;
  195. }
  196. if (info->flags & API_FAST)
  197. timeout /= 2;
  198. write_reg(irq, SW1_INT_SET);
  199. while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) {
  200. if (cnt > 200 && !in_atomic())
  201. sig = cx18_msleep_timeout(10, 1);
  202. cnt++;
  203. }
  204. if (sig)
  205. return -EINTR;
  206. if (cnt == 660) {
  207. writel(oldreq, &mb->request);
  208. CX18_ERR("mb %s failed\n", info->name);
  209. return -EINVAL;
  210. }
  211. for (i = 0; i < MAX_MB_ARGUMENTS; i++)
  212. data[i] = readl(&mb->args[i]);
  213. err = readl(&mb->error);
  214. if (!in_atomic() && (info->flags & API_SLOW))
  215. cx18_msleep_timeout(300, 0);
  216. if (err)
  217. CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
  218. info->name);
  219. return err ? -EIO : 0;
  220. }
  221. int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
  222. {
  223. int res = cx18_api_call(cx, cmd, args, data);
  224. /* Allow a single retry, probably already too late though.
  225. If there is no free mailbox then that is usually an indication
  226. of a more serious problem. */
  227. return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res;
  228. }
  229. static int cx18_set_filter_param(struct cx18_stream *s)
  230. {
  231. struct cx18 *cx = s->cx;
  232. u32 mode;
  233. int ret;
  234. mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0);
  235. ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
  236. s->handle, 1, mode, cx->spatial_strength);
  237. mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0);
  238. ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
  239. s->handle, 0, mode, cx->temporal_strength);
  240. ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
  241. s->handle, 2, cx->filter_mode >> 2, 0);
  242. return ret;
  243. }
  244. int cx18_api_func(void *priv, u32 cmd, int in, int out,
  245. u32 data[CX2341X_MBOX_MAX_DATA])
  246. {
  247. struct cx18 *cx = priv;
  248. struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
  249. switch (cmd) {
  250. case CX2341X_ENC_SET_OUTPUT_PORT:
  251. return 0;
  252. case CX2341X_ENC_SET_FRAME_RATE:
  253. return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6,
  254. s->handle, 0, 0, 0, 0, data[0]);
  255. case CX2341X_ENC_SET_FRAME_SIZE:
  256. return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3,
  257. s->handle, data[1], data[0]);
  258. case CX2341X_ENC_SET_STREAM_TYPE:
  259. return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2,
  260. s->handle, data[0]);
  261. case CX2341X_ENC_SET_ASPECT_RATIO:
  262. return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2,
  263. s->handle, data[0]);
  264. case CX2341X_ENC_SET_GOP_PROPERTIES:
  265. return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3,
  266. s->handle, data[0], data[1]);
  267. case CX2341X_ENC_SET_GOP_CLOSURE:
  268. return 0;
  269. case CX2341X_ENC_SET_AUDIO_PROPERTIES:
  270. return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
  271. s->handle, data[0]);
  272. case CX2341X_ENC_MUTE_AUDIO:
  273. return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
  274. s->handle, data[0]);
  275. case CX2341X_ENC_SET_BIT_RATE:
  276. return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5,
  277. s->handle, data[0], data[1], data[2], data[3]);
  278. case CX2341X_ENC_MUTE_VIDEO:
  279. return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
  280. s->handle, data[0]);
  281. case CX2341X_ENC_SET_FRAME_DROP_RATE:
  282. return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2,
  283. s->handle, data[0]);
  284. case CX2341X_ENC_MISC:
  285. return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4,
  286. s->handle, data[0], data[1], data[2]);
  287. case CX2341X_ENC_SET_DNR_FILTER_MODE:
  288. cx->filter_mode = (data[0] & 3) | (data[1] << 2);
  289. return cx18_set_filter_param(s);
  290. case CX2341X_ENC_SET_DNR_FILTER_PROPS:
  291. cx->spatial_strength = data[0];
  292. cx->temporal_strength = data[1];
  293. return cx18_set_filter_param(s);
  294. case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
  295. return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3,
  296. s->handle, data[0], data[1]);
  297. case CX2341X_ENC_SET_CORING_LEVELS:
  298. return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5,
  299. s->handle, data[0], data[1], data[2], data[3]);
  300. }
  301. CX18_WARN("Unknown cmd %x\n", cmd);
  302. return 0;
  303. }
  304. int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS],
  305. u32 cmd, int args, ...)
  306. {
  307. va_list ap;
  308. int i;
  309. va_start(ap, args);
  310. for (i = 0; i < args; i++)
  311. data[i] = va_arg(ap, u32);
  312. va_end(ap);
  313. return cx18_api(cx, cmd, args, data);
  314. }
  315. int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...)
  316. {
  317. u32 data[MAX_MB_ARGUMENTS];
  318. va_list ap;
  319. int i;
  320. if (cx == NULL) {
  321. CX18_ERR("cx == NULL (cmd=%x)\n", cmd);
  322. return 0;
  323. }
  324. if (args > MAX_MB_ARGUMENTS) {
  325. CX18_ERR("args too big (cmd=%x)\n", cmd);
  326. args = MAX_MB_ARGUMENTS;
  327. }
  328. va_start(ap, args);
  329. for (i = 0; i < args; i++)
  330. data[i] = va_arg(ap, u32);
  331. va_end(ap);
  332. return cx18_api(cx, cmd, args, data);
  333. }