OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From c64d8ab6260330fa2fe9a2d676256697e4e2a83c Mon Sep 17 00:00:00 2001 |
2 | From: Biwen Li <biwen.li@nxp.com> |
||
3 | Date: Tue, 30 Oct 2018 18:26:44 +0800 |
||
4 | Subject: [PATCH 31/40] ls2-console: support layerscape |
||
5 | This is an integrated patch of ls2-console for |
||
6 | layerscape |
||
7 | |||
8 | Signed-off-by: Razvan Stefanescu <razvan.stefanescu@nxp.com> |
||
9 | Signed-off-by: Biwen Li <biwen.li@nxp.com> |
||
10 | --- |
||
11 | drivers/soc/fsl/ls2-console/Kconfig | 4 + |
||
12 | drivers/soc/fsl/ls2-console/Makefile | 1 + |
||
13 | drivers/soc/fsl/ls2-console/ls2-console.c | 284 ++++++++++++++++++++++ |
||
14 | 3 files changed, 289 insertions(+) |
||
15 | create mode 100644 drivers/soc/fsl/ls2-console/Kconfig |
||
16 | create mode 100644 drivers/soc/fsl/ls2-console/Makefile |
||
17 | create mode 100644 drivers/soc/fsl/ls2-console/ls2-console.c |
||
18 | |||
19 | --- /dev/null |
||
20 | +++ b/drivers/soc/fsl/ls2-console/Kconfig |
||
21 | @@ -0,0 +1,4 @@ |
||
22 | +config FSL_LS2_CONSOLE |
||
23 | + tristate "Layerscape MC and AIOP console support" |
||
24 | + depends on ARCH_LAYERSCAPE |
||
25 | + default y |
||
26 | --- /dev/null |
||
27 | +++ b/drivers/soc/fsl/ls2-console/Makefile |
||
28 | @@ -0,0 +1 @@ |
||
29 | +obj-$(CONFIG_FSL_LS2_CONSOLE) += ls2-console.o |
||
30 | --- /dev/null |
||
31 | +++ b/drivers/soc/fsl/ls2-console/ls2-console.c |
||
32 | @@ -0,0 +1,284 @@ |
||
33 | +/* Copyright 2015-2016 Freescale Semiconductor Inc. |
||
34 | + * |
||
35 | + * Redistribution and use in source and binary forms, with or without |
||
36 | + * modification, are permitted provided that the following conditions are met: |
||
37 | + * * Redistributions of source code must retain the above copyright |
||
38 | + * notice, this list of conditions and the following disclaimer. |
||
39 | + * * Redistributions in binary form must reproduce the above copyright |
||
40 | + * notice, this list of conditions and the following disclaimer in the |
||
41 | + * documentation and/or other materials provided with the distribution. |
||
42 | + * * Neither the name of the above-listed copyright holders nor the |
||
43 | + * names of any contributors may be used to endorse or promote products |
||
44 | + * derived from this software without specific prior written permission. |
||
45 | + * |
||
46 | + * |
||
47 | + * ALTERNATIVELY, this software may be distributed under the terms of the |
||
48 | + * GNU General Public License ("GPL") as published by the Free Software |
||
49 | + * Foundation, either version 2 of that License or (at your option) any |
||
50 | + * later version. |
||
51 | + * |
||
52 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
53 | + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
54 | + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
55 | + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE |
||
56 | + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
57 | + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
58 | + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
59 | + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
60 | + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
61 | + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
62 | + * POSSIBILITY OF SUCH DAMAGE. |
||
63 | + */ |
||
64 | + |
||
65 | +#include <linux/miscdevice.h> |
||
66 | +#include <linux/uaccess.h> |
||
67 | +#include <linux/poll.h> |
||
68 | +#include <linux/compat.h> |
||
69 | +#include <linux/module.h> |
||
70 | +#include <linux/slab.h> |
||
71 | +#include <linux/io.h> |
||
72 | + |
||
73 | +/* SoC address for the MC firmware base low/high registers */ |
||
74 | +#define SOC_CCSR_MC_FW_BASE_ADDR_REGS 0x8340020 |
||
75 | +#define SOC_CCSR_MC_FW_BASE_ADDR_REGS_SIZE 2 |
||
76 | +/* MC firmware base low/high registers indexes */ |
||
77 | +#define MCFBALR_OFFSET 0 |
||
78 | +#define MCFBAHR_OFFSET 1 |
||
79 | + |
||
80 | +/* Bit mask used to obtain the most significant part of the MC base address */ |
||
81 | +#define MC_FW_HIGH_ADDR_MASK 0x1FFFF |
||
82 | +/* Bit mask used to obtain the least significant part of the MC base address */ |
||
83 | +#define MC_FW_LOW_ADDR_MASK 0xE0000000 |
||
84 | + |
||
85 | +#define MC_BUFFER_OFFSET 0x01000000 |
||
86 | +#define MC_BUFFER_SIZE (1024*1024*16) |
||
87 | +#define MC_OFFSET_DELTA (MC_BUFFER_OFFSET) |
||
88 | + |
||
89 | +#define AIOP_BUFFER_OFFSET 0x06000000 |
||
90 | +#define AIOP_BUFFER_SIZE (1024*1024*16) |
||
91 | +#define AIOP_OFFSET_DELTA (0) |
||
92 | + |
||
93 | +struct log_header { |
||
94 | + char magic_word[8]; /* magic word */ |
||
95 | + uint32_t buf_start; /* holds the 32-bit little-endian |
||
96 | + * offset of the start of the buffer |
||
97 | + */ |
||
98 | + uint32_t buf_length; /* holds the 32-bit little-endian |
||
99 | + * length of the buffer |
||
100 | + */ |
||
101 | + uint32_t last_byte; /* holds the 32-bit little-endian offset |
||
102 | + * of the byte after the last byte that |
||
103 | + * was written |
||
104 | + */ |
||
105 | + char reserved[44]; |
||
106 | +}; |
||
107 | + |
||
108 | +#define LOG_HEADER_FLAG_BUFFER_WRAPAROUND 0x80000000 |
||
109 | +#define LOG_VERSION_MAJOR 1 |
||
110 | +#define LOG_VERSION_MINOR 0 |
||
111 | + |
||
112 | + |
||
113 | +#define invalidate(p) { asm volatile("dc ivac, %0" : : "r" (p) : "memory"); } |
||
114 | + |
||
115 | +struct console_data { |
||
116 | + char *map_addr; |
||
117 | + struct log_header *hdr; |
||
118 | + char *start_addr; /* Start of buffer */ |
||
119 | + char *end_addr; /* End of buffer */ |
||
120 | + char *end_of_data; /* Current end of data */ |
||
121 | + char *cur_ptr; /* Last data sent to console */ |
||
122 | +}; |
||
123 | + |
||
124 | +#define LAST_BYTE(a) ((a) & ~(LOG_HEADER_FLAG_BUFFER_WRAPAROUND)) |
||
125 | + |
||
126 | +static inline void __adjust_end(struct console_data *cd) |
||
127 | +{ |
||
128 | + cd->end_of_data = cd->start_addr |
||
129 | + + LAST_BYTE(le32_to_cpu(cd->hdr->last_byte)); |
||
130 | +} |
||
131 | + |
||
132 | +static inline void adjust_end(struct console_data *cd) |
||
133 | +{ |
||
134 | + invalidate(cd->hdr); |
||
135 | + __adjust_end(cd); |
||
136 | +} |
||
137 | + |
||
138 | +static inline uint64_t get_mc_fw_base_address(void) |
||
139 | +{ |
||
140 | + u32 *mcfbaregs = (u32 *) ioremap(SOC_CCSR_MC_FW_BASE_ADDR_REGS, |
||
141 | + SOC_CCSR_MC_FW_BASE_ADDR_REGS_SIZE); |
||
142 | + u64 mcfwbase = 0ULL; |
||
143 | + |
||
144 | + mcfwbase = readl(mcfbaregs + MCFBAHR_OFFSET) & MC_FW_HIGH_ADDR_MASK; |
||
145 | + mcfwbase <<= 32; |
||
146 | + mcfwbase |= readl(mcfbaregs + MCFBALR_OFFSET) & MC_FW_LOW_ADDR_MASK; |
||
147 | + iounmap(mcfbaregs); |
||
148 | + pr_info("fsl-ls2-console: MC base address at 0x%016llx\n", mcfwbase); |
||
149 | + return mcfwbase; |
||
150 | +} |
||
151 | + |
||
152 | +static int fsl_ls2_generic_console_open(struct inode *node, struct file *fp, |
||
153 | + u64 offset, u64 size, |
||
154 | + uint8_t *emagic, uint8_t magic_len, |
||
155 | + u32 offset_delta) |
||
156 | +{ |
||
157 | + struct console_data *cd; |
||
158 | + uint8_t *magic; |
||
159 | + uint32_t wrapped; |
||
160 | + |
||
161 | + cd = kmalloc(sizeof(*cd), GFP_KERNEL); |
||
162 | + if (cd == NULL) |
||
163 | + return -ENOMEM; |
||
164 | + fp->private_data = cd; |
||
165 | + cd->map_addr = ioremap(get_mc_fw_base_address() + offset, size); |
||
166 | + |
||
167 | + cd->hdr = (struct log_header *) cd->map_addr; |
||
168 | + invalidate(cd->hdr); |
||
169 | + |
||
170 | + magic = cd->hdr->magic_word; |
||
171 | + if (memcmp(magic, emagic, magic_len)) { |
||
172 | + pr_info("magic didn't match!\n"); |
||
173 | + pr_info("expected: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
||
174 | + emagic[0], emagic[1], emagic[2], emagic[3], |
||
175 | + emagic[4], emagic[5], emagic[6], emagic[7]); |
||
176 | + pr_info(" seen: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
||
177 | + magic[0], magic[1], magic[2], magic[3], |
||
178 | + magic[4], magic[5], magic[6], magic[7]); |
||
179 | + kfree(cd); |
||
180 | + iounmap(cd->map_addr); |
||
181 | + return -EIO; |
||
182 | + } |
||
183 | + |
||
184 | + cd->start_addr = cd->map_addr |
||
185 | + + le32_to_cpu(cd->hdr->buf_start) - offset_delta; |
||
186 | + cd->end_addr = cd->start_addr + le32_to_cpu(cd->hdr->buf_length); |
||
187 | + |
||
188 | + wrapped = le32_to_cpu(cd->hdr->last_byte) |
||
189 | + & LOG_HEADER_FLAG_BUFFER_WRAPAROUND; |
||
190 | + |
||
191 | + __adjust_end(cd); |
||
192 | + if (wrapped && (cd->end_of_data != cd->end_addr)) |
||
193 | + cd->cur_ptr = cd->end_of_data+1; |
||
194 | + else |
||
195 | + cd->cur_ptr = cd->start_addr; |
||
196 | + |
||
197 | + return 0; |
||
198 | +} |
||
199 | + |
||
200 | +static int fsl_ls2_mc_console_open(struct inode *node, struct file *fp) |
||
201 | +{ |
||
202 | + uint8_t magic_word[] = { 0, 1, 'C', 'M' }; |
||
203 | + |
||
204 | + return fsl_ls2_generic_console_open(node, fp, |
||
205 | + MC_BUFFER_OFFSET, MC_BUFFER_SIZE, |
||
206 | + magic_word, sizeof(magic_word), |
||
207 | + MC_OFFSET_DELTA); |
||
208 | +} |
||
209 | + |
||
210 | +static int fsl_ls2_aiop_console_open(struct inode *node, struct file *fp) |
||
211 | +{ |
||
212 | + uint8_t magic_word[] = { 'P', 'O', 'I', 'A' }; |
||
213 | + |
||
214 | + return fsl_ls2_generic_console_open(node, fp, |
||
215 | + AIOP_BUFFER_OFFSET, AIOP_BUFFER_SIZE, |
||
216 | + magic_word, sizeof(magic_word), |
||
217 | + AIOP_OFFSET_DELTA); |
||
218 | +} |
||
219 | + |
||
220 | +static int fsl_ls2_console_close(struct inode *node, struct file *fp) |
||
221 | +{ |
||
222 | + struct console_data *cd = fp->private_data; |
||
223 | + |
||
224 | + iounmap(cd->map_addr); |
||
225 | + kfree(cd); |
||
226 | + return 0; |
||
227 | +} |
||
228 | + |
||
229 | +ssize_t fsl_ls2_console_read(struct file *fp, char __user *buf, size_t count, |
||
230 | + loff_t *f_pos) |
||
231 | +{ |
||
232 | + struct console_data *cd = fp->private_data; |
||
233 | + size_t bytes = 0; |
||
234 | + char data; |
||
235 | + |
||
236 | + /* Check if we need to adjust the end of data addr */ |
||
237 | + adjust_end(cd); |
||
238 | + |
||
239 | + while ((count != bytes) && (cd->end_of_data != cd->cur_ptr)) { |
||
240 | + if (((u64)cd->cur_ptr) % 64 == 0) |
||
241 | + invalidate(cd->cur_ptr); |
||
242 | + |
||
243 | + data = *(cd->cur_ptr); |
||
244 | + if (copy_to_user(&buf[bytes], &data, 1)) |
||
245 | + return -EFAULT; |
||
246 | + cd->cur_ptr++; |
||
247 | + if (cd->cur_ptr >= cd->end_addr) |
||
248 | + cd->cur_ptr = cd->start_addr; |
||
249 | + ++bytes; |
||
250 | + } |
||
251 | + return bytes; |
||
252 | +} |
||
253 | + |
||
254 | +static const struct file_operations fsl_ls2_mc_console_fops = { |
||
255 | + .owner = THIS_MODULE, |
||
256 | + .open = fsl_ls2_mc_console_open, |
||
257 | + .release = fsl_ls2_console_close, |
||
258 | + .read = fsl_ls2_console_read, |
||
259 | +}; |
||
260 | + |
||
261 | +static struct miscdevice fsl_ls2_mc_console_dev = { |
||
262 | + .minor = MISC_DYNAMIC_MINOR, |
||
263 | + .name = "fsl_mc_console", |
||
264 | + .fops = &fsl_ls2_mc_console_fops |
||
265 | +}; |
||
266 | + |
||
267 | +static const struct file_operations fsl_ls2_aiop_console_fops = { |
||
268 | + .owner = THIS_MODULE, |
||
269 | + .open = fsl_ls2_aiop_console_open, |
||
270 | + .release = fsl_ls2_console_close, |
||
271 | + .read = fsl_ls2_console_read, |
||
272 | +}; |
||
273 | + |
||
274 | +static struct miscdevice fsl_ls2_aiop_console_dev = { |
||
275 | + .minor = MISC_DYNAMIC_MINOR, |
||
276 | + .name = "fsl_aiop_console", |
||
277 | + .fops = &fsl_ls2_aiop_console_fops |
||
278 | +}; |
||
279 | + |
||
280 | +static int __init fsl_ls2_console_init(void) |
||
281 | +{ |
||
282 | + int err = 0; |
||
283 | + |
||
284 | + pr_info("Freescale LS2 console driver\n"); |
||
285 | + err = misc_register(&fsl_ls2_mc_console_dev); |
||
286 | + if (err) { |
||
287 | + pr_err("fsl_mc_console: cannot register device\n"); |
||
288 | + return err; |
||
289 | + } |
||
290 | + pr_info("fsl-ls2-console: device %s registered\n", |
||
291 | + fsl_ls2_mc_console_dev.name); |
||
292 | + |
||
293 | + err = misc_register(&fsl_ls2_aiop_console_dev); |
||
294 | + if (err) { |
||
295 | + pr_err("fsl_aiop_console: cannot register device\n"); |
||
296 | + return err; |
||
297 | + } |
||
298 | + pr_info("fsl-ls2-console: device %s registered\n", |
||
299 | + fsl_ls2_aiop_console_dev.name); |
||
300 | + |
||
301 | + return 0; |
||
302 | +} |
||
303 | + |
||
304 | +static void __exit fsl_ls2_console_exit(void) |
||
305 | +{ |
||
306 | + misc_deregister(&fsl_ls2_mc_console_dev); |
||
307 | + |
||
308 | + misc_deregister(&fsl_ls2_aiop_console_dev); |
||
309 | +} |
||
310 | + |
||
311 | +module_init(fsl_ls2_console_init); |
||
312 | +module_exit(fsl_ls2_console_exit); |
||
313 | + |
||
314 | +MODULE_AUTHOR("Roy Pledge <roy.pledge@freescale.com>"); |
||
315 | +MODULE_LICENSE("Dual BSD/GPL"); |
||
316 | +MODULE_DESCRIPTION("Freescale LS2 console driver"); |