cx18-mailbox.c 11 KB

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