Skip to content

Commit

Permalink
MIPS: Loongson: Improve LEFI firmware interface
Browse files Browse the repository at this point in the history
Machtypes of Loongson-3 machines become more and more, but there are
only small differences among different machtypes. Keeping a large table
of machtypes is very ugly and hard to extend. We found that the major
machtype differences are UARTs information (number of UARTs, UART IRQs,
UART clocks, etc.), platform devices (EC, temperature sensors, fan
controllers, etc.) and some workarounds (because of some CPU bugs or
mainboard bugs).

In this patch we improve the UEFI-like (LEFI) interface to make all
Loongson-3 machines use a same machtype "generic-loongson-machine".

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Cc: John Crispin <john@phrozen.org>
Cc: Steven J. Hill <Steven.Hill@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: Fuxin Zhang <zhangfx@lemote.com>
Cc: Zhangjin Wu <wuzhangjin@gmail.com>
Patchwork: https://patchwork.linux-mips.org/patch/8324/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
chenhuacai authored and ralfbaechle committed Nov 24, 2014
1 parent ec0f8d3 commit 3adeb25
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 42 deletions.
5 changes: 1 addition & 4 deletions arch/mips/include/asm/bootinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,7 @@ enum loongson_machine_type {
MACH_DEXXON_GDIUM2F10,
MACH_LEMOTE_NAS,
MACH_LEMOTE_LL2F,
MACH_LEMOTE_A1004,
MACH_LEMOTE_A1101,
MACH_LEMOTE_A1201,
MACH_LEMOTE_A1205,
MACH_LOONGSON_GENERIC,
MACH_LOONGSON_END
};

Expand Down
44 changes: 42 additions & 2 deletions arch/mips/include/asm/mach-loongson/boot_param.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
#define VIDEO_ROM 7
#define ADAPTER_ROM 8
#define ACPI_TABLE 9
#define MAX_MEMORY_TYPE 10
#define SMBIOS_TABLE 10
#define MAX_MEMORY_TYPE 11

