Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2000, 2001, 2002 Broadcom Corporation
0004  */
0005 
0006 /*
0007  *
0008  * Broadcom Common Firmware Environment (CFE)
0009  *
0010  * This module contains device function stubs (small routines to
0011  * call the standard "iocb" interface entry point to CFE).
0012  * There should be one routine here per iocb function call.
0013  *
0014  * Authors:  Mitch Lichtenberg, Chris Demetriou
0015  */
0016 #include <linux/init.h>
0017 #include <linux/kernel.h>
0018 #include <linux/printk.h>
0019 #include <asm/mipsregs.h>
0020 #include <asm/fw/cfe/cfe_api.h>
0021 #include "cfe_api_int.h"
0022 
0023 unsigned long __initdata cfe_seal;
0024 
0025 /* Cast from a native pointer to a cfe_xptr_t and back.  */
0026 #define XPTR_FROM_NATIVE(n) ((cfe_xptr_t) (intptr_t) (n))
0027 #define NATIVE_FROM_XPTR(x) ((void *) (intptr_t) (x))
0028 
0029 int cfe_iocb_dispatch(struct cfe_xiocb *xiocb);
0030 
0031 /*
0032  * Declare the dispatch function with args of "intptr_t".
0033  * This makes sure whatever model we're compiling in
0034  * puts the pointers in a single register.  For example,
0035  * combining -mlong64 and -mips1 or -mips2 would lead to
0036  * trouble, since the handle and IOCB pointer will be
0037  * passed in two registers each, and CFE expects one.
0038  */
0039 
0040 static int (*cfe_dispfunc) (intptr_t handle, intptr_t xiocb);
0041 static u64 cfe_handle;
0042 
0043 int cfe_init(u64 handle, u64 ept)
0044 {
0045     cfe_dispfunc = NATIVE_FROM_XPTR(ept);
0046     cfe_handle = handle;
0047     return 0;
0048 }
0049 
0050 int cfe_iocb_dispatch(struct cfe_xiocb * xiocb)
0051 {
0052     if (!cfe_dispfunc)
0053         return -1;
0054     return (*cfe_dispfunc) ((intptr_t) cfe_handle, (intptr_t) xiocb);
0055 }
0056 
0057 int cfe_close(int handle)
0058 {
0059     struct cfe_xiocb xiocb;
0060 
0061     xiocb.xiocb_fcode = CFE_CMD_DEV_CLOSE;
0062     xiocb.xiocb_status = 0;
0063     xiocb.xiocb_handle = handle;
0064     xiocb.xiocb_flags = 0;
0065     xiocb.xiocb_psize = 0;
0066 
0067     cfe_iocb_dispatch(&xiocb);
0068 
0069     return xiocb.xiocb_status;
0070 
0071 }
0072 
0073 int cfe_cpu_start(int cpu, void (*fn) (void), long sp, long gp, long a1)
0074 {
0075     struct cfe_xiocb xiocb;
0076 
0077     xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
0078     xiocb.xiocb_status = 0;
0079     xiocb.xiocb_handle = 0;
0080     xiocb.xiocb_flags = 0;
0081     xiocb.xiocb_psize = sizeof(struct xiocb_cpuctl);
0082     xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
0083     xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_START;
0084     xiocb.plist.xiocb_cpuctl.gp_val = gp;
0085     xiocb.plist.xiocb_cpuctl.sp_val = sp;
0086     xiocb.plist.xiocb_cpuctl.a1_val = a1;
0087     xiocb.plist.xiocb_cpuctl.start_addr = (long) fn;
0088 
0089     cfe_iocb_dispatch(&xiocb);
0090 
0091     return xiocb.xiocb_status;
0092 }
0093 
0094 int cfe_cpu_stop(int cpu)
0095 {
0096     struct cfe_xiocb xiocb;
0097 
0098     xiocb.xiocb_fcode = CFE_CMD_FW_CPUCTL;
0099     xiocb.xiocb_status = 0;
0100     xiocb.xiocb_handle = 0;
0101     xiocb.xiocb_flags = 0;
0102     xiocb.xiocb_psize = sizeof(struct xiocb_cpuctl);
0103     xiocb.plist.xiocb_cpuctl.cpu_number = cpu;
0104     xiocb.plist.xiocb_cpuctl.cpu_command = CFE_CPU_CMD_STOP;
0105 
0106     cfe_iocb_dispatch(&xiocb);
0107 
0108     return xiocb.xiocb_status;
0109 }
0110 
0111 int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen)
0112 {
0113     struct cfe_xiocb xiocb;
0114 
0115     xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
0116     xiocb.xiocb_status = 0;
0117     xiocb.xiocb_handle = 0;
0118     xiocb.xiocb_flags = 0;
0119     xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
0120     xiocb.plist.xiocb_envbuf.enum_idx = idx;
0121     xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
0122     xiocb.plist.xiocb_envbuf.name_length = namelen;
0123     xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(val);
0124     xiocb.plist.xiocb_envbuf.val_length = vallen;
0125 
0126     cfe_iocb_dispatch(&xiocb);
0127 
0128     return xiocb.xiocb_status;
0129 }
0130 
0131 int
0132 cfe_enummem(int idx, int flags, u64 *start, u64 *length, u64 *type)
0133 {
0134     struct cfe_xiocb xiocb;
0135 
0136     xiocb.xiocb_fcode = CFE_CMD_FW_MEMENUM;
0137     xiocb.xiocb_status = 0;
0138     xiocb.xiocb_handle = 0;
0139     xiocb.xiocb_flags = flags;
0140     xiocb.xiocb_psize = sizeof(struct xiocb_meminfo);
0141     xiocb.plist.xiocb_meminfo.mi_idx = idx;
0142 
0143     cfe_iocb_dispatch(&xiocb);
0144 
0145     if (xiocb.xiocb_status < 0)
0146         return xiocb.xiocb_status;
0147 
0148     *start = xiocb.plist.xiocb_meminfo.mi_addr;
0149     *length = xiocb.plist.xiocb_meminfo.mi_size;
0150     *type = xiocb.plist.xiocb_meminfo.mi_type;
0151 
0152     return 0;
0153 }
0154 
0155 int cfe_exit(int warm, int status)
0156 {
0157     struct cfe_xiocb xiocb;
0158 
0159     xiocb.xiocb_fcode = CFE_CMD_FW_RESTART;
0160     xiocb.xiocb_status = 0;
0161     xiocb.xiocb_handle = 0;
0162     xiocb.xiocb_flags = warm ? CFE_FLG_WARMSTART : 0;
0163     xiocb.xiocb_psize = sizeof(struct xiocb_exitstat);
0164     xiocb.plist.xiocb_exitstat.status = status;
0165 
0166     cfe_iocb_dispatch(&xiocb);
0167 
0168     return xiocb.xiocb_status;
0169 }
0170 
0171 int cfe_flushcache(int flg)
0172 {
0173     struct cfe_xiocb xiocb;
0174 
0175     xiocb.xiocb_fcode = CFE_CMD_FW_FLUSHCACHE;
0176     xiocb.xiocb_status = 0;
0177     xiocb.xiocb_handle = 0;
0178     xiocb.xiocb_flags = flg;
0179     xiocb.xiocb_psize = 0;
0180 
0181     cfe_iocb_dispatch(&xiocb);
0182 
0183     return xiocb.xiocb_status;
0184 }
0185 
0186 int cfe_getdevinfo(char *name)
0187 {
0188     struct cfe_xiocb xiocb;
0189 
0190     xiocb.xiocb_fcode = CFE_CMD_DEV_GETINFO;
0191     xiocb.xiocb_status = 0;
0192     xiocb.xiocb_handle = 0;
0193     xiocb.xiocb_flags = 0;
0194     xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
0195     xiocb.plist.xiocb_buffer.buf_offset = 0;
0196     xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(name);
0197     xiocb.plist.xiocb_buffer.buf_length = strlen(name);
0198 
0199     cfe_iocb_dispatch(&xiocb);
0200 
0201     if (xiocb.xiocb_status < 0)
0202         return xiocb.xiocb_status;
0203     return xiocb.plist.xiocb_buffer.buf_ioctlcmd;
0204 }
0205 
0206 int cfe_getenv(char *name, char *dest, int destlen)
0207 {
0208     struct cfe_xiocb xiocb;
0209 
0210     *dest = 0;
0211 
0212     xiocb.xiocb_fcode = CFE_CMD_ENV_GET;
0213     xiocb.xiocb_status = 0;
0214     xiocb.xiocb_handle = 0;
0215     xiocb.xiocb_flags = 0;
0216     xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
0217     xiocb.plist.xiocb_envbuf.enum_idx = 0;
0218     xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
0219     xiocb.plist.xiocb_envbuf.name_length = strlen(name);
0220     xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(dest);
0221     xiocb.plist.xiocb_envbuf.val_length = destlen;
0222 
0223     cfe_iocb_dispatch(&xiocb);
0224 
0225     return xiocb.xiocb_status;
0226 }
0227 
0228 int cfe_getfwinfo(cfe_fwinfo_t * info)
0229 {
0230     struct cfe_xiocb xiocb;
0231 
0232     xiocb.xiocb_fcode = CFE_CMD_FW_GETINFO;
0233     xiocb.xiocb_status = 0;
0234     xiocb.xiocb_handle = 0;
0235     xiocb.xiocb_flags = 0;
0236     xiocb.xiocb_psize = sizeof(struct xiocb_fwinfo);
0237 
0238     cfe_iocb_dispatch(&xiocb);
0239 
0240     if (xiocb.xiocb_status < 0)
0241         return xiocb.xiocb_status;
0242 
0243     info->fwi_version = xiocb.plist.xiocb_fwinfo.fwi_version;
0244     info->fwi_totalmem = xiocb.plist.xiocb_fwinfo.fwi_totalmem;
0245     info->fwi_flags = xiocb.plist.xiocb_fwinfo.fwi_flags;
0246     info->fwi_boardid = xiocb.plist.xiocb_fwinfo.fwi_boardid;
0247     info->fwi_bootarea_va = xiocb.plist.xiocb_fwinfo.fwi_bootarea_va;
0248     info->fwi_bootarea_pa = xiocb.plist.xiocb_fwinfo.fwi_bootarea_pa;
0249     info->fwi_bootarea_size =
0250         xiocb.plist.xiocb_fwinfo.fwi_bootarea_size;
0251 
0252     return 0;
0253 }
0254 
0255 int cfe_getstdhandle(int flg)
0256 {
0257     struct cfe_xiocb xiocb;
0258 
0259     xiocb.xiocb_fcode = CFE_CMD_DEV_GETHANDLE;
0260     xiocb.xiocb_status = 0;
0261     xiocb.xiocb_handle = 0;
0262     xiocb.xiocb_flags = flg;
0263     xiocb.xiocb_psize = 0;
0264 
0265     cfe_iocb_dispatch(&xiocb);
0266 
0267     if (xiocb.xiocb_status < 0)
0268         return xiocb.xiocb_status;
0269     return xiocb.xiocb_handle;
0270 }
0271 
0272 int64_t
0273 cfe_getticks(void)
0274 {
0275     struct cfe_xiocb xiocb;
0276 
0277     xiocb.xiocb_fcode = CFE_CMD_FW_GETTIME;
0278     xiocb.xiocb_status = 0;
0279     xiocb.xiocb_handle = 0;
0280     xiocb.xiocb_flags = 0;
0281     xiocb.xiocb_psize = sizeof(struct xiocb_time);
0282     xiocb.plist.xiocb_time.ticks = 0;
0283 
0284     cfe_iocb_dispatch(&xiocb);
0285 
0286     return xiocb.plist.xiocb_time.ticks;
0287 
0288 }
0289 
0290 int cfe_inpstat(int handle)
0291 {
0292     struct cfe_xiocb xiocb;
0293 
0294     xiocb.xiocb_fcode = CFE_CMD_DEV_INPSTAT;
0295     xiocb.xiocb_status = 0;
0296     xiocb.xiocb_handle = handle;
0297     xiocb.xiocb_flags = 0;
0298     xiocb.xiocb_psize = sizeof(struct xiocb_inpstat);
0299     xiocb.plist.xiocb_inpstat.inp_status = 0;
0300 
0301     cfe_iocb_dispatch(&xiocb);
0302 
0303     if (xiocb.xiocb_status < 0)
0304         return xiocb.xiocb_status;
0305     return xiocb.plist.xiocb_inpstat.inp_status;
0306 }
0307 
0308 int
0309 cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer,
0310       int length, int *retlen, u64 offset)
0311 {
0312     struct cfe_xiocb xiocb;
0313 
0314     xiocb.xiocb_fcode = CFE_CMD_DEV_IOCTL;
0315     xiocb.xiocb_status = 0;
0316     xiocb.xiocb_handle = handle;
0317     xiocb.xiocb_flags = 0;
0318     xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
0319     xiocb.plist.xiocb_buffer.buf_offset = offset;
0320     xiocb.plist.xiocb_buffer.buf_ioctlcmd = ioctlnum;
0321     xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
0322     xiocb.plist.xiocb_buffer.buf_length = length;
0323 
0324     cfe_iocb_dispatch(&xiocb);
0325 
0326     if (retlen)
0327         *retlen = xiocb.plist.xiocb_buffer.buf_retlen;
0328     return xiocb.xiocb_status;
0329 }
0330 
0331 int cfe_open(char *name)
0332 {
0333     struct cfe_xiocb xiocb;
0334 
0335     xiocb.xiocb_fcode = CFE_CMD_DEV_OPEN;
0336     xiocb.xiocb_status = 0;
0337     xiocb.xiocb_handle = 0;
0338     xiocb.xiocb_flags = 0;
0339     xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
0340     xiocb.plist.xiocb_buffer.buf_offset = 0;
0341     xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(name);
0342     xiocb.plist.xiocb_buffer.buf_length = strlen(name);
0343 
0344     cfe_iocb_dispatch(&xiocb);
0345 
0346     if (xiocb.xiocb_status < 0)
0347         return xiocb.xiocb_status;
0348     return xiocb.xiocb_handle;
0349 }
0350 
0351 int cfe_read(int handle, unsigned char *buffer, int length)
0352 {
0353     return cfe_readblk(handle, 0, buffer, length);
0354 }
0355 
0356 int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length)
0357 {
0358     struct cfe_xiocb xiocb;
0359 
0360     xiocb.xiocb_fcode = CFE_CMD_DEV_READ;
0361     xiocb.xiocb_status = 0;
0362     xiocb.xiocb_handle = handle;
0363     xiocb.xiocb_flags = 0;
0364     xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
0365     xiocb.plist.xiocb_buffer.buf_offset = offset;
0366     xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
0367     xiocb.plist.xiocb_buffer.buf_length = length;
0368 
0369     cfe_iocb_dispatch(&xiocb);
0370 
0371     if (xiocb.xiocb_status < 0)
0372         return xiocb.xiocb_status;
0373     return xiocb.plist.xiocb_buffer.buf_retlen;
0374 }
0375 
0376 int cfe_setenv(char *name, char *val)
0377 {
0378     struct cfe_xiocb xiocb;
0379 
0380     xiocb.xiocb_fcode = CFE_CMD_ENV_SET;
0381     xiocb.xiocb_status = 0;
0382     xiocb.xiocb_handle = 0;
0383     xiocb.xiocb_flags = 0;
0384     xiocb.xiocb_psize = sizeof(struct xiocb_envbuf);
0385     xiocb.plist.xiocb_envbuf.enum_idx = 0;
0386     xiocb.plist.xiocb_envbuf.name_ptr = XPTR_FROM_NATIVE(name);
0387     xiocb.plist.xiocb_envbuf.name_length = strlen(name);
0388     xiocb.plist.xiocb_envbuf.val_ptr = XPTR_FROM_NATIVE(val);
0389     xiocb.plist.xiocb_envbuf.val_length = strlen(val);
0390 
0391     cfe_iocb_dispatch(&xiocb);
0392 
0393     return xiocb.xiocb_status;
0394 }
0395 
0396 int cfe_write(int handle, const char *buffer, int length)
0397 {
0398     return cfe_writeblk(handle, 0, buffer, length);
0399 }
0400 
0401 int cfe_writeblk(int handle, s64 offset, const char *buffer, int length)
0402 {
0403     struct cfe_xiocb xiocb;
0404 
0405     xiocb.xiocb_fcode = CFE_CMD_DEV_WRITE;
0406     xiocb.xiocb_status = 0;
0407     xiocb.xiocb_handle = handle;
0408     xiocb.xiocb_flags = 0;
0409     xiocb.xiocb_psize = sizeof(struct xiocb_buffer);
0410     xiocb.plist.xiocb_buffer.buf_offset = offset;
0411     xiocb.plist.xiocb_buffer.buf_ptr = XPTR_FROM_NATIVE(buffer);
0412     xiocb.plist.xiocb_buffer.buf_length = length;
0413 
0414     cfe_iocb_dispatch(&xiocb);
0415 
0416     if (xiocb.xiocb_status < 0)
0417         return xiocb.xiocb_status;
0418     return xiocb.plist.xiocb_buffer.buf_retlen;
0419 }
0420 
0421 void __init cfe_die(char *fmt, ...)
0422 {
0423     unsigned int prid, __maybe_unused rev;
0424     char msg[128];
0425     va_list ap;
0426     int handle;
0427     unsigned int count;
0428 
0429     va_start(ap, fmt);
0430     vsprintf(msg, fmt, ap);
0431     strcat(msg, "\r\n");
0432 
0433     if (cfe_seal != CFE_EPTSEAL)
0434         goto no_cfe;
0435 
0436     prid = read_c0_prid();
0437     if ((prid & PRID_COMP_MASK) != PRID_COMP_BROADCOM)
0438         goto no_cfe;
0439 
0440     rev = prid & PRID_REV_MASK;
0441 
0442     /* disable XKS01 so that CFE can access the registers */
0443     switch (prid & PRID_IMP_MASK) {
0444 #ifdef CONFIG_CPU_BMIPS4380
0445     case PRID_IMP_BMIPS43XX:
0446         if (rev >= PRID_REV_BMIPS4380_LO &&
0447             rev <= PRID_REV_BMIPS4380_HI)
0448             __write_32bit_c0_register($22, 3,
0449                 __read_32bit_c0_register($22, 3) & ~BIT(12));
0450         break;
0451 #endif
0452 #ifdef CONFIG_CPU_BMIPS5000
0453     case PRID_IMP_BMIPS5000:
0454     case PRID_IMP_BMIPS5200:
0455         __write_32bit_c0_register($22, 5,
0456             __read_32bit_c0_register($22, 5) & ~BIT(8));
0457         break;
0458 #endif
0459     default:
0460         break;
0461     }
0462 
0463     handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
0464     if (handle < 0)
0465         goto no_cfe;
0466 
0467     cfe_write(handle, msg, strlen(msg));
0468 
0469     for (count = 0; count < 0x7fffffff; count++)
0470         mb();
0471     cfe_exit(0, 1);
0472     while (1)
0473         ;
0474 
0475 no_cfe:
0476     /* probably won't print anywhere useful */
0477     panic("%s", msg);
0478 
0479     va_end(ap);
0480 }