Re: [PATCH v2 1/4] x86, earlyprintk: add earlyprintk for Intel Moorestown platform

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



* Feng Tang <feng.tang@xxxxxxxxx> wrote:

> 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@xxxxxxxxx>
> Cc: x86 maintainers <x86@xxxxxxxxxx>
> Signed-off-by: Alan Cox <alan@xxxxxxxxxxxxxxx>
> ---
>  arch/x86/Kconfig.debug             |    4 +
>  arch/x86/include/asm/mrst.h        |    4 +
>  arch/x86/kernel/Makefile           |    1 +
>  arch/x86/kernel/early_printk.c     |    5 +
>  arch/x86/kernel/mrst_earlyprintk.c |  241 ++++++++++++++++++++++++++++++++++++
>  5 files changed, 255 insertions(+), 0 deletions(-)
>  create mode 100644 arch/x86/kernel/mrst_earlyprintk.c
> 
> diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
> index 7508508..9c10cd6 100644
> --- a/arch/x86/Kconfig.debug
> +++ b/arch/x86/Kconfig.debug
> @@ -43,6 +43,10 @@ config EARLY_PRINTK
>  	  with klogd/syslogd or the X server. You should normally N here,
>  	  unless you want to debug such a crash.
>  
> +config X86_MRST_EARLY_PRINTK
> +	bool "Early printk for MRST platform support"
> +	depends on EARLY_PRINTK && X86_MRST
> +
>  config EARLY_PRINTK_DBGP
>  	bool "Early printk via EHCI debug port"
>  	depends on EARLY_PRINTK && PCI
> diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h
> index 1635074..4b891b3 100644
> --- a/arch/x86/include/asm/mrst.h
> +++ b/arch/x86/include/asm/mrst.h
> @@ -10,6 +10,9 @@
>   */
>  #ifndef _ASM_X86_MRST_H
>  #define _ASM_X86_MRST_H
> +
> +#include <linux/sfi.h>
> +
>  extern int pci_mrst_init(void);
>  int __init sfi_parse_mrtc(struct sfi_table_header *table);
>  
> @@ -42,4 +45,5 @@ extern enum mrst_timer_options mrst_timer_options;
>  #define SFI_MTMR_MAX_NUM 8
>  #define SFI_MRTC_MAX	8
>  
> +extern struct console early_mrst_console;
>  #endif /* _ASM_X86_MRST_H */
> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> index 0925676..e6dbe95 100644
> --- a/arch/x86/kernel/Makefile
> +++ b/arch/x86/kernel/Makefile
> @@ -83,6 +83,7 @@ obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault_32.o
>  obj-$(CONFIG_KGDB)		+= kgdb.o
>  obj-$(CONFIG_VM86)		+= vm86_32.o
>  obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
> +obj-$(CONFIG_X86_MRST_EARLY_PRINTK)	+= mrst_earlyprintk.o
>  
>  obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
>  obj-$(CONFIG_APB_TIMER)		+= apb_timer.o
> diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
> index fa99bae..435a070 100644
> --- a/arch/x86/kernel/early_printk.c
> +++ b/arch/x86/kernel/early_printk.c
> @@ -14,6 +14,7 @@
>  #include <xen/hvc-console.h>
>  #include <asm/pci-direct.h>
>  #include <asm/fixmap.h>
> +#include <asm/mrst.h>
>  #include <asm/pgtable.h>
>  #include <linux/usb/ehci_def.h>
>  
> @@ -239,6 +240,10 @@ static int __init setup_early_printk(char *buf)
>  		if (!strncmp(buf, "xen", 3))
>  			early_console_register(&xenboot_console, keep);
>  #endif
> +#ifdef CONFIG_X86_MRST_EARLY_PRINTK
> +		if (!strncmp(buf, "mrst", 4))
> +			early_console_register(&early_mrst_console, keep);
> +#endif
>  		buf++;
>  	}
>  	return 0;
> diff --git a/arch/x86/kernel/mrst_earlyprintk.c b/arch/x86/kernel/mrst_earlyprintk.c
> new file mode 100644
> index 0000000..7c29025
> --- /dev/null
> +++ b/arch/x86/kernel/mrst_earlyprintk.c

Small nit: please name the new file hierarchically and according to 
existing namespace patterns: i.e. arch/x86/kernel/early_printk_mrst.c.

