diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index 1f7ca8b00404..8b2eaa155d18 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -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 }; diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h b/arch/mips/include/asm/mach-loongson/boot_param.h index 11ebf4ca2b41..fa802926523f 100644 --- a/arch/mips/include/asm/mach-loongson/boot_param.h +++ b/arch/mips/include/asm/mach-loongson/boot_param.h @@ -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 { @@ -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 { @@ -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 diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h index 92bf76c21441..5459ac09679f 100644 --- a/arch/mips/include/asm/mach-loongson/loongson.h +++ b/arch/mips/include/asm/mach-loongson/loongson.h @@ -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 diff --git a/arch/mips/include/asm/mach-loongson/loongson_hwmon.h b/arch/mips/include/asm/mach-loongson/loongson_hwmon.h new file mode 100644 index 000000000000..4431fc54a36c --- /dev/null +++ b/arch/mips/include/asm/mach-loongson/loongson_hwmon.h @@ -0,0 +1,55 @@ +#ifndef __LOONGSON_HWMON_H_ +#define __LOONGSON_HWMON_H_ + +#include + +#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_*/ diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h index 228e37847a36..cb2b60249cd2 100644 --- a/arch/mips/include/asm/mach-loongson/machine.h +++ b/arch/mips/include/asm/mach-loongson/machine.h @@ -26,7 +26,7 @@ #ifdef CONFIG_LOONGSON_MACH3X -#define LOONGSON_MACHTYPE MACH_LEMOTE_A1101 +#define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC #endif /* CONFIG_LOONGSON_MACH3X */ diff --git a/arch/mips/include/asm/mach-loongson/workarounds.h b/arch/mips/include/asm/mach-loongson/workarounds.h new file mode 100644 index 000000000000..e180c1422eae --- /dev/null +++ b/arch/mips/include/asm/mach-loongson/workarounds.h @@ -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 diff --git a/arch/mips/loongson/common/early_printk.c b/arch/mips/loongson/common/early_printk.c index ced461b39069..6ca632e529dc 100644 --- a/arch/mips/loongson/common/early_printk.c +++ b/arch/mips/loongson/common/early_printk.c @@ -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) && diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index d8be5398105c..045ea3d47c87 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c @@ -21,6 +21,7 @@ #include #include #include +#include u32 cpu_clock_freq; EXPORT_SYMBOL(cpu_clock_freq); @@ -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 { \ @@ -67,6 +67,7 @@ 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; @@ -74,6 +75,8 @@ void __init prom_init_env(void) 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 *) @@ -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; @@ -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; @@ -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 = (¤t_cpu_data)->processor_id; diff --git a/arch/mips/loongson/common/machtype.c b/arch/mips/loongson/common/machtype.c index 1a4797984b8d..26629abe3f1f 100644 --- a/arch/mips/loongson/common/machtype.c +++ b/arch/mips/loongson/common/machtype.c @@ -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, }; diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c index bd2b7095b6dc..d2f4817a4b45 100644 --- a/arch/mips/loongson/common/serial.c +++ b/arch/mips/loongson/common/serial.c @@ -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), {} }, @@ -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] {}, }; @@ -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); diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c index 1e1eeea73fde..9de559d58e1f 100644 --- a/arch/mips/loongson/common/uart_base.c +++ b/arch/mips/loongson/common/uart_base.c @@ -13,22 +13,27 @@ #include -/* 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: @@ -36,17 +41,10 @@ void prom_init_loongson_uart_base(void) 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); } diff --git a/arch/mips/loongson/loongson-3/Makefile b/arch/mips/loongson/loongson-3/Makefile index b4df775b9f30..69809a3d8f34 100644 --- a/arch/mips/loongson/loongson-3/Makefile +++ b/arch/mips/loongson/loongson-3/Makefile @@ -1,7 +1,7 @@ # # Makefile for Loongson-3 family machines # -obj-y += irq.o cop2-ex.o +obj-y += irq.o cop2-ex.o platform.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/mips/loongson/loongson-3/platform.c b/arch/mips/loongson/loongson-3/platform.c new file mode 100644 index 000000000000..25a97cc0ee33 --- /dev/null +++ b/arch/mips/loongson/loongson-3/platform.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Lemote Inc. + * Author: Wu Zhangjin, wuzhangjin@gmail.com + * Xiang Yu, xiangy@lemote.com + * Chen Huacai, chenhc@lemote.com + * + * 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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +static int __init loongson3_platform_init(void) +{ + int i; + struct platform_device *pdev; + + if (loongson_sysconf.ecname[0] != '\0') + platform_device_register_simple(loongson_sysconf.ecname, -1, NULL, 0); + + for (i = 0; i < loongson_sysconf.nr_sensors; i++) { + if (loongson_sysconf.sensors[i].type > SENSOR_FAN) + continue; + + pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + pdev->name = loongson_sysconf.sensors[i].name; + pdev->id = loongson_sysconf.sensors[i].id; + pdev->dev.platform_data = &loongson_sysconf.sensors[i]; + platform_device_register(pdev); + } + + return 0; +} + +arch_initcall(loongson3_platform_init); diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c index 94ed8a57353c..e2eb688b5434 100644 --- a/arch/mips/loongson/loongson-3/smp.c +++ b/arch/mips/loongson/loongson-3/smp.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "smp.h" @@ -587,7 +588,7 @@ void loongson3_disable_clock(int cpu) if (loongson_sysconf.cputype == Loongson_3A) { LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id)); } else if (loongson_sysconf.cputype == Loongson_3B) { - if (!cpuhotplug_workaround) + if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG)) LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3)); } } @@ -600,7 +601,7 @@ void loongson3_enable_clock(int cpu) if (loongson_sysconf.cputype == Loongson_3A) { LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id); } else if (loongson_sysconf.cputype == Loongson_3B) { - if (!cpuhotplug_workaround) + if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG)) LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3); } }