0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/init.h>
0009 #include <linux/kernel.h>
0010 #include <linux/serial_reg.h>
0011 #include <linux/spinlock.h>
0012 #include <linux/export.h>
0013 #include <linux/string.h>
0014 #include <linux/io.h>
0015 #include <asm/bootinfo.h>
0016 #include <asm/setup.h>
0017
0018 #include <asm/mach-ar7/ar7.h>
0019 #include <asm/mach-ar7/prom.h>
0020
0021 #define MAX_ENTRY 80
0022
0023 struct env_var {
0024 char *name;
0025 char *value;
0026 };
0027
0028 static struct env_var adam2_env[MAX_ENTRY];
0029
0030 char *prom_getenv(const char *name)
0031 {
0032 int i;
0033
0034 for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++)
0035 if (!strcmp(name, adam2_env[i].name))
0036 return adam2_env[i].value;
0037
0038 return NULL;
0039 }
0040 EXPORT_SYMBOL(prom_getenv);
0041
0042 static void __init ar7_init_cmdline(int argc, char *argv[])
0043 {
0044 int i;
0045
0046 for (i = 1; i < argc; i++) {
0047 strlcat(arcs_cmdline, argv[i], COMMAND_LINE_SIZE);
0048 if (i < (argc - 1))
0049 strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
0050 }
0051 }
0052
0053 struct psbl_rec {
0054 u32 psbl_size;
0055 u32 env_base;
0056 u32 env_size;
0057 u32 ffs_base;
0058 u32 ffs_size;
0059 };
0060
0061 static const char psp_env_version[] __initconst = "TIENV0.8";
0062
0063 struct psp_env_chunk {
0064 u8 num;
0065 u8 ctrl;
0066 u16 csum;
0067 u8 len;
0068 char data[11];
0069 } __packed;
0070
0071 struct psp_var_map_entry {
0072 u8 num;
0073 char *value;
0074 };
0075
0076 static const struct psp_var_map_entry psp_var_map[] = {
0077 { 1, "cpufrequency" },
0078 { 2, "memsize" },
0079 { 3, "flashsize" },
0080 { 4, "modetty0" },
0081 { 5, "modetty1" },
0082 { 8, "maca" },
0083 { 9, "macb" },
0084 { 28, "sysfrequency" },
0085 { 38, "mipsfrequency" },
0086 };
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114 #define PSP_ENV_SIZE 4096
0115
0116 static char psp_env_data[PSP_ENV_SIZE] = { 0, };
0117
0118 static char * __init lookup_psp_var_map(u8 num)
0119 {
0120 int i;
0121
0122 for (i = 0; i < ARRAY_SIZE(psp_var_map); i++)
0123 if (psp_var_map[i].num == num)
0124 return psp_var_map[i].value;
0125
0126 return NULL;
0127 }
0128
0129 static void __init add_adam2_var(char *name, char *value)
0130 {
0131 int i;
0132
0133 for (i = 0; i < MAX_ENTRY; i++) {
0134 if (!adam2_env[i].name) {
0135 adam2_env[i].name = name;
0136 adam2_env[i].value = value;
0137 return;
0138 } else if (!strcmp(adam2_env[i].name, name)) {
0139 adam2_env[i].value = value;
0140 return;
0141 }
0142 }
0143 }
0144
0145 static int __init parse_psp_env(void *psp_env_base)
0146 {
0147 int i, n;
0148 char *name, *value;
0149 struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data;
0150
0151 memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE);
0152
0153 i = 1;
0154 n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk);
0155 while (i < n) {
0156 if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n))
0157 break;
0158 value = chunks[i].data;
0159 if (chunks[i].num) {
0160 name = lookup_psp_var_map(chunks[i].num);
0161 } else {
0162 name = value;
0163 value += strlen(name) + 1;
0164 }
0165 if (name)
0166 add_adam2_var(name, value);
0167 i += chunks[i].len;
0168 }
0169 return 0;
0170 }
0171
0172 static void __init ar7_init_env(struct env_var *env)
0173 {
0174 int i;
0175 struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300));
0176 void *psp_env = (void *)KSEG1ADDR(psbl->env_base);
0177
0178 if (strcmp(psp_env, psp_env_version) == 0) {
0179 parse_psp_env(psp_env);
0180 } else {
0181 for (i = 0; i < MAX_ENTRY; i++, env++)
0182 if (env->name)
0183 add_adam2_var(env->name, env->value);
0184 }
0185 }
0186
0187 static void __init console_config(void)
0188 {
0189 #ifdef CONFIG_SERIAL_8250_CONSOLE
0190 char console_string[40];
0191 int baud = 0;
0192 char parity = '\0', bits = '\0', flow = '\0';
0193 char *s, *p;
0194
0195 if (strstr(arcs_cmdline, "console="))
0196 return;
0197
0198 s = prom_getenv("modetty0");
0199 if (s) {
0200 baud = simple_strtoul(s, &p, 10);
0201 s = p;
0202 if (*s == ',')
0203 s++;
0204 if (*s)
0205 parity = *s++;
0206 if (*s == ',')
0207 s++;
0208 if (*s)
0209 bits = *s++;
0210 if (*s == ',')
0211 s++;
0212 if (*s == 'h')
0213 flow = 'r';
0214 }
0215
0216 if (baud == 0)
0217 baud = 38400;
0218 if (parity != 'n' && parity != 'o' && parity != 'e')
0219 parity = 'n';
0220 if (bits != '7' && bits != '8')
0221 bits = '8';
0222
0223 if (flow == 'r')
0224 sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
0225 parity, bits, flow);
0226 else
0227 sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity,
0228 bits);
0229 strlcat(arcs_cmdline, console_string, COMMAND_LINE_SIZE);
0230 #endif
0231 }
0232
0233 void __init prom_init(void)
0234 {
0235 ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
0236 ar7_init_env((struct env_var *)fw_arg2);
0237 console_config();
0238 }
0239
0240 #define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
0241 static inline unsigned int serial_in(int offset)
0242 {
0243 return readl((void *)PORT(offset));
0244 }
0245
0246 static inline void serial_out(int offset, int value)
0247 {
0248 writel(value, (void *)PORT(offset));
0249 }
0250
0251 void prom_putchar(char c)
0252 {
0253 while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0)
0254 ;
0255 serial_out(UART_TX, c);
0256 }