Path: blob/master/arch/x86/platform/mrst/early_printk_mrst.c
10819 views
/*1* early_printk_mrst.c - early consoles for Intel MID platforms2*3* Copyright (c) 2008-2010, Intel Corporation4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License7* as published by the Free Software Foundation; version 28* of the License.9*/1011/*12* This file implements two early consoles named mrst and hsu.13* mrst is based on Maxim3110 spi-uart device, it exists in both14* Moorestown and Medfield platforms, while hsu is based on a High15* Speed UART device which only exists in the Medfield platform16*/1718#include <linux/serial_reg.h>19#include <linux/serial_mfd.h>20#include <linux/kmsg_dump.h>21#include <linux/console.h>22#include <linux/kernel.h>23#include <linux/delay.h>24#include <linux/init.h>25#include <linux/io.h>2627#include <asm/fixmap.h>28#include <asm/pgtable.h>29#include <asm/mrst.h>3031#define MRST_SPI_TIMEOUT 0x20000032#define MRST_REGBASE_SPI0 0xff12800033#define MRST_REGBASE_SPI1 0xff12840034#define MRST_CLK_SPI0_REG 0xff11d86c3536/* Bit fields in CTRLR0 */37#define SPI_DFS_OFFSET 03839#define SPI_FRF_OFFSET 440#define SPI_FRF_SPI 0x041#define SPI_FRF_SSP 0x142#define SPI_FRF_MICROWIRE 0x243#define SPI_FRF_RESV 0x34445#define SPI_MODE_OFFSET 646#define SPI_SCPH_OFFSET 647#define SPI_SCOL_OFFSET 748#define SPI_TMOD_OFFSET 849#define SPI_TMOD_TR 0x0 /* xmit & recv */50#define SPI_TMOD_TO 0x1 /* xmit only */51#define SPI_TMOD_RO 0x2 /* recv only */52#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */5354#define SPI_SLVOE_OFFSET 1055#define SPI_SRL_OFFSET 1156#define SPI_CFS_OFFSET 125758/* Bit fields in SR, 7 bits */59#define SR_MASK 0x7f /* cover 7 bits */60#define SR_BUSY (1 << 0)61#define SR_TF_NOT_FULL (1 << 1)62#define SR_TF_EMPT (1 << 2)63#define SR_RF_NOT_EMPT (1 << 3)64#define SR_RF_FULL (1 << 4)65#define SR_TX_ERR (1 << 5)66#define SR_DCOL (1 << 6)6768struct dw_spi_reg {69u32 ctrl0;70u32 ctrl1;71u32 ssienr;72u32 mwcr;73u32 ser;74u32 baudr;75u32 txfltr;76u32 rxfltr;77u32 txflr;78u32 rxflr;79u32 sr;80u32 imr;81u32 isr;82u32 risr;83u32 txoicr;84u32 rxoicr;85u32 rxuicr;86u32 msticr;87u32 icr;88u32 dmacr;89u32 dmatdlr;90u32 dmardlr;91u32 idr;92u32 version;9394/* Currently operates as 32 bits, though only the low 16 bits matter */95u32 dr;96} __packed;9798#define dw_readl(dw, name) __raw_readl(&(dw)->name)99#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name)100101/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */102static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;103104static u32 *pclk_spi0;105/* Always contains an accessible address, start with 0 */106static struct dw_spi_reg *pspi;107108static struct kmsg_dumper dw_dumper;109static int dumper_registered;110111static void dw_kmsg_dump(struct kmsg_dumper *dumper,112enum kmsg_dump_reason reason,113const char *s1, unsigned long l1,114const char *s2, unsigned long l2)115{116int i;117118/* When run to this, we'd better re-init the HW */119mrst_early_console_init();120121for (i = 0; i < l1; i++)122early_mrst_console.write(&early_mrst_console, s1 + i, 1);123for (i = 0; i < l2; i++)124early_mrst_console.write(&early_mrst_console, s2 + i, 1);125}126127/* Set the ratio rate to 115200, 8n1, IRQ disabled */128static void max3110_write_config(void)129{130u16 config;131132config = 0xc001;133dw_writel(pspi, dr, config);134}135136/* Translate char to a eligible word and send to max3110 */137static void max3110_write_data(char c)138{139u16 data;140141data = 0x8000 | c;142dw_writel(pspi, dr, data);143}144145void mrst_early_console_init(void)146{147u32 ctrlr0 = 0;148u32 spi0_cdiv;149u32 freq; /* Freqency info only need be searched once */150151/* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */152pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,153MRST_CLK_SPI0_REG);154spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;155freq = 100000000 / (spi0_cdiv + 1);156157if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL)158mrst_spi_paddr = MRST_REGBASE_SPI1;159160pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,161mrst_spi_paddr);162163/* Disable SPI controller */164dw_writel(pspi, ssienr, 0);165166/* Set control param, 8 bits, transmit only mode */167ctrlr0 = dw_readl(pspi, ctrl0);168169ctrlr0 &= 0xfcc0;170ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)171| (SPI_TMOD_TO << SPI_TMOD_OFFSET);172dw_writel(pspi, ctrl0, ctrlr0);173174/*175* Change the spi0 clk to comply with 115200 bps, use 100000 to176* calculate the clk dividor to make the clock a little slower177* than real baud rate.178*/179dw_writel(pspi, baudr, freq/100000);180181/* Disable all INT for early phase */182dw_writel(pspi, imr, 0x0);183184/* Set the cs to spi-uart */185dw_writel(pspi, ser, 0x2);186187/* Enable the HW, the last step for HW init */188dw_writel(pspi, ssienr, 0x1);189190/* Set the default configuration */191max3110_write_config();192193/* Register the kmsg dumper */194if (!dumper_registered) {195dw_dumper.dump = dw_kmsg_dump;196kmsg_dump_register(&dw_dumper);197dumper_registered = 1;198}199}200201/* Slave select should be called in the read/write function */202static void early_mrst_spi_putc(char c)203{204unsigned int timeout;205u32 sr;206207timeout = MRST_SPI_TIMEOUT;208/* Early putc needs to make sure the TX FIFO is not full */209while (--timeout) {210sr = dw_readl(pspi, sr);211if (!(sr & SR_TF_NOT_FULL))212cpu_relax();213else214break;215}216217if (!timeout)218pr_warning("MRST earlycon: timed out\n");219else220max3110_write_data(c);221}222223/* Early SPI only uses polling mode */224static void early_mrst_spi_write(struct console *con, const char *str, unsigned n)225{226int i;227228for (i = 0; i < n && *str; i++) {229if (*str == '\n')230early_mrst_spi_putc('\r');231early_mrst_spi_putc(*str);232str++;233}234}235236struct console early_mrst_console = {237.name = "earlymrst",238.write = early_mrst_spi_write,239.flags = CON_PRINTBUFFER,240.index = -1,241};242243/*244* Following is the early console based on Medfield HSU (High245* Speed UART) device.246*/247#define HSU_PORT2_PADDR 0xffa28180248249static void __iomem *phsu;250251void hsu_early_console_init(void)252{253u8 lcr;254255phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,256HSU_PORT2_PADDR);257258/* Disable FIFO */259writeb(0x0, phsu + UART_FCR);260261/* Set to default 115200 bps, 8n1 */262lcr = readb(phsu + UART_LCR);263writeb((0x80 | lcr), phsu + UART_LCR);264writeb(0x18, phsu + UART_DLL);265writeb(lcr, phsu + UART_LCR);266writel(0x3600, phsu + UART_MUL*4);267268writeb(0x8, phsu + UART_MCR);269writeb(0x7, phsu + UART_FCR);270writeb(0x3, phsu + UART_LCR);271272/* Clear IRQ status */273readb(phsu + UART_LSR);274readb(phsu + UART_RX);275readb(phsu + UART_IIR);276readb(phsu + UART_MSR);277278/* Enable FIFO */279writeb(0x7, phsu + UART_FCR);280}281282#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)283284static void early_hsu_putc(char ch)285{286unsigned int timeout = 10000; /* 10ms */287u8 status;288289while (--timeout) {290status = readb(phsu + UART_LSR);291if (status & BOTH_EMPTY)292break;293udelay(1);294}295296/* Only write the char when there was no timeout */297if (timeout)298writeb(ch, phsu + UART_TX);299}300301static void early_hsu_write(struct console *con, const char *str, unsigned n)302{303int i;304305for (i = 0; i < n && *str; i++) {306if (*str == '\n')307early_hsu_putc('\r');308early_hsu_putc(*str);309str++;310}311}312313struct console early_hsu_console = {314.name = "earlyhsu",315.write = early_hsu_write,316.flags = CON_PRINTBUFFER,317.index = -1,318};319320321