cx18-mailbox.c 11 KB

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