> @@ -0,0 +1,241 @@
> +/*
> + * mrst_earlyprintk.c - spi-uart early printk for Intel Moorestown platform
> + *
> + * Copyright (c) 2009 Intel Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; version 2
> + * of the License.
> + */
> +
> +#include <linux/kmsg_dump.h>
> +#include <linux/console.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +
> +#include <asm/fixmap.h>
> +#include <asm/pgtable.h>
> +#include <asm/mrst.h>
> +
> +#define MRST_SPI_TIMEOUT	0x200000
> +#define MRST_REGBASE_SPI0	0xff128000
> +#define MRST_REGBASE_SPI1	0xff128400
> +#define MRST_CLK_SPI0_REG	0xff11d86c
> +
> +/* Bit fields in CTRLR0 */
> +#define SPI_DFS_OFFSET			0
> +
> +#define SPI_FRF_OFFSET			4
> +#define SPI_FRF_SPI			0x0
> +#define SPI_FRF_SSP			0x1
> +#define SPI_FRF_MICROWIRE		0x2
> +#define SPI_FRF_RESV			0x3

Small nit: please try to use uniform vertical spacing for like-minded 
symbols - i.e. move the four MRST_* one tab to the right - so that if 
someone looks at the file for the first time sees a tidy picture of 
constants, without extra visual noise.

> +
> +#define SPI_MODE_OFFSET			6
> +#define SPI_SCPH_OFFSET			6
> +#define SPI_SCOL_OFFSET			7
> +#define SPI_TMOD_OFFSET			8
> +#define	SPI_TMOD_TR			0x0		/* xmit & recv */
> +#define SPI_TMOD_TO			0x1		/* xmit only */
> +#define SPI_TMOD_RO			0x2		/* recv only */
> +#define SPI_TMOD_EPROMREAD		0x3		/* eeprom read mode */
> +
> +#define SPI_SLVOE_OFFSET		10
> +#define SPI_SRL_OFFSET			11
> +#define SPI_CFS_OFFSET			12
> +
> +/* Bit fields in SR, 7 bits */
> +#define SR_MASK				0x7f		/* cover 7 bits */
> +#define SR_BUSY				(1 << 0)
> +#define SR_TF_NOT_FULL			(1 << 1)
> +#define SR_TF_EMPT			(1 << 2)
> +#define SR_RF_NOT_EMPT			(1 << 3)
> +#define SR_RF_FULL			(1 << 4)
> +#define SR_TX_ERR			(1 << 5)
> +#define SR_DCOL				(1 << 6)
> +
> +struct dw_spi_reg {
> +	u32	ctrl0;
> +	u32	ctrl1;
> +	u32	ssienr;
> +	u32	mwcr;
> +	u32	ser;
> +	u32	baudr;
> +	u32	txfltr;
> +	u32	rxfltr;
> +	u32	txflr;
> +	u32	rxflr;
> +	u32	sr;
> +	u32	imr;
> +	u32	isr;
> +	u32	risr;
> +	u32	txoicr;
> +	u32	rxoicr;
> +	u32	rxuicr;
> +	u32	msticr;
> +	u32	icr;
> +	u32	dmacr;
> +	u32	dmatdlr;
> +	u32	dmardlr;
> +	u32	idr;
> +	u32	version;
> +	u32	dr;		/* Currently oper as 32 bits,
> +				   though only low 16 bits matters */

please use the customary (multi-line) comment style:

  /*
   * Comment .....
   * ...... goes here.
   */

specified in Documentation/CodingStyle. (or use an overlong comment line 
and ignore checkpatch)

Also, the sentence should probably read:

  /* Currently operates as 32 bits, though only the low 16 bits matter */

> +} __packed;
> +
> +#define dw_readl(dw, name) \
> +	__raw_readl(&dw->name)
> +#define dw_writel(dw, name, val) \
> +	__raw_writel((val), &dw->name)

'dw' needs to be macro-side-effect protected as well, not just 'val'.

Also, these definitions do not need to be multi-line. This looks much 
tidier:

#define dw_readl(dw, name)		__raw_readl(&(dw)->name)
#define dw_writel(dw, name, val)	__raw_writel((val), &(dw)->name)

( for extra bonus see that the vertical spacing lines up with the 
  constant section higher in the file. )