#define LOONGSON3_BOOT_MEM_MAP_MAX 128
struct efi_memory_map_loongson {
Expand Down Expand Up @@ -48,10 +49,43 @@ struct efi_cpuinfo_loongson {
u32 nr_cpus;
} __packed;

#define MAX_UARTS 64
struct uart_device {
u32 iotype; /* see include/linux/serial_core.h */
u32 uartclk;
u32 int_offset;
u64 uart_base;
} __packed;

#define MAX_SENSORS 64
#define SENSOR_TEMPER 0x00000001
#define SENSOR_VOLTAGE 0x00000002
#define SENSOR_FAN 0x00000004
struct sensor_device {
char name[32]; /* a formal name */
char label[64]; /* a flexible description */
u32 type; /* SENSOR_* */
u32 id; /* instance id of a sensor-class */
u32 fan_policy; /* see loongson_hwmon.h */
u32 fan_percent;/* only for constant speed policy */
u64 base_addr; /* base address of device registers */
} __packed;

struct system_loongson {
u16 vers; /* version of system_loongson */
u32 ccnuma_smp; /* 0: no numa; 1: has numa */
u32 sing_double_channel; /* 1:single; 2:double */
u32 nr_uarts;
struct uart_device uarts[MAX_UARTS];
u32 nr_sensors;
struct sensor_device sensors[MAX_SENSORS];
char has_ec;
char ec_name[32];
u64 ec_base_addr;
char has_tcm;
char tcm_name[32];
u64 tcm_base_addr;
u64 workarounds; /* see workarounds.h */
} __packed;

struct irq_source_routing_table {
Expand Down Expand Up @@ -162,9 +196,15 @@ struct loongson_system_configuration {
u64 suspend_addr;
u64 vgabios_addr;
u32 dma_mask_bits;
char ecname[32];
u32 nr_uarts;
struct uart_device uarts[MAX_UARTS];
u32 nr_sensors;
struct sensor_device sensors[MAX_SENSORS];
u64 workarounds;
};

extern struct efi_memory_map_loongson *loongson_memmap;
extern struct loongson_system_configuration loongson_sysconf;
extern int cpuhotplug_workaround;

#endif
2 changes: 1 addition & 1 deletion arch/mips/include/asm/mach-loongson/loongson.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extern void __init prom_init_cmdline(void);
extern void __init prom_init_machtype(void);
extern void __init prom_init_env(void);
#ifdef CONFIG_LOONGSON_UART_BASE
extern unsigned long _loongson_uart_base, loongson_uart_base;
extern unsigned long _loongson_uart_base[], loongson_uart_base[];
extern void prom_init_loongson_uart_base(void);
#endif

Expand Down
55 changes: 55 additions & 0 deletions arch/mips/include/asm/mach-loongson/loongson_hwmon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef __LOONGSON_HWMON_H_
#define __LOONGSON_HWMON_H_

#include <linux/types.h>

#define MIN_TEMP 0
#define MAX_TEMP 255
#define NOT_VALID_TEMP 999

typedef int (*get_temp_fun)(int);
extern int loongson3_cpu_temp(int);

/* 0:Max speed, 1:Manual, 2:Auto */
enum fan_control_mode {
FAN_FULL_MODE = 0,
FAN_MANUAL_MODE = 1,
FAN_AUTO_MODE = 2,
FAN_MODE_END
};

struct temp_range {
u8 low;
u8 high;
u8 level;
};

#define CONSTANT_SPEED_POLICY 0 /* at constent speed */
#define STEP_SPEED_POLICY 1 /* use up/down arrays to describe policy */
#define KERNEL_HELPER_POLICY 2 /* kernel as a helper to fan control */

#define MAX_STEP_NUM 16
#define MAX_FAN_LEVEL 255

/* loongson_fan_policy works when fan work at FAN_AUTO_MODE */
struct loongson_fan_policy {
u8 type;

/* percent only used when type is CONSTANT_SPEED_POLICY */
u8 percent;

/* period between two check. (Unit: S) */
u8 adjust_period;

/* fan adjust usually depend on a temprature input */
get_temp_fun depend_temp;

/* up_step/down_step used when type is STEP_SPEED_POLICY */
u8 up_step_num;
u8 down_step_num;
struct temp_range up_step[MAX_STEP_NUM];
struct temp_range down_step[MAX_STEP_NUM];
struct delayed_work work;
};

#endif /* __LOONGSON_HWMON_H_*/
2 changes: 1 addition & 1 deletion arch/mips/include/asm/mach-loongson/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

#ifdef CONFIG_LOONGSON_MACH3X

#define LOONGSON_MACHTYPE MACH_LEMOTE_A1101
#define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC

#endif /* CONFIG_LOONGSON_MACH3X */

Expand Down
7 changes: 7 additions & 0 deletions arch/mips/include/asm/mach-loongson/workarounds.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef __ASM_MACH_LOONGSON_WORKAROUNDS_H_
#define __ASM_MACH_LOONGSON_WORKAROUNDS_H_

#define WORKAROUND_CPUFREQ 0x00000001
#define WORKAROUND_CPUHOTPLUG 0x00000002

#endif
2 changes: 1 addition & 1 deletion arch/mips/loongson/common/early_printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ void prom_putchar(char c)
int timeout;
unsigned char *uart_base;

uart_base = (unsigned char *)_loongson_uart_base;
uart_base = (unsigned char *)_loongson_uart_base[0];
timeout = 1024;

while (((serial_in(uart_base, UART_LSR) & UART_LSR_THRE) == 0) &&
Expand Down
26 changes: 24 additions & 2 deletions arch/mips/loongson/common/env.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <asm/bootinfo.h>
#include <loongson.h>
#include <boot_param.h>
#include <workarounds.h>

u32 cpu_clock_freq;
EXPORT_SYMBOL(cpu_clock_freq);
Expand All @@ -31,7 +32,6 @@ u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
u64 loongson_freqctrl[MAX_PACKAGES];

unsigned long long smp_group[4];
int cpuhotplug_workaround = 0;

#define parse_even_earlier(res, option, p) \
do { \
Expand Down Expand Up @@ -67,13 +67,16 @@ void __init prom_init_env(void)
#else
struct boot_params *boot_p;
struct loongson_params *loongson_p;
struct system_loongson *esys;
struct efi_cpuinfo_loongson *ecpu;
struct irq_source_routing_table *eirq_source;

/* firmware arguments are initialized in head.S */
boot_p = (struct boot_params *)fw_arg2;
loongson_p = &(boot_p->efi.smbios.lp);

esys = (struct system_loongson *)
((u64)loongson_p + loongson_p->system_offset);
ecpu = (struct efi_cpuinfo_loongson *)
((u64)loongson_p + loongson_p->cpu_offset);
eirq_source = (struct irq_source_routing_table *)
Expand All @@ -95,6 +98,7 @@ void __init prom_init_env(void)
loongson_chipcfg[2] = 0x900020001fe00180;
loongson_chipcfg[3] = 0x900030001fe00180;
loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
loongson_sysconf.workarounds = WORKAROUND_CPUFREQ;
} else if (ecpu->cputype == Loongson_3B) {
loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */
loongson_sysconf.cores_per_package = 8;
Expand All @@ -111,7 +115,7 @@ void __init prom_init_env(void)
loongson_freqctrl[2] = 0x900040001fe001d0;
loongson_freqctrl[3] = 0x900060001fe001d0;
loongson_sysconf.ht_control_base = 0x90001EFDFB000000;
cpuhotplug_workaround = 1;
loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG;
} else {
loongson_sysconf.cores_per_node = 1;
loongson_sysconf.cores_per_package = 1;
Expand Down Expand Up @@ -143,6 +147,24 @@ void __init prom_init_env(void)
pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
loongson_sysconf.vgabios_addr);

memset(loongson_sysconf.ecname, 0, 32);
if (esys->has_ec)
memcpy(loongson_sysconf.ecname, esys->ec_name, 32);
loongson_sysconf.workarounds |= esys->workarounds;

loongson_sysconf.nr_uarts = esys->nr_uarts;
if (esys->nr_uarts < 1 || esys->nr_uarts > MAX_UARTS)
loongson_sysconf.nr_uarts = 1;
memcpy(loongson_sysconf.uarts, esys->uarts,
sizeof(struct uart_device) * loongson_sysconf.nr_uarts);

loongson_sysconf.nr_sensors = esys->nr_sensors;
if (loongson_sysconf.nr_sensors > MAX_SENSORS)
loongson_sysconf.nr_sensors = 0;
if (loongson_sysconf.nr_sensors)
memcpy(loongson_sysconf.sensors, esys->sensors,
sizeof(struct sensor_device) * loongson_sysconf.nr_sensors);
#endif
if (cpu_clock_freq == 0) {
processor_id = (&current_cpu_data)->processor_id;
Expand Down
5 changes: 1 addition & 4 deletions arch/mips/loongson/common/machtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ static const char *system_types[] = {
[MACH_DEXXON_GDIUM2F10] "dexxon-gdium-2f",
[MACH_LEMOTE_NAS] "lemote-nas-2f",
[MACH_LEMOTE_LL2F] "lemote-lynloong-2f",
[MACH_LEMOTE_A1004] "lemote-3a-notebook-a1004",
[MACH_LEMOTE_A1101] "lemote-3a-itx-a1101",
[MACH_LEMOTE_A1201] "lemote-2gq-notebook-a1201",
[MACH_LEMOTE_A1205] "lemote-2gq-aio-a1205",
[MACH_LOONGSON_GENERIC] "generic-loongson-machine",
[MACH_LOONGSON_END] NULL,
};

Expand Down
48 changes: 40 additions & 8 deletions arch/mips/loongson/common/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
.regshift = 0, \
}

static struct plat_serial8250_port uart8250_data[][2] = {
static struct plat_serial8250_port uart8250_data[][MAX_UARTS + 1] = {
[MACH_LOONGSON_UNKNOWN] {},
[MACH_LEMOTE_FL2E] {PORT(4, 1843200), {} },
[MACH_LEMOTE_FL2F] {PORT(3, 1843200), {} },
Expand All @@ -47,10 +47,7 @@ static struct plat_serial8250_port uart8250_data[][2] = {
[MACH_DEXXON_GDIUM2F10] {PORT_M(3, 3686400), {} },
[MACH_LEMOTE_NAS] {PORT_M(3, 3686400), {} },
[MACH_LEMOTE_LL2F] {PORT(3, 1843200), {} },
[MACH_LEMOTE_A1004] {PORT_M(2, 33177600), {} },
[MACH_LEMOTE_A1101] {PORT_M(2, 25000000), {} },
[MACH_LEMOTE_A1201] {PORT_M(2, 25000000), {} },
[MACH_LEMOTE_A1205] {PORT_M(2, 25000000), {} },
[MACH_LOONGSON_GENERIC] {PORT_M(2, 25000000), {} },
[MACH_LOONGSON_END] {},
};

Expand All @@ -61,17 +58,52 @@ static struct platform_device uart8250_device = {

static int __init serial_init(void)
{
int i;
unsigned char iotype;

iotype = uart8250_data[mips_machtype][0].iotype;

if (UPIO_MEM == iotype)
if (UPIO_MEM == iotype) {
uart8250_data[mips_machtype][0].mapbase =
loongson_uart_base[0];
uart8250_data[mips_machtype][0].membase =
(void __iomem *)_loongson_uart_base;
(void __iomem *)_loongson_uart_base[0];
}
else if (UPIO_PORT == iotype)
uart8250_data[mips_machtype][0].iobase =
loongson_uart_base - LOONGSON_PCIIO_BASE;
loongson_uart_base[0] - LOONGSON_PCIIO_BASE;

if (loongson_sysconf.uarts[0].uartclk)
uart8250_data[mips_machtype][0].uartclk =
loongson_sysconf.uarts[0].uartclk;

for (i = 1; i < loongson_sysconf.nr_uarts; i++) {
iotype = loongson_sysconf.uarts[i].iotype;
uart8250_data[mips_machtype][i].iotype = iotype;
loongson_uart_base[i] = loongson_sysconf.uarts[i].uart_base;

if (UPIO_MEM == iotype) {
uart8250_data[mips_machtype][i].irq =
MIPS_CPU_IRQ_BASE + loongson_sysconf.uarts[i].int_offset;
uart8250_data[mips_machtype][i].mapbase =
loongson_uart_base[i];
uart8250_data[mips_machtype][i].membase =
ioremap_nocache(loongson_uart_base[i], 8);
} else if (UPIO_PORT == iotype) {
uart8250_data[mips_machtype][i].irq =
loongson_sysconf.uarts[i].int_offset;
uart8250_data[mips_machtype][i].iobase =
loongson_uart_base[i] - LOONGSON_PCIIO_BASE;
}

uart8250_data[mips_machtype][i].uartclk =
loongson_sysconf.uarts[i].uartclk;
uart8250_data[mips_machtype][i].flags =
UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
}

memset(&uart8250_data[mips_machtype][loongson_sysconf.nr_uarts],
0, sizeof(struct plat_serial8250_port));
uart8250_device.dev.platform_data = uart8250_data[mips_machtype];

return platform_device_register(&uart8250_device);
Expand Down
30 changes: 14 additions & 16 deletions arch/mips/loongson/common/uart_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,38 @@

#include <loongson.h>

/* ioremapped */
unsigned long _loongson_uart_base;
EXPORT_SYMBOL(_loongson_uart_base);
/* raw */
unsigned long loongson_uart_base;
unsigned long loongson_uart_base[MAX_UARTS] = {};
/* ioremapped */
unsigned long _loongson_uart_base[MAX_UARTS] = {};

EXPORT_SYMBOL(loongson_uart_base);
EXPORT_SYMBOL(_loongson_uart_base);

void prom_init_loongson_uart_base(void)
{
switch (mips_machtype) {
case MACH_LOONGSON_GENERIC:
/* The CPU provided serial port (CPU) */
loongson_uart_base[0] = LOONGSON_REG_BASE + 0x1e0;
break;
case MACH_LEMOTE_FL2E:
loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
loongson_uart_base[0] = LOONGSON_PCIIO_BASE + 0x3f8;
break;
case MACH_LEMOTE_FL2F:
case MACH_LEMOTE_LL2F:
loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
loongson_uart_base[0] = LOONGSON_PCIIO_BASE + 0x2f8;
break;
case MACH_LEMOTE_ML2F7:
case MACH_LEMOTE_YL2F89:
case MACH_DEXXON_GDIUM2F10:
case MACH_LEMOTE_NAS:
default:
/* The CPU provided serial port (LPC) */
loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
break;
case MACH_LEMOTE_A1004:
case MACH_LEMOTE_A1101:
case MACH_LEMOTE_A1201:
case MACH_LEMOTE_A1205:
/* The CPU provided serial port (CPU) */
loongson_uart_base = LOONGSON_REG_BASE + 0x1e0;
loongson_uart_base[0] = LOONGSON_LIO1_BASE + 0x3f8;
break;
}

_loongson_uart_base =
(unsigned long)ioremap_nocache(loongson_uart_base, 8);
_loongson_uart_base[0] =
(unsigned long)ioremap_nocache(loongson_uart_base[0], 8);
}
Loading

0 comments on commit 3adeb25

Please sign in to comment.