kernel: bump 4.14 to 4.14.125 (FS#2305 FS#2297)
[oweals/openwrt.git] / target / linux / layerscape / patches-4.14 / 814-ls2-console-support-layerscape.patch
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");