diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/ar7/prom.c | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/ar7/prom.c')
-rw-r--r-- | arch/mips/ar7/prom.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c new file mode 100644 index 000000000..5810d3993 --- /dev/null +++ b/arch/mips/ar7/prom.c | |||
@@ -0,0 +1,256 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * Carsten Langgaard, carstenl@mips.com | ||
4 | * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. | ||
5 | * | ||
6 | * Putting things on the screen/serial line using YAMONs facilities. | ||
7 | */ | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/serial_reg.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | #include <linux/export.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <asm/bootinfo.h> | ||
16 | #include <asm/setup.h> | ||
17 | |||
18 | #include <asm/mach-ar7/ar7.h> | ||
19 | #include <asm/mach-ar7/prom.h> | ||
20 | |||
21 | #define MAX_ENTRY 80 | ||
22 | |||
23 | struct env_var { | ||
24 | char *name; | ||
25 | char *value; | ||
26 | }; | ||
27 | |||
28 | static struct env_var adam2_env[MAX_ENTRY]; | ||
29 | |||
30 | char *prom_getenv(const char *name) | ||
31 | { | ||
32 | int i; | ||
33 | |||
34 | for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++) | ||
35 | if (!strcmp(name, adam2_env[i].name)) | ||
36 | return adam2_env[i].value; | ||
37 | |||
38 | return NULL; | ||
39 | } | ||
40 | EXPORT_SYMBOL(prom_getenv); | ||
41 | |||
42 | static void __init ar7_init_cmdline(int argc, char *argv[]) | ||
43 | { | ||
44 | int i; | ||
45 | |||
46 | for (i = 1; i < argc; i++) { | ||
47 | strlcat(arcs_cmdline, argv[i], COMMAND_LINE_SIZE); | ||
48 | if (i < (argc - 1)) | ||
49 | strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | struct psbl_rec { | ||
54 | u32 psbl_size; | ||
55 | u32 env_base; | ||
56 | u32 env_size; | ||
57 | u32 ffs_base; | ||
58 | u32 ffs_size; | ||
59 | }; | ||
60 | |||
61 | static const char psp_env_version[] __initconst = "TIENV0.8"; | ||
62 | |||
63 | struct psp_env_chunk { | ||
64 | u8 num; | ||
65 | u8 ctrl; | ||
66 | u16 csum; | ||
67 | u8 len; | ||
68 | char data[11]; | ||
69 | } __packed; | ||
70 | |||
71 | struct psp_var_map_entry { | ||
72 | u8 num; | ||
73 | char *value; | ||
74 | }; | ||
75 | |||
76 | static const struct psp_var_map_entry psp_var_map[] = { | ||
77 | { 1, "cpufrequency" }, | ||
78 | { 2, "memsize" }, | ||
79 | { 3, "flashsize" }, | ||
80 | { 4, "modetty0" }, | ||
81 | { 5, "modetty1" }, | ||
82 | { 8, "maca" }, | ||
83 | { 9, "macb" }, | ||
84 | { 28, "sysfrequency" }, | ||
85 | { 38, "mipsfrequency" }, | ||
86 | }; | ||
87 | |||
88 | /* | ||
89 | |||
90 | Well-known variable (num is looked up in table above for matching variable name) | ||
91 | Example: cpufrequency=211968000 | ||
92 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
93 | | 01 |CTRL|CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \0 | FF | ||
94 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
95 | |||
96 | Name=Value pair in a single chunk | ||
97 | Example: NAME=VALUE | ||
98 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
99 | | 00 |CTRL|CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \0 | ||
100 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
101 | |||
102 | Name=Value pair in 2 chunks (len is the number of chunks) | ||
103 | Example: bootloaderVersion=1.3.7.15 | ||
104 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
105 | | 00 |CTRL|CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V | ||
106 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
107 | | _e | _r | _s | _i | _o | _n | \0 | _1 | _. | _3 | _. | _7 | _. | _1 | _5 | \0 | ||
108 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
109 | |||
110 | Data is padded with 0xFF | ||
111 | |||
112 | */ | ||
113 | |||
114 | #define PSP_ENV_SIZE 4096 | ||
115 | |||
116 | static char psp_env_data[PSP_ENV_SIZE] = { 0, }; | ||
117 | |||
118 | static char * __init lookup_psp_var_map(u8 num) | ||
119 | { | ||
120 | int i; | ||
121 | |||
122 | for (i = 0; i < ARRAY_SIZE(psp_var_map); i++) | ||
123 | if (psp_var_map[i].num == num) | ||
124 | return psp_var_map[i].value; | ||
125 | |||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | static void __init add_adam2_var(char *name, char *value) | ||
130 | { | ||
131 | int i; | ||
132 | |||
133 | for (i = 0; i < MAX_ENTRY; i++) { | ||
134 | if (!adam2_env[i].name) { | ||
135 | adam2_env[i].name = name; | ||
136 | adam2_env[i].value = value; | ||
137 | return; | ||
138 | } else if (!strcmp(adam2_env[i].name, name)) { | ||
139 | adam2_env[i].value = value; | ||
140 | return; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static int __init parse_psp_env(void *psp_env_base) | ||
146 | { | ||
147 | int i, n; | ||
148 | char *name, *value; | ||
149 | struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data; | ||
150 | |||
151 | memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE); | ||
152 | |||
153 | i = 1; | ||
154 | n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk); | ||
155 | while (i < n) { | ||
156 | if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n)) | ||
157 | break; | ||
158 | value = chunks[i].data; | ||
159 | if (chunks[i].num) { | ||
160 | name = lookup_psp_var_map(chunks[i].num); | ||
161 | } else { | ||
162 | name = value; | ||
163 | value += strlen(name) + 1; | ||
164 | } | ||
165 | if (name) | ||
166 | add_adam2_var(name, value); | ||
167 | i += chunks[i].len; | ||
168 | } | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static void __init ar7_init_env(struct env_var *env) | ||
173 | { | ||
174 | int i; | ||
175 | struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300)); | ||
176 | void *psp_env = (void *)KSEG1ADDR(psbl->env_base); | ||
177 | |||
178 | if (strcmp(psp_env, psp_env_version) == 0) { | ||
179 | parse_psp_env(psp_env); | ||
180 | } else { | ||
181 | for (i = 0; i < MAX_ENTRY; i++, env++) | ||
182 | if (env->name) | ||
183 | add_adam2_var(env->name, env->value); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | static void __init console_config(void) | ||
188 | { | ||
189 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
190 | char console_string[40]; | ||
191 | int baud = 0; | ||
192 | char parity = '\0', bits = '\0', flow = '\0'; | ||
193 | char *s, *p; | ||
194 | |||
195 | if (strstr(arcs_cmdline, "console=")) | ||
196 | return; | ||
197 | |||
198 | s = prom_getenv("modetty0"); | ||
199 | if (s) { | ||
200 | baud = simple_strtoul(s, &p, 10); | ||
201 | s = p; | ||
202 | if (*s == ',') | ||
203 | s++; | ||
204 | if (*s) | ||
205 | parity = *s++; | ||
206 | if (*s == ',') | ||
207 | s++; | ||
208 | if (*s) | ||
209 | bits = *s++; | ||
210 | if (*s == ',') | ||
211 | s++; | ||
212 | if (*s == 'h') | ||
213 | flow = 'r'; | ||
214 | } | ||
215 | |||
216 | if (baud == 0) | ||
217 | baud = 38400; | ||
218 | if (parity != 'n' && parity != 'o' && parity != 'e') | ||
219 | parity = 'n'; | ||
220 | if (bits != '7' && bits != '8') | ||
221 | bits = '8'; | ||
222 | |||
223 | if (flow == 'r') | ||
224 | sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, | ||
225 | parity, bits, flow); | ||
226 | else | ||
227 | sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity, | ||
228 | bits); | ||
229 | strlcat(arcs_cmdline, console_string, COMMAND_LINE_SIZE); | ||
230 | #endif | ||
231 | } | ||
232 | |||
233 | void __init prom_init(void) | ||
234 | { | ||
235 | ar7_init_cmdline(fw_arg0, (char **)fw_arg1); | ||
236 | ar7_init_env((struct env_var *)fw_arg2); | ||
237 | console_config(); | ||
238 | } | ||
239 | |||
240 | #define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4))) | ||
241 | static inline unsigned int serial_in(int offset) | ||
242 | { | ||
243 | return readl((void *)PORT(offset)); | ||
244 | } | ||
245 | |||
246 | static inline void serial_out(int offset, int value) | ||
247 | { | ||
248 | writel(value, (void *)PORT(offset)); | ||
249 | } | ||
250 | |||
251 | void prom_putchar(char c) | ||
252 | { | ||
253 | while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0) | ||
254 | ; | ||
255 | serial_out(UART_TX, c); | ||
256 | } | ||