cfe_api.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2000, 2001, 2002 Broadcom Corporation
  4. */
  5. /*
  6. *
  7. * Broadcom Common Firmware Environment (CFE)
  8. *
  9. * This module contains device function stubs (small routines to
  10. * call the standard "iocb" interface entry point to CFE).
  11. * There should be one routine here per iocb function call.
  12. *
  13. * Authors: Mitch Lichtenberg, Chris Demetriou
  14. */
  15. #include <linux/init.h>
  16. #include <linux/kernel.h>
  17. #include <linux/printk.h>
  18. #include <asm/mipsregs.h>
  19. #include <asm/fw/cfe/cfe_api.h>
  20. #include "cfe_api_int.h"
  21. unsigned long __initdata cfe_seal;
  22. /* Cast from a native pointer to a cfe_xptr_t and back. */
  23. #define XPTR_FROM_NATIVE(n) ((cfe_xptr_t) (intptr_t) (n))
  24. #define NATIVE_FROM_XPTR(x) ((void *) (intptr_t) (x))
  25. int cfe_iocb_dispatch(struct cfe_xiocb *xiocb);
  26. /*
  27. * Declare the dispatch function with args of "intptr_t".
  28. * This makes sure whatever model we're compiling in
  29. * puts the pointers in a single register. For example,
  30. * combining -mlong64 and -mips1 or -mips2 would lead to
  31. * trouble, since the handle and IOCB pointer will be
  32. * passed in two registers each, and CFE expects one.
  33. */
  34. static int (*cfe_dispfunc) (intptr_t handle, intptr_t xiocb);
  35. static u64 cfe_handle;
  36. int cfe_init(u64 handle, u64 ept)
  37. {
  38. cfe_dispfunc = NATIVE_FROM_XPTR(ept);
  39. cfe_handle = handle;
  40. return 0;
  41. }
  42. int cfe_iocb_dispatch(struct cfe_xiocb * xiocb)
  43. {
  44. if (!cfe_dispfunc)
  45. return -1;
  46. return (*cfe_dispfunc) ((intptr_t) cfe_handle, (intptr_t) xiocb);
  47. }
  48. int cfe_close(int handle)
  49. {
  50. struct cfe_xiocb xiocb;
  51. xiocb.xiocb_fcode = CFE_CMD_DEV_CLOSE;
  52. xiocb.xiocb_status = 0;
  53. xiocb.xiocb_handle = handle;
  54. xiocb.xiocb_flags = 0;
  55. xiocb.xiocb_psize = 0;
  56. cfe_iocb_dispatch(&xiocb);
  57. return xiocb.xiocb_status;
  58. }
  59. int cfe_cpu_start(int cpu, void (*fn) (void), long sp, long gp, long a1)
  60. {
  61. struct cfe_xiocb xiocb;
  62. xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
  63. xiocb.xiocb_status = 0;
  64. xiocb.xiocb_handle = 0;
  65. xiocb.xiocb_flags = 0;
  66. xiocb.xiocb_psize = sizeof(struct xiocb_cpuctl);
  67. xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
  68. xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START;
  69. xiocb.plist.xiocb_cpuctl.gp_val = gp;
  70. xiocb.plist.xiocb_cpuctl.sp_val = sp;
  71. xiocb.plist.xiocb_cpuctl.a1_val = a1;
  72. xiocb.plist.xiocb_cpuctl.start_addr = (long) fn;
  73. cfe_iocb_dispatch(&xiocb);
  74. return xiocb.xiocb_status;
  75. }
  76. int cfe_cpu_stop(int cpu)
  77. {
  78. struct cfe_xiocb xiocb;
  79. xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
  80. xiocb.xiocb_status = 0;
  81. xiocb.xiocb_handle = 0;
  82. xiocb.xiocb_flags = 0;
  83. xiocb.xiocb_psize = sizeof(struct xiocb_cpuctl);
  84. xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
  85. xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_STOP;
  86. cfe_iocb_dispatch(&xiocb);
  87. return xiocb.xiocb_status;
  88. }
  89. int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen)
  90. {
  91. struct cfe_xiocb xiocb;
  92. xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
  93. xiocb.xiocb_status = 0;
  94. xiocb.xiocb_handle = 0;
  95. xiocb.xiocb_flags = 0;
  96. xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
  97. xiocb.plist.xiocb_envbuf.enum_idx = idx;
  98. xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
  99. xiocb.plist.xiocb_envbuf.name_length = namelen;
  100. xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(val);
  101. xiocb.plist.xiocb_envbuf.val_length = vallen;
  102. cfe_iocb_dispatch(&xiocb);
  103. return xiocb.xiocb_status;
  104. }
  105. int
  106. cfe_enummem(int idx, int flags, u64 *start, u64 *length, u64 *type)
  107. {
  108. struct cfe_xiocb xiocb;
  109. xiocb.xiocb_fcode = CFE_CMD_FW_MEMENUM;
  110. xiocb.xiocb_status = 0;
  111. xiocb.xiocb_handle = 0;
  112. xiocb.xiocb_flags = flags;
  113. xiocb.xiocb_psize = sizeof(struct xiocb_meminfo);
  114. xiocb.plist.xiocb_meminfo.mi_idx = idx;
  115. cfe_iocb_dispatch(&xiocb);
  116. if (xiocb.xiocb_status < 0)
  117. return xiocb.xiocb_status;
  118. *start = xiocb.plist.xiocb_meminfo.mi_addr;
  119. *length = xiocb.plist.xiocb_meminfo.mi_size;
  120. *type = xiocb.plist.xiocb_meminfo.mi_type;
  121. return 0;
  122. }
  123. int cfe_exit(int warm, int status)
  124. {
  125. struct cfe_xiocb xiocb;
  126. xiocb.xiocb_fcode = CFE_CMD_FW_RESTART;
  127. xiocb.xiocb_status = 0;
  128. xiocb.xiocb_handle = 0;
  129. xiocb.xiocb_flags = warm ? CFE_FLG_WARMSTART : 0;
  130. xiocb.xiocb_psize = sizeof(struct xiocb_exitstat);
  131. xiocb.plist.xiocb_exitstat.status = status;
  132. cfe_iocb_dispatch(&xiocb);
  133. return xiocb.xiocb_status;
  134. }
  135. int cfe_flushcache(int flg)
  136. {
  137. struct cfe_xiocb xiocb;
  138. xiocb.xiocb_fcode = CFE_CMD_FW_FLUSHCACHE;
  139. xiocb.xiocb_status = 0;
  140. xiocb.xiocb_handle = 0;
  141. xiocb.xiocb_flags = flg;
  142. xiocb.xiocb_psize = 0;
  143. cfe_iocb_dispatch(&xiocb);
  144. return xiocb.xiocb_status;
  145. }
  146. int cfe_getdevinfo(char *name)
  147. {
  148. struct cfe_xiocb xiocb;
  149. xiocb.xiocb_fcode = CFE_CMD_DEV_GETINFO;
  150. xiocb.xiocb_status = 0;
  151. xiocb.xiocb_handle = 0;
  152. xiocb.xiocb_flags = 0;
  153. xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
  154. xiocb.plist.xiocb_buffer.buf_offset = 0;
  155. xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(name);
  156. xiocb.plist.xiocb_buffer.buf_length = strlen(name);
  157. cfe_iocb_dispatch(&xiocb);
  158. if (xiocb.xiocb_status < 0)
  159. return xiocb.xiocb_status;
  160. return xiocb.plist.xiocb_buffer.buf_ioctlcmd;
  161. }
  162. int cfe_getenv(char *name, char *dest, int destlen)
  163. {
  164. struct cfe_xiocb xiocb;
  165. *dest = 0;
  166. xiocb.xiocb_fcode = CFE_CMD_ENV_GET;
  167. xiocb.xiocb_status = 0;
  168. xiocb.xiocb_handle = 0;
  169. xiocb.xiocb_flags = 0;
  170. xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
  171. xiocb.plist.xiocb_envbuf.enum_idx = 0;
  172. xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
  173. xiocb.plist.xiocb_envbuf.name_length = strlen(name);
  174. xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(dest);
  175. xiocb.plist.xiocb_envbuf.val_length = destlen;
  176. cfe_iocb_dispatch(&xiocb);
  177. return xiocb.xiocb_status;
  178. }
  179. int cfe_getfwinfo(cfe_fwinfo_t * info)
  180. {
  181. struct cfe_xiocb xiocb;
  182. xiocb.xiocb_fcode = CFE_CMD_FW_GETINFO;
  183. xiocb.xiocb_status = 0;
  184. xiocb.xiocb_handle = 0;
  185. xiocb.xiocb_flags = 0;
  186. xiocb.xiocb_psize = sizeof(struct xiocb_fwinfo);
  187. cfe_iocb_dispatch(&xiocb);
  188. if (xiocb.xiocb_status < 0)
  189. return xiocb.xiocb_status;
  190. info->fwi_version = xiocb.plist.xiocb_fwinfo.fwi_version;
  191. info->fwi_totalmem = xiocb.plist.xiocb_fwinfo.fwi_totalmem;
  192. info->fwi_flags = xiocb.plist.xiocb_fwinfo.fwi_flags;
  193. info->fwi_boardid = xiocb.plist.xiocb_fwinfo.fwi_boardid;
  194. info->fwi_bootarea_va = xiocb.plist.xiocb_fwinfo.fwi_bootarea_va;
  195. info->fwi_bootarea_pa = xiocb.plist.xiocb_fwinfo.fwi_bootarea_pa;
  196. info->fwi_bootarea_size =
  197. xiocb.plist.xiocb_fwinfo.fwi_bootarea_size;
  198. return 0;
  199. }
  200. int cfe_getstdhandle(int flg)
  201. {
  202. struct cfe_xiocb xiocb;
  203. xiocb.xiocb_fcode = CFE_CMD_DEV_GETHANDLE;
  204. xiocb.xiocb_status = 0;
  205. xiocb.xiocb_handle = 0;
  206. xiocb.xiocb_flags = flg;
  207. xiocb.xiocb_psize = 0;
  208. cfe_iocb_dispatch(&xiocb);
  209. if (xiocb.xiocb_status < 0)
  210. return xiocb.xiocb_status;
  211. return xiocb.xiocb_handle;
  212. }
  213. int64_t
  214. cfe_getticks(void)
  215. {
  216. struct cfe_xiocb xiocb;
  217. xiocb.xiocb_fcode = CFE_CMD_FW_GETTIME;
  218. xiocb.xiocb_status = 0;
  219. xiocb.xiocb_handle = 0;
  220. xiocb.xiocb_flags = 0;
  221. xiocb.xiocb_psize = sizeof(struct xiocb_time);
  222. xiocb.plist.xiocb_time.ticks = 0;
  223. cfe_iocb_dispatch(&xiocb);
  224. return xiocb.plist.xiocb_time.ticks;
  225. }
  226. int cfe_inpstat(int handle)
  227. {
  228. struct cfe_xiocb xiocb;
  229. xiocb.xiocb_fcode = CFE_CMD_DEV_INPSTAT;
  230. xiocb.xiocb_status = 0;
  231. xiocb.xiocb_handle = handle;
  232. xiocb.xiocb_flags = 0;
  233. xiocb.xiocb_psize = sizeof(struct xiocb_inpstat);
  234. xiocb.plist.xiocb_inpstat.inp_status = 0;
  235. cfe_iocb_dispatch(&xiocb);
  236. if (xiocb.xiocb_status < 0)
  237. return xiocb.xiocb_status;
  238. return xiocb.plist.xiocb_inpstat.inp_status;
  239. }
  240. int
  241. cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer,
  242. int length, int *retlen, u64 offset)
  243. {
  244. struct cfe_xiocb xiocb;
  245. xiocb.xiocb_fcode = CFE_CMD_DEV_IOCTL;
  246. xiocb.xiocb_status = 0;
  247. xiocb.xiocb_handle = handle;
  248. xiocb.xiocb_flags = 0;
  249. xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
  250. xiocb.plist.xiocb_buffer.buf_offset = offset;
  251. xiocb.plist.xiocb_buffer.buf_ioctlcmd = ioctlnum;
  252. xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
  253. xiocb.plist.xiocb_buffer.buf_length = length;
  254. cfe_iocb_dispatch(&xiocb);
  255. if (retlen)
  256. *retlen = xiocb.plist.xiocb_buffer.buf_retlen;
  257. return xiocb.xiocb_status;
  258. }
  259. int cfe_open(char *name)
  260. {
  261. struct cfe_xiocb xiocb;
  262. xiocb.xiocb_fcode = CFE_CMD_DEV_OPEN;
  263. xiocb.xiocb_status = 0;
  264. xiocb.xiocb_handle = 0;
  265. xiocb.xiocb_flags = 0;
  266. xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
  267. xiocb.plist.xiocb_buffer.buf_offset = 0;
  268. xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(name);
  269. xiocb.plist.xiocb_buffer.buf_length = strlen(name);
  270. cfe_iocb_dispatch(&xiocb);
  271. if (xiocb.xiocb_status < 0)
  272. return xiocb.xiocb_status;
  273. return xiocb.xiocb_handle;
  274. }
  275. int cfe_read(int handle, unsigned char *buffer, int length)
  276. {
  277. return cfe_readblk(handle, 0, buffer, length);
  278. }
  279. int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length)
  280. {
  281. struct cfe_xiocb xiocb;
  282. xiocb.xiocb_fcode = CFE_CMD_DEV_READ;
  283. xiocb.xiocb_status = 0;
  284. xiocb.xiocb_handle = handle;
  285. xiocb.xiocb_flags = 0;
  286. xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
  287. xiocb.plist.xiocb_buffer.buf_offset = offset;
  288. xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
  289. xiocb.plist.xiocb_buffer.buf_length = length;
  290. cfe_iocb_dispatch(&xiocb);
  291. if (xiocb.xiocb_status < 0)
  292. return xiocb.xiocb_status;
  293. return xiocb.plist.xiocb_buffer.buf_retlen;
  294. }
  295. int cfe_setenv(char *name, char *val)
  296. {
  297. struct cfe_xiocb xiocb;
  298. xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
  299. xiocb.xiocb_status = 0;
  300. xiocb.xiocb_handle = 0;
  301. xiocb.xiocb_flags = 0;
  302. xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
  303. xiocb.plist.xiocb_envbuf.enum_idx = 0;
  304. xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
  305. xiocb.plist.xiocb_envbuf.name_length = strlen(name);
  306. xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(val);
  307. xiocb.plist.xiocb_envbuf.val_length = strlen(val);
  308. cfe_iocb_dispatch(&xiocb);
  309. return xiocb.xiocb_status;
  310. }
  311. int cfe_write(int handle, const char *buffer, int length)
  312. {
  313. return cfe_writeblk(handle, 0, buffer, length);
  314. }
  315. int cfe_writeblk(int handle, s64 offset, const char *buffer, int length)
  316. {
  317. struct cfe_xiocb xiocb;
  318. xiocb.xiocb_fcode = CFE_CMD_DEV_WRITE;
  319. xiocb.xiocb_status = 0;
  320. xiocb.xiocb_handle = handle;
  321. xiocb.xiocb_flags = 0;
  322. xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
  323. xiocb.plist.xiocb_buffer.buf_offset = offset;
  324. xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
  325. xiocb.plist.xiocb_buffer.buf_length = length;
  326. cfe_iocb_dispatch(&xiocb);
  327. if (xiocb.xiocb_status < 0)
  328. return xiocb.xiocb_status;
  329. return xiocb.plist.xiocb_buffer.buf_retlen;
  330. }
  331. void __init cfe_die(char *fmt, ...)
  332. {
  333. unsigned int prid, __maybe_unused rev;
  334. char msg[128];
  335. va_list ap;
  336. int handle;
  337. unsigned int count;
  338. va_start(ap, fmt);
  339. vsprintf(msg, fmt, ap);
  340. strcat(msg, "\r\n");
  341. if (cfe_seal != CFE_EPTSEAL)
  342. goto no_cfe;
  343. prid = read_c0_prid();
  344. if ((prid & PRID_COMP_MASK) != PRID_COMP_BROADCOM)
  345. goto no_cfe;
  346. rev = prid & PRID_REV_MASK;
  347. /* disable XKS01 so that CFE can access the registers */
  348. switch (prid & PRID_IMP_MASK) {
  349. #ifdef CONFIG_CPU_BMIPS4380
  350. case PRID_IMP_BMIPS43XX:
  351. if (rev >= PRID_REV_BMIPS4380_LO &&
  352. rev <= PRID_REV_BMIPS4380_HI)
  353. __write_32bit_c0_register($22, 3,
  354. __read_32bit_c0_register($22, 3) & ~BIT(12));
  355. break;
  356. #endif
  357. #ifdef CONFIG_CPU_BMIPS5000
  358. case PRID_IMP_BMIPS5000:
  359. case PRID_IMP_BMIPS5200:
  360. __write_32bit_c0_register($22, 5,
  361. __read_32bit_c0_register($22, 5) & ~BIT(8));
  362. break;
  363. #endif
  364. default:
  365. break;
  366. }
  367. handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
  368. if (handle < 0)
  369. goto no_cfe;
  370. cfe_write(handle, msg, strlen(msg));
  371. for (count = 0; count < 0x7fffffff; count++)
  372. mb();
  373. cfe_exit(0, 1);
  374. while (1)
  375. ;
  376. no_cfe:
  377. /* probably won't print anywhere useful */
  378. panic("%s", msg);
  379. va_end(ap);
  380. }