aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-17 15:50:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-17 15:50:54 -0400
commitbfaf245022b4b8661af2e35f467cf0e91943c24c (patch)
treeb5a6ee49a047557a791eb897c8c9545a155e36b7 /drivers/platform
parent96d928ed75c4ba4253e82910a697ec7b06ace8b4 (diff)
parent3e20a26b02bd4f24945c87407df51948dd488620 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle: "This is the main pull request for MIPS for Linux 4.1. Most noteworthy: - Add more Octeon-optimized crypto functions - Octeon crypto preemption and locking fixes - Little endian support for Octeon - Use correct CSR to soft reset Octeons - Support LEDs on the Octeon-based DSR-1000N - Fix PCI interrupt mapping for the Octeon-based DSR-1000N - Mark prom_free_prom_memory() as __init for a number of systems - Support for Imagination's Pistachio SOC. This includes arch and CLK bits. I'd like to merge pinctrl bits later - Improve parallelism of csum_partial for certain pipelines - Organize DTB files in subdirs like other architectures - Implement read_sched_clock for all MIPS platforms other than Octeon - Massive series of 38 fixes and cleanups for the FPU emulator / kernel - Further FPU remulator work to support new features. This sits on a separate branch which also has been pulled into the 4.1 KVM branch - Clean up and fixes for the SEAD3 eval board; remove unused file - Various updates for Netlogic platforms - A number of small updates for Loongson 3 platforms - Increase the memory limit for ATH79 platforms to 256MB - A fair number of fixes and updates for BCM47xx platforms - Finish the implementation of XPA support - MIPS FDC support. No, not floppy controller but Fast Debug Channel :) - Detect the R16000 used in SGI legacy platforms - Fix Kconfig dependencies for the SSB bus support" * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (265 commits) MIPS: Makefile: Fix MIPS ASE detection code MIPS: asm: elf: Set O32 default FPU flags MIPS: BCM47XX: Fix detecting Microsoft MN-700 & Asus WL500G MIPS: Kconfig: Disable SMP/CPS for 64-bit MIPS: Hibernate: flush TLB entries earlier MIPS: smp-cps: cpu_set FPU mask if FPU present MIPS: lose_fpu(): Disable FPU when MSA enabled MIPS: ralink: add missing symbol for RALINK_ILL_ACC MIPS: ralink: Fix bad config symbol in PCI makefile. SSB: fix Kconfig dependencies MIPS: Malta: Detect and fix bad memsize values Revert "MIPS: Avoid pipeline stalls on some MIPS32R2 cores." MIPS: Octeon: Delete override of cpu_has_mips_r2_exec_hazard. MIPS: Fix cpu_has_mips_r2_exec_hazard. MIPS: kernel: entry.S: Set correct ISA level for mips_ihb MIPS: asm: spinlock: Fix addiu instruction for R10000_LLSC_WAR case MIPS: r4kcache: Use correct base register for MIPS R6 cache flushes MIPS: Kconfig: Fix typo for the r2-to-r6 emulator kernel parameter MIPS: unaligned: Fix regular load/store instruction emulation for EVA MIPS: unaligned: Surround load/store macros in do {} while statements ...
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/Kconfig3
-rw-r--r--drivers/platform/Makefile1
-rw-r--r--drivers/platform/mips/Kconfig30
-rw-r--r--drivers/platform/mips/Makefile2
-rw-r--r--drivers/platform/mips/acpi_init.c150
-rw-r--r--drivers/platform/mips/cpu_hwmon.c207
6 files changed, 393 insertions, 0 deletions
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 09fde58b12e0..0adccbf5c83f 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,6 +1,9 @@
1if X86 1if X86
2source "drivers/platform/x86/Kconfig" 2source "drivers/platform/x86/Kconfig"
3endif 3endif
4if MIPS
5source "drivers/platform/mips/Kconfig"
6endif
4if GOLDFISH 7if GOLDFISH
5source "drivers/platform/goldfish/Kconfig" 8source "drivers/platform/goldfish/Kconfig"
6endif 9endif
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 3656b7b17b99..ca2692510733 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -3,6 +3,7 @@
3# 3#
4 4
5obj-$(CONFIG_X86) += x86/ 5obj-$(CONFIG_X86) += x86/
6obj-$(CONFIG_MIPS) += mips/
6obj-$(CONFIG_OLPC) += olpc/ 7obj-$(CONFIG_OLPC) += olpc/
7obj-$(CONFIG_GOLDFISH) += goldfish/ 8obj-$(CONFIG_GOLDFISH) += goldfish/
8obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ 9obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
new file mode 100644
index 000000000000..125e569017be
--- /dev/null
+++ b/drivers/platform/mips/Kconfig
@@ -0,0 +1,30 @@
1#
2# MIPS Platform Specific Drivers
3#
4
5menuconfig MIPS_PLATFORM_DEVICES
6 bool "MIPS Platform Specific Device Drivers"
7 default y
8 help
9 Say Y here to get to see options for device drivers of various
10 MIPS platforms, including vendor-specific netbook/laptop/desktop
11 extension and hardware monitor drivers. This option itself does
12 not add any kernel code.
13
14 If you say N, all options in this submenu will be skipped and disabled.
15
16if MIPS_PLATFORM_DEVICES
17
18config MIPS_ACPI
19 bool
20 default y if LOONGSON_MACH3X
21
22config CPU_HWMON
23 tristate "Loongson CPU HWMon Driver"
24 depends on LOONGSON_MACH3X
25 select HWMON
26 default y
27 help
28 Loongson-3A/3B CPU Hwmon (temperature sensor) driver.
29
30endif # MIPS_PLATFORM_DEVICES
diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile
new file mode 100644
index 000000000000..43412849b195
--- /dev/null
+++ b/drivers/platform/mips/Makefile
@@ -0,0 +1,2 @@
1obj-$(CONFIG_MIPS_ACPI) += acpi_init.o
2obj-$(CONFIG_CPU_HWMON) += cpu_hwmon.o
diff --git a/drivers/platform/mips/acpi_init.c b/drivers/platform/mips/acpi_init.c
new file mode 100644
index 000000000000..dbdad79ead8f
--- /dev/null
+++ b/drivers/platform/mips/acpi_init.c
@@ -0,0 +1,150 @@
1#include <linux/io.h>
2#include <linux/init.h>
3#include <linux/ioport.h>
4#include <linux/export.h>
5
6#define SBX00_ACPI_IO_BASE 0x800
7#define SBX00_ACPI_IO_SIZE 0x100
8
9#define ACPI_PM_EVT_BLK (SBX00_ACPI_IO_BASE + 0x00) /* 4 bytes */
10#define ACPI_PM_CNT_BLK (SBX00_ACPI_IO_BASE + 0x04) /* 2 bytes */
11#define ACPI_PMA_CNT_BLK (SBX00_ACPI_IO_BASE + 0x0F) /* 1 byte */
12#define ACPI_PM_TMR_BLK (SBX00_ACPI_IO_BASE + 0x18) /* 4 bytes */
13#define ACPI_GPE0_BLK (SBX00_ACPI_IO_BASE + 0x10) /* 8 bytes */
14#define ACPI_END (SBX00_ACPI_IO_BASE + 0x80)
15
16#define PM_INDEX 0xCD6
17#define PM_DATA 0xCD7
18#define PM2_INDEX 0xCD0
19#define PM2_DATA 0xCD1
20
21/*
22 * SCI interrupt need acpi space, allocate here
23 */
24
25static int __init register_acpi_resource(void)
26{
27 request_region(SBX00_ACPI_IO_BASE, SBX00_ACPI_IO_SIZE, "acpi");
28 return 0;
29}
30
31static void pmio_write_index(u16 index, u8 reg, u8 value)
32{
33 outb(reg, index);
34 outb(value, index + 1);
35}
36
37static u8 pmio_read_index(u16 index, u8 reg)
38{
39 outb(reg, index);
40 return inb(index + 1);
41}
42
43void pm_iowrite(u8 reg, u8 value)
44{
45 pmio_write_index(PM_INDEX, reg, value);
46}
47EXPORT_SYMBOL(pm_iowrite);
48
49u8 pm_ioread(u8 reg)
50{
51 return pmio_read_index(PM_INDEX, reg);
52}
53EXPORT_SYMBOL(pm_ioread);
54
55void pm2_iowrite(u8 reg, u8 value)
56{
57 pmio_write_index(PM2_INDEX, reg, value);
58}
59EXPORT_SYMBOL(pm2_iowrite);
60
61u8 pm2_ioread(u8 reg)
62{
63 return pmio_read_index(PM2_INDEX, reg);
64}
65EXPORT_SYMBOL(pm2_ioread);
66
67static void acpi_hw_clear_status(void)
68{
69 u16 value;
70
71 /* PMStatus: Clear WakeStatus/PwrBtnStatus */
72 value = inw(ACPI_PM_EVT_BLK);
73 value |= (1 << 8 | 1 << 15);
74 outw(value, ACPI_PM_EVT_BLK);
75
76 /* GPEStatus: Clear all generated events */
77 outl(inl(ACPI_GPE0_BLK), ACPI_GPE0_BLK);
78}
79
80void acpi_registers_setup(void)
81{
82 u32 value;
83
84 /* PM Status Base */
85 pm_iowrite(0x20, ACPI_PM_EVT_BLK & 0xff);
86 pm_iowrite(0x21, ACPI_PM_EVT_BLK >> 8);
87
88 /* PM Control Base */
89 pm_iowrite(0x22, ACPI_PM_CNT_BLK & 0xff);
90 pm_iowrite(0x23, ACPI_PM_CNT_BLK >> 8);
91
92 /* GPM Base */
93 pm_iowrite(0x28, ACPI_GPE0_BLK & 0xff);
94 pm_iowrite(0x29, ACPI_GPE0_BLK >> 8);
95
96 /* ACPI End */
97 pm_iowrite(0x2e, ACPI_END & 0xff);
98 pm_iowrite(0x2f, ACPI_END >> 8);
99
100 /* IO Decode: When AcpiDecodeEnable set, South-Bridge uses the contents
101 * of the PM registers at index 0x20~0x2B to decode ACPI I/O address. */
102 pm_iowrite(0x0e, 1 << 3);
103
104 /* SCI_EN set */
105 outw(1, ACPI_PM_CNT_BLK);
106
107 /* Enable to generate SCI */
108 pm_iowrite(0x10, pm_ioread(0x10) | 1);
109
110 /* GPM3/GPM9 enable */
111 value = inl(ACPI_GPE0_BLK + 4);
112 outl(value | (1 << 14) | (1 << 22), ACPI_GPE0_BLK + 4);
113
114 /* Set GPM9 as input */
115 pm_iowrite(0x8d, pm_ioread(0x8d) & (~(1 << 1)));
116
117 /* Set GPM9 as non-output */
118 pm_iowrite(0x94, pm_ioread(0x94) | (1 << 3));
119
120 /* GPM3 config ACPI trigger SCIOUT */
121 pm_iowrite(0x33, pm_ioread(0x33) & (~(3 << 4)));
122
123 /* GPM9 config ACPI trigger SCIOUT */
124 pm_iowrite(0x3d, pm_ioread(0x3d) & (~(3 << 2)));
125
126 /* GPM3 config falling edge trigger */
127 pm_iowrite(0x37, pm_ioread(0x37) & (~(1 << 6)));
128
129 /* No wait for STPGNT# in ACPI Sx state */
130 pm_iowrite(0x7c, pm_ioread(0x7c) | (1 << 6));
131
132 /* Set GPM3 pull-down enable */
133 value = pm2_ioread(0xf6);
134 value |= ((1 << 7) | (1 << 3));
135 pm2_iowrite(0xf6, value);
136
137 /* Set GPM9 pull-down enable */
138 value = pm2_ioread(0xf8);
139 value |= ((1 << 5) | (1 << 1));
140 pm2_iowrite(0xf8, value);
141}
142
143int __init sbx00_acpi_init(void)
144{
145 register_acpi_resource();
146 acpi_registers_setup();
147 acpi_hw_clear_status();
148
149 return 0;
150}
diff --git a/drivers/platform/mips/cpu_hwmon.c b/drivers/platform/mips/cpu_hwmon.c
new file mode 100644
index 000000000000..0f6c63e17049
--- /dev/null
+++ b/drivers/platform/mips/cpu_hwmon.c
@@ -0,0 +1,207 @@
1#include <linux/err.h>
2#include <linux/module.h>
3#include <linux/reboot.h>
4#include <linux/jiffies.h>
5#include <linux/hwmon.h>
6#include <linux/hwmon-sysfs.h>
7
8#include <loongson.h>
9#include <boot_param.h>
10#include <loongson_hwmon.h>
11
12/*
13 * Loongson-3 series cpu has two sensors inside,
14 * each of them from 0 to 255,
15 * if more than 127, that is dangerous.
16 * here only provide sensor1 data, because it always hot than sensor0
17 */
18int loongson3_cpu_temp(int cpu)
19{
20 u32 reg;
21
22 reg = LOONGSON_CHIPTEMP(cpu);
23 if (loongson_sysconf.cputype == Loongson_3A)
24 reg = (reg >> 8) & 0xff;
25 else if (loongson_sysconf.cputype == Loongson_3B)
26 reg = ((reg >> 8) & 0xff) - 100;
27
28 return (int)reg * 1000;
29}
30
31static struct device *cpu_hwmon_dev;
32
33static ssize_t get_hwmon_name(struct device *dev,
34 struct device_attribute *attr, char *buf);
35static SENSOR_DEVICE_ATTR(name, S_IRUGO, get_hwmon_name, NULL, 0);
36
37static struct attribute *cpu_hwmon_attributes[] = {
38 &sensor_dev_attr_name.dev_attr.attr,
39 NULL
40};
41
42/* Hwmon device attribute group */
43static struct attribute_group cpu_hwmon_attribute_group = {
44 .attrs = cpu_hwmon_attributes,
45};
46
47/* Hwmon device get name */
48static ssize_t get_hwmon_name(struct device *dev,
49 struct device_attribute *attr, char *buf)
50{
51 return sprintf(buf, "cpu-hwmon\n");
52}
53
54static ssize_t get_cpu0_temp(struct device *dev,
55 struct device_attribute *attr, char *buf);
56static ssize_t get_cpu1_temp(struct device *dev,
57 struct device_attribute *attr, char *buf);
58static ssize_t cpu0_temp_label(struct device *dev,
59 struct device_attribute *attr, char *buf);
60static ssize_t cpu1_temp_label(struct device *dev,
61 struct device_attribute *attr, char *buf);
62
63static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu0_temp, NULL, 1);
64static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu0_temp_label, NULL, 1);
65static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu1_temp, NULL, 2);
66static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu1_temp_label, NULL, 2);
67
68static const struct attribute *hwmon_cputemp1[] = {
69 &sensor_dev_attr_temp1_input.dev_attr.attr,
70 &sensor_dev_attr_temp1_label.dev_attr.attr,
71 NULL
72};
73
74static const struct attribute *hwmon_cputemp2[] = {
75 &sensor_dev_attr_temp2_input.dev_attr.attr,
76 &sensor_dev_attr_temp2_label.dev_attr.attr,
77 NULL
78};
79
80static ssize_t cpu0_temp_label(struct device *dev,
81 struct device_attribute *attr, char *buf)
82{
83 return sprintf(buf, "CPU 0 Temprature\n");
84}
85
86static ssize_t cpu1_temp_label(struct device *dev,
87 struct device_attribute *attr, char *buf)
88{
89 return sprintf(buf, "CPU 1 Temprature\n");
90}
91
92static ssize_t get_cpu0_temp(struct device *dev,
93 struct device_attribute *attr, char *buf)
94{
95 int value = loongson3_cpu_temp(0);
96 return sprintf(buf, "%d\n", value);
97}
98
99static ssize_t get_cpu1_temp(struct device *dev,
100 struct device_attribute *attr, char *buf)
101{
102 int value = loongson3_cpu_temp(1);
103 return sprintf(buf, "%d\n", value);
104}
105
106static int create_sysfs_cputemp_files(struct kobject *kobj)
107{
108 int ret;
109
110 ret = sysfs_create_files(kobj, hwmon_cputemp1);
111 if (ret)
112 goto sysfs_create_temp1_fail;
113
114 if (loongson_sysconf.nr_cpus <= loongson_sysconf.cores_per_package)
115 return 0;
116
117 ret = sysfs_create_files(kobj, hwmon_cputemp2);
118 if (ret)
119 goto sysfs_create_temp2_fail;
120
121 return 0;
122
123sysfs_create_temp2_fail:
124 sysfs_remove_files(kobj, hwmon_cputemp1);
125
126sysfs_create_temp1_fail:
127 return -1;
128}
129
130static void remove_sysfs_cputemp_files(struct kobject *kobj)
131{
132 sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp1);
133
134 if (loongson_sysconf.nr_cpus > loongson_sysconf.cores_per_package)
135 sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp2);
136}
137
138#define CPU_THERMAL_THRESHOLD 90000
139static struct delayed_work thermal_work;
140
141static void do_thermal_timer(struct work_struct *work)
142{
143 int value = loongson3_cpu_temp(0);
144 if (value <= CPU_THERMAL_THRESHOLD)
145 schedule_delayed_work(&thermal_work, msecs_to_jiffies(5000));
146 else
147 orderly_poweroff(true);
148}
149
150static int __init loongson_hwmon_init(void)
151{
152 int ret;
153
154 pr_info("Loongson Hwmon Enter...\n");
155
156 cpu_hwmon_dev = hwmon_device_register(NULL);
157 if (IS_ERR(cpu_hwmon_dev)) {
158 ret = -ENOMEM;
159 pr_err("hwmon_device_register fail!\n");
160 goto fail_hwmon_device_register;
161 }
162
163 ret = sysfs_create_group(&cpu_hwmon_dev->kobj,
164 &cpu_hwmon_attribute_group);
165 if (ret) {
166 pr_err("fail to create loongson hwmon!\n");
167 goto fail_sysfs_create_group_hwmon;
168 }
169
170 ret = create_sysfs_cputemp_files(&cpu_hwmon_dev->kobj);
171 if (ret) {
172 pr_err("fail to create cpu temprature interface!\n");
173 goto fail_create_sysfs_cputemp_files;
174 }
175
176 INIT_DEFERRABLE_WORK(&thermal_work, do_thermal_timer);
177 schedule_delayed_work(&thermal_work, msecs_to_jiffies(20000));
178
179 return ret;
180
181fail_create_sysfs_cputemp_files:
182 sysfs_remove_group(&cpu_hwmon_dev->kobj,
183 &cpu_hwmon_attribute_group);
184
185fail_sysfs_create_group_hwmon:
186 hwmon_device_unregister(cpu_hwmon_dev);
187
188fail_hwmon_device_register:
189 return ret;
190}
191
192static void __exit loongson_hwmon_exit(void)
193{
194 cancel_delayed_work_sync(&thermal_work);
195 remove_sysfs_cputemp_files(&cpu_hwmon_dev->kobj);
196 sysfs_remove_group(&cpu_hwmon_dev->kobj,
197 &cpu_hwmon_attribute_group);
198 hwmon_device_unregister(cpu_hwmon_dev);
199}
200
201module_init(loongson_hwmon_init);
202module_exit(loongson_hwmon_exit);
203
204MODULE_AUTHOR("Yu Xiang <xiangy@lemote.com>");
205MODULE_AUTHOR("Huacai Chen <chenhc@lemote.com>");
206MODULE_DESCRIPTION("Loongson CPU Hwmon driver");
207MODULE_LICENSE("GPL");