Initial commit; kernel source import

This commit is contained in:
Nathan
2025-04-06 23:50:55 -05:00
commit 25c6d769f4
45093 changed files with 18199410 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
obj-$(CONFIG_X86_INTEL_MID) += mrst.o
obj-$(CONFIG_X86_INTEL_MID) += vrtc.o
obj-$(CONFIG_EARLY_PRINTK_INTEL_MID) += early_printk_mrst.o

View File

@@ -0,0 +1,324 @@
/*
* early_printk_mrst.c - early consoles for Intel MID platforms
*
* Copyright (c) 2008-2010, 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.
*/
/*
* This file implements two early consoles named mrst and hsu.
* mrst is based on Maxim3110 spi-uart device, it exists in both
* Moorestown and Medfield platforms, while hsu is based on a High
* Speed UART device which only exists in the Medfield platform
*/
#include <linux/serial_reg.h>
#include <linux/serial_mfd.h>
#include <linux/kmsg_dump.h>
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/delay.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
#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;
/* Currently operates as 32 bits, though only the low 16 bits matter */
u32 dr;
} __packed;
#define dw_readl(dw, name) __raw_readl(&(dw)->name)
#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name)
/* 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 accessible address, start with 0 */
static struct dw_spi_reg *pspi;
static struct kmsg_dumper dw_dumper;
static int dumper_registered;
static void dw_kmsg_dump(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason)
{
static char line[1024];
size_t len;
/* When run to this, we'd better re-init the HW */
mrst_early_console_init();
while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len))
early_mrst_console.write(&early_mrst_console, line, len);
}
/* Set the ratio rate to 115200, 8n1, IRQ disabled */
static void max3110_write_config(void)
{
u16 config;
config = 0xc001;
dw_writel(pspi, dr, config);
}
/* Translate char to a eligible word and send to max3110 */
static void max3110_write_data(char c)
{
u16 data;
data = 0x8000 | c;
dw_writel(pspi, dr, data);
}
void mrst_early_console_init(void)
{
u32 ctrlr0 = 0;
u32 spi0_cdiv;
u32 freq; /* Freqency info only need be searched once */
/* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
MRST_CLK_SPI0_REG);
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;
pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
mrst_spi_paddr);
/* 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 to
* calculate the clk dividor to make the clock a little slower
* than real baud rate.
*/
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);
/* Set the default configuration */
max3110_write_config();
/* Register the kmsg dumper */
if (!dumper_registered) {
dw_dumper.dump = dw_kmsg_dump;
kmsg_dump_register(&dw_dumper);
dumper_registered = 1;
}
}
/* 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 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("MRST earlycon: timed out\n");
else
max3110_write_data(c);
}
/* Early SPI only uses polling mode */
static void early_mrst_spi_write(struct console *con, const char *str, unsigned n)
{
int i;
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,
};
/*
* Following is the early console based on Medfield HSU (High
* Speed UART) device.
*/
#define HSU_PORT_BASE 0xffa28080
static void __iomem *phsu;
void hsu_early_console_init(const char *s)
{
unsigned long paddr, port = 0;
u8 lcr;
/*
* Select the early HSU console port if specified by user in the
* kernel command line.
*/
if (*s && !kstrtoul(s, 10, &port))
port = clamp_val(port, 0, 2);
paddr = HSU_PORT_BASE + port * 0x80;
phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
/* Disable FIFO */
writeb(0x0, phsu + UART_FCR);
/* Set to default 115200 bps, 8n1 */
lcr = readb(phsu + UART_LCR);
writeb((0x80 | lcr), phsu + UART_LCR);
writeb(0x18, phsu + UART_DLL);
writeb(lcr, phsu + UART_LCR);
writel(0x3600, phsu + UART_MUL*4);
writeb(0x8, phsu + UART_MCR);
writeb(0x7, phsu + UART_FCR);
writeb(0x3, phsu + UART_LCR);
/* Clear IRQ status */
readb(phsu + UART_LSR);
readb(phsu + UART_RX);
readb(phsu + UART_IIR);
readb(phsu + UART_MSR);
/* Enable FIFO */
writeb(0x7, phsu + UART_FCR);
}
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
static void early_hsu_putc(char ch)
{
unsigned int timeout = 10000; /* 10ms */
u8 status;
while (--timeout) {
status = readb(phsu + UART_LSR);
if (status & BOTH_EMPTY)
break;
udelay(1);
}
/* Only write the char when there was no timeout */
if (timeout)
writeb(ch, phsu + UART_TX);
}
static void early_hsu_write(struct console *con, const char *str, unsigned n)
{
int i;
for (i = 0; i < n && *str; i++) {
if (*str == '\n')
early_hsu_putc('\r');
early_hsu_putc(*str);
str++;
}
}
struct console early_hsu_console = {
.name = "earlyhsu",
.write = early_hsu_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,177 @@
/*
* vrtc.c: Driver for virtual RTC device on Intel MID platform
*
* (C) Copyright 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.
*
* Note:
* VRTC is emulated by system controller firmware, the real HW
* RTC is located in the PMIC device. SCU FW shadows PMIC RTC
* in a memory mapped IO space that is visible to the host IA
* processor.
*
* This driver is based on RTC CMOS driver.
*/
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/sfi.h>
#include <linux/platform_device.h>
#include <asm/mrst.h>
#include <asm/mrst-vrtc.h>
#include <asm/time.h>
#include <asm/fixmap.h>
static unsigned char __iomem *vrtc_virt_base;
unsigned char vrtc_cmos_read(unsigned char reg)
{
unsigned char retval;
/* vRTC's registers range from 0x0 to 0xD */
if (reg > 0xd || !vrtc_virt_base)
return 0xff;
lock_cmos_prefix(reg);
retval = __raw_readb(vrtc_virt_base + (reg << 2));
lock_cmos_suffix(reg);
return retval;
}
EXPORT_SYMBOL_GPL(vrtc_cmos_read);
void vrtc_cmos_write(unsigned char val, unsigned char reg)
{
if (reg > 0xd || !vrtc_virt_base)
return;
lock_cmos_prefix(reg);
__raw_writeb(val, vrtc_virt_base + (reg << 2));
lock_cmos_suffix(reg);
}
EXPORT_SYMBOL_GPL(vrtc_cmos_write);
unsigned long vrtc_get_time(void)
{
u8 sec, min, hour, mday, mon;
unsigned long flags;
u32 year;
spin_lock_irqsave(&rtc_lock, flags);
while ((vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP))
cpu_relax();
sec = vrtc_cmos_read(RTC_SECONDS);
min = vrtc_cmos_read(RTC_MINUTES);
hour = vrtc_cmos_read(RTC_HOURS);
mday = vrtc_cmos_read(RTC_DAY_OF_MONTH);
mon = vrtc_cmos_read(RTC_MONTH);
year = vrtc_cmos_read(RTC_YEAR);
spin_unlock_irqrestore(&rtc_lock, flags);
/* vRTC YEAR reg contains the offset to 1972 */
year += 1972;
printk(KERN_INFO "vRTC: sec: %d min: %d hour: %d day: %d "
"mon: %d year: %d\n", sec, min, hour, mday, mon, year);
return mktime(year, mon, mday, hour, min, sec);
}
int vrtc_set_mmss(unsigned long nowtime)
{
unsigned long flags;
struct rtc_time tm;
int year;
int retval = 0;
rtc_time_to_tm(nowtime, &tm);
if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) {
/*
* tm.year is the number of years since 1900, and the
* vrtc need the years since 1972.
*/
year = tm.tm_year - 72;
spin_lock_irqsave(&rtc_lock, flags);
vrtc_cmos_write(year, RTC_YEAR);
vrtc_cmos_write(tm.tm_mon, RTC_MONTH);
vrtc_cmos_write(tm.tm_mday, RTC_DAY_OF_MONTH);
vrtc_cmos_write(tm.tm_hour, RTC_HOURS);
vrtc_cmos_write(tm.tm_min, RTC_MINUTES);
vrtc_cmos_write(tm.tm_sec, RTC_SECONDS);
spin_unlock_irqrestore(&rtc_lock, flags);
} else {
printk(KERN_ERR
"%s: Invalid vRTC value: write of %lx to vRTC failed\n",
__FUNCTION__, nowtime);
retval = -EINVAL;
}
return retval;
}
void __init mrst_rtc_init(void)
{
unsigned long vrtc_paddr;
sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
vrtc_paddr = sfi_mrtc_array[0].phys_addr;
if (!sfi_mrtc_num || !vrtc_paddr)
return;
vrtc_virt_base = (void __iomem *)set_fixmap_offset_nocache(FIX_LNW_VRTC,
vrtc_paddr);
x86_platform.get_wallclock = vrtc_get_time;
x86_platform.set_wallclock = vrtc_set_mmss;
}
/*
* The Moorestown platform has a memory mapped virtual RTC device that emulates
* the programming interface of the RTC.
*/
static struct resource vrtc_resources[] = {
[0] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.flags = IORESOURCE_IRQ,
}
};
static struct platform_device vrtc_device = {
.name = "rtc_mrst",
.id = -1,
.resource = vrtc_resources,
.num_resources = ARRAY_SIZE(vrtc_resources),
};
/* Register the RTC device if appropriate */
static int __init mrst_device_create(void)
{
/* No Moorestown, no device */
if (!mrst_identify_cpu())
return -ENODEV;
/* No timer, no device */
if (!sfi_mrtc_num)
return -ENODEV;
/* iomem resource */
vrtc_resources[0].start = sfi_mrtc_array[0].phys_addr;
vrtc_resources[0].end = sfi_mrtc_array[0].phys_addr +
MRST_VRTC_MAP_SZ;
/* irq resource */
vrtc_resources[1].start = sfi_mrtc_array[0].irq;
vrtc_resources[1].end = sfi_mrtc_array[0].irq;
return platform_device_register(&vrtc_device);
}
module_init(mrst_device_create);