aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-09-13 03:08:55 -0400
committerIngo Molnar <mingo@elte.hu>2010-10-08 04:01:47 -0400
commitc20b5c3318fe45e4f33f01a91ccead645dfdf619 (patch)
tree7fb6e9ad8643b60c93ba2dc163c010f3b6978836 /arch/x86
parent5a47c7dae861c3ca3edf178546641909851bf715 (diff)
x86, earlyprintk: Add earlyprintk for Intel Moorestown platform
Intel Moorestown platform has a spi-uart device(Maxim3110), which connects to a Designware spi core controller. This patch will add early console function based on it. As it will be used long before Linux spi subsystem get initialised, we simply directly manipulate the spi controller's register to acheive the early console func. This is safe as it will be disabled when devices subsytem get initialised. To use it, user need enable CONFIG_X86_MRST_EARLY_PRINTK in kenrel config and add "earlyprintk=mrst" in kernel command line. Signed-off-by: Feng Tang <feng.tang@intel.com> Acked-by: Alan Cox <alan@linux.intel.com> Cc: greg@kroah.com LKML-Reference: <1284361736-23011-4-git-send-email-feng.tang@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/Kconfig.debug4
-rw-r--r--arch/x86/include/asm/mrst.h5
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/early_printk.c7
-rw-r--r--arch/x86/kernel/early_printk_mrst.c232
5 files changed, 249 insertions, 0 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 75085080b63e..e5bb96b10f1a 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -43,6 +43,10 @@ config EARLY_PRINTK
43 with klogd/syslogd or the X server. You should normally N here, 43 with klogd/syslogd or the X server. You should normally N here,
44 unless you want to debug such a crash. 44 unless you want to debug such a crash.
45 45
46config EARLY_PRINTK_MRST
47 bool "Early printk for MRST platform support"
48 depends on EARLY_PRINTK && X86_MRST
49
46config EARLY_PRINTK_DBGP 50config EARLY_PRINTK_DBGP
47 bool "Early printk via EHCI debug port" 51 bool "Early printk via EHCI debug port"
48 depends on EARLY_PRINTK && PCI 52 depends on EARLY_PRINTK && PCI
diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h
index 33fc2966beb7..d0ea5bc505a3 100644
--- a/arch/x86/include/asm/mrst.h
+++ b/arch/x86/include/asm/mrst.h
@@ -10,6 +10,9 @@
10 */ 10 */
11#ifndef _ASM_X86_MRST_H 11#ifndef _ASM_X86_MRST_H
12#define _ASM_X86_MRST_H 12#define _ASM_X86_MRST_H
13
14#include <linux/sfi.h>
15
13extern int pci_mrst_init(void); 16extern int pci_mrst_init(void);
14int __init sfi_parse_mrtc(struct sfi_table_header *table); 17int __init sfi_parse_mrtc(struct sfi_table_header *table);
15 18
@@ -42,4 +45,6 @@ extern enum mrst_timer_options mrst_timer_options;
42#define SFI_MTMR_MAX_NUM 8 45#define SFI_MTMR_MAX_NUM 8
43#define SFI_MRTC_MAX 8 46#define SFI_MRTC_MAX 8
44 47
48extern struct console early_mrst_console;
49extern void mrst_early_console_init(void);
45#endif /* _ASM_X86_MRST_H */ 50#endif /* _ASM_X86_MRST_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index fedf32a8c3ec..3cd01d04613d 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o
85obj-$(CONFIG_KGDB) += kgdb.o 85obj-$(CONFIG_KGDB) += kgdb.o
86obj-$(CONFIG_VM86) += vm86_32.o 86obj-$(CONFIG_VM86) += vm86_32.o
87obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 87obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
88obj-$(CONFIG_EARLY_PRINTK_MRST) += early_printk_mrst.o
88 89
89obj-$(CONFIG_HPET_TIMER) += hpet.o 90obj-$(CONFIG_HPET_TIMER) += hpet.o
90obj-$(CONFIG_APB_TIMER) += apb_timer.o 91obj-$(CONFIG_APB_TIMER) += apb_timer.o
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index fa99bae75ace..6082463768a2 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -14,6 +14,7 @@
14#include <xen/hvc-console.h> 14#include <xen/hvc-console.h>
15#include <asm/pci-direct.h> 15#include <asm/pci-direct.h>
16#include <asm/fixmap.h> 16#include <asm/fixmap.h>
17#include <asm/mrst.h>
17#include <asm/pgtable.h> 18#include <asm/pgtable.h>
18#include <linux/usb/ehci_def.h> 19#include <linux/usb/ehci_def.h>
19 20
@@ -239,6 +240,12 @@ static int __init setup_early_printk(char *buf)
239 if (!strncmp(buf, "xen", 3)) 240 if (!strncmp(buf, "xen", 3))
240 early_console_register(&xenboot_console, keep); 241 early_console_register(&xenboot_console, keep);
241#endif 242#endif
243#ifdef CONFIG_X86_MRST_EARLY_PRINTK
244 if (!strncmp(buf, "mrst", 4)) {
245 mrst_early_console_init();
246 early_console_register(&early_mrst_console, keep);
247 }
248#endif
242 buf++; 249 buf++;
243 } 250 }
244 return 0; 251 return 0;
diff --git a/arch/x86/kernel/early_printk_mrst.c b/arch/x86/kernel/early_printk_mrst.c
new file mode 100644
index 000000000000..05d27e1e2b62
--- /dev/null
+++ b/arch/x86/kernel/early_printk_mrst.c
@@ -0,0 +1,232 @@
1/*
2 * early_printk_mrst.c - spi-uart early printk for Intel Moorestown platform
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#include <linux/kmsg_dump.h>
13#include <linux/console.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/io.h>
17
18#include <asm/fixmap.h>
19#include <asm/pgtable.h>
20#include <asm/mrst.h>
21
22#define MRST_SPI_TIMEOUT 0x200000
23#define MRST_REGBASE_SPI0 0xff128000
24#define MRST_REGBASE_SPI1 0xff128400
25#define MRST_CLK_SPI0_REG 0xff11d86c
26
27/* Bit fields in CTRLR0 */
28#define SPI_DFS_OFFSET 0
29
30#define SPI_FRF_OFFSET 4
31#define SPI_FRF_SPI 0x0
32#define SPI_FRF_SSP 0x1
33#define SPI_FRF_MICROWIRE 0x2
34#define SPI_FRF_RESV 0x3
35
36#define SPI_MODE_OFFSET 6
37#define SPI_SCPH_OFFSET 6
38#define SPI_SCOL_OFFSET 7
39#define SPI_TMOD_OFFSET 8
40#define SPI_TMOD_TR 0x0 /* xmit & recv */
41#define SPI_TMOD_TO 0x1 /* xmit only */
42#define SPI_TMOD_RO 0x2 /* recv only */
43#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
44
45#define SPI_SLVOE_OFFSET 10
46#define SPI_SRL_OFFSET 11
47#define SPI_CFS_OFFSET 12
48
49/* Bit fields in SR, 7 bits */
50#define SR_MASK 0x7f /* cover 7 bits */
51#define SR_BUSY (1 << 0)
52#define SR_TF_NOT_FULL (1 << 1)
53#define SR_TF_EMPT (1 << 2)
54#define SR_RF_NOT_EMPT (1 << 3)
55#define SR_RF_FULL (1 << 4)
56#define SR_TX_ERR (1 << 5)
57#define SR_DCOL (1 << 6)
58
59struct dw_spi_reg {
60 u32 ctrl0;
61 u32 ctrl1;
62 u32 ssienr;
63 u32 mwcr;
64 u32 ser;
65 u32 baudr;
66 u32 txfltr;
67 u32 rxfltr;
68 u32 txflr;
69 u32 rxflr;
70 u32 sr;
71 u32 imr;
72 u32 isr;
73 u32 risr;
74 u32 txoicr;
75 u32 rxoicr;
76 u32 rxuicr;
77 u32 msticr;
78 u32 icr;
79 u32 dmacr;
80 u32 dmatdlr;
81 u32 dmardlr;
82 u32 idr;
83 u32 version;
84
85 /* Currently operates as 32 bits, though only the low 16 bits matter */
86 u32 dr;
87} __packed;
88
89#define dw_readl(dw, name) __raw_readl(&(dw)->name)
90#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name)
91
92/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */
93static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
94
95static u32 *pclk_spi0;
96/* Always contains an accessable address, start with 0 */
97static struct dw_spi_reg *pspi;
98
99static struct kmsg_dumper dw_dumper;
100static int dumper_registered;
101
102static void dw_kmsg_dump(struct kmsg_dumper *dumper,
103 enum kmsg_dump_reason reason,
104 const char *s1, unsigned long l1,
105 const char *s2, unsigned long l2)
106{
107 int i;
108
109 /* When run to this, we'd better re-init the HW */
110 mrst_early_console_init();
111
112 for (i = 0; i < l1; i++)
113 early_mrst_console.write(&early_mrst_console, s1 + i, 1);
114 for (i = 0; i < l2; i++)
115 early_mrst_console.write(&early_mrst_console, s2 + i, 1);
116}
117
118/* Set the ratio rate to 115200, 8n1, IRQ disabled */
119static void max3110_write_config(void)
120{
121 u16 config;
122
123 config = 0xc001;
124 dw_writel(pspi, dr, config);
125}
126
127/* Translate char to a eligible word and send to max3110 */
128static void max3110_write_data(char c)
129{
130 u16 data;
131
132 data = 0x8000 | c;
133 dw_writel(pspi, dr, data);
134}
135
136void mrst_early_console_init(void)
137{
138 u32 ctrlr0 = 0;
139 u32 spi0_cdiv;
140 u32 freq; /* Freqency info only need be searched once */
141
142 /* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
143 pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
144 MRST_CLK_SPI0_REG);
145 spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
146 freq = 100000000 / (spi0_cdiv + 1);
147
148 if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL)
149 mrst_spi_paddr = MRST_REGBASE_SPI1;
150
151 pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
152 mrst_spi_paddr);
153
154 /* Disable SPI controller */
155 dw_writel(pspi, ssienr, 0);
156
157 /* Set control param, 8 bits, transmit only mode */
158 ctrlr0 = dw_readl(pspi, ctrl0);
159
160 ctrlr0 &= 0xfcc0;
161 ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
162 | (SPI_TMOD_TO << SPI_TMOD_OFFSET);
163 dw_writel(pspi, ctrl0, ctrlr0);
164
165 /*
166 * Change the spi0 clk to comply with 115200 bps, use 100000 to
167 * calculate the clk dividor to make the clock a little slower
168 * than real baud rate.
169 */
170 dw_writel(pspi, baudr, freq/100000);
171
172 /* Disable all INT for early phase */
173 dw_writel(pspi, imr, 0x0);
174
175 /* Set the cs to spi-uart */
176 dw_writel(pspi, ser, 0x2);
177
178 /* Enable the HW, the last step for HW init */
179 dw_writel(pspi, ssienr, 0x1);
180
181 /* Set the default configuration */
182 max3110_write_config();
183
184 /* Register the kmsg dumper */
185 if (!dumper_registered) {
186 dw_dumper.dump = dw_kmsg_dump;
187 kmsg_dump_register(&dw_dumper);
188 dumper_registered = 1;
189 }
190}
191
192/* Slave select should be called in the read/write function */
193static void early_mrst_spi_putc(char c)
194{
195 unsigned int timeout;
196 u32 sr;
197
198 timeout = MRST_SPI_TIMEOUT;
199 /* Early putc needs to make sure the TX FIFO is not full */
200 while (--timeout) {
201 sr = dw_readl(pspi, sr);
202 if (!(sr & SR_TF_NOT_FULL))
203 cpu_relax();
204 else
205 break;
206 }
207
208 if (!timeout)
209 pr_warning("MRST earlycon: timed out\n");
210 else
211 max3110_write_data(c);
212}
213
214/* Early SPI only uses polling mode */
215static void early_mrst_spi_write(struct console *con, const char *str, unsigned n)
216{
217 int i;
218
219 for (i = 0; i < n && *str; i++) {
220 if (*str == '\n')
221 early_mrst_spi_putc('\r');
222 early_mrst_spi_putc(*str);
223 str++;
224 }
225}
226
227struct console early_mrst_console = {
228 .name = "earlymrst",
229 .write = early_mrst_spi_write,
230 .flags = CON_PRINTBUFFER,
231 .index = -1,
232};