Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/platform/mrst/early_printk_mrst.c
10819 views
1
/*
2
* early_printk_mrst.c - early consoles for Intel MID platforms
3
*
4
* Copyright (c) 2008-2010, Intel Corporation
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; version 2
9
* of the License.
10
*/
11
12
/*
13
* This file implements two early consoles named mrst and hsu.
14
* mrst is based on Maxim3110 spi-uart device, it exists in both
15
* Moorestown and Medfield platforms, while hsu is based on a High
16
* Speed UART device which only exists in the Medfield platform
17
*/
18
19
#include <linux/serial_reg.h>
20
#include <linux/serial_mfd.h>
21
#include <linux/kmsg_dump.h>
22
#include <linux/console.h>
23
#include <linux/kernel.h>
24
#include <linux/delay.h>
25
#include <linux/init.h>
26
#include <linux/io.h>
27
28
#include <asm/fixmap.h>
29
#include <asm/pgtable.h>
30
#include <asm/mrst.h>
31
32
#define MRST_SPI_TIMEOUT 0x200000
33
#define MRST_REGBASE_SPI0 0xff128000
34
#define MRST_REGBASE_SPI1 0xff128400
35
#define MRST_CLK_SPI0_REG 0xff11d86c
36
37
/* Bit fields in CTRLR0 */
38
#define SPI_DFS_OFFSET 0
39
40
#define SPI_FRF_OFFSET 4
41
#define SPI_FRF_SPI 0x0
42
#define SPI_FRF_SSP 0x1
43
#define SPI_FRF_MICROWIRE 0x2
44
#define SPI_FRF_RESV 0x3
45
46
#define SPI_MODE_OFFSET 6
47
#define SPI_SCPH_OFFSET 6
48
#define SPI_SCOL_OFFSET 7
49
#define SPI_TMOD_OFFSET 8
50
#define SPI_TMOD_TR 0x0 /* xmit & recv */
51
#define SPI_TMOD_TO 0x1 /* xmit only */
52
#define SPI_TMOD_RO 0x2 /* recv only */
53
#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
54
55
#define SPI_SLVOE_OFFSET 10
56
#define SPI_SRL_OFFSET 11
57
#define SPI_CFS_OFFSET 12
58
59
/* Bit fields in SR, 7 bits */
60
#define SR_MASK 0x7f /* cover 7 bits */
61
#define SR_BUSY (1 << 0)
62
#define SR_TF_NOT_FULL (1 << 1)
63
#define SR_TF_EMPT (1 << 2)
64
#define SR_RF_NOT_EMPT (1 << 3)
65
#define SR_RF_FULL (1 << 4)
66
#define SR_TX_ERR (1 << 5)
67
#define SR_DCOL (1 << 6)
68
69
struct dw_spi_reg {
70
u32 ctrl0;
71
u32 ctrl1;
72
u32 ssienr;
73
u32 mwcr;
74
u32 ser;
75
u32 baudr;
76
u32 txfltr;
77
u32 rxfltr;
78
u32 txflr;
79
u32 rxflr;
80
u32 sr;
81
u32 imr;
82
u32 isr;
83
u32 risr;
84
u32 txoicr;
85
u32 rxoicr;
86
u32 rxuicr;
87
u32 msticr;
88
u32 icr;
89
u32 dmacr;
90
u32 dmatdlr;
91
u32 dmardlr;
92
u32 idr;
93
u32 version;
94
95
/* Currently operates as 32 bits, though only the low 16 bits matter */
96
u32 dr;
97
} __packed;
98
99
#define dw_readl(dw, name) __raw_readl(&(dw)->name)
100
#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name)
101
102
/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */
103
static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
104
105
static u32 *pclk_spi0;
106
/* Always contains an accessible address, start with 0 */
107
static struct dw_spi_reg *pspi;
108
109
static struct kmsg_dumper dw_dumper;
110
static int dumper_registered;
111
112
static void dw_kmsg_dump(struct kmsg_dumper *dumper,
113
enum kmsg_dump_reason reason,
114
const char *s1, unsigned long l1,
115
const char *s2, unsigned long l2)
116
{
117
int i;
118
119
/* When run to this, we'd better re-init the HW */
120
mrst_early_console_init();
121
122
for (i = 0; i < l1; i++)
123
early_mrst_console.write(&early_mrst_console, s1 + i, 1);
124
for (i = 0; i < l2; i++)
125
early_mrst_console.write(&early_mrst_console, s2 + i, 1);
126
}
127
128
/* Set the ratio rate to 115200, 8n1, IRQ disabled */
129
static void max3110_write_config(void)
130
{
131
u16 config;
132
133
config = 0xc001;
134
dw_writel(pspi, dr, config);
135
}
136
137
/* Translate char to a eligible word and send to max3110 */
138
static void max3110_write_data(char c)
139
{
140
u16 data;
141
142
data = 0x8000 | c;
143
dw_writel(pspi, dr, data);
144
}
145
146
void mrst_early_console_init(void)
147
{
148
u32 ctrlr0 = 0;
149
u32 spi0_cdiv;
150
u32 freq; /* Freqency info only need be searched once */
151
152
/* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
153
pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
154
MRST_CLK_SPI0_REG);
155
spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
156
freq = 100000000 / (spi0_cdiv + 1);
157
158
if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL)
159
mrst_spi_paddr = MRST_REGBASE_SPI1;
160
161
pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
162
mrst_spi_paddr);
163
164
/* Disable SPI controller */
165
dw_writel(pspi, ssienr, 0);
166
167
/* Set control param, 8 bits, transmit only mode */
168
ctrlr0 = dw_readl(pspi, ctrl0);
169
170
ctrlr0 &= 0xfcc0;
171
ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
172
| (SPI_TMOD_TO << SPI_TMOD_OFFSET);
173
dw_writel(pspi, ctrl0, ctrlr0);
174
175
/*
176
* Change the spi0 clk to comply with 115200 bps, use 100000 to
177
* calculate the clk dividor to make the clock a little slower
178
* than real baud rate.
179
*/
180
dw_writel(pspi, baudr, freq/100000);
181
182
/* Disable all INT for early phase */
183
dw_writel(pspi, imr, 0x0);
184
185
/* Set the cs to spi-uart */
186
dw_writel(pspi, ser, 0x2);
187
188
/* Enable the HW, the last step for HW init */
189
dw_writel(pspi, ssienr, 0x1);
190
191
/* Set the default configuration */
192
max3110_write_config();
193
194
/* Register the kmsg dumper */
195
if (!dumper_registered) {
196
dw_dumper.dump = dw_kmsg_dump;
197
kmsg_dump_register(&dw_dumper);
198
dumper_registered = 1;
199
}
200
}
201
202
/* Slave select should be called in the read/write function */
203
static void early_mrst_spi_putc(char c)
204
{
205
unsigned int timeout;
206
u32 sr;
207
208
timeout = MRST_SPI_TIMEOUT;
209
/* Early putc needs to make sure the TX FIFO is not full */
210
while (--timeout) {
211
sr = dw_readl(pspi, sr);
212
if (!(sr & SR_TF_NOT_FULL))
213
cpu_relax();
214
else
215
break;
216
}
217
218
if (!timeout)
219
pr_warning("MRST earlycon: timed out\n");
220
else
221
max3110_write_data(c);
222
}
223
224
/* Early SPI only uses polling mode */
225
static void early_mrst_spi_write(struct console *con, const char *str, unsigned n)
226
{
227
int i;
228
229
for (i = 0; i < n && *str; i++) {
230
if (*str == '\n')
231
early_mrst_spi_putc('\r');
232
early_mrst_spi_putc(*str);
233
str++;
234
}
235
}
236
237
struct console early_mrst_console = {
238
.name = "earlymrst",
239
.write = early_mrst_spi_write,
240
.flags = CON_PRINTBUFFER,
241
.index = -1,
242
};
243
244
/*
245
* Following is the early console based on Medfield HSU (High
246
* Speed UART) device.
247
*/
248
#define HSU_PORT2_PADDR 0xffa28180
249
250
static void __iomem *phsu;
251
252
void hsu_early_console_init(void)
253
{
254
u8 lcr;
255
256
phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
257
HSU_PORT2_PADDR);
258
259
/* Disable FIFO */
260
writeb(0x0, phsu + UART_FCR);
261
262
/* Set to default 115200 bps, 8n1 */
263
lcr = readb(phsu + UART_LCR);
264
writeb((0x80 | lcr), phsu + UART_LCR);
265
writeb(0x18, phsu + UART_DLL);
266
writeb(lcr, phsu + UART_LCR);
267
writel(0x3600, phsu + UART_MUL*4);
268
269
writeb(0x8, phsu + UART_MCR);
270
writeb(0x7, phsu + UART_FCR);
271
writeb(0x3, phsu + UART_LCR);
272
273
/* Clear IRQ status */
274
readb(phsu + UART_LSR);
275
readb(phsu + UART_RX);
276
readb(phsu + UART_IIR);
277
readb(phsu + UART_MSR);
278
279
/* Enable FIFO */
280
writeb(0x7, phsu + UART_FCR);
281
}
282
283
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
284
285
static void early_hsu_putc(char ch)
286
{
287
unsigned int timeout = 10000; /* 10ms */
288
u8 status;
289
290
while (--timeout) {
291
status = readb(phsu + UART_LSR);
292
if (status & BOTH_EMPTY)
293
break;
294
udelay(1);
295
}
296
297
/* Only write the char when there was no timeout */
298
if (timeout)
299
writeb(ch, phsu + UART_TX);
300
}
301
302
static void early_hsu_write(struct console *con, const char *str, unsigned n)
303
{
304
int i;
305
306
for (i = 0; i < n && *str; i++) {
307
if (*str == '\n')
308
early_hsu_putc('\r');
309
early_hsu_putc(*str);
310
str++;
311
}
312
}
313
314
struct console early_hsu_console = {
315
.name = "earlyhsu",
316
.write = early_hsu_write,
317
.flags = CON_PRINTBUFFER,
318
.index = -1,
319
};
320
321