> +
> +/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1*/
> +static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
> +
> +static u32 *pclk_spi0;
> +/* Always contains an accessable address, start with 0 */
> +static struct dw_spi_reg *pspi;
> +static int mrst_spi_init_done;
> +
> +static struct kmsg_dumper dw_dumper;
> +static int dumper_registered;
> +
> +static void dw_kmsg_dump(struct kmsg_dumper *dumper,
> +			enum kmsg_dump_reason reason,
> +			const char *s1, unsigned long l1,
> +			const char *s2, unsigned long l2)
> +{
> +	int i;
> +
> +	/* When run to this, we'd better re-init the HW */
> +	mrst_spi_init_done = 0;

The mrst_spi_init_done flaggery and its interaction with implicit 
initialization in the write() method is really ugly and non-obvious.

Please add an explicit 'first initialization' call in the MRST bootup 
code (or somewhere in the x86 bootup code), and then explicitly call 
early_mrst_spi_init() here in the dumper.

This allows the elimination of mrst_spi_init_done.

> +
> +	for (i = 0; i < l1; i++)
> +		early_mrst_console.write(&early_mrst_console, s1 + i, 1);
> +	for (i = 0; i < l2; i++)
> +		early_mrst_console.write(&early_mrst_console, s2 + i, 1);
> +}
> +
> +static void early_mrst_spi_init(void)
> +{
> +	u32 ctrlr0 = 0;
> +	u32 spi0_cdiv;
> +	static u32 freq; /* freq info only need be searched once */

Very small nit: please use consistent capitalization in comments. This 
comment should be capitalized - as most other comments are in the file.

> +
> +	if (!freq) {
> +		set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, MRST_CLK_SPI0_REG);
> +		pclk_spi0 = (void *)(__fix_to_virt(FIX_EARLYCON_MEM_BASE) +
> +				(MRST_CLK_SPI0_REG & (PAGE_SIZE - 1)));
> +
> +		spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
> +		freq = 100000000 / (spi0_cdiv + 1);
> +	}
> +
> +	if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL)
> +		mrst_spi_paddr = MRST_REGBASE_SPI1;
> +
> +	set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, mrst_spi_paddr);
> +	pspi = (void *)(__fix_to_virt(FIX_EARLYCON_MEM_BASE) +
> +			(mrst_spi_paddr & (PAGE_SIZE - 1)));
> +
> +	/* Disable SPI controller */
> +	dw_writel(pspi, ssienr, 0);
> +
> +	/* Set control param, 8 bits, transmit only mode */
> +	ctrlr0 = dw_readl(pspi, ctrl0);
> +
> +	ctrlr0 &= 0xfcc0;
> +	ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
> +		      | (SPI_TMOD_TO << SPI_TMOD_OFFSET);
> +	dw_writel(pspi, ctrl0, ctrlr0);
> +
> +	/* Change the spi0 clk to comply with 115200 bps,
> +	 * use 100000 as dividor to make the clock a little
> +	 * slower than baud rate */

Comment style.

> +	dw_writel(pspi, baudr, freq/100000);
> +
> +	/* Disable all INT for early phase */
> +	dw_writel(pspi, imr, 0x0);
> +
> +	/* Set the cs to spi-uart */
> +	dw_writel(pspi, ser, 0x2);
> +
> +	/* Enable the HW, the last step for HW init */
> +	dw_writel(pspi, ssienr, 0x1);
> +
> +	mrst_spi_init_done = 1;
> +
> +	/* Register the kmsg dumper */
> +	if (!dumper_registered) {
> +		dw_dumper.dump = dw_kmsg_dump;
> +		kmsg_dump_register(&dw_dumper);
> +		dumper_registered = 1;
> +	}
> +}
> +
> +/* Set the ratio rate, INT */
> +static void max3110_write_config(void)
> +{
> +	u16 config;
> +
> +	/* 115200, TM not set, no parity, 8bit word */
> +	config = 0xc001;
> +	dw_writel(pspi, dr, config);
> +}
> +
> +/* Translate char to a eligibal word and send to max3110 */

eligible?

> +static void max3110_write_data(char c)
> +{
> +	u16 data;
> +
> +	data = 0x8000 | c;
> +	dw_writel(pspi, dr, data);
> +}
> +
> +/* Slave select should be called in the read/write function */
> +static void early_mrst_spi_putc(char c)
> +{
> +	unsigned int timeout;
> +	u32 sr;
> +
> +	timeout = MRST_SPI_TIMEOUT;
> +	/* Early putc need make sure the TX FIFO is not full*/

Comments end with ' */', not with '*/', plus the sentence should 
probably read:

  /* Early putc needs to make sure the TX FIFO is not full */

> +	while (--timeout) {
> +		sr = dw_readl(pspi, sr);
> +		if (!(sr & SR_TF_NOT_FULL))
> +			cpu_relax();
> +		else
> +			break;
> +	}
> +
> +	if (!timeout)
> +		pr_warning("SPI: waiting timeout\n");

"SPI: timed out\n"

or:

"SPI: waiting timed out\n"

> +	else
> +		max3110_write_data(c);
> +}
> +
> +/* Early SPI only use polling mode */

s/use/uses

> +static void early_mrst_spi_write(struct console *con, const char *str, unsigned n)
> +{
> +	int i;
> +
> +	if (unlikely(!mrst_spi_init_done)) {
> +		early_mrst_spi_init();
> +		max3110_write_config();
> +	}

Shouldnt the call to max3110_write_config() be moved into 
early_mrst_spi_init()?

> +
> +	for (i = 0; i < n && *str; i++) {
> +		if (*str == '\n')
> +			early_mrst_spi_putc('\r');
> +		early_mrst_spi_putc(*str);
> +		str++;
> +	}
> +}
> +
> +struct console early_mrst_console = {
> +	.name =		"earlymrst",
> +	.write =	early_mrst_spi_write,
> +	.flags =	CON_PRINTBUFFER,
> +	.index =	-1,
> +};

Thanks,

	Ingo
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux