blob: 679c814dffa856a212e9b0e69acd1f942164e23b [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Youness Alaouic4b4ff32017-05-11 10:36:29 -04002
Elyes HAOUAS361a9352019-12-18 21:26:33 +01003#include <commonlib/helpers.h>
Arthur Heymansc2a9f0c2018-03-28 18:48:24 +02004#include <commonlib/region.h>
Youness Alaouic4b4ff32017-05-11 10:36:29 -04005#include <fmap.h>
6#include <console/console.h>
7#include <console/flash.h>
Elyes HAOUASede8dd02019-06-23 06:57:53 +02008#include <types.h>
Youness Alaouic4b4ff32017-05-11 10:36:29 -04009
10#define LINE_BUFFER_SIZE 128
11#define READ_BUFFER_SIZE 0x100
12
Patrick Georgic9b13592019-11-29 11:47:47 +010013static const struct region_device *rdev_ptr;
14static struct region_device rdev;
15static uint8_t line_buffer[LINE_BUFFER_SIZE];
16static size_t offset;
17static size_t line_offset;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040018
19void flashconsole_init(void)
20{
Youness Alaouic4b4ff32017-05-11 10:36:29 -040021 uint8_t buffer[READ_BUFFER_SIZE];
22 size_t size;
Johanna Schander1c9746c2020-01-04 04:05:02 +010023 size_t initial_offset = 0;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040024 size_t len = READ_BUFFER_SIZE;
25 size_t i;
26
Patrick Georgic9b13592019-11-29 11:47:47 +010027 if (fmap_locate_area_as_rdev_rw("CONSOLE", &rdev)) {
Youness Alaouic4b4ff32017-05-11 10:36:29 -040028 printk(BIOS_INFO, "Can't find 'CONSOLE' area in FMAP\n");
29 return;
30 }
Patrick Georgic9b13592019-11-29 11:47:47 +010031 size = region_device_sz(&rdev);
Youness Alaouic4b4ff32017-05-11 10:36:29 -040032
33 /*
34 * We need to check the region until we find a 0xff indicating
35 * the end of a previous log write.
36 * We can't erase the region because one stage would erase the
37 * data from the previous stage. Also, it looks like doing an
38 * erase could completely freeze the SPI controller and then
39 * we can't write anything anymore (apparently might happen if
40 * the sector is already erased, so we would need to read
41 * anyways to check if it's all 0xff).
42 */
Johanna Schander1c9746c2020-01-04 04:05:02 +010043 for (i = 0; i < len && initial_offset < size;) {
Youness Alaouic4b4ff32017-05-11 10:36:29 -040044 // Fill the buffer on first iteration
45 if (i == 0) {
Elyes HAOUAS361a9352019-12-18 21:26:33 +010046 len = MIN(READ_BUFFER_SIZE, size - offset);
Johanna Schander1c9746c2020-01-04 04:05:02 +010047 if (rdev_readat(&rdev, buffer, initial_offset, len) != len)
Youness Alaouic4b4ff32017-05-11 10:36:29 -040048 return;
49 }
50 if (buffer[i] == 0xff) {
Johanna Schander1c9746c2020-01-04 04:05:02 +010051 initial_offset += i;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040052 break;
53 }
54 // If we're done, repeat the process for the next sector
55 if (++i == READ_BUFFER_SIZE) {
Johanna Schander1c9746c2020-01-04 04:05:02 +010056 initial_offset += len;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040057 i = 0;
58 }
59 }
60 // Make sure there is still space left on the console
Johanna Schander1c9746c2020-01-04 04:05:02 +010061 if (initial_offset >= size) {
Youness Alaouic4b4ff32017-05-11 10:36:29 -040062 printk(BIOS_INFO, "No space left on 'console' region in SPI flash\n");
63 return;
64 }
65
Johanna Schander1c9746c2020-01-04 04:05:02 +010066 offset = initial_offset;
Patrick Georgic9b13592019-11-29 11:47:47 +010067 rdev_ptr = &rdev;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040068}
69
70void flashconsole_tx_byte(unsigned char c)
71{
Patrick Georgic9b13592019-11-29 11:47:47 +010072 if (!rdev_ptr)
Youness Alaouic4b4ff32017-05-11 10:36:29 -040073 return;
74
Patrick Georgic9b13592019-11-29 11:47:47 +010075 size_t region_size = region_device_sz(rdev_ptr);
Youness Alaouic4b4ff32017-05-11 10:36:29 -040076
Nico Huber361a5c02020-11-26 13:35:09 +010077 if (line_offset < LINE_BUFFER_SIZE)
78 line_buffer[line_offset++] = c;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040079
Patrick Georgic9b13592019-11-29 11:47:47 +010080 if (line_offset >= LINE_BUFFER_SIZE ||
81 offset + line_offset >= region_size || c == '\n') {
Youness Alaouic4b4ff32017-05-11 10:36:29 -040082 flashconsole_tx_flush();
83 }
84}
85
86void flashconsole_tx_flush(void)
87{
Patrick Georgic9b13592019-11-29 11:47:47 +010088 size_t len = line_offset;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040089 size_t region_size;
Arthur Heymans6ea3a132019-11-20 21:50:54 +010090 static int busy;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040091
92 /* Prevent any recursive loops in case the spi flash driver
93 * calls printk (in case of transaction timeout or
94 * any other error while writing) */
Arthur Heymans6ea3a132019-11-20 21:50:54 +010095 if (busy)
96 return;
Youness Alaouic4b4ff32017-05-11 10:36:29 -040097
Patrick Georgic9b13592019-11-29 11:47:47 +010098 if (!rdev_ptr)
Arthur Heymans6ea3a132019-11-20 21:50:54 +010099 return;
100
101 busy = 1;
Patrick Georgic9b13592019-11-29 11:47:47 +0100102 region_size = region_device_sz(rdev_ptr);
Youness Alaouic4b4ff32017-05-11 10:36:29 -0400103 if (offset + len >= region_size)
104 len = region_size - offset;
105
Patrick Georgic9b13592019-11-29 11:47:47 +0100106 if (rdev_writeat(&rdev, line_buffer, offset, len) != len)
Arthur Heymans6ea3a132019-11-20 21:50:54 +0100107 return;
Youness Alaouic4b4ff32017-05-11 10:36:29 -0400108
109 // If the region is full, stop future write attempts
110 if (offset + len >= region_size)
Arthur Heymans6ea3a132019-11-20 21:50:54 +0100111 return;
Youness Alaouic4b4ff32017-05-11 10:36:29 -0400112
Johanna Schander1c9746c2020-01-04 04:05:02 +0100113 offset += len;
Patrick Georgic9b13592019-11-29 11:47:47 +0100114 line_offset = 0;
Youness Alaouic4b4ff32017-05-11 10:36:29 -0400115
Arthur Heymans6ea3a132019-11-20 21:50:54 +0100116 busy = 0;
Youness Alaouic4b4ff32017-05-11 10:36:29 -0400117}