diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 10:59:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 10:59:54 -0700 |
commit | 568d135d337d3114688fef9fdbce7fb6dbbd04c7 (patch) | |
tree | b9355b94182a51eec5cfc69dd335e39a2e97ac7d /drivers | |
parent | 4ecd4ff55ac5c7fe9e232f34a41c4d54f2d825c1 (diff) | |
parent | d40e0d4fb5613099a58c95a9403f51b03e40e861 (diff) | |
download | linux-568d135d337d3114688fef9fdbce7fb6dbbd04c7.tar.bz2 |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"Boston platform support:
- Document DT bindings
- Add CLK driver for board clocks
CM:
- Avoid per-core locking with CM3 & higher
- WARN on attempt to lock invalid VP, not BUG
CPS:
- Select CONFIG_SYS_SUPPORTS_SCHED_SMT for MIPSr6
- Prevent multi-core with dcache aliasing
- Handle cores not powering down more gracefully
- Handle spurious VP starts more gracefully
DSP:
- Add lwx & lhx missaligned access support
eBPF:
- Add MIPS support along with many supporting change to add the
required infrastructure
Generic arch code:
- Misc sysmips MIPS_ATOMIC_SET fixes
- Drop duplicate HAVE_SYSCALL_TRACEPOINTS
- Negate error syscall return in trace
- Correct forced syscall errors
- Traced negative syscalls should return -ENOSYS
- Allow samples/bpf/tracex5 to access syscall arguments for sane
traces
- Cleanup from old Kconfig options in defconfigs
- Fix PREF instruction usage by memcpy for MIPS R6
- Fix various special cases in the FPU eulation
- Fix some special cases in MIPS16e2 support
- Fix MIPS I ISA /proc/cpuinfo reporting
- Sort MIPS Kconfig alphabetically
- Fix minimum alignment requirement of IRQ stack as required by
ABI / GCC
- Fix special cases in the module loader
- Perform post-DMA cache flushes on systems with MAARs
- Probe the I6500 CPU
- Cleanup cmpxchg and add support for 1 and 2 byte operations
- Use queued read/write locks (qrwlock)
- Use queued spinlocks (qspinlock)
- Add CPU shared FTLB feature detection
- Handle tlbex-tlbp race condition
- Allow storing pgd in C0_CONTEXT for MIPSr6
- Use current_cpu_type() in m4kc_tlbp_war()
- Support Boston in the generic kernel
Generic platform:
- yamon-dt: Pull YAMON DT shim code out of SEAD-3 board
- yamon-dt: Support > 256MB of RAM
- yamon-dt: Use serial* rather than uart* aliases
- Abstract FDT fixup application
- Set RTC_ALWAYS_BCD to 0
- Add a MAINTAINERS entry
core kernel:
- qspinlock.c: include linux/prefetch.h
Loongson 3:
- Add support
Perf:
- Add I6500 support
SEAD-3:
- Remove GIC timer from DT
- Set interrupt-parent per-device, not at root node
- Fix GIC interrupt specifiers
SMP:
- Skip IPI setup if we only have a single CPU
VDSO:
- Make comment match reality
- Improvements to time code in VDSO"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (86 commits)
locking/qspinlock: Include linux/prefetch.h
MIPS: Fix MIPS I ISA /proc/cpuinfo reporting
MIPS: Fix minimum alignment requirement of IRQ stack
MIPS: generic: Support MIPS Boston development boards
MIPS: DTS: img: Don't attempt to build-in all .dtb files
clk: boston: Add a driver for MIPS Boston board clocks
dt-bindings: Document img,boston-clock binding
MIPS: Traced negative syscalls should return -ENOSYS
MIPS: Correct forced syscall errors
MIPS: Negate error syscall return in trace
MIPS: Drop duplicate HAVE_SYSCALL_TRACEPOINTS select
MIPS16e2: Provide feature overrides for non-MIPS16 systems
MIPS: MIPS16e2: Report ASE presence in /proc/cpuinfo
MIPS: MIPS16e2: Subdecode extended LWSP/SWSP instructions
MIPS: MIPS16e2: Identify ASE presence
MIPS: VDSO: Fix a mismatch between comment and preprocessor constant
MIPS: VDSO: Add implementation of gettimeofday() fallback
MIPS: VDSO: Add implementation of clock_gettime() fallback
MIPS: VDSO: Fix conversions in do_monotonic()/do_monotonic_coarse()
MIPS: Use current_cpu_type() in m4kc_tlbp_war()
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/Kconfig | 1 | ||||
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/imgtec/Kconfig | 9 | ||||
-rw-r--r-- | drivers/clk/imgtec/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/imgtec/clk-boston.c | 103 | ||||
-rw-r--r-- | drivers/platform/mips/cpu_hwmon.c | 136 |
6 files changed, 186 insertions, 65 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index d406b087553f..68ca2d9fcd73 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -221,6 +221,7 @@ config COMMON_CLK_VC5 source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" +source "drivers/clk/imgtec/Kconfig" source "drivers/clk/keystone/Kconfig" source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 4f6a812342ed..cd376b3fb47a 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -60,6 +60,7 @@ obj-y += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_H8300) += h8300/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ +obj-y += imgtec/ obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_MACH_INGENIC) += ingenic/ obj-$(CONFIG_ARCH_KEYSTONE) += keystone/ diff --git a/drivers/clk/imgtec/Kconfig b/drivers/clk/imgtec/Kconfig new file mode 100644 index 000000000000..f6dcb748e9c4 --- /dev/null +++ b/drivers/clk/imgtec/Kconfig @@ -0,0 +1,9 @@ +config COMMON_CLK_BOSTON + bool "Clock driver for MIPS Boston boards" + depends on MIPS || COMPILE_TEST + select MFD_SYSCON + ---help--- + Enable this to support the system & CPU clocks on the MIPS Boston + development board from Imagination Technologies. These are simple + fixed rate clocks whose rate is determined by reading a platform + provided register. diff --git a/drivers/clk/imgtec/Makefile b/drivers/clk/imgtec/Makefile new file mode 100644 index 000000000000..ac779b8c22f2 --- /dev/null +++ b/drivers/clk/imgtec/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_COMMON_CLK_BOSTON) += clk-boston.o diff --git a/drivers/clk/imgtec/clk-boston.c b/drivers/clk/imgtec/clk-boston.c new file mode 100644 index 000000000000..f18f10351785 --- /dev/null +++ b/drivers/clk/imgtec/clk-boston.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016-2017 Imagination Technologies + * Author: Paul Burton <paul.burton@imgtec.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. + */ + +#define pr_fmt(fmt) "clk-boston: " fmt + +#include <linux/clk-provider.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/mfd/syscon.h> + +#include <dt-bindings/clock/boston-clock.h> + +#define BOSTON_PLAT_MMCMDIV 0x30 +# define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0) +# define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8) +# define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16) +# define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24) + +#define BOSTON_CLK_COUNT 3 + +static u32 ext_field(u32 val, u32 mask) +{ + return (val & mask) >> (ffs(mask) - 1); +} + +static void __init clk_boston_setup(struct device_node *np) +{ + unsigned long in_freq, cpu_freq, sys_freq; + uint mmcmdiv, mul, cpu_div, sys_div; + struct clk_hw_onecell_data *onecell; + struct regmap *regmap; + struct clk_hw *hw; + int err; + + regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(regmap)) { + pr_err("failed to find regmap\n"); + return; + } + + err = regmap_read(regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv); + if (err) { + pr_err("failed to read mmcm_div register: %d\n", err); + return; + } + + in_freq = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT) * 1000000; + mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL); + + sys_div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV); + sys_freq = mult_frac(in_freq, mul, sys_div); + + cpu_div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV); + cpu_freq = mult_frac(in_freq, mul, cpu_div); + + onecell = kzalloc(sizeof(*onecell) + + (BOSTON_CLK_COUNT * sizeof(struct clk_hw *)), + GFP_KERNEL); + if (!onecell) + return; + + onecell->num = BOSTON_CLK_COUNT; + + hw = clk_hw_register_fixed_rate(NULL, "input", NULL, 0, in_freq); + if (IS_ERR(hw)) { + pr_err("failed to register input clock: %ld\n", PTR_ERR(hw)); + return; + } + onecell->hws[BOSTON_CLK_INPUT] = hw; + + hw = clk_hw_register_fixed_rate(NULL, "sys", "input", 0, sys_freq); + if (IS_ERR(hw)) { + pr_err("failed to register sys clock: %ld\n", PTR_ERR(hw)); + return; + } + onecell->hws[BOSTON_CLK_SYS] = hw; + + hw = clk_hw_register_fixed_rate(NULL, "cpu", "input", 0, cpu_freq); + if (IS_ERR(hw)) { + pr_err("failed to register cpu clock: %ld\n", PTR_ERR(hw)); + return; + } + onecell->hws[BOSTON_CLK_CPU] = hw; + + err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, onecell); + if (err) + pr_err("failed to add DT provider: %d\n", err); +} + +/* + * Use CLK_OF_DECLARE so that this driver is probed early enough to provide the + * CPU frequency for use with the GIC or cop0 counters/timers. + */ +CLK_OF_DECLARE(clk_boston, "img,boston-clock", clk_boston_setup); diff --git a/drivers/platform/mips/cpu_hwmon.c b/drivers/platform/mips/cpu_hwmon.c index 4300a558d0f3..322de58eebaf 100644 --- a/drivers/platform/mips/cpu_hwmon.c +++ b/drivers/platform/mips/cpu_hwmon.c @@ -17,17 +17,27 @@ */ int loongson3_cpu_temp(int cpu) { - u32 reg; + u32 reg, prid_rev; reg = LOONGSON_CHIPTEMP(cpu); - if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) + prid_rev = read_c0_prid() & PRID_REV_MASK; + switch (prid_rev) { + case PRID_REV_LOONGSON3A_R1: reg = (reg >> 8) & 0xff; - else + break; + case PRID_REV_LOONGSON3A_R2: + case PRID_REV_LOONGSON3B_R1: + case PRID_REV_LOONGSON3B_R2: reg = ((reg >> 8) & 0xff) - 100; - + break; + case PRID_REV_LOONGSON3A_R3: + reg = (reg & 0xffff)*731/0x4000 - 273; + break; + } return (int)reg * 1000; } +static int nr_packages; static struct device *cpu_hwmon_dev; static ssize_t get_hwmon_name(struct device *dev, @@ -51,88 +61,74 @@ static ssize_t get_hwmon_name(struct device *dev, return sprintf(buf, "cpu-hwmon\n"); } -static ssize_t get_cpu0_temp(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t get_cpu1_temp(struct device *dev, +static ssize_t get_cpu_temp(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t cpu0_temp_label(struct device *dev, +static ssize_t cpu_temp_label(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t cpu1_temp_label(struct device *dev, - struct device_attribute *attr, char *buf); - -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu0_temp, NULL, 1); -static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu0_temp_label, NULL, 1); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu1_temp, NULL, 2); -static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu1_temp_label, NULL, 2); -static const struct attribute *hwmon_cputemp1[] = { - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp1_label.dev_attr.attr, - NULL -}; - -static const struct attribute *hwmon_cputemp2[] = { - &sensor_dev_attr_temp2_input.dev_attr.attr, - &sensor_dev_attr_temp2_label.dev_attr.attr, - NULL +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, cpu_temp_label, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_cpu_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, cpu_temp_label, NULL, 2); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, get_cpu_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, cpu_temp_label, NULL, 3); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, get_cpu_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, cpu_temp_label, NULL, 4); + +static const struct attribute *hwmon_cputemp[4][3] = { + { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + NULL + }, + { + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_label.dev_attr.attr, + NULL + }, + { + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_label.dev_attr.attr, + NULL + }, + { + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_label.dev_attr.attr, + NULL + } }; -static ssize_t cpu0_temp_label(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "CPU 0 Temperature\n"); -} - -static ssize_t cpu1_temp_label(struct device *dev, +static ssize_t cpu_temp_label(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "CPU 1 Temperature\n"); + int id = (to_sensor_dev_attr(attr))->index - 1; + return sprintf(buf, "CPU %d Temperature\n", id); } -static ssize_t get_cpu0_temp(struct device *dev, +static ssize_t get_cpu_temp(struct device *dev, struct device_attribute *attr, char *buf) { - int value = loongson3_cpu_temp(0); - return sprintf(buf, "%d\n", value); -} - -static ssize_t get_cpu1_temp(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int value = loongson3_cpu_temp(1); + int id = (to_sensor_dev_attr(attr))->index - 1; + int value = loongson3_cpu_temp(id); return sprintf(buf, "%d\n", value); } static int create_sysfs_cputemp_files(struct kobject *kobj) { - int ret; - - ret = sysfs_create_files(kobj, hwmon_cputemp1); - if (ret) - goto sysfs_create_temp1_fail; - - if (loongson_sysconf.nr_cpus <= loongson_sysconf.cores_per_package) - return 0; + int i, ret = 0; - ret = sysfs_create_files(kobj, hwmon_cputemp2); - if (ret) - goto sysfs_create_temp2_fail; + for (i=0; i<nr_packages; i++) + ret = sysfs_create_files(kobj, hwmon_cputemp[i]); - return 0; - -sysfs_create_temp2_fail: - sysfs_remove_files(kobj, hwmon_cputemp1); - -sysfs_create_temp1_fail: - return -1; + return ret; } static void remove_sysfs_cputemp_files(struct kobject *kobj) { - sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp1); + int i; - if (loongson_sysconf.nr_cpus > loongson_sysconf.cores_per_package) - sysfs_remove_files(&cpu_hwmon_dev->kobj, hwmon_cputemp2); + for (i=0; i<nr_packages; i++) + sysfs_remove_files(kobj, hwmon_cputemp[i]); } #define CPU_THERMAL_THRESHOLD 90000 @@ -140,8 +136,15 @@ static struct delayed_work thermal_work; static void do_thermal_timer(struct work_struct *work) { - int value = loongson3_cpu_temp(0); - if (value <= CPU_THERMAL_THRESHOLD) + int i, value, temp_max = 0; + + for (i=0; i<nr_packages; i++) { + value = loongson3_cpu_temp(i); + if (value > temp_max) + temp_max = value; + } + + if (temp_max <= CPU_THERMAL_THRESHOLD) schedule_delayed_work(&thermal_work, msecs_to_jiffies(5000)); else orderly_poweroff(true); @@ -160,6 +163,9 @@ static int __init loongson_hwmon_init(void) goto fail_hwmon_device_register; } + nr_packages = loongson_sysconf.nr_cpus / + loongson_sysconf.cores_per_package; + ret = sysfs_create_group(&cpu_hwmon_dev->kobj, &cpu_hwmon_attribute_group); if (ret) { |