diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-19 10:02:26 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-19 10:02:26 -0700 |
commit | 07b75260ebc2c789724c594d7eaf0194fa47b3be (patch) | |
tree | d88b770bca479789e688d95e50aacd5d09b59b21 | |
parent | 0efacbbaee1e94e9942da0912f5b46ffd45a74bd (diff) | |
parent | 6e4ad1b413604b9130bdbe532aafdbd47ff5318e (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 4.7. Here's the summary of
the changes:
- ATH79: Support for DTB passuing using the UHI boot protocol
- ATH79: Remove support for builtin DTB.
- ATH79: Add zboot debug serial support.
- ATH79: Add initial support for Dragino MS14 (Dragine 2), Onion Omega
and DPT-Module.
- ATH79: Update devicetree clock support for AR9132 and AR9331.
- ATH79: Cleanup the DT code.
- ATH79: Support newer SOCs in ath79_ddr_ctrl_init.
- ATH79: Fix regression in PCI window initialization.
- BCM47xx: Move SPROM driver to drivers/firmware/
- BCM63xx: Enable partition parser in defconfig.
- BMIPS: BMIPS5000 has I cache filing from D cache
- BMIPS: BMIPS: Add cpu-feature-overrides.h
- BMIPS: Add Whirlwind support
- BMIPS: Adjust mips-hpt-frequency for BCM7435
- BMIPS: Remove maxcpus from BCM97435SVMB DTS
- BMIPS: Add missing 7038 L1 register cells to BCM7435
- BMIPS: Various tweaks to initialization code.
- BMIPS: Enable partition parser in defconfig.
- BMIPS: Cache tweaks.
- BMIPS: Add UART, I2C and SATA devices to DT.
- BMIPS: Add BCM6358 and BCM63268support
- BMIPS: Add device tree example for BCM6358.
- BMIPS: Improve Improve BCM6328 and BCM6368 device trees
- Lantiq: Add support for device tree file from boot loader
- Lantiq: Allow build with no built-in DT.
- Loongson 3: Reserve 32MB for RS780E integrated GPU.
- Loongson 3: Fix build error after ld-version.sh modification
- Loongson 3: Move chipset ACPI code from drivers to arch.
- Loongson 3: Speedup irq processing.
- Loongson 3: Add basic Loongson 3A support.
- Loongson 3: Set cache flush handlers to nop.
- Loongson 3: Invalidate special TLBs when needed.
- Loongson 3: Fast TLB refill handler.
- MT7620: Fallback strategy for invalid syscfg0.
- Netlogic: Fix CP0_EBASE redefinition warnings
- Octeon: Initialization fixes
- Octeon: Add DTS files for the D-Link DSR-1000N and EdgeRouter Lite
- Octeon: Enable add Octeon-drivers in cavium_octeon_defconfig
- Octeon: Correctly handle endian-swapped initramfs images.
- Octeon: Support CN73xx, CN75xx and CN78xx.
- Octeon: Remove dead code from cvmx-sysinfo.
- Octeon: Extend number of supported CPUs past 32.
- Octeon: Remove some code limiting NR_IRQS to 255.
- Octeon: Simplify octeon_irq_ciu_gpio_set_type.
- Octeon: Mark some functions __init in smp.c
- Octeon: Octeon: Add Octeon III CN7xxx interface detection
- PIC32: Add serial driver and bindings for it.
- PIC32: Add PIC32 deadman timer driver and bindings.
- PIC32: Add PIC32 clock timer driver and bindings.
- Pistachio: Determine SoC revision during boot
- Sibyte: Fix Kconfig dependencies of SIBYTE_BUS_WATCHER.
- Sibyte: Strip redundant comments from bcm1480_regs.h.
- Panic immediately if panic_on_oops is set.
- module: fix incorrect IS_ERR_VALUE macro usage.
- module: Make consistent use of pr_*
- Remove no longer needed work_on_cpu() call.
- Remove CONFIG_IPV6_PRIVACY from defconfigs.
- Fix registers of non-crashing CPUs in dumps.
- Handle MIPSisms in new vmcore_elf32_check_arch.
- Select CONFIG_HANDLE_DOMAIN_IRQ and make it work.
- Allow RIXI to be used on non-R2 or R6 cores.
- Reserve nosave data for hibernation
- Fix siginfo.h to use strict POSIX types.
- Don't unwind user mode with EVA.
- Fix watchpoint restoration
- Ptrace watchpoints for R6.
- Sync icache when it fills from dcache
- I6400 I-cache fills from dcache.
- Various MSA fixes.
- Cleanup MIPS_CPU_* definitions.
- Signal: Move generic copy_siginfo to signal.h
- Signal: Fix uapi include in exported asm/siginfo.h
- Timer fixes for sake of KVM.
- XPA TLB refill fixes.
- Treat perf counter feature
- Update John Crispin's email address
- Add PIC32 watchdog and bindings.
- Handle R10000 LL/SC bug in set_pte()
- cpufreq: Various fixes for Longson1.
- R6: Fix R2 emulation.
- mathemu: Cosmetic fix to ADDIUPC emulation, plenty of other small fixes
- ELF: ABI and FP fixes.
- Allow for relocatable kernel and use that to support KASLR.
- Fix CPC_BASE_ADDR mask
- Plenty fo smp-cps, CM, R6 and M6250 fixes.
- Make reset_control_ops const.
- Fix kernel command line handling of leading whitespace.
- Cleanups to cache handling.
- Add brcm, bcm6345-l1-intc device tree bindings.
- Use generic clkdev.h header
- Remove CLK_IS_ROOT usage.
- Misc small cleanups.
- CM: Fix compilation error when !MIPS_CM
- oprofile: Fix a preemption issue
- Detect DSP ASE v3 support:1"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (275 commits)
MIPS: pic32mzda: fix getting timer clock rate.
MIPS: ath79: fix regression in PCI window initialization
MIPS: ath79: make ath79_ddr_ctrl_init() compatible for newer SoCs
MIPS: Fix VZ probe gas errors with binutils <2.24
MIPS: perf: Fix I6400 event numbers
MIPS: DEC: Export `ioasic_ssr_lock' to modules
MIPS: MSA: Fix a link error on `_init_msa_upper' with older GCC
MIPS: CM: Fix compilation error when !MIPS_CM
MIPS: Fix genvdso error on rebuild
USB: ohci-jz4740: Remove obsolete driver
MIPS: JZ4740: Probe OHCI platform device via DT
MIPS: JZ4740: Qi LB60: Remove support for AVT2 variant
MIPS: pistachio: Determine SoC revision during boot
MIPS: BMIPS: Adjust mips-hpt-frequency for BCM7435
mips: mt7620: fallback to SDRAM when syscfg0 does not have a valid value for the memory type
MIPS: Prevent "restoration" of MSA context in non-MSA kernels
MIPS: cevt-r4k: Dynamically calculate min_delta_ns
MIPS: malta-time: Take seconds into account
MIPS: malta-time: Start GIC count before syncing to RTC
MIPS: Force CPUs to lose FP context during mode switches
...
358 files changed, 14005 insertions, 3399 deletions
diff --git a/Documentation/devicetree/bindings/clock/microchip,pic32.txt b/Documentation/devicetree/bindings/clock/microchip,pic32.txt new file mode 100644 index 000000000000..c93d88fdd858 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/microchip,pic32.txt @@ -0,0 +1,39 @@ +Microchip PIC32 Clock Controller Binding +---------------------------------------- +Microchip clock controller is consists of few oscillators, PLL, multiplexer +and few divider modules. + +This binding uses common clock bindings. +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: shall be "microchip,pic32mzda-clk". +- reg: shall contain base address and length of clock registers. +- #clock-cells: shall be 1. + +Optional properties: +- microchip,pic32mzda-sosc: shall be added only if platform has + secondary oscillator connected. + +Example: + rootclk: clock-controller@1f801200 { + compatible = "microchip,pic32mzda-clk"; + reg = <0x1f801200 0x200>; + #clock-cells = <1>; + /* optional */ + microchip,pic32mzda-sosc; + }; + + +The clock consumer shall specify the desired clock-output of the clock +controller (as defined in [2]) by specifying output-id in its "clock" +phandle cell. +[2] include/dt-bindings/clock/microchip,pic32-clock.h + +For example for UART2: +uart2: serial@2 { + compatible = "microchip,pic32mzda-uart"; + reg = <>; + interrupts = <>; + clocks = <&rootclk PB2CLK>; +}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt new file mode 100644 index 000000000000..4040905388d9 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt @@ -0,0 +1,57 @@ +Broadcom BCM6345-style Level 1 interrupt controller + +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. + +Key elements of the hardware design include: + +- 32, 64 or 128 incoming level IRQ lines + +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Contains one or more enable/status word pairs per CPU + +- No atomic set/clear operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-4 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm<soc>-l1-intc", "brcm,bcm6345-l1-intc" +- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller(s) + this one is cascaded from +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP +system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +The driver operates in native CPU endian by default, there is no support for +specifying an alternative endianness. + +Example: + +periph_intc: interrupt-controller@10000000 { + compatible = "brcm,bcm63168-l1-intc", "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x20>, + <0x10000040 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +}; diff --git a/Documentation/devicetree/bindings/mips/brcm/soc.txt b/Documentation/devicetree/bindings/mips/brcm/soc.txt index 7bab90cc4a7b..4a7e030e4f9b 100644 --- a/Documentation/devicetree/bindings/mips/brcm/soc.txt +++ b/Documentation/devicetree/bindings/mips/brcm/soc.txt @@ -4,7 +4,8 @@ Required properties: - compatible: "brcm,bcm3384", "brcm,bcm33843" "brcm,bcm3384-viper", "brcm,bcm33843-viper" - "brcm,bcm6328", "brcm,bcm6368", + "brcm,bcm6328", "brcm,bcm6358", "brcm,bcm6368", + "brcm,bcm63168", "brcm,bcm63268", "brcm,bcm7125", "brcm,bcm7346", "brcm,bcm7358", "brcm,bcm7360", "brcm,bcm7362", "brcm,bcm7420", "brcm,bcm7425" diff --git a/Documentation/devicetree/bindings/mips/cavium/ciu3.txt b/Documentation/devicetree/bindings/mips/cavium/ciu3.txt new file mode 100644 index 000000000000..616862ad2b71 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/cavium/ciu3.txt @@ -0,0 +1,27 @@ +* Central Interrupt Unit v3 + +Properties: +- compatible: "cavium,octeon-7890-ciu3" + + Compatibility with 78XX and 73XX SOCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: The base address of the CIU's register bank. + +- #interrupt-cells: Must be <2>. The first cell is source number. + The second cell indicates the triggering semantics, and may have a + value of either 4 for level semantics, or 1 for edge semantics. + +Example: + interrupt-controller@1010000000000 { + compatible = "cavium,octeon-7890-ciu3"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Source number (20 significant bits) + * 2) Trigger type: (4 == level, 1 == edge) + */ + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x10100 0x00000000 0x0 0xb0000000>; + }; diff --git a/Documentation/devicetree/bindings/serial/microchip,pic32-uart.txt b/Documentation/devicetree/bindings/serial/microchip,pic32-uart.txt new file mode 100644 index 000000000000..65b38bf60ae0 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/microchip,pic32-uart.txt @@ -0,0 +1,29 @@ +* Microchip Universal Asynchronous Receiver Transmitter (UART) + +Required properties: +- compatible: Should be "microchip,pic32mzda-uart" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt +- clocks: Phandle to the clock. + See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- pinctrl-names: A pinctrl state names "default" must be defined. +- pinctrl-0: Phandle referencing pin configuration of the UART peripheral. + See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt + +Optional properties: +- cts-gpios: CTS pin for UART + +Example: + uart1: serial@1f822000 { + compatible = "microchip,pic32mzda-uart"; + reg = <0x1f822000 0x50>; + interrupts = <112 IRQ_TYPE_LEVEL_HIGH>, + <113 IRQ_TYPE_LEVEL_HIGH>, + <114 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&PBCLK2>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1 + &pinctrl_uart1_cts + &pinctrl_uart1_rts>; + cts-gpios = <&gpio1 15 0>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 021bbe7866e0..316412dc7913 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -72,6 +72,8 @@ digilent Diglent, Inc. dlg Dialog Semiconductor dlink D-Link Corporation dmo Data Modul AG +dptechnics DPTechnics +dragino Dragino Technology Co., Limited ea Embedded Artists AB ebv EBV Elektronik edt Emerging Display Technologies @@ -176,6 +178,7 @@ nvidia NVIDIA nxp NXP Semiconductors okaya Okaya Electric America, Inc. olimex OLIMEX Ltd. +onion Onion Corporation onnn ON Semiconductor Corp. opencores OpenCores.org option Option NV diff --git a/Documentation/devicetree/bindings/watchdog/microchip,pic32-dmt.txt b/Documentation/devicetree/bindings/watchdog/microchip,pic32-dmt.txt new file mode 100644 index 000000000000..852f694f3177 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/microchip,pic32-dmt.txt @@ -0,0 +1,19 @@ +* Microchip PIC32 Deadman Timer + +The deadman timer is used to reset the processor in the event of a software +malfunction. It is a free-running instruction fetch timer, which is clocked +whenever an instruction fetch occurs until a count match occurs. + +Required properties: +- compatible: must be "microchip,pic32mzda-dmt". +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: phandle of parent clock (should be &PBCLK7). + +Example: + + watchdog@1f800a00 { + compatible = "microchip,pic32mzda-dmt"; + reg = <0x1f800a00 0x80>; + clocks = <&PBCLK7>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/microchip,pic32-wdt.txt b/Documentation/devicetree/bindings/watchdog/microchip,pic32-wdt.txt new file mode 100644 index 000000000000..d1401030e75c --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/microchip,pic32-wdt.txt @@ -0,0 +1,18 @@ +* Microchip PIC32 Watchdog Timer + +When enabled, the watchdog peripheral can be used to reset the device if the +WDT is not cleared periodically in software. + +Required properties: +- compatible: must be "microchip,pic32mzda-wdt". +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: phandle of source clk. should be <&LPRC> clk. + +Example: + + watchdog@1f800800 { + compatible = "microchip,pic32mzda-wdt"; + reg = <0x1f800800 0x200>; + clocks = <&LPRC>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 3f14e1dffa6a..ef8a56e04af6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6491,7 +6491,7 @@ F: net/l3mdev F: include/net/l3mdev.h LANTIQ MIPS ARCHITECTURE -M: John Crispin <blogic@openwrt.org> +M: John Crispin <john@phrozen.org> L: linux-mips@linux-mips.org S: Maintained F: arch/mips/lantiq @@ -7332,6 +7332,15 @@ S: Supported F: Documentation/mips/ F: arch/mips/ +MIPS/LOONGSON1 ARCHITECTURE +M: Keguang Zhang <keguang.zhang@gmail.com> +L: linux-mips@linux-mips.org +S: Maintained +F: arch/mips/loongson32/ +F: arch/mips/include/asm/mach-loongson32/ +F: drivers/*/*loongson1* +F: drivers/*/*/*loongson1* + MIROSOUND PCM20 FM RADIO RECEIVER DRIVER M: Hans Verkuil <hverkuil@xs4all.nl> L: linux-media@vger.kernel.org @@ -9251,7 +9260,7 @@ S: Maintained F: drivers/video/fbdev/aty/aty128fb.c RALINK MIPS ARCHITECTURE -M: John Crispin <blogic@openwrt.org> +M: John Crispin <john@phrozen.org> L: linux-mips@linux-mips.org S: Maintained F: arch/mips/ralink diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index d2ac1174ee17..5663f411c225 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -62,6 +62,7 @@ config MIPS select HAVE_IRQ_TIME_ACCOUNTING select GENERIC_TIME_VSYSCALL select ARCH_CLOCKSOURCE_DATA + select HANDLE_DOMAIN_IRQ menu "Machine selection" @@ -137,7 +138,7 @@ config ATH79 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_MIPS16 - select SYS_SUPPORTS_ZBOOT + select SYS_SUPPORTS_ZBOOT_UART_PROM select USE_OF help Support for the Atheros AR71XX/AR724X/AR913X SoCs. @@ -194,6 +195,7 @@ config BCM47XX select GPIOLIB select LEDS_GPIO_REGISTER select BCM47XX_NVRAM + select BCM47XX_SPROM help Support for BCM47XX based boards @@ -471,6 +473,7 @@ config MIPS_MALTA select SYS_SUPPORTS_MULTITHREADING select SYS_SUPPORTS_SMARTMIPS select SYS_SUPPORTS_ZBOOT + select SYS_SUPPORTS_RELOCATABLE select USE_OF select ZONE_DMA32 if 64BIT select BUILTIN_DTB @@ -505,6 +508,7 @@ config MIPS_SEAD3 select MIPS_MSC select SYS_HAS_CPU_MIPS32_R1 select SYS_HAS_CPU_MIPS32_R2 + select SYS_HAS_CPU_MIPS32_R6 select SYS_HAS_CPU_MIPS64_R1 select SYS_HAS_EARLY_PRINTK select SYS_SUPPORTS_32BIT_KERNEL @@ -514,6 +518,7 @@ config MIPS_SEAD3 select SYS_SUPPORTS_SMARTMIPS select SYS_SUPPORTS_MICROMIPS select SYS_SUPPORTS_MIPS16 + select SYS_SUPPORTS_RELOCATABLE select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_MMIO select USE_OF @@ -1153,6 +1158,13 @@ config ISA_DMA_API config HOLES_IN_ZONE bool +config SYS_SUPPORTS_RELOCATABLE + bool + help + Selected if the platform supports relocating the kernel. + The platform must provide plat_get_fdt() if it selects CONFIG_USE_OF + to allow access to command line and entropy sources. + # # Endianness selection. Sufficiently obscure so many users don't know what to # answer,so we try hard to limit the available choices. Also the use of a @@ -1340,11 +1352,30 @@ config CPU_LOONGSON3 select CPU_SUPPORTS_HUGEPAGES select WEAK_ORDERING select WEAK_REORDERING_BEYOND_LLSC + select MIPS_PGD_C0_CONTEXT select GPIOLIB help The Loongson 3 processor implements the MIPS64R2 instruction set with many extensions. +config LOONGSON3_ENHANCEMENT + bool "New Loongson 3 CPU Enhancements" + default n + select CPU_MIPSR2 + select CPU_HAS_PREFETCH + depends on CPU_LOONGSON3 + help + New Loongson 3 CPU (since Loongson-3A R2, as opposed to Loongson-3A + R1, Loongson-3B R1 and Loongson-3B R2) has many enhancements, such as + FTLB, L1-VCache, EI/DI/Wait/Prefetch instruction, DSP/DSPv2 ASE, User + Local register, Read-Inhibit/Execute-Inhibit, SFB (Store Fill Buffer), + Fast TLB refill support, etc. + + This option enable those enhancements which are not probed at run + time. If you want a generic kernel to run on all Loongson 3 machines, + please say 'N' here. If you want a high-performance kernel to run on + new Loongson 3 machines only, please say 'Y' here. + config CPU_LOONGSON2E bool "Loongson 2E" depends on SYS_HAS_CPU_LOONGSON2E @@ -1373,6 +1404,8 @@ config CPU_LOONGSON1B bool "Loongson 1B" depends on SYS_HAS_CPU_LOONGSON1B select CPU_LOONGSON1 + select ARCH_WANT_OPTIONAL_GPIOLIB + select LEDS_GPIO_REGISTER help The Loongson 1B is a 32-bit SoC, which implements the MIPS32 release 2 instruction set. @@ -1671,6 +1704,7 @@ config CPU_XLP select CPU_HAS_PREFETCH select CPU_MIPSR2 select CPU_SUPPORTS_HUGEPAGES + select MIPS_ASID_BITS_VARIABLE help Netlogic Microsystems XLP processors. endchoice @@ -1796,6 +1830,7 @@ config CPU_BMIPS4380 select MIPS_L1_CACHE_SHIFT_6 select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU + select CPU_HAS_RIXI config CPU_BMIPS5000 bool @@ -1803,10 +1838,12 @@ config CPU_BMIPS5000 select MIPS_L1_CACHE_SHIFT_7 select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU + select CPU_HAS_RIXI config SYS_HAS_CPU_LOONGSON3 bool select CPU_SUPPORTS_CPUFREQ + select CPU_HAS_RIXI config SYS_HAS_CPU_LOONGSON2E bool @@ -1959,11 +1996,15 @@ config CPU_MIPSR1 config CPU_MIPSR2 bool default y if CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_CAVIUM_OCTEON + select CPU_HAS_RIXI select MIPS_SPRAM config CPU_MIPSR6 bool default y if CPU_MIPS32_R6 || CPU_MIPS64_R6 + select CPU_HAS_RIXI + select HAVE_ARCH_BITREVERSE + select MIPS_ASID_BITS_VARIABLE select MIPS_SPRAM config EVA @@ -1997,7 +2038,7 @@ config MIPS_PGD_C0_CONTEXT # config HARDWARE_WATCHPOINTS bool - default y if CPU_MIPSR1 || CPU_MIPSR2 + default y if CPU_MIPSR1 || CPU_MIPSR2 || CPU_MIPSR6 menu "Kernel type" @@ -2040,6 +2081,16 @@ config KVM_GUEST_TIMER_FREQ emulation when determining guest CPU Frequency. Instead, the guest's timer frequency is specified directly. +config MIPS_VA_BITS_48 + bool "48 bits virtual memory" + depends on 64BIT + help + Support a maximum at least 48 bits of application virtual memory. + Default is 40 bits or less, depending on the CPU. + This option result in a small memory overhead for page tables. + This option is only supported with 16k and 64k page sizes. + If unsure, say N. + choice prompt "Kernel page size" default PAGE_SIZE_4KB @@ -2047,6 +2098,7 @@ choice config PAGE_SIZE_4KB bool "4kB" depends on !CPU_LOONGSON2 && !CPU_LOONGSON3 + depends on !MIPS_VA_BITS_48 help This option select the standard 4kB Linux page size. On some R3000-family processors this is the only available page size. Using @@ -2056,6 +2108,7 @@ config PAGE_SIZE_4KB config PAGE_SIZE_8KB bool "8kB" depends on CPU_R8000 || CPU_CAVIUM_OCTEON + depends on !MIPS_VA_BITS_48 help Using 8kB page size will result in higher performance kernel at the price of higher memory consumption. This option is available @@ -2074,6 +2127,7 @@ config PAGE_SIZE_16KB config PAGE_SIZE_32KB bool "32kB" depends on CPU_CAVIUM_OCTEON + depends on !MIPS_VA_BITS_48 help Using 32kB page size will result in higher performance kernel at the price of higher memory consumption. This option is available @@ -2278,7 +2332,7 @@ config MIPS_CMP config MIPS_CPS bool "MIPS Coherent Processing System support" - depends on SYS_SUPPORTS_MIPS_CPS && !CPU_MIPSR6 + depends on SYS_SUPPORTS_MIPS_CPS select MIPS_CM select MIPS_CPC select MIPS_CPS_PM if HOTPLUG_CPU @@ -2369,6 +2423,9 @@ config CPU_HAS_WB config XKS01 bool +config CPU_HAS_RIXI + bool + # # Vectored interrupt mode is an R2 feature # @@ -2399,6 +2456,21 @@ config CPU_R4000_WORKAROUNDS config CPU_R4400_WORKAROUNDS bool +config MIPS_ASID_SHIFT + int + default 6 if CPU_R3000 || CPU_TX39XX + default 4 if CPU_R8000 + default 0 + +config MIPS_ASID_BITS + int + default 0 if MIPS_ASID_BITS_VARIABLE + default 6 if CPU_R3000 || CPU_TX39XX + default 8 + +config MIPS_ASID_BITS_VARIABLE + bool + # # - Highmem only makes sense for the 32-bit kernel. # - The current highmem code will only work properly on physically indexed @@ -2468,6 +2540,61 @@ config NUMA config SYS_SUPPORTS_NUMA bool +config RELOCATABLE + bool "Relocatable kernel" + depends on SYS_SUPPORTS_RELOCATABLE && (CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_MIPS32_R6 || CPU_MIPS64_R6) + help + This builds a kernel image that retains relocation information + so it can be loaded someplace besides the default 1MB. + The relocations make the kernel binary about 15% larger, + but are discarded at runtime + +config RELOCATION_TABLE_SIZE + hex "Relocation table size" + depends on RELOCATABLE + range 0x0 0x01000000 + default "0x00100000" + ---help--- + A table of relocation data will be appended to the kernel binary + and parsed at boot to fix up the relocated kernel. + + This option allows the amount of space reserved for the table to be + adjusted, although the default of 1Mb should be ok in most cases. + + The build will fail and a valid size suggested if this is too small. + + If unsure, leave at the default value. + +config RANDOMIZE_BASE + bool "Randomize the address of the kernel image" + depends on RELOCATABLE + ---help--- + Randomizes the physical and virtual address at which the + kernel image is loaded, as a security feature that + deters exploit attempts relying on knowledge of the location + of kernel internals. + + Entropy is generated using any coprocessor 0 registers available. + + The kernel will be offset by up to RANDOMIZE_BASE_MAX_OFFSET. + + If unsure, say N. + +config RANDOMIZE_BASE_MAX_OFFSET + hex "Maximum kASLR offset" if EXPERT + depends on RANDOMIZE_BASE + range 0x0 0x40000000 if EVA || 64BIT + range 0x0 0x08000000 + default "0x01000000" + ---help--- + When kASLR is active, this provides the maximum offset that will + be applied to the kernel image. It should be set according to the + amount of physical RAM available in the target system minus + PHYSICAL_START and must be a power of 2. + + This is limited by the size of KSEG0, 256Mb on 32-bit or 1Gb with + EVA or 64-bit. The default is 16Mb. + config NODES_SHIFT int default "6" @@ -2475,7 +2602,7 @@ config NODES_SHIFT config HW_PERF_EVENTS bool "Enable hardware performance counter support for perf events" - depends on PERF_EVENTS && OPROFILE=n && (CPU_MIPS32 || CPU_MIPS64 || CPU_R10000 || CPU_SB1 || CPU_CAVIUM_OCTEON || CPU_XLP || CPU_LOONGSON3) + depends on PERF_EVENTS && !OPROFILE && (CPU_MIPS32 || CPU_MIPS64 || CPU_R10000 || CPU_SB1 || CPU_CAVIUM_OCTEON || CPU_XLP || CPU_LOONGSON3) default y help Enable hardware performance counter support for perf events. If @@ -2808,6 +2935,10 @@ choice config MIPS_CMDLINE_FROM_BOOTLOADER bool "Bootloader kernel arguments if available" + + config MIPS_CMDLINE_BUILTIN_EXTEND + depends on CMDLINE_BOOL + bool "Extend builtin kernel arguments with bootloader arguments" endchoice endmenu diff --git a/arch/mips/Makefile b/arch/mips/Makefile index e78d60dbdffd..efd7a9dc93c4 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -12,6 +12,9 @@ # for "archclean" cleaning up for this architecture. # +archscripts: scripts_basic + $(Q)$(MAKE) $(build)=arch/mips/boot/tools relocs + KBUILD_DEFCONFIG := ip22_defconfig # @@ -93,6 +96,10 @@ LDFLAGS_vmlinux += -G 0 -static -n -nostdlib KBUILD_AFLAGS_MODULE += -mlong-calls KBUILD_CFLAGS_MODULE += -mlong-calls +ifeq ($(CONFIG_RELOCATABLE),y) +LDFLAGS_vmlinux += --emit-relocs +endif + # # pass -msoft-float to GAS if it supports it. However on newer binutils # (specifically newer than 2.24.51.20140728) we then also need to explicitly @@ -193,6 +200,8 @@ ifeq ($(CONFIG_CPU_HAS_MSA),y) toolchain-msa := $(call cc-option-yn,$(mips-cflags) -mhard-float -mfp64 -Wa$(comma)-mmsa) cflags-$(toolchain-msa) += -DTOOLCHAIN_SUPPORTS_MSA endif +toolchain-virt := $(call cc-option-yn,$(mips-cflags) -mvirt) +cflags-$(toolchain-virt) += -DTOOLCHAIN_SUPPORTS_VIRT cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_NEVER) += -mcompact-branches=never cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_OPTIMAL) += -mcompact-branches=optimal @@ -310,6 +319,10 @@ rom.bin rom.sw: vmlinux $(bootvars-y) $@ endif +CMD_RELOCS = arch/mips/boot/tools/relocs +quiet_cmd_relocs = RELOCS $< + cmd_relocs = $(CMD_RELOCS) $< + # # Some machines like the Indy need 32-bit ELF binaries for booting purposes. # Other need ECOFF, so we build a 32-bit ELF binary for them which we then @@ -318,6 +331,11 @@ endif quiet_cmd_32 = OBJCOPY $@ cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ vmlinux.32: vmlinux +ifeq ($(CONFIG_RELOCATABLE)$(CONFIG_64BIT),yy) +# Currently, objcopy fails to handle the relocations in the elf64 +# So the relocs tool must be run here to remove them first + $(call cmd,relocs) +endif $(call cmd,32) # @@ -333,6 +351,9 @@ all: $(all-y) # boot $(boot-y): $(vmlinux-32) FORCE +ifeq ($(CONFIG_RELOCATABLE)$(CONFIG_32BIT),yy) + $(call cmd,relocs) +endif $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) \ $(bootvars-y) arch/mips/boot/$@ @@ -385,6 +406,7 @@ endif archclean: $(Q)$(MAKE) $(clean)=arch/mips/boot $(Q)$(MAKE) $(clean)=arch/mips/boot/compressed + $(Q)$(MAKE) $(clean)=arch/mips/boot/tools $(Q)$(MAKE) $(clean)=arch/mips/lasat define archhelp diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index bd34f4093cd9..7ba7ea0a22f8 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -1043,8 +1043,7 @@ static int __init alchemy_clk_init(void) /* Root of the Alchemy clock tree: external 12MHz crystal osc */ c = clk_register_fixed_rate(NULL, ALCHEMY_ROOT_CLK, NULL, - CLK_IS_ROOT, - ALCHEMY_ROOTCLK_RATE); + 0, ALCHEMY_ROOTCLK_RATE); ERRCK(c) /* CPU core clock */ diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index 13c04cf54afa..dfc60209dc63 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -71,18 +71,6 @@ config ATH79_MACH_UBNT_XM Say 'Y' here if you want your kernel to support the Ubiquiti Networks XM (rev 1.0) board. -choice - prompt "Build a DTB in the kernel" - optional - help - Select a devicetree that should be built into the kernel. - - config DTB_TL_WR1043ND_V1 - bool "TL-WR1043ND Version 1" - select BUILTIN_DTB - select SOC_AR913X -endchoice - endmenu config SOC_AR71XX diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c index 618dfd735eed..2e7378467c5c 100644 --- a/arch/mips/ath79/clock.c +++ b/arch/mips/ath79/clock.c @@ -18,17 +18,21 @@ #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <dt-bindings/clock/ath79-clk.h> #include <asm/div64.h> #include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ar71xx_regs.h> #include "common.h" +#include "machtypes.h" #define AR71XX_BASE_FREQ 40000000 #define AR724X_BASE_FREQ 40000000 -static struct clk *clks[3]; +static struct clk *clks[ATH79_CLK_END]; static struct clk_onecell_data clk_data = { .clks = clks, .clk_num = ARRAY_SIZE(clks), @@ -40,7 +44,7 @@ static struct clk *__init ath79_add_sys_clkdev( struct clk *clk; int err; - clk = clk_register_fixed_rate(NULL, id, NULL, CLK_IS_ROOT, rate); + clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate); if (!clk) panic("failed to allocate %s clock structure", id); @@ -78,107 +82,139 @@ static void __init ar71xx_clocks_init(void) ahb_rate = cpu_rate / div; ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + clks[ATH79_CLK_CPU] = ath79_add_sys_clkdev("cpu", cpu_rate); + clks[ATH79_CLK_DDR] = ath79_add_sys_clkdev("ddr", ddr_rate); + clks[ATH79_CLK_AHB] = ath79_add_sys_clkdev("ahb", ahb_rate); clk_add_alias("wdt", NULL, "ahb", NULL); clk_add_alias("uart", NULL, "ahb", NULL); } -static void __init ar724x_clocks_init(void) +static struct clk * __init ath79_reg_ffclk(const char *name, + const char *parent_name, unsigned int mult, unsigned int div) { - unsigned long ref_rate; - unsigned long cpu_rate; - unsigned long ddr_rate; - unsigned long ahb_rate; - u32 pll; - u32 freq; - u32 div; + struct clk *clk; - ref_rate = AR724X_BASE_FREQ; - pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); + clk = clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div); + if (!clk) + panic("failed to allocate %s clock structure", name); - div = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK); - freq = div * ref_rate; + return clk; +} +static void __init ar724x_clk_init(struct clk *ref_clk, void __iomem *pll_base) +{ + u32 pll; + u32 mult, div, ddr_div, ahb_div; + + pll = __raw_readl(pll_base + AR724X_PLL_REG_CPU_CONFIG); + + mult = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK); div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK) * 2; - freq /= div; - cpu_rate = freq; + ddr_div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; + ahb_div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; - div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; - ddr_rate = freq / div; + clks[ATH79_CLK_CPU] = ath79_reg_ffclk("cpu", "ref", mult, div); + clks[ATH79_CLK_DDR] = ath79_reg_ffclk("ddr", "ref", mult, div * ddr_div); + clks[ATH79_CLK_AHB] = ath79_reg_ffclk("ahb", "ref", mult, div * ahb_div); +} - div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; - ahb_rate = cpu_rate / div; +static void __init ar724x_clocks_init(void) +{ + struct clk *ref_clk; - ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + ref_clk = ath79_add_sys_clkdev("ref", AR724X_BASE_FREQ); + + ar724x_clk_init(ref_clk, ath79_pll_base); + + /* just make happy plat_time_init() from arch/mips/ath79/setup.c */ + clk_register_clkdev(clks[ATH79_CLK_CPU], "cpu", NULL); + clk_register_clkdev(clks[ATH79_CLK_DDR], "ddr", NULL); + clk_register_clkdev(clks[ATH79_CLK_AHB], "ahb", NULL); clk_add_alias("wdt", NULL, "ahb", NULL); clk_add_alias("uart", NULL, "ahb", NULL); } -static void __init ar933x_clocks_init(void) +static void __init ar9330_clk_init(struct clk *ref_clk, void __iomem *pll_base) { - unsigned long ref_rate; - unsigned long cpu_rate; - unsigned long ddr_rate; - unsigned long ahb_rate; u32 clock_ctrl; - u32 cpu_config; - u32 freq; - u32 t; + u32 ref_div; + u32 ninit_mul; + u32 out_div; - t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); - if (t & AR933X_BOOTSTRAP_REF_CLK_40) - ref_rate = (40 * 1000 * 1000); - else - ref_rate = (25 * 1000 * 1000); + u32 cpu_div; + u32 ddr_div; + u32 ahb_div; - clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG); + clock_ctrl = __raw_readl(pll_base + AR933X_PLL_CLOCK_CTRL_REG); if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { - cpu_rate = ref_rate; - ahb_rate = ref_rate; - ddr_rate = ref_rate; + ref_div = 1; + ninit_mul = 1; + out_div = 1; + + cpu_div = 1; + ddr_div = 1; + ahb_div = 1; } else { - cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG); + u32 cpu_config; + u32 t; + + cpu_config = __raw_readl(pll_base + AR933X_PLL_CPU_CONFIG_REG); t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & AR933X_PLL_CPU_CONFIG_REFDIV_MASK; - freq = ref_rate / t; + ref_div = t; - t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & + ninit_mul = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & AR933X_PLL_CPU_CONFIG_NINT_MASK; - freq *= t; t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; if (t == 0) t = 1; - freq >>= t; + out_div = (1 << t); - t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & + cpu_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; - cpu_rate = freq / t; - t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & + ddr_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; - ddr_rate = freq / t; - t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & + ahb_div = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; - ahb_rate = freq / t; } - ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + clks[ATH79_CLK_CPU] = ath79_reg_ffclk("cpu", "ref", + ninit_mul, ref_div * out_div * cpu_div); + clks[ATH79_CLK_DDR] = ath79_reg_ffclk("ddr", "ref", + ninit_mul, ref_div * out_div * ddr_div); + clks[ATH79_CLK_AHB] = ath79_reg_ffclk("ahb", "ref", + ninit_mul, ref_div * out_div * ahb_div); +} + +static void __init ar933x_clocks_init(void) +{ + struct clk *ref_clk; + unsigned long ref_rate; + u32 t; + + t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); + if (t & AR933X_BOOTSTRAP_REF_CLK_40) + ref_rate = (40 * 1000 * 1000); + else + ref_rate = (25 * 1000 * 1000); + + ref_clk = ath79_add_sys_clkdev("ref", ref_rate); + + ar9330_clk_init(ref_clk, ath79_pll_base); + + /* just make happy plat_time_init() from arch/mips/ath79/setup.c */ + clk_register_clkdev(clks[ATH79_CLK_CPU], "cpu", NULL); + clk_register_clkdev(clks[ATH79_CLK_DDR], "ddr", NULL); + clk_register_clkdev(clks[ATH79_CLK_AHB], "ahb", NULL); clk_add_alias("wdt", NULL, "ahb", NULL); clk_add_alias("uart", NULL, "ref", NULL); @@ -310,9 +346,9 @@ static void __init ar934x_clocks_init(void) ahb_rate = cpu_pll / (postdiv + 1); ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + clks[ATH79_CLK_CPU] = ath79_add_sys_clkdev("cpu", cpu_rate); + clks[ATH79_CLK_DDR] = ath79_add_sys_clkdev("ddr", ddr_rate); + clks[ATH79_CLK_AHB] = ath79_add_sys_clkdev("ahb", ahb_rate); clk_add_alias("wdt", NULL, "ref", NULL); clk_add_alias("uart", NULL, "ref", NULL); @@ -397,9 +433,9 @@ static void __init qca955x_clocks_init(void) ahb_rate = cpu_pll / (postdiv + 1); ath79_add_sys_clkdev("ref", ref_rate); - clks[0] = ath79_add_sys_clkdev("cpu", cpu_rate); - clks[1] = ath79_add_sys_clkdev("ddr", ddr_rate); - clks[2] = ath79_add_sys_clkdev("ahb", ahb_rate); + clks[ATH79_CLK_CPU] = ath79_add_sys_clkdev("cpu", cpu_rate); + clks[ATH79_CLK_DDR] = ath79_add_sys_clkdev("ddr", ddr_rate); + clks[ATH79_CLK_AHB] = ath79_add_sys_clkdev("ahb", ahb_rate); clk_add_alias("wdt", NULL, "ref", NULL); clk_add_alias("uart", NULL, "ref", NULL); @@ -419,8 +455,6 @@ void __init ath79_clocks_init(void) qca955x_clocks_init(); else BUG(); - - of_clk_init(NULL); } unsigned long __init @@ -447,8 +481,49 @@ static void __init ath79_clocks_init_dt(struct device_node *np) CLK_OF_DECLARE(ar7100, "qca,ar7100-pll", ath79_clocks_init_dt); CLK_OF_DECLARE(ar7240, "qca,ar7240-pll", ath79_clocks_init_dt); -CLK_OF_DECLARE(ar9130, "qca,ar9130-pll", ath79_clocks_init_dt); -CLK_OF_DECLARE(ar9330, "qca,ar9330-pll", ath79_clocks_init_dt); CLK_OF_DECLARE(ar9340, "qca,ar9340-pll", ath79_clocks_init_dt); CLK_OF_DECLARE(ar9550, "qca,qca9550-pll", ath79_clocks_init_dt); + +static void __init ath79_clocks_init_dt_ng(struct device_node *np) +{ + struct clk *ref_clk; + void __iomem *pll_base; + const char *dnfn = of_node_full_name(np); + + ref_clk = of_clk_get(np, 0); + if (IS_ERR(ref_clk)) { + pr_err("%s: of_clk_get failed\n", dnfn); + goto err; + } + + pll_base = of_iomap(np, 0); + if (!pll_base) { + pr_err("%s: can't map pll registers\n", dnfn); + goto err_clk; + } + + if (of_device_is_compatible(np, "qca,ar9130-pll")) + ar724x_clk_init(ref_clk, pll_base); + else if (of_device_is_compatible(np, "qca,ar9330-pll")) + ar9330_clk_init(ref_clk, pll_base); + else { + pr_err("%s: could not find any appropriate clk_init()\n", dnfn); + goto err_clk; + } + + if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) { + pr_err("%s: could not register clk provider\n", dnfn); + goto err_clk; + } + + return; + +err_clk: + clk_put(ref_clk); + +err: + return; +} +CLK_OF_DECLARE(ar9130_clk, "qca,ar9130-pll", ath79_clocks_init_dt_ng); +CLK_OF_DECLARE(ar9330_clk, "qca,ar9330-pll", ath79_clocks_init_dt_ng); #endif diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c index 3cedd1f95e0f..d071a3a0f876 100644 --- a/arch/mips/ath79/common.c +++ b/arch/mips/ath79/common.c @@ -46,12 +46,12 @@ void ath79_ddr_ctrl_init(void) { ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE); - if (soc_is_ar71xx() || soc_is_ar934x()) { - ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c; - ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c; - } else { + if (soc_is_ar913x() || soc_is_ar724x() || soc_is_ar933x()) { ath79_ddr_wb_flush_base = ath79_ddr_base + 0x7c; ath79_ddr_pci_win_base = 0; + } else { + ath79_ddr_wb_flush_base = ath79_ddr_base + 0x9c; + ath79_ddr_pci_win_base = ath79_ddr_base + 0x7c; } } EXPORT_SYMBOL_GPL(ath79_ddr_ctrl_init); @@ -76,14 +76,14 @@ void ath79_ddr_set_pci_windows(void) { BUG_ON(!ath79_ddr_pci_win_base); - __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0); - __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 1); - __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 2); - __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 3); - __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 4); - __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 5); - __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 6); - __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 7); + __raw_writel(AR71XX_PCI_WIN0_OFFS, ath79_ddr_pci_win_base + 0x0); + __raw_writel(AR71XX_PCI_WIN1_OFFS, ath79_ddr_pci_win_base + 0x4); + __raw_writel(AR71XX_PCI_WIN2_OFFS, ath79_ddr_pci_win_base + 0x8); + __raw_writel(AR71XX_PCI_WIN3_OFFS, ath79_ddr_pci_win_base + 0xc); + __raw_writel(AR71XX_PCI_WIN4_OFFS, ath79_ddr_pci_win_base + 0x10); + __raw_writel(AR71XX_PCI_WIN5_OFFS, ath79_ddr_pci_win_base + 0x14); + __raw_writel(AR71XX_PCI_WIN6_OFFS, ath79_ddr_pci_win_base + 0x18); + __raw_writel(AR71XX_PCI_WIN7_OFFS, ath79_ddr_pci_win_base + 0x1c); } EXPORT_SYMBOL_GPL(ath79_ddr_set_pci_windows); diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index be451ee4a5ea..7adab180e0ca 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -17,6 +17,7 @@ #include <linux/bootmem.h> #include <linux/err.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/of_platform.h> #include <linux/of_fdt.h> @@ -203,26 +204,57 @@ void __init plat_mem_setup(void) fdt_start = fw_getenvl("fdt_start"); if (fdt_start) __dt_setup_arch((void *)KSEG0ADDR(fdt_start)); -#ifdef CONFIG_BUILTIN_DTB - else - __dt_setup_arch(__dtb_start); -#endif + else if (fw_arg0 == -2) + __dt_setup_arch((void *)KSEG0ADDR(fw_arg1)); - ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE, - AR71XX_RESET_SIZE); - ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, - AR71XX_PLL_SIZE); - ath79_detect_sys_type(); - ath79_ddr_ctrl_init(); + if (mips_machtype != ATH79_MACH_GENERIC_OF) { + ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE, + AR71XX_RESET_SIZE); + ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE, + AR71XX_PLL_SIZE); + ath79_detect_sys_type(); + ath79_ddr_ctrl_init(); - if (mips_machtype != ATH79_MACH_GENERIC_OF) detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX); - _machine_restart = ath79_restart; + /* OF machines should use the reset driver */ + _machine_restart = ath79_restart; + } + _machine_halt = ath79_halt; pm_power_off = ath79_halt; } +static void __init ath79_of_plat_time_init(void) +{ + struct device_node *np; + struct clk *clk; + unsigned long cpu_clk_rate; + + of_clk_init(NULL); + + np = of_get_cpu_node(0, NULL); + if (!np) { + pr_err("Failed to get CPU node\n"); + return; + } + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk)); + return; + } + + cpu_clk_rate = clk_get_rate(clk); + + pr_info("CPU clock: %lu.%03lu MHz\n", + cpu_clk_rate / 1000000, (cpu_clk_rate / 1000) % 1000); + + mips_hpt_frequency = cpu_clk_rate / 2; + + clk_put(clk); +} + void __init plat_time_init(void) { unsigned long cpu_clk_rate; @@ -230,6 +262,11 @@ void __init plat_time_init(void) unsigned long ddr_clk_rate; unsigned long ref_clk_rate; + if (IS_ENABLED(CONFIG_OF) && mips_machtype == ATH79_MACH_GENERIC_OF) { + ath79_of_plat_time_init(); + return; + } + ath79_clocks_init(); cpu_clk_rate = ath79_get_sys_clk_rate("cpu"); diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile index 66bea4ecf449..6d8615074075 100644 --- a/arch/mips/bcm47xx/Makefile +++ b/arch/mips/bcm47xx/Makefile @@ -3,5 +3,5 @@ # under Linux. # -obj-y += irq.o prom.o serial.o setup.o time.o sprom.o +obj-y += irq.o prom.o serial.o setup.o time.o obj-y += board.o buttons.o leds.o workarounds.o diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h index 41796befa9df..0367ac7286fe 100644 --- a/arch/mips/bcm47xx/bcm47xx_private.h +++ b/arch/mips/bcm47xx/bcm47xx_private.h @@ -10,9 +10,6 @@ /* prom.c */ void __init bcm47xx_prom_highmem_init(void); -/* sprom.c */ -void bcm47xx_sprom_register_fallbacks(void); - /* buttons.c */ int __init bcm47xx_buttons_register(void); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index c807e32d6d81..6054d49e608e 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -28,6 +28,7 @@ #include "bcm47xx_private.h" +#include <linux/bcm47xx_sprom.h> #include <linux/export.h> #include <linux/types.h> #include <linux/ethtool.h> @@ -151,7 +152,6 @@ void __init plat_mem_setup(void) pr_info("Using bcma bus\n"); #ifdef CONFIG_BCM47XX_BCMA bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA; - bcm47xx_sprom_register_fallbacks(); bcm47xx_register_bcma(); bcm47xx_set_system_type(bcm47xx_bus.bcma.bus.chipinfo.id); #ifdef CONFIG_HIGHMEM diff --git a/arch/mips/bmips/Kconfig b/arch/mips/bmips/Kconfig index e2c4fd682c74..264328d528c7 100644 --- a/arch/mips/bmips/Kconfig +++ b/arch/mips/bmips/Kconfig @@ -21,6 +21,10 @@ config DT_BCM93384WVG_VIPER bool "BCM93384WVG Viper CPU (EXPERIMENTAL)" select BUILTIN_DTB +config DT_BCM96358NB4SER + bool "BCM96358NB4SER" + select BUILTIN_DTB + config DT_BCM96368MVWG bool "BCM96368MVWG" select BUILTIN_DTB diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index 35535284b39e..f146d1219bde 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -95,6 +95,15 @@ static void bcm6328_quirks(void) bcm63xx_fixup_cpu1(); } +static void bcm6358_quirks(void) +{ + /* + * BCM6358 needs special handling for its shared TLB, so + * disable SMP for now + */ + bmips_smp_enabled = 0; +} + static void bcm6368_quirks(void) { bcm63xx_fixup_cpu1(); @@ -104,13 +113,16 @@ static const struct bmips_quirk bmips_quirk_list[] = { { "brcm,bcm3384-viper", &bcm3384_viper_quirks }, { "brcm,bcm33843-viper", &bcm3384_viper_quirks }, { "brcm,bcm6328", &bcm6328_quirks }, + { "brcm,bcm6358", &bcm6358_quirks }, { "brcm,bcm6368", &bcm6368_quirks }, { "brcm,bcm63168", &bcm6368_quirks }, + { "brcm,bcm63268", &bcm6368_quirks }, { }, }; void __init prom_init(void) { + bmips_cpu_setup(); register_bmips_smp_ops(); } diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 309d2ad67e4d..90aca95fe314 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -37,8 +37,13 @@ vmlinuzobjs-$(CONFIG_DEBUG_ZBOOT) += $(obj)/dbg.o vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART_PROM) += $(obj)/uart-prom.o vmlinuzobjs-$(CONFIG_MIPS_ALCHEMY) += $(obj)/uart-alchemy.o +vmlinuzobjs-$(CONFIG_ATH79) += $(obj)/uart-ath79.o endif +extra-y += uart-ath79.c +$(obj)/uart-ath79.c: $(srctree)/arch/mips/ath79/early_printk.c + $(call cmd,shipped) + vmlinuzobjs-$(CONFIG_KERNEL_XZ) += $(obj)/ashldi3.o $(obj)/bswapsi.o extra-y += ashldi3.c bswapsi.c diff --git a/arch/mips/boot/dts/brcm/Makefile b/arch/mips/boot/dts/brcm/Makefile index eabeb603e805..fda9d387cc08 100644 --- a/arch/mips/boot/dts/brcm/Makefile +++ b/arch/mips/boot/dts/brcm/Makefile @@ -1,5 +1,6 @@ dtb-$(CONFIG_DT_BCM93384WVG) += bcm93384wvg.dtb dtb-$(CONFIG_DT_BCM93384WVG_VIPER) += bcm93384wvg_viper.dtb +dtb-$(CONFIG_DT_BCM96358NB4SER) += bcm96358nb4ser.dtb dtb-$(CONFIG_DT_BCM96368MVWG) += bcm96368mvwg.dtb dtb-$(CONFIG_DT_BCM9EJTAGPRB) += bcm9ejtagprb.dtb dtb-$(CONFIG_DT_BCM97125CBMB) += bcm97125cbmb.dtb @@ -14,6 +15,7 @@ dtb-$(CONFIG_DT_BCM97435SVMB) += bcm97435svmb.dtb dtb-$(CONFIG_DT_NONE) += \ bcm93384wvg.dtb \ bcm93384wvg_viper.dtb \ + bcm96358nb4ser.dtb \ bcm96368mvwg.dtb \ bcm9ejtagprb.dtb \ bcm97125cbmb.dtb \ diff --git a/arch/mips/boot/dts/brcm/bcm6328.dtsi b/arch/mips/boot/dts/brcm/bcm6328.dtsi index 9d19236f53e7..5633b9d90f55 100644 --- a/arch/mips/boot/dts/brcm/bcm6328.dtsi +++ b/arch/mips/boot/dts/brcm/bcm6328.dtsi @@ -23,7 +23,7 @@ }; clocks { - periph_clk: periph_clk { + periph_clk: periph-clk { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <50000000>; @@ -31,11 +31,11 @@ }; aliases { - leds0 = &leds0; - uart0 = &uart0; + serial0 = &uart0; + serial1 = &uart1; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -50,16 +50,16 @@ compatible = "simple-bus"; ranges; - periph_intc: periph_intc@10000020 { - compatible = "brcm,bcm3380-l2-intc"; - reg = <0x10000024 0x4 0x1000002c 0x4>, - <0x10000020 0x4 0x10000028 0x4>; + periph_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x10>, + <0x10000030 0x10>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&cpu_intc>; - interrupts = <2>; + interrupts = <2>, <3>; }; uart0: serial@10000100 { @@ -71,13 +71,22 @@ status = "disabled"; }; - timer: timer@10000040 { + uart1: serial@10000120 { + compatible = "brcm,bcm6345-uart"; + reg = <0x10000120 0x18>; + interrupt-parent = <&periph_intc>; + interrupts = <39>; + clocks = <&periph_clk>; + status = "disabled"; + }; + + timer: syscon@10000040 { compatible = "syscon"; reg = <0x10000040 0x2c>; native-endian; }; - reboot { + reboot: syscon-reboot@10000068 { compatible = "syscon-reboot"; regmap = <&timer>; offset = <0x28>; @@ -91,5 +100,24 @@ reg = <0x10000800 0x24>; status = "disabled"; }; + + ehci: usb@10002500 { + compatible = "brcm,bcm6328-ehci", "generic-ehci"; + reg = <0x10002500 0x100>; + big-endian; + interrupt-parent = <&periph_intc>; + interrupts = <42>; + status = "disabled"; + }; + + ohci: usb@10002600 { + compatible = "brcm,bcm6328-ohci", "generic-ohci"; + reg = <0x10002600 0x100>; + big-endian; + no-big-frame-no; + interrupt-parent = <&periph_intc>; + interrupts = <41>; + status = "disabled"; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm6358.dtsi b/arch/mips/boot/dts/brcm/bcm6358.dtsi new file mode 100644 index 000000000000..f9d8d392162b --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm6358.dtsi @@ -0,0 +1,130 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "brcm,bcm6358"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + mips-hpt-frequency = <150000000>; + + cpu@0 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "brcm,bmips4350"; + device_type = "cpu"; + reg = <1>; + }; + }; + + clocks { + periph_clk: periph-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + }; + }; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + cpu_intc: interrupt-controller { + #address-cells = <0>; + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + ubus { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "simple-bus"; + ranges; + + periph_cntl: syscon@fffe0000 { + compatible = "syscon"; + reg = <0xfffe0000 0xc>; + native-endian; + }; + + reboot: syscon-reboot@fffe0008 { + compatible = "syscon-reboot"; + regmap = <&periph_cntl>; + offset = <0x8>; + mask = <0x1>; + }; + + periph_intc: interrupt-controller@fffe000c { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0xfffe000c 0x8>, + <0xfffe0038 0x8>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; + }; + + leds0: led-controller@fffe00d0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "brcm,bcm6358-leds"; + reg = <0xfffe00d0 0x8>; + + status = "disabled"; + }; + + uart0: serial@fffe0100 { + compatible = "brcm,bcm6345-uart"; + reg = <0xfffe0100 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <2>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + uart1: serial@fffe0120 { + compatible = "brcm,bcm6345-uart"; + reg = <0xfffe0120 0x18>; + + interrupt-parent = <&periph_intc>; + interrupts = <3>; + + clocks = <&periph_clk>; + + status = "disabled"; + }; + + ehci: usb@fffe1300 { + compatible = "brcm,bcm6358-ehci", "generic-ehci"; + reg = <0xfffe1300 0x100>; + big-endian; + interrupt-parent = <&periph_intc>; + interrupts = <10>; + status = "disabled"; + }; + + ohci: usb@fffe1400 { + compatible = "brcm,bcm6358-ohci", "generic-ohci"; + reg = <0xfffe1400 0x100>; + big-endian; + no-big-frame-no; + interrupt-parent = <&periph_intc>; + interrupts = <5>; + status = "disabled"; + }; + }; +}; diff --git a/arch/mips/boot/dts/brcm/bcm6368.dtsi b/arch/mips/boot/dts/brcm/bcm6368.dtsi index 1f6b9b5cddb4..d0e3a70b32e2 100644 --- a/arch/mips/boot/dts/brcm/bcm6368.dtsi +++ b/arch/mips/boot/dts/brcm/bcm6368.dtsi @@ -20,11 +20,10 @@ device_type = "cpu"; reg = <1>; }; - }; clocks { - periph_clk: periph_clk { + periph_clk: periph-clk { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <50000000>; @@ -32,11 +31,11 @@ }; aliases { - leds0 = &leds0; - uart0 = &uart0; + serial0 = &uart0; + serial1 = &uart1; }; - cpu_intc: cpu_intc { + cpu_intc: interrupt-controller { #address-cells = <0>; compatible = "mti,cpu-interrupt-controller"; @@ -64,16 +63,16 @@ mask = <0x1>; }; - periph_intc: periph_intc@10000020 { - compatible = "brcm,bcm3380-l2-intc"; - reg = <0x10000024 0x4 0x1000002c 0x4>, - <0x10000020 0x4 0x10000028 0x4>; + periph_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x10>, + <0x10000030 0x10>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&cpu_intc>; - interrupts = <2>; + interrupts = <2>, <3>; }; leds0: led-controller@100000d0 { @@ -93,7 +92,16 @@ status = "disabled"; }; - ehci0: usb@10001500 { + uart1: serial@10000120 { + compatible = "brcm,bcm6345-uart"; + reg = <0x10000120 0x18>; + interrupt-parent = <&periph_intc>; + interrupts = <3>; + clocks = <&periph_clk>; + status = "disabled"; + }; + + ehci: usb@10001500 { compatible = "brcm,bcm6368-ehci", "generic-ehci"; reg = <0x10001500 0x100>; big-endian; @@ -102,7 +110,7 @@ status = "disabled"; }; - ohci0: usb@10001600 { + ohci: usb@10001600 { compatible = "brcm,bcm6368-ohci", "generic-ohci"; reg = <0x10001600 0x100>; big-endian; diff --git a/arch/mips/boot/dts/brcm/bcm7125.dtsi b/arch/mips/boot/dts/brcm/bcm7125.dtsi index 3ae16053a0c9..550e1d9e3ee0 100644 --- a/arch/mips/boot/dts/brcm/bcm7125.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7125.dtsi @@ -85,14 +85,15 @@ compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; - brcm,int-map-mask = <0x44>; + brcm,int-map-mask = <0x44>, <0xf000000>; brcm,int-fwd-mask = <0x70000>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&periph_intc>; - interrupts = <18>; + interrupts = <18>, <19>; + interrupt-names = "upg_main", "upg_bsc"; }; sun_top_ctrl: syscon@404000 { @@ -118,6 +119,70 @@ status = "disabled"; }; + uart1: serial@406b40 { + compatible = "ns16550a"; + reg = <0x406b40 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + native-endian; + interrupt-parent = <&periph_intc>; + interrupts = <64>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + uart2: serial@406b80 { + compatible = "ns16550a"; + reg = <0x406b80 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + native-endian; + interrupt-parent = <&periph_intc>; + interrupts = <65>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + bsca: i2c@406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406200 0x58>; + interrupts = <24>; + interrupt-names = "upg_bsca"; + status = "disabled"; + }; + + bscb: i2c@406280 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406280 0x58>; + interrupts = <25>; + interrupt-names = "upg_bscb"; + status = "disabled"; + }; + + bscc: i2c@406300 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406300 0x58>; + interrupts = <26>; + interrupt-names = "upg_bscc"; + status = "disabled"; + }; + + bscd: i2c@406380 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406380 0x58>; + interrupts = <27>; + interrupt-names = "upg_bscd"; + status = "disabled"; + }; + ehci0: usb@488300 { compatible = "brcm,bcm7125-ehci", "generic-ehci"; reg = <0x488300 0x100>; diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi index be7991917d29..ec959061d52e 100644 --- a/arch/mips/boot/dts/brcm/bcm7346.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi @@ -24,8 +24,6 @@ aliases { uart0 = &uart0; - uart1 = &uart1; - uart2 = &uart2; }; cpu_intc: cpu_intc { @@ -323,8 +321,6 @@ interrupts = <40>; #address-cells = <1>; #size-cells = <0>; - brcm,broken-ncq; - brcm,broken-phy; status = "disabled"; sata0: sata-port@0 { @@ -338,7 +334,7 @@ }; }; - sata_phy: sata-phy@1800000 { + sata_phy: sata-phy@180100 { compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; reg = <0x180100 0x0eff>; reg-names = "phy"; diff --git a/arch/mips/boot/dts/brcm/bcm7358.dtsi b/arch/mips/boot/dts/brcm/bcm7358.dtsi index 060805be619a..ca57fb5eb122 100644 --- a/arch/mips/boot/dts/brcm/bcm7358.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7358.dtsi @@ -18,8 +18,6 @@ aliases { uart0 = &uart0; - uart1 = &uart1; - uart2 = &uart2; }; cpu_intc: cpu_intc { diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi index bcdb09bfe07b..1c0c3d438c7a 100644 --- a/arch/mips/boot/dts/brcm/bcm7360.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi @@ -18,8 +18,6 @@ aliases { uart0 = &uart0; - uart1 = &uart1; - uart2 = &uart2; }; cpu_intc: cpu_intc { @@ -241,5 +239,45 @@ interrupts = <66>; status = "disabled"; }; + + sata: sata@181000 { + compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; + reg-names = "ahci", "top-ctrl"; + reg = <0x181000 0xa9c>, <0x180020 0x1c>; + interrupt-parent = <&periph_intc>; + interrupts = <86>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + sata0: sata-port@0 { + reg = <0>; + phys = <&sata_phy0>; + }; + + sata1: sata-port@1 { + reg = <1>; + phys = <&sata_phy1>; + }; + }; + + sata_phy: sata-phy@180100 { + compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; + reg = <0x180100 0x0eff>; + reg-names = "phy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + sata_phy0: sata-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + sata_phy1: sata-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi index d3b1b762e6c3..6b4713add4b8 100644 --- a/arch/mips/boot/dts/brcm/bcm7362.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi @@ -24,8 +24,6 @@ aliases { uart0 = &uart0; - uart1 = &uart1; - uart2 = &uart2; }; cpu_intc: cpu_intc { @@ -246,8 +244,6 @@ interrupts = <86>; #address-cells = <1>; #size-cells = <0>; - brcm,broken-ncq; - brcm,broken-phy; status = "disabled"; sata0: sata-port@0 { @@ -261,7 +257,7 @@ }; }; - sata_phy: sata-phy@1800000 { + sata_phy: sata-phy@180100 { compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; reg = <0x180100 0x0eff>; reg-names = "phy"; diff --git a/arch/mips/boot/dts/brcm/bcm7420.dtsi b/arch/mips/boot/dts/brcm/bcm7420.dtsi index 3302a1b8a5c9..0586bf662571 100644 --- a/arch/mips/boot/dts/brcm/bcm7420.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7420.dtsi @@ -86,14 +86,15 @@ compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; - brcm,int-map-mask = <0x44>; + brcm,int-map-mask = <0x44>, <0x1f000000>; brcm,int-fwd-mask = <0x70000>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&periph_intc>; - interrupts = <18>; + interrupts = <18>, <19>; + interrupt-names = "upg_main", "upg_bsc"; }; sun_top_ctrl: syscon@404000 { @@ -118,6 +119,78 @@ status = "disabled"; }; + uart1: serial@406b40 { + compatible = "ns16550a"; + reg = <0x406b40 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <64>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + uart2: serial@406b80 { + compatible = "ns16550a"; + reg = <0x406b80 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <65>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + bsca: i2c@406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406200 0x58>; + interrupts = <24>; + interrupt-names = "upg_bsca"; + status = "disabled"; + }; + + bscb: i2c@406280 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406280 0x58>; + interrupts = <25>; + interrupt-names = "upg_bscb"; + status = "disabled"; + }; + + bscc: i2c@406300 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406300 0x58>; + interrupts = <26>; + interrupt-names = "upg_bscc"; + status = "disabled"; + }; + + bscd: i2c@406380 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406380 0x58>; + interrupts = <27>; + interrupt-names = "upg_bscd"; + status = "disabled"; + }; + + bsce: i2c@406800 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406800 0x58>; + interrupts = <28>; + interrupt-names = "upg_bsce"; + status = "disabled"; + }; + enet0: ethernet@468000 { phy-mode = "internal"; phy-handle = <&phy1>; diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi index 15b27aae15a9..c1c15edaf829 100644 --- a/arch/mips/boot/dts/brcm/bcm7425.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi @@ -87,14 +87,32 @@ compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; - brcm,int-map-mask = <0x44>; + brcm,int-map-mask = <0x44>, <0x7000000>; brcm,int-fwd-mask = <0x70000>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&periph_intc>; - interrupts = <55>; + interrupts = <55>, <53>; + interrupt-names = "upg_main", "upg_bsc"; + }; + + upg_aon_irq0_intc: upg_aon_irq0_intc@409480 { + compatible = "brcm,bcm7120-l2-intc"; + reg = <0x409480 0x8>; + + brcm,int-map-mask = <0x40>, <0x18000000>, <0x100000>; + brcm,int-fwd-mask = <0>; + brcm,irq-can-wake; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&periph_intc>; + interrupts = <56>, <54>, <59>; + interrupt-names = "upg_main_aon", "upg_bsc_aon", + "upg_spi"; }; sun_top_ctrl: syscon@404000 { @@ -119,6 +137,78 @@ status = "disabled"; }; + uart1: serial@406b40 { + compatible = "ns16550a"; + reg = <0x406b40 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <62>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + uart2: serial@406b80 { + compatible = "ns16550a"; + reg = <0x406b80 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <63>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + bsca: i2c@409180 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_aon_irq0_intc>; + reg = <0x409180 0x58>; + interrupts = <27>; + interrupt-names = "upg_bsca"; + status = "disabled"; + }; + + bscb: i2c@409400 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_aon_irq0_intc>; + reg = <0x409400 0x58>; + interrupts = <28>; + interrupt-names = "upg_bscb"; + status = "disabled"; + }; + + bscc: i2c@406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406200 0x58>; + interrupts = <24>; + interrupt-names = "upg_bscc"; + status = "disabled"; + }; + + bscd: i2c@406280 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406280 0x58>; + interrupts = <25>; + interrupt-names = "upg_bscd"; + status = "disabled"; + }; + + bsce: i2c@406300 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406300 0x58>; + interrupts = <26>; + interrupt-names = "upg_bsce"; + status = "disabled"; + }; + enet0: ethernet@b80000 { phy-mode = "internal"; phy-handle = <&phy1>; @@ -227,11 +317,9 @@ reg-names = "ahci", "top-ctrl"; reg = <0x181000 0xa9c>, <0x180020 0x1c>; interrupt-parent = <&periph_intc>; - interrupts = <40>; + interrupts = <41>; #address-cells = <1>; #size-cells = <0>; - brcm,broken-ncq; - brcm,broken-phy; status = "disabled"; sata0: sata-port@0 { @@ -245,7 +333,7 @@ }; }; - sata_phy: sata-phy@1800000 { + sata_phy: sata-phy@180100 { compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; reg = <0x180100 0x0eff>; reg-names = "phy"; diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi index 56035e5b7008..a874d3a0e2ee 100644 --- a/arch/mips/boot/dts/brcm/bcm7435.dtsi +++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi @@ -7,7 +7,7 @@ #address-cells = <1>; #size-cells = <0>; - mips-hpt-frequency = <163125000>; + mips-hpt-frequency = <175625000>; cpu@0 { compatible = "brcm,bmips5200"; @@ -63,13 +63,14 @@ periph_intc: periph_intc@41b500 { compatible = "brcm,bcm7038-l1-intc"; - reg = <0x41b500 0x40>, <0x41b600 0x40>; + reg = <0x41b500 0x40>, <0x41b600 0x40>, + <0x41b700 0x40>, <0x41b800 0x40>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&cpu_intc>; - interrupts = <2>, <3>; + interrupts = <2>, <3>, <2>, <3>; }; sun_l2_intc: sun_l2_intc@403000 { @@ -101,14 +102,32 @@ compatible = "brcm,bcm7120-l2-intc"; reg = <0x406780 0x8>; - brcm,int-map-mask = <0x44>; + brcm,int-map-mask = <0x44>, <0x7000000>; brcm,int-fwd-mask = <0x70000>; interrupt-controller; #interrupt-cells = <1>; interrupt-parent = <&periph_intc>; - interrupts = <60>; + interrupts = <60>, <58>; + interrupt-names = "upg_main", "upg_bsc"; + }; + + upg_aon_irq0_intc: upg_aon_irq0_intc@409480 { + compatible = "brcm,bcm7120-l2-intc"; + reg = <0x409480 0x8>; + + brcm,int-map-mask = <0x40>, <0x18000000>, <0x100000>; + brcm,int-fwd-mask = <0>; + brcm,irq-can-wake; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&periph_intc>; + interrupts = <61>, <59>, <64>; + interrupt-names = "upg_main_aon", "upg_bsc_aon", + "upg_spi"; }; sun_top_ctrl: syscon@404000 { @@ -133,6 +152,78 @@ status = "disabled"; }; + uart1: serial@406b40 { + compatible = "ns16550a"; + reg = <0x406b40 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <67>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + uart2: serial@406b80 { + compatible = "ns16550a"; + reg = <0x406b80 0x20>; + reg-io-width = <0x4>; + reg-shift = <0x2>; + interrupt-parent = <&periph_intc>; + interrupts = <68>; + clocks = <&uart_clk>; + status = "disabled"; + }; + + bsca: i2c@406300 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406300 0x58>; + interrupts = <26>; + interrupt-names = "upg_bsca"; + status = "disabled"; + }; + + bscb: i2c@409400 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_aon_irq0_intc>; + reg = <0x409400 0x58>; + interrupts = <28>; + interrupt-names = "upg_bscb"; + status = "disabled"; + }; + + bscc: i2c@406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406200 0x58>; + interrupts = <24>; + interrupt-names = "upg_bscc"; + status = "disabled"; + }; + + bscd: i2c@406280 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_irq0_intc>; + reg = <0x406280 0x58>; + interrupts = <25>; + interrupt-names = "upg_bscd"; + status = "disabled"; + }; + + bsce: i2c@409180 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&upg_aon_irq0_intc>; + reg = <0x409180 0x58>; + interrupts = <27>; + interrupt-names = "upg_bsce"; + status = "disabled"; + }; + enet0: ethernet@b80000 { phy-mode = "internal"; phy-handle = <&phy1>; @@ -235,5 +326,45 @@ interrupts = <78>; status = "disabled"; }; + + sata: sata@181000 { + compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci"; + reg-names = "ahci", "top-ctrl"; + reg = <0x181000 0xa9c>, <0x180020 0x1c>; + interrupt-parent = <&periph_intc>; + interrupts = <45>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + sata0: sata-port@0 { + reg = <0>; + phys = <&sata_phy0>; + }; + + sata1: sata-port@1 { + reg = <1>; + phys = <&sata_phy1>; + }; + }; + + sata_phy: sata-phy@180100 { + compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3"; + reg = <0x180100 0x0eff>; + reg-names = "phy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + sata_phy0: sata-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + sata_phy1: sata-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; }; }; diff --git a/arch/mips/boot/dts/brcm/bcm96358nb4ser.dts b/arch/mips/boot/dts/brcm/bcm96358nb4ser.dts new file mode 100644 index 000000000000..f412117972e6 --- /dev/null +++ b/arch/mips/boot/dts/brcm/bcm96358nb4ser.dts @@ -0,0 +1,46 @@ +/dts-v1/; + +/include/ "bcm6358.dtsi" + +/ { + compatible = "sfr,nb4-ser", "brcm,bcm6358"; + model = "SFR Neufbox 4 (Sercomm)"; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x02000000>; + }; + + chosen { + stdout-path = &uart0; + }; +}; + +&leds0 { + status = "ok"; + + led@0 { + reg = <0>; + active-low; + label = "nb4-ser:white:alarm"; + }; + led@2 { + reg = <2>; + active-low; + label = "nb4-ser:white:tv"; + }; + led@3 { + reg = <3>; + active-low; + label = "nb4-ser:white:tel"; + }; + led@4 { + reg = <4>; + active-low; + label = "nb4-ser:white:adsl"; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm96368mvwg.dts b/arch/mips/boot/dts/brcm/bcm96368mvwg.dts index 0e890c28fe5c..8c71c6845730 100644 --- a/arch/mips/boot/dts/brcm/bcm96368mvwg.dts +++ b/arch/mips/boot/dts/brcm/bcm96368mvwg.dts @@ -22,10 +22,10 @@ }; /* FIXME: need to set up USB_CTRL registers first */ -&ehci0 { +&ehci { status = "disabled"; }; -&ohci0 { +&ohci { status = "disabled"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97125cbmb.dts b/arch/mips/boot/dts/brcm/bcm97125cbmb.dts index e046b1109eab..f2449d147c6d 100644 --- a/arch/mips/boot/dts/brcm/bcm97125cbmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97125cbmb.dts @@ -21,6 +21,30 @@ status = "okay"; }; +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&bsca { + status = "okay"; +}; + +&bscb { + status = "okay"; +}; + +&bscc { + status = "okay"; +}; + +&bscd { + status = "okay"; +}; + /* FIXME: USB is wonky; disable it for now */ &ehci0 { status = "disabled"; diff --git a/arch/mips/boot/dts/brcm/bcm97360svmb.dts b/arch/mips/boot/dts/brcm/bcm97360svmb.dts index d48462e091f1..73124be9548a 100644 --- a/arch/mips/boot/dts/brcm/bcm97360svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97360svmb.dts @@ -56,3 +56,11 @@ &ohci0 { status = "okay"; }; + +&sata { + status = "okay"; +}; + +&sata_phy { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/brcm/bcm97420c.dts b/arch/mips/boot/dts/brcm/bcm97420c.dts index 67fe1f3a3891..600d57abee05 100644 --- a/arch/mips/boot/dts/brcm/bcm97420c.dts +++ b/arch/mips/boot/dts/brcm/bcm97420c.dts @@ -23,6 +23,34 @@ status = "okay"; }; +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&bsca { + status = "okay"; +}; + +&bscb { + status = "okay"; +}; + +&bscc { + status = "okay"; +}; + +&bscd { + status = "okay"; +}; + +&bsce { + status = "okay"; +}; + /* FIXME: MAC driver comes up but cannot attach to PHY */ &enet0 { status = "disabled"; diff --git a/arch/mips/boot/dts/brcm/bcm97425svmb.dts b/arch/mips/boot/dts/brcm/bcm97425svmb.dts index 689c68a4f9c8..119c714805cb 100644 --- a/arch/mips/boot/dts/brcm/bcm97425svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97425svmb.dts @@ -23,6 +23,34 @@ status = "okay"; }; +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&bsca { + status = "okay"; +}; + +&bscb { + status = "okay"; +}; + +&bscc { + status = "okay"; +}; + +&bscd { + status = "okay"; +}; + +&bsce { + status = "okay"; +}; + &enet0 { status = "okay"; }; diff --git a/arch/mips/boot/dts/brcm/bcm97435svmb.dts b/arch/mips/boot/dts/brcm/bcm97435svmb.dts index 1df088183523..43e3ba27f07b 100644 --- a/arch/mips/boot/dts/brcm/bcm97435svmb.dts +++ b/arch/mips/boot/dts/brcm/bcm97435svmb.dts @@ -14,7 +14,7 @@ }; chosen { - bootargs = "console=ttyS0,115200 maxcpus=1"; + bootargs = "console=ttyS0,115200"; stdout-path = &uart0; }; }; @@ -23,6 +23,34 @@ status = "okay"; }; +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&bsca { + status = "okay"; +}; + +&bscb { + status = "okay"; +}; + +&bscc { + status = "okay"; +}; + +&bscd { + status = "okay"; +}; + +&bsce { + status = "okay"; +}; + &enet0 { status = "okay"; }; @@ -58,3 +86,11 @@ &ohci3 { status = "okay"; }; + +&sata { + status = "okay"; +}; + +&sata_phy { + status = "okay"; +}; diff --git a/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts new file mode 100644 index 000000000000..d6bc994f736f --- /dev/null +++ b/arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts @@ -0,0 +1,78 @@ +/* + * Device tree source for D-Link DSR-1000N. + * + * Written by: Aaro Koskinen <aaro.koskinen@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/include/ "octeon_3xxx.dtsi" + +/ { + model = "dlink,dsr-1000n"; + + soc@0 { + smi0: mdio@1180000001800 { + phy8: ethernet-phy@8 { + reg = <8>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + }; + + pip: pip@11800a0000000 { + interface@0 { + ethernet@0 { + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + ethernet@1 { + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + ethernet@2 { + phy-handle = <&phy8>; + }; + }; + }; + + twsi0: i2c@1180000001000 { + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + }; + + uart0: serial@1180000000800 { + clock-frequency = <500000000>; + }; + + usbn: usbn@1180068000000 { + refclk-frequency = <12000000>; + refclk-type = "crystal"; + }; + }; + + leds { + compatible = "gpio-leds"; + + usb1 { + label = "usb1"; + gpios = <&gpio 9 1>; /* Active low */ + }; + + usb2 { + label = "usb2"; + gpios = <&gpio 10 1>; /* Active low */ + }; + }; + + aliases { + pip = &pip; + }; +}; diff --git a/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts b/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts index 9c48e0586ba7..de61f02d3ef6 100644 --- a/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts +++ b/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts @@ -1,4 +1,3 @@ -/dts-v1/; /* * OCTEON 3XXX, 5XXX, 63XX device tree skeleton. * @@ -6,56 +5,12 @@ * use. Because of this, it contains a super-set of the available * devices and properties. */ -/ { - compatible = "cavium,octeon-3860"; - #address-cells = <2>; - #size-cells = <2>; - interrupt-parent = <&ciu>; - - soc@0 { - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges; /* Direct mapping */ - - ciu: interrupt-controller@1070000000000 { - compatible = "cavium,octeon-3860-ciu"; - interrupt-controller; - /* Interrupts are specified by two parts: - * 1) Controller register (0 or 1) - * 2) Bit within the register (0..63) - */ - #interrupt-cells = <2>; - reg = <0x10700 0x00000000 0x0 0x7000>; - }; - gpio: gpio-controller@1070000000800 { - #gpio-cells = <2>; - compatible = "cavium,octeon-3860-gpio"; - reg = <0x10700 0x00000800 0x0 0x100>; - gpio-controller; - /* Interrupts are specified by two parts: - * 1) GPIO pin number (0..15) - * 2) Triggering (1 - edge rising - * 2 - edge falling - * 4 - level active high - * 8 - level active low) - */ - interrupt-controller; - #interrupt-cells = <2>; - /* The GPIO pin connect to 16 consecutive CUI bits */ - interrupts = <0 16>, <0 17>, <0 18>, <0 19>, - <0 20>, <0 21>, <0 22>, <0 23>, - <0 24>, <0 25>, <0 26>, <0 27>, - <0 28>, <0 29>, <0 30>, <0 31>; - }; +/include/ "octeon_3xxx.dtsi" +/ { + soc@0 { smi0: mdio@1180000001800 { - compatible = "cavium,octeon-3860-mdio"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x11800 0x00001800 0x0 0x40>; - phy0: ethernet-phy@0 { compatible = "marvell,88e1118"; marvell,reg-init = @@ -220,35 +175,16 @@ }; pip: pip@11800a0000000 { - compatible = "cavium,octeon-3860-pip"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x11800 0xa0000000 0x0 0x2000>; - interface@0 { - compatible = "cavium,octeon-3860-pip-interface"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; /* interface */ - ethernet@0 { - compatible = "cavium,octeon-3860-pip-port"; - reg = <0x0>; /* Port */ - local-mac-address = [ 00 00 00 00 00 00 ]; phy-handle = <&phy2>; cavium,alt-phy-handle = <&phy100>; }; ethernet@1 { - compatible = "cavium,octeon-3860-pip-port"; - reg = <0x1>; /* Port */ - local-mac-address = [ 00 00 00 00 00 00 ]; phy-handle = <&phy3>; cavium,alt-phy-handle = <&phy101>; }; ethernet@2 { - compatible = "cavium,octeon-3860-pip-port"; - reg = <0x2>; /* Port */ - local-mac-address = [ 00 00 00 00 00 00 ]; phy-handle = <&phy4>; cavium,alt-phy-handle = <&phy102>; }; @@ -322,11 +258,6 @@ }; interface@1 { - compatible = "cavium,octeon-3860-pip-interface"; - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; /* interface */ - ethernet@0 { compatible = "cavium,octeon-3860-pip-port"; reg = <0x0>; /* Port */ @@ -355,13 +286,6 @@ }; twsi0: i2c@1180000001000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "cavium,octeon-3860-twsi"; - reg = <0x11800 0x00001000 0x0 0x200>; - interrupts = <0 45>; - clock-frequency = <100000>; - rtc@68 { compatible = "dallas,ds1337"; reg = <0x68>; @@ -381,15 +305,6 @@ clock-frequency = <100000>; }; - uart0: serial@1180000000800 { - compatible = "cavium,octeon-3860-uart","ns16550"; - reg = <0x11800 0x00000800 0x0 0x400>; - clock-frequency = <0>; - current-speed = <115200>; - reg-shift = <3>; - interrupts = <0 34>; - }; - uart1: serial@1180000000c00 { compatible = "cavium,octeon-3860-uart","ns16550"; reg = <0x11800 0x00000c00 0x0 0x400>; @@ -409,98 +324,6 @@ }; bootbus: bootbus@1180000000000 { - compatible = "cavium,octeon-3860-bootbus"; - reg = <0x11800 0x00000000 0x0 0x200>; - /* The chip select number and offset */ - #address-cells = <2>; - /* The size of the chip select region */ - #size-cells = <1>; - ranges = <0 0 0x0 0x1f400000 0xc00000>, - <1 0 0x10000 0x30000000 0>, - <2 0 0x10000 0x40000000 0>, - <3 0 0x10000 0x50000000 0>, - <4 0 0x0 0x1d020000 0x10000>, - <5 0 0x0 0x1d040000 0x10000>, - <6 0 0x0 0x1d050000 0x10000>, - <7 0 0x10000 0x90000000 0>; - - cavium,cs-config@0 { - compatible = "cavium,octeon-3860-bootbus-config"; - cavium,cs-index = <0>; - cavium,t-adr = <20>; - cavium,t-ce = <60>; - cavium,t-oe = <60>; - cavium,t-we = <45>; - cavium,t-rd-hld = <35>; - cavium,t-wr-hld = <45>; - cavium,t-pause = <0>; - cavium,t-wait = <0>; - cavium,t-page = <35>; - cavium,t-rd-dly = <0>; - - cavium,pages = <0>; - cavium,bus-width = <8>; - }; - cavium,cs-config@4 { - compatible = "cavium,octeon-3860-bootbus-config"; - cavium,cs-index = <4>; - cavium,t-adr = <320>; - cavium,t-ce = <320>; - cavium,t-oe = <320>; - cavium,t-we = <320>; - cavium,t-rd-hld = <320>; - cavium,t-wr-hld = <320>; - cavium,t-pause = <320>; - cavium,t-wait = <320>; - cavium,t-page = <320>; - cavium,t-rd-dly = <0>; - - cavium,pages = <0>; - cavium,bus-width = <8>; - }; - cavium,cs-config@5 { - compatible = "cavium,octeon-3860-bootbus-config"; - cavium,cs-index = <5>; - cavium,t-adr = <5>; - cavium,t-ce = <300>; - cavium,t-oe = <125>; - cavium,t-we = <150>; - cavium,t-rd-hld = <100>; - cavium,t-wr-hld = <30>; - cavium,t-pause = <0>; - cavium,t-wait = <30>; - cavium,t-page = <320>; - cavium,t-rd-dly = <0>; - - cavium,pages = <0>; - cavium,bus-width = <16>; - }; - cavium,cs-config@6 { - compatible = "cavium,octeon-3860-bootbus-config"; - cavium,cs-index = <6>; - cavium,t-adr = <5>; - cavium,t-ce = <300>; - cavium,t-oe = <270>; - cavium,t-we = <150>; - cavium,t-rd-hld = <100>; - cavium,t-wr-hld = <70>; - cavium,t-pause = <0>; - cavium,t-wait = <0>; - cavium,t-page = <320>; - cavium,t-rd-dly = <0>; - - cavium,pages = <0>; - cavium,wait-mode; - cavium,bus-width = <16>; - }; - - flash0: nor@0,0 { - compatible = "cfi-flash"; - reg = <0 0 0x800000>; - #address-cells = <1>; - #size-cells = <1>; - }; - led0: led-display@4,0 { compatible = "avago,hdsp-253x"; reg = <4 0x20 0x20>, <4 0 0x20>; @@ -515,17 +338,6 @@ }; }; - dma0: dma-engine@1180000000100 { - compatible = "cavium,octeon-5750-bootbus-dma"; - reg = <0x11800 0x00000100 0x0 0x8>; - interrupts = <0 63>; - }; - dma1: dma-engine@1180000000108 { - compatible = "cavium,octeon-5750-bootbus-dma"; - reg = <0x11800 0x00000108 0x0 0x8>; - interrupts = <0 63>; - }; - uctl: uctl@118006f000000 { compatible = "cavium,octeon-6335-uctl"; reg = <0x11800 0x6f000000 0x0 0x100>; @@ -552,21 +364,10 @@ }; usbn: usbn@1180068000000 { - compatible = "cavium,octeon-5750-usbn"; - reg = <0x11800 0x68000000 0x0 0x1000>; - ranges; /* Direct mapping */ - #address-cells = <2>; - #size-cells = <2>; /* 12MHz, 24MHz and 48MHz allowed */ refclk-frequency = <12000000>; /* Either "crystal" or "external" */ refclk-type = "crystal"; - - usbc@16f0010000000 { - compatible = "cavium,octeon-5750-usbc"; - reg = <0x16f00 0x10000000 0x0 0x80000>; - interrupts = <0 56>; - }; }; }; diff --git a/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dtsi b/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dtsi new file mode 100644 index 000000000000..5302148e05a3 --- /dev/null +++ b/arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dtsi @@ -0,0 +1,231 @@ +/* OCTEON 3XXX DTS common parts. */ + +/dts-v1/; + +/ { + compatible = "cavium,octeon-3860"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&ciu>; + + soc@0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; /* Direct mapping */ + + ciu: interrupt-controller@1070000000000 { + compatible = "cavium,octeon-3860-ciu"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 1) + * 2) Bit within the register (0..63) + */ + #interrupt-cells = <2>; + reg = <0x10700 0x00000000 0x0 0x7000>; + }; + + gpio: gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pin connect to 16 consecutive CUI bits */ + interrupts = <0 16>, <0 17>, <0 18>, <0 19>, + <0 20>, <0 21>, <0 22>, <0 23>, + <0 24>, <0 25>, <0 26>, <0 27>, + <0 28>, <0 29>, <0 30>, <0 31>; + }; + + smi0: mdio@1180000001800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001800 0x0 0x40>; + }; + + pip: pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 00 00 00 00 00 ]; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; /* interface */ + }; + }; + + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <0 45>; + clock-frequency = <100000>; + }; + + uart0: serial@1180000000800 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000800 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <0 34>; + }; + + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0x0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0x0 0x1d020000 0x10000>, + <5 0 0x0 0x1d040000 0x10000>, + <6 0 0x0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <20>; + cavium,t-ce = <60>; + cavium,t-oe = <60>; + cavium,t-we = <45>; + cavium,t-rd-hld = <35>; + cavium,t-wr-hld = <45>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <35>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@4 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <4>; + cavium,t-adr = <320>; + cavium,t-ce = <320>; + cavium,t-oe = <320>; + cavium,t-we = <320>; + cavium,t-rd-hld = <320>; + cavium,t-wr-hld = <320>; + cavium,t-pause = <320>; + cavium,t-wait = <320>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + cavium,cs-config@5 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <5>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <125>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <30>; + cavium,t-pause = <0>; + cavium,t-wait = <30>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <16>; + }; + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <270>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <70>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + + flash0: nor@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; + + dma1: dma-engine@1180000000108 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000108 0x0 0x8>; + interrupts = <0 63>; + }; + + usbn: usbn@1180068000000 { + compatible = "cavium,octeon-5750-usbn"; + reg = <0x11800 0x68000000 0x0 0x1000>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + + usbc@16f0010000000 { + compatible = "cavium,octeon-5750-usbc"; + reg = <0x16f00 0x10000000 0x0 0x80000>; + interrupts = <0 56>; + }; + }; + }; +}; diff --git a/arch/mips/boot/dts/cavium-octeon/ubnt_e100.dts b/arch/mips/boot/dts/cavium-octeon/ubnt_e100.dts new file mode 100644 index 000000000000..243e5dc444fb --- /dev/null +++ b/arch/mips/boot/dts/cavium-octeon/ubnt_e100.dts @@ -0,0 +1,59 @@ +/* + * Device tree source for EdgeRouter Lite. + * + * Written by: Aaro Koskinen <aaro.koskinen@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/include/ "octeon_3xxx.dtsi" + +/ { + model = "ubnt,e100"; + + soc@0 { + smi0: mdio@1180000001800 { + phy5: ethernet-phy@5 { + reg = <5>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + phy6: ethernet-phy@6 { + reg = <6>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + phy7: ethernet-phy@7 { + reg = <7>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + }; + + pip: pip@11800a0000000 { + interface@0 { + ethernet@0 { + phy-handle = <&phy7>; + }; + ethernet@1 { + phy-handle = <&phy6>; + }; + ethernet@2 { + phy-handle = <&phy5>; + }; + }; + }; + + uart0: serial@1180000000800 { + clock-frequency = <500000000>; + }; + + usbn: usbn@1180068000000 { + refclk-frequency = <12000000>; + refclk-type = "crystal"; + }; + }; + + aliases { + pip = &pip; + }; +}; diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi index 8b2437cd019f..4a9c8f2a72d6 100644 --- a/arch/mips/boot/dts/ingenic/jz4740.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi @@ -65,4 +65,18 @@ clocks = <&ext>, <&cgu JZ4740_CLK_UART1>; clock-names = "baud", "module"; }; + + uhc: uhc@13030000 { + compatible = "ingenic,jz4740-ohci", "generic-ohci"; + reg = <0x13030000 0x1000>; + + clocks = <&cgu JZ4740_CLK_UHC>; + assigned-clocks = <&cgu JZ4740_CLK_UHC>; + assigned-clock-rates = <48000000>; + + interrupt-parent = <&intc>; + interrupts = <3>; + + status = "disabled"; + }; }; diff --git a/arch/mips/boot/dts/lantiq/easy50712.dts b/arch/mips/boot/dts/lantiq/easy50712.dts index 143b8a37b5e4..b59962585dde 100644 --- a/arch/mips/boot/dts/lantiq/easy50712.dts +++ b/arch/mips/boot/dts/lantiq/easy50712.dts @@ -52,7 +52,7 @@ }; gpio: pinmux@E100B10 { - compatible = "lantiq,pinctrl-xway"; + compatible = "lantiq,danube-pinctrl"; pinctrl-names = "default"; pinctrl-0 = <&state_default>; diff --git a/arch/mips/boot/dts/pic32/pic32mzda-clk.dtsi b/arch/mips/boot/dts/pic32/pic32mzda-clk.dtsi deleted file mode 100644 index ef1335012f43..000000000000 --- a/arch/mips/boot/dts/pic32/pic32mzda-clk.dtsi +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Device Tree Source for PIC32MZDA clock data - * - * Purna Chandra Mandal <purna.mandal@microchip.com> - * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. - * - * Licensed under GPLv2 or later. - */ - -/* all fixed rate clocks */ - -/ { - POSC:posc_clk { /* On-chip primary oscillator */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - }; - - FRC:frc_clk { /* internal FRC oscillator */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <8000000>; - }; - - BFRC:bfrc_clk { /* internal backup FRC oscillator */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <8000000>; - }; - - LPRC:lprc_clk { /* internal low-power FRC oscillator */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <32000>; - }; - - /* UPLL provides clock to USBCORE */ - UPLL:usb_phy_clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - clock-output-names = "usbphy_clk"; - }; - - TxCKI:txcki_clk { /* external clock input on TxCLKI pin */ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <4000000>; - status = "disabled"; - }; - - /* external clock input on REFCLKIx pin */ - REFIx:refix_clk { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - status = "disabled"; - }; - - /* PIC32 specific clks */ - pic32_clktree { - #address-cells = <1>; - #size-cells = <1>; - reg = <0x1f801200 0x200>; - compatible = "microchip,pic32mzda-clk"; - ranges = <0 0x1f801200 0x200>; - - /* secondary oscillator; external input on SOSCI pin */ - SOSC:sosc_clk@0 { - #clock-cells = <0>; - compatible = "microchip,pic32mzda-sosc"; - clock-frequency = <32768>; - reg = <0x000 0x10>, /* enable reg */ - <0x1d0 0x10>; /* status reg */ - microchip,bit-mask = <0x02>; /* enable mask */ - microchip,status-bit-mask = <0x10>; /* status-mask*/ - }; - - FRCDIV:frcdiv_clk { - #clock-cells = <0>; - compatible = "microchip,pic32mzda-frcdivclk"; - clocks = <&FRC>; - clock-output-names = "frcdiv_clk"; - }; - - /* System PLL clock */ - SYSPLL:spll_clk@020 { - #clock-cells = <0>; - compatible = "microchip,pic32mzda-syspll"; - reg = <0x020 0x10>, /* SPLL register */ - <0x1d0 0x10>; /* CLKSTAT register */ - clocks = <&POSC>, <&FRC>; - clock-output-names = "sys_pll"; - microchip,status-bit-mask = <0x80>; /* SPLLRDY */ - }; - - /* system clock; mux with postdiv & slew */ - SYSCLK:sys_clk@1c0 { - #clock-cells = <0>; - compatible = "microchip,pic32mzda-sysclk-v2"; - reg = <0x1c0 0x04>; /* SLEWCON */ - clocks = <&FRCDIV>, <&SYSPLL>, <&POSC>, <&SOSC>, - <&LPRC>, <&FRCDIV>; - microchip,clock-indices = <0>, <1>, <2>, <4>, - <5>, <7>; - clock-output-names = "sys_clk"; - }; - - /* Peripheral bus1 clock */ - PBCLK1:pb1_clk@140 { - reg = <0x140 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb1_clk"; - /* used by system modules, not gateable */ - microchip,ignore-unused; - }; - - /* Peripheral bus2 clock */ - PBCLK2:pb2_clk@150 { - reg = <0x150 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb2_clk"; - /* avoid gating even if unused */ - microchip,ignore-unused; - }; - - /* Peripheral bus3 clock */ - PBCLK3:pb3_clk@160 { - reg = <0x160 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb3_clk"; - }; - - /* Peripheral bus4 clock(I/O ports, GPIO) */ - PBCLK4:pb4_clk@170 { - reg = <0x170 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb4_clk"; - }; - - /* Peripheral bus clock */ - PBCLK5:pb5_clk@180 { - reg = <0x180 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - clock-output-names = "pb5_clk"; - }; - - /* Peripheral Bus6 clock; */ - PBCLK6:pb6_clk@190 { - reg = <0x190 0x10>; - compatible = "microchip,pic32mzda-pbclk"; - clocks = <&SYSCLK>; - #clock-cells = <0>; - }; - - /* Peripheral bus7 clock */ - PBCLK7:pb7_clk@1a0 { - reg = <0x1a0 0x10>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-pbclk"; - /* CPU is driven by this clock; so named */ - clock-output-names = "cpu_clk"; - clocks = <&SYSCLK>; - }; - - /* Reference Oscillator clock for SPI/I2S */ - REFCLKO1:refo1_clk@80 { - reg = <0x080 0x20>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>, <&PBCLK1>, <&POSC>, <&FRC>, <&LPRC>, - <&SOSC>, <&SYSPLL>, <&REFIx>, <&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - clock-output-names = "refo1_clk"; - }; - - /* Reference Oscillator clock for SQI */ - REFCLKO2:refo2_clk@a0 { - reg = <0x0a0 0x20>; - #clock-cells = <0>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>, <&PBCLK1>, <&POSC>, <&FRC>, <&LPRC>, - <&SOSC>, <&SYSPLL>, <&REFIx>, <&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - clock-output-names = "refo2_clk"; - }; - - /* Reference Oscillator clock, ADC */ - REFCLKO3:refo3_clk@c0 { - reg = <0x0c0 0x20>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>, <&PBCLK1>, <&POSC>, <&FRC>, <&LPRC>, - <&SOSC>, <&SYSPLL>, <&REFIx>, <&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - #clock-cells = <0>; - clock-output-names = "refo3_clk"; - }; - - /* Reference Oscillator clock */ - REFCLKO4:refo4_clk@e0 { - reg = <0x0e0 0x20>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>, <&PBCLK1>, <&POSC>, <&FRC>, <&LPRC>, - <&SOSC>, <&SYSPLL>, <&REFIx>, <&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - #clock-cells = <0>; - clock-output-names = "refo4_clk"; - }; - - /* Reference Oscillator clock, LCD */ - REFCLKO5:refo5_clk@100 { - reg = <0x100 0x20>; - compatible = "microchip,pic32mzda-refoclk"; - clocks = <&SYSCLK>,<&PBCLK1>,<&POSC>,<&FRC>,<&LPRC>, - <&SOSC>,<&SYSPLL>,<&REFIx>,<&BFRC>; - microchip,clock-indices = <0>, <1>, <2>, <3>, <4>, - <5>, <7>, <8>, <9>; - #clock-cells = <0>; - clock-output-names = "refo5_clk"; - }; - }; -}; diff --git a/arch/mips/boot/dts/pic32/pic32mzda.dtsi b/arch/mips/boot/dts/pic32/pic32mzda.dtsi index ad9e3318c2ce..5353a639c4fb 100644 --- a/arch/mips/boot/dts/pic32/pic32mzda.dtsi +++ b/arch/mips/boot/dts/pic32/pic32mzda.dtsi @@ -6,11 +6,9 @@ * published by the Free Software Foundation. * */ - +#include <dt-bindings/clock/microchip,pic32-clock.h> #include <dt-bindings/interrupt-controller/irq.h> -#include "pic32mzda-clk.dtsi" - / { #address-cells = <1>; #size-cells = <1>; @@ -50,6 +48,29 @@ interrupts = <0 IRQ_TYPE_EDGE_RISING>; }; + /* external clock input on TxCLKI pin */ + txcki: txcki_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <4000000>; + status = "disabled"; + }; + + /* external input on REFCLKIx pin */ + refix: refix_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + status = "disabled"; + }; + + rootclk: clock-controller@1f801200 { + compatible = "microchip,pic32mzda-clk"; + reg = <0x1f801200 0x200>; + #clock-cells = <1>; + microchip,pic32mzda-sosc; + }; + evic: interrupt-controller@1f810000 { compatible = "microchip,pic32mzda-evic"; interrupt-controller; @@ -63,7 +84,7 @@ #size-cells = <1>; compatible = "microchip,pic32mzda-pinctrl"; reg = <0x1f801400 0x400>; - clocks = <&PBCLK1>; + clocks = <&rootclk PB1CLK>; }; /* PORTA */ @@ -75,7 +96,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <0>; gpio-ranges = <&pic32_pinctrl 0 0 16>; }; @@ -89,7 +110,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <1>; gpio-ranges = <&pic32_pinctrl 0 16 16>; }; @@ -103,7 +124,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <2>; gpio-ranges = <&pic32_pinctrl 0 32 16>; }; @@ -117,7 +138,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <3>; gpio-ranges = <&pic32_pinctrl 0 48 16>; }; @@ -131,7 +152,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <4>; gpio-ranges = <&pic32_pinctrl 0 64 16>; }; @@ -145,7 +166,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <5>; gpio-ranges = <&pic32_pinctrl 0 80 16>; }; @@ -159,7 +180,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <6>; gpio-ranges = <&pic32_pinctrl 0 96 16>; }; @@ -173,7 +194,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <7>; gpio-ranges = <&pic32_pinctrl 0 112 16>; }; @@ -189,7 +210,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <8>; gpio-ranges = <&pic32_pinctrl 0 128 16>; }; @@ -203,7 +224,7 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - clocks = <&PBCLK4>; + clocks = <&rootclk PB4CLK>; microchip,gpio-bank = <9>; gpio-ranges = <&pic32_pinctrl 0 144 16>; }; @@ -212,7 +233,7 @@ compatible = "microchip,pic32mzda-sdhci"; reg = <0x1f8ec000 0x100>; interrupts = <191 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&REFCLKO4>, <&PBCLK5>; + clocks = <&rootclk REF4CLK>, <&rootclk PB5CLK>; clock-names = "base_clk", "sys_clk"; bus-width = <4>; cap-sd-highspeed; @@ -225,7 +246,7 @@ interrupts = <112 IRQ_TYPE_LEVEL_HIGH>, <113 IRQ_TYPE_LEVEL_HIGH>, <114 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -235,7 +256,7 @@ interrupts = <145 IRQ_TYPE_LEVEL_HIGH>, <146 IRQ_TYPE_LEVEL_HIGH>, <147 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -245,7 +266,7 @@ interrupts = <157 IRQ_TYPE_LEVEL_HIGH>, <158 IRQ_TYPE_LEVEL_HIGH>, <159 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -255,7 +276,7 @@ interrupts = <170 IRQ_TYPE_LEVEL_HIGH>, <171 IRQ_TYPE_LEVEL_HIGH>, <172 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -265,7 +286,7 @@ interrupts = <179 IRQ_TYPE_LEVEL_HIGH>, <180 IRQ_TYPE_LEVEL_HIGH>, <181 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; @@ -275,7 +296,7 @@ interrupts = <188 IRQ_TYPE_LEVEL_HIGH>, <189 IRQ_TYPE_LEVEL_HIGH>, <190 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&PBCLK2>; + clocks = <&rootclk PB2CLK>; status = "disabled"; }; }; diff --git a/arch/mips/boot/dts/pic32/pic32mzda_sk.dts b/arch/mips/boot/dts/pic32/pic32mzda_sk.dts index 5d434a50e85b..fc740102852e 100644 --- a/arch/mips/boot/dts/pic32/pic32mzda_sk.dts +++ b/arch/mips/boot/dts/pic32/pic32mzda_sk.dts @@ -95,8 +95,9 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdhc1>; status = "okay"; - assigned-clocks = <&REFCLKO2>,<&REFCLKO4>,<&REFCLKO5>; - assigned-clock-rates = <50000000>,<25000000>,<40000000>; + assigned-clocks = <&rootclk REF2CLK>, <&rootclk REF4CLK>, + <&rootclk REF5CLK>; + assigned-clock-rates = <50000000>, <25000000>, <40000000>; }; &pic32_pinctrl { diff --git a/arch/mips/boot/dts/qca/Makefile b/arch/mips/boot/dts/qca/Makefile index 2d61455d585d..63a9ddf048c9 100644 --- a/arch/mips/boot/dts/qca/Makefile +++ b/arch/mips/boot/dts/qca/Makefile @@ -1,8 +1,9 @@ # All DTBs dtb-$(CONFIG_ATH79) += ar9132_tl_wr1043nd_v1.dtb - -# Select a DTB to build in the kernel -obj-$(CONFIG_DTB_TL_WR1043ND_V1) += ar9132_tl_wr1043nd_v1.dtb.o +dtb-$(CONFIG_ATH79) += ar9331_dpt_module.dtb +dtb-$(CONFIG_ATH79) += ar9331_dragino_ms14.dtb +dtb-$(CONFIG_ATH79) += ar9331_omega.dtb +dtb-$(CONFIG_ATH79) += ar9331_tl_mr3020.dtb # Force kbuild to make empty built-in.o if necessary obj- += dummy.o diff --git a/arch/mips/boot/dts/qca/ar9132.dtsi b/arch/mips/boot/dts/qca/ar9132.dtsi index 3c2ed9ee5b2f..302f0a8d2988 100644 --- a/arch/mips/boot/dts/qca/ar9132.dtsi +++ b/arch/mips/boot/dts/qca/ar9132.dtsi @@ -1,3 +1,5 @@ +#include <dt-bindings/clock/ath79-clk.h> + / { compatible = "qca,ar9132"; @@ -11,6 +13,7 @@ cpu@0 { device_type = "cpu"; compatible = "mips,mips24Kc"; + clocks = <&pll ATH79_CLK_CPU>; reg = <0>; }; }; @@ -52,12 +55,12 @@ #qca,ddr-wb-channel-cells = <1>; }; - uart@18020000 { + uart: uart@18020000 { compatible = "ns8250"; reg = <0x18020000 0x20>; interrupts = <3>; - clocks = <&pll 2>; + clocks = <&pll ATH79_CLK_AHB>; clock-names = "uart"; reg-io-width = <4>; @@ -94,13 +97,13 @@ clock-output-names = "cpu", "ddr", "ahb"; }; - wdt@18060008 { + wdt: wdt@18060008 { compatible = "qca,ar7130-wdt"; reg = <0x18060008 0x8>; interrupts = <4>; - clocks = <&pll 2>; + clocks = <&pll ATH79_CLK_AHB>; clock-names = "wdt"; }; @@ -125,7 +128,7 @@ }; }; - usb@1b000100 { + usb: usb@1b000100 { compatible = "qca,ar7100-ehci", "generic-ehci"; reg = <0x1b000100 0x100>; @@ -140,11 +143,11 @@ status = "disabled"; }; - spi@1f000000 { + spi: spi@1f000000 { compatible = "qca,ar9132-spi", "qca,ar7100-spi"; reg = <0x1f000000 0x10>; - clocks = <&pll 2>; + clocks = <&pll ATH79_CLK_AHB>; clock-names = "ahb"; status = "disabled"; diff --git a/arch/mips/boot/dts/qca/ar9132_tl_wr1043nd_v1.dts b/arch/mips/boot/dts/qca/ar9132_tl_wr1043nd_v1.dts index 4f1540e5f963..3c3b7ce5737b 100644 --- a/arch/mips/boot/dts/qca/ar9132_tl_wr1043nd_v1.dts +++ b/arch/mips/boot/dts/qca/ar9132_tl_wr1043nd_v1.dts @@ -9,10 +9,6 @@ compatible = "tplink,tl-wr1043nd-v1", "qca,ar9132"; model = "TP-Link TL-WR1043ND Version 1"; - alias { - serial0 = "/ahb/apb/uart@18020000"; - }; - memory@0 { device_type = "memory"; reg = <0x0 0x2000000>; @@ -24,55 +20,6 @@ clock-frequency = <40000000>; }; - ahb { - apb { - uart@18020000 { - status = "okay"; - }; - - pll-controller@18050000 { - clocks = <&extosc>; - }; - }; - - usb@1b000100 { - status = "okay"; - }; - - spi@1f000000 { - status = "okay"; - num-cs = <1>; - - flash@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "s25sl064a"; - reg = <0>; - spi-max-frequency = <25000000>; - - partition@0 { - label = "u-boot"; - reg = <0x000000 0x020000>; - }; - - partition@1 { - label = "firmware"; - reg = <0x020000 0x7D0000>; - }; - - partition@2 { - label = "art"; - reg = <0x7F0000 0x010000>; - read-only; - }; - }; - }; - }; - - usb-phy { - status = "okay"; - }; - gpio-keys { compatible = "gpio-keys-polled"; #address-cells = <1>; @@ -118,3 +65,48 @@ }; }; }; + +&uart { + status = "okay"; +}; + +&pll { + clocks = <&extosc>; +}; + +&usb { + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + status = "okay"; + num-cs = <1>; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "s25sl064a"; + reg = <0>; + spi-max-frequency = <25000000>; + + partition@0 { + label = "u-boot"; + reg = <0x000000 0x020000>; + }; + + partition@1 { + label = "firmware"; + reg = <0x020000 0x7D0000>; + }; + + partition@2 { + label = "art"; + reg = <0x7F0000 0x010000>; + read-only; + }; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331.dtsi b/arch/mips/boot/dts/qca/ar9331.dtsi new file mode 100644 index 000000000000..cf47ed4d8569 --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331.dtsi @@ -0,0 +1,155 @@ +#include <dt-bindings/clock/ath79-clk.h> + +/ { + compatible = "qca,ar9331"; + + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "mips,mips24Kc"; + clocks = <&pll ATH79_CLK_CPU>; + reg = <0>; + }; + }; + + cpuintc: interrupt-controller { + compatible = "qca,ar7100-cpu-intc"; + + interrupt-controller; + #interrupt-cells = <1>; + + qca,ddr-wb-channel-interrupts = <2>, <3>; + qca,ddr-wb-channels = <&ddr_ctrl 3>, <&ddr_ctrl 2>; + }; + + ref: ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + ahb { + compatible = "simple-bus"; + ranges; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&cpuintc>; + + apb { + compatible = "simple-bus"; + ranges; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-parent = <&miscintc>; + + ddr_ctrl: memory-controller@18000000 { + compatible = "qca,ar7240-ddr-controller"; + reg = <0x18000000 0x100>; + + #qca,ddr-wb-channel-cells = <1>; + }; + + uart: uart@18020000 { + compatible = "qca,ar9330-uart"; + reg = <0x18020000 0x14>; + + interrupts = <3>; + + clocks = <&ref>; + clock-names = "uart"; + + status = "disabled"; + }; + + gpio: gpio@18040000 { + compatible = "qca,ar7100-gpio"; + reg = <0x18040000 0x34>; + interrupts = <2>; + + ngpios = <30>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + status = "disabled"; + }; + + pll: pll-controller@18050000 { + compatible = "qca,ar9330-pll"; + reg = <0x18050000 0x100>; + + clocks = <&ref>; + clock-names = "ref"; + + #clock-cells = <1>; + }; + + miscintc: interrupt-controller@18060010 { + compatible = "qca,ar7240-misc-intc"; + reg = <0x18060010 0x4>; + + interrupt-parent = <&cpuintc>; + interrupts = <6>; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + rst: reset-controller@1806001c { + compatible = "qca,ar7100-reset"; + reg = <0x1806001c 0x4>; + + #reset-cells = <1>; + }; + }; + + usb: usb@1b000100 { + compatible = "chipidea,usb2"; + reg = <0x1b000000 0x200>; + + interrupts = <3>; + resets = <&rst 5>; + + phy-names = "usb-phy"; + phys = <&usb_phy>; + + status = "disabled"; + }; + + spi: spi@1f000000 { + compatible = "qca,ar7100-spi"; + reg = <0x1f000000 0x10>; + + clocks = <&pll ATH79_CLK_AHB>; + clock-names = "ahb"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + usb_phy: usb-phy { + compatible = "qca,ar7100-usb-phy"; + + reset-names = "usb-phy", "usb-suspend-override"; + resets = <&rst 4>, <&rst 3>; + + #phy-cells = <0>; + + status = "disabled"; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331_dpt_module.dts b/arch/mips/boot/dts/qca/ar9331_dpt_module.dts new file mode 100644 index 000000000000..98e74500e79d --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331_dpt_module.dts @@ -0,0 +1,78 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +#include "ar9331.dtsi" + +/ { + model = "DPTechnics DPT-Module"; + compatible = "dptechnics,dpt-module"; + + aliases { + serial0 = &uart; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + leds { + compatible = "gpio-leds"; + + system { + label = "dpt-module:green:system"; + gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "reset"; + linux,code = <KEY_RESTART>; + gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + num-chipselects = <1>; + status = "okay"; + + /* Winbond 25Q128FVSG SPI flash */ + spiflash: w25q128@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "winbond,w25q128", "jedec,spi-nor"; + spi-max-frequency = <104000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331_dragino_ms14.dts b/arch/mips/boot/dts/qca/ar9331_dragino_ms14.dts new file mode 100644 index 000000000000..56f832076a69 --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331_dragino_ms14.dts @@ -0,0 +1,102 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +#include "ar9331.dtsi" + +/ { + model = "Dragino MS14 (Dragino 2)"; + compatible = "dragino,ms14"; + + aliases { + serial0 = &uart; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + leds { + compatible = "gpio-leds"; + + wlan { + label = "dragino2:red:wlan"; + gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + lan { + label = "dragino2:red:lan"; + gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + wan { + label = "dragino2:red:wan"; + gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + system { + label = "dragino2:red:system"; + gpios = <&gpio 28 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "jumpstart"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + }; + + button@1 { + label = "reset"; + linux,code = <KEY_RESTART>; + gpios = <&gpio 12 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + num-chipselects = <1>; + status = "okay"; + + /* Winbond 25Q128BVFG SPI flash */ + spiflash: w25q128@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "winbond,w25q128", "jedec,spi-nor"; + spi-max-frequency = <104000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331_omega.dts b/arch/mips/boot/dts/qca/ar9331_omega.dts new file mode 100644 index 000000000000..b2be3b04479d --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331_omega.dts @@ -0,0 +1,78 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +#include "ar9331.dtsi" + +/ { + model = "Onion Omega"; + compatible = "onion,omega"; + + aliases { + serial0 = &uart; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x4000000>; + }; + + leds { + compatible = "gpio-leds"; + + system { + label = "onion:amber:system"; + gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "reset"; + linux,code = <KEY_RESTART>; + gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + num-chipselects = <1>; + status = "okay"; + + /* Winbond 25Q128FVSG SPI flash */ + spiflash: w25q128@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "winbond,w25q128", "jedec,spi-nor"; + spi-max-frequency = <104000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/boot/dts/qca/ar9331_tl_mr3020.dts b/arch/mips/boot/dts/qca/ar9331_tl_mr3020.dts new file mode 100644 index 000000000000..919cf3b854a5 --- /dev/null +++ b/arch/mips/boot/dts/qca/ar9331_tl_mr3020.dts @@ -0,0 +1,118 @@ +/dts-v1/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +#include "ar9331.dtsi" + +/ { + model = "TP-Link TL-MR3020"; + compatible = "tplink,tl-mr3020"; + + aliases { + serial0 = &uart; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x2000000>; + }; + + leds { + compatible = "gpio-leds"; + + wlan { + label = "tp-link:green:wlan"; + gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + lan { + label = "tp-link:green:lan"; + gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + wps { + label = "tp-link:green:wps"; + gpios = <&gpio 26 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led3g { + label = "tp-link:green:3g"; + gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + button@0 { + label = "wps"; + linux,code = <KEY_WPS_BUTTON>; + gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; + }; + + button@1 { + label = "sw1"; + linux,code = <BTN_0>; + gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; + }; + + button@2 { + label = "sw2"; + linux,code = <BTN_1>; + gpios = <&gpio 20 GPIO_ACTIVE_HIGH>; + }; + }; + + reg_usb_vbus: reg_usb_vbus { + compatible = "regulator-fixed"; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio 8 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&ref { + clock-frequency = <25000000>; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&usb { + dr_mode = "host"; + vbus-supply = <®_usb_vbus>; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&spi { + num-chipselects = <1>; + status = "okay"; + + /* Spansion S25FL032PIF SPI flash */ + spiflash: s25sl032p@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25sl032p", "jedec,spi-nor"; + spi-max-frequency = <104000000>; + reg = <0>; + }; +}; diff --git a/arch/mips/boot/tools/.gitignore b/arch/mips/boot/tools/.gitignore new file mode 100644 index 000000000000..be0ed065249b --- /dev/null +++ b/arch/mips/boot/tools/.gitignore @@ -0,0 +1 @@ +relocs diff --git a/arch/mips/boot/tools/Makefile b/arch/mips/boot/tools/Makefile new file mode 100644 index 000000000000..d232a68f6c8a --- /dev/null +++ b/arch/mips/boot/tools/Makefile @@ -0,0 +1,8 @@ + +hostprogs-y += relocs +relocs-objs += relocs_32.o +relocs-objs += relocs_64.o +relocs-objs += relocs_main.o +PHONY += relocs +relocs: $(obj)/relocs + @: diff --git a/arch/mips/boot/tools/relocs.c b/arch/mips/boot/tools/relocs.c new file mode 100644 index 000000000000..b9cbf78527e8 --- /dev/null +++ b/arch/mips/boot/tools/relocs.c @@ -0,0 +1,680 @@ +/* This is included from relocs_32/64.c */ + +#define ElfW(type) _ElfW(ELF_BITS, type) +#define _ElfW(bits, type) __ElfW(bits, type) +#define __ElfW(bits, type) Elf##bits##_##type + +#define Elf_Addr ElfW(Addr) +#define Elf_Ehdr ElfW(Ehdr) +#define Elf_Phdr ElfW(Phdr) +#define Elf_Shdr ElfW(Shdr) +#define Elf_Sym ElfW(Sym) + +static Elf_Ehdr ehdr; + +struct relocs { + uint32_t *offset; + unsigned long count; + unsigned long size; +}; + +static struct relocs relocs; + +struct section { + Elf_Shdr shdr; + struct section *link; + Elf_Sym *symtab; + Elf_Rel *reltab; + char *strtab; + long shdr_offset; +}; +static struct section *secs; + +static const char * const regex_sym_kernel = { +/* Symbols matching these regex's should never be relocated */ + "^(__crc_)", +}; + +static regex_t sym_regex_c; + +static int regex_skip_reloc(const char *sym_name) +{ + return !regexec(&sym_regex_c, sym_name, 0, NULL, 0); +} + +static void regex_init(void) +{ + char errbuf[128]; + int err; + + err = regcomp(&sym_regex_c, regex_sym_kernel, + REG_EXTENDED|REG_NOSUB); + + if (err) { + regerror(err, &sym_regex_c, errbuf, sizeof(errbuf)); + die("%s", errbuf); + } +} + +static const char *rel_type(unsigned type) +{ + static const char * const type_name[] = { +#define REL_TYPE(X)[X] = #X + REL_TYPE(R_MIPS_NONE), + REL_TYPE(R_MIPS_16), + REL_TYPE(R_MIPS_32), + REL_TYPE(R_MIPS_REL32), + REL_TYPE(R_MIPS_26), + REL_TYPE(R_MIPS_HI16), + REL_TYPE(R_MIPS_LO16), + REL_TYPE(R_MIPS_GPREL16), + REL_TYPE(R_MIPS_LITERAL), + REL_TYPE(R_MIPS_GOT16), + REL_TYPE(R_MIPS_PC16), + REL_TYPE(R_MIPS_CALL16), + REL_TYPE(R_MIPS_GPREL32), + REL_TYPE(R_MIPS_64), + REL_TYPE(R_MIPS_HIGHER), + REL_TYPE(R_MIPS_HIGHEST), + REL_TYPE(R_MIPS_PC21_S2), + REL_TYPE(R_MIPS_PC26_S2), +#undef REL_TYPE + }; + const char *name = "unknown type rel type name"; + + if (type < ARRAY_SIZE(type_name) && type_name[type]) + name = type_name[type]; + return name; +} + +static const char *sec_name(unsigned shndx) +{ + const char *sec_strtab; + const char *name; + + sec_strtab = secs[ehdr.e_shstrndx].strtab; + if (shndx < ehdr.e_shnum) + name = sec_strtab + secs[shndx].shdr.sh_name; + else if (shndx == SHN_ABS) + name = "ABSOLUTE"; + else if (shndx == SHN_COMMON) + name = "COMMON"; + else + name = "<noname>"; + return name; +} + +static struct section *sec_lookup(const char *secname) +{ + int i; + + for (i = 0; i < ehdr.e_shnum; i++) + if (strcmp(secname, sec_name(i)) == 0) + return &secs[i]; + + return NULL; +} + +static const char *sym_name(const char *sym_strtab, Elf_Sym *sym) +{ + const char *name; + + if (sym->st_name) + name = sym_strtab + sym->st_name; + else + name = sec_name(sym->st_shndx); + return name; +} + +#if BYTE_ORDER == LITTLE_ENDIAN +#define le16_to_cpu(val) (val) +#define le32_to_cpu(val) (val) +#define le64_to_cpu(val) (val) +#define be16_to_cpu(val) bswap_16(val) +#define be32_to_cpu(val) bswap_32(val) +#define be64_to_cpu(val) bswap_64(val) + +#define cpu_to_le16(val) (val) +#define cpu_to_le32(val) (val) +#define cpu_to_le64(val) (val) +#define cpu_to_be16(val) bswap_16(val) +#define cpu_to_be32(val) bswap_32(val) +#define cpu_to_be64(val) bswap_64(val) +#endif +#if BYTE_ORDER == BIG_ENDIAN +#define le16_to_cpu(val) bswap_16(val) +#define le32_to_cpu(val) bswap_32(val) +#define le64_to_cpu(val) bswap_64(val) +#define be16_to_cpu(val) (val) +#define be32_to_cpu(val) (val) +#define be64_to_cpu(val) (val) + +#define cpu_to_le16(val) bswap_16(val) +#define cpu_to_le32(val) bswap_32(val) +#define cpu_to_le64(val) bswap_64(val) +#define cpu_to_be16(val) (val) +#define cpu_to_be32(val) (val) +#define cpu_to_be64(val) (val) +#endif + +static uint16_t elf16_to_cpu(uint16_t val) +{ + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + return le16_to_cpu(val); + else + return be16_to_cpu(val); +} + +static uint32_t elf32_to_cpu(uint32_t val) +{ + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + return le32_to_cpu(val); + else + return be32_to_cpu(val); +} + +static uint32_t cpu_to_elf32(uint32_t val) +{ + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + return cpu_to_le32(val); + else + return cpu_to_be32(val); +} + +#define elf_half_to_cpu(x) elf16_to_cpu(x) +#define elf_word_to_cpu(x) elf32_to_cpu(x) + +#if ELF_BITS == 64 +static uint64_t elf64_to_cpu(uint64_t val) +{ + if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + return le64_to_cpu(val); + else + return be64_to_cpu(val); +} +#define elf_addr_to_cpu(x) elf64_to_cpu(x) +#define elf_off_to_cpu(x) elf64_to_cpu(x) +#define elf_xword_to_cpu(x) elf64_to_cpu(x) +#else +#define elf_addr_to_cpu(x) elf32_to_cpu(x) +#define elf_off_to_cpu(x) elf32_to_cpu(x) +#define elf_xword_to_cpu(x) elf32_to_cpu(x) +#endif + +static void read_ehdr(FILE *fp) +{ + if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) + die("Cannot read ELF header: %s\n", strerror(errno)); + + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) + die("No ELF magic\n"); + + if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) + die("Not a %d bit executable\n", ELF_BITS); + + if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) && + (ehdr.e_ident[EI_DATA] != ELFDATA2MSB)) + die("Unknown ELF Endianness\n"); + + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) + die("Unknown ELF version\n"); + + /* Convert the fields to native endian */ + ehdr.e_type = elf_half_to_cpu(ehdr.e_type); + ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine); + ehdr.e_version = elf_word_to_cpu(ehdr.e_version); + ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry); + ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff); + ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff); + ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags); + ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize); + ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize); + ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum); + ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize); + ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum); + ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx); + + if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) + die("Unsupported ELF header type\n"); + + if (ehdr.e_machine != ELF_MACHINE) + die("Not for %s\n", ELF_MACHINE_NAME); + + if (ehdr.e_version != EV_CURRENT) + die("Unknown ELF version\n"); + + if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) + die("Bad Elf header size\n"); + + if (ehdr.e_phentsize != sizeof(Elf_Phdr)) + die("Bad program header entry\n"); + + if (ehdr.e_shentsize != sizeof(Elf_Shdr)) + die("Bad section header entry\n"); + + if (ehdr.e_shstrndx >= ehdr.e_shnum) + die("String table index out of bounds\n"); +} + +static void read_shdrs(FILE *fp) +{ + int i; + Elf_Shdr shdr; + + secs = calloc(ehdr.e_shnum, sizeof(struct section)); + if (!secs) + die("Unable to allocate %d section headers\n", ehdr.e_shnum); + + if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", ehdr.e_shoff, strerror(errno)); + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + + sec->shdr_offset = ftell(fp); + if (fread(&shdr, sizeof(shdr), 1, fp) != 1) + die("Cannot read ELF section headers %d/%d: %s\n", + i, ehdr.e_shnum, strerror(errno)); + sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name); + sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type); + sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags); + sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr); + sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset); + sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size); + sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link); + sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info); + sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign); + sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize); + if (sec->shdr.sh_link < ehdr.e_shnum) + sec->link = &secs[sec->shdr.sh_link]; + } +} + +static void read_strtabs(FILE *fp) +{ + int i; + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_STRTAB) + continue; + + sec->strtab = malloc(sec->shdr.sh_size); + if (!sec->strtab) + die("malloc of %d bytes for strtab failed\n", + sec->shdr.sh_size); + + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + + if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) != + sec->shdr.sh_size) + die("Cannot read symbol table: %s\n", strerror(errno)); + } +} + +static void read_symtabs(FILE *fp) +{ + int i, j; + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + if (sec->shdr.sh_type != SHT_SYMTAB) + continue; + + sec->symtab = malloc(sec->shdr.sh_size); + if (!sec->symtab) + die("malloc of %d bytes for symtab failed\n", + sec->shdr.sh_size); + + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + + if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) != + sec->shdr.sh_size) + die("Cannot read symbol table: %s\n", strerror(errno)); + + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) { + Elf_Sym *sym = &sec->symtab[j]; + + sym->st_name = elf_word_to_cpu(sym->st_name); + sym->st_value = elf_addr_to_cpu(sym->st_value); + sym->st_size = elf_xword_to_cpu(sym->st_size); + sym->st_shndx = elf_half_to_cpu(sym->st_shndx); + } + } +} + +static void read_relocs(FILE *fp) +{ + static unsigned long base = 0; + int i, j; + + if (!base) { + struct section *sec = sec_lookup(".text"); + + if (!sec) + die("Could not find .text section\n"); + + base = sec->shdr.sh_addr; + } + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_REL_TYPE) + continue; + + sec->reltab = malloc(sec->shdr.sh_size); + if (!sec->reltab) + die("malloc of %d bytes for relocs failed\n", + sec->shdr.sh_size); + + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + + if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) != + sec->shdr.sh_size) + die("Cannot read symbol table: %s\n", strerror(errno)); + + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { + Elf_Rel *rel = &sec->reltab[j]; + + rel->r_offset = elf_addr_to_cpu(rel->r_offset); + /* Set offset into kernel image */ + rel->r_offset -= base; +#if (ELF_BITS == 32) + rel->r_info = elf_xword_to_cpu(rel->r_info); +#else + /* Convert MIPS64 RELA format - only the symbol + * index needs converting to native endianness + */ + rel->r_info = rel->r_info; + ELF_R_SYM(rel->r_info) = elf32_to_cpu(ELF_R_SYM(rel->r_info)); +#endif +#if (SHT_REL_TYPE == SHT_RELA) + rel->r_addend = elf_xword_to_cpu(rel->r_addend); +#endif + } + } +} + +static void remove_relocs(FILE *fp) +{ + int i; + Elf_Shdr shdr; + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_REL_TYPE) + continue; + + if (fseek(fp, sec->shdr_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr_offset, strerror(errno)); + + if (fread(&shdr, sizeof(shdr), 1, fp) != 1) + die("Cannot read ELF section headers %d/%d: %s\n", + i, ehdr.e_shnum, strerror(errno)); + + /* Set relocation section size to 0, effectively removing it. + * This is necessary due to lack of support for relocations + * in objcopy when creating 32bit elf from 64bit elf. + */ + shdr.sh_size = 0; + + if (fseek(fp, sec->shdr_offset, SEEK_SET) < 0) + die("Seek to %d failed: %s\n", + sec->shdr_offset, strerror(errno)); + + if (fwrite(&shdr, sizeof(shdr), 1, fp) != 1) + die("Cannot write ELF section headers %d/%d: %s\n", + i, ehdr.e_shnum, strerror(errno)); + } +} + +static void add_reloc(struct relocs *r, uint32_t offset, unsigned type) +{ + /* Relocation representation in binary table: + * |76543210|76543210|76543210|76543210| + * | Type | offset from _text >> 2 | + */ + offset >>= 2; + if (offset > 0x00FFFFFF) + die("Kernel image exceeds maximum size for relocation!\n"); + + offset = (offset & 0x00FFFFFF) | ((type & 0xFF) << 24); + + if (r->count == r->size) { + unsigned long newsize = r->size + 50000; + void *mem = realloc(r->offset, newsize * sizeof(r->offset[0])); + + if (!mem) + die("realloc failed\n"); + + r->offset = mem; + r->size = newsize; + } + r->offset[r->count++] = offset; +} + +static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel, + Elf_Sym *sym, const char *symname)) +{ + int i; + + /* Walk through the relocations */ + for (i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf_Sym *sh_symtab; + struct section *sec_applies, *sec_symtab; + int j; + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_REL_TYPE) + continue; + + sec_symtab = sec->link; + sec_applies = &secs[sec->shdr.sh_info]; + if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) + continue; + + sh_symtab = sec_symtab->symtab; + sym_strtab = sec_symtab->link->strtab; + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { + Elf_Rel *rel = &sec->reltab[j]; + Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)]; + const char *symname = sym_name(sym_strtab, sym); + + process(sec, rel, sym, symname); + } + } +} + +static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym, + const char *symname) +{ + unsigned r_type = ELF_R_TYPE(rel->r_info); + unsigned bind = ELF_ST_BIND(sym->st_info); + + if ((bind == STB_WEAK) && (sym->st_value == 0)) { + /* Don't relocate weak symbols without a target */ + return 0; + } + + if (regex_skip_reloc(symname)) + return 0; + + switch (r_type) { + case R_MIPS_NONE: + case R_MIPS_REL32: + case R_MIPS_PC16: + case R_MIPS_PC21_S2: + case R_MIPS_PC26_S2: + /* + * NONE can be ignored and PC relative relocations don't + * need to be adjusted. + */ + case R_MIPS_HIGHEST: + case R_MIPS_HIGHER: + /* We support relocating within the same 4Gb segment only, + * thus leaving the top 32bits unchanged + */ + case R_MIPS_LO16: + /* We support relocating by 64k jumps only + * thus leaving the bottom 16bits unchanged + */ + break; + + case R_MIPS_64: + case R_MIPS_32: + case R_MIPS_26: + case R_MIPS_HI16: + add_reloc(&relocs, rel->r_offset, r_type); + break; + + default: + die("Unsupported relocation type: %s (%d)\n", + rel_type(r_type), r_type); + break; + } + + return 0; +} + +static int write_reloc_as_bin(uint32_t v, FILE *f) +{ + unsigned char buf[4]; + + v = cpu_to_elf32(v); + + memcpy(buf, &v, sizeof(uint32_t)); + return fwrite(buf, 1, 4, f); +} + +static int write_reloc_as_text(uint32_t v, FILE *f) +{ + int res; + + res = fprintf(f, "\t.long 0x%08"PRIx32"\n", v); + if (res < 0) + return res; + else + return sizeof(uint32_t); +} + +static void emit_relocs(int as_text, int as_bin, FILE *outf) +{ + int i; + int (*write_reloc)(uint32_t, FILE *) = write_reloc_as_bin; + int size = 0; + int size_reserved; + struct section *sec_reloc; + + sec_reloc = sec_lookup(".data.reloc"); + if (!sec_reloc) + die("Could not find relocation section\n"); + + size_reserved = sec_reloc->shdr.sh_size; + + /* Collect up the relocations */ + walk_relocs(do_reloc); + + /* Print the relocations */ + if (as_text) { + /* Print the relocations in a form suitable that + * gas will like. + */ + printf(".section \".data.reloc\",\"a\"\n"); + printf(".balign 4\n"); + /* Output text to stdout */ + write_reloc = write_reloc_as_text; + outf = stdout; + } else if (as_bin) { + /* Output raw binary to stdout */ + outf = stdout; + } else { + /* Seek to offset of the relocation section. + * Each relocation is then written into the + * vmlinux kernel image. + */ + if (fseek(outf, sec_reloc->shdr.sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + sec_reloc->shdr.sh_offset, strerror(errno)); + } + } + + for (i = 0; i < relocs.count; i++) + size += write_reloc(relocs.offset[i], outf); + + /* Print a stop, but only if we've actually written some relocs */ + if (size) + size += write_reloc(0, outf); + + if (size > size_reserved) + /* Die, but suggest a value for CONFIG_RELOCATION_TABLE_SIZE + * which will fix this problem and allow a bit of headroom + * if more kernel features are enabled + */ + die("Relocations overflow available space!\n" \ + "Please adjust CONFIG_RELOCATION_TABLE_SIZE " \ + "to at least 0x%08x\n", (size + 0x1000) & ~0xFFF); +} + +/* + * As an aid to debugging problems with different linkers + * print summary information about the relocs. + * Since different linkers tend to emit the sections in + * different orders we use the section names in the output. + */ +static int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, + const char *symname) +{ + printf("%16s 0x%08x %16s %40s %16s\n", + sec_name(sec->shdr.sh_info), + (unsigned int)rel->r_offset, + rel_type(ELF_R_TYPE(rel->r_info)), + symname, + sec_name(sym->st_shndx)); + return 0; +} + +static void print_reloc_info(void) +{ + printf("%16s %10s %16s %40s %16s\n", + "reloc section", + "offset", + "reloc type", + "symbol", + "symbol section"); + walk_relocs(do_reloc_info); +} + +#if ELF_BITS == 64 +# define process process_64 +#else +# define process process_32 +#endif + +void process(FILE *fp, int as_text, int as_bin, + int show_reloc_info, int keep_relocs) +{ + regex_init(); + read_ehdr(fp); + read_shdrs(fp); + read_strtabs(fp); + read_symtabs(fp); + read_relocs(fp); + if (show_reloc_info) { + print_reloc_info(); + return; + } + emit_relocs(as_text, as_bin, fp); + if (!keep_relocs) + remove_relocs(fp); +} diff --git a/arch/mips/boot/tools/relocs.h b/arch/mips/boot/tools/relocs.h new file mode 100644 index 000000000000..3cf676f49e18 --- /dev/null +++ b/arch/mips/boot/tools/relocs.h @@ -0,0 +1,45 @@ +#ifndef RELOCS_H +#define RELOCS_H + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <elf.h> +#include <byteswap.h> +#define USE_BSD +#include <endian.h> +#include <regex.h> + +void die(char *fmt, ...); + +/* + * Introduced for MIPSr6 + */ +#ifndef R_MIPS_PC21_S2 +#define R_MIPS_PC21_S2 60 +#endif + +#ifndef R_MIPS_PC26_S2 +#define R_MIPS_PC26_S2 61 +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +enum symtype { + S_ABS, + S_REL, + S_SEG, + S_LIN, + S_NSYMTYPES +}; + +void process_32(FILE *fp, int as_text, int as_bin, + int show_reloc_info, int keep_relocs); +void process_64(FILE *fp, int as_text, int as_bin, + int show_reloc_info, int keep_relocs); +#endif /* RELOCS_H */ diff --git a/arch/mips/boot/tools/relocs_32.c b/arch/mips/boot/tools/relocs_32.c new file mode 100644 index 000000000000..915bdc07f5ed --- /dev/null +++ b/arch/mips/boot/tools/relocs_32.c @@ -0,0 +1,17 @@ +#include "relocs.h" + +#define ELF_BITS 32 + +#define ELF_MACHINE EM_MIPS +#define ELF_MACHINE_NAME "MIPS" +#define SHT_REL_TYPE SHT_REL +#define Elf_Rel ElfW(Rel) + +#define ELF_CLASS ELFCLASS32 +#define ELF_R_SYM(val) ELF32_R_SYM(val) +#define ELF_R_TYPE(val) ELF32_R_TYPE(val) +#define ELF_ST_TYPE(o) ELF32_ST_TYPE(o) +#define ELF_ST_BIND(o) ELF32_ST_BIND(o) +#define ELF_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o) + +#include "relocs.c" diff --git a/arch/mips/boot/tools/relocs_64.c b/arch/mips/boot/tools/relocs_64.c new file mode 100644 index 000000000000..b671b5e2dcd8 --- /dev/null +++ b/arch/mips/boot/tools/relocs_64.c @@ -0,0 +1,27 @@ +#include "relocs.h" + +#define ELF_BITS 64 + +#define ELF_MACHINE EM_MIPS +#define ELF_MACHINE_NAME "MIPS64" +#define SHT_REL_TYPE SHT_RELA +#define Elf_Rel Elf64_Rela + +typedef uint8_t Elf64_Byte; + +typedef struct { + Elf64_Word r_sym; /* Symbol index. */ + Elf64_Byte r_ssym; /* Special symbol. */ + Elf64_Byte r_type3; /* Third relocation. */ + Elf64_Byte r_type2; /* Second relocation. */ + Elf64_Byte r_type; /* First relocation. */ +} Elf64_Mips_Rela; + +#define ELF_CLASS ELFCLASS64 +#define ELF_R_SYM(val) (((Elf64_Mips_Rela *)(&val))->r_sym) +#define ELF_R_TYPE(val) (((Elf64_Mips_Rela *)(&val))->r_type) +#define ELF_ST_TYPE(o) ELF64_ST_TYPE(o) +#define ELF_ST_BIND(o) ELF64_ST_BIND(o) +#define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o) + +#include "relocs.c" diff --git a/arch/mips/boot/tools/relocs_main.c b/arch/mips/boot/tools/relocs_main.c new file mode 100644 index 000000000000..d8fe2343b8d0 --- /dev/null +++ b/arch/mips/boot/tools/relocs_main.c @@ -0,0 +1,84 @@ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <endian.h> +#include <elf.h> + +#include "relocs.h" + +void die(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static void usage(void) +{ + die("relocs [--reloc-info|--text|--bin|--keep] vmlinux\n"); +} + +int main(int argc, char **argv) +{ + int show_reloc_info, as_text, as_bin, keep_relocs; + const char *fname; + FILE *fp; + int i; + unsigned char e_ident[EI_NIDENT]; + + show_reloc_info = 0; + as_text = 0; + as_bin = 0; + keep_relocs = 0; + fname = NULL; + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + + if (*arg == '-') { + if (strcmp(arg, "--reloc-info") == 0) { + show_reloc_info = 1; + continue; + } + if (strcmp(arg, "--text") == 0) { + as_text = 1; + continue; + } + if (strcmp(arg, "--bin") == 0) { + as_bin = 1; + continue; + } + if (strcmp(arg, "--keep") == 0) { + keep_relocs = 1; + continue; + } + } else if (!fname) { + fname = arg; + continue; + } + usage(); + } + if (!fname) + usage(); + + fp = fopen(fname, "r+"); + if (!fp) + die("Cannot open %s: %s\n", fname, strerror(errno)); + + if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT) + die("Cannot read %s: %s", fname, strerror(errno)); + + rewind(fp); + if (e_ident[EI_CLASS] == ELFCLASS64) + process_64(fp, as_text, as_bin, show_reloc_info, keep_relocs); + else + process_32(fp, as_text, as_bin, show_reloc_info, keep_relocs); + fclose(fp); + return 0; +} diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c index 1882e6475dd0..23c2344a3552 100644 --- a/arch/mips/cavium-octeon/csrc-octeon.c +++ b/arch/mips/cavium-octeon/csrc-octeon.c @@ -19,6 +19,7 @@ #include <asm/octeon/cvmx-ipd-defs.h> #include <asm/octeon/cvmx-mio-defs.h> #include <asm/octeon/cvmx-rst-defs.h> +#include <asm/octeon/cvmx-fpa-defs.h> static u64 f; static u64 rdiv; @@ -65,9 +66,13 @@ void __init octeon_setup_delays(void) */ void octeon_init_cvmcount(void) { + u64 clk_reg; unsigned long flags; unsigned loops = 2; + clk_reg = octeon_has_feature(OCTEON_FEATURE_FPA3) ? + CVMX_FPA_CLK_COUNT : CVMX_IPD_CLK_COUNT; + /* Clobber loops so GCC will not unroll the following while loop. */ asm("" : "+r" (loops)); @@ -77,18 +82,18 @@ void octeon_init_cvmcount(void) * which should give more deterministic timing. */ while (loops--) { - u64 ipd_clk_count = cvmx_read_csr(CVMX_IPD_CLK_COUNT); + u64 clk_count = cvmx_read_csr(clk_reg); if (rdiv != 0) { - ipd_clk_count *= rdiv; + clk_count *= rdiv; if (f != 0) { asm("dmultu\t%[cnt],%[f]\n\t" "mfhi\t%[cnt]" - : [cnt] "+r" (ipd_clk_count) + : [cnt] "+r" (clk_count) : [f] "r" (f) : "hi", "lo"); } } - write_c0_cvmcount(ipd_clk_count); + write_c0_cvmcount(clk_count); } local_irq_restore(flags); } diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index 376701f41cc2..ff26d0217b87 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -87,6 +87,8 @@ int cvmx_helper_get_number_of_interfaces(void) return 9; if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) return 4; + if (OCTEON_IS_MODEL(OCTEON_CN7XXX)) + return 5; else return 3; } @@ -260,6 +262,41 @@ static cvmx_helper_interface_mode_t __cvmx_get_mode_octeon2(int interface) } /** + * @INTERNAL + * Return interface mode for CN7XXX. + */ +static cvmx_helper_interface_mode_t __cvmx_get_mode_cn7xxx(int interface) +{ + union cvmx_gmxx_inf_mode mode; + + mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); + + switch (interface) { + case 0: + case 1: + switch (mode.cn68xx.mode) { + case 0: + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + case 1: + case 2: + return CVMX_HELPER_INTERFACE_MODE_SGMII; + case 3: + return CVMX_HELPER_INTERFACE_MODE_XAUI; + default: + return CVMX_HELPER_INTERFACE_MODE_SGMII; + } + case 2: + return CVMX_HELPER_INTERFACE_MODE_NPI; + case 3: + return CVMX_HELPER_INTERFACE_MODE_LOOP; + case 4: + return CVMX_HELPER_INTERFACE_MODE_RGMII; + default: + return CVMX_HELPER_INTERFACE_MODE_DISABLED; + } +} + +/** * Get the operating mode of an interface. Depending on the Octeon * chip and configuration, this function returns an enumeration * of the type of packet I/O supported by an interface. @@ -278,6 +315,12 @@ cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) return CVMX_HELPER_INTERFACE_MODE_DISABLED; /* + * OCTEON III models + */ + if (OCTEON_IS_MODEL(OCTEON_CN7XXX)) + return __cvmx_get_mode_cn7xxx(interface); + + /* * Octeon II models */ if (OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF71XX)) diff --git a/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c b/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c index 3d17fac29359..cc1b1d2a6fa1 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c +++ b/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c @@ -32,86 +32,22 @@ #include <linux/module.h> #include <asm/octeon/cvmx.h> -#include <asm/octeon/cvmx-spinlock.h> #include <asm/octeon/cvmx-sysinfo.h> -/** +/* * This structure defines the private state maintained by sysinfo module. - * */ -static struct { - struct cvmx_sysinfo sysinfo; /* system information */ - cvmx_spinlock_t lock; /* mutex spinlock */ - -} state = { - .lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER -}; - +static struct cvmx_sysinfo sysinfo; /* system information */ /* - * Global variables that define the min/max of the memory region set - * up for 32 bit userspace access. - */ -uint64_t linux_mem32_min; -uint64_t linux_mem32_max; -uint64_t linux_mem32_wired; -uint64_t linux_mem32_offset; - -/** - * This function returns the application information as obtained + * Returns the application information as obtained * by the bootloader. This provides the core mask of the cores * running the same application image, as well as the physical * memory regions available to the core. - * - * Returns Pointer to the boot information structure - * */ struct cvmx_sysinfo *cvmx_sysinfo_get(void) { - return &(state.sysinfo); + return &sysinfo; } EXPORT_SYMBOL(cvmx_sysinfo_get); -/** - * This function is used in non-simple executive environments (such as - * Linux kernel, u-boot, etc.) to configure the minimal fields that - * are required to use simple executive files directly. - * - * Locking (if required) must be handled outside of this - * function - * - * @phy_mem_desc_ptr: - * Pointer to global physical memory descriptor - * (bootmem descriptor) @board_type: Octeon board - * type enumeration - * - * @board_rev_major: - * Board major revision - * @board_rev_minor: - * Board minor revision - * @cpu_clock_hz: - * CPU clock freqency in hertz - * - * Returns 0: Failure - * 1: success - */ -int cvmx_sysinfo_minimal_initialize(void *phy_mem_desc_ptr, - uint16_t board_type, - uint8_t board_rev_major, - uint8_t board_rev_minor, - uint32_t cpu_clock_hz) -{ - - /* The sysinfo structure was already initialized */ - if (state.sysinfo.board_type) - return 0; - - memset(&(state.sysinfo), 0x0, sizeof(state.sysinfo)); - state.sysinfo.phy_mem_desc_ptr = phy_mem_desc_ptr; - state.sysinfo.board_type = board_type; - state.sysinfo.board_rev_major = board_rev_major; - state.sysinfo.board_rev_minor = board_rev_minor; - state.sysinfo.cpu_clock_hz = cpu_clock_hz; - - return 1; -} diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c index b2104bd9ab3b..d08a2bce653c 100644 --- a/arch/mips/cavium-octeon/executive/octeon-model.c +++ b/arch/mips/cavium-octeon/executive/octeon-model.c @@ -71,11 +71,11 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, uint32_t fuse_data = 0; fus3.u64 = 0; - if (!OCTEON_IS_MODEL(OCTEON_CN6XXX)) + if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)) fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); - num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU_FUSE)); + num_cores = cvmx_octeon_num_cores(); /* Make sure the non existent devices look disabled */ switch ((chip_id >> 8) & 0xff) { @@ -121,6 +121,15 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, * later. */ switch (num_cores) { + case 48: + core_model = "90"; + break; + case 44: + core_model = "88"; + break; + case 40: + core_model = "85"; + break; case 32: core_model = "80"; break; @@ -297,7 +306,7 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, if (fus_dat3.s.nozip) suffix = "SCP"; - if (fus_dat3.s.bar2_en) + if (fus_dat3.cn56xx.bar2_en) suffix = "NSPB2"; } if (fus3.cn56xx.crip_1024k) @@ -369,6 +378,73 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, else suffix = "AAP"; break; + case 0x94: /* CNF71XX */ + family = "F71"; + if (fus_dat3.cnf71xx.nozip) + suffix = "SCP"; + else + suffix = "AAP"; + break; + case 0x95: /* CN78XX */ + if (num_cores == 6) /* Other core counts match generic */ + core_model = "35"; + if (OCTEON_IS_MODEL(OCTEON_CN76XX)) + family = "76"; + else + family = "78"; + if (fus_dat3.cn78xx.l2c_crip == 2) + family = "77"; + if (fus_dat3.cn78xx.nozip + && fus_dat3.cn78xx.nodfa_dte + && fus_dat3.cn78xx.nohna_dte) { + if (fus_dat3.cn78xx.nozip && + !fus_dat2.cn78xx.raid_en && + fus_dat3.cn78xx.nohna_dte) { + suffix = "CP"; + } else { + suffix = "SCP"; + } + } else if (fus_dat2.cn78xx.raid_en == 0) + suffix = "HCP"; + else + suffix = "AAP"; + break; + case 0x96: /* CN70XX */ + family = "70"; + if (cvmx_read_csr(CVMX_MIO_FUS_PDF) & (0x1ULL << 32)) + family = "71"; + if (fus_dat2.cn70xx.nocrypto) + suffix = "CP"; + else if (fus_dat3.cn70xx.nodfa_dte) + suffix = "SCP"; + else + suffix = "AAP"; + break; + case 0x97: /* CN73XX */ + if (num_cores == 6) /* Other core counts match generic */ + core_model = "35"; + family = "73"; + if (fus_dat3.cn73xx.l2c_crip == 2) + family = "72"; + if (fus_dat3.cn73xx.nozip + && fus_dat3.cn73xx.nodfa_dte + && fus_dat3.cn73xx.nohna_dte) { + if (!fus_dat2.cn73xx.raid_en) + suffix = "CP"; + else + suffix = "SCP"; + } else + suffix = "AAP"; + break; + case 0x98: /* CN75XX */ + family = "F75"; + if (fus_dat3.cn78xx.nozip + && fus_dat3.cn78xx.nodfa_dte + && fus_dat3.cn78xx.nohna_dte) + suffix = "SCP"; + else + suffix = "AAP"; + break; default: family = "XX"; core_model = "XX"; diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 4f9eb0576884..368eb490354c 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2004-2014 Cavium, Inc. + * Copyright (C) 2004-2016 Cavium, Inc. */ #include <linux/of_address.h> @@ -19,16 +19,53 @@ #include <asm/octeon/octeon.h> #include <asm/octeon/cvmx-ciu2-defs.h> +#include <asm/octeon/cvmx-ciu3-defs.h> static DEFINE_PER_CPU(unsigned long, octeon_irq_ciu0_en_mirror); static DEFINE_PER_CPU(unsigned long, octeon_irq_ciu1_en_mirror); static DEFINE_PER_CPU(raw_spinlock_t, octeon_irq_ciu_spinlock); +static DEFINE_PER_CPU(unsigned int, octeon_irq_ciu3_idt_ip2); + +static DEFINE_PER_CPU(unsigned int, octeon_irq_ciu3_idt_ip3); +static DEFINE_PER_CPU(struct octeon_ciu3_info *, octeon_ciu3_info); +#define CIU3_MBOX_PER_CORE 10 + +/* + * The 8 most significant bits of the intsn identify the interrupt major block. + * Each major block might use its own interrupt domain. Thus 256 domains are + * needed. + */ +#define MAX_CIU3_DOMAINS 256 + +typedef irq_hw_number_t (*octeon_ciu3_intsn2hw_t)(struct irq_domain *, unsigned int); + +/* Information for each ciu3 in the system */ +struct octeon_ciu3_info { + u64 ciu3_addr; + int node; + struct irq_domain *domain[MAX_CIU3_DOMAINS]; + octeon_ciu3_intsn2hw_t intsn2hw[MAX_CIU3_DOMAINS]; +}; + +/* Each ciu3 in the system uses its own data (one ciu3 per node) */ +static struct octeon_ciu3_info *octeon_ciu3_info_per_node[4]; struct octeon_irq_ciu_domain_data { int num_sum; /* number of sum registers (2 or 3). */ }; -static __read_mostly u8 octeon_irq_ciu_to_irq[8][64]; +/* Register offsets from ciu3_addr */ +#define CIU3_CONST 0x220 +#define CIU3_IDT_CTL(_idt) ((_idt) * 8 + 0x110000) +#define CIU3_IDT_PP(_idt, _idx) ((_idt) * 32 + (_idx) * 8 + 0x120000) +#define CIU3_IDT_IO(_idt) ((_idt) * 8 + 0x130000) +#define CIU3_DEST_PP_INT(_pp_ip) ((_pp_ip) * 8 + 0x200000) +#define CIU3_DEST_IO_INT(_io) ((_io) * 8 + 0x210000) +#define CIU3_ISC_CTL(_intsn) ((_intsn) * 8 + 0x80000000) +#define CIU3_ISC_W1C(_intsn) ((_intsn) * 8 + 0x90000000) +#define CIU3_ISC_W1S(_intsn) ((_intsn) * 8 + 0xa0000000) + +static __read_mostly int octeon_irq_ciu_to_irq[8][64]; struct octeon_ciu_chip_data { union { @@ -39,10 +76,11 @@ struct octeon_ciu_chip_data { struct { /* only used for ciu/ciu2 */ u8 line; u8 bit; - u8 gpio_line; }; }; + int gpio_line; int current_cpu; /* Next CPU expected to take this irq */ + int ciu_node; /* NUMA node number of the CIU */ }; struct octeon_core_chip_data { @@ -626,6 +664,18 @@ static void octeon_irq_ciu_enable_all_v2(struct irq_data *data) } } +static int octeon_irq_ciu_set_type(struct irq_data *data, unsigned int t) +{ + irqd_set_trigger_type(data, t); + + if (t & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(data, handle_edge_irq); + else + irq_set_handler_locked(data, handle_level_irq); + + return IRQ_SET_MASK_OK; +} + static void octeon_irq_gpio_setup(struct irq_data *data) { union cvmx_gpio_bit_cfgx cfg; @@ -663,7 +713,7 @@ static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t) irqd_set_trigger_type(data, t); octeon_irq_gpio_setup(data); - if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH) + if (t & IRQ_TYPE_EDGE_BOTH) irq_set_handler_locked(data, handle_edge_irq); else irq_set_handler_locked(data, handle_level_irq); @@ -863,6 +913,16 @@ static int octeon_irq_ciu_set_affinity_sum2(struct irq_data *data, } #endif +static unsigned int edge_startup(struct irq_data *data) +{ + /* ack any pending edge-irq at startup, so there is + * an _edge_ to fire on when the event reappears. + */ + data->chip->irq_ack(data); + data->chip->irq_enable(data); + return 0; +} + /* * Newer octeon chips have support for lockless CIU operation. */ @@ -1158,16 +1218,6 @@ static struct irq_chip *octeon_irq_ciu_chip; static struct irq_chip *octeon_irq_ciu_chip_edge; static struct irq_chip *octeon_irq_gpio_chip; -static bool octeon_irq_virq_in_range(unsigned int virq) -{ - /* We cannot let it overflow the mapping array. */ - if (virq < (1ul << 8 * sizeof(octeon_irq_ciu_to_irq[0][0]))) - return true; - - WARN_ONCE(true, "virq out of range %u.\n", virq); - return false; -} - static int octeon_irq_ciu_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { @@ -1176,13 +1226,6 @@ static int octeon_irq_ciu_map(struct irq_domain *d, unsigned int bit = hw & 63; struct octeon_irq_ciu_domain_data *dd = d->host_data; - if (!octeon_irq_virq_in_range(virq)) - return -EINVAL; - - /* Don't map irq if it is reserved for GPIO. */ - if (line == 0 && bit >= 16 && bit <32) - return 0; - if (line >= dd->num_sum || octeon_irq_ciu_to_irq[line][bit] != 0) return -EINVAL; @@ -1215,9 +1258,6 @@ static int octeon_irq_gpio_map(struct irq_domain *d, unsigned int line, bit; int r; - if (!octeon_irq_virq_in_range(virq)) - return -EINVAL; - line = (hw + gpiod->base_hwirq) >> 6; bit = (hw + gpiod->base_hwirq) & 63; if (line > ARRAY_SIZE(octeon_irq_ciu_to_irq) || @@ -1899,9 +1939,6 @@ static int octeon_irq_ciu2_map(struct irq_domain *d, unsigned int line = hw >> 6; unsigned int bit = hw & 63; - if (!octeon_irq_virq_in_range(virq)) - return -EINVAL; - /* * Don't map irq if it is reserved for GPIO. * (Line 7 are the GPIO lines.) @@ -2294,10 +2331,598 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, return 0; } +int octeon_irq_ciu3_xlat(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + struct octeon_ciu3_info *ciu3_info = d->host_data; + unsigned int hwirq, type, intsn_major; + union cvmx_ciu3_iscx_ctl isc; + + if (intsize < 2) + return -EINVAL; + hwirq = intspec[0]; + type = intspec[1]; + + if (hwirq >= (1 << 20)) + return -EINVAL; + + intsn_major = hwirq >> 12; + switch (intsn_major) { + case 0x04: /* Software handled separately. */ + return -EINVAL; + default: + break; + } + + isc.u64 = cvmx_read_csr(ciu3_info->ciu3_addr + CIU3_ISC_CTL(hwirq)); + if (!isc.s.imp) + return -EINVAL; + + switch (type) { + case 4: /* official value for level triggering. */ + *out_type = IRQ_TYPE_LEVEL_HIGH; + break; + case 0: /* unofficial value, but we might as well let it work. */ + case 1: /* official value for edge triggering. */ + *out_type = IRQ_TYPE_EDGE_RISING; + break; + default: /* Nothing else is acceptable. */ + return -EINVAL; + } + + *out_hwirq = hwirq; + + return 0; +} + +void octeon_irq_ciu3_enable(struct irq_data *data) +{ + int cpu; + union cvmx_ciu3_iscx_ctl isc_ctl; + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_ctl_addr; + + struct octeon_ciu_chip_data *cd; + + cpu = next_cpu_for_irq(data); + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64); + + isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn); + isc_ctl.u64 = 0; + isc_ctl.s.en = 1; + isc_ctl.s.idt = per_cpu(octeon_irq_ciu3_idt_ip2, cpu); + cvmx_write_csr(isc_ctl_addr, isc_ctl.u64); + cvmx_read_csr(isc_ctl_addr); +} + +void octeon_irq_ciu3_disable(struct irq_data *data) +{ + u64 isc_ctl_addr; + union cvmx_ciu3_iscx_w1c isc_w1c; + + struct octeon_ciu_chip_data *cd; + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + + isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn); + cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64); + cvmx_write_csr(isc_ctl_addr, 0); + cvmx_read_csr(isc_ctl_addr); +} + +void octeon_irq_ciu3_ack(struct irq_data *data) +{ + u64 isc_w1c_addr; + union cvmx_ciu3_iscx_w1c isc_w1c; + struct octeon_ciu_chip_data *cd; + u32 trigger_type = irqd_get_trigger_type(data); + + /* + * We use a single irq_chip, so we have to do nothing to ack a + * level interrupt. + */ + if (!(trigger_type & IRQ_TYPE_EDGE_BOTH)) + return; + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.raw = 1; + + isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn); + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); +} + +void octeon_irq_ciu3_mask(struct irq_data *data) +{ + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_w1c_addr; + struct octeon_ciu_chip_data *cd; + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + + isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn); + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); +} + +void octeon_irq_ciu3_mask_ack(struct irq_data *data) +{ + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_w1c_addr; + struct octeon_ciu_chip_data *cd; + u32 trigger_type = irqd_get_trigger_type(data); + + cd = irq_data_get_irq_chip_data(data); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + + /* + * We use a single irq_chip, so only ack an edge (!level) + * interrupt. + */ + if (trigger_type & IRQ_TYPE_EDGE_BOTH) + isc_w1c.s.raw = 1; + + isc_w1c_addr = cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn); + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); +} + +#ifdef CONFIG_SMP +int octeon_irq_ciu3_set_affinity(struct irq_data *data, + const struct cpumask *dest, bool force) +{ + union cvmx_ciu3_iscx_ctl isc_ctl; + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_ctl_addr; + int cpu; + bool enable_one = !irqd_irq_disabled(data) && !irqd_irq_masked(data); + struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data); + + if (!cpumask_subset(dest, cpumask_of_node(cd->ciu_node))) + return -EINVAL; + + if (!enable_one) + return IRQ_SET_MASK_OK; + + cd = irq_data_get_irq_chip_data(data); + cpu = cpumask_first(dest); + if (cpu >= nr_cpu_ids) + cpu = smp_processor_id(); + cd->current_cpu = cpu; + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + cvmx_write_csr(cd->ciu3_addr + CIU3_ISC_W1C(cd->intsn), isc_w1c.u64); + + isc_ctl_addr = cd->ciu3_addr + CIU3_ISC_CTL(cd->intsn); + isc_ctl.u64 = 0; + isc_ctl.s.en = 1; + isc_ctl.s.idt = per_cpu(octeon_irq_ciu3_idt_ip2, cpu); + cvmx_write_csr(isc_ctl_addr, isc_ctl.u64); + cvmx_read_csr(isc_ctl_addr); + + return IRQ_SET_MASK_OK; +} +#endif + +static struct irq_chip octeon_irq_chip_ciu3 = { + .name = "CIU3", + .irq_startup = edge_startup, + .irq_enable = octeon_irq_ciu3_enable, + .irq_disable = octeon_irq_ciu3_disable, + .irq_ack = octeon_irq_ciu3_ack, + .irq_mask = octeon_irq_ciu3_mask, + .irq_mask_ack = octeon_irq_ciu3_mask_ack, + .irq_unmask = octeon_irq_ciu3_enable, + .irq_set_type = octeon_irq_ciu_set_type, +#ifdef CONFIG_SMP + .irq_set_affinity = octeon_irq_ciu3_set_affinity, + .irq_cpu_offline = octeon_irq_cpu_offline_ciu, +#endif +}; + +int octeon_irq_ciu3_mapx(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw, struct irq_chip *chip) +{ + struct octeon_ciu3_info *ciu3_info = d->host_data; + struct octeon_ciu_chip_data *cd = kzalloc_node(sizeof(*cd), GFP_KERNEL, + ciu3_info->node); + if (!cd) + return -ENOMEM; + cd->intsn = hw; + cd->current_cpu = -1; + cd->ciu3_addr = ciu3_info->ciu3_addr; + cd->ciu_node = ciu3_info->node; + irq_set_chip_and_handler(virq, chip, handle_edge_irq); + irq_set_chip_data(virq, cd); + + return 0; +} + +static int octeon_irq_ciu3_map(struct irq_domain *d, + unsigned int virq, irq_hw_number_t hw) +{ + return octeon_irq_ciu3_mapx(d, virq, hw, &octeon_irq_chip_ciu3); +} + +static struct irq_domain_ops octeon_dflt_domain_ciu3_ops = { + .map = octeon_irq_ciu3_map, + .unmap = octeon_irq_free_cd, + .xlate = octeon_irq_ciu3_xlat, +}; + +static void octeon_irq_ciu3_ip2(void) +{ + union cvmx_ciu3_destx_pp_int dest_pp_int; + struct octeon_ciu3_info *ciu3_info; + u64 ciu3_addr; + + ciu3_info = __this_cpu_read(octeon_ciu3_info); + ciu3_addr = ciu3_info->ciu3_addr; + + dest_pp_int.u64 = cvmx_read_csr(ciu3_addr + CIU3_DEST_PP_INT(3 * cvmx_get_local_core_num())); + + if (likely(dest_pp_int.s.intr)) { + irq_hw_number_t intsn = dest_pp_int.s.intsn; + irq_hw_number_t hw; + struct irq_domain *domain; + /* Get the domain to use from the major block */ + int block = intsn >> 12; + int ret; + + domain = ciu3_info->domain[block]; + if (ciu3_info->intsn2hw[block]) + hw = ciu3_info->intsn2hw[block](domain, intsn); + else + hw = intsn; + + ret = handle_domain_irq(domain, hw, NULL); + if (ret < 0) { + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_w1c_addr = ciu3_addr + CIU3_ISC_W1C(intsn); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); + spurious_interrupt(); + } + } else { + spurious_interrupt(); + } +} + +/* + * 10 mbox per core starting from zero. + * Base mbox is core * 10 + */ +static unsigned int octeon_irq_ciu3_base_mbox_intsn(int core) +{ + /* SW (mbox) are 0x04 in bits 12..19 */ + return 0x04000 + CIU3_MBOX_PER_CORE * core; +} + +static unsigned int octeon_irq_ciu3_mbox_intsn_for_core(int core, unsigned int mbox) +{ + return octeon_irq_ciu3_base_mbox_intsn(core) + mbox; +} + +static unsigned int octeon_irq_ciu3_mbox_intsn_for_cpu(int cpu, unsigned int mbox) +{ + int local_core = octeon_coreid_for_cpu(cpu) & 0x3f; + + return octeon_irq_ciu3_mbox_intsn_for_core(local_core, mbox); +} + +static void octeon_irq_ciu3_mbox(void) +{ + union cvmx_ciu3_destx_pp_int dest_pp_int; + struct octeon_ciu3_info *ciu3_info; + u64 ciu3_addr; + int core = cvmx_get_local_core_num(); + + ciu3_info = __this_cpu_read(octeon_ciu3_info); + ciu3_addr = ciu3_info->ciu3_addr; + + dest_pp_int.u64 = cvmx_read_csr(ciu3_addr + CIU3_DEST_PP_INT(1 + 3 * core)); + + if (likely(dest_pp_int.s.intr)) { + irq_hw_number_t intsn = dest_pp_int.s.intsn; + int mbox = intsn - octeon_irq_ciu3_base_mbox_intsn(core); + + if (likely(mbox >= 0 && mbox < CIU3_MBOX_PER_CORE)) { + do_IRQ(mbox + OCTEON_IRQ_MBOX0); + } else { + union cvmx_ciu3_iscx_w1c isc_w1c; + u64 isc_w1c_addr = ciu3_addr + CIU3_ISC_W1C(intsn); + + isc_w1c.u64 = 0; + isc_w1c.s.en = 1; + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); + spurious_interrupt(); + } + } else { + spurious_interrupt(); + } +} + +void octeon_ciu3_mbox_send(int cpu, unsigned int mbox) +{ + struct octeon_ciu3_info *ciu3_info; + unsigned int intsn; + union cvmx_ciu3_iscx_w1s isc_w1s; + u64 isc_w1s_addr; + + if (WARN_ON_ONCE(mbox >= CIU3_MBOX_PER_CORE)) + return; + + intsn = octeon_irq_ciu3_mbox_intsn_for_cpu(cpu, mbox); + ciu3_info = per_cpu(octeon_ciu3_info, cpu); + isc_w1s_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1S(intsn); + + isc_w1s.u64 = 0; + isc_w1s.s.raw = 1; + + cvmx_write_csr(isc_w1s_addr, isc_w1s.u64); + cvmx_read_csr(isc_w1s_addr); +} + +static void octeon_irq_ciu3_mbox_set_enable(struct irq_data *data, int cpu, bool en) +{ + struct octeon_ciu3_info *ciu3_info; + unsigned int intsn; + u64 isc_ctl_addr, isc_w1c_addr; + union cvmx_ciu3_iscx_ctl isc_ctl; + unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0; + + intsn = octeon_irq_ciu3_mbox_intsn_for_cpu(cpu, mbox); + ciu3_info = per_cpu(octeon_ciu3_info, cpu); + isc_w1c_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1C(intsn); + isc_ctl_addr = ciu3_info->ciu3_addr + CIU3_ISC_CTL(intsn); + + isc_ctl.u64 = 0; + isc_ctl.s.en = 1; + + cvmx_write_csr(isc_w1c_addr, isc_ctl.u64); + cvmx_write_csr(isc_ctl_addr, 0); + if (en) { + unsigned int idt = per_cpu(octeon_irq_ciu3_idt_ip3, cpu); + + isc_ctl.u64 = 0; + isc_ctl.s.en = 1; + isc_ctl.s.idt = idt; + cvmx_write_csr(isc_ctl_addr, isc_ctl.u64); + } + cvmx_read_csr(isc_ctl_addr); +} + +static void octeon_irq_ciu3_mbox_enable(struct irq_data *data) +{ + int cpu; + unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0; + + WARN_ON(mbox >= CIU3_MBOX_PER_CORE); + + for_each_online_cpu(cpu) + octeon_irq_ciu3_mbox_set_enable(data, cpu, true); +} + +static void octeon_irq_ciu3_mbox_disable(struct irq_data *data) +{ + int cpu; + unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0; + + WARN_ON(mbox >= CIU3_MBOX_PER_CORE); + + for_each_online_cpu(cpu) + octeon_irq_ciu3_mbox_set_enable(data, cpu, false); +} + +static void octeon_irq_ciu3_mbox_ack(struct irq_data *data) +{ + struct octeon_ciu3_info *ciu3_info; + unsigned int intsn; + u64 isc_w1c_addr; + union cvmx_ciu3_iscx_w1c isc_w1c; + unsigned int mbox = data->irq - OCTEON_IRQ_MBOX0; + + intsn = octeon_irq_ciu3_mbox_intsn_for_core(cvmx_get_local_core_num(), mbox); + + isc_w1c.u64 = 0; + isc_w1c.s.raw = 1; + + ciu3_info = __this_cpu_read(octeon_ciu3_info); + isc_w1c_addr = ciu3_info->ciu3_addr + CIU3_ISC_W1C(intsn); + cvmx_write_csr(isc_w1c_addr, isc_w1c.u64); + cvmx_read_csr(isc_w1c_addr); +} + +static void octeon_irq_ciu3_mbox_cpu_online(struct irq_data *data) +{ + octeon_irq_ciu3_mbox_set_enable(data, smp_processor_id(), true); +} + +static void octeon_irq_ciu3_mbox_cpu_offline(struct irq_data *data) +{ + octeon_irq_ciu3_mbox_set_enable(data, smp_processor_id(), false); +} + +static int octeon_irq_ciu3_alloc_resources(struct octeon_ciu3_info *ciu3_info) +{ + u64 b = ciu3_info->ciu3_addr; + int idt_ip2, idt_ip3, idt_ip4; + int unused_idt2; + int core = cvmx_get_local_core_num(); + int i; + + __this_cpu_write(octeon_ciu3_info, ciu3_info); + + /* + * 4 idt per core starting from 1 because zero is reserved. + * Base idt per core is 4 * core + 1 + */ + idt_ip2 = core * 4 + 1; + idt_ip3 = core * 4 + 2; + idt_ip4 = core * 4 + 3; + unused_idt2 = core * 4 + 4; + __this_cpu_write(octeon_irq_ciu3_idt_ip2, idt_ip2); + __this_cpu_write(octeon_irq_ciu3_idt_ip3, idt_ip3); + + /* ip2 interrupts for this CPU */ + cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip2), 0); + cvmx_write_csr(b + CIU3_IDT_PP(idt_ip2, 0), 1ull << core); + cvmx_write_csr(b + CIU3_IDT_IO(idt_ip2), 0); + + /* ip3 interrupts for this CPU */ + cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip3), 1); + cvmx_write_csr(b + CIU3_IDT_PP(idt_ip3, 0), 1ull << core); + cvmx_write_csr(b + CIU3_IDT_IO(idt_ip3), 0); + + /* ip4 interrupts for this CPU */ + cvmx_write_csr(b + CIU3_IDT_CTL(idt_ip4), 2); + cvmx_write_csr(b + CIU3_IDT_PP(idt_ip4, 0), 0); + cvmx_write_csr(b + CIU3_IDT_IO(idt_ip4), 0); + + cvmx_write_csr(b + CIU3_IDT_CTL(unused_idt2), 0); + cvmx_write_csr(b + CIU3_IDT_PP(unused_idt2, 0), 0); + cvmx_write_csr(b + CIU3_IDT_IO(unused_idt2), 0); + + for (i = 0; i < CIU3_MBOX_PER_CORE; i++) { + unsigned int intsn = octeon_irq_ciu3_mbox_intsn_for_core(core, i); + + cvmx_write_csr(b + CIU3_ISC_W1C(intsn), 2); + cvmx_write_csr(b + CIU3_ISC_CTL(intsn), 0); + } + + return 0; +} + +static void octeon_irq_setup_secondary_ciu3(void) +{ + struct octeon_ciu3_info *ciu3_info; + + ciu3_info = octeon_ciu3_info_per_node[cvmx_get_node_num()]; + octeon_irq_ciu3_alloc_resources(ciu3_info); + irq_cpu_online(); + + /* Enable the CIU lines */ + set_c0_status(STATUSF_IP3 | STATUSF_IP2); + if (octeon_irq_use_ip4) + set_c0_status(STATUSF_IP4); + else + clear_c0_status(STATUSF_IP4); +} + +static struct irq_chip octeon_irq_chip_ciu3_mbox = { + .name = "CIU3-M", + .irq_enable = octeon_irq_ciu3_mbox_enable, + .irq_disable = octeon_irq_ciu3_mbox_disable, + .irq_ack = octeon_irq_ciu3_mbox_ack, + + .irq_cpu_online = octeon_irq_ciu3_mbox_cpu_online, + .irq_cpu_offline = octeon_irq_ciu3_mbox_cpu_offline, + .flags = IRQCHIP_ONOFFLINE_ENABLED, +}; + +static int __init octeon_irq_init_ciu3(struct device_node *ciu_node, + struct device_node *parent) +{ + int i; + int node; + struct irq_domain *domain; + struct octeon_ciu3_info *ciu3_info; + const __be32 *zero_addr; + u64 base_addr; + union cvmx_ciu3_const consts; + + node = 0; /* of_node_to_nid(ciu_node); */ + ciu3_info = kzalloc_node(sizeof(*ciu3_info), GFP_KERNEL, node); + + if (!ciu3_info) + return -ENOMEM; + + zero_addr = of_get_address(ciu_node, 0, NULL, NULL); + if (WARN_ON(!zero_addr)) + return -EINVAL; + + base_addr = of_translate_address(ciu_node, zero_addr); + base_addr = (u64)phys_to_virt(base_addr); + + ciu3_info->ciu3_addr = base_addr; + ciu3_info->node = node; + + consts.u64 = cvmx_read_csr(base_addr + CIU3_CONST); + + octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu3; + + octeon_irq_ip2 = octeon_irq_ciu3_ip2; + octeon_irq_ip3 = octeon_irq_ciu3_mbox; + octeon_irq_ip4 = octeon_irq_ip4_mask; + + if (node == cvmx_get_node_num()) { + /* Mips internal */ + octeon_irq_init_core(); + + /* Only do per CPU things if it is the CIU of the boot node. */ + i = irq_alloc_descs_from(OCTEON_IRQ_MBOX0, 8, node); + WARN_ON(i < 0); + + for (i = 0; i < 8; i++) + irq_set_chip_and_handler(i + OCTEON_IRQ_MBOX0, + &octeon_irq_chip_ciu3_mbox, handle_percpu_irq); + } + + /* + * Initialize all domains to use the default domain. Specific major + * blocks will overwrite the default domain as needed. + */ + domain = irq_domain_add_tree(ciu_node, &octeon_dflt_domain_ciu3_ops, + ciu3_info); + for (i = 0; i < MAX_CIU3_DOMAINS; i++) + ciu3_info->domain[i] = domain; + + octeon_ciu3_info_per_node[node] = ciu3_info; + + if (node == cvmx_get_node_num()) { + /* Only do per CPU things if it is the CIU of the boot node. */ + octeon_irq_ciu3_alloc_resources(ciu3_info); + if (node == 0) + irq_set_default_host(domain); + + octeon_irq_use_ip4 = false; + /* Enable the CIU lines */ + set_c0_status(STATUSF_IP2 | STATUSF_IP3); + clear_c0_status(STATUSF_IP4); + } + + return 0; +} + static struct of_device_id ciu_types[] __initdata = { {.compatible = "cavium,octeon-3860-ciu", .data = octeon_irq_init_ciu}, {.compatible = "cavium,octeon-3860-gpio", .data = octeon_irq_init_gpio}, {.compatible = "cavium,octeon-6880-ciu2", .data = octeon_irq_init_ciu2}, + {.compatible = "cavium,octeon-7890-ciu3", .data = octeon_irq_init_ciu3}, {.compatible = "cavium,octeon-7130-cib", .data = octeon_irq_init_cib}, {} }; diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index d113c8ded6e2..7aeafedff94e 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -13,6 +13,7 @@ #include <linux/i2c.h> #include <linux/usb.h> #include <linux/dma-mapping.h> +#include <linux/etherdevice.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/slab.h> @@ -525,10 +526,17 @@ static void __init octeon_fdt_set_phy(int eth, int phy_addr) static void __init octeon_fdt_set_mac_addr(int n, u64 *pmac) { + const u8 *old_mac; + int old_len; u8 new_mac[6]; u64 mac = *pmac; int r; + old_mac = fdt_getprop(initial_boot_params, n, "local-mac-address", + &old_len); + if (!old_mac || old_len != 6 || is_valid_ether_addr(old_mac)) + return; + new_mac[0] = (mac >> 40) & 0xff; new_mac[1] = (mac >> 32) & 0xff; new_mac[2] = (mac >> 24) & 0xff; @@ -560,7 +568,7 @@ static void __init octeon_fdt_rm_ethernet(int node) fdt_nop_node(initial_boot_params, node); } -static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pmac) +static void __init octeon_fdt_pip_port(int iface, int i, int p, int max) { char name_buffer[20]; int eth; @@ -583,10 +591,9 @@ static void __init octeon_fdt_pip_port(int iface, int i, int p, int max, u64 *pm phy_addr = cvmx_helper_board_get_mii_address(ipd_port); octeon_fdt_set_phy(eth, phy_addr); - octeon_fdt_set_mac_addr(eth, pmac); } -static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac) +static void __init octeon_fdt_pip_iface(int pip, int idx) { char name_buffer[20]; int iface; @@ -602,7 +609,73 @@ static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac) count = cvmx_helper_ports_on_interface(idx); for (p = 0; p < 16; p++) - octeon_fdt_pip_port(iface, idx, p, count - 1, pmac); + octeon_fdt_pip_port(iface, idx, p, count - 1); +} + +void __init octeon_fill_mac_addresses(void) +{ + const char *alias_prop; + char name_buffer[20]; + u64 mac_addr_base; + int aliases; + int pip; + int i; + + aliases = fdt_path_offset(initial_boot_params, "/aliases"); + if (aliases < 0) + return; + + mac_addr_base = + ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | + ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | + ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | + ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | + ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | + (octeon_bootinfo->mac_addr_base[5] & 0xffull); + + for (i = 0; i < 2; i++) { + int mgmt; + + snprintf(name_buffer, sizeof(name_buffer), "mix%d", i); + alias_prop = fdt_getprop(initial_boot_params, aliases, + name_buffer, NULL); + if (!alias_prop) + continue; + mgmt = fdt_path_offset(initial_boot_params, alias_prop); + if (mgmt < 0) + continue; + octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); + } + + alias_prop = fdt_getprop(initial_boot_params, aliases, "pip", NULL); + if (!alias_prop) + return; + + pip = fdt_path_offset(initial_boot_params, alias_prop); + if (pip < 0) + return; + + for (i = 0; i <= 4; i++) { + int iface; + int p; + + snprintf(name_buffer, sizeof(name_buffer), "interface@%d", i); + iface = fdt_subnode_offset(initial_boot_params, pip, + name_buffer); + if (iface < 0) + continue; + for (p = 0; p < 16; p++) { + int eth; + + snprintf(name_buffer, sizeof(name_buffer), + "ethernet@%x", p); + eth = fdt_subnode_offset(initial_boot_params, iface, + name_buffer); + if (eth < 0) + continue; + octeon_fdt_set_mac_addr(eth, &mac_addr_base); + } + } } int __init octeon_prune_device_tree(void) @@ -612,7 +685,6 @@ int __init octeon_prune_device_tree(void) const char *alias_prop; char name_buffer[20]; int aliases; - u64 mac_addr_base; if (fdt_check_header(initial_boot_params)) panic("Corrupt Device Tree."); @@ -623,15 +695,6 @@ int __init octeon_prune_device_tree(void) return -EINVAL; } - - mac_addr_base = - ((octeon_bootinfo->mac_addr_base[0] & 0xffull)) << 40 | - ((octeon_bootinfo->mac_addr_base[1] & 0xffull)) << 32 | - ((octeon_bootinfo->mac_addr_base[2] & 0xffull)) << 24 | - ((octeon_bootinfo->mac_addr_base[3] & 0xffull)) << 16 | - ((octeon_bootinfo->mac_addr_base[4] & 0xffull)) << 8 | - (octeon_bootinfo->mac_addr_base[5] & 0xffull); - if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) max_port = 2; else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN68XX)) @@ -660,7 +723,6 @@ int __init octeon_prune_device_tree(void) } else { int phy_addr = cvmx_helper_board_get_mii_address(CVMX_HELPER_BOARD_MGMT_IPD_PORT + i); octeon_fdt_set_phy(mgmt, phy_addr); - octeon_fdt_set_mac_addr(mgmt, &mac_addr_base); } } } @@ -670,7 +732,7 @@ int __init octeon_prune_device_tree(void) int pip = fdt_path_offset(initial_boot_params, pip_path); if (pip >= 0) for (i = 0; i <= 4; i++) - octeon_fdt_pip_iface(pip, i, &mac_addr_base); + octeon_fdt_pip_iface(pip, i); } /* I2C */ diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index cd7101fb6227..64f852b063a8 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -43,8 +43,6 @@ #include <asm/octeon/cvmx-mio-defs.h> #include <asm/octeon/cvmx-rst-defs.h> -extern struct plat_smp_ops octeon_smp_ops; - #ifdef CONFIG_PCI extern void pci_console_init(const char *arg); #endif @@ -466,15 +464,25 @@ static void octeon_halt(void) static char __read_mostly octeon_system_type[80]; -static int __init init_octeon_system_type(void) +static void __init init_octeon_system_type(void) { - snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)", - cvmx_board_type_to_string(octeon_bootinfo->board_type), - octeon_model_get_string(read_c0_prid())); + char const *board_type; + + board_type = cvmx_board_type_to_string(octeon_bootinfo->board_type); + if (board_type == NULL) { + struct device_node *root; + int ret; + + root = of_find_node_by_path("/"); + ret = of_property_read_string(root, "model", &board_type); + of_node_put(root); + if (ret) + board_type = "Unsupported Board"; + } - return 0; + snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)", + board_type, octeon_model_get_string(read_c0_prid())); } -early_initcall(init_octeon_system_type); /** * Return a string representing the system type @@ -492,8 +500,6 @@ const char *get_system_type(void) void octeon_user_io_init(void) { union octeon_cvmemctl cvmmemctl; - union cvmx_iob_fau_timeout fau_timeout; - union cvmx_pow_nw_tim nm_tim; /* Get the current settings for CP0_CVMMEMCTL_REG */ cvmmemctl.u64 = read_c0_cvmmemctl(); @@ -595,17 +601,27 @@ void octeon_user_io_init(void) CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128); - /* Set a default for the hardware timeouts */ - fau_timeout.u64 = 0; - fau_timeout.s.tout_val = 0xfff; - /* Disable tagwait FAU timeout */ - fau_timeout.s.tout_enb = 0; - cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_timeout.u64); + if (octeon_has_feature(OCTEON_FEATURE_FAU)) { + union cvmx_iob_fau_timeout fau_timeout; + + /* Set a default for the hardware timeouts */ + fau_timeout.u64 = 0; + fau_timeout.s.tout_val = 0xfff; + /* Disable tagwait FAU timeout */ + fau_timeout.s.tout_enb = 0; + cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_timeout.u64); + } - nm_tim.u64 = 0; - /* 4096 cycles */ - nm_tim.s.nw_tim = 3; - cvmx_write_csr(CVMX_POW_NW_TIM, nm_tim.u64); + if ((!OCTEON_IS_MODEL(OCTEON_CN68XX) && + !OCTEON_IS_MODEL(OCTEON_CN7XXX)) || + OCTEON_IS_MODEL(OCTEON_CN70XX)) { + union cvmx_pow_nw_tim nm_tim; + + nm_tim.u64 = 0; + /* 4096 cycles */ + nm_tim.s.nw_tim = 3; + cvmx_write_csr(CVMX_POW_NW_TIM, nm_tim.u64); + } write_octeon_c0_icacheerr(0); write_c0_derraddr1(0); @@ -637,9 +653,22 @@ void __init prom_init(void) sysinfo = cvmx_sysinfo_get(); memset(sysinfo, 0, sizeof(*sysinfo)); sysinfo->system_dram_size = octeon_bootinfo->dram_size << 20; - sysinfo->phy_mem_desc_ptr = - cvmx_phys_to_ptr(octeon_bootinfo->phy_mem_desc_addr); - sysinfo->core_mask = octeon_bootinfo->core_mask; + sysinfo->phy_mem_desc_addr = (u64)phys_to_virt(octeon_bootinfo->phy_mem_desc_addr); + + if ((octeon_bootinfo->major_version > 1) || + (octeon_bootinfo->major_version == 1 && + octeon_bootinfo->minor_version >= 4)) + cvmx_coremask_copy(&sysinfo->core_mask, + &octeon_bootinfo->ext_core_mask); + else + cvmx_coremask_set64(&sysinfo->core_mask, + octeon_bootinfo->core_mask); + + /* Some broken u-boot pass garbage in upper bits, clear them out */ + if (!OCTEON_IS_MODEL(OCTEON_CN78XX)) + for (i = 512; i < 1024; i++) + cvmx_coremask_clear_core(&sysinfo->core_mask, i); + sysinfo->exception_base_addr = octeon_bootinfo->exception_base_addr; sysinfo->cpu_clock_hz = octeon_bootinfo->eclock_hz; sysinfo->dram_data_rate_hz = octeon_bootinfo->dclock_hz * 2; @@ -867,7 +896,7 @@ void __init prom_init(void) #endif octeon_user_io_init(); - register_smp_ops(&octeon_smp_ops); + octeon_setup_smp(); } /* Exclude a single page from the regions obtained in plat_mem_setup. */ @@ -1079,6 +1108,7 @@ void __init prom_free_prom_memory(void) } } +void __init octeon_fill_mac_addresses(void); int octeon_prune_device_tree(void); extern const char __appended_dtb; @@ -1088,11 +1118,13 @@ void __init device_tree_init(void) { const void *fdt; bool do_prune; + bool fill_mac; #ifdef CONFIG_MIPS_ELF_APPENDED_DTB if (!fdt_check_header(&__appended_dtb)) { fdt = &__appended_dtb; do_prune = false; + fill_mac = true; pr_info("Using appended Device Tree.\n"); } else #endif @@ -1101,13 +1133,16 @@ void __init device_tree_init(void) if (fdt_check_header(fdt)) panic("Corrupt Device Tree passed to kernel."); do_prune = false; + fill_mac = false; pr_info("Using passed Device Tree.\n"); } else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { fdt = &__dtb_octeon_68xx_begin; do_prune = true; + fill_mac = true; } else { fdt = &__dtb_octeon_3xxx_begin; do_prune = true; + fill_mac = true; } initial_boot_params = (void *)fdt; @@ -1116,7 +1151,10 @@ void __init device_tree_init(void) octeon_prune_device_tree(); pr_info("Using internal Device Tree.\n"); } + if (fill_mac) + octeon_fill_mac_addresses(); unflatten_and_copy_device_tree(); + init_octeon_system_type(); } static int __initdata disable_octeon_edac_p; diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index 42412ba0f3bf..dff88aa7e377 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -30,25 +30,55 @@ uint64_t octeon_bootloader_entry_addr; EXPORT_SYMBOL(octeon_bootloader_entry_addr); #endif +static void octeon_icache_flush(void) +{ + asm volatile ("synci 0($0)\n"); +} + +static void (*octeon_message_functions[8])(void) = { + scheduler_ipi, + generic_smp_call_function_interrupt, + octeon_icache_flush, +}; + static irqreturn_t mailbox_interrupt(int irq, void *dev_id) { - const int coreid = cvmx_get_core_num(); - uint64_t action; + u64 mbox_clrx = CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()); + u64 action; + int i; + + /* + * Make sure the function array initialization remains + * correct. + */ + BUILD_BUG_ON(SMP_RESCHEDULE_YOURSELF != (1 << 0)); + BUILD_BUG_ON(SMP_CALL_FUNCTION != (1 << 1)); + BUILD_BUG_ON(SMP_ICACHE_FLUSH != (1 << 2)); + + /* + * Load the mailbox register to figure out what we're supposed + * to do. + */ + action = cvmx_read_csr(mbox_clrx); - /* Load the mailbox register to figure out what we're supposed to do */ - action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)) & 0xffff; + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + action &= 0xff; + else + action &= 0xffff; /* Clear the mailbox to clear the interrupt */ - cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action); + cvmx_write_csr(mbox_clrx, action); - if (action & SMP_CALL_FUNCTION) - generic_smp_call_function_interrupt(); - if (action & SMP_RESCHEDULE_YOURSELF) - scheduler_ipi(); + for (i = 0; i < ARRAY_SIZE(octeon_message_functions) && action;) { + if (action & 1) { + void (*fn)(void) = octeon_message_functions[i]; - /* Check if we've been told to flush the icache */ - if (action & SMP_ICACHE_FLUSH) - asm volatile ("synci 0($0)\n"); + if (fn) + fn(); + } + action >>= 1; + i++; + } return IRQ_HANDLED; } @@ -97,13 +127,15 @@ static void octeon_smp_hotplug_setup(void) #endif } -static void octeon_smp_setup(void) +static void __init octeon_smp_setup(void) { const int coreid = cvmx_get_core_num(); int cpus; int id; - int core_mask = octeon_get_boot_coremask(); + struct cvmx_sysinfo *sysinfo = cvmx_sysinfo_get(); + #ifdef CONFIG_HOTPLUG_CPU + int core_mask = octeon_get_boot_coremask(); unsigned int num_cores = cvmx_octeon_num_cores(); #endif @@ -119,7 +151,7 @@ static void octeon_smp_setup(void) /* The present CPUs get the lowest CPU numbers. */ cpus = 1; for (id = 0; id < NR_CPUS; id++) { - if ((id != coreid) && (core_mask & (1 << id))) { + if ((id != coreid) && cvmx_coremask_is_core_set(&sysinfo->core_mask, id)) { set_cpu_possible(cpus, true); set_cpu_present(cpus, true); __cpu_number_map[id] = cpus; @@ -196,7 +228,7 @@ static void octeon_init_secondary(void) * Callout to firmware before smp_init * */ -void octeon_prepare_cpus(unsigned int max_cpus) +static void __init octeon_prepare_cpus(unsigned int max_cpus) { /* * Only the low order mailbox bits are used for IPIs, leave @@ -242,7 +274,7 @@ static int octeon_cpu_disable(void) cpumask_clear_cpu(cpu, &cpu_callin_map); octeon_fixup_irqs(); - flush_cache_all(); + __flush_cache_all(); local_flush_tlb_all(); return 0; @@ -388,3 +420,92 @@ struct plat_smp_ops octeon_smp_ops = { .cpu_die = octeon_cpu_die, #endif }; + +static irqreturn_t octeon_78xx_reched_interrupt(int irq, void *dev_id) +{ + scheduler_ipi(); + return IRQ_HANDLED; +} + +static irqreturn_t octeon_78xx_call_function_interrupt(int irq, void *dev_id) +{ + generic_smp_call_function_interrupt(); + return IRQ_HANDLED; +} + +static irqreturn_t octeon_78xx_icache_flush_interrupt(int irq, void *dev_id) +{ + octeon_icache_flush(); + return IRQ_HANDLED; +} + +/* + * Callout to firmware before smp_init + */ +static void octeon_78xx_prepare_cpus(unsigned int max_cpus) +{ + if (request_irq(OCTEON_IRQ_MBOX0 + 0, + octeon_78xx_reched_interrupt, + IRQF_PERCPU | IRQF_NO_THREAD, "Scheduler", + octeon_78xx_reched_interrupt)) { + panic("Cannot request_irq for SchedulerIPI"); + } + if (request_irq(OCTEON_IRQ_MBOX0 + 1, + octeon_78xx_call_function_interrupt, + IRQF_PERCPU | IRQF_NO_THREAD, "SMP-Call", + octeon_78xx_call_function_interrupt)) { + panic("Cannot request_irq for SMP-Call"); + } + if (request_irq(OCTEON_IRQ_MBOX0 + 2, + octeon_78xx_icache_flush_interrupt, + IRQF_PERCPU | IRQF_NO_THREAD, "ICache-Flush", + octeon_78xx_icache_flush_interrupt)) { + panic("Cannot request_irq for ICache-Flush"); + } +} + +static void octeon_78xx_send_ipi_single(int cpu, unsigned int action) +{ + int i; + + for (i = 0; i < 8; i++) { + if (action & 1) + octeon_ciu3_mbox_send(cpu, i); + action >>= 1; + } +} + +static void octeon_78xx_send_ipi_mask(const struct cpumask *mask, + unsigned int action) +{ + unsigned int cpu; + + for_each_cpu(cpu, mask) + octeon_78xx_send_ipi_single(cpu, action); +} + +static struct plat_smp_ops octeon_78xx_smp_ops = { + .send_ipi_single = octeon_78xx_send_ipi_single, + .send_ipi_mask = octeon_78xx_send_ipi_mask, + .init_secondary = octeon_init_secondary, + .smp_finish = octeon_smp_finish, + .boot_secondary = octeon_boot_secondary, + .smp_setup = octeon_smp_setup, + .prepare_cpus = octeon_78xx_prepare_cpus, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = octeon_cpu_disable, + .cpu_die = octeon_cpu_die, +#endif +}; + +void __init octeon_setup_smp(void) +{ + struct plat_smp_ops *ops; + + if (octeon_has_feature(OCTEON_FEATURE_CIU3)) + ops = &octeon_78xx_smp_ops; + else + ops = &octeon_smp_ops; + + register_smp_ops(ops); +} diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig index 0db4eb319e0a..fad8e964f14c 100644 --- a/arch/mips/configs/bcm47xx_defconfig +++ b/arch/mips/configs/bcm47xx_defconfig @@ -23,7 +23,6 @@ CONFIG_IP_MROUTE=y CONFIG_IP_MROUTE_MULTIPLE_TABLES=y CONFIG_SYN_COOKIES=y CONFIG_TCP_CONG_ADVANCED=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_IPV6_MROUTE=y diff --git a/arch/mips/configs/bcm63xx_defconfig b/arch/mips/configs/bcm63xx_defconfig index 3fec26410f34..5599a9f1e3c6 100644 --- a/arch/mips/configs/bcm63xx_defconfig +++ b/arch/mips/configs/bcm63xx_defconfig @@ -44,6 +44,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set CONFIG_MTD=y +CONFIG_MTD_BCM63XX_PARTS=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index e070dac071c8..d20b09d77b53 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -62,7 +62,6 @@ CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m # CONFIG_INET_LRO is not set CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y diff --git a/arch/mips/configs/bmips_be_defconfig b/arch/mips/configs/bmips_be_defconfig index 24dcb90b0f64..acf7785c4cdb 100644 --- a/arch/mips/configs/bmips_be_defconfig +++ b/arch/mips/configs/bmips_be_defconfig @@ -36,6 +36,7 @@ CONFIG_DEVTMPFS_MOUNT=y CONFIG_PRINTK_TIME=y CONFIG_BRCMSTB_GISB_ARB=y CONFIG_MTD=y +CONFIG_MTD_BCM63XX_PARTS=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y diff --git a/arch/mips/configs/cavium_octeon_defconfig b/arch/mips/configs/cavium_octeon_defconfig index e57058d4ec22..dcac308cec39 100644 --- a/arch/mips/configs/cavium_octeon_defconfig +++ b/arch/mips/configs/cavium_octeon_defconfig @@ -119,14 +119,16 @@ CONFIG_SPI=y CONFIG_SPI_OCTEON=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y -# CONFIG_USB_SUPPORT is not set -CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y -CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y -CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB=m +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_HCD_PLATFORM=m +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_PLATFORM=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_STAGING=y CONFIG_OCTEON_ETHERNET=y +CONFIG_OCTEON_USB=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y @@ -152,6 +154,9 @@ CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MD5_OCTEON=y +CONFIG_CRYPTO_SHA1_OCTEON=m +CONFIG_CRYPTO_SHA256_OCTEON=m +CONFIG_CRYPTO_SHA512_OCTEON=m CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index ebc011c51e5a..2b6cb41d5715 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig @@ -30,7 +30,6 @@ CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index 6ba9ce9fcdd5..5d83ff755547 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -48,7 +48,6 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m # CONFIG_INET_LRO is not set CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 77e9f505f5e4..2b74aee320a1 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -43,7 +43,6 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig index a5e85e1ee5de..3019fce63cd3 100644 --- a/arch/mips/configs/jazz_defconfig +++ b/arch/mips/configs/jazz_defconfig @@ -34,7 +34,6 @@ CONFIG_IP_PIMSM_V2=y CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index d1f198b072a0..5da76e0e120f 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -71,7 +71,6 @@ CONFIG_TCP_CONG_ADVANCED=y CONFIG_TCP_CONG_BIC=y CONFIG_DEFAULT_BIC=y CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_TUNNEL=m CONFIG_IPV6_MULTIPLE_TABLES=y diff --git a/arch/mips/configs/ls1b_defconfig b/arch/mips/configs/loongson1b_defconfig index 1b2cc1fb26a1..c442f27685f4 100644 --- a/arch/mips/configs/ls1b_defconfig +++ b/arch/mips/configs/loongson1b_defconfig @@ -1,19 +1,17 @@ CONFIG_MACH_LOONGSON32=y CONFIG_PREEMPT=y # CONFIG_SECCOMP is not set -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_XZ=y CONFIG_SYSVIPC=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_NAMESPACES=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y # CONFIG_COMPAT_BRK is not set @@ -41,6 +39,12 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_LOONGSON1=y +CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_SCSI=m # CONFIG_SCSI_PROC_FS is not set @@ -48,7 +52,6 @@ CONFIG_BLK_DEV_SD=m # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_BROADCOM is not set -# CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set @@ -56,7 +59,6 @@ CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_SMSC is not set CONFIG_STMMAC_ETH=y -CONFIG_STMMAC_DA=y # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y @@ -69,18 +71,25 @@ CONFIG_LEGACY_PTY_COUNT=8 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_HW_RANDOM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIO_LOONGSON1=y # CONFIG_HWMON is not set # CONFIG_VGA_CONSOLE is not set -CONFIG_USB_HID=m CONFIG_HID_GENERIC=m +CONFIG_USB_HID=m CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_HCD_PLATFORM=y # CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=m CONFIG_USB_SERIAL=m CONFIG_USB_SERIAL_PL2303=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_LOONGSON1=y # CONFIG_IOMMU_SUPPORT is not set @@ -96,15 +105,21 @@ CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_ATIME_SUPPORT=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_ISO8859_1=m +CONFIG_DYNAMIC_DEBUG=y # CONFIG_ENABLE_WARN_DEPRECATED is not set # CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_DEBUG_FS=y CONFIG_MAGIC_SYSRQ=y # CONFIG_SCHED_DEBUG is not set # CONFIG_DEBUG_PREEMPT is not set # CONFIG_FTRACE is not set # CONFIG_EARLY_PRINTK is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_HW is not set diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 9b6926d6bb32..f3f60056bc27 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -51,7 +51,6 @@ CONFIG_INET_IPCOMP=m CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m diff --git a/arch/mips/configs/nlm_xlp_defconfig b/arch/mips/configs/nlm_xlp_defconfig index b3d1d37f85ea..b496c25fced6 100644 --- a/arch/mips/configs/nlm_xlp_defconfig +++ b/arch/mips/configs/nlm_xlp_defconfig @@ -95,7 +95,6 @@ CONFIG_TCP_CONG_YEAH=m CONFIG_TCP_CONG_ILLINOIS=m CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y -CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig index 3d8016d6cf3e..8e99ad807a57 100644 --- a/arch/mips/configs/nlm_xlr_defconfig +++ b/arch/mips/configs/nlm_xlr_defconfig @@ -75,7 +75,6 @@ CONFIG_TCP_CONG_YEAH=m CONFIG_TCP_CONG_ILLINOIS=m CONFIG_TCP_MD5SIG=y CONFIG_IPV6=y -CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 82db4e3e4cf1..c2b4e3f33a73 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -37,7 +37,6 @@ CONFIG_INET_XFRM_MODE_TRANSPORT=m CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index a0b8943c8f11..1c3bf9fe926f 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -60,6 +60,7 @@ EXPORT_SYMBOL(dec_kn_slot_size); int dec_tc_bus; DEFINE_SPINLOCK(ioasic_ssr_lock); +EXPORT_SYMBOL(ioasic_ssr_lock); volatile u32 *ioasic_base; diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index c7fe4d01e79c..9740066cc631 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -1,5 +1,6 @@ # MIPS headers generic-(CONFIG_GENERIC_CSUM) += checksum.h +generic-y += clkdev.h generic-y += cputime.h generic-y += current.h generic-y += dma-contiguous.h diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 867f924b05c7..6741673c92ca 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -235,6 +235,7 @@ .macro ld_b wd, off, base .set push .set mips32r2 + .set fp=64 .set msa ld.b $w\wd, \off(\base) .set pop @@ -243,6 +244,7 @@ .macro ld_h wd, off, base .set push .set mips32r2 + .set fp=64 .set msa ld.h $w\wd, \off(\base) .set pop @@ -251,6 +253,7 @@ .macro ld_w wd, off, base .set push .set mips32r2 + .set fp=64 .set msa ld.w $w\wd, \off(\base) .set pop @@ -268,6 +271,7 @@ .macro st_b wd, off, base .set push .set mips32r2 + .set fp=64 .set msa st.b $w\wd, \off(\base) .set pop @@ -276,6 +280,7 @@ .macro st_h wd, off, base .set push .set mips32r2 + .set fp=64 .set msa st.h $w\wd, \off(\base) .set pop @@ -284,6 +289,7 @@ .macro st_w wd, off, base .set push .set mips32r2 + .set fp=64 .set msa st.w $w\wd, \off(\base) .set pop @@ -298,21 +304,21 @@ .set pop .endm - .macro copy_u_w ws, n + .macro copy_s_w ws, n .set push .set mips32r2 .set fp=64 .set msa - copy_u.w $1, $w\ws[\n] + copy_s.w $1, $w\ws[\n] .set pop .endm - .macro copy_u_d ws, n + .macro copy_s_d ws, n .set push .set mips64r2 .set fp=64 .set msa - copy_u.d $1, $w\ws[\n] + copy_s.d $1, $w\ws[\n] .set pop .endm @@ -346,8 +352,8 @@ #define STH_MSA_INSN 0x5800081f #define STW_MSA_INSN 0x5800082f #define STD_MSA_INSN 0x5800083f -#define COPY_UW_MSA_INSN 0x58f00056 -#define COPY_UD_MSA_INSN 0x58f80056 +#define COPY_SW_MSA_INSN 0x58b00056 +#define COPY_SD_MSA_INSN 0x58b80056 #define INSERT_W_MSA_INSN 0x59300816 #define INSERT_D_MSA_INSN 0x59380816 #else @@ -361,8 +367,8 @@ #define STH_MSA_INSN 0x78000825 #define STW_MSA_INSN 0x78000826 #define STD_MSA_INSN 0x78000827 -#define COPY_UW_MSA_INSN 0x78f00059 -#define COPY_UD_MSA_INSN 0x78f80059 +#define COPY_SW_MSA_INSN 0x78b00059 +#define COPY_SD_MSA_INSN 0x78b80059 #define INSERT_W_MSA_INSN 0x79300819 #define INSERT_D_MSA_INSN 0x79380819 #endif @@ -393,7 +399,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word LDB_MSA_INSN | (\wd << 6) .set pop .endm @@ -402,7 +408,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word LDH_MSA_INSN | (\wd << 6) .set pop .endm @@ -411,7 +417,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word LDW_MSA_INSN | (\wd << 6) .set pop .endm @@ -420,7 +426,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word LDD_MSA_INSN | (\wd << 6) .set pop .endm @@ -429,7 +435,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word STB_MSA_INSN | (\wd << 6) .set pop .endm @@ -438,7 +444,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word STH_MSA_INSN | (\wd << 6) .set pop .endm @@ -447,7 +453,7 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word STW_MSA_INSN | (\wd << 6) .set pop .endm @@ -456,26 +462,26 @@ .set push .set noat SET_HARDFLOAT - addu $1, \base, \off + PTR_ADDU $1, \base, \off .word STD_MSA_INSN | (\wd << 6) .set pop .endm - .macro copy_u_w ws, n + .macro copy_s_w ws, n .set push .set noat SET_HARDFLOAT .insn - .word COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11) + .word COPY_SW_MSA_INSN | (\n << 16) | (\ws << 11) .set pop .endm - .macro copy_u_d ws, n + .macro copy_s_d ws, n .set push .set noat SET_HARDFLOAT .insn - .word COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11) + .word COPY_SD_MSA_INSN | (\n << 16) | (\ws << 11) .set pop .endm @@ -496,41 +502,52 @@ .endm #endif +#ifdef TOOLCHAIN_SUPPORTS_MSA +#define FPR_BASE_OFFS THREAD_FPR0 +#define FPR_BASE $1 +#else +#define FPR_BASE_OFFS 0 +#define FPR_BASE \thread +#endif + .macro msa_save_all thread - st_d 0, THREAD_FPR0, \thread - st_d 1, THREAD_FPR1, \thread - st_d 2, THREAD_FPR2, \thread - st_d 3, THREAD_FPR3, \thread - st_d 4, THREAD_FPR4, \thread - st_d 5, THREAD_FPR5, \thread - st_d 6, THREAD_FPR6, \thread - st_d 7, THREAD_FPR7, \thread - st_d 8, THREAD_FPR8, \thread - st_d 9, THREAD_FPR9, \thread - st_d 10, THREAD_FPR10, \thread - st_d 11, THREAD_FPR11, \thread - st_d 12, THREAD_FPR12, \thread - st_d 13, THREAD_FPR13, \thread - st_d 14, THREAD_FPR14, \thread - st_d 15, THREAD_FPR15, \thread - st_d 16, THREAD_FPR16, \thread - st_d 17, THREAD_FPR17, \thread - st_d 18, THREAD_FPR18, \thread - st_d 19, THREAD_FPR19, \thread - st_d 20, THREAD_FPR20, \thread - st_d 21, THREAD_FPR21, \thread - st_d 22, THREAD_FPR22, \thread - st_d 23, THREAD_FPR23, \thread - st_d 24, THREAD_FPR24, \thread - st_d 25, THREAD_FPR25, \thread - st_d 26, THREAD_FPR26, \thread - st_d 27, THREAD_FPR27, \thread - st_d 28, THREAD_FPR28, \thread - st_d 29, THREAD_FPR29, \thread - st_d 30, THREAD_FPR30, \thread - st_d 31, THREAD_FPR31, \thread .set push .set noat +#ifdef TOOLCHAIN_SUPPORTS_MSA + PTR_ADDU FPR_BASE, \thread, FPR_BASE_OFFS +#endif + st_d 0, THREAD_FPR0 - FPR_BASE_OFFS, FPR_BASE + st_d 1, THREAD_FPR1 - FPR_BASE_OFFS, FPR_BASE + st_d 2, THREAD_FPR2 - FPR_BASE_OFFS, FPR_BASE + st_d 3, THREAD_FPR3 - FPR_BASE_OFFS, FPR_BASE + st_d 4, THREAD_FPR4 - FPR_BASE_OFFS, FPR_BASE + st_d 5, THREAD_FPR5 - FPR_BASE_OFFS, FPR_BASE + st_d 6, THREAD_FPR6 - FPR_BASE_OFFS, FPR_BASE + st_d 7, THREAD_FPR7 - FPR_BASE_OFFS, FPR_BASE + st_d 8, THREAD_FPR8 - FPR_BASE_OFFS, FPR_BASE + st_d 9, THREAD_FPR9 - FPR_BASE_OFFS, FPR_BASE + st_d 10, THREAD_FPR10 - FPR_BASE_OFFS, FPR_BASE + st_d 11, THREAD_FPR11 - FPR_BASE_OFFS, FPR_BASE + st_d 12, THREAD_FPR12 - FPR_BASE_OFFS, FPR_BASE + st_d 13, THREAD_FPR13 - FPR_BASE_OFFS, FPR_BASE + st_d 14, THREAD_FPR14 - FPR_BASE_OFFS, FPR_BASE + st_d 15, THREAD_FPR15 - FPR_BASE_OFFS, FPR_BASE + st_d 16, THREAD_FPR16 - FPR_BASE_OFFS, FPR_BASE + st_d 17, THREAD_FPR17 - FPR_BASE_OFFS, FPR_BASE + st_d 18, THREAD_FPR18 - FPR_BASE_OFFS, FPR_BASE + st_d 19, THREAD_FPR19 - FPR_BASE_OFFS, FPR_BASE + st_d 20, THREAD_FPR20 - FPR_BASE_OFFS, FPR_BASE + st_d 21, THREAD_FPR21 - FPR_BASE_OFFS, FPR_BASE + st_d 22, THREAD_FPR22 - FPR_BASE_OFFS, FPR_BASE + st_d 23, THREAD_FPR23 - FPR_BASE_OFFS, FPR_BASE + st_d 24, THREAD_FPR24 - FPR_BASE_OFFS, FPR_BASE + st_d 25, THREAD_FPR25 - FPR_BASE_OFFS, FPR_BASE + st_d 26, THREAD_FPR26 - FPR_BASE_OFFS, FPR_BASE + st_d 27, THREAD_FPR27 - FPR_BASE_OFFS, FPR_BASE + st_d 28, THREAD_FPR28 - FPR_BASE_OFFS, FPR_BASE + st_d 29, THREAD_FPR29 - FPR_BASE_OFFS, FPR_BASE + st_d 30, THREAD_FPR30 - FPR_BASE_OFFS, FPR_BASE + st_d 31, THREAD_FPR31 - FPR_BASE_OFFS, FPR_BASE SET_HARDFLOAT _cfcmsa $1, MSA_CSR sw $1, THREAD_MSA_CSR(\thread) @@ -543,40 +560,46 @@ SET_HARDFLOAT lw $1, THREAD_MSA_CSR(\thread) _ctcmsa MSA_CSR, $1 - .set pop - ld_d 0, THREAD_FPR0, \thread - ld_d 1, THREAD_FPR1, \thread - ld_d 2, THREAD_FPR2, \thread - ld_d 3, THREAD_FPR3, \thread - ld_d 4, THREAD_FPR4, \thread - ld_d 5, THREAD_FPR5, \thread - ld_d 6, THREAD_FPR6, \thread - ld_d 7, THREAD_FPR7, \thread - ld_d 8, THREAD_FPR8, \thread - ld_d 9, THREAD_FPR9, \thread - ld_d 10, THREAD_FPR10, \thread - ld_d 11, THREAD_FPR11, \thread - ld_d 12, THREAD_FPR12, \thread - ld_d 13, THREAD_FPR13, \thread - ld_d 14, THREAD_FPR14, \thread - ld_d 15, THREAD_FPR15, \thread - ld_d 16, THREAD_FPR16, \thread - ld_d 17, THREAD_FPR17, \thread - ld_d 18, THREAD_FPR18, \thread - ld_d 19, THREAD_FPR19, \thread - ld_d 20, THREAD_FPR20, \thread - ld_d 21, THREAD_FPR21, \thread - ld_d 22, THREAD_FPR22, \thread - ld_d 23, THREAD_FPR23, \thread - ld_d 24, THREAD_FPR24, \thread - ld_d 25, THREAD_FPR25, \thread - ld_d 26, THREAD_FPR26, \thread - ld_d 27, THREAD_FPR27, \thread - ld_d 28, THREAD_FPR28, \thread - ld_d 29, THREAD_FPR29, \thread - ld_d 30, THREAD_FPR30, \thread - ld_d 31, THREAD_FPR31, \thread - .endm +#ifdef TOOLCHAIN_SUPPORTS_MSA + PTR_ADDU FPR_BASE, \thread, FPR_BASE_OFFS +#endif + ld_d 0, THREAD_FPR0 - FPR_BASE_OFFS, FPR_BASE + ld_d 1, THREAD_FPR1 - FPR_BASE_OFFS, FPR_BASE + ld_d 2, THREAD_FPR2 - FPR_BASE_OFFS, FPR_BASE + ld_d 3, THREAD_FPR3 - FPR_BASE_OFFS, FPR_BASE + ld_d 4, THREAD_FPR4 - FPR_BASE_OFFS, FPR_BASE + ld_d 5, THREAD_FPR5 - FPR_BASE_OFFS, FPR_BASE + ld_d 6, THREAD_FPR6 - FPR_BASE_OFFS, FPR_BASE + ld_d 7, THREAD_FPR7 - FPR_BASE_OFFS, FPR_BASE + ld_d 8, THREAD_FPR8 - FPR_BASE_OFFS, FPR_BASE + ld_d 9, THREAD_FPR9 - FPR_BASE_OFFS, FPR_BASE + ld_d 10, THREAD_FPR10 - FPR_BASE_OFFS, FPR_BASE + ld_d 11, THREAD_FPR11 - FPR_BASE_OFFS, FPR_BASE + ld_d 12, THREAD_FPR12 - FPR_BASE_OFFS, FPR_BASE + ld_d 13, THREAD_FPR13 - FPR_BASE_OFFS, FPR_BASE + ld_d 14, THREAD_FPR14 - FPR_BASE_OFFS, FPR_BASE + ld_d 15, THREAD_FPR15 - FPR_BASE_OFFS, FPR_BASE + ld_d 16, THREAD_FPR16 - FPR_BASE_OFFS, FPR_BASE + ld_d 17, THREAD_FPR17 - FPR_BASE_OFFS, FPR_BASE + ld_d 18, THREAD_FPR18 - FPR_BASE_OFFS, FPR_BASE + ld_d 19, THREAD_FPR19 - FPR_BASE_OFFS, FPR_BASE + ld_d 20, THREAD_FPR20 - FPR_BASE_OFFS, FPR_BASE + ld_d 21, THREAD_FPR21 - FPR_BASE_OFFS, FPR_BASE + ld_d 22, THREAD_FPR22 - FPR_BASE_OFFS, FPR_BASE + ld_d 23, THREAD_FPR23 - FPR_BASE_OFFS, FPR_BASE + ld_d 24, THREAD_FPR24 - FPR_BASE_OFFS, FPR_BASE + ld_d 25, THREAD_FPR25 - FPR_BASE_OFFS, FPR_BASE + ld_d 26, THREAD_FPR26 - FPR_BASE_OFFS, FPR_BASE + ld_d 27, THREAD_FPR27 - FPR_BASE_OFFS, FPR_BASE + ld_d 28, THREAD_FPR28 - FPR_BASE_OFFS, FPR_BASE + ld_d 29, THREAD_FPR29 - FPR_BASE_OFFS, FPR_BASE + ld_d 30, THREAD_FPR30 - FPR_BASE_OFFS, FPR_BASE + ld_d 31, THREAD_FPR31 - FPR_BASE_OFFS, FPR_BASE + .set pop + .endm + +#undef FPR_BASE_OFFS +#undef FPR_BASE .macro msa_init_upper wd #ifdef CONFIG_64BIT diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h index ce9666cf1499..fa57cef12a46 100644 --- a/arch/mips/include/asm/bitops.h +++ b/arch/mips/include/asm/bitops.h @@ -19,25 +19,10 @@ #include <asm/byteorder.h> /* sigh ... */ #include <asm/compiler.h> #include <asm/cpu-features.h> +#include <asm/llsc.h> #include <asm/sgidefs.h> #include <asm/war.h> -#if _MIPS_SZLONG == 32 -#define SZLONG_LOG 5 -#define SZLONG_MASK 31UL -#define __LL "ll " -#define __SC "sc " -#define __INS "ins " -#define __EXT "ext " -#elif _MIPS_SZLONG == 64 -#define SZLONG_LOG 6 -#define SZLONG_MASK 63UL -#define __LL "lld " -#define __SC "scd " -#define __INS "dins " -#define __EXT "dext " -#endif - /* * These are the "slower" versions of the functions and are in bitops.c. * These functions call raw_local_irq_{save,restore}(). diff --git a/arch/mips/include/asm/bitrev.h b/arch/mips/include/asm/bitrev.h new file mode 100644 index 000000000000..bc739a404ae3 --- /dev/null +++ b/arch/mips/include/asm/bitrev.h @@ -0,0 +1,30 @@ +#ifndef __MIPS_ASM_BITREV_H__ +#define __MIPS_ASM_BITREV_H__ + +#include <linux/swab.h> + +static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) +{ + u32 ret; + + asm("bitswap %0, %1" : "=r"(ret) : "r"(__swab32(x))); + return ret; +} + +static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x) +{ + u16 ret; + + asm("bitswap %0, %1" : "=r"(ret) : "r"(__swab16(x))); + return ret; +} + +static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x) +{ + u8 ret; + + asm("bitswap %0, %1" : "=r"(ret) : "r"(x)); + return ret; +} + +#endif /* __MIPS_ASM_BITREV_H__ */ diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h index 6d25ad33ec78..a92aee7b977a 100644 --- a/arch/mips/include/asm/bmips.h +++ b/arch/mips/include/asm/bmips.h @@ -88,6 +88,7 @@ extern unsigned long bmips_tp1_irqs; extern void bmips_ebase_setup(void); extern asmlinkage void plat_wired_tlb_setup(void); +extern void bmips_cpu_setup(void); static inline unsigned long bmips_read_zscm_reg(unsigned int offset) { diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index b603804caac5..9f67033961a6 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -144,4 +144,22 @@ static inline void plat_swiotlb_setup(void) {} #endif /* CONFIG_SWIOTLB */ +#ifdef CONFIG_USE_OF +/** + * plat_get_fdt() - Return a pointer to the platform's device tree blob + * + * This function provides a platform independent API to get a pointer to the + * flattened device tree blob. The interface between bootloader and kernel + * is not consistent across platforms so it is necessary to provide this + * API such that common startup code can locate the FDT. + * + * This is used by the KASLR code to get command line arguments and random + * seed from the device tree. Any platform wishing to use KASLR should + * provide this API and select SYS_SUPPORTS_RELOCATABLE. + * + * Return: Pointer to the flattened device tree blob. + */ +extern void *plat_get_fdt(void); +#endif /* CONFIG_USE_OF */ + #endif /* _ASM_BOOTINFO_H */ diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index 723229f4cf27..34ed22ec6c33 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h @@ -51,7 +51,6 @@ extern void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn); extern void __flush_dcache_page(struct page *page); -extern void __flush_icache_page(struct vm_area_struct *vma, struct page *page); #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 static inline void flush_dcache_page(struct page *page) @@ -77,11 +76,6 @@ static inline void flush_anon_page(struct vm_area_struct *vma, static inline void flush_icache_page(struct vm_area_struct *vma, struct page *page) { - if (!cpu_has_ic_fills_f_dc && (vma->vm_flags & VM_EXEC) && - Page_dcache_dirty(page)) { - __flush_icache_page(vma, page); - ClearPageDcacheDirty(page); - } } extern void (*flush_icache_range)(unsigned long start, unsigned long end); @@ -132,6 +126,7 @@ static inline void kunmap_noncoherent(void) static inline void flush_kernel_dcache_page(struct page *page) { BUG_ON(cpu_has_dc_aliases && PageHighMem(page)); + flush_dcache_page(page); } /* diff --git a/arch/mips/include/asm/cacheops.h b/arch/mips/include/asm/cacheops.h index c3212ff26723..8031fbc6b69a 100644 --- a/arch/mips/include/asm/cacheops.h +++ b/arch/mips/include/asm/cacheops.h @@ -21,6 +21,7 @@ #define Cache_I 0x00 #define Cache_D 0x01 #define Cache_T 0x02 +#define Cache_V 0x02 /* Loongson-3 */ #define Cache_S 0x03 #define Index_Writeback_Inv 0x00 @@ -107,4 +108,9 @@ */ #define Hit_Invalidate_I_Loongson2 (Cache_I | 0x00) +/* + * Loongson3-specific cacheops + */ +#define Index_Writeback_Inv_V (Cache_V | Index_Writeback_Inv) + #endif /* __ASM_CACHEOPS_H */ diff --git a/arch/mips/include/asm/clkdev.h b/arch/mips/include/asm/clkdev.h deleted file mode 100644 index 1b3ad7b09dc1..000000000000 --- a/arch/mips/include/asm/clkdev.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * based on arch/arm/include/asm/clkdev.h - * - * Copyright (C) 2008 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Helper for the clk API to assist looking up a struct clk. - */ -#ifndef __ASM_CLKDEV_H -#define __ASM_CLKDEV_H - -#include <linux/slab.h> - -#ifndef CONFIG_COMMON_CLK -#define __clk_get(clk) ({ 1; }) -#define __clk_put(clk) do { } while (0) -#endif - -static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) -{ - return kzalloc(size, GFP_KERNEL); -} - -#endif diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index eeec8c8e2da2..e6f19fc61bf2 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -35,6 +35,9 @@ #ifndef cpu_has_htw #define cpu_has_htw (cpu_data[0].options & MIPS_CPU_HTW) #endif +#ifndef cpu_has_ldpte +#define cpu_has_ldpte (cpu_data[0].options & MIPS_CPU_LDPTE) +#endif #ifndef cpu_has_rixiex #define cpu_has_rixiex (cpu_data[0].options & MIPS_CPU_RIXIEX) #endif @@ -117,6 +120,21 @@ #ifndef kernel_uses_llsc #define kernel_uses_llsc cpu_has_llsc #endif +#ifndef cpu_has_guestctl0ext +#define cpu_has_guestctl0ext (cpu_data[0].options & MIPS_CPU_GUESTCTL0EXT) +#endif +#ifndef cpu_has_guestctl1 +#define cpu_has_guestctl1 (cpu_data[0].options & MIPS_CPU_GUESTCTL1) +#endif +#ifndef cpu_has_guestctl2 +#define cpu_has_guestctl2 (cpu_data[0].options & MIPS_CPU_GUESTCTL2) +#endif +#ifndef cpu_has_guestid +#define cpu_has_guestid (cpu_data[0].options & MIPS_CPU_GUESTID) +#endif +#ifndef cpu_has_drg +#define cpu_has_drg (cpu_data[0].options & MIPS_CPU_DRG) +#endif #ifndef cpu_has_mips16 #define cpu_has_mips16 (cpu_data[0].ases & MIPS_ASE_MIPS16) #endif @@ -142,8 +160,14 @@ # endif #endif +#ifndef cpu_has_lpa +#define cpu_has_lpa (cpu_data[0].options & MIPS_CPU_LPA) +#endif +#ifndef cpu_has_mvh +#define cpu_has_mvh (cpu_data[0].options & MIPS_CPU_MVH) +#endif #ifndef cpu_has_xpa -#define cpu_has_xpa (cpu_data[0].options & MIPS_CPU_XPA) +#define cpu_has_xpa (cpu_has_lpa && cpu_has_mvh) #endif #ifndef cpu_has_vtag_icache #define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG) @@ -307,10 +331,18 @@ #define cpu_has_dsp2 (cpu_data[0].ases & MIPS_ASE_DSP2P) #endif +#ifndef cpu_has_dsp3 +#define cpu_has_dsp3 (cpu_data[0].ases & MIPS_ASE_DSP3) +#endif + #ifndef cpu_has_mipsmt #define cpu_has_mipsmt (cpu_data[0].ases & MIPS_ASE_MIPSMT) #endif +#ifndef cpu_has_vp +#define cpu_has_vp (cpu_data[0].options & MIPS_CPU_VP) +#endif + #ifndef cpu_has_userlocal #define cpu_has_userlocal (cpu_data[0].options & MIPS_CPU_ULRI) #endif @@ -421,4 +453,107 @@ #define cpu_has_nan_2008 (cpu_data[0].options & MIPS_CPU_NAN_2008) #endif +#ifndef cpu_has_ebase_wg +# define cpu_has_ebase_wg (cpu_data[0].options & MIPS_CPU_EBASE_WG) +#endif + +#ifndef cpu_has_badinstr +# define cpu_has_badinstr (cpu_data[0].options & MIPS_CPU_BADINSTR) +#endif + +#ifndef cpu_has_badinstrp +# define cpu_has_badinstrp (cpu_data[0].options & MIPS_CPU_BADINSTRP) +#endif + +#ifndef cpu_has_contextconfig +# define cpu_has_contextconfig (cpu_data[0].options & MIPS_CPU_CTXTC) +#endif + +#ifndef cpu_has_perf +# define cpu_has_perf (cpu_data[0].options & MIPS_CPU_PERF) +#endif + +/* + * Guest capabilities + */ +#ifndef cpu_guest_has_conf1 +#define cpu_guest_has_conf1 (cpu_data[0].guest.conf & (1 << 1)) +#endif +#ifndef cpu_guest_has_conf2 +#define cpu_guest_has_conf2 (cpu_data[0].guest.conf & (1 << 2)) +#endif +#ifndef cpu_guest_has_conf3 +#define cpu_guest_has_conf3 (cpu_data[0].guest.conf & (1 << 3)) +#endif +#ifndef cpu_guest_has_conf4 +#define cpu_guest_has_conf4 (cpu_data[0].guest.conf & (1 << 4)) +#endif +#ifndef cpu_guest_has_conf5 +#define cpu_guest_has_conf5 (cpu_data[0].guest.conf & (1 << 5)) +#endif +#ifndef cpu_guest_has_conf6 +#define cpu_guest_has_conf6 (cpu_data[0].guest.conf & (1 << 6)) +#endif +#ifndef cpu_guest_has_conf7 +#define cpu_guest_has_conf7 (cpu_data[0].guest.conf & (1 << 7)) +#endif +#ifndef cpu_guest_has_fpu +#define cpu_guest_has_fpu (cpu_data[0].guest.options & MIPS_CPU_FPU) +#endif +#ifndef cpu_guest_has_watch +#define cpu_guest_has_watch (cpu_data[0].guest.options & MIPS_CPU_WATCH) +#endif +#ifndef cpu_guest_has_contextconfig +#define cpu_guest_has_contextconfig (cpu_data[0].guest.options & MIPS_CPU_CTXTC) +#endif +#ifndef cpu_guest_has_segments +#define cpu_guest_has_segments (cpu_data[0].guest.options & MIPS_CPU_SEGMENTS) +#endif +#ifndef cpu_guest_has_badinstr +#define cpu_guest_has_badinstr (cpu_data[0].guest.options & MIPS_CPU_BADINSTR) +#endif +#ifndef cpu_guest_has_badinstrp +#define cpu_guest_has_badinstrp (cpu_data[0].guest.options & MIPS_CPU_BADINSTRP) +#endif +#ifndef cpu_guest_has_htw +#define cpu_guest_has_htw (cpu_data[0].guest.options & MIPS_CPU_HTW) +#endif +#ifndef cpu_guest_has_msa +#define cpu_guest_has_msa (cpu_data[0].guest.ases & MIPS_ASE_MSA) +#endif +#ifndef cpu_guest_has_kscr +#define cpu_guest_has_kscr(n) (cpu_data[0].guest.kscratch_mask & (1u << (n))) +#endif +#ifndef cpu_guest_has_rw_llb +#define cpu_guest_has_rw_llb (cpu_has_mips_r6 || (cpu_data[0].guest.options & MIPS_CPU_RW_LLB)) +#endif +#ifndef cpu_guest_has_perf +#define cpu_guest_has_perf (cpu_data[0].guest.options & MIPS_CPU_PERF) +#endif +#ifndef cpu_guest_has_maar +#define cpu_guest_has_maar (cpu_data[0].guest.options & MIPS_CPU_MAAR) +#endif + +/* + * Guest dynamic capabilities + */ +#ifndef cpu_guest_has_dyn_fpu +#define cpu_guest_has_dyn_fpu (cpu_data[0].guest.options_dyn & MIPS_CPU_FPU) +#endif +#ifndef cpu_guest_has_dyn_watch +#define cpu_guest_has_dyn_watch (cpu_data[0].guest.options_dyn & MIPS_CPU_WATCH) +#endif +#ifndef cpu_guest_has_dyn_contextconfig +#define cpu_guest_has_dyn_contextconfig (cpu_data[0].guest.options_dyn & MIPS_CPU_CTXTC) +#endif +#ifndef cpu_guest_has_dyn_perf +#define cpu_guest_has_dyn_perf (cpu_data[0].guest.options_dyn & MIPS_CPU_PERF) +#endif +#ifndef cpu_guest_has_dyn_msa +#define cpu_guest_has_dyn_msa (cpu_data[0].guest.ases_dyn & MIPS_ASE_MSA) +#endif +#ifndef cpu_guest_has_dyn_maar +#define cpu_guest_has_dyn_maar (cpu_data[0].guest.options_dyn & MIPS_CPU_MAAR) +#endif + #endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index af12c1f9f1a8..edbe2734a1bf 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h @@ -28,6 +28,15 @@ struct cache_desc { unsigned char flags; /* Flags describing cache properties */ }; +struct guest_info { + unsigned long ases; + unsigned long ases_dyn; + unsigned long long options; + unsigned long long options_dyn; + u8 conf; + u8 kscratch_mask; +}; + /* * Flag definitions */ @@ -40,6 +49,9 @@ struct cache_desc { struct cpuinfo_mips { unsigned long asid_cache; +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + unsigned long asid_mask; +#endif /* * Capability and feature descriptor structure for MIPS CPU @@ -60,6 +72,7 @@ struct cpuinfo_mips { int tlbsizeftlbways; struct cache_desc icache; /* Primary I-cache */ struct cache_desc dcache; /* Primary D or combined I/D cache */ + struct cache_desc vcache; /* Victim cache, between pcache and scache */ struct cache_desc scache; /* Secondary cache */ struct cache_desc tcache; /* Tertiary/split secondary cache */ int srsets; /* Shadow register sets */ @@ -68,7 +81,7 @@ struct cpuinfo_mips { #ifdef CONFIG_64BIT int vmbits; /* Virtual memory size in bits */ #endif -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) /* * There is not necessarily a 1:1 mapping of VPE num to CPU number * in particular on multi-core systems. @@ -91,6 +104,11 @@ struct cpuinfo_mips { * htw_start/htw_stop calls */ unsigned int htw_seq; + + /* VZ & Guest features */ + struct guest_info guest; + unsigned int gtoffset_mask; + unsigned int guestid_mask; } __attribute__((aligned(SMP_CACHE_BYTES))); extern struct cpuinfo_mips cpu_data[]; @@ -125,10 +143,31 @@ struct proc_cpuinfo_notifier_args { unsigned long n; }; -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) # define cpu_vpe_id(cpuinfo) ((cpuinfo)->vpe_id) #else # define cpu_vpe_id(cpuinfo) ({ (void)cpuinfo; 0; }) #endif +static inline unsigned long cpu_asid_inc(void) +{ + return 1 << CONFIG_MIPS_ASID_SHIFT; +} + +static inline unsigned long cpu_asid_mask(struct cpuinfo_mips *cpuinfo) +{ +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + return cpuinfo->asid_mask; +#endif + return ((1 << CONFIG_MIPS_ASID_BITS) - 1) << CONFIG_MIPS_ASID_SHIFT; +} + +static inline void set_cpu_asid_mask(struct cpuinfo_mips *cpuinfo, + unsigned long asid_mask) +{ +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + cpuinfo->asid_mask = asid_mask; +#endif +} + #endif /* __ASM_CPU_INFO_H */ diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h index abee2bfd10dc..fbe1881f28fc 100644 --- a/arch/mips/include/asm/cpu-type.h +++ b/arch/mips/include/asm/cpu-type.h @@ -77,8 +77,13 @@ static inline int __pure __get_cpu_type(const int cpu_type) */ #endif +#ifdef CONFIG_SYS_HAS_CPU_MIPS32_R6 + case CPU_M6250: +#endif + #ifdef CONFIG_SYS_HAS_CPU_MIPS64_R6 case CPU_I6400: + case CPU_P6600: #endif #ifdef CONFIG_SYS_HAS_CPU_R3000 diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index a97ca97285ec..f672df8b26d0 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -42,6 +42,7 @@ #define PRID_COMP_LEXRA 0x0b0000 #define PRID_COMP_NETLOGIC 0x0c0000 #define PRID_COMP_CAVIUM 0x0d0000 +#define PRID_COMP_LOONGSON 0x140000 #define PRID_COMP_INGENIC_D0 0xd00000 /* JZ4740, JZ4750 */ #define PRID_COMP_INGENIC_D1 0xd10000 /* JZ4770, JZ4775 */ #define PRID_COMP_INGENIC_E1 0xe10000 /* JZ4780 */ @@ -118,9 +119,11 @@ #define PRID_IMP_INTERAPTIV_MP 0xa100 #define PRID_IMP_PROAPTIV_UP 0xa200 #define PRID_IMP_PROAPTIV_MP 0xa300 +#define PRID_IMP_P6600 0xa400 #define PRID_IMP_M5150 0xa700 #define PRID_IMP_P5600 0xa800 #define PRID_IMP_I6400 0xa900 +#define PRID_IMP_M6250 0xab00 /* * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE @@ -169,6 +172,8 @@ #define PRID_IMP_CAVIUM_CNF71XX 0x9400 #define PRID_IMP_CAVIUM_CN78XX 0x9500 #define PRID_IMP_CAVIUM_CN70XX 0x9600 +#define PRID_IMP_CAVIUM_CN73XX 0x9700 +#define PRID_IMP_CAVIUM_CNF75XX 0x9800 /* * These are the PRID's for when 23:16 == PRID_COMP_INGENIC_* @@ -237,9 +242,10 @@ #define PRID_REV_LOONGSON1B 0x0020 #define PRID_REV_LOONGSON2E 0x0002 #define PRID_REV_LOONGSON2F 0x0003 -#define PRID_REV_LOONGSON3A 0x0005 +#define PRID_REV_LOONGSON3A_R1 0x0005 #define PRID_REV_LOONGSON3B_R1 0x0006 #define PRID_REV_LOONGSON3B_R2 0x0007 +#define PRID_REV_LOONGSON3A_R2 0x0008 /* * Older processors used to encode processor version and revision in two @@ -307,8 +313,8 @@ enum cpu_type_enum { CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K, CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, - CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150, - CPU_I6400, + CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, + CPU_M5150, CPU_I6400, CPU_P6600, CPU_M6250, /* * MIPS64 class processors @@ -346,48 +352,68 @@ enum cpu_type_enum { MIPS_CPU_ISA_M64R6) /* + * Private version of BIT_ULL() to escape include file recursion hell. + * We soon will have to switch to another mechanism that will work with + * more than 64 bits anyway. + */ +#define MBIT_ULL(bit) (1ULL << (bit)) + +/* * CPU Option encodings */ -#define MIPS_CPU_TLB 0x00000001ull /* CPU has TLB */ -#define MIPS_CPU_4KEX 0x00000002ull /* "R4K" exception model */ -#define MIPS_CPU_3K_CACHE 0x00000004ull /* R3000-style caches */ -#define MIPS_CPU_4K_CACHE 0x00000008ull /* R4000-style caches */ -#define MIPS_CPU_TX39_CACHE 0x00000010ull /* TX3900-style caches */ -#define MIPS_CPU_FPU 0x00000020ull /* CPU has FPU */ -#define MIPS_CPU_32FPR 0x00000040ull /* 32 dbl. prec. FP registers */ -#define MIPS_CPU_COUNTER 0x00000080ull /* Cycle count/compare */ -#define MIPS_CPU_WATCH 0x00000100ull /* watchpoint registers */ -#define MIPS_CPU_DIVEC 0x00000200ull /* dedicated interrupt vector */ -#define MIPS_CPU_VCE 0x00000400ull /* virt. coherence conflict possible */ -#define MIPS_CPU_CACHE_CDEX_P 0x00000800ull /* Create_Dirty_Exclusive CACHE op */ -#define MIPS_CPU_CACHE_CDEX_S 0x00001000ull /* ... same for seconary cache ... */ -#define MIPS_CPU_MCHECK 0x00002000ull /* Machine check exception */ -#define MIPS_CPU_EJTAG 0x00004000ull /* EJTAG exception */ -#define MIPS_CPU_NOFPUEX 0x00008000ull /* no FPU exception */ -#define MIPS_CPU_LLSC 0x00010000ull /* CPU has ll/sc instructions */ -#define MIPS_CPU_INCLUSIVE_CACHES 0x00020000ull /* P-cache subset enforced */ -#define MIPS_CPU_PREFETCH 0x00040000ull /* CPU has usable prefetch */ -#define MIPS_CPU_VINT 0x00080000ull /* CPU supports MIPSR2 vectored interrupts */ -#define MIPS_CPU_VEIC 0x00100000ull /* CPU supports MIPSR2 external interrupt controller mode */ -#define MIPS_CPU_ULRI 0x00200000ull /* CPU has ULRI feature */ -#define MIPS_CPU_PCI 0x00400000ull /* CPU has Perf Ctr Int indicator */ -#define MIPS_CPU_RIXI 0x00800000ull /* CPU has TLB Read/eXec Inhibit */ -#define MIPS_CPU_MICROMIPS 0x01000000ull /* CPU has microMIPS capability */ -#define MIPS_CPU_TLBINV 0x02000000ull /* CPU supports TLBINV/F */ -#define MIPS_CPU_SEGMENTS 0x04000000ull /* CPU supports Segmentation Control registers */ -#define MIPS_CPU_EVA 0x80000000ull /* CPU supports Enhanced Virtual Addressing */ -#define MIPS_CPU_HTW 0x100000000ull /* CPU support Hardware Page Table Walker */ -#define MIPS_CPU_RIXIEX 0x200000000ull /* CPU has unique exception codes for {Read, Execute}-Inhibit exceptions */ -#define MIPS_CPU_MAAR 0x400000000ull /* MAAR(I) registers are present */ -#define MIPS_CPU_FRE 0x800000000ull /* FRE & UFE bits implemented */ -#define MIPS_CPU_RW_LLB 0x1000000000ull /* LLADDR/LLB writes are allowed */ -#define MIPS_CPU_XPA 0x2000000000ull /* CPU supports Extended Physical Addressing */ -#define MIPS_CPU_CDMM 0x4000000000ull /* CPU has Common Device Memory Map */ -#define MIPS_CPU_BP_GHIST 0x8000000000ull /* R12K+ Branch Prediction Global History */ -#define MIPS_CPU_SP 0x10000000000ull /* Small (1KB) page support */ -#define MIPS_CPU_FTLB 0x20000000000ull /* CPU has Fixed-page-size TLB */ -#define MIPS_CPU_NAN_LEGACY 0x40000000000ull /* Legacy NaN implemented */ -#define MIPS_CPU_NAN_2008 0x80000000000ull /* 2008 NaN implemented */ +#define MIPS_CPU_TLB MBIT_ULL( 0) /* CPU has TLB */ +#define MIPS_CPU_4KEX MBIT_ULL( 1) /* "R4K" exception model */ +#define MIPS_CPU_3K_CACHE MBIT_ULL( 2) /* R3000-style caches */ +#define MIPS_CPU_4K_CACHE MBIT_ULL( 3) /* R4000-style caches */ +#define MIPS_CPU_TX39_CACHE MBIT_ULL( 4) /* TX3900-style caches */ +#define MIPS_CPU_FPU MBIT_ULL( 5) /* CPU has FPU */ +#define MIPS_CPU_32FPR MBIT_ULL( 6) /* 32 dbl. prec. FP registers */ +#define MIPS_CPU_COUNTER MBIT_ULL( 7) /* Cycle count/compare */ +#define MIPS_CPU_WATCH MBIT_ULL( 8) /* watchpoint registers */ +#define MIPS_CPU_DIVEC MBIT_ULL( 9) /* dedicated interrupt vector */ +#define MIPS_CPU_VCE MBIT_ULL(10) /* virt. coherence conflict possible */ +#define MIPS_CPU_CACHE_CDEX_P MBIT_ULL(11) /* Create_Dirty_Exclusive CACHE op */ +#define MIPS_CPU_CACHE_CDEX_S MBIT_ULL(12) /* ... same for seconary cache ... */ +#define MIPS_CPU_MCHECK MBIT_ULL(13) /* Machine check exception */ +#define MIPS_CPU_EJTAG MBIT_ULL(14) /* EJTAG exception */ +#define MIPS_CPU_NOFPUEX MBIT_ULL(15) /* no FPU exception */ +#define MIPS_CPU_LLSC MBIT_ULL(16) /* CPU has ll/sc instructions */ +#define MIPS_CPU_INCLUSIVE_CACHES MBIT_ULL(17) /* P-cache subset enforced */ +#define MIPS_CPU_PREFETCH MBIT_ULL(18) /* CPU has usable prefetch */ +#define MIPS_CPU_VINT MBIT_ULL(19) /* CPU supports MIPSR2 vectored interrupts */ +#define MIPS_CPU_VEIC MBIT_ULL(20) /* CPU supports MIPSR2 external interrupt controller mode */ +#define MIPS_CPU_ULRI MBIT_ULL(21) /* CPU has ULRI feature */ +#define MIPS_CPU_PCI MBIT_ULL(22) /* CPU has Perf Ctr Int indicator */ +#define MIPS_CPU_RIXI MBIT_ULL(23) /* CPU has TLB Read/eXec Inhibit */ +#define MIPS_CPU_MICROMIPS MBIT_ULL(24) /* CPU has microMIPS capability */ +#define MIPS_CPU_TLBINV MBIT_ULL(25) /* CPU supports TLBINV/F */ +#define MIPS_CPU_SEGMENTS MBIT_ULL(26) /* CPU supports Segmentation Control registers */ +#define MIPS_CPU_EVA MBIT_ULL(27) /* CPU supports Enhanced Virtual Addressing */ +#define MIPS_CPU_HTW MBIT_ULL(28) /* CPU support Hardware Page Table Walker */ +#define MIPS_CPU_RIXIEX MBIT_ULL(29) /* CPU has unique exception codes for {Read, Execute}-Inhibit exceptions */ +#define MIPS_CPU_MAAR MBIT_ULL(30) /* MAAR(I) registers are present */ +#define MIPS_CPU_FRE MBIT_ULL(31) /* FRE & UFE bits implemented */ +#define MIPS_CPU_RW_LLB MBIT_ULL(32) /* LLADDR/LLB writes are allowed */ +#define MIPS_CPU_LPA MBIT_ULL(33) /* CPU supports Large Physical Addressing */ +#define MIPS_CPU_CDMM MBIT_ULL(34) /* CPU has Common Device Memory Map */ +#define MIPS_CPU_BP_GHIST MBIT_ULL(35) /* R12K+ Branch Prediction Global History */ +#define MIPS_CPU_SP MBIT_ULL(36) /* Small (1KB) page support */ +#define MIPS_CPU_FTLB MBIT_ULL(37) /* CPU has Fixed-page-size TLB */ +#define MIPS_CPU_NAN_LEGACY MBIT_ULL(38) /* Legacy NaN implemented */ +#define MIPS_CPU_NAN_2008 MBIT_ULL(39) /* 2008 NaN implemented */ +#define MIPS_CPU_VP MBIT_ULL(40) /* MIPSr6 Virtual Processors (multi-threading) */ +#define MIPS_CPU_LDPTE MBIT_ULL(41) /* CPU has ldpte/lddir instructions */ +#define MIPS_CPU_MVH MBIT_ULL(42) /* CPU supports MFHC0/MTHC0 */ +#define MIPS_CPU_EBASE_WG MBIT_ULL(43) /* CPU has EBase.WG */ +#define MIPS_CPU_BADINSTR MBIT_ULL(44) /* CPU has BadInstr register */ +#define MIPS_CPU_BADINSTRP MBIT_ULL(45) /* CPU has BadInstrP register */ +#define MIPS_CPU_CTXTC MBIT_ULL(46) /* CPU has [X]ConfigContext registers */ +#define MIPS_CPU_PERF MBIT_ULL(47) /* CPU has MIPS performance counters */ +#define MIPS_CPU_GUESTCTL0EXT MBIT_ULL(48) /* CPU has VZ GuestCtl0Ext register */ +#define MIPS_CPU_GUESTCTL1 MBIT_ULL(49) /* CPU has VZ GuestCtl1 register */ +#define MIPS_CPU_GUESTCTL2 MBIT_ULL(50) /* CPU has VZ GuestCtl2 register */ +#define MIPS_CPU_GUESTID MBIT_ULL(51) /* CPU uses VZ ASE GuestID feature */ +#define MIPS_CPU_DRG MBIT_ULL(52) /* CPU has VZ Direct Root to Guest (DRG) */ /* * CPU ASE encodings @@ -401,5 +427,6 @@ enum cpu_type_enum { #define MIPS_ASE_DSP2P 0x00000040 /* Signal Processing ASE Rev 2 */ #define MIPS_ASE_VZ 0x00000080 /* Virtualization ASE */ #define MIPS_ASE_MSA 0x00000100 /* MIPS SIMD Architecture */ +#define MIPS_ASE_DSP3 0x00000200 /* Signal Processing ASE Rev 3*/ #endif /* _ASM_CPU_H */ diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index e090fc388e02..f5f45717968e 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -111,6 +111,11 @@ #define R_MIPS_CALLHI16 30 #define R_MIPS_CALLLO16 31 /* + * Introduced for MIPSr6. + */ +#define R_MIPS_PC21_S2 60 +#define R_MIPS_PC26_S2 61 +/* * This range is reserved for vendor specific relocations. */ #define R_MIPS_LOVENDOR 100 @@ -170,16 +175,14 @@ #define SHF_MIPS_NAMES 0x02000000 #define SHF_MIPS_NODUPES 0x01000000 -#ifndef ELF_ARCH -/* ELF register definitions */ -#define ELF_NGREG 45 -#define ELF_NFPREG 33 - -typedef unsigned long elf_greg_t; -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -typedef double elf_fpreg_t; -typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; +#define MIPS_ABI_FP_ANY 0 /* FP ABI doesn't matter */ +#define MIPS_ABI_FP_DOUBLE 1 /* -mdouble-float */ +#define MIPS_ABI_FP_SINGLE 2 /* -msingle-float */ +#define MIPS_ABI_FP_SOFT 3 /* -msoft-float */ +#define MIPS_ABI_FP_OLD_64 4 /* -mips32r2 -mfp64 */ +#define MIPS_ABI_FP_XX 5 /* -mfpxx */ +#define MIPS_ABI_FP_64 6 /* -mips32r2 -mfp64 */ +#define MIPS_ABI_FP_64A 7 /* -mips32r2 -mfp64 -mno-odd-spreg */ struct mips_elf_abiflags_v0 { uint16_t version; /* Version of flags structure */ @@ -196,16 +199,54 @@ struct mips_elf_abiflags_v0 { uint32_t flags2; }; -#define MIPS_ABI_FP_ANY 0 /* FP ABI doesn't matter */ -#define MIPS_ABI_FP_DOUBLE 1 /* -mdouble-float */ -#define MIPS_ABI_FP_SINGLE 2 /* -msingle-float */ -#define MIPS_ABI_FP_SOFT 3 /* -msoft-float */ -#define MIPS_ABI_FP_OLD_64 4 /* -mips32r2 -mfp64 */ -#define MIPS_ABI_FP_XX 5 /* -mfpxx */ -#define MIPS_ABI_FP_64 6 /* -mips32r2 -mfp64 */ -#define MIPS_ABI_FP_64A 7 /* -mips32r2 -mfp64 -mno-odd-spreg */ +#ifndef ELF_ARCH +/* ELF register definitions */ +#define ELF_NGREG 45 +#define ELF_NFPREG 33 + +typedef unsigned long elf_greg_t; +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef double elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #ifdef CONFIG_32BIT +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch elfo32_check_arch + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 + +#endif /* CONFIG_32BIT */ + +#ifdef CONFIG_64BIT +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch elfn64_check_arch + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS64 + +#endif /* CONFIG_64BIT */ + +/* + * These are used to set parameters in the core dumps. + */ +#ifdef __MIPSEB__ +#define ELF_DATA ELFDATA2MSB +#elif defined(__MIPSEL__) +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_MIPS + +#endif /* !defined(ELF_ARCH) */ /* * In order to be sure that we don't attempt to execute an O32 binary which @@ -219,10 +260,15 @@ struct mips_elf_abiflags_v0 { # define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64 #endif +#define mips_elf_check_machine(x) ((x)->e_machine == EM_MIPS) + +#define vmcore_elf32_check_arch mips_elf_check_machine +#define vmcore_elf64_check_arch mips_elf_check_machine + /* - * This is used to ensure we don't load something for the wrong architecture. + * Return non-zero if HDR identifies an o32 ELF binary. */ -#define elf_check_arch(hdr) \ +#define elfo32_check_arch(hdr) \ ({ \ int __res = 1; \ struct elfhdr *__h = (hdr); \ @@ -243,17 +289,9 @@ struct mips_elf_abiflags_v0 { }) /* - * These are used to set parameters in the core dumps. - */ -#define ELF_CLASS ELFCLASS32 - -#endif /* CONFIG_32BIT */ - -#ifdef CONFIG_64BIT -/* - * This is used to ensure we don't load something for the wrong architecture. + * Return non-zero if HDR identifies an n64 ELF binary. */ -#define elf_check_arch(hdr) \ +#define elfn64_check_arch(hdr) \ ({ \ int __res = 1; \ struct elfhdr *__h = (hdr); \ @@ -267,28 +305,23 @@ struct mips_elf_abiflags_v0 { }) /* - * These are used to set parameters in the core dumps. + * Return non-zero if HDR identifies an n32 ELF binary. */ -#define ELF_CLASS ELFCLASS64 - -#endif /* CONFIG_64BIT */ - -/* - * These are used to set parameters in the core dumps. - */ -#ifdef __MIPSEB__ -#define ELF_DATA ELFDATA2MSB -#elif defined(__MIPSEL__) -#define ELF_DATA ELFDATA2LSB -#endif -#define ELF_ARCH EM_MIPS - -#endif /* !defined(ELF_ARCH) */ - -#define mips_elf_check_machine(x) ((x)->e_machine == EM_MIPS) - -#define vmcore_elf32_check_arch mips_elf_check_machine -#define vmcore_elf64_check_arch mips_elf_check_machine +#define elfn32_check_arch(hdr) \ +({ \ + int __res = 1; \ + struct elfhdr *__h = (hdr); \ + \ + if (!mips_elf_check_machine(__h)) \ + __res = 0; \ + if (__h->e_ident[EI_CLASS] != ELFCLASS32) \ + __res = 0; \ + if (((__h->e_flags & EF_MIPS_ABI2) == 0) || \ + ((__h->e_flags & EF_MIPS_ABI) != 0)) \ + __res = 0; \ + \ + __res; \ +}) struct mips_abi; @@ -300,17 +333,16 @@ extern struct mips_abi mips_abi_n32; #define SET_PERSONALITY2(ex, state) \ do { \ - if (personality(current->personality) != PER_LINUX) \ - set_personality(PER_LINUX); \ - \ clear_thread_flag(TIF_HYBRID_FPREGS); \ set_thread_flag(TIF_32BIT_FPREGS); \ \ - mips_set_personality_fp(state); \ - \ current->thread.abi = &mips_abi; \ \ + mips_set_personality_fp(state); \ mips_set_personality_nan(state); \ + \ + if (personality(current->personality) != PER_LINUX) \ + set_personality(PER_LINUX); \ } while (0) #endif /* CONFIG_32BIT */ @@ -321,6 +353,7 @@ do { \ #define __SET_PERSONALITY32_N32() \ do { \ set_thread_flag(TIF_32BIT_ADDR); \ + \ current->thread.abi = &mips_abi_n32; \ } while (0) #else @@ -336,9 +369,9 @@ do { \ clear_thread_flag(TIF_HYBRID_FPREGS); \ set_thread_flag(TIF_32BIT_FPREGS); \ \ - mips_set_personality_fp(state); \ - \ current->thread.abi = &mips_abi_32; \ + \ + mips_set_personality_fp(state); \ } while (0) #else #define __SET_PERSONALITY32_O32(ex, state) \ diff --git a/arch/mips/include/asm/hazards.h b/arch/mips/include/asm/hazards.h index 7b99efd31074..dbb1eb6e284f 100644 --- a/arch/mips/include/asm/hazards.h +++ b/arch/mips/include/asm/hazards.h @@ -22,7 +22,8 @@ /* * TLB hazards */ -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) && !defined(CONFIG_CPU_CAVIUM_OCTEON) +#if (defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)) && \ + !defined(CONFIG_CPU_CAVIUM_OCTEON) && !defined(CONFIG_LOONGSON3_ENHANCEMENT) /* * MIPSR2 defines ehb for hazard avoidance @@ -155,8 +156,8 @@ do { \ } while (0) #elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \ - defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \ - defined(CONFIG_CPU_R5500) || defined(CONFIG_CPU_XLR) + defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_LOONGSON3_ENHANCEMENT) || \ + defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_R5500) || defined(CONFIG_CPU_XLR) /* * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer. diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 01880b34a209..64f2500d891b 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -19,8 +19,10 @@ #ifdef __KERNEL__ +#include <linux/bug.h> #include <linux/interrupt.h> #include <linux/uaccess.h> +#include <asm/cpu-features.h> #include <asm/kmap_types.h> /* undef for production */ @@ -50,7 +52,7 @@ extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); -#define flush_cache_kmaps() flush_cache_all() +#define flush_cache_kmaps() BUG_ON(cpu_has_dc_aliases) extern void kmap_init(void); diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 2b4dc7ad53b8..ecabc00c1e66 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -304,10 +304,10 @@ static inline void iounmap(const volatile void __iomem *addr) #undef __IS_KSEG1 } -#ifdef CONFIG_CPU_CAVIUM_OCTEON -#define war_octeon_io_reorder_wmb() wmb() +#if defined(CONFIG_CPU_CAVIUM_OCTEON) || defined(CONFIG_LOONGSON3_ENHANCEMENT) +#define war_io_reorder_wmb() wmb() #else -#define war_octeon_io_reorder_wmb() do { } while (0) +#define war_io_reorder_wmb() do { } while (0) #endif #define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, irq) \ @@ -318,7 +318,7 @@ static inline void pfx##write##bwlq(type val, \ volatile type *__mem; \ type __val; \ \ - war_octeon_io_reorder_wmb(); \ + war_io_reorder_wmb(); \ \ __mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem)); \ \ @@ -387,7 +387,7 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ volatile type *__addr; \ type __val; \ \ - war_octeon_io_reorder_wmb(); \ + war_io_reorder_wmb(); \ \ __addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \ \ diff --git a/arch/mips/include/asm/irq_regs.h b/arch/mips/include/asm/irq_regs.h index 33bd2a06de57..8c48d6dd1d78 100644 --- a/arch/mips/include/asm/irq_regs.h +++ b/arch/mips/include/asm/irq_regs.h @@ -18,4 +18,14 @@ static inline struct pt_regs *get_irq_regs(void) return current_thread_info()->regs; } +static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs) +{ + struct pt_regs *old_regs; + + old_regs = get_irq_regs(); + current_thread_info()->regs = new_regs; + + return old_regs; +} + #endif /* __ASM_IRQ_REGS_H */ diff --git a/arch/mips/include/asm/irqflags.h b/arch/mips/include/asm/irqflags.h index 65c351e328cc..9d3610be2323 100644 --- a/arch/mips/include/asm/irqflags.h +++ b/arch/mips/include/asm/irqflags.h @@ -41,7 +41,12 @@ static inline unsigned long arch_local_irq_save(void) " .set push \n" " .set reorder \n" " .set noat \n" +#if defined(CONFIG_CPU_LOONGSON3) + " mfc0 %[flags], $12 \n" + " di \n" +#else " di %[flags] \n" +#endif " andi %[flags], 1 \n" " " __stringify(__irq_disable_hazard) " \n" " .set pop \n" diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index f6b12790716c..b76e132c87e4 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -311,17 +311,18 @@ enum emulation_result { #define MIPS3_PG_FRAME 0x3fffffc0 #define VPN2_MASK 0xffffe000 +#define KVM_ENTRYHI_ASID MIPS_ENTRYHI_ASID #define TLB_IS_GLOBAL(x) (((x).tlb_lo0 & MIPS3_PG_G) && \ ((x).tlb_lo1 & MIPS3_PG_G)) #define TLB_VPN2(x) ((x).tlb_hi & VPN2_MASK) -#define TLB_ASID(x) ((x).tlb_hi & ASID_MASK) +#define TLB_ASID(x) ((x).tlb_hi & KVM_ENTRYHI_ASID) #define TLB_IS_VALID(x, va) (((va) & (1 << PAGE_SHIFT)) \ ? ((x).tlb_lo1 & MIPS3_PG_V) \ : ((x).tlb_lo0 & MIPS3_PG_V)) #define TLB_HI_VPN2_HIT(x, y) ((TLB_VPN2(x) & ~(x).tlb_mask) == \ ((y) & VPN2_MASK & ~(x).tlb_mask)) #define TLB_HI_ASID_HIT(x, y) (TLB_IS_GLOBAL(x) || \ - TLB_ASID(x) == ((y) & ASID_MASK)) + TLB_ASID(x) == ((y) & KVM_ENTRYHI_ASID)) struct kvm_mips_tlb { long tlb_mask; diff --git a/arch/mips/include/asm/llsc.h b/arch/mips/include/asm/llsc.h new file mode 100644 index 000000000000..c6d17d171147 --- /dev/null +++ b/arch/mips/include/asm/llsc.h @@ -0,0 +1,28 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Macros for 32/64-bit neutral inline assembler + */ + +#ifndef __ASM_LLSC_H +#define __ASM_LLSC_H + +#if _MIPS_SZLONG == 32 +#define SZLONG_LOG 5 +#define SZLONG_MASK 31UL +#define __LL "ll " +#define __SC "sc " +#define __INS "ins " +#define __EXT "ext " +#elif _MIPS_SZLONG == 64 +#define SZLONG_LOG 6 +#define SZLONG_MASK 63UL +#define __LL "lld " +#define __SC "scd " +#define __INS "dins " +#define __EXT "dext " +#endif + +#endif /* __ASM_LLSC_H */ diff --git a/arch/mips/include/asm/mach-bmips/cpu-feature-overrides.h b/arch/mips/include/asm/mach-bmips/cpu-feature-overrides.h new file mode 100644 index 000000000000..fa0583e1ce0d --- /dev/null +++ b/arch/mips/include/asm/mach-bmips/cpu-feature-overrides.h @@ -0,0 +1,14 @@ +#ifndef __ASM_MACH_BMIPS_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_BMIPS_CPU_FEATURE_OVERRIDES_H + +/* Invariants across all BMIPS processors */ +#define cpu_has_vtag_icache 0 +#define cpu_icache_snoops_remote_store 1 + +/* Processor ISA compatibility is MIPS32R1 */ +#define cpu_has_mips32r1 1 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r1 0 +#define cpu_has_mips64r2 0 + +#endif /* __ASM_MACH_BMIPS_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-bmips/ioremap.h b/arch/mips/include/asm/mach-bmips/ioremap.h new file mode 100644 index 000000000000..29c7a7bb7080 --- /dev/null +++ b/arch/mips/include/asm/mach-bmips/ioremap.h @@ -0,0 +1,33 @@ +#ifndef __ASM_MACH_BMIPS_IOREMAP_H +#define __ASM_MACH_BMIPS_IOREMAP_H + +#include <linux/types.h> + +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) +{ + return phys_addr; +} + +static inline int is_bmips_internal_registers(phys_addr_t offset) +{ + if (offset >= 0xfff80000) + return 1; + + return 0; +} + +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, + unsigned long flags) +{ + if (is_bmips_internal_registers(offset)) + return (void __iomem *)offset; + + return NULL; +} + +static inline int plat_iounmap(const volatile void __iomem *addr) +{ + return is_bmips_internal_registers((unsigned long)addr); +} + +#endif /* __ASM_MACH_BMIPS_IOREMAP_H */ diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h index 32cfbe6a191b..073b8bfbb3b3 100644 --- a/arch/mips/include/asm/mach-jz4740/platform.h +++ b/arch/mips/include/asm/mach-jz4740/platform.h @@ -19,7 +19,6 @@ #include <linux/platform_device.h> -extern struct platform_device jz4740_usb_ohci_device; extern struct platform_device jz4740_udc_device; extern struct platform_device jz4740_udc_xceiv_device; extern struct platform_device jz4740_mmc_device; diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h index 98d6a2f14aaf..7023883ca50f 100644 --- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_FALCON_H__ diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h index 4e5ae6523cb4..8064d7a4b33d 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LANTIQ_H__ #define _LANTIQ_H__ diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h index e23bf7c9a2d0..17d2fdcdaef4 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LANTIQ_PLATFORM_H__ diff --git a/arch/mips/include/asm/mach-lantiq/xway/irq.h b/arch/mips/include/asm/mach-lantiq/xway/irq.h index a1471d2dd0d2..83e5f03cccb5 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/irq.h +++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef __LANTIQ_IRQ_H diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h index 5eadfe582529..141076325307 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LANTIQ_XWAY_IRQ_H__ diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index dd6005b75e0c..f87310755319 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_XWAY_H__ diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h index 5f8693d5ab12..4901833498f7 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h +++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h @@ -12,7 +12,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2011 John Crispin <blogic@openwrt.org> + * Copyright (C) 2011 John Crispin <john@phrozen.org> */ #ifndef LTQ_DMA_H__ diff --git a/arch/mips/include/asm/mach-loongson32/cpufreq.h b/arch/mips/include/asm/mach-loongson32/cpufreq.h index 6843fa1a608d..2f1ecb081223 100644 --- a/arch/mips/include/asm/mach-loongson32/cpufreq.h +++ b/arch/mips/include/asm/mach-loongson32/cpufreq.h @@ -9,7 +9,6 @@ * option) any later version. */ - #ifndef __ASM_MACH_LOONGSON32_CPUFREQ_H #define __ASM_MACH_LOONGSON32_CPUFREQ_H diff --git a/arch/mips/include/asm/mach-loongson32/dma.h b/arch/mips/include/asm/mach-loongson32/dma.h new file mode 100644 index 000000000000..ad1dec743ccc --- /dev/null +++ b/arch/mips/include/asm/mach-loongson32/dma.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015 Zhang, Keguang <keguang.zhang@gmail.com> + * + * Loongson 1 NAND platform support. + * + * 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. + */ + +#ifndef __ASM_MACH_LOONGSON32_DMA_H +#define __ASM_MACH_LOONGSON32_DMA_H + +#define LS1X_DMA_CHANNEL0 0 +#define LS1X_DMA_CHANNEL1 1 +#define LS1X_DMA_CHANNEL2 2 + +struct plat_ls1x_dma { + int nr_channels; +}; + +extern struct plat_ls1x_dma ls1b_dma_pdata; + +#endif /* __ASM_MACH_LOONGSON32_DMA_H */ diff --git a/arch/mips/include/asm/mach-loongson32/irq.h b/arch/mips/include/asm/mach-loongson32/irq.h index 0d35b994e8d2..c1c744197de4 100644 --- a/arch/mips/include/asm/mach-loongson32/irq.h +++ b/arch/mips/include/asm/mach-loongson32/irq.h @@ -9,7 +9,6 @@ * option) any later version. */ - #ifndef __ASM_MACH_LOONGSON32_IRQ_H #define __ASM_MACH_LOONGSON32_IRQ_H diff --git a/arch/mips/include/asm/mach-loongson32/loongson1.h b/arch/mips/include/asm/mach-loongson32/loongson1.h index 12aa129aad80..978f6df8970a 100644 --- a/arch/mips/include/asm/mach-loongson32/loongson1.h +++ b/arch/mips/include/asm/mach-loongson32/loongson1.h @@ -9,7 +9,6 @@ * option) any later version. */ - #ifndef __ASM_MACH_LOONGSON32_LOONGSON1_H #define __ASM_MACH_LOONGSON32_LOONGSON1_H @@ -18,6 +17,9 @@ /* Loongson 1 Register Bases */ #define LS1X_MUX_BASE 0x1fd00420 #define LS1X_INTC_BASE 0x1fd01040 +#define LS1X_GPIO0_BASE 0x1fd010c0 +#define LS1X_GPIO1_BASE 0x1fd010c4 +#define LS1X_DMAC_BASE 0x1fd01160 #define LS1X_EHCI_BASE 0x1fe00000 #define LS1X_OHCI_BASE 0x1fe08000 #define LS1X_GMAC0_BASE 0x1fe10000 diff --git a/arch/mips/include/asm/mach-loongson32/nand.h b/arch/mips/include/asm/mach-loongson32/nand.h new file mode 100644 index 000000000000..e274912e9de1 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson32/nand.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015 Zhang, Keguang <keguang.zhang@gmail.com> + * + * Loongson 1 NAND platform support. + * + * 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. + */ + +#ifndef __ASM_MACH_LOONGSON32_NAND_H +#define __ASM_MACH_LOONGSON32_NAND_H + +#include <linux/dmaengine.h> +#include <linux/mtd/partitions.h> + +struct plat_ls1x_nand { + struct mtd_partition *parts; + unsigned int nr_parts; + + int hold_cycle; + int wait_cycle; +}; + +extern struct plat_ls1x_nand ls1b_nand_pdata; + +bool ls1x_dma_filter_fn(struct dma_chan *chan, void *param); + +#endif /* __ASM_MACH_LOONGSON32_NAND_H */ diff --git a/arch/mips/include/asm/mach-loongson32/platform.h b/arch/mips/include/asm/mach-loongson32/platform.h index c32f03f3f72c..672531aa9bef 100644 --- a/arch/mips/include/asm/mach-loongson32/platform.h +++ b/arch/mips/include/asm/mach-loongson32/platform.h @@ -7,20 +7,28 @@ * option) any later version. */ - #ifndef __ASM_MACH_LOONGSON32_PLATFORM_H #define __ASM_MACH_LOONGSON32_PLATFORM_H #include <linux/platform_device.h> +#include <dma.h> +#include <nand.h> + extern struct platform_device ls1x_uart_pdev; extern struct platform_device ls1x_cpufreq_pdev; +extern struct platform_device ls1x_dma_pdev; extern struct platform_device ls1x_eth0_pdev; extern struct platform_device ls1x_eth1_pdev; extern struct platform_device ls1x_ehci_pdev; +extern struct platform_device ls1x_gpio0_pdev; +extern struct platform_device ls1x_gpio1_pdev; +extern struct platform_device ls1x_nand_pdev; extern struct platform_device ls1x_rtc_pdev; -extern void __init ls1x_clk_init(void); -extern void __init ls1x_serial_setup(struct platform_device *pdev); +void __init ls1x_clk_init(void); +void __init ls1x_dma_set_platdata(struct plat_ls1x_dma *pdata); +void __init ls1x_nand_set_platdata(struct plat_ls1x_nand *pdata); +void __init ls1x_serial_set_uartclk(struct platform_device *pdev); #endif /* __ASM_MACH_LOONGSON32_PLATFORM_H */ diff --git a/arch/mips/include/asm/mach-loongson32/regs-clk.h b/arch/mips/include/asm/mach-loongson32/regs-clk.h index 1f5a715ac841..4d56fc38f0c4 100644 --- a/arch/mips/include/asm/mach-loongson32/regs-clk.h +++ b/arch/mips/include/asm/mach-loongson32/regs-clk.h @@ -19,18 +19,18 @@ #define LS1X_CLK_PLL_DIV LS1X_CLK_REG(0x4) /* Clock PLL Divisor Register Bits */ -#define DIV_DC_EN (0x1 << 31) -#define DIV_DC_RST (0x1 << 30) -#define DIV_CPU_EN (0x1 << 25) -#define DIV_CPU_RST (0x1 << 24) -#define DIV_DDR_EN (0x1 << 19) -#define DIV_DDR_RST (0x1 << 18) -#define RST_DC_EN (0x1 << 5) -#define RST_DC (0x1 << 4) -#define RST_DDR_EN (0x1 << 3) -#define RST_DDR (0x1 << 2) -#define RST_CPU_EN (0x1 << 1) -#define RST_CPU 0x1 +#define DIV_DC_EN BIT(31) +#define DIV_DC_RST BIT(30) +#define DIV_CPU_EN BIT(25) +#define DIV_CPU_RST BIT(24) +#define DIV_DDR_EN BIT(19) +#define DIV_DDR_RST BIT(18) +#define RST_DC_EN BIT(5) +#define RST_DC BIT(4) +#define RST_DDR_EN BIT(3) +#define RST_DDR BIT(2) +#define RST_CPU_EN BIT(1) +#define RST_CPU BIT(0) #define DIV_DC_SHIFT 26 #define DIV_CPU_SHIFT 20 diff --git a/arch/mips/include/asm/mach-loongson32/regs-mux.h b/arch/mips/include/asm/mach-loongson32/regs-mux.h index 8302d92f2da2..7c394f93cb9e 100644 --- a/arch/mips/include/asm/mach-loongson32/regs-mux.h +++ b/arch/mips/include/asm/mach-loongson32/regs-mux.h @@ -19,49 +19,49 @@ #define LS1X_MUX_CTRL1 LS1X_MUX_REG(0x4) /* MUX CTRL0 Register Bits */ -#define UART0_USE_PWM23 (0x1 << 28) -#define UART0_USE_PWM01 (0x1 << 27) -#define UART1_USE_LCD0_5_6_11 (0x1 << 26) -#define I2C2_USE_CAN1 (0x1 << 25) -#define I2C1_USE_CAN0 (0x1 << 24) -#define NAND3_USE_UART5 (0x1 << 23) -#define NAND3_USE_UART4 (0x1 << 22) -#define NAND3_USE_UART1_DAT (0x1 << 21) -#define NAND3_USE_UART1_CTS (0x1 << 20) -#define NAND3_USE_PWM23 (0x1 << 19) -#define NAND3_USE_PWM01 (0x1 << 18) -#define NAND2_USE_UART5 (0x1 << 17) -#define NAND2_USE_UART4 (0x1 << 16) -#define NAND2_USE_UART1_DAT (0x1 << 15) -#define NAND2_USE_UART1_CTS (0x1 << 14) -#define NAND2_USE_PWM23 (0x1 << 13) -#define NAND2_USE_PWM01 (0x1 << 12) -#define NAND1_USE_UART5 (0x1 << 11) -#define NAND1_USE_UART4 (0x1 << 10) -#define NAND1_USE_UART1_DAT (0x1 << 9) -#define NAND1_USE_UART1_CTS (0x1 << 8) -#define NAND1_USE_PWM23 (0x1 << 7) -#define NAND1_USE_PWM01 (0x1 << 6) -#define GMAC1_USE_UART1 (0x1 << 4) -#define GMAC1_USE_UART0 (0x1 << 3) -#define LCD_USE_UART0_DAT (0x1 << 2) -#define LCD_USE_UART15 (0x1 << 1) -#define LCD_USE_UART0 0x1 +#define UART0_USE_PWM23 BIT(28) +#define UART0_USE_PWM01 BIT(27) +#define UART1_USE_LCD0_5_6_11 BIT(26) +#define I2C2_USE_CAN1 BIT(25) +#define I2C1_USE_CAN0 BIT(24) +#define NAND3_USE_UART5 BIT(23) +#define NAND3_USE_UART4 BIT(22) +#define NAND3_USE_UART1_DAT BIT(21) +#define NAND3_USE_UART1_CTS BIT(20) +#define NAND3_USE_PWM23 BIT(19) +#define NAND3_USE_PWM01 BIT(18) +#define NAND2_USE_UART5 BIT(17) +#define NAND2_USE_UART4 BIT(16) +#define NAND2_USE_UART1_DAT BIT(15) +#define NAND2_USE_UART1_CTS BIT(14) +#define NAND2_USE_PWM23 BIT(13) +#define NAND2_USE_PWM01 BIT(12) +#define NAND1_USE_UART5 BIT(11) +#define NAND1_USE_UART4 BIT(10) +#define NAND1_USE_UART1_DAT BIT(9) +#define NAND1_USE_UART1_CTS BIT(8) +#define NAND1_USE_PWM23 BIT(7) +#define NAND1_USE_PWM01 BIT(6) +#define GMAC1_USE_UART1 BIT(4) +#define GMAC1_USE_UART0 BIT(3) +#define LCD_USE_UART0_DAT BIT(2) +#define LCD_USE_UART15 BIT(1) +#define LCD_USE_UART0 BIT(0) /* MUX CTRL1 Register Bits */ -#define USB_RESET (0x1 << 31) -#define SPI1_CS_USE_PWM01 (0x1 << 24) -#define SPI1_USE_CAN (0x1 << 23) -#define DISABLE_DDR_CONFSPACE (0x1 << 20) -#define DDR32TO16EN (0x1 << 16) -#define GMAC1_SHUT (0x1 << 13) -#define GMAC0_SHUT (0x1 << 12) -#define USB_SHUT (0x1 << 11) -#define UART1_3_USE_CAN1 (0x1 << 5) -#define UART1_2_USE_CAN0 (0x1 << 4) -#define GMAC1_USE_TXCLK (0x1 << 3) -#define GMAC0_USE_TXCLK (0x1 << 2) -#define GMAC1_USE_PWM23 (0x1 << 1) -#define GMAC0_USE_PWM01 0x1 +#define USB_RESET BIT(31) +#define SPI1_CS_USE_PWM01 BIT(24) +#define SPI1_USE_CAN BIT(23) +#define DISABLE_DDR_CONFSPACE BIT(20) +#define DDR32TO16EN BIT(16) +#define GMAC1_SHUT BIT(13) +#define GMAC0_SHUT BIT(12) +#define USB_SHUT BIT(11) +#define UART1_3_USE_CAN1 BIT(5) +#define UART1_2_USE_CAN0 BIT(4) +#define GMAC1_USE_TXCLK BIT(3) +#define GMAC0_USE_TXCLK BIT(2) +#define GMAC1_USE_PWM23 BIT(1) +#define GMAC0_USE_PWM01 BIT(0) #endif /* __ASM_MACH_LOONGSON32_REGS_MUX_H */ diff --git a/arch/mips/include/asm/mach-loongson32/regs-pwm.h b/arch/mips/include/asm/mach-loongson32/regs-pwm.h index 69f174ed13a4..4119600ce79a 100644 --- a/arch/mips/include/asm/mach-loongson32/regs-pwm.h +++ b/arch/mips/include/asm/mach-loongson32/regs-pwm.h @@ -19,11 +19,11 @@ #define PWM_CTRL 0xc /* PWM Control Register Bits */ -#define CNT_RST (0x1 << 7) -#define INT_SR (0x1 << 6) -#define INT_EN (0x1 << 5) -#define PWM_SINGLE (0x1 << 4) -#define PWM_OE (0x1 << 3) -#define CNT_EN 0x1 +#define CNT_RST BIT(7) +#define INT_SR BIT(6) +#define INT_EN BIT(5) +#define PWM_SINGLE BIT(4) +#define PWM_OE BIT(3) +#define CNT_EN BIT(0) #endif /* __ASM_MACH_LOONGSON32_REGS_PWM_H */ diff --git a/arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h b/arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h index 98963c2c7be4..89328a3d44d8 100644 --- a/arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h @@ -16,11 +16,6 @@ #ifndef __ASM_MACH_LOONGSON64_CPU_FEATURE_OVERRIDES_H #define __ASM_MACH_LOONGSON64_CPU_FEATURE_OVERRIDES_H -#define cpu_dcache_line_size() 32 -#define cpu_icache_line_size() 32 -#define cpu_scache_line_size() 32 - - #define cpu_has_32fpr 1 #define cpu_has_3k_cache 0 #define cpu_has_4k_cache 1 @@ -31,24 +26,17 @@ #define cpu_has_counter 1 #define cpu_has_dc_aliases (PAGE_SIZE < 0x4000) #define cpu_has_divec 0 -#define cpu_has_dsp 0 -#define cpu_has_dsp2 0 #define cpu_has_ejtag 0 -#define cpu_has_ic_fills_f_dc 0 #define cpu_has_inclusive_pcaches 1 #define cpu_has_llsc 1 #define cpu_has_mcheck 0 #define cpu_has_mdmx 0 #define cpu_has_mips16 0 -#define cpu_has_mips32r2 0 #define cpu_has_mips3d 0 -#define cpu_has_mips64r2 0 #define cpu_has_mipsmt 0 -#define cpu_has_prefetch 0 #define cpu_has_smartmips 0 #define cpu_has_tlb 1 #define cpu_has_tx39_cache 0 -#define cpu_has_userlocal 0 #define cpu_has_vce 0 #define cpu_has_veic 0 #define cpu_has_vint 0 @@ -56,6 +44,10 @@ #define cpu_has_watch 1 #define cpu_has_local_ebase 0 -#define cpu_has_wsbh IS_ENABLED(CONFIG_CPU_LOONGSON3) +#ifdef CONFIG_CPU_LOONGSON3 +#define cpu_has_wsbh 1 +#define cpu_has_ic_fills_f_dc 1 +#define cpu_hwrena_impl_bits 0xc0000000 +#endif #endif /* __ASM_MACH_LOONGSON64_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h b/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h index 3f2f84f6c401..8393bc548987 100644 --- a/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h @@ -23,8 +23,15 @@ or t0, (0x1 << 7) mtc0 t0, $16, 3 /* Set ELPA on LOONGSON3 pagegrain */ - li t0, (0x1 << 29) + mfc0 t0, $5, 1 + or t0, (0x1 << 29) mtc0 t0, $5, 1 +#ifdef CONFIG_LOONGSON3_ENHANCEMENT + /* Enable STFill Buffer */ + mfc0 t0, $16, 6 + or t0, 0x100 + mtc0 t0, $16, 6 +#endif _ehb .set pop #endif @@ -42,8 +49,15 @@ or t0, (0x1 << 7) mtc0 t0, $16, 3 /* Set ELPA on LOONGSON3 pagegrain */ - li t0, (0x1 << 29) + mfc0 t0, $5, 1 + or t0, (0x1 << 29) mtc0 t0, $5, 1 +#ifdef CONFIG_LOONGSON3_ENHANCEMENT + /* Enable STFill Buffer */ + mfc0 t0, $16, 6 + or t0, 0x100 + mtc0 t0, $16, 6 +#endif _ehb .set pop #endif diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h index 455d406e8ddf..a73350b07fdf 100644 --- a/arch/mips/include/asm/mach-ralink/mt7620.h +++ b/arch/mips/include/asm/mach-ralink/mt7620.h @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #ifndef _MT7620_REGS_H_ @@ -72,6 +72,7 @@ #define SYSCFG0_DRAM_TYPE_SDRAM 0 #define SYSCFG0_DRAM_TYPE_DDR1 1 #define SYSCFG0_DRAM_TYPE_DDR2 2 +#define SYSCFG0_DRAM_TYPE_UNKNOWN 3 #define SYSCFG0_DRAM_TYPE_DDR2_MT7628 0 #define SYSCFG0_DRAM_TYPE_DDR1_MT7628 1 diff --git a/arch/mips/include/asm/mach-ralink/mt7621.h b/arch/mips/include/asm/mach-ralink/mt7621.h index 610b61e3f9df..a672e06fa5fd 100644 --- a/arch/mips/include/asm/mach-ralink/mt7621.h +++ b/arch/mips/include/asm/mach-ralink/mt7621.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2015 John Crispin <john@phrozen.org> */ #ifndef _MT7621_REGS_H_ diff --git a/arch/mips/include/asm/mach-ralink/pinmux.h b/arch/mips/include/asm/mach-ralink/pinmux.h index be106cb2e26d..ba8ac331af0c 100644 --- a/arch/mips/include/asm/mach-ralink/pinmux.h +++ b/arch/mips/include/asm/mach-ralink/pinmux.h @@ -3,7 +3,7 @@ * it under the terms of the GNU General Public License version 2 as * publishhed by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #ifndef _RT288X_PINMUX_H__ diff --git a/arch/mips/include/asm/mach-ralink/ralink_regs.h b/arch/mips/include/asm/mach-ralink/ralink_regs.h index 4c9fba68c8b2..9df1a53bcb36 100644 --- a/arch/mips/include/asm/mach-ralink/ralink_regs.h +++ b/arch/mips/include/asm/mach-ralink/ralink_regs.h @@ -1,7 +1,7 @@ /* * Ralink SoC register definitions * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * diff --git a/arch/mips/include/asm/mach-ralink/rt288x.h b/arch/mips/include/asm/mach-ralink/rt288x.h index 03ad716acb42..25ae1042d57b 100644 --- a/arch/mips/include/asm/mach-ralink/rt288x.h +++ b/arch/mips/include/asm/mach-ralink/rt288x.h @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #ifndef _RT288X_REGS_H_ diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h index 2eea79331a14..ac2d65c04b5f 100644 --- a/arch/mips/include/asm/mach-ralink/rt305x.h +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #ifndef _RT305X_REGS_H_ diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index d4635391c36a..9411a4c0bdad 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -208,6 +208,7 @@ BUILD_CM_RW(l2_config, MIPS_CM_GCB_OFS + 0x130) BUILD_CM_RW(sys_config2, MIPS_CM_GCB_OFS + 0x150) BUILD_CM_RW(l2_pft_control, MIPS_CM_GCB_OFS + 0x300) BUILD_CM_RW(l2_pft_control_b, MIPS_CM_GCB_OFS + 0x308) +BUILD_CM_RW(bev_base, MIPS_CM_GCB_OFS + 0x680) /* Core Local & Core Other register accessor functions */ BUILD_CM_Cx_RW(reset_release, 0x00) @@ -290,8 +291,8 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_GCR_GIC_BASE_GICEN_MSK (_ULCAST_(0x1) << 0) /* GCR_CPC_BASE register fields */ -#define CM_GCR_CPC_BASE_CPCBASE_SHF 17 -#define CM_GCR_CPC_BASE_CPCBASE_MSK (_ULCAST_(0x7fff) << 17) +#define CM_GCR_CPC_BASE_CPCBASE_SHF 15 +#define CM_GCR_CPC_BASE_CPCBASE_MSK (_ULCAST_(0x1ffff) << 15) #define CM_GCR_CPC_BASE_CPCEN_SHF 0 #define CM_GCR_CPC_BASE_CPCEN_MSK (_ULCAST_(0x1) << 0) @@ -461,7 +462,10 @@ static inline unsigned int mips_cm_max_vp_width(void) if (mips_cm_revision() >= CM_REV_CM3) return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW_MSK; - return smp_num_siblings; + if (config_enabled(CONFIG_SMP)) + return smp_num_siblings; + + return 1; } /** @@ -505,7 +509,7 @@ extern void mips_cm_unlock_other(void); #else /* !CONFIG_MIPS_CM */ -static inline void mips_cm_lock_other(unsigned int core) { } +static inline void mips_cm_lock_other(unsigned int core, unsigned int vp) { } static inline void mips_cm_unlock_other(void) { } #endif /* !CONFIG_MIPS_CM */ diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index e09035239e53..8c519f9827a3 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h @@ -106,6 +106,9 @@ BUILD_CPC_R_(revision, MIPS_CPC_GCB_OFS + 0x20) BUILD_CPC_Cx_RW(cmd, 0x00) BUILD_CPC_Cx_RW(stat_conf, 0x08) BUILD_CPC_Cx_RW(other, 0x10) +BUILD_CPC_Cx_RW(vp_stop, 0x20) +BUILD_CPC_Cx_RW(vp_run, 0x28) +BUILD_CPC_Cx_RW(vp_running, 0x30) /* CPC_Cx_CMD register fields */ #define CPC_Cx_CMD_SHF 0 diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3ad19ad04d8a..25d01577d0b5 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -55,8 +55,14 @@ #define CP0_BADINSTR $8, 1 #define CP0_COUNT $9 #define CP0_ENTRYHI $10 +#define CP0_GUESTCTL1 $10, 4 +#define CP0_GUESTCTL2 $10, 5 +#define CP0_GUESTCTL3 $10, 6 #define CP0_COMPARE $11 +#define CP0_GUESTCTL0EXT $11, 4 #define CP0_STATUS $12 +#define CP0_GUESTCTL0 $12, 6 +#define CP0_GTOFFSET $12, 7 #define CP0_CAUSE $13 #define CP0_EPC $14 #define CP0_PRID $15 @@ -229,6 +235,8 @@ /* MIPS32/64 EntryHI bit definitions */ #define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) +#define MIPS_ENTRYHI_ASIDX (_ULCAST_(0x3) << 8) +#define MIPS_ENTRYHI_ASID (_ULCAST_(0xff) << 0) /* * R4x00 interrupt enable / cause bits @@ -390,6 +398,8 @@ #define CAUSEF_IP7 (_ULCAST_(1) << 15) #define CAUSEB_FDCI 21 #define CAUSEF_FDCI (_ULCAST_(1) << 21) +#define CAUSEB_WP 22 +#define CAUSEF_WP (_ULCAST_(1) << 22) #define CAUSEB_IV 23 #define CAUSEF_IV (_ULCAST_(1) << 23) #define CAUSEB_PCI 26 @@ -611,7 +621,8 @@ #define MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT (_ULCAST_(1) << 14) #define MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT (_ULCAST_(2) << 14) #define MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT (_ULCAST_(3) << 14) -#define MIPS_CONF4_KSCREXIST (_ULCAST_(255) << 16) +#define MIPS_CONF4_KSCREXIST_SHIFT (16) +#define MIPS_CONF4_KSCREXIST (_ULCAST_(255) << MIPS_CONF4_KSCREXIST_SHIFT) #define MIPS_CONF4_VTLBSIZEEXT_SHIFT (24) #define MIPS_CONF4_VTLBSIZEEXT (_ULCAST_(15) << MIPS_CONF4_VTLBSIZEEXT_SHIFT) #define MIPS_CONF4_AE (_ULCAST_(1) << 28) @@ -623,6 +634,7 @@ #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_VP (_ULCAST_(1) << 7) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27) @@ -633,6 +645,8 @@ #define MIPS_CONF6_SYND (_ULCAST_(1) << 13) /* proAptiv FTLB on/off bit */ #define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15) +/* Loongson-3 FTLB on/off bit */ +#define MIPS_CONF6_FTLBDIS (_ULCAST_(1) << 22) /* FTLB probability bits */ #define MIPS_CONF6_FTLBP_SHIFT (16) @@ -645,12 +659,38 @@ /* FTLB probability bits for R6 */ #define MIPS_CONF7_FTLBP_SHIFT (18) +/* WatchLo* register definitions */ +#define MIPS_WATCHLO_IRW (_ULCAST_(0x7) << 0) + +/* WatchHi* register definitions */ +#define MIPS_WATCHHI_M (_ULCAST_(1) << 31) +#define MIPS_WATCHHI_G (_ULCAST_(1) << 30) +#define MIPS_WATCHHI_WM (_ULCAST_(0x3) << 28) +#define MIPS_WATCHHI_WM_R_RVA (_ULCAST_(0) << 28) +#define MIPS_WATCHHI_WM_R_GPA (_ULCAST_(1) << 28) +#define MIPS_WATCHHI_WM_G_GVA (_ULCAST_(2) << 28) +#define MIPS_WATCHHI_EAS (_ULCAST_(0x3) << 24) +#define MIPS_WATCHHI_ASID (_ULCAST_(0xff) << 16) +#define MIPS_WATCHHI_MASK (_ULCAST_(0x1ff) << 3) +#define MIPS_WATCHHI_I (_ULCAST_(1) << 2) +#define MIPS_WATCHHI_R (_ULCAST_(1) << 1) +#define MIPS_WATCHHI_W (_ULCAST_(1) << 0) +#define MIPS_WATCHHI_IRW (_ULCAST_(0x7) << 0) + /* MAAR bit definitions */ #define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) #define MIPS_MAAR_ADDR_SHIFT 12 #define MIPS_MAAR_S (_ULCAST_(1) << 1) #define MIPS_MAAR_V (_ULCAST_(1) << 0) +/* EBase bit definitions */ +#define MIPS_EBASE_CPUNUM_SHIFT 0 +#define MIPS_EBASE_CPUNUM (_ULCAST_(0x3ff) << 0) +#define MIPS_EBASE_WG_SHIFT 11 +#define MIPS_EBASE_WG (_ULCAST_(1) << 11) +#define MIPS_EBASE_BASE_SHIFT 12 +#define MIPS_EBASE_BASE (~_ULCAST_((1 << MIPS_EBASE_BASE_SHIFT) - 1)) + /* CMGCRBase bit definitions */ #define MIPS_CMGCRB_BASE 11 #define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1)) @@ -706,6 +746,94 @@ #define MIPS_PWCTL_PSN_SHIFT 0 #define MIPS_PWCTL_PSN_MASK 0x0000003f +/* GuestCtl0 fields */ +#define MIPS_GCTL0_GM_SHIFT 31 +#define MIPS_GCTL0_GM (_ULCAST_(1) << MIPS_GCTL0_GM_SHIFT) +#define MIPS_GCTL0_RI_SHIFT 30 +#define MIPS_GCTL0_RI (_ULCAST_(1) << MIPS_GCTL0_RI_SHIFT) +#define MIPS_GCTL0_MC_SHIFT 29 +#define MIPS_GCTL0_MC (_ULCAST_(1) << MIPS_GCTL0_MC_SHIFT) +#define MIPS_GCTL0_CP0_SHIFT 28 +#define MIPS_GCTL0_CP0 (_ULCAST_(1) << MIPS_GCTL0_CP0_SHIFT) +#define MIPS_GCTL0_AT_SHIFT 26 +#define MIPS_GCTL0_AT (_ULCAST_(0x3) << MIPS_GCTL0_AT_SHIFT) +#define MIPS_GCTL0_GT_SHIFT 25 +#define MIPS_GCTL0_GT (_ULCAST_(1) << MIPS_GCTL0_GT_SHIFT) +#define MIPS_GCTL0_CG_SHIFT 24 +#define MIPS_GCTL0_CG (_ULCAST_(1) << MIPS_GCTL0_CG_SHIFT) +#define MIPS_GCTL0_CF_SHIFT 23 +#define MIPS_GCTL0_CF (_ULCAST_(1) << MIPS_GCTL0_CF_SHIFT) +#define MIPS_GCTL0_G1_SHIFT 22 +#define MIPS_GCTL0_G1 (_ULCAST_(1) << MIPS_GCTL0_G1_SHIFT) +#define MIPS_GCTL0_G0E_SHIFT 19 +#define MIPS_GCTL0_G0E (_ULCAST_(1) << MIPS_GCTL0_G0E_SHIFT) +#define MIPS_GCTL0_PT_SHIFT 18 +#define MIPS_GCTL0_PT (_ULCAST_(1) << MIPS_GCTL0_PT_SHIFT) +#define MIPS_GCTL0_RAD_SHIFT 9 +#define MIPS_GCTL0_RAD (_ULCAST_(1) << MIPS_GCTL0_RAD_SHIFT) +#define MIPS_GCTL0_DRG_SHIFT 8 +#define MIPS_GCTL0_DRG (_ULCAST_(1) << MIPS_GCTL0_DRG_SHIFT) +#define MIPS_GCTL0_G2_SHIFT 7 +#define MIPS_GCTL0_G2 (_ULCAST_(1) << MIPS_GCTL0_G2_SHIFT) +#define MIPS_GCTL0_GEXC_SHIFT 2 +#define MIPS_GCTL0_GEXC (_ULCAST_(0x1f) << MIPS_GCTL0_GEXC_SHIFT) +#define MIPS_GCTL0_SFC2_SHIFT 1 +#define MIPS_GCTL0_SFC2 (_ULCAST_(1) << MIPS_GCTL0_SFC2_SHIFT) +#define MIPS_GCTL0_SFC1_SHIFT 0 +#define MIPS_GCTL0_SFC1 (_ULCAST_(1) << MIPS_GCTL0_SFC1_SHIFT) + +/* GuestCtl0.AT Guest address translation control */ +#define MIPS_GCTL0_AT_ROOT 1 /* Guest MMU under Root control */ +#define MIPS_GCTL0_AT_GUEST 3 /* Guest MMU under Guest control */ + +/* GuestCtl0.GExcCode Hypervisor exception cause codes */ +#define MIPS_GCTL0_GEXC_GPSI 0 /* Guest Privileged Sensitive Instruction */ +#define MIPS_GCTL0_GEXC_GSFC 1 /* Guest Software Field Change */ +#define MIPS_GCTL0_GEXC_HC 2 /* Hypercall */ +#define MIPS_GCTL0_GEXC_GRR 3 /* Guest Reserved Instruction Redirect */ +#define MIPS_GCTL0_GEXC_GVA 8 /* Guest Virtual Address available */ +#define MIPS_GCTL0_GEXC_GHFC 9 /* Guest Hardware Field Change */ +#define MIPS_GCTL0_GEXC_GPA 10 /* Guest Physical Address available */ + +/* GuestCtl0Ext fields */ +#define MIPS_GCTL0EXT_RPW_SHIFT 8 +#define MIPS_GCTL0EXT_RPW (_ULCAST_(0x3) << MIPS_GCTL0EXT_RPW_SHIFT) +#define MIPS_GCTL0EXT_NCC_SHIFT 6 +#define MIPS_GCTL0EXT_NCC (_ULCAST_(0x3) << MIPS_GCTL0EXT_NCC_SHIFT) +#define MIPS_GCTL0EXT_CGI_SHIFT 4 +#define MIPS_GCTL0EXT_CGI (_ULCAST_(1) << MIPS_GCTL0EXT_CGI_SHIFT) +#define MIPS_GCTL0EXT_FCD_SHIFT 3 +#define MIPS_GCTL0EXT_FCD (_ULCAST_(1) << MIPS_GCTL0EXT_FCD_SHIFT) +#define MIPS_GCTL0EXT_OG_SHIFT 2 +#define MIPS_GCTL0EXT_OG (_ULCAST_(1) << MIPS_GCTL0EXT_OG_SHIFT) +#define MIPS_GCTL0EXT_BG_SHIFT 1 +#define MIPS_GCTL0EXT_BG (_ULCAST_(1) << MIPS_GCTL0EXT_BG_SHIFT) +#define MIPS_GCTL0EXT_MG_SHIFT 0 +#define MIPS_GCTL0EXT_MG (_ULCAST_(1) << MIPS_GCTL0EXT_MG_SHIFT) + +/* GuestCtl0Ext.RPW Root page walk configuration */ +#define MIPS_GCTL0EXT_RPW_BOTH 0 /* Root PW for GPA->RPA and RVA->RPA */ +#define MIPS_GCTL0EXT_RPW_GPA 2 /* Root PW for GPA->RPA */ +#define MIPS_GCTL0EXT_RPW_RVA 3 /* Root PW for RVA->RPA */ + +/* GuestCtl0Ext.NCC Nested cache coherency attributes */ +#define MIPS_GCTL0EXT_NCC_IND 0 /* Guest CCA independent of Root CCA */ +#define MIPS_GCTL0EXT_NCC_MOD 1 /* Guest CCA modified by Root CCA */ + +/* GuestCtl1 fields */ +#define MIPS_GCTL1_ID_SHIFT 0 +#define MIPS_GCTL1_ID_WIDTH 8 +#define MIPS_GCTL1_ID (_ULCAST_(0xff) << MIPS_GCTL1_ID_SHIFT) +#define MIPS_GCTL1_RID_SHIFT 16 +#define MIPS_GCTL1_RID_WIDTH 8 +#define MIPS_GCTL1_RID (_ULCAST_(0xff) << MIPS_GCTL1_RID_SHIFT) +#define MIPS_GCTL1_EID_SHIFT 24 +#define MIPS_GCTL1_EID_WIDTH 8 +#define MIPS_GCTL1_EID (_ULCAST_(0xff) << MIPS_GCTL1_EID_SHIFT) + +/* GuestID reserved for root context */ +#define MIPS_GCTL1_ROOT_GUESTID 0 + /* CDMMBase register bit definitions */ #define MIPS_CDMMBASE_SIZE_SHIFT 0 #define MIPS_CDMMBASE_SIZE (_ULCAST_(511) << MIPS_CDMMBASE_SIZE_SHIFT) @@ -757,6 +885,15 @@ /* Disable Branch Return Cache */ #define R10K_DIAG_D_BRC (_ULCAST_(1) << 22) +/* Flush ITLB */ +#define LOONGSON_DIAG_ITLB (_ULCAST_(1) << 2) +/* Flush DTLB */ +#define LOONGSON_DIAG_DTLB (_ULCAST_(1) << 3) +/* Flush VTLB */ +#define LOONGSON_DIAG_VTLB (_ULCAST_(1) << 12) +/* Flush FTLB */ +#define LOONGSON_DIAG_FTLB (_ULCAST_(1) << 13) + /* * Coprocessor 1 (FPU) register names */ @@ -1186,9 +1323,15 @@ do { \ #define read_c0_context() __read_ulong_c0_register($4, 0) #define write_c0_context(val) __write_ulong_c0_register($4, 0, val) +#define read_c0_contextconfig() __read_32bit_c0_register($4, 1) +#define write_c0_contextconfig(val) __write_32bit_c0_register($4, 1, val) + #define read_c0_userlocal() __read_ulong_c0_register($4, 2) #define write_c0_userlocal(val) __write_ulong_c0_register($4, 2, val) +#define read_c0_xcontextconfig() __read_ulong_c0_register($4, 3) +#define write_c0_xcontextconfig(val) __write_ulong_c0_register($4, 3, val) + #define read_c0_pagemask() __read_32bit_c0_register($5, 0) #define write_c0_pagemask(val) __write_32bit_c0_register($5, 0, val) @@ -1206,6 +1349,9 @@ do { \ #define read_c0_badvaddr() __read_ulong_c0_register($8, 0) #define write_c0_badvaddr(val) __write_ulong_c0_register($8, 0, val) +#define read_c0_badinstr() __read_32bit_c0_register($8, 1) +#define read_c0_badinstrp() __read_32bit_c0_register($8, 2) + #define read_c0_count() __read_32bit_c0_register($9, 0) #define write_c0_count(val) __write_32bit_c0_register($9, 0, val) @@ -1218,9 +1364,21 @@ do { \ #define read_c0_entryhi() __read_ulong_c0_register($10, 0) #define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val) +#define read_c0_guestctl1() __read_32bit_c0_register($10, 4) +#define write_c0_guestctl1(val) __write_32bit_c0_register($10, 4, val) + +#define read_c0_guestctl2() __read_32bit_c0_register($10, 5) +#define write_c0_guestctl2(val) __write_32bit_c0_register($10, 5, val) + +#define read_c0_guestctl3() __read_32bit_c0_register($10, 6) +#define write_c0_guestctl3(val) __write_32bit_c0_register($10, 6, val) + #define read_c0_compare() __read_32bit_c0_register($11, 0) #define write_c0_compare(val) __write_32bit_c0_register($11, 0, val) +#define read_c0_guestctl0ext() __read_32bit_c0_register($11, 4) +#define write_c0_guestctl0ext(val) __write_32bit_c0_register($11, 4, val) + #define read_c0_compare2() __read_32bit_c0_register($11, 6) /* pnx8550 */ #define write_c0_compare2(val) __write_32bit_c0_register($11, 6, val) @@ -1231,6 +1389,12 @@ do { \ #define write_c0_status(val) __write_32bit_c0_register($12, 0, val) +#define read_c0_guestctl0() __read_32bit_c0_register($12, 6) +#define write_c0_guestctl0(val) __write_32bit_c0_register($12, 6, val) + +#define read_c0_gtoffset() __read_32bit_c0_register($12, 7) +#define write_c0_gtoffset(val) __write_32bit_c0_register($12, 7, val) + #define read_c0_cause() __read_32bit_c0_register($13, 0) #define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) @@ -1416,6 +1580,9 @@ do { \ #define read_c0_ebase() __read_32bit_c0_register($15, 1) #define write_c0_ebase(val) __write_32bit_c0_register($15, 1, val) +#define read_c0_ebase_64() __read_64bit_c0_register($15, 1) +#define write_c0_ebase_64(val) __write_64bit_c0_register($15, 1, val) + #define read_c0_cdmmbase() __read_ulong_c0_register($15, 2) #define write_c0_cdmmbase(val) __write_ulong_c0_register($15, 2, val) @@ -1442,6 +1609,12 @@ do { \ #define read_c0_pwctl() __read_32bit_c0_register($6, 6) #define write_c0_pwctl(val) __write_32bit_c0_register($6, 6, val) +#define read_c0_pgd() __read_64bit_c0_register($9, 7) +#define write_c0_pgd(val) __write_64bit_c0_register($9, 7, val) + +#define read_c0_kpgd() __read_64bit_c0_register($31, 7) +#define write_c0_kpgd(val) __write_64bit_c0_register($31, 7, val) + /* Cavium OCTEON (cnMIPS) */ #define read_c0_cvmcount() __read_ulong_c0_register($9, 6) #define write_c0_cvmcount(val) __write_ulong_c0_register($9, 6, val) @@ -1507,6 +1680,317 @@ do { \ #define write_c0_brcm_sleepcount(val) __write_32bit_c0_register($22, 7, val) /* + * Macros to access the guest system control coprocessor + */ + +#ifdef TOOLCHAIN_SUPPORTS_VIRT + +#define __read_32bit_gc0_register(source, sel) \ +({ int __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips32r2\n\t" \ + ".set\tvirt\n\t" \ + "mfgc0\t%0, $%1, %2\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (source), "i" (sel)); \ + __res; \ +}) + +#define __read_64bit_gc0_register(source, sel) \ +({ unsigned long long __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips64r2\n\t" \ + ".set\tvirt\n\t" \ + "dmfgc0\t%0, $%1, %2\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (source), "i" (sel)); \ + __res; \ +}) + +#define __write_32bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips32r2\n\t" \ + ".set\tvirt\n\t" \ + "mtgc0\t%z0, $%1, %2\n\t" \ + ".set\tpop" \ + : : "Jr" ((unsigned int)(value)), \ + "i" (register), "i" (sel)); \ +} while (0) + +#define __write_64bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips64r2\n\t" \ + ".set\tvirt\n\t" \ + "dmtgc0\t%z0, $%1, %2\n\t" \ + ".set\tpop" \ + : : "Jr" (value), \ + "i" (register), "i" (sel)); \ +} while (0) + +#else /* TOOLCHAIN_SUPPORTS_VIRT */ + +#define __read_32bit_gc0_register(source, sel) \ +({ int __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tnoat\n\t" \ + "# mfgc0\t$1, $%1, %2\n\t" \ + ".word\t(0x40610000 | %1 << 11 | %2)\n\t" \ + "move\t%0, $1\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (source), "i" (sel)); \ + __res; \ +}) + +#define __read_64bit_gc0_register(source, sel) \ +({ unsigned long long __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tnoat\n\t" \ + "# dmfgc0\t$1, $%1, %2\n\t" \ + ".word\t(0x40610100 | %1 << 11 | %2)\n\t" \ + "move\t%0, $1\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (source), "i" (sel)); \ + __res; \ +}) + +#define __write_32bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tnoat\n\t" \ + "move\t$1, %0\n\t" \ + "# mtgc0\t$1, $%1, %2\n\t" \ + ".word\t(0x40610200 | %1 << 11 | %2)\n\t" \ + ".set\tpop" \ + : : "Jr" ((unsigned int)(value)), \ + "i" (register), "i" (sel)); \ +} while (0) + +#define __write_64bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tnoat\n\t" \ + "move\t$1, %0\n\t" \ + "# dmtgc0\t$1, $%1, %2\n\t" \ + ".word\t(0x40610300 | %1 << 11 | %2)\n\t" \ + ".set\tpop" \ + : : "Jr" (value), \ + "i" (register), "i" (sel)); \ +} while (0) + +#endif /* !TOOLCHAIN_SUPPORTS_VIRT */ + +#define __read_ulong_gc0_register(reg, sel) \ + ((sizeof(unsigned long) == 4) ? \ + (unsigned long) __read_32bit_gc0_register(reg, sel) : \ + (unsigned long) __read_64bit_gc0_register(reg, sel)) + +#define __write_ulong_gc0_register(reg, sel, val) \ +do { \ + if (sizeof(unsigned long) == 4) \ + __write_32bit_gc0_register(reg, sel, val); \ + else \ + __write_64bit_gc0_register(reg, sel, val); \ +} while (0) + +#define read_gc0_index() __read_32bit_gc0_register(0, 0) +#define write_gc0_index(val) __write_32bit_gc0_register(0, 0, val) + +#define read_gc0_entrylo0() __read_ulong_gc0_register(2, 0) +#define write_gc0_entrylo0(val) __write_ulong_gc0_register(2, 0, val) + +#define read_gc0_entrylo1() __read_ulong_gc0_register(3, 0) +#define write_gc0_entrylo1(val) __write_ulong_gc0_register(3, 0, val) + +#define read_gc0_context() __read_ulong_gc0_register(4, 0) +#define write_gc0_context(val) __write_ulong_gc0_register(4, 0, val) + +#define read_gc0_contextconfig() __read_32bit_gc0_register(4, 1) +#define write_gc0_contextconfig(val) __write_32bit_gc0_register(4, 1, val) + +#define read_gc0_userlocal() __read_ulong_gc0_register(4, 2) +#define write_gc0_userlocal(val) __write_ulong_gc0_register(4, 2, val) + +#define read_gc0_xcontextconfig() __read_ulong_gc0_register(4, 3) +#define write_gc0_xcontextconfig(val) __write_ulong_gc0_register(4, 3, val) + +#define read_gc0_pagemask() __read_32bit_gc0_register(5, 0) +#define write_gc0_pagemask(val) __write_32bit_gc0_register(5, 0, val) + +#define read_gc0_pagegrain() __read_32bit_gc0_register(5, 1) +#define write_gc0_pagegrain(val) __write_32bit_gc0_register(5, 1, val) + +#define read_gc0_segctl0() __read_ulong_gc0_register(5, 2) +#define write_gc0_segctl0(val) __write_ulong_gc0_register(5, 2, val) + +#define read_gc0_segctl1() __read_ulong_gc0_register(5, 3) +#define write_gc0_segctl1(val) __write_ulong_gc0_register(5, 3, val) + +#define read_gc0_segctl2() __read_ulong_gc0_register(5, 4) +#define write_gc0_segctl2(val) __write_ulong_gc0_register(5, 4, val) + +#define read_gc0_pwbase() __read_ulong_gc0_register(5, 5) +#define write_gc0_pwbase(val) __write_ulong_gc0_register(5, 5, val) + +#define read_gc0_pwfield() __read_ulong_gc0_register(5, 6) +#define write_gc0_pwfield(val) __write_ulong_gc0_register(5, 6, val) + +#define read_gc0_pwsize() __read_ulong_gc0_register(5, 7) +#define write_gc0_pwsize(val) __write_ulong_gc0_register(5, 7, val) + +#define read_gc0_wired() __read_32bit_gc0_register(6, 0) +#define write_gc0_wired(val) __write_32bit_gc0_register(6, 0, val) + +#define read_gc0_pwctl() __read_32bit_gc0_register(6, 6) +#define write_gc0_pwctl(val) __write_32bit_gc0_register(6, 6, val) + +#define read_gc0_hwrena() __read_32bit_gc0_register(7, 0) +#define write_gc0_hwrena(val) __write_32bit_gc0_register(7, 0, val) + +#define read_gc0_badvaddr() __read_ulong_gc0_register(8, 0) +#define write_gc0_badvaddr(val) __write_ulong_gc0_register(8, 0, val) + +#define read_gc0_badinstr() __read_32bit_gc0_register(8, 1) +#define write_gc0_badinstr(val) __write_32bit_gc0_register(8, 1, val) + +#define read_gc0_badinstrp() __read_32bit_gc0_register(8, 2) +#define write_gc0_badinstrp(val) __write_32bit_gc0_register(8, 2, val) + +#define read_gc0_count() __read_32bit_gc0_register(9, 0) + +#define read_gc0_entryhi() __read_ulong_gc0_register(10, 0) +#define write_gc0_entryhi(val) __write_ulong_gc0_register(10, 0, val) + +#define read_gc0_compare() __read_32bit_gc0_register(11, 0) +#define write_gc0_compare(val) __write_32bit_gc0_register(11, 0, val) + +#define read_gc0_status() __read_32bit_gc0_register(12, 0) +#define write_gc0_status(val) __write_32bit_gc0_register(12, 0, val) + +#define read_gc0_intctl() __read_32bit_gc0_register(12, 1) +#define write_gc0_intctl(val) __write_32bit_gc0_register(12, 1, val) + +#define read_gc0_cause() __read_32bit_gc0_register(13, 0) +#define write_gc0_cause(val) __write_32bit_gc0_register(13, 0, val) + +#define read_gc0_epc() __read_ulong_gc0_register(14, 0) +#define write_gc0_epc(val) __write_ulong_gc0_register(14, 0, val) + +#define read_gc0_ebase() __read_32bit_gc0_register(15, 1) +#define write_gc0_ebase(val) __write_32bit_gc0_register(15, 1, val) + +#define read_gc0_ebase_64() __read_64bit_gc0_register(15, 1) +#define write_gc0_ebase_64(val) __write_64bit_gc0_register(15, 1, val) + +#define read_gc0_config() __read_32bit_gc0_register(16, 0) +#define read_gc0_config1() __read_32bit_gc0_register(16, 1) +#define read_gc0_config2() __read_32bit_gc0_register(16, 2) +#define read_gc0_config3() __read_32bit_gc0_register(16, 3) +#define read_gc0_config4() __read_32bit_gc0_register(16, 4) +#define read_gc0_config5() __read_32bit_gc0_register(16, 5) +#define read_gc0_config6() __read_32bit_gc0_register(16, 6) +#define read_gc0_config7() __read_32bit_gc0_register(16, 7) +#define write_gc0_config(val) __write_32bit_gc0_register(16, 0, val) +#define write_gc0_config1(val) __write_32bit_gc0_register(16, 1, val) +#define write_gc0_config2(val) __write_32bit_gc0_register(16, 2, val) +#define write_gc0_config3(val) __write_32bit_gc0_register(16, 3, val) +#define write_gc0_config4(val) __write_32bit_gc0_register(16, 4, val) +#define write_gc0_config5(val) __write_32bit_gc0_register(16, 5, val) +#define write_gc0_config6(val) __write_32bit_gc0_register(16, 6, val) +#define write_gc0_config7(val) __write_32bit_gc0_register(16, 7, val) + +#define read_gc0_watchlo0() __read_ulong_gc0_register(18, 0) +#define read_gc0_watchlo1() __read_ulong_gc0_register(18, 1) +#define read_gc0_watchlo2() __read_ulong_gc0_register(18, 2) +#define read_gc0_watchlo3() __read_ulong_gc0_register(18, 3) +#define read_gc0_watchlo4() __read_ulong_gc0_register(18, 4) +#define read_gc0_watchlo5() __read_ulong_gc0_register(18, 5) +#define read_gc0_watchlo6() __read_ulong_gc0_register(18, 6) +#define read_gc0_watchlo7() __read_ulong_gc0_register(18, 7) +#define write_gc0_watchlo0(val) __write_ulong_gc0_register(18, 0, val) +#define write_gc0_watchlo1(val) __write_ulong_gc0_register(18, 1, val) +#define write_gc0_watchlo2(val) __write_ulong_gc0_register(18, 2, val) +#define write_gc0_watchlo3(val) __write_ulong_gc0_register(18, 3, val) +#define write_gc0_watchlo4(val) __write_ulong_gc0_register(18, 4, val) +#define write_gc0_watchlo5(val) __write_ulong_gc0_register(18, 5, val) +#define write_gc0_watchlo6(val) __write_ulong_gc0_register(18, 6, val) +#define write_gc0_watchlo7(val) __write_ulong_gc0_register(18, 7, val) + +#define read_gc0_watchhi0() __read_32bit_gc0_register(19, 0) +#define read_gc0_watchhi1() __read_32bit_gc0_register(19, 1) +#define read_gc0_watchhi2() __read_32bit_gc0_register(19, 2) +#define read_gc0_watchhi3() __read_32bit_gc0_register(19, 3) +#define read_gc0_watchhi4() __read_32bit_gc0_register(19, 4) +#define read_gc0_watchhi5() __read_32bit_gc0_register(19, 5) +#define read_gc0_watchhi6() __read_32bit_gc0_register(19, 6) +#define read_gc0_watchhi7() __read_32bit_gc0_register(19, 7) +#define write_gc0_watchhi0(val) __write_32bit_gc0_register(19, 0, val) +#define write_gc0_watchhi1(val) __write_32bit_gc0_register(19, 1, val) +#define write_gc0_watchhi2(val) __write_32bit_gc0_register(19, 2, val) +#define write_gc0_watchhi3(val) __write_32bit_gc0_register(19, 3, val) +#define write_gc0_watchhi4(val) __write_32bit_gc0_register(19, 4, val) +#define write_gc0_watchhi5(val) __write_32bit_gc0_register(19, 5, val) +#define write_gc0_watchhi6(val) __write_32bit_gc0_register(19, 6, val) +#define write_gc0_watchhi7(val) __write_32bit_gc0_register(19, 7, val) + +#define read_gc0_xcontext() __read_ulong_gc0_register(20, 0) +#define write_gc0_xcontext(val) __write_ulong_gc0_register(20, 0, val) + +#define read_gc0_perfctrl0() __read_32bit_gc0_register(25, 0) +#define write_gc0_perfctrl0(val) __write_32bit_gc0_register(25, 0, val) +#define read_gc0_perfcntr0() __read_32bit_gc0_register(25, 1) +#define write_gc0_perfcntr0(val) __write_32bit_gc0_register(25, 1, val) +#define read_gc0_perfcntr0_64() __read_64bit_gc0_register(25, 1) +#define write_gc0_perfcntr0_64(val) __write_64bit_gc0_register(25, 1, val) +#define read_gc0_perfctrl1() __read_32bit_gc0_register(25, 2) +#define write_gc0_perfctrl1(val) __write_32bit_gc0_register(25, 2, val) +#define read_gc0_perfcntr1() __read_32bit_gc0_register(25, 3) +#define write_gc0_perfcntr1(val) __write_32bit_gc0_register(25, 3, val) +#define read_gc0_perfcntr1_64() __read_64bit_gc0_register(25, 3) +#define write_gc0_perfcntr1_64(val) __write_64bit_gc0_register(25, 3, val) +#define read_gc0_perfctrl2() __read_32bit_gc0_register(25, 4) +#define write_gc0_perfctrl2(val) __write_32bit_gc0_register(25, 4, val) +#define read_gc0_perfcntr2() __read_32bit_gc0_register(25, 5) +#define write_gc0_perfcntr2(val) __write_32bit_gc0_register(25, 5, val) +#define read_gc0_perfcntr2_64() __read_64bit_gc0_register(25, 5) +#define write_gc0_perfcntr2_64(val) __write_64bit_gc0_register(25, 5, val) +#define read_gc0_perfctrl3() __read_32bit_gc0_register(25, 6) +#define write_gc0_perfctrl3(val) __write_32bit_gc0_register(25, 6, val) +#define read_gc0_perfcntr3() __read_32bit_gc0_register(25, 7) +#define write_gc0_perfcntr3(val) __write_32bit_gc0_register(25, 7, val) +#define read_gc0_perfcntr3_64() __read_64bit_gc0_register(25, 7) +#define write_gc0_perfcntr3_64(val) __write_64bit_gc0_register(25, 7, val) + +#define read_gc0_errorepc() __read_ulong_gc0_register(30, 0) +#define write_gc0_errorepc(val) __write_ulong_gc0_register(30, 0, val) + +#define read_gc0_kscratch1() __read_ulong_gc0_register(31, 2) +#define read_gc0_kscratch2() __read_ulong_gc0_register(31, 3) +#define read_gc0_kscratch3() __read_ulong_gc0_register(31, 4) +#define read_gc0_kscratch4() __read_ulong_gc0_register(31, 5) +#define read_gc0_kscratch5() __read_ulong_gc0_register(31, 6) +#define read_gc0_kscratch6() __read_ulong_gc0_register(31, 7) +#define write_gc0_kscratch1(val) __write_ulong_gc0_register(31, 2, val) +#define write_gc0_kscratch2(val) __write_ulong_gc0_register(31, 3, val) +#define write_gc0_kscratch3(val) __write_ulong_gc0_register(31, 4, val) +#define write_gc0_kscratch4(val) __write_ulong_gc0_register(31, 5, val) +#define write_gc0_kscratch5(val) __write_ulong_gc0_register(31, 6, val) +#define write_gc0_kscratch6(val) __write_ulong_gc0_register(31, 7, val) + +/* * Macros to access the floating point coprocessor control registers */ #define _read_32bit_cp1_register(source, gas_hardfloat) \ @@ -2001,47 +2485,159 @@ static inline void tlb_write_random(void) ".set reorder"); } +#ifdef TOOLCHAIN_SUPPORTS_VIRT + /* - * Manipulate bits in a c0 register. + * Guest TLB operations. + * + * It is responsibility of the caller to take care of any TLB hazards. */ -#define __BUILD_SET_C0(name) \ +static inline void guest_tlb_probe(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbgp\n\t" + ".set pop"); +} + +static inline void guest_tlb_read(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbgr\n\t" + ".set pop"); +} + +static inline void guest_tlb_write_indexed(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbgwi\n\t" + ".set pop"); +} + +static inline void guest_tlb_write_random(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbgwr\n\t" + ".set pop"); +} + +/* + * Guest TLB Invalidate Flush + */ +static inline void guest_tlbinvf(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set virt\n\t" + "tlbginvf\n\t" + ".set pop"); +} + +#else /* TOOLCHAIN_SUPPORTS_VIRT */ + +/* + * Guest TLB operations. + * + * It is responsibility of the caller to take care of any TLB hazards. + */ +static inline void guest_tlb_probe(void) +{ + __asm__ __volatile__( + "# tlbgp\n\t" + ".word 0x42000010"); +} + +static inline void guest_tlb_read(void) +{ + __asm__ __volatile__( + "# tlbgr\n\t" + ".word 0x42000009"); +} + +static inline void guest_tlb_write_indexed(void) +{ + __asm__ __volatile__( + "# tlbgwi\n\t" + ".word 0x4200000a"); +} + +static inline void guest_tlb_write_random(void) +{ + __asm__ __volatile__( + "# tlbgwr\n\t" + ".word 0x4200000e"); +} + +/* + * Guest TLB Invalidate Flush + */ +static inline void guest_tlbinvf(void) +{ + __asm__ __volatile__( + "# tlbginvf\n\t" + ".word 0x4200000c"); +} + +#endif /* !TOOLCHAIN_SUPPORTS_VIRT */ + +/* + * Manipulate bits in a register. + */ +#define __BUILD_SET_COMMON(name) \ static inline unsigned int \ -set_c0_##name(unsigned int set) \ +set_##name(unsigned int set) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res | set; \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } \ \ static inline unsigned int \ -clear_c0_##name(unsigned int clear) \ +clear_##name(unsigned int clear) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res & ~clear; \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } \ \ static inline unsigned int \ -change_c0_##name(unsigned int change, unsigned int val) \ +change_##name(unsigned int change, unsigned int val) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res & ~change; \ new |= (val & change); \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } +/* + * Manipulate bits in a c0 register. + */ +#define __BUILD_SET_C0(name) __BUILD_SET_COMMON(c0_##name) + __BUILD_SET_C0(status) __BUILD_SET_C0(cause) __BUILD_SET_C0(config) @@ -2050,6 +2646,11 @@ __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap) __BUILD_SET_C0(pagegrain) +__BUILD_SET_C0(guestctl0) +__BUILD_SET_C0(guestctl0ext) +__BUILD_SET_C0(guestctl1) +__BUILD_SET_C0(guestctl2) +__BUILD_SET_C0(guestctl3) __BUILD_SET_C0(brcm_config_0) __BUILD_SET_C0(brcm_bus_pll) __BUILD_SET_C0(brcm_reset) @@ -2059,12 +2660,21 @@ __BUILD_SET_C0(brcm_config) __BUILD_SET_C0(brcm_mode) /* + * Manipulate bits in a guest c0 register. + */ +#define __BUILD_SET_GC0(name) __BUILD_SET_COMMON(gc0_##name) + +__BUILD_SET_GC0(status) +__BUILD_SET_GC0(cause) +__BUILD_SET_GC0(ebase) + +/* * Return low 10 bits of ebase. * Note that under KVM (MIPSVZ) this returns vcpu id. */ static inline unsigned int get_ebase_cpunum(void) { - return read_c0_ebase() & 0x3ff; + return read_c0_ebase() & MIPS_EBASE_CPUNUM; } #endif /* !__ASSEMBLY__ */ diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index 45914b59824c..fc57e135cb0a 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h @@ -65,37 +65,32 @@ extern unsigned long pgd_current[]; back_to_back_c0_hazard(); \ TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir) #endif /* CONFIG_MIPS_PGD_C0_CONTEXT*/ -#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) -#define ASID_INC 0x40 -#define ASID_MASK 0xfc0 - -#elif defined(CONFIG_CPU_R8000) - -#define ASID_INC 0x10 -#define ASID_MASK 0xff0 - -#else /* FIXME: not correct for R6000 */ +/* + * All unused by hardware upper bits will be considered + * as a software asid extension. + */ +static unsigned long asid_version_mask(unsigned int cpu) +{ + unsigned long asid_mask = cpu_asid_mask(&cpu_data[cpu]); -#define ASID_INC 0x1 -#define ASID_MASK 0xff + return ~(asid_mask | (asid_mask - 1)); +} -#endif +static unsigned long asid_first_version(unsigned int cpu) +{ + return ~asid_version_mask(cpu) + 1; +} #define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) -#define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) #define asid_cache(cpu) (cpu_data[cpu].asid_cache) +#define cpu_asid(cpu, mm) \ + (cpu_context((cpu), (mm)) & cpu_asid_mask(&cpu_data[cpu])) static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } -/* - * All unused by hardware upper bits will be considered - * as a software asid extension. - */ -#define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1))) -#define ASID_FIRST_VERSION ((unsigned long)(~ASID_VERSION_MASK) + 1) /* Normal, classic MIPS get_new_mmu_context */ static inline void @@ -104,7 +99,7 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) extern void kvm_local_flush_tlb_all(void); unsigned long asid = asid_cache(cpu); - if (! ((asid += ASID_INC) & ASID_MASK) ) { + if (!((asid += cpu_asid_inc()) & cpu_asid_mask(&cpu_data[cpu]))) { if (cpu_has_vtag_icache) flush_icache_all(); #ifdef CONFIG_KVM @@ -113,7 +108,7 @@ get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) local_flush_tlb_all(); /* start new asid cycle */ #endif if (!asid) /* fix version if needed */ - asid = ASID_FIRST_VERSION; + asid = asid_first_version(cpu); } cpu_context(cpu, mm) = asid_cache(cpu) = asid; @@ -145,7 +140,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, htw_stop(); /* Check if our ASID is of an older version and thus invalid */ - if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK) + if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & asid_version_mask(cpu)) get_new_mmu_context(next, cpu); write_c0_entryhi(cpu_asid(cpu, next)); TLBMISS_HANDLER_SETUP_PGD(next->pgd); diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h index bbb85fe21642..6e4effa6f626 100644 --- a/arch/mips/include/asm/msa.h +++ b/arch/mips/include/asm/msa.h @@ -147,6 +147,19 @@ static inline void restore_msa(struct task_struct *t) _restore_msa(t); } +static inline void init_msa_upper(void) +{ + /* + * Check cpu_has_msa only if it's a constant. This will allow the + * compiler to optimise out code for CPUs without MSA without adding + * an extra redundant check for CPUs with MSA. + */ + if (__builtin_constant_p(cpu_has_msa) && !cpu_has_msa) + return; + + _init_msa_upper(); +} + #ifdef TOOLCHAIN_SUPPORTS_MSA #define __BUILD_MSA_CTL_REG(name, cs) \ diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h index d92cf59bdae6..62787765575e 100644 --- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h @@ -32,6 +32,8 @@ #ifndef __CVMX_BOOTINFO_H__ #define __CVMX_BOOTINFO_H__ +#include "cvmx-coremask.h" + /* * Current major and minor versions of the CVMX bootinfo block that is * passed from the bootloader to the application. This is versioned @@ -39,7 +41,7 @@ * versions. */ #define CVMX_BOOTINFO_MAJ_VER 1 -#define CVMX_BOOTINFO_MIN_VER 3 +#define CVMX_BOOTINFO_MIN_VER 4 #if (CVMX_BOOTINFO_MAJ_VER == 1) #define CVMX_BOOTINFO_OCTEON_SERIAL_LEN 20 @@ -124,6 +126,13 @@ struct cvmx_bootinfo { */ uint64_t fdt_addr; #endif +#if (CVMX_BOOTINFO_MIN_VER >= 4) + /* + * Coremask used for processors with more than 32 cores + * or with OCI. This replaces core_mask. + */ + struct cvmx_coremask ext_core_mask; +#endif #else /* __BIG_ENDIAN */ /* * Little-Endian: When the CPU mode is switched to @@ -177,6 +186,9 @@ struct cvmx_bootinfo { #if (CVMX_BOOTINFO_MIN_VER >= 3) uint64_t fdt_addr; #endif +#if (CVMX_BOOTINFO_MIN_VER >= 4) + struct cvmx_coremask ext_core_mask; +#endif #endif }; @@ -388,7 +400,7 @@ static inline const char *cvmx_board_type_to_string(enum ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX) } - return "Unsupported Board"; + return NULL; } #define ENUM_CHIP_TYPE_CASE(x) \ diff --git a/arch/mips/include/asm/octeon/cvmx-ciu3-defs.h b/arch/mips/include/asm/octeon/cvmx-ciu3-defs.h new file mode 100644 index 000000000000..547f778f5b05 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-ciu3-defs.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2003-2016 Cavium Inc. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, Version 2, as + * published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + */ + +#ifndef __CVMX_CIU3_DEFS_H__ +#define __CVMX_CIU3_DEFS_H__ + +#define CVMX_CIU3_FUSE CVMX_ADD_IO_SEG(0x00010100000001A0ull) +#define CVMX_CIU3_BIST CVMX_ADD_IO_SEG(0x00010100000001C0ull) +#define CVMX_CIU3_CONST CVMX_ADD_IO_SEG(0x0001010000000220ull) +#define CVMX_CIU3_CTL CVMX_ADD_IO_SEG(0x00010100000000E0ull) +#define CVMX_CIU3_DESTX_IO_INT(offset) (CVMX_ADD_IO_SEG(0x0001010000210000ull) + ((offset) & 7) * 8) +#define CVMX_CIU3_DESTX_PP_INT(offset) (CVMX_ADD_IO_SEG(0x0001010000200000ull) + ((offset) & 255) * 8) +#define CVMX_CIU3_GSTOP CVMX_ADD_IO_SEG(0x0001010000000140ull) +#define CVMX_CIU3_IDTX_CTL(offset) (CVMX_ADD_IO_SEG(0x0001010000110000ull) + ((offset) & 255) * 8) +#define CVMX_CIU3_IDTX_IO(offset) (CVMX_ADD_IO_SEG(0x0001010000130000ull) + ((offset) & 255) * 8) +#define CVMX_CIU3_IDTX_PPX(offset, block_id) (CVMX_ADD_IO_SEG(0x0001010000120000ull) + ((block_id) & 255) * 0x20ull) +#define CVMX_CIU3_INTR_RAM_ECC_CTL CVMX_ADD_IO_SEG(0x0001010000000260ull) +#define CVMX_CIU3_INTR_RAM_ECC_ST CVMX_ADD_IO_SEG(0x0001010000000280ull) +#define CVMX_CIU3_INTR_READY CVMX_ADD_IO_SEG(0x00010100000002A0ull) +#define CVMX_CIU3_INTR_SLOWDOWN CVMX_ADD_IO_SEG(0x0001010000000240ull) +#define CVMX_CIU3_ISCX_CTL(offset) (CVMX_ADD_IO_SEG(0x0001010080000000ull) + ((offset) & 1048575) * 8) +#define CVMX_CIU3_ISCX_W1C(offset) (CVMX_ADD_IO_SEG(0x0001010090000000ull) + ((offset) & 1048575) * 8) +#define CVMX_CIU3_ISCX_W1S(offset) (CVMX_ADD_IO_SEG(0x00010100A0000000ull) + ((offset) & 1048575) * 8) +#define CVMX_CIU3_NMI CVMX_ADD_IO_SEG(0x0001010000000160ull) +#define CVMX_CIU3_SISCX(offset) (CVMX_ADD_IO_SEG(0x0001010000220000ull) + ((offset) & 255) * 8) +#define CVMX_CIU3_TIMX(offset) (CVMX_ADD_IO_SEG(0x0001010000010000ull) + ((offset) & 15) * 8) + +union cvmx_ciu3_bist { + uint64_t u64; + struct cvmx_ciu3_bist_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_9_63 : 55; + uint64_t bist : 9; +#else + uint64_t bist : 9; + uint64_t reserved_9_63 : 55; +#endif + } s; +}; + +union cvmx_ciu3_const { + uint64_t u64; + struct cvmx_ciu3_const_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t dests_io : 16; + uint64_t pintsn : 16; + uint64_t dests_pp : 16; + uint64_t idt : 16; +#else + uint64_t idt : 16; + uint64_t dests_pp : 16; + uint64_t pintsn : 16; + uint64_t dests_io : 16; +#endif + } s; +}; + +union cvmx_ciu3_ctl { + uint64_t u64; + struct cvmx_ciu3_ctl_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_5_63 : 59; + uint64_t mcd_sel : 2; + uint64_t iscmem_le : 1; + uint64_t seq_dis : 1; + uint64_t cclk_dis : 1; +#else + uint64_t cclk_dis : 1; + uint64_t seq_dis : 1; + uint64_t iscmem_le : 1; + uint64_t mcd_sel : 2; + uint64_t reserved_5_63 : 59; +#endif + } s; +}; + +union cvmx_ciu3_destx_io_int { + uint64_t u64; + struct cvmx_ciu3_destx_io_int_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_52_63 : 12; + uint64_t intsn : 20; + uint64_t reserved_10_31 : 22; + uint64_t intidt : 8; + uint64_t newint : 1; + uint64_t intr : 1; +#else + uint64_t intr : 1; + uint64_t newint : 1; + uint64_t intidt : 8; + uint64_t reserved_10_31 : 22; + uint64_t intsn : 20; + uint64_t reserved_52_63 : 12; +#endif + } s; +}; + +union cvmx_ciu3_destx_pp_int { + uint64_t u64; + struct cvmx_ciu3_destx_pp_int_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_52_63 : 12; + uint64_t intsn : 20; + uint64_t reserved_10_31 : 22; + uint64_t intidt : 8; + uint64_t newint : 1; + uint64_t intr : 1; +#else + uint64_t intr : 1; + uint64_t newint : 1; + uint64_t intidt : 8; + uint64_t reserved_10_31 : 22; + uint64_t intsn : 20; + uint64_t reserved_52_63 : 12; +#endif + } s; +}; + +union cvmx_ciu3_gstop { + uint64_t u64; + struct cvmx_ciu3_gstop_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_1_63 : 63; + uint64_t gstop : 1; +#else + uint64_t gstop : 1; + uint64_t reserved_1_63 : 63; +#endif + } s; +}; + +union cvmx_ciu3_idtx_ctl { + uint64_t u64; + struct cvmx_ciu3_idtx_ctl_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_52_63 : 12; + uint64_t intsn : 20; + uint64_t reserved_4_31 : 28; + uint64_t intr : 1; + uint64_t newint : 1; + uint64_t ip_num : 2; +#else + uint64_t ip_num : 2; + uint64_t newint : 1; + uint64_t intr : 1; + uint64_t reserved_4_31 : 28; + uint64_t intsn : 20; + uint64_t reserved_52_63 : 12; +#endif + } s; +}; + +union cvmx_ciu3_idtx_io { + uint64_t u64; + struct cvmx_ciu3_idtx_io_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_5_63 : 59; + uint64_t io : 5; +#else + uint64_t io : 5; + uint64_t reserved_5_63 : 59; +#endif + } s; +}; + +union cvmx_ciu3_idtx_ppx { + uint64_t u64; + struct cvmx_ciu3_idtx_ppx_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_48_63 : 16; + uint64_t pp : 48; +#else + uint64_t pp : 48; + uint64_t reserved_48_63 : 16; +#endif + } s; +}; + +union cvmx_ciu3_intr_ram_ecc_ctl { + uint64_t u64; + struct cvmx_ciu3_intr_ram_ecc_ctl_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_3_63 : 61; + uint64_t flip_synd : 2; + uint64_t ecc_ena : 1; +#else + uint64_t ecc_ena : 1; + uint64_t flip_synd : 2; + uint64_t reserved_3_63 : 61; +#endif + } s; +}; + +union cvmx_ciu3_intr_ram_ecc_st { + uint64_t u64; + struct cvmx_ciu3_intr_ram_ecc_st_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_52_63 : 12; + uint64_t addr : 20; + uint64_t reserved_6_31 : 26; + uint64_t sisc_dbe : 1; + uint64_t sisc_sbe : 1; + uint64_t idt_dbe : 1; + uint64_t idt_sbe : 1; + uint64_t isc_dbe : 1; + uint64_t isc_sbe : 1; +#else + uint64_t isc_sbe : 1; + uint64_t isc_dbe : 1; + uint64_t idt_sbe : 1; + uint64_t idt_dbe : 1; + uint64_t sisc_sbe : 1; + uint64_t sisc_dbe : 1; + uint64_t reserved_6_31 : 26; + uint64_t addr : 20; + uint64_t reserved_52_63 : 12; +#endif + } s; +}; + +union cvmx_ciu3_intr_ready { + uint64_t u64; + struct cvmx_ciu3_intr_ready_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_46_63 : 18; + uint64_t index : 14; + uint64_t reserved_1_31 : 31; + uint64_t ready : 1; +#else + uint64_t ready : 1; + uint64_t reserved_1_31 : 31; + uint64_t index : 14; + uint64_t reserved_46_63 : 18; +#endif + } s; +}; + +union cvmx_ciu3_intr_slowdown { + uint64_t u64; + struct cvmx_ciu3_intr_slowdown_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_3_63 : 61; + uint64_t ctl : 3; +#else + uint64_t ctl : 3; + uint64_t reserved_3_63 : 61; +#endif + } s; +}; + +union cvmx_ciu3_iscx_ctl { + uint64_t u64; + struct cvmx_ciu3_iscx_ctl_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_24_63 : 40; + uint64_t idt : 8; + uint64_t imp : 1; + uint64_t reserved_2_14 : 13; + uint64_t en : 1; + uint64_t raw : 1; +#else + uint64_t raw : 1; + uint64_t en : 1; + uint64_t reserved_2_14 : 13; + uint64_t imp : 1; + uint64_t idt : 8; + uint64_t reserved_24_63 : 40; +#endif + } s; +}; + +union cvmx_ciu3_iscx_w1c { + uint64_t u64; + struct cvmx_ciu3_iscx_w1c_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_2_63 : 62; + uint64_t en : 1; + uint64_t raw : 1; +#else + uint64_t raw : 1; + uint64_t en : 1; + uint64_t reserved_2_63 : 62; +#endif + } s; +}; + +union cvmx_ciu3_iscx_w1s { + uint64_t u64; + struct cvmx_ciu3_iscx_w1s_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_2_63 : 62; + uint64_t en : 1; + uint64_t raw : 1; +#else + uint64_t raw : 1; + uint64_t en : 1; + uint64_t reserved_2_63 : 62; +#endif + } s; +}; + +union cvmx_ciu3_nmi { + uint64_t u64; + struct cvmx_ciu3_nmi_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_48_63 : 16; + uint64_t nmi : 48; +#else + uint64_t nmi : 48; + uint64_t reserved_48_63 : 16; +#endif + } s; +}; + +union cvmx_ciu3_siscx { + uint64_t u64; + struct cvmx_ciu3_siscx_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t en : 64; +#else + uint64_t en : 64; +#endif + } s; +}; + +union cvmx_ciu3_timx { + uint64_t u64; + struct cvmx_ciu3_timx_s { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_37_63 : 27; + uint64_t one_shot : 1; + uint64_t len : 36; +#else + uint64_t len : 36; + uint64_t one_shot : 1; + uint64_t reserved_37_63 : 27; +#endif + } s; +}; + +#endif diff --git a/arch/mips/include/asm/octeon/cvmx-coremask.h b/arch/mips/include/asm/octeon/cvmx-coremask.h new file mode 100644 index 000000000000..097dc096db84 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-coremask.h @@ -0,0 +1,89 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2016 Cavium Inc. (support@cavium.com). + * + */ + +/* + * Module to support operations on bitmap of cores. Coremask can be used to + * select a specific core, a group of cores, or all available cores, for + * initialization and differentiation of roles within a single shared binary + * executable image. + * + * The core numbers used in this file are the same value as what is found in + * the COP0_EBASE register and the rdhwr 0 instruction. + * + * For the CN78XX and other multi-node environments the core numbers are not + * contiguous. The core numbers for the CN78XX are as follows: + * + * Node 0: Cores 0 - 47 + * Node 1: Cores 128 - 175 + * Node 2: Cores 256 - 303 + * Node 3: Cores 384 - 431 + * + */ + +#ifndef __CVMX_COREMASK_H__ +#define __CVMX_COREMASK_H__ + +#define CVMX_MIPS_MAX_CORES 1024 +/* bits per holder */ +#define CVMX_COREMASK_ELTSZ 64 + +/* cvmx_coremask_t's size in u64 */ +#define CVMX_COREMASK_BMPSZ (CVMX_MIPS_MAX_CORES / CVMX_COREMASK_ELTSZ) + + +/* cvmx_coremask_t */ +struct cvmx_coremask { + u64 coremask_bitmap[CVMX_COREMASK_BMPSZ]; +}; + +/* + * Is ``core'' set in the coremask? + */ +static inline bool cvmx_coremask_is_core_set(const struct cvmx_coremask *pcm, + int core) +{ + int n, i; + + n = core % CVMX_COREMASK_ELTSZ; + i = core / CVMX_COREMASK_ELTSZ; + + return (pcm->coremask_bitmap[i] & ((u64)1 << n)) != 0; +} + +/* + * Make a copy of a coremask + */ +static inline void cvmx_coremask_copy(struct cvmx_coremask *dest, + const struct cvmx_coremask *src) +{ + memcpy(dest, src, sizeof(*dest)); +} + +/* + * Set the lower 64-bit of the coremask. + */ +static inline void cvmx_coremask_set64(struct cvmx_coremask *pcm, + uint64_t coremask_64) +{ + pcm->coremask_bitmap[0] = coremask_64; +} + +/* + * Clear ``core'' from the coremask. + */ +static inline void cvmx_coremask_clear_core(struct cvmx_coremask *pcm, int core) +{ + int n, i; + + n = core % CVMX_COREMASK_ELTSZ; + i = core / CVMX_COREMASK_ELTSZ; + pcm->coremask_bitmap[i] &= ~(1ull << n); +} + +#endif /* __CVMX_COREMASK_H__ */ diff --git a/arch/mips/include/asm/octeon/cvmx-fpa-defs.h b/arch/mips/include/asm/octeon/cvmx-fpa-defs.h index 1d79e3c7040d..887ff8e1f715 100644 --- a/arch/mips/include/asm/octeon/cvmx-fpa-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-fpa-defs.h @@ -66,6 +66,7 @@ #define CVMX_FPA_WART_CTL (CVMX_ADD_IO_SEG(0x00011800280000D8ull)) #define CVMX_FPA_WART_STATUS (CVMX_ADD_IO_SEG(0x00011800280000E0ull)) #define CVMX_FPA_WQE_THRESHOLD (CVMX_ADD_IO_SEG(0x0001180028000468ull)) +#define CVMX_FPA_CLK_COUNT (CVMX_ADD_IO_SEG(0x00012800000000F0ull)) union cvmx_fpa_addr_range_error { uint64_t u64; diff --git a/arch/mips/include/asm/octeon/cvmx-mio-defs.h b/arch/mips/include/asm/octeon/cvmx-mio-defs.h index bb0ae338a460..5196c04eee41 100644 --- a/arch/mips/include/asm/octeon/cvmx-mio-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-mio-defs.h @@ -1481,7 +1481,9 @@ union cvmx_mio_fus_dat2 { uint64_t u64; struct cvmx_mio_fus_dat2_s { #ifdef __BIG_ENDIAN_BITFIELD - uint64_t reserved_48_63:16; + uint64_t reserved_59_63:5; + uint64_t run_platform:3; + uint64_t gbl_pwr_throttle:8; uint64_t fus118:1; uint64_t rom_info:10; uint64_t power_limit:2; @@ -1513,7 +1515,9 @@ union cvmx_mio_fus_dat2 { uint64_t power_limit:2; uint64_t rom_info:10; uint64_t fus118:1; - uint64_t reserved_48_63:16; + uint64_t gbl_pwr_throttle:8; + uint64_t run_platform:3; + uint64_t reserved_59_63:5; #endif } s; struct cvmx_mio_fus_dat2_cn30xx { @@ -1837,50 +1841,192 @@ union cvmx_mio_fus_dat2 { #endif } cn68xx; struct cvmx_mio_fus_dat2_cn68xx cn68xxp1; + struct cvmx_mio_fus_dat2_cn70xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_48_63:16; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_31_29:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_25_24:2; + uint64_t chip_id:8; + uint64_t reserved_15_0:16; +#else + uint64_t reserved_15_0:16; + uint64_t chip_id:8; + uint64_t reserved_25_24:2; + uint64_t nocrypto:1; + uint64_t nomul:1; + uint64_t nodfa_cp2:1; + uint64_t reserved_31_29:3; + uint64_t raid_en:1; + uint64_t fus318:1; + uint64_t dorm_crypto:1; + uint64_t power_limit:2; + uint64_t rom_info:10; + uint64_t fus118:1; + uint64_t reserved_48_63:16; +#endif + } cn70xx; + struct cvmx_mio_fus_dat2_cn70xx cn70xxp1; + struct cvmx_mio_fus_dat2_cn73xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_59_63:5; + uint64_t run_platform:3; + uint64_t gbl_pwr_throttle:8; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_31_29:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_25_24:2; + uint64_t chip_id:8; + uint64_t reserved_15_0:16; +#else + uint64_t reserved_15_0:16; + uint64_t chip_id:8; + uint64_t reserved_25_24:2; + uint64_t nocrypto:1; + uint64_t nomul:1; + uint64_t nodfa_cp2:1; + uint64_t reserved_31_29:3; + uint64_t raid_en:1; + uint64_t fus318:1; + uint64_t dorm_crypto:1; + uint64_t power_limit:2; + uint64_t rom_info:10; + uint64_t fus118:1; + uint64_t gbl_pwr_throttle:8; + uint64_t run_platform:3; + uint64_t reserved_59_63:5; +#endif + } cn73xx; + struct cvmx_mio_fus_dat2_cn78xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_59_63:5; + uint64_t run_platform:3; + uint64_t reserved_48_55:8; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_31_29:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_25_24:2; + uint64_t chip_id:8; + uint64_t reserved_0_15:16; +#else + uint64_t reserved_0_15:16; + uint64_t chip_id:8; + uint64_t reserved_25_24:2; + uint64_t nocrypto:1; + uint64_t nomul:1; + uint64_t nodfa_cp2:1; + uint64_t reserved_31_29:3; + uint64_t raid_en:1; + uint64_t fus318:1; + uint64_t dorm_crypto:1; + uint64_t power_limit:2; + uint64_t rom_info:10; + uint64_t fus118:1; + uint64_t reserved_48_55:8; + uint64_t run_platform:3; + uint64_t reserved_59_63:5; +#endif + } cn78xx; + struct cvmx_mio_fus_dat2_cn78xxp2 { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_59_63:5; + uint64_t run_platform:3; + uint64_t gbl_pwr_throttle:8; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_31_29:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_25_24:2; + uint64_t chip_id:8; + uint64_t reserved_0_15:16; +#else + uint64_t reserved_0_15:16; + uint64_t chip_id:8; + uint64_t reserved_25_24:2; + uint64_t nocrypto:1; + uint64_t nomul:1; + uint64_t nodfa_cp2:1; + uint64_t reserved_31_29:3; + uint64_t raid_en:1; + uint64_t fus318:1; + uint64_t dorm_crypto:1; + uint64_t power_limit:2; + uint64_t rom_info:10; + uint64_t fus118:1; + uint64_t gbl_pwr_throttle:8; + uint64_t run_platform:3; + uint64_t reserved_59_63:5; +#endif + } cn78xxp2; struct cvmx_mio_fus_dat2_cn61xx cnf71xx; + struct cvmx_mio_fus_dat2_cn73xx cnf75xx; }; union cvmx_mio_fus_dat3 { uint64_t u64; struct cvmx_mio_fus_dat3_s { #ifdef __BIG_ENDIAN_BITFIELD - uint64_t reserved_58_63:6; + uint64_t ema0:6; uint64_t pll_ctl:10; uint64_t dfa_info_dte:3; uint64_t dfa_info_clm:4; - uint64_t reserved_40_40:1; - uint64_t ema:2; + uint64_t pll_alt_matrix:1; + uint64_t reserved_38_39:2; uint64_t efus_lck_rsv:1; uint64_t efus_lck_man:1; uint64_t pll_half_dis:1; uint64_t l2c_crip:3; - uint64_t pll_div4:1; - uint64_t reserved_29_30:2; - uint64_t bar2_en:1; + uint64_t reserved_28_31:4; uint64_t efus_lck:1; uint64_t efus_ign:1; uint64_t nozip:1; uint64_t nodfa_dte:1; - uint64_t icache:24; + uint64_t reserved_0_23:24; #else - uint64_t icache:24; + uint64_t reserved_0_23:24; uint64_t nodfa_dte:1; uint64_t nozip:1; uint64_t efus_ign:1; uint64_t efus_lck:1; - uint64_t bar2_en:1; - uint64_t reserved_29_30:2; - uint64_t pll_div4:1; + uint64_t reserved_28_31:4; uint64_t l2c_crip:3; uint64_t pll_half_dis:1; uint64_t efus_lck_man:1; uint64_t efus_lck_rsv:1; - uint64_t ema:2; - uint64_t reserved_40_40:1; + uint64_t reserved_38_39:2; + uint64_t pll_alt_matrix:1; uint64_t dfa_info_clm:4; uint64_t dfa_info_dte:3; uint64_t pll_ctl:10; - uint64_t reserved_58_63:6; + uint64_t ema0:6; #endif } s; struct cvmx_mio_fus_dat3_cn30xx { @@ -2022,7 +2168,239 @@ union cvmx_mio_fus_dat3 { struct cvmx_mio_fus_dat3_cn61xx cn66xx; struct cvmx_mio_fus_dat3_cn61xx cn68xx; struct cvmx_mio_fus_dat3_cn61xx cn68xxp1; + struct cvmx_mio_fus_dat3_cn70xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t pll_alt_matrix:1; + uint64_t pll_bwadj_denom:2; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t use_int_refclk:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t reserved_0_17:18; +#else + uint64_t reserved_0_17:18; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t use_int_refclk:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t pll_bwadj_denom:2; + uint64_t pll_alt_matrix:1; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cn70xx; + struct cvmx_mio_fus_dat3_cn70xxp1 { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t reserved_38_40:3; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t reserved_31_31:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t reserved_0_17:18; +#else + uint64_t reserved_0_17:18; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t reserved_31_31:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t reserved_38_40:3; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cn70xxp1; + struct cvmx_mio_fus_dat3_cn73xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t pll_alt_matrix:1; + uint64_t pll_bwadj_denom:2; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t use_int_refclk:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t nohna_dte:1; + uint64_t hna_info_dte:3; + uint64_t hna_info_clm:4; + uint64_t reserved_9_9:1; + uint64_t core_pll_mul:5; + uint64_t pnr_pll_mul:4; +#else + uint64_t pnr_pll_mul:4; + uint64_t core_pll_mul:5; + uint64_t reserved_9_9:1; + uint64_t hna_info_clm:4; + uint64_t hna_info_dte:3; + uint64_t nohna_dte:1; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t use_int_refclk:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t pll_bwadj_denom:2; + uint64_t pll_alt_matrix:1; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cn73xx; + struct cvmx_mio_fus_dat3_cn78xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t reserved_38_40:3; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t reserved_31_31:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t nohna_dte:1; + uint64_t hna_info_dte:3; + uint64_t hna_info_clm:4; + uint64_t reserved_0_9:10; +#else + uint64_t reserved_0_9:10; + uint64_t hna_info_clm:4; + uint64_t hna_info_dte:3; + uint64_t nohna_dte:1; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t reserved_31_31:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t reserved_38_40:3; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cn78xx; + struct cvmx_mio_fus_dat3_cn73xx cn78xxp2; struct cvmx_mio_fus_dat3_cn61xx cnf71xx; + struct cvmx_mio_fus_dat3_cnf75xx { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t ema0:6; + uint64_t pll_ctl:10; + uint64_t dfa_info_dte:3; + uint64_t dfa_info_clm:4; + uint64_t pll_alt_matrix:1; + uint64_t pll_bwadj_denom:2; + uint64_t efus_lck_rsv:1; + uint64_t efus_lck_man:1; + uint64_t pll_half_dis:1; + uint64_t l2c_crip:3; + uint64_t use_int_refclk:1; + uint64_t zip_info:2; + uint64_t bar2_sz_conf:1; + uint64_t efus_lck:1; + uint64_t efus_ign:1; + uint64_t nozip:1; + uint64_t nodfa_dte:1; + uint64_t ema1:6; + uint64_t reserved_9_17:9; + uint64_t core_pll_mul:5; + uint64_t pnr_pll_mul:4; +#else + uint64_t pnr_pll_mul:4; + uint64_t core_pll_mul:5; + uint64_t reserved_9_17:9; + uint64_t ema1:6; + uint64_t nodfa_dte:1; + uint64_t nozip:1; + uint64_t efus_ign:1; + uint64_t efus_lck:1; + uint64_t bar2_sz_conf:1; + uint64_t zip_info:2; + uint64_t use_int_refclk:1; + uint64_t l2c_crip:3; + uint64_t pll_half_dis:1; + uint64_t efus_lck_man:1; + uint64_t efus_lck_rsv:1; + uint64_t pll_bwadj_denom:2; + uint64_t pll_alt_matrix:1; + uint64_t dfa_info_clm:4; + uint64_t dfa_info_dte:3; + uint64_t pll_ctl:10; + uint64_t ema0:6; +#endif + } cnf75xx; }; union cvmx_mio_fus_ema { diff --git a/arch/mips/include/asm/octeon/cvmx-sysinfo.h b/arch/mips/include/asm/octeon/cvmx-sysinfo.h index 2131197422e5..c6c3ee39c69d 100644 --- a/arch/mips/include/asm/octeon/cvmx-sysinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-sysinfo.h @@ -4,7 +4,7 @@ * Contact: support@caviumnetworks.com * This file is part of the OCTEON SDK * - * Copyright (c) 2003-2008 Cavium Networks + * Copyright (c) 2003-2016 Cavium, Inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as @@ -32,6 +32,8 @@ #ifndef __CVMX_SYSINFO_H__ #define __CVMX_SYSINFO_H__ +#include "cvmx-coremask.h" + #define OCTEON_SERIAL_LEN 20 /** * Structure describing application specific information. @@ -50,8 +52,7 @@ struct cvmx_sysinfo { uint64_t system_dram_size; /* ptr to memory descriptor block */ - void *phy_mem_desc_ptr; - + uint64_t phy_mem_desc_addr; /* Application image specific variables */ /* stack top address (virtual) */ @@ -63,7 +64,7 @@ struct cvmx_sysinfo { /* heap size in bytes */ uint32_t heap_size; /* coremask defining cores running application */ - uint32_t core_mask; + struct cvmx_coremask core_mask; /* Deprecated, use cvmx_coremask_first_core() to select init core */ uint32_t init_core; @@ -121,32 +122,4 @@ struct cvmx_sysinfo { extern struct cvmx_sysinfo *cvmx_sysinfo_get(void); -/** - * This function is used in non-simple executive environments (such as - * Linux kernel, u-boot, etc.) to configure the minimal fields that - * are required to use simple executive files directly. - * - * Locking (if required) must be handled outside of this - * function - * - * @phy_mem_desc_ptr: Pointer to global physical memory descriptor - * (bootmem descriptor) @board_type: Octeon board - * type enumeration - * - * @board_rev_major: - * Board major revision - * @board_rev_minor: - * Board minor revision - * @cpu_clock_hz: - * CPU clock freqency in hertz - * - * Returns 0: Failure - * 1: success - */ -extern int cvmx_sysinfo_minimal_initialize(void *phy_mem_desc_ptr, - uint16_t board_type, - uint8_t board_rev_major, - uint8_t board_rev_minor, - uint32_t cpu_clock_hz); - #endif /* __CVMX_SYSINFO_H__ */ diff --git a/arch/mips/include/asm/octeon/cvmx.h b/arch/mips/include/asm/octeon/cvmx.h index 3e982e0c397e..2530e8731c8a 100644 --- a/arch/mips/include/asm/octeon/cvmx.h +++ b/arch/mips/include/asm/octeon/cvmx.h @@ -57,6 +57,7 @@ enum cvmx_mips_space { #include <asm/octeon/cvmx-sysinfo.h> #include <asm/octeon/cvmx-ciu-defs.h> +#include <asm/octeon/cvmx-ciu3-defs.h> #include <asm/octeon/cvmx-gpio-defs.h> #include <asm/octeon/cvmx-iob-defs.h> #include <asm/octeon/cvmx-ipd-defs.h> @@ -341,6 +342,21 @@ static inline unsigned int cvmx_get_core_num(void) return core_num; } +/* Maximum # of bits to define core in node */ +#define CVMX_NODE_NO_SHIFT 7 +#define CVMX_NODE_MASK 0x3 +static inline unsigned int cvmx_get_node_num(void) +{ + unsigned int core_num = cvmx_get_core_num(); + + return (core_num >> CVMX_NODE_NO_SHIFT) & CVMX_NODE_MASK; +} + +static inline unsigned int cvmx_get_local_core_num(void) +{ + return cvmx_get_core_num() & ((1 << CVMX_NODE_NO_SHIFT) - 1); +} + /** * Returns the number of bits set in the provided value. * Simple wrapper for POP instruction. @@ -448,8 +464,15 @@ static inline uint64_t cvmx_get_cycle_global(void) /* Return the number of cores available in the chip */ static inline uint32_t cvmx_octeon_num_cores(void) { - uint32_t ciu_fuse = (uint32_t) cvmx_read_csr(CVMX_CIU_FUSE) & 0xffff; - return cvmx_pop(ciu_fuse); + u64 ciu_fuse_reg; + u64 ciu_fuse; + + if (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX)) + ciu_fuse_reg = CVMX_CIU3_FUSE; + else + ciu_fuse_reg = CVMX_CIU_FUSE; + ciu_fuse = cvmx_read_csr(ciu_fuse_reg); + return cvmx_dpop(ciu_fuse); } #endif /* __CVMX_H__ */ diff --git a/arch/mips/include/asm/octeon/octeon-feature.h b/arch/mips/include/asm/octeon/octeon-feature.h index 3ed10a8d7865..a19ca3b2775c 100644 --- a/arch/mips/include/asm/octeon/octeon-feature.h +++ b/arch/mips/include/asm/octeon/octeon-feature.h @@ -81,6 +81,10 @@ enum octeon_feature { OCTEON_FEATURE_HFA, OCTEON_FEATURE_DFM, OCTEON_FEATURE_CIU2, + OCTEON_FEATURE_CIU3, + /* Octeon has FPA first seen on 78XX */ + OCTEON_FEATURE_FPA3, + OCTEON_FEATURE_FAU, OCTEON_MAX_FEATURE }; @@ -110,7 +114,7 @@ static inline int octeon_has_crypto(void) * Returns Non zero if the feature exists. Zero if the feature does not * exist. */ -static inline int octeon_has_feature(enum octeon_feature feature) +static inline bool octeon_has_feature(enum octeon_feature feature) { switch (feature) { case OCTEON_FEATURE_SAAD: @@ -122,7 +126,7 @@ static inline int octeon_has_feature(enum octeon_feature feature) fus_2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); return !fus_2.s.nocrypto && !fus_2.s.nomul && fus_2.s.dorm_crypto; } else { - return 0; + return false; } case OCTEON_FEATURE_PCIE: @@ -190,11 +194,20 @@ static inline int octeon_has_feature(enum octeon_feature feature) case OCTEON_FEATURE_CIU2: return OCTEON_IS_MODEL(OCTEON_CN68XX); + case OCTEON_FEATURE_CIU3: + case OCTEON_FEATURE_FPA3: + return OCTEON_IS_MODEL(OCTEON_CN78XX) + || OCTEON_IS_MODEL(OCTEON_CNF75XX) + || OCTEON_IS_MODEL(OCTEON_CN73XX); + case OCTEON_FEATURE_FAU: + return !(OCTEON_IS_MODEL(OCTEON_CN78XX) + || OCTEON_IS_MODEL(OCTEON_CNF75XX) + || OCTEON_IS_MODEL(OCTEON_CN73XX)); default: break; } - return 0; + return false; } #endif /* __OCTEON_FEATURE_H__ */ diff --git a/arch/mips/include/asm/octeon/octeon-model.h b/arch/mips/include/asm/octeon/octeon-model.h index 92b377e36dac..6c68517c2770 100644 --- a/arch/mips/include/asm/octeon/octeon-model.h +++ b/arch/mips/include/asm/octeon/octeon-model.h @@ -74,7 +74,12 @@ * CN7XXX models with new revision encoding */ +#define OCTEON_CNF75XX_PASS1_0 0x000d9800 +#define OCTEON_CNF75XX (OCTEON_CNF75XX_PASS1_0 | OM_IGNORE_REVISION) +#define OCTEON_CNF75XX_PASS1_X (OCTEON_CNF75XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) + #define OCTEON_CN73XX_PASS1_0 0x000d9700 +#define OCTEON_CN73XX_PASS1_1 0x000d9701 #define OCTEON_CN73XX (OCTEON_CN73XX_PASS1_0 | OM_IGNORE_REVISION) #define OCTEON_CN73XX_PASS1_X (OCTEON_CN73XX_PASS1_0 | \ OM_IGNORE_MINOR_REVISION) diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index de9f74ee5dd0..07c0516ef4d5 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h @@ -299,6 +299,31 @@ static inline void octeon_npi_write32(uint64_t address, uint32_t val) cvmx_read64_uint32(address ^ 4); } +#ifdef CONFIG_SMP +void octeon_setup_smp(void); +#else +static inline void octeon_setup_smp(void) {} +#endif + +struct irq_domain; +struct device_node; +struct irq_data; +struct irq_chip; +void octeon_ciu3_mbox_send(int cpu, unsigned int mbox); +int octeon_irq_ciu3_xlat(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type); +void octeon_irq_ciu3_enable(struct irq_data *data); +void octeon_irq_ciu3_disable(struct irq_data *data); +void octeon_irq_ciu3_ack(struct irq_data *data); +void octeon_irq_ciu3_mask(struct irq_data *data); +void octeon_irq_ciu3_mask_ack(struct irq_data *data); +int octeon_irq_ciu3_mapx(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw, struct irq_chip *chip); + /* Octeon multiplier save/restore routines from octeon_switch.S */ void octeon_mult_save(void); void octeon_mult_restore(void); diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 8c16fb7b8fdb..86b239d9d75d 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -43,8 +43,6 @@ struct pci_controller { and XFree86. Eventually will be removed. */ unsigned int need_domain_info; - int iommu; - /* Optional access methods for reading/writing the bus number of the PCI controller */ int (*get_busno)(void); @@ -106,11 +104,11 @@ static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, struct pci_dev; /* - * The PCI address space does equal the physical memory address space. The - * networking and block device layers use this boolean for bounce buffer - * decisions. This is set if any hose does not have an IOMMU. + * The PCI address space does equal the physical memory address space. + * The networking and block device layers use this boolean for bounce + * buffer decisions. */ -extern unsigned int PCI_DMA_BUS_IS_PHYS; +#define PCI_DMA_BUS_IS_PHYS (1) #ifdef CONFIG_PCI_DOMAINS #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h index 832e2167d00f..d21f3da7bdb6 100644 --- a/arch/mips/include/asm/pgtable-32.h +++ b/arch/mips/include/asm/pgtable-32.h @@ -103,8 +103,8 @@ static inline void pmd_clear(pmd_t *pmdp) pmd_val(*pmdp) = ((unsigned long) invalid_pte_table); } -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) -#define pte_page(x) pfn_to_page(pte_pfn(x)) +#if defined(CONFIG_XPA) + #define pte_pfn(x) (((unsigned long)((x).pte_high >> _PFN_SHIFT)) | (unsigned long)((x).pte_low << _PAGE_PRESENT_SHIFT)) static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) @@ -118,9 +118,21 @@ pfn_pte(unsigned long pfn, pgprot_t prot) return pte; } -#else +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) -#define pte_page(x) pfn_to_page(pte_pfn(x)) +#define pte_pfn(x) ((unsigned long)((x).pte_high >> 6)) + +static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) +{ + pte_t pte; + + pte.pte_high = (pfn << 6) | (pgprot_val(prot) & 0x3f); + pte.pte_low = pgprot_val(prot); + + return pte; +} + +#else #ifdef CONFIG_CPU_VR41XX #define pte_pfn(x) ((unsigned long)((x).pte >> (PAGE_SHIFT + 2))) @@ -131,6 +143,8 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #endif #endif /* defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) */ +#define pte_page(x) pfn_to_page(pte_pfn(x)) + #define __pgd_offset(address) pgd_index(address) #define __pud_offset(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) #define __pmd_offset(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) @@ -166,7 +180,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #else -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_XPA) /* Swap entries must have VALID and GLOBAL bits cleared. */ #define __swp_type(x) (((x).val >> 4) & 0x1f) @@ -175,6 +189,15 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high }) #define __swp_entry_to_pte(x) ((pte_t) { 0, (x).val }) +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) + +/* Swap entries must have VALID and GLOBAL bits cleared. */ +#define __swp_type(x) (((x).val >> 2) & 0x1f) +#define __swp_offset(x) ((x).val >> 7) +#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 7) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high }) +#define __swp_entry_to_pte(x) ((pte_t) { 0, (x).val }) + #else /* * Constraints: diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h index cf661a2fb141..514cbc0a6a67 100644 --- a/arch/mips/include/asm/pgtable-64.h +++ b/arch/mips/include/asm/pgtable-64.h @@ -17,7 +17,7 @@ #include <asm/cachectl.h> #include <asm/fixmap.h> -#ifdef CONFIG_PAGE_SIZE_64KB +#if defined(CONFIG_PAGE_SIZE_64KB) && !defined(CONFIG_MIPS_VA_BITS_48) #include <asm-generic/pgtable-nopmd.h> #else #include <asm-generic/pgtable-nopud.h> @@ -90,7 +90,11 @@ #define PTE_ORDER 0 #endif #ifdef CONFIG_PAGE_SIZE_16KB -#define PGD_ORDER 0 +#ifdef CONFIG_MIPS_VA_BITS_48 +#define PGD_ORDER 1 +#else +#define PGD_ORDER 0 +#endif #define PUD_ORDER aieeee_attempt_to_allocate_pud #define PMD_ORDER 0 #define PTE_ORDER 0 @@ -104,7 +108,11 @@ #ifdef CONFIG_PAGE_SIZE_64KB #define PGD_ORDER 0 #define PUD_ORDER aieeee_attempt_to_allocate_pud +#ifdef CONFIG_MIPS_VA_BITS_48 +#define PMD_ORDER 0 +#else #define PMD_ORDER aieeee_attempt_to_allocate_pmd +#endif #define PTE_ORDER 0 #endif @@ -114,11 +122,7 @@ #endif #define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t)) -#if PGDIR_SIZE >= TASK_SIZE64 -#define USER_PTRS_PER_PGD (1) -#else -#define USER_PTRS_PER_PGD (TASK_SIZE64 / PGDIR_SIZE) -#endif +#define USER_PTRS_PER_PGD ((TASK_SIZE64 / PGDIR_SIZE)?(TASK_SIZE64 / PGDIR_SIZE):1) #define FIRST_USER_ADDRESS 0UL /* diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index 97b313882678..f88a48cd68b2 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -32,149 +32,132 @@ * unpredictable things. The code (when it is written) to deal with * this problem will be in the update_mmu_cache() code for the r4k. */ -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_XPA) /* - * The following bits are implemented by the TLB hardware + * Page table bit offsets used for 64 bit physical addressing on + * MIPS32r5 with XPA. */ -#define _PAGE_NO_EXEC_SHIFT 0 -#define _PAGE_NO_EXEC (1 << _PAGE_NO_EXEC_SHIFT) -#define _PAGE_NO_READ_SHIFT (_PAGE_NO_EXEC_SHIFT + 1) -#define _PAGE_NO_READ (1 << _PAGE_NO_READ_SHIFT) -#define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) -#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) -#define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) -#define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -#define _PAGE_DIRTY_SHIFT (_PAGE_VALID_SHIFT + 1) -#define _PAGE_DIRTY (1 << _PAGE_DIRTY_SHIFT) -#define _CACHE_SHIFT (_PAGE_DIRTY_SHIFT + 1) -#define _CACHE_MASK (7 << _CACHE_SHIFT) - -/* - * The following bits are implemented in software - */ -#define _PAGE_PRESENT_SHIFT (24) -#define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) -#define _PAGE_READ_SHIFT (_PAGE_PRESENT_SHIFT + 1) -#define _PAGE_READ (1 << _PAGE_READ_SHIFT) -#define _PAGE_WRITE_SHIFT (_PAGE_READ_SHIFT + 1) -#define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#define _PAGE_ACCESSED_SHIFT (_PAGE_WRITE_SHIFT + 1) -#define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) -#define _PAGE_MODIFIED_SHIFT (_PAGE_ACCESSED_SHIFT + 1) -#define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) - -#define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) +enum pgtable_bits { + /* Used by TLB hardware (placed in EntryLo*) */ + _PAGE_NO_EXEC_SHIFT, + _PAGE_NO_READ_SHIFT, + _PAGE_GLOBAL_SHIFT, + _PAGE_VALID_SHIFT, + _PAGE_DIRTY_SHIFT, + _CACHE_SHIFT, + + /* Used only by software (masked out before writing EntryLo*) */ + _PAGE_PRESENT_SHIFT = 24, + _PAGE_WRITE_SHIFT, + _PAGE_ACCESSED_SHIFT, + _PAGE_MODIFIED_SHIFT, +}; /* * Bits for extended EntryLo0/EntryLo1 registers */ #define _PFNX_MASK 0xffffff -#elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) /* - * The following bits are implemented in software + * Page table bit offsets used for 36 bit physical addressing on MIPS32, + * for example with Alchemy or Netlogic XLP/XLR. */ -#define _PAGE_PRESENT_SHIFT (0) -#define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) -#define _PAGE_READ_SHIFT (_PAGE_PRESENT_SHIFT + 1) -#define _PAGE_READ (1 << _PAGE_READ_SHIFT) -#define _PAGE_WRITE_SHIFT (_PAGE_READ_SHIFT + 1) -#define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#define _PAGE_ACCESSED_SHIFT (_PAGE_WRITE_SHIFT + 1) -#define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) -#define _PAGE_MODIFIED_SHIFT (_PAGE_ACCESSED_SHIFT + 1) -#define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) +enum pgtable_bits { + /* Used by TLB hardware (placed in EntryLo*) */ + _PAGE_GLOBAL_SHIFT, + _PAGE_VALID_SHIFT, + _PAGE_DIRTY_SHIFT, + _CACHE_SHIFT, + + /* Used only by software (masked out before writing EntryLo*) */ + _PAGE_PRESENT_SHIFT = _CACHE_SHIFT + 3, + _PAGE_NO_READ_SHIFT, + _PAGE_WRITE_SHIFT, + _PAGE_ACCESSED_SHIFT, + _PAGE_MODIFIED_SHIFT, +}; -/* - * The following bits are implemented by the TLB hardware - */ -#define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 4) -#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) -#define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) -#define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -#define _PAGE_DIRTY_SHIFT (_PAGE_VALID_SHIFT + 1) -#define _PAGE_DIRTY (1 << _PAGE_DIRTY_SHIFT) -#define _CACHE_UNCACHED_SHIFT (_PAGE_DIRTY_SHIFT + 1) -#define _CACHE_UNCACHED (1 << _CACHE_UNCACHED_SHIFT) -#define _CACHE_MASK _CACHE_UNCACHED +#elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) -#define _PFN_SHIFT PAGE_SHIFT +/* Page table bits used for r3k systems */ +enum pgtable_bits { + /* Used only by software (writes to EntryLo ignored) */ + _PAGE_PRESENT_SHIFT, + _PAGE_NO_READ_SHIFT, + _PAGE_WRITE_SHIFT, + _PAGE_ACCESSED_SHIFT, + _PAGE_MODIFIED_SHIFT, + + /* Used by TLB hardware (placed in EntryLo) */ + _PAGE_GLOBAL_SHIFT = 8, + _PAGE_VALID_SHIFT, + _PAGE_DIRTY_SHIFT, + _CACHE_UNCACHED_SHIFT, +}; #else -/* - * Below are the "Normal" R4K cases - */ -/* - * The following bits are implemented in software - */ -#define _PAGE_PRESENT_SHIFT 0 +/* Page table bits used for r4k systems */ +enum pgtable_bits { + /* Used only by software (masked out before writing EntryLo*) */ + _PAGE_PRESENT_SHIFT, +#if !defined(CONFIG_CPU_HAS_RIXI) + _PAGE_NO_READ_SHIFT, +#endif + _PAGE_WRITE_SHIFT, + _PAGE_ACCESSED_SHIFT, + _PAGE_MODIFIED_SHIFT, +#if defined(CONFIG_64BIT) && defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) + _PAGE_HUGE_SHIFT, +#endif + + /* Used by TLB hardware (placed in EntryLo*) */ +#if defined(CONFIG_CPU_HAS_RIXI) + _PAGE_NO_EXEC_SHIFT, + _PAGE_NO_READ_SHIFT, +#endif + _PAGE_GLOBAL_SHIFT, + _PAGE_VALID_SHIFT, + _PAGE_DIRTY_SHIFT, + _CACHE_SHIFT, +}; + +#endif /* defined(CONFIG_PHYS_ADDR_T_64BIT && defined(CONFIG_CPU_MIPS32) */ + +/* Used only by software */ #define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) -/* R2 or later cores check for RI/XI support to determine _PAGE_READ */ -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) -#define _PAGE_WRITE_SHIFT (_PAGE_PRESENT_SHIFT + 1) -#define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#else -#define _PAGE_READ_SHIFT (_PAGE_PRESENT_SHIFT + 1) -#define _PAGE_READ (1 << _PAGE_READ_SHIFT) -#define _PAGE_WRITE_SHIFT (_PAGE_READ_SHIFT + 1) #define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#endif -#define _PAGE_ACCESSED_SHIFT (_PAGE_WRITE_SHIFT + 1) #define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) -#define _PAGE_MODIFIED_SHIFT (_PAGE_ACCESSED_SHIFT + 1) #define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) - #if defined(CONFIG_64BIT) && defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) -/* Huge TLB page */ -#define _PAGE_HUGE_SHIFT (_PAGE_MODIFIED_SHIFT + 1) -#define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) -#endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */ - -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) -/* XI - page cannot be executed */ -#ifdef _PAGE_HUGE_SHIFT -#define _PAGE_NO_EXEC_SHIFT (_PAGE_HUGE_SHIFT + 1) -#else -#define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1) +# define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) #endif -#define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) - -/* RI - page cannot be read */ -#define _PAGE_READ_SHIFT (_PAGE_NO_EXEC_SHIFT + 1) -#define _PAGE_READ (cpu_has_rixi ? 0 : (1 << _PAGE_READ_SHIFT)) -#define _PAGE_NO_READ_SHIFT _PAGE_READ_SHIFT -#define _PAGE_NO_READ (cpu_has_rixi ? (1 << _PAGE_READ_SHIFT) : 0) -#endif /* defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) */ - -#if defined(_PAGE_NO_READ_SHIFT) -#define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) -#elif defined(_PAGE_HUGE_SHIFT) -#define _PAGE_GLOBAL_SHIFT (_PAGE_HUGE_SHIFT + 1) -#else -#define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) + +/* Used by TLB hardware (placed in EntryLo*) */ +#if defined(CONFIG_XPA) +# define _PAGE_NO_EXEC (1 << _PAGE_NO_EXEC_SHIFT) +#elif defined(CONFIG_CPU_HAS_RIXI) +# define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) #endif +#define _PAGE_NO_READ (1 << _PAGE_NO_READ_SHIFT) #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) - -#define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) #define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -#define _PAGE_DIRTY_SHIFT (_PAGE_VALID_SHIFT + 1) #define _PAGE_DIRTY (1 << _PAGE_DIRTY_SHIFT) -#define _CACHE_SHIFT (_PAGE_DIRTY_SHIFT + 1) -#define _CACHE_MASK (7 << _CACHE_SHIFT) - -#define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) - -#endif /* defined(CONFIG_PHYS_ADDR_T_64BIT && defined(CONFIG_CPU_MIPS32) */ +#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) +# define _CACHE_UNCACHED (1 << _CACHE_UNCACHED_SHIFT) +# define _CACHE_MASK _CACHE_UNCACHED +# define _PFN_SHIFT PAGE_SHIFT +#else +# define _CACHE_MASK (7 << _CACHE_SHIFT) +# define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) +#endif #ifndef _PAGE_NO_EXEC #define _PAGE_NO_EXEC 0 #endif -#ifndef _PAGE_NO_READ -#define _PAGE_NO_READ 0 -#endif #define _PAGE_SILENT_READ _PAGE_VALID #define _PAGE_SILENT_WRITE _PAGE_DIRTY @@ -191,14 +174,13 @@ */ -#ifndef __ASSEMBLY__ /* * pte_to_entrylo converts a page table entry (PTE) into a Mips * entrylo0/1 value. */ static inline uint64_t pte_to_entrylo(unsigned long pte_val) { -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) +#ifdef CONFIG_CPU_HAS_RIXI if (cpu_has_rixi) { int sa; #ifdef CONFIG_32BIT @@ -218,7 +200,6 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) return pte_val >> _PAGE_GLOBAL_SHIFT; } -#endif /* * Cache attributes @@ -274,7 +255,7 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) #define _CACHE_UNCACHED_ACCELERATED (7<<_CACHE_SHIFT) #endif -#define __READABLE (_PAGE_SILENT_READ | _PAGE_READ | _PAGE_ACCESSED) +#define __READABLE (_PAGE_SILENT_READ | _PAGE_ACCESSED) #define __WRITEABLE (_PAGE_SILENT_WRITE | _PAGE_WRITE | _PAGE_MODIFIED) #define _PAGE_CHG_MASK (_PAGE_ACCESSED | _PAGE_MODIFIED | \ diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 9a4fe0133ff1..e07a105cafc2 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -23,18 +23,19 @@ struct mm_struct; struct vm_area_struct; -#define PAGE_NONE __pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_WRITE | _PAGE_READ | \ +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_NO_READ | \ + _CACHE_CACHABLE_NONCOHERENT) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_WRITE | \ _page_cachable_default) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_NO_EXEC | \ +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_NO_EXEC | \ _page_cachable_default) -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_READ | \ +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | \ _page_cachable_default) #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ _PAGE_GLOBAL | _page_cachable_default) #define PAGE_KERNEL_NC __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ _PAGE_GLOBAL | _CACHE_CACHABLE_NONCOHERENT) -#define PAGE_USERIO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ +#define PAGE_USERIO __pgprot(_PAGE_PRESENT | _PAGE_WRITE | \ _page_cachable_default) #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | \ __WRITEABLE | _PAGE_GLOBAL | _CACHE_UNCACHED) @@ -127,10 +128,19 @@ do { \ } \ } while(0) +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval); + #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) -#define pte_none(pte) (!(((pte).pte_high) & ~_PAGE_GLOBAL)) +#ifdef CONFIG_XPA +# define pte_none(pte) (!(((pte).pte_high) & ~_PAGE_GLOBAL)) +#else +# define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL)) +#endif + #define pte_present(pte) ((pte).pte_low & _PAGE_PRESENT) +#define pte_no_exec(pte) ((pte).pte_low & _PAGE_NO_EXEC) static inline void set_pte(pte_t *ptep, pte_t pte) { @@ -138,17 +148,23 @@ static inline void set_pte(pte_t *ptep, pte_t pte) smp_wmb(); ptep->pte_low = pte.pte_low; +#ifdef CONFIG_XPA if (pte.pte_high & _PAGE_GLOBAL) { +#else + if (pte.pte_low & _PAGE_GLOBAL) { +#endif pte_t *buddy = ptep_buddy(ptep); /* * Make sure the buddy is global too (if it's !none, * it better already be global) */ - if (pte_none(*buddy)) + if (pte_none(*buddy)) { + if (!config_enabled(CONFIG_XPA)) + buddy->pte_low |= _PAGE_GLOBAL; buddy->pte_high |= _PAGE_GLOBAL; + } } } -#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { @@ -156,8 +172,13 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt htw_stop(); /* Preserve global status for the pair */ - if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL) - null.pte_high = _PAGE_GLOBAL; + if (config_enabled(CONFIG_XPA)) { + if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL) + null.pte_high = _PAGE_GLOBAL; + } else { + if (ptep_buddy(ptep)->pte_low & _PAGE_GLOBAL) + null.pte_low = null.pte_high = _PAGE_GLOBAL; + } set_pte_at(mm, addr, ptep, null); htw_start(); @@ -166,6 +187,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt #define pte_none(pte) (!(pte_val(pte) & ~_PAGE_GLOBAL)) #define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) +#define pte_no_exec(pte) (pte_val(pte) & _PAGE_NO_EXEC) /* * Certain architectures need to do special things when pte's @@ -187,30 +209,42 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) * For SMP, multiple CPUs can race, so we need to do * this atomically. */ -#ifdef CONFIG_64BIT -#define LL_INSN "lld" -#define SC_INSN "scd" -#else /* CONFIG_32BIT */ -#define LL_INSN "ll" -#define SC_INSN "sc" -#endif unsigned long page_global = _PAGE_GLOBAL; unsigned long tmp; - __asm__ __volatile__ ( - " .set push\n" - " .set noreorder\n" - "1: " LL_INSN " %[tmp], %[buddy]\n" - " bnez %[tmp], 2f\n" - " or %[tmp], %[tmp], %[global]\n" - " " SC_INSN " %[tmp], %[buddy]\n" - " beqz %[tmp], 1b\n" - " nop\n" - "2:\n" - " .set pop" - : [buddy] "+m" (buddy->pte), - [tmp] "=&r" (tmp) + if (kernel_uses_llsc && R10000_LLSC_WAR) { + __asm__ __volatile__ ( + " .set arch=r4000 \n" + " .set push \n" + " .set noreorder \n" + "1:" __LL "%[tmp], %[buddy] \n" + " bnez %[tmp], 2f \n" + " or %[tmp], %[tmp], %[global] \n" + __SC "%[tmp], %[buddy] \n" + " beqzl %[tmp], 1b \n" + " nop \n" + "2: \n" + " .set pop \n" + " .set mips0 \n" + : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) + : [global] "r" (page_global)); + } else if (kernel_uses_llsc) { + __asm__ __volatile__ ( + " .set "MIPS_ISA_ARCH_LEVEL" \n" + " .set push \n" + " .set noreorder \n" + "1:" __LL "%[tmp], %[buddy] \n" + " bnez %[tmp], 2f \n" + " or %[tmp], %[tmp], %[global] \n" + __SC "%[tmp], %[buddy] \n" + " beqz %[tmp], 1b \n" + " nop \n" + "2: \n" + " .set pop \n" + " .set mips0 \n" + : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) : [global] "r" (page_global)); + } #else /* !CONFIG_SMP */ if (pte_none(*buddy)) pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL; @@ -218,7 +252,6 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) } #endif } -#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { @@ -234,6 +267,22 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt } #endif +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) +{ + extern void __update_cache(unsigned long address, pte_t pte); + + if (!pte_present(pteval)) + goto cache_sync_done; + + if (pte_present(*ptep) && (pte_pfn(*ptep) == pte_pfn(pteval))) + goto cache_sync_done; + + __update_cache(addr, pteval); +cache_sync_done: + set_pte(ptep, pteval); +} + /* * (pmds are folded into puds so this doesn't get actually called, * but the define is needed for a generic inline function.) @@ -270,6 +319,8 @@ static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; } static inline pte_t pte_wrprotect(pte_t pte) { pte.pte_low &= ~_PAGE_WRITE; + if (!config_enabled(CONFIG_XPA)) + pte.pte_low &= ~_PAGE_SILENT_WRITE; pte.pte_high &= ~_PAGE_SILENT_WRITE; return pte; } @@ -277,6 +328,8 @@ static inline pte_t pte_wrprotect(pte_t pte) static inline pte_t pte_mkclean(pte_t pte) { pte.pte_low &= ~_PAGE_MODIFIED; + if (!config_enabled(CONFIG_XPA)) + pte.pte_low &= ~_PAGE_SILENT_WRITE; pte.pte_high &= ~_PAGE_SILENT_WRITE; return pte; } @@ -284,6 +337,8 @@ static inline pte_t pte_mkclean(pte_t pte) static inline pte_t pte_mkold(pte_t pte) { pte.pte_low &= ~_PAGE_ACCESSED; + if (!config_enabled(CONFIG_XPA)) + pte.pte_low &= ~_PAGE_SILENT_READ; pte.pte_high &= ~_PAGE_SILENT_READ; return pte; } @@ -291,24 +346,33 @@ static inline pte_t pte_mkold(pte_t pte) static inline pte_t pte_mkwrite(pte_t pte) { pte.pte_low |= _PAGE_WRITE; - if (pte.pte_low & _PAGE_MODIFIED) + if (pte.pte_low & _PAGE_MODIFIED) { + if (!config_enabled(CONFIG_XPA)) + pte.pte_low |= _PAGE_SILENT_WRITE; pte.pte_high |= _PAGE_SILENT_WRITE; + } return pte; } static inline pte_t pte_mkdirty(pte_t pte) { pte.pte_low |= _PAGE_MODIFIED; - if (pte.pte_low & _PAGE_WRITE) + if (pte.pte_low & _PAGE_WRITE) { + if (!config_enabled(CONFIG_XPA)) + pte.pte_low |= _PAGE_SILENT_WRITE; pte.pte_high |= _PAGE_SILENT_WRITE; + } return pte; } static inline pte_t pte_mkyoung(pte_t pte) { pte.pte_low |= _PAGE_ACCESSED; - if (pte.pte_low & _PAGE_READ) + if (!(pte.pte_low & _PAGE_NO_READ)) { + if (!config_enabled(CONFIG_XPA)) + pte.pte_low |= _PAGE_SILENT_READ; pte.pte_high |= _PAGE_SILENT_READ; + } return pte; } #else @@ -353,13 +417,8 @@ static inline pte_t pte_mkdirty(pte_t pte) static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) if (!(pte_val(pte) & _PAGE_NO_READ)) pte_val(pte) |= _PAGE_SILENT_READ; - else -#endif - if (pte_val(pte) & _PAGE_READ) - pte_val(pte) |= _PAGE_SILENT_READ; return pte; } @@ -411,7 +470,7 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot) */ #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_XPA) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte.pte_low &= (_PAGE_MODIFIED | _PAGE_ACCESSED | _PFNX_MASK); @@ -420,6 +479,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) pte.pte_high |= pgprot_val(newprot) & ~_PFN_MASK; return pte; } +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte.pte_low &= _PAGE_CHG_MASK; + pte.pte_high &= (_PFN_MASK | _CACHE_MASK); + pte.pte_low |= pgprot_val(newprot); + pte.pte_high |= pgprot_val(newprot) & ~(_PFN_MASK | _CACHE_MASK); + return pte; +} #else static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { @@ -430,15 +498,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) extern void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte); -extern void __update_cache(struct vm_area_struct *vma, unsigned long address, - pte_t pte); static inline void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { pte_t pte = *ptep; __update_tlb(vma, address, pte); - __update_cache(vma, address, pte); } static inline void update_mmu_cache_pmd(struct vm_area_struct *vma, @@ -542,13 +607,8 @@ static inline pmd_t pmd_mkyoung(pmd_t pmd) { pmd_val(pmd) |= _PAGE_ACCESSED; -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) if (!(pmd_val(pmd) & _PAGE_NO_READ)) pmd_val(pmd) |= _PAGE_SILENT_READ; - else -#endif - if (pmd_val(pmd) & _PAGE_READ) - pmd_val(pmd) |= _PAGE_SILENT_READ; return pmd; } diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 041153f5cf93..7e78b6208d7d 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -63,7 +63,11 @@ extern unsigned int vced_count, vcei_count; * 8192EB ... */ #define TASK_SIZE32 0x7fff8000UL -#define TASK_SIZE64 0x10000000000UL +#ifdef CONFIG_MIPS_VA_BITS_48 +#define TASK_SIZE64 (0x1UL << ((cpu_data[0].vmbits>48)?48:cpu_data[0].vmbits)) +#else +#define TASK_SIZE64 0x10000000000UL +#endif #define TASK_SIZE (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE64) #define STACK_TOP_MAX TASK_SIZE64 @@ -355,6 +359,10 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk); */ extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); +static inline void flush_thread(void) +{ +} + unsigned long get_wchan(struct task_struct *p); #define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \ diff --git a/arch/mips/include/asm/seccomp.h b/arch/mips/include/asm/seccomp.h index 1d8a2e2c75c1..684fb3a12ed3 100644 --- a/arch/mips/include/asm/seccomp.h +++ b/arch/mips/include/asm/seccomp.h @@ -2,27 +2,32 @@ #include <linux/unistd.h> -/* - * Kludge alert: - * - * The generic seccomp code currently allows only a single compat ABI. Until - * this is fixed we priorize O32 as the compat ABI over N32. - */ -#ifdef CONFIG_MIPS32_O32 - -#define __NR_seccomp_read_32 4003 -#define __NR_seccomp_write_32 4004 -#define __NR_seccomp_exit_32 4001 -#define __NR_seccomp_sigreturn_32 4193 /* rt_sigreturn */ - -#elif defined(CONFIG_MIPS32_N32) - -#define __NR_seccomp_read_32 6000 -#define __NR_seccomp_write_32 6001 -#define __NR_seccomp_exit_32 6058 -#define __NR_seccomp_sigreturn_32 6211 /* rt_sigreturn */ - -#endif /* CONFIG_MIPS32_O32 */ +#ifdef CONFIG_COMPAT +static inline const int *get_compat_mode1_syscalls(void) +{ + static const int syscalls_O32[] = { + __NR_O32_Linux + 3, __NR_O32_Linux + 4, + __NR_O32_Linux + 1, __NR_O32_Linux + 193, + 0, /* null terminated */ + }; + static const int syscalls_N32[] = { + __NR_N32_Linux + 0, __NR_N32_Linux + 1, + __NR_N32_Linux + 58, __NR_N32_Linux + 211, + 0, /* null terminated */ + }; + + if (config_enabled(CONFIG_MIPS32_O32) && test_thread_flag(TIF_32BIT_REGS)) + return syscalls_O32; + + if (config_enabled(CONFIG_MIPS32_N32)) + return syscalls_N32; + + BUG(); +} + +#define get_compat_mode1_syscalls get_compat_mode1_syscalls + +#endif /* CONFIG_COMPAT */ #include <asm-generic/seccomp.h> diff --git a/arch/mips/include/asm/sibyte/bcm1480_regs.h b/arch/mips/include/asm/sibyte/bcm1480_regs.h index ec0dacf6f0cb..32a84837b8fa 100644 --- a/arch/mips/include/asm/sibyte/bcm1480_regs.h +++ b/arch/mips/include/asm/sibyte/bcm1480_regs.h @@ -415,8 +415,8 @@ (cpu)*BCM1480_IMR_ALIAS_MAILBOX_SPACING) #define A_BCM1480_IMR_ALIAS_MAILBOX_REGISTER(cpu, reg) (A_BCM1480_IMR_ALIAS_MAILBOX(cpu)+(reg)) -#define R_BCM1480_IMR_ALIAS_MAILBOX_0 0x0000 /* 0x0x0 */ -#define R_BCM1480_IMR_ALIAS_MAILBOX_0_SET 0x0008 /* 0x0x8 */ +#define R_BCM1480_IMR_ALIAS_MAILBOX_0 0x0000 +#define R_BCM1480_IMR_ALIAS_MAILBOX_0_SET 0x0008 /* * these macros work together to build the address of a mailbox diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h index 003e273eff4c..2292373ff11a 100644 --- a/arch/mips/include/asm/signal.h +++ b/arch/mips/include/asm/signal.h @@ -11,11 +11,17 @@ #include <uapi/asm/signal.h> +#ifdef CONFIG_MIPS32_COMPAT +extern struct mips_abi mips_abi_32; -#ifdef CONFIG_TRAD_SIGNALS -#define sig_uses_siginfo(ka) ((ka)->sa.sa_flags & SA_SIGINFO) +#define sig_uses_siginfo(ka, abi) \ + ((abi != &mips_abi_32) ? 1 : \ + ((ka)->sa.sa_flags & SA_SIGINFO)) #else -#define sig_uses_siginfo(ka) (1) +#define sig_uses_siginfo(ka, abi) \ + (config_enabled(CONFIG_64BIT) ? 1 : \ + (config_enabled(CONFIG_TRAD_SIGNALS) ? \ + ((ka)->sa.sa_flags & SA_SIGINFO) : 1) ) #endif #include <asm/sigcontext.h> diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h index 326c16ebd589..2ae1f61a4a95 100644 --- a/arch/mips/include/asm/smp-cps.h +++ b/arch/mips/include/asm/smp-cps.h @@ -29,7 +29,7 @@ extern struct core_boot_config *mips_cps_core_bootcfg; extern void mips_cps_core_entry(void); extern void mips_cps_core_init(void); -extern struct vpe_boot_config *mips_cps_boot_vpes(void); +extern void mips_cps_boot_vpes(struct core_boot_config *cfg, unsigned vpe); extern void mips_cps_pm_save(void); extern void mips_cps_pm_restore(void); diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index 28b5d84a5022..ebb5c0f2f90d 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -105,7 +105,7 @@ do { \ __clear_software_ll_bit(); \ if (cpu_has_userlocal) \ write_c0_userlocal(task_thread_info(next)->tp_value); \ - __restore_watch(); \ + __restore_watch(next); \ (last) = resume(prev, next, task_thread_info(next)); \ } while (0) diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index fc1cdd25fcda..b6ecfeee4dbe 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h @@ -171,7 +171,8 @@ Ip_u2u1(_wsbh); Ip_u3u1u2(_xor); Ip_u2u1u3(_xori); Ip_u2u1(_yield); - +Ip_u1u2(_ldpte); +Ip_u2u1u3(_lddir); /* Handle labels. */ struct uasm_label { diff --git a/arch/mips/include/asm/watch.h b/arch/mips/include/asm/watch.h index 20126ec79359..6ffe3eadf105 100644 --- a/arch/mips/include/asm/watch.h +++ b/arch/mips/include/asm/watch.h @@ -12,21 +12,21 @@ #include <asm/mipsregs.h> -void mips_install_watch_registers(void); +void mips_install_watch_registers(struct task_struct *t); void mips_read_watch_registers(void); void mips_clear_watch_registers(void); void mips_probe_watch_registers(struct cpuinfo_mips *c); #ifdef CONFIG_HARDWARE_WATCHPOINTS -#define __restore_watch() do { \ +#define __restore_watch(task) do { \ if (unlikely(test_bit(TIF_LOAD_WATCH, \ - ¤t_thread_info()->flags))) { \ - mips_install_watch_registers(); \ + &task_thread_info(task)->flags))) { \ + mips_install_watch_registers(task); \ } \ } while (0) #else -#define __restore_watch() do {} while (0) +#define __restore_watch(task) do {} while (0) #endif #endif /* _ASM_WATCH_H */ diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index ddea53e3a9bb..8051f9aa1379 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -167,6 +167,7 @@ enum cop1_sdw_func { fceill_op = 0x0a, ffloorl_op = 0x0b, fround_op = 0x0c, ftrunc_op = 0x0d, fceil_op = 0x0e, ffloor_op = 0x0f, + fsel_op = 0x10, fmovc_op = 0x11, fmovz_op = 0x12, fmovn_op = 0x13, fseleqz_op = 0x14, frecip_op = 0x15, frsqrt_op = 0x16, @@ -204,6 +205,16 @@ enum mad_func { }; /* + * func field for page table walker (Loongson-3). + */ +enum ptw_func { + lwdir_op = 0x00, + lwpte_op = 0x01, + lddir_op = 0x02, + ldpte_op = 0x03, +}; + +/* * func field for special3 lx opcodes (Cavium Octeon). */ enum lx_func { diff --git a/arch/mips/include/uapi/asm/siginfo.h b/arch/mips/include/uapi/asm/siginfo.h index cc49dc240d67..8069cf766603 100644 --- a/arch/mips/include/uapi/asm/siginfo.h +++ b/arch/mips/include/uapi/asm/siginfo.h @@ -28,7 +28,7 @@ #define __ARCH_SIGSYS -#include <uapi/asm-generic/siginfo.h> +#include <asm-generic/siginfo.h> /* We can't use generic siginfo_t, because our si_code and si_errno are swapped */ typedef struct siginfo { @@ -42,13 +42,13 @@ typedef struct siginfo { /* kill() */ struct { - pid_t _pid; /* sender's pid */ + __kernel_pid_t _pid; /* sender's pid */ __ARCH_SI_UID_T _uid; /* sender's uid */ } _kill; /* POSIX.1b timers */ struct { - timer_t _tid; /* timer id */ + __kernel_timer_t _tid; /* timer id */ int _overrun; /* overrun count */ char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)]; sigval_t _sigval; /* same as below */ @@ -57,26 +57,26 @@ typedef struct siginfo { /* POSIX.1b signals */ struct { - pid_t _pid; /* sender's pid */ + __kernel_pid_t _pid; /* sender's pid */ __ARCH_SI_UID_T _uid; /* sender's uid */ sigval_t _sigval; } _rt; /* SIGCHLD */ struct { - pid_t _pid; /* which child */ + __kernel_pid_t _pid; /* which child */ __ARCH_SI_UID_T _uid; /* sender's uid */ int _status; /* exit code */ - clock_t _utime; - clock_t _stime; + __kernel_clock_t _utime; + __kernel_clock_t _stime; } _sigchld; /* IRIX SIGCHLD */ struct { - pid_t _pid; /* which child */ - clock_t _utime; + __kernel_pid_t _pid; /* which child */ + __kernel_clock_t _utime; int _status; /* exit code */ - clock_t _stime; + __kernel_clock_t _stime; } _irix_sigchld; /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ @@ -123,6 +123,4 @@ typedef struct siginfo { #define SI_TIMER __SI_CODE(__SI_TIMER, -3) /* sent by timer expiration */ #define SI_MESGQ __SI_CODE(__SI_MESGQ, -4) /* sent by real time mesq state change */ -#include <asm-generic/siginfo.h> - #endif /* _UAPI_ASM_SIGINFO_H */ diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 934b15b5b575..4e3f9b7a02e4 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -39,8 +39,6 @@ #include "clock.h" -static bool is_avt2; - /* GPIOs */ #define QI_LB60_GPIO_SD_CD JZ_GPIO_PORTD(0) #define QI_LB60_GPIO_SD_VCC_EN_N JZ_GPIO_PORTD(2) @@ -367,43 +365,12 @@ static struct jz4740_mmc_platform_data qi_lb60_mmc_pdata = { .power_active_low = 1, }; -/* OHCI */ -static struct regulator_consumer_supply avt2_usb_regulator_consumer = - REGULATOR_SUPPLY("vbus", "jz4740-ohci"); - -static struct regulator_init_data avt2_usb_regulator_init_data = { - .num_consumer_supplies = 1, - .consumer_supplies = &avt2_usb_regulator_consumer, - .constraints = { - .name = "USB power", - .min_uV = 5000000, - .max_uV = 5000000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - }, -}; - -static struct fixed_voltage_config avt2_usb_regulator_data = { - .supply_name = "USB power", - .microvolts = 5000000, - .gpio = JZ_GPIO_PORTB(17), - .init_data = &avt2_usb_regulator_init_data, -}; - -static struct platform_device avt2_usb_regulator_device = { - .name = "reg-fixed-voltage", - .id = -1, - .dev = { - .platform_data = &avt2_usb_regulator_data, - } -}; - +/* beeper */ static struct pwm_lookup qi_lb60_pwm_lookup[] = { PWM_LOOKUP("jz4740-pwm", 4, "pwm-beeper", NULL, 0, PWM_POLARITY_NORMAL), }; -/* beeper */ static struct platform_device qi_lb60_pwm_beeper = { .name = "pwm-beeper", .id = -1, @@ -487,11 +454,6 @@ static int __init qi_lb60_init_platform_devices(void) spi_register_board_info(qi_lb60_spi_board_info, ARRAY_SIZE(qi_lb60_spi_board_info)); - if (is_avt2) { - platform_device_register(&avt2_usb_regulator_device); - platform_device_register(&jz4740_usb_ohci_device); - } - pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup)); return platform_add_devices(jz_platform_devices, @@ -499,19 +461,9 @@ static int __init qi_lb60_init_platform_devices(void) } -static __init int board_avt2(char *str) -{ - qi_lb60_mmc_pdata.card_detect_active_low = 1; - is_avt2 = true; - - return 1; -} -__setup("avt2", board_avt2); - static int __init qi_lb60_board_setup(void) { - printk(KERN_INFO "Qi Hardware JZ4740 QI %s setup\n", - is_avt2 ? "AVT2" : "LB60"); + printk(KERN_INFO "Qi Hardware JZ4740 QI LB60 setup\n"); board_gpio_setup(); diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c index e8a463b9b663..2f1dab35c061 100644 --- a/arch/mips/jz4740/platform.c +++ b/arch/mips/jz4740/platform.c @@ -32,31 +32,6 @@ #include "clock.h" -/* OHCI controller */ -static struct resource jz4740_usb_ohci_resources[] = { - { - .start = JZ4740_UHC_BASE_ADDR, - .end = JZ4740_UHC_BASE_ADDR + 0x1000 - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = JZ4740_IRQ_UHC, - .end = JZ4740_IRQ_UHC, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device jz4740_usb_ohci_device = { - .name = "jz4740-ohci", - .id = -1, - .dev = { - .dma_mask = &jz4740_usb_ohci_device.dev.coherent_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(jz4740_usb_ohci_resources), - .resource = jz4740_usb_ohci_resources, -}; - /* USB Device Controller */ struct platform_device jz4740_udc_xceiv_device = { .name = "usb_phy_generic", diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index b0988fd62fcc..e6053d07072f 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -44,7 +44,7 @@ obj-$(CONFIG_CPU_CAVIUM_OCTEON) += r4k_fpu.o octeon_switch.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP_UP) += smp-up.o -obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o +obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o bmips_5xxx_init.o obj-$(CONFIG_MIPS_MT) += mips-mt.o obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o @@ -83,6 +83,8 @@ obj-$(CONFIG_I8253) += i8253.o obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o +obj-$(CONFIG_RELOCATABLE) += relocate.o + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 154e2039ea5e..1ea973b2abb1 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -14,6 +14,7 @@ #include <linux/mm.h> #include <linux/kbuild.h> #include <linux/suspend.h> +#include <asm/cpu-info.h> #include <asm/pm.h> #include <asm/ptrace.h> #include <asm/processor.h> @@ -338,6 +339,15 @@ void output_pm_defines(void) } #endif +void output_cpuinfo_defines(void) +{ + COMMENT(" MIPS cpuinfo offsets. "); + DEFINE(CPUINFO_SIZE, sizeof(struct cpuinfo_mips)); +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + OFFSET(CPUINFO_ASID_MASK, cpuinfo_mips, asid_mask); +#endif +} + void output_kvm_defines(void) { COMMENT(" KVM/MIPS Specfic offsets. "); diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c index 1b992c6e3d8e..58ad63d7eb42 100644 --- a/arch/mips/kernel/binfmt_elfn32.c +++ b/arch/mips/kernel/binfmt_elfn32.c @@ -30,21 +30,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; /* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(hdr) \ -({ \ - int __res = 1; \ - struct elfhdr *__h = (hdr); \ - \ - if (!mips_elf_check_machine(__h)) \ - __res = 0; \ - if (__h->e_ident[EI_CLASS] != ELFCLASS32) \ - __res = 0; \ - if (((__h->e_flags & EF_MIPS_ABI2) == 0) || \ - ((__h->e_flags & EF_MIPS_ABI) != 0)) \ - __res = 0; \ - \ - __res; \ -}) +#define elf_check_arch elfn32_check_arch #define TASK32_SIZE 0x7fff8000UL #undef ELF_ET_DYN_BASE diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index abd3affe5fb3..49fb881481f7 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -28,39 +28,9 @@ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; /* - * In order to be sure that we don't attempt to execute an O32 binary which - * requires 64 bit FP (FR=1) on a system which does not support it we refuse - * to execute any binary which has bits specified by the following macro set - * in its ELF header flags. - */ -#ifdef CONFIG_MIPS_O32_FP64_SUPPORT -# define __MIPS_O32_FP64_MUST_BE_ZERO 0 -#else -# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64 -#endif - -/* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(hdr) \ -({ \ - int __res = 1; \ - struct elfhdr *__h = (hdr); \ - \ - if (!mips_elf_check_machine(__h)) \ - __res = 0; \ - if (__h->e_ident[EI_CLASS] != ELFCLASS32) \ - __res = 0; \ - if ((__h->e_flags & EF_MIPS_ABI2) != 0) \ - __res = 0; \ - if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ - ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ - __res = 0; \ - if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \ - __res = 0; \ - \ - __res; \ -}) +#define elf_check_arch elfo32_check_arch #ifdef CONFIG_KVM_GUEST #define TASK32_SIZE 0x3fff8000UL diff --git a/arch/mips/kernel/bmips_5xxx_init.S b/arch/mips/kernel/bmips_5xxx_init.S new file mode 100644 index 000000000000..adaa82e00f2b --- /dev/null +++ b/arch/mips/kernel/bmips_5xxx_init.S @@ -0,0 +1,753 @@ + +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011-2012 by Broadcom Corporation + * + * Init for bmips 5000. + * Used to init second core in dual core 5000's. + */ + +#include <linux/init.h> + +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/cacheops.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/stackframe.h> +#include <asm/addrspace.h> +#include <asm/hazards.h> +#include <asm/bmips.h> + +#ifdef CONFIG_CPU_BMIPS5000 + + +#define cacheop(kva, size, linesize, op) \ + .set noreorder ; \ + addu t1, kva, size ; \ + subu t2, linesize, 1 ; \ + not t2 ; \ + and t0, kva, t2 ; \ + addiu t1, t1, -1 ; \ + and t1, t2 ; \ +9: cache op, 0(t0) ; \ + bne t0, t1, 9b ; \ + addu t0, linesize ; \ + .set reorder ; + + + +#define IS_SHIFT 22 +#define IL_SHIFT 19 +#define IA_SHIFT 16 +#define DS_SHIFT 13 +#define DL_SHIFT 10 +#define DA_SHIFT 7 +#define IS_MASK 7 +#define IL_MASK 7 +#define IA_MASK 7 +#define DS_MASK 7 +#define DL_MASK 7 +#define DA_MASK 7 +#define ICE_MASK 0x80000000 +#define DCE_MASK 0x40000000 + +#define CP0_BRCM_CONFIG0 $22, 0 +#define CP0_BRCM_MODE $22, 1 +#define CP0_CONFIG_K0_MASK 7 + +#define CP0_ICACHE_TAG_LO $28 +#define CP0_ICACHE_DATA_LO $28, 1 +#define CP0_DCACHE_TAG_LO $28, 2 +#define CP0_D_SEC_CACHE_DATA_LO $28, 3 +#define CP0_ICACHE_TAG_HI $29 +#define CP0_ICACHE_DATA_HI $29, 1 +#define CP0_DCACHE_TAG_HI $29, 2 + +#define CP0_BRCM_MODE_Luc_MASK (1 << 11) +#define CP0_BRCM_CONFIG0_CWF_MASK (1 << 20) +#define CP0_BRCM_CONFIG0_TSE_MASK (1 << 19) +#define CP0_BRCM_MODE_SET_MASK (1 << 7) +#define CP0_BRCM_MODE_ClkRATIO_MASK (7 << 4) +#define CP0_BRCM_MODE_BrPRED_MASK (3 << 24) +#define CP0_BRCM_MODE_BrPRED_SHIFT 24 +#define CP0_BRCM_MODE_BrHIST_MASK (0x1f << 20) +#define CP0_BRCM_MODE_BrHIST_SHIFT 20 + +/* ZSC L2 Cache Register Access Register Definitions */ +#define BRCM_ZSC_ALL_REGS_SELECT 0x7 << 24 + +#define BRCM_ZSC_CONFIG_REG 0 << 3 +#define BRCM_ZSC_REQ_BUFFER_REG 2 << 3 +#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG0 4 << 3 +#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG1 6 << 3 +#define BRCM_ZSC_RBUS_ADDR_MAPPING_REG2 8 << 3 + +#define BRCM_ZSC_SCB0_ADDR_MAPPING_REG0 0xa << 3 +#define BRCM_ZSC_SCB0_ADDR_MAPPING_REG1 0xc << 3 + +#define BRCM_ZSC_SCB1_ADDR_MAPPING_REG0 0xe << 3 +#define BRCM_ZSC_SCB1_ADDR_MAPPING_REG1 0x10 << 3 + +#define BRCM_ZSC_CONFIG_LMB1En 1 << (15) +#define BRCM_ZSC_CONFIG_LMB0En 1 << (14) + +/* branch predition values */ + +#define BRCM_BrPRED_ALL_TAKEN (0x0) +#define BRCM_BrPRED_ALL_NOT_TAKEN (0x1) +#define BRCM_BrPRED_BHT_ENABLE (0x2) +#define BRCM_BrPRED_PREDICT_BACKWARD (0x3) + + + +.align 2 +/* + * Function: size_i_cache + * Arguments: None + * Returns: v0 = i cache size, v1 = I cache line size + * Description: compute the I-cache size and I-cache line size + * Trashes: v0, v1, a0, t0 + * + * pseudo code: + * + */ + +LEAF(size_i_cache) + .set noreorder + + mfc0 a0, CP0_CONFIG, 1 + move t0, a0 + + /* + * Determine sets per way: IS + * + * This field contains the number of sets (i.e., indices) per way of + * the instruction cache: + * i) 0x0: 64, ii) 0x1: 128, iii) 0x2: 256, iv) 0x3: 512, v) 0x4: 1k + * vi) 0x5 - 0x7: Reserved. + */ + + srl a0, a0, IS_SHIFT + and a0, a0, IS_MASK + + /* sets per way = (64<<IS) */ + + li v0, 0x40 + sllv v0, v0, a0 + + /* + * Determine line size + * + * This field contains the line size of the instruction cache: + * i) 0x0: No I-cache present, i) 0x3: 16 bytes, ii) 0x4: 32 bytes, iii) + * 0x5: 64 bytes, iv) the rest: Reserved. + */ + + move a0, t0 + + srl a0, a0, IL_SHIFT + and a0, a0, IL_MASK + + beqz a0, no_i_cache + nop + + /* line size = 2 ^ (IL+1) */ + + addi a0, a0, 1 + li v1, 1 + sll v1, v1, a0 + + /* v0 now have sets per way, multiply it by line size now + * that will give the set size + */ + + sll v0, v0, a0 + + /* + * Determine set associativity + * + * This field contains the set associativity of the instruction cache. + * i) 0x0: Direct mapped, ii) 0x1: 2-way, iii) 0x2: 3-way, iv) 0x3: + * 4-way, v) 0x4 - 0x7: Reserved. + */ + + move a0, t0 + + srl a0, a0, IA_SHIFT + and a0, a0, IA_MASK + addi a0, a0, 0x1 + + /* v0 has the set size, multiply it by + * set associativiy, to get the cache size + */ + + multu v0, a0 /*multu is interlocked, so no need to insert nops */ + mflo v0 + b 1f + nop + +no_i_cache: + move v0, zero + move v1, zero +1: + jr ra + nop + .set reorder + +END(size_i_cache) + +/* + * Function: size_d_cache + * Arguments: None + * Returns: v0 = d cache size, v1 = d cache line size + * Description: compute the D-cache size and D-cache line size. + * Trashes: v0, v1, a0, t0 + * + */ + +LEAF(size_d_cache) + .set noreorder + + mfc0 a0, CP0_CONFIG, 1 + move t0, a0 + + /* + * Determine sets per way: IS + * + * This field contains the number of sets (i.e., indices) per way of + * the instruction cache: + * i) 0x0: 64, ii) 0x1: 128, iii) 0x2: 256, iv) 0x3: 512, v) 0x4: 1k + * vi) 0x5 - 0x7: Reserved. + */ + + srl a0, a0, DS_SHIFT + and a0, a0, DS_MASK + + /* sets per way = (64<<IS) */ + + li v0, 0x40 + sllv v0, v0, a0 + + /* + * Determine line size + * + * This field contains the line size of the instruction cache: + * i) 0x0: No I-cache present, i) 0x3: 16 bytes, ii) 0x4: 32 bytes, iii) + * 0x5: 64 bytes, iv) the rest: Reserved. + */ + move a0, t0 + + srl a0, a0, DL_SHIFT + and a0, a0, DL_MASK + + beqz a0, no_d_cache + nop + + /* line size = 2 ^ (IL+1) */ + + addi a0, a0, 1 + li v1, 1 + sll v1, v1, a0 + + /* v0 now have sets per way, multiply it by line size now + * that will give the set size + */ + + sll v0, v0, a0 + + /* determine set associativity + * + * This field contains the set associativity of the instruction cache. + * i) 0x0: Direct mapped, ii) 0x1: 2-way, iii) 0x2: 3-way, iv) 0x3: + * 4-way, v) 0x4 - 0x7: Reserved. + */ + + move a0, t0 + + srl a0, a0, DA_SHIFT + and a0, a0, DA_MASK + addi a0, a0, 0x1 + + /* v0 has the set size, multiply it by + * set associativiy, to get the cache size + */ + + multu v0, a0 /*multu is interlocked, so no need to insert nops */ + mflo v0 + + b 1f + nop + +no_d_cache: + move v0, zero + move v1, zero +1: + jr ra + nop + .set reorder + +END(size_d_cache) + + +/* + * Function: enable_ID + * Arguments: None + * Returns: None + * Description: Enable I and D caches, initialize I and D-caches, also set + * hardware delay for d-cache (TP0). + * Trashes: t0 + * + */ + .global enable_ID + .ent enable_ID + .set noreorder +enable_ID: + mfc0 t0, CP0_BRCM_CONFIG0 + or t0, t0, (ICE_MASK | DCE_MASK) + mtc0 t0, CP0_BRCM_CONFIG0 + jr ra + nop + + .end enable_ID + .set reorder + + +/* + * Function: l1_init + * Arguments: None + * Returns: None + * Description: Enable I and D caches, and initialize I and D-caches + * Trashes: a0, v0, v1, t0, t1, t2, t8 + * + */ + .globl l1_init + .ent l1_init + .set noreorder +l1_init: + + /* save return address */ + move t8, ra + + + /* initialize I and D cache Data and Tag registers. */ + mtc0 zero, CP0_ICACHE_TAG_LO + mtc0 zero, CP0_ICACHE_TAG_HI + mtc0 zero, CP0_ICACHE_DATA_LO + mtc0 zero, CP0_ICACHE_DATA_HI + mtc0 zero, CP0_DCACHE_TAG_LO + mtc0 zero, CP0_DCACHE_TAG_HI + + /* Enable Caches before Clearing. If the caches are disabled + * then the cache operations to clear the cache will be ignored + */ + + jal enable_ID + nop + + jal size_i_cache /* v0 = i-cache size, v1 = i-cache line size */ + nop + + /* run uncached in kseg 1 */ + la k0, 1f + lui k1, 0x2000 + or k0, k1, k0 + jr k0 + nop +1: + + /* + * set K0 cache mode + */ + + mfc0 t0, CP0_CONFIG + and t0, t0, ~CP0_CONFIG_K0_MASK + or t0, t0, 3 /* Write Back mode */ + mtc0 t0, CP0_CONFIG + + /* + * Initialize instruction cache. + */ + + li a0, KSEG0 + cacheop(a0, v0, v1, Index_Store_Tag_I) + + /* + * Now we can run from I-$, kseg 0 + */ + la k0, 1f + lui k1, 0x2000 + or k0, k1, k0 + xor k0, k1, k0 + jr k0 + nop +1: + /* + * Initialize data cache. + */ + + jal size_d_cache /* v0 = d-cache size, v1 = d-cache line size */ + nop + + + li a0, KSEG0 + cacheop(a0, v0, v1, Index_Store_Tag_D) + + jr t8 + nop + + .end l1_init + .set reorder + + +/* + * Function: set_other_config + * Arguments: none + * Returns: None + * Description: initialize other remainder configuration to defaults. + * Trashes: t0, t1 + * + * pseudo code: + * + */ +LEAF(set_other_config) + .set noreorder + + /* enable Bus error for I-fetch */ + mfc0 t0, CP0_CACHEERR, 0 + li t1, 0x4 + or t0, t1 + mtc0 t0, CP0_CACHEERR, 0 + + /* enable Bus error for Load */ + mfc0 t0, CP0_CACHEERR, 1 + li t1, 0x4 + or t0, t1 + mtc0 t0, CP0_CACHEERR, 1 + + /* enable Bus Error for Store */ + mfc0 t0, CP0_CACHEERR, 2 + li t1, 0x4 + or t0, t1 + mtc0 t0, CP0_CACHEERR, 2 + + jr ra + nop + .set reorder +END(set_other_config) + +/* + * Function: set_branch_pred + * Arguments: none + * Returns: None + * Description: + * Trashes: t0, t1 + * + * pseudo code: + * + */ + +LEAF(set_branch_pred) + .set noreorder + mfc0 t0, CP0_BRCM_MODE + li t1, ~(CP0_BRCM_MODE_BrPRED_MASK | CP0_BRCM_MODE_BrHIST_MASK ) + and t0, t0, t1 + + /* enable Branch prediction */ + li t1, BRCM_BrPRED_BHT_ENABLE + sll t1, CP0_BRCM_MODE_BrPRED_SHIFT + or t0, t0, t1 + + /* set history count to 8 */ + li t1, 8 + sll t1, CP0_BRCM_MODE_BrHIST_SHIFT + or t0, t0, t1 + + mtc0 t0, CP0_BRCM_MODE + jr ra + nop + .set reorder +END(set_branch_pred) + + +/* + * Function: set_luc + * Arguments: set link uncached. + * Returns: None + * Description: + * Trashes: t0, t1 + * + */ +LEAF(set_luc) + .set noreorder + mfc0 t0, CP0_BRCM_MODE + li t1, ~(CP0_BRCM_MODE_Luc_MASK) + and t0, t0, t1 + + /* set Luc */ + ori t0, t0, CP0_BRCM_MODE_Luc_MASK + + mtc0 t0, CP0_BRCM_MODE + jr ra + nop + .set reorder +END(set_luc) + +/* + * Function: set_cwf_tse + * Arguments: set CWF and TSE bits + * Returns: None + * Description: + * Trashes: t0, t1 + * + */ +LEAF(set_cwf_tse) + .set noreorder + mfc0 t0, CP0_BRCM_CONFIG0 + li t1, (CP0_BRCM_CONFIG0_CWF_MASK | CP0_BRCM_CONFIG0_TSE_MASK) + or t0, t0, t1 + + mtc0 t0, CP0_BRCM_CONFIG0 + jr ra + nop + .set reorder +END(set_cwf_tse) + +/* + * Function: set_clock_ratio + * Arguments: set clock ratio specified by a0 + * Returns: None + * Description: + * Trashes: v0, v1, a0, a1 + * + * pseudo code: + * + */ +LEAF(set_clock_ratio) + .set noreorder + + mfc0 t0, CP0_BRCM_MODE + li t1, ~(CP0_BRCM_MODE_SET_MASK | CP0_BRCM_MODE_ClkRATIO_MASK) + and t0, t0, t1 + li t1, CP0_BRCM_MODE_SET_MASK + or t0, t0, t1 + or t0, t0, a0 + mtc0 t0, CP0_BRCM_MODE + jr ra + nop + .set reorder +END(set_clock_ratio) +/* + * Function: set_zephyr + * Arguments: None + * Returns: None + * Description: Set any zephyr bits + * Trashes: t0 & t1 + * + */ +LEAF(set_zephyr) + .set noreorder + + /* enable read/write of CP0 #22 sel. 8 */ + li t0, 0x5a455048 + .word 0x4088b00f /* mtc0 t0, $22, 15 */ + + .word 0x4008b008 /* mfc0 t0, $22, 8 */ + li t1, 0x09008000 /* turn off pref, jtb */ + or t0, t0, t1 + .word 0x4088b008 /* mtc0 t0, $22, 8 */ + sync + + /* disable read/write of CP0 #22 sel 8 */ + li t0, 0x0 + .word 0x4088b00f /* mtc0 t0, $22, 15 */ + + + jr ra + nop + .set reorder + +END(set_zephyr) + + +/* + * Function: set_llmb + * Arguments: a0=0 disable llmb, a0=1 enables llmb + * Returns: None + * Description: + * Trashes: t0, t1, t2 + * + * pseudo code: + * + */ +LEAF(set_llmb) + .set noreorder + + li t2, 0x90000000 | BRCM_ZSC_ALL_REGS_SELECT | BRCM_ZSC_CONFIG_REG + sync + cache 0x7, 0x0(t2) + sync + mfc0 t0, CP0_D_SEC_CACHE_DATA_LO + li t1, ~(BRCM_ZSC_CONFIG_LMB1En | BRCM_ZSC_CONFIG_LMB0En) + and t0, t0, t1 + + beqz a0, svlmb + nop + +enable_lmb: + li t1, (BRCM_ZSC_CONFIG_LMB1En | BRCM_ZSC_CONFIG_LMB0En) + or t0, t0, t1 + +svlmb: + mtc0 t0, CP0_D_SEC_CACHE_DATA_LO + sync + cache 0xb, 0x0(t2) + sync + + jr ra + nop + .set reorder + +END(set_llmb) +/* + * Function: core_init + * Arguments: none + * Returns: None + * Description: initialize core related configuration + * Trashes: v0,v1,a0,a1,t8 + * + * pseudo code: + * + */ + .globl core_init + .ent core_init + .set noreorder +core_init: + move t8, ra + + /* set Zephyr bits. */ + bal set_zephyr + nop + +#if ENABLE_FPU==1 + /* initialize the Floating point unit (both TPs) */ + bal init_fpu + nop +#endif + + /* set low latency memory bus */ + li a0, 1 + bal set_llmb + nop + + /* set branch prediction (TP0 only) */ + bal set_branch_pred + nop + + /* set link uncached */ + bal set_luc + nop + + /* set CWF and TSE */ + bal set_cwf_tse + nop + + /* + *set clock ratio by setting 1 to 'set' + * and 0 to ClkRatio, (TP0 only) + */ + li a0, 0 + bal set_clock_ratio + nop + + /* set other configuration to defaults */ + bal set_other_config + nop + + move ra, t8 + jr ra + nop + + .set reorder + .end core_init + +/* + * Function: clear_jump_target_buffer + * Arguments: None + * Returns: None + * Description: + * Trashes: t0, t1, t2 + * + */ +#define RESET_CALL_RETURN_STACK_THIS_THREAD (0x06<<16) +#define RESET_JUMP_TARGET_BUFFER_THIS_THREAD (0x04<<16) +#define JTB_CS_CNTL_MASK (0xFF<<16) + + .globl clear_jump_target_buffer + .ent clear_jump_target_buffer + .set noreorder +clear_jump_target_buffer: + + mfc0 t0, $22, 2 + nop + nop + + li t1, ~JTB_CS_CNTL_MASK + and t0, t0, t1 + li t2, RESET_CALL_RETURN_STACK_THIS_THREAD + or t0, t0, t2 + mtc0 t0, $22, 2 + nop + nop + + and t0, t0, t1 + li t2, RESET_JUMP_TARGET_BUFFER_THIS_THREAD + or t0, t0, t2 + mtc0 t0, $22, 2 + nop + nop + jr ra + nop + + .end clear_jump_target_buffer + .set reorder +/* + * Function: bmips_cache_init + * Arguments: None + * Returns: None + * Description: Enable I and D caches, and initialize I and D-caches + * Trashes: v0, v1, t0, t1, t2, t5, t7, t8 + * + */ + .globl bmips_5xxx_init + .ent bmips_5xxx_init + .set noreorder +bmips_5xxx_init: + + /* save return address and A0 */ + move t7, ra + move t5, a0 + + jal l1_init + nop + + jal core_init + nop + + jal clear_jump_target_buffer + nop + + mtc0 zero, CP0_CAUSE + + move a0, t5 + jr t7 + nop + + .end bmips_5xxx_init + .set reorder + + +#endif diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S index 86495072a922..921a5fa55da6 100644 --- a/arch/mips/kernel/bmips_vec.S +++ b/arch/mips/kernel/bmips_vec.S @@ -88,12 +88,13 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp) li k1, (1 << 19) mfc0 k0, CP0_STATUS and k0, k1 - beqz k0, bmips_smp_entry + beqz k0, soft_reset #if defined(CONFIG_CPU_BMIPS5000) mfc0 k0, CP0_PRID li k1, PRID_IMP_BMIPS5000 - andi k0, 0xff00 + /* mask with PRID_IMP_BMIPS5000 to cover both variants */ + andi k0, PRID_IMP_BMIPS5000 bne k0, k1, 1f /* if we're not on core 0, this must be the SMP boot signal */ @@ -125,13 +126,48 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp) .set arch=r4000 eret +#ifdef CONFIG_SMP +soft_reset: + +#if defined(CONFIG_CPU_BMIPS5000) + mfc0 k0, CP0_PRID + andi k0, 0xff00 + li k1, PRID_IMP_BMIPS5200 + bne k0, k1, bmips_smp_entry + + /* if running on TP 1, jump to bmips_smp_entry */ + mfc0 k0, $22 + li k1, (1 << 24) + and k1, k0 + bnez k1, bmips_smp_entry + nop + + /* + * running on TP0, can not be core 0 (the boot core). + * Check for soft reset. Indicates a warm boot + */ + mfc0 k0, $12 + li k1, (1 << 20) + and k0, k1 + beqz k0, bmips_smp_entry + + /* + * Warm boot. + * Cache init is only done on TP0 + */ + la k0, bmips_5xxx_init + jalr k0 + nop + + b bmips_smp_entry + nop +#endif + /*********************************************************************** * CPU1 reset vector (used for the initial boot only) * This is still part of bmips_reset_nmi_vec(). ***********************************************************************/ -#ifdef CONFIG_SMP - bmips_smp_entry: /* set up CP0 STATUS; enable FPU */ @@ -166,10 +202,12 @@ bmips_smp_entry: 2: #endif /* CONFIG_CPU_BMIPS4350 || CONFIG_CPU_BMIPS4380 */ #if defined(CONFIG_CPU_BMIPS5000) - /* set exception vector base */ + /* mask with PRID_IMP_BMIPS5000 to cover both variants */ li k1, PRID_IMP_BMIPS5000 + andi k0, PRID_IMP_BMIPS5000 bne k0, k1, 3f + /* set exception vector base */ la k0, ebase lw k0, 0(k0) mtc0 k0, $15, 1 @@ -263,6 +301,8 @@ LEAF(bmips_enable_xks01) #endif /* CONFIG_CPU_BMIPS4380 */ #if defined(CONFIG_CPU_BMIPS5000) li t1, PRID_IMP_BMIPS5000 + /* mask with PRID_IMP_BMIPS5000 to cover both variants */ + andi t2, PRID_IMP_BMIPS5000 bne t2, t1, 2f mfc0 t0, $22, 5 diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index d8f9b357b222..ceca6cc41b2b 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -688,21 +688,9 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, } lose_fpu(1); /* Save FPU state for the emulator. */ reg = insn.i_format.rt; - bit = 0; - switch (insn.i_format.rs) { - case bc1eqz_op: - /* Test bit 0 */ - if (get_fpr32(¤t->thread.fpu.fpr[reg], 0) - & 0x1) - bit = 1; - break; - case bc1nez_op: - /* Test bit 0 */ - if (!(get_fpr32(¤t->thread.fpu.fpr[reg], 0) - & 0x1)) - bit = 1; - break; - } + bit = get_fpr32(¤t->thread.fpu.fpr[reg], 0) & 0x1; + if (insn.i_format.rs == bc1eqz_op) + bit = !bit; own_fpu(1); if (bit) epc = epc + 4 + diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 8dfe6a6e1480..e4c21bbf9422 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -28,6 +28,83 @@ static int mips_next_event(unsigned long delta, return res; } +/** + * calculate_min_delta() - Calculate a good minimum delta for mips_next_event(). + * + * Running under virtualisation can introduce overhead into mips_next_event() in + * the form of hypervisor emulation of CP0_Count/CP0_Compare registers, + * potentially with an unnatural frequency, which makes a fixed min_delta_ns + * value inappropriate as it may be too small. + * + * It can also introduce occasional latency from the guest being descheduled. + * + * This function calculates a good minimum delta based roughly on the 75th + * percentile of the time taken to do the mips_next_event() sequence, in order + * to handle potentially higher overhead while also eliminating outliers due to + * unpredictable hypervisor latency (which can be handled by retries). + * + * Return: An appropriate minimum delta for the clock event device. + */ +static unsigned int calculate_min_delta(void) +{ + unsigned int cnt, i, j, k, l; + unsigned int buf1[4], buf2[3]; + unsigned int min_delta; + + /* + * Calculate the median of 5 75th percentiles of 5 samples of how long + * it takes to set CP0_Compare = CP0_Count + delta. + */ + for (i = 0; i < 5; ++i) { + for (j = 0; j < 5; ++j) { + /* + * This is like the code in mips_next_event(), and + * directly measures the borderline "safe" delta. + */ + cnt = read_c0_count(); + write_c0_compare(cnt); + cnt = read_c0_count() - cnt; + + /* Sorted insert into buf1 */ + for (k = 0; k < j; ++k) { + if (cnt < buf1[k]) { + l = min_t(unsigned int, + j, ARRAY_SIZE(buf1) - 1); + for (; l > k; --l) + buf1[l] = buf1[l - 1]; + break; + } + } + if (k < ARRAY_SIZE(buf1)) + buf1[k] = cnt; + } + + /* Sorted insert of 75th percentile into buf2 */ + for (k = 0; k < i; ++k) { + if (buf1[ARRAY_SIZE(buf1) - 1] < buf2[k]) { + l = min_t(unsigned int, + i, ARRAY_SIZE(buf2) - 1); + for (; l > k; --l) + buf2[l] = buf2[l - 1]; + break; + } + } + if (k < ARRAY_SIZE(buf2)) + buf2[k] = buf1[ARRAY_SIZE(buf1) - 1]; + } + + /* Use 2 * median of 75th percentiles */ + min_delta = buf2[ARRAY_SIZE(buf2) - 1] * 2; + + /* Don't go too low */ + if (min_delta < 0x300) + min_delta = 0x300; + + pr_debug("%s: median 75th percentile=%#x, min_delta=%#x\n", + __func__, buf2[ARRAY_SIZE(buf2) - 1], min_delta); + return min_delta; +} + DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); int cp0_timer_irq_installed; @@ -177,7 +254,7 @@ int r4k_clockevent_init(void) { unsigned int cpu = smp_processor_id(); struct clock_event_device *cd; - unsigned int irq; + unsigned int irq, min_delta; if (!cpu_has_counter || !mips_hpt_frequency) return -ENXIO; @@ -203,7 +280,8 @@ int r4k_clockevent_init(void) /* Calculate the min / max delta */ cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); - cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + min_delta = calculate_min_delta(); + cd->min_delta_ns = clockevent_delta2ns(min_delta, cd); cd->rating = 300; cd->irq = irq; diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index ac81edd44563..51b98dc371b3 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -18,9 +18,12 @@ #include <asm/mipsmtregs.h> #include <asm/pm.h> +#define GCR_CPC_BASE_OFS 0x0088 #define GCR_CL_COHERENCE_OFS 0x2008 #define GCR_CL_ID_OFS 0x2028 +#define CPC_CL_VC_RUN_OFS 0x2028 + .extern mips_cm_base .set noreorder @@ -60,6 +63,37 @@ nop .endm + /* + * Set dest to non-zero if the core supports MIPSr6 multithreading + * (ie. VPs), else zero. If MIPSr6 multithreading is not supported then + * branch to nomt. + */ + .macro has_vp dest, nomt + mfc0 \dest, CP0_CONFIG, 1 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 2 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 3 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 4 + bgez \dest, \nomt + mfc0 \dest, CP0_CONFIG, 5 + andi \dest, \dest, MIPS_CONF5_VP + beqz \dest, \nomt + nop + .endm + + /* Calculate an uncached address for the CM GCRs */ + .macro cmgcrb dest + .set push + .set noat + MFC0 $1, CP0_CMGCRBASE + PTR_SLL $1, $1, 4 + PTR_LI \dest, UNCAC_BASE + PTR_ADDU \dest, \dest, $1 + .set pop + .endm + .section .text.cps-vec .balign 0x1000 @@ -90,120 +124,64 @@ not_nmi: li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS mtc0 t0, CP0_STATUS - /* - * Clear the bits used to index the caches. Note that the architecture - * dictates that writing to any of TagLo or TagHi selects 0 or 2 should - * be valid for all MIPS32 CPUs, even those for which said writes are - * unnecessary. - */ - mtc0 zero, CP0_TAGLO, 0 - mtc0 zero, CP0_TAGHI, 0 - mtc0 zero, CP0_TAGLO, 2 - mtc0 zero, CP0_TAGHI, 2 - ehb - - /* Primary cache configuration is indicated by Config1 */ - mfc0 v0, CP0_CONFIG, 1 - - /* Detect I-cache line size */ - _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ - beqz t0, icache_done - li t1, 2 - sllv t0, t1, t0 - - /* Detect I-cache size */ - _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ - xori t2, t1, 0x7 - beqz t2, 1f - li t3, 32 - addiu t1, t1, 1 - sllv t1, t3, t1 -1: /* At this point t1 == I-cache sets per way */ - _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ - addiu t2, t2, 1 - mul t1, t1, t0 - mul t1, t1, t2 - - li a0, CKSEG0 - PTR_ADD a1, a0, t1 -1: cache Index_Store_Tag_I, 0(a0) - PTR_ADD a0, a0, t0 - bne a0, a1, 1b + /* Skip cache & coherence setup if we're already coherent */ + cmgcrb v1 + lw s7, GCR_CL_COHERENCE_OFS(v1) + bnez s7, 1f nop -icache_done: - /* Detect D-cache line size */ - _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ - beqz t0, dcache_done - li t1, 2 - sllv t0, t1, t0 - - /* Detect D-cache size */ - _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ - xori t2, t1, 0x7 - beqz t2, 1f - li t3, 32 - addiu t1, t1, 1 - sllv t1, t3, t1 -1: /* At this point t1 == D-cache sets per way */ - _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ - addiu t2, t2, 1 - mul t1, t1, t0 - mul t1, t1, t2 + /* Initialize the L1 caches */ + jal mips_cps_cache_init + nop - li a0, CKSEG0 - PTR_ADDU a1, a0, t1 - PTR_SUBU a1, a1, t0 -1: cache Index_Store_Tag_D, 0(a0) - bne a0, a1, 1b - PTR_ADD a0, a0, t0 -dcache_done: + /* Enter the coherent domain */ + li t0, 0xff + sw t0, GCR_CL_COHERENCE_OFS(v1) + ehb /* Set Kseg0 CCA to that in s0 */ - mfc0 t0, CP0_CONFIG +1: mfc0 t0, CP0_CONFIG ori t0, 0x7 xori t0, 0x7 or t0, t0, s0 mtc0 t0, CP0_CONFIG ehb - /* Calculate an uncached address for the CM GCRs */ - MFC0 v1, CP0_CMGCRBASE - PTR_SLL v1, v1, 4 - PTR_LI t0, UNCAC_BASE - PTR_ADDU v1, v1, t0 - - /* Enter the coherent domain */ - li t0, 0xff - sw t0, GCR_CL_COHERENCE_OFS(v1) - ehb - /* Jump to kseg0 */ PTR_LA t0, 1f jr t0 nop /* - * We're up, cached & coherent. Perform any further required core-level - * initialisation. + * We're up, cached & coherent. Perform any EVA initialization necessary + * before we access memory. */ -1: jal mips_cps_core_init +1: eva_init + + /* Retrieve boot configuration pointers */ + jal mips_cps_get_bootcfg nop - /* Do any EVA initialization if necessary */ - eva_init + /* Skip core-level init if we started up coherent */ + bnez s7, 1f + nop + + /* Perform any further required core-level initialisation */ + jal mips_cps_core_init + nop /* * Boot any other VPEs within this core that should be online, and * deactivate this VPE if it should be offline. */ + move a1, t9 jal mips_cps_boot_vpes - nop + move a0, v0 /* Off we go! */ - PTR_L t1, VPEBOOTCFG_PC(v0) - PTR_L gp, VPEBOOTCFG_GP(v0) - PTR_L sp, VPEBOOTCFG_SP(v0) +1: PTR_L t1, VPEBOOTCFG_PC(v1) + PTR_L gp, VPEBOOTCFG_GP(v1) + PTR_L sp, VPEBOOTCFG_SP(v1) jr t1 nop END(mips_cps_core_entry) @@ -245,7 +223,6 @@ LEAF(excep_intex) .org 0x480 LEAF(excep_ejtag) - DUMP_EXCEP("EJTAG") PTR_LA k0, ejtag_debug_handler jr k0 nop @@ -323,22 +300,35 @@ LEAF(mips_cps_core_init) nop END(mips_cps_core_init) -LEAF(mips_cps_boot_vpes) - /* Retrieve CM base address */ - PTR_LA t0, mips_cm_base - PTR_L t0, 0(t0) - +/** + * mips_cps_get_bootcfg() - retrieve boot configuration pointers + * + * Returns: pointer to struct core_boot_config in v0, pointer to + * struct vpe_boot_config in v1, VPE ID in t9 + */ +LEAF(mips_cps_get_bootcfg) /* Calculate a pointer to this cores struct core_boot_config */ + cmgcrb t0 lw t0, GCR_CL_ID_OFS(t0) li t1, COREBOOTCFG_SIZE mul t0, t0, t1 PTR_LA t1, mips_cps_core_bootcfg PTR_L t1, 0(t1) - PTR_ADDU t0, t0, t1 + PTR_ADDU v0, t0, t1 /* Calculate this VPEs ID. If the core doesn't support MT use 0 */ li t9, 0 -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_CPU_MIPSR6) + has_vp ta2, 1f + + /* + * Assume non-contiguous numbering. Perhaps some day we'll need + * to handle contiguous VP numbering, but no such systems yet + * exist. + */ + mfc0 t9, $3, 1 + andi t9, t9, 0xff +#elif defined(CONFIG_MIPS_MT_SMP) has_mt ta2, 1f /* Find the number of VPEs present in the core */ @@ -362,22 +352,43 @@ LEAF(mips_cps_boot_vpes) 1: /* Calculate a pointer to this VPEs struct vpe_boot_config */ li t1, VPEBOOTCFG_SIZE - mul v0, t9, t1 - PTR_L ta3, COREBOOTCFG_VPECONFIG(t0) - PTR_ADDU v0, v0, ta3 - -#ifdef CONFIG_MIPS_MT_SMP + mul v1, t9, t1 + PTR_L ta3, COREBOOTCFG_VPECONFIG(v0) + PTR_ADDU v1, v1, ta3 - /* If the core doesn't support MT then return */ - bnez ta2, 1f - nop jr ra nop + END(mips_cps_get_bootcfg) + +LEAF(mips_cps_boot_vpes) + PTR_L ta2, COREBOOTCFG_VPEMASK(a0) + PTR_L ta3, COREBOOTCFG_VPECONFIG(a0) + +#if defined(CONFIG_CPU_MIPSR6) + + has_vp t0, 5f + + /* Find base address of CPC */ + cmgcrb t3 + PTR_L t1, GCR_CPC_BASE_OFS(t3) + PTR_LI t2, ~0x7fff + and t1, t1, t2 + PTR_LI t2, UNCAC_BASE + PTR_ADD t1, t1, t2 + + /* Set VC_RUN to the VPE mask */ + PTR_S ta2, CPC_CL_VC_RUN_OFS(t1) + ehb + +#elif defined(CONFIG_MIPS_MT) .set push .set mt -1: /* Enter VPE configuration state */ + /* If the core doesn't support MT then return */ + has_mt t0, 5f + + /* Enter VPE configuration state */ dvpe PTR_LA t1, 1f jr.hb t1 @@ -388,7 +399,6 @@ LEAF(mips_cps_boot_vpes) ehb /* Loop through each VPE */ - PTR_L ta2, COREBOOTCFG_VPEMASK(t0) move t8, ta2 li ta1, 0 @@ -465,7 +475,7 @@ LEAF(mips_cps_boot_vpes) /* Check whether this VPE is meant to be running */ li t0, 1 - sll t0, t0, t9 + sll t0, t0, a1 and t0, t0, t8 bnez t0, 2f nop @@ -482,10 +492,84 @@ LEAF(mips_cps_boot_vpes) #endif /* CONFIG_MIPS_MT_SMP */ /* Return */ - jr ra +5: jr ra nop END(mips_cps_boot_vpes) +LEAF(mips_cps_cache_init) + /* + * Clear the bits used to index the caches. Note that the architecture + * dictates that writing to any of TagLo or TagHi selects 0 or 2 should + * be valid for all MIPS32 CPUs, even those for which said writes are + * unnecessary. + */ + mtc0 zero, CP0_TAGLO, 0 + mtc0 zero, CP0_TAGHI, 0 + mtc0 zero, CP0_TAGLO, 2 + mtc0 zero, CP0_TAGHI, 2 + ehb + + /* Primary cache configuration is indicated by Config1 */ + mfc0 v0, CP0_CONFIG, 1 + + /* Detect I-cache line size */ + _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ + beqz t0, icache_done + li t1, 2 + sllv t0, t1, t0 + + /* Detect I-cache size */ + _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ + xori t2, t1, 0x7 + beqz t2, 1f + li t3, 32 + addiu t1, t1, 1 + sllv t1, t3, t1 +1: /* At this point t1 == I-cache sets per way */ + _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ + addiu t2, t2, 1 + mul t1, t1, t0 + mul t1, t1, t2 + + li a0, CKSEG0 + PTR_ADD a1, a0, t1 +1: cache Index_Store_Tag_I, 0(a0) + PTR_ADD a0, a0, t0 + bne a0, a1, 1b + nop +icache_done: + + /* Detect D-cache line size */ + _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ + beqz t0, dcache_done + li t1, 2 + sllv t0, t1, t0 + + /* Detect D-cache size */ + _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ + xori t2, t1, 0x7 + beqz t2, 1f + li t3, 32 + addiu t1, t1, 1 + sllv t1, t3, t1 +1: /* At this point t1 == D-cache sets per way */ + _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ + addiu t2, t2, 1 + mul t1, t1, t0 + mul t1, t1, t2 + + li a0, CKSEG0 + PTR_ADDU a1, a0, t1 + PTR_SUBU a1, a1, t0 +1: cache Index_Store_Tag_D, 0(a0) + bne a0, a1, 1b + PTR_ADD a0, a0, t0 +dcache_done: + + jr ra + nop + END(mips_cps_cache_init) + #if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM) /* Calculate a pointer to this CPUs struct mips_static_suspend_state */ diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index b725b713b9f8..5ac5c3e23460 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -539,6 +539,7 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) switch (c->cputype) { case CPU_PROAPTIV: case CPU_P5600: + case CPU_P6600: /* proAptiv & related cores use Config6 to enable the FTLB */ config = read_c0_config6(); /* Clear the old probability value */ @@ -561,6 +562,19 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) write_c0_config7(config | (calculate_ftlb_probability(c) << MIPS_CONF7_FTLBP_SHIFT)); break; + case CPU_LOONGSON3: + /* Flush ITLB, DTLB, VTLB and FTLB */ + write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB | + LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB); + /* Loongson-3 cores use Config6 to enable the FTLB */ + config = read_c0_config6(); + if (enable) + /* Enable FTLB */ + write_c0_config6(config & ~MIPS_CONF6_FTLBDIS); + else + /* Disable FTLB */ + write_c0_config6(config | MIPS_CONF6_FTLBDIS); + break; default: return 1; } @@ -634,6 +648,8 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c) if (config1 & MIPS_CONF1_MD) c->ases |= MIPS_ASE_MDMX; + if (config1 & MIPS_CONF1_PC) + c->options |= MIPS_CPU_PERF; if (config1 & MIPS_CONF1_WR) c->options |= MIPS_CPU_WATCH; if (config1 & MIPS_CONF1_CA) @@ -673,18 +689,25 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) if (config3 & MIPS_CONF3_SM) { c->ases |= MIPS_ASE_SMARTMIPS; - c->options |= MIPS_CPU_RIXI; + c->options |= MIPS_CPU_RIXI | MIPS_CPU_CTXTC; } if (config3 & MIPS_CONF3_RXI) c->options |= MIPS_CPU_RIXI; + if (config3 & MIPS_CONF3_CTXTC) + c->options |= MIPS_CPU_CTXTC; if (config3 & MIPS_CONF3_DSP) c->ases |= MIPS_ASE_DSP; - if (config3 & MIPS_CONF3_DSP2P) + if (config3 & MIPS_CONF3_DSP2P) { c->ases |= MIPS_ASE_DSP2P; + if (cpu_has_mips_r6) + c->ases |= MIPS_ASE_DSP3; + } if (config3 & MIPS_CONF3_VINT) c->options |= MIPS_CPU_VINT; if (config3 & MIPS_CONF3_VEIC) c->options |= MIPS_CPU_VEIC; + if (config3 & MIPS_CONF3_LPA) + c->options |= MIPS_CPU_LPA; if (config3 & MIPS_CONF3_MT) c->ases |= MIPS_ASE_MIPSMT; if (config3 & MIPS_CONF3_ULRI) @@ -695,6 +718,10 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->ases |= MIPS_ASE_VZ; if (config3 & MIPS_CONF3_SC) c->options |= MIPS_CPU_SEGMENTS; + if (config3 & MIPS_CONF3_BI) + c->options |= MIPS_CPU_BADINSTR; + if (config3 & MIPS_CONF3_BP) + c->options |= MIPS_CPU_BADINSTRP; if (config3 & MIPS_CONF3_MSA) c->ases |= MIPS_ASE_MSA; if (config3 & MIPS_CONF3_PW) { @@ -715,6 +742,7 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) unsigned int newcf4; unsigned int mmuextdef; unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE; + unsigned long asid_mask; config4 = read_c0_config4(); @@ -773,7 +801,20 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) } } - c->kscratch_mask = (config4 >> 16) & 0xff; + c->kscratch_mask = (config4 & MIPS_CONF4_KSCREXIST) + >> MIPS_CONF4_KSCREXIST_SHIFT; + + asid_mask = MIPS_ENTRYHI_ASID; + if (config4 & MIPS_CONF4_AE) + asid_mask |= MIPS_ENTRYHI_ASIDX; + set_cpu_asid_mask(c, asid_mask); + + /* + * Warn if the computed ASID mask doesn't match the mask the kernel + * is built for. This may indicate either a serious problem or an + * easy optimisation opportunity, but either way should be addressed. + */ + WARN_ON(asid_mask != cpu_asid_mask(c)); return config4 & MIPS_CONF_M; } @@ -796,6 +837,8 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) if (config5 & MIPS_CONF5_MVH) c->options |= MIPS_CPU_XPA; #endif + if (cpu_has_mips_r6 && (config5 & MIPS_CONF5_VP)) + c->options |= MIPS_CPU_VP; return config5 & MIPS_CONF_M; } @@ -826,17 +869,43 @@ static void decode_configs(struct cpuinfo_mips *c) if (ok) ok = decode_config5(c); - mips_probe_watch_registers(c); - - if (cpu_has_rixi) { - /* Enable the RIXI exceptions */ - set_c0_pagegrain(PG_IEC); - back_to_back_c0_hazard(); - /* Verify the IEC bit is set */ - if (read_c0_pagegrain() & PG_IEC) - c->options |= MIPS_CPU_RIXIEX; + /* Probe the EBase.WG bit */ + if (cpu_has_mips_r2_r6) { + u64 ebase; + unsigned int status; + + /* {read,write}_c0_ebase_64() may be UNDEFINED prior to r6 */ + ebase = cpu_has_mips64r6 ? read_c0_ebase_64() + : (s32)read_c0_ebase(); + if (ebase & MIPS_EBASE_WG) { + /* WG bit already set, we can avoid the clumsy probe */ + c->options |= MIPS_CPU_EBASE_WG; + } else { + /* Its UNDEFINED to change EBase while BEV=0 */ + status = read_c0_status(); + write_c0_status(status | ST0_BEV); + irq_enable_hazard(); + /* + * On pre-r6 cores, this may well clobber the upper bits + * of EBase. This is hard to avoid without potentially + * hitting UNDEFINED dm*c0 behaviour if EBase is 32-bit. + */ + if (cpu_has_mips64r6) + write_c0_ebase_64(ebase | MIPS_EBASE_WG); + else + write_c0_ebase(ebase | MIPS_EBASE_WG); + back_to_back_c0_hazard(); + /* Restore BEV */ + write_c0_status(status); + if (read_c0_ebase() & MIPS_EBASE_WG) { + c->options |= MIPS_CPU_EBASE_WG; + write_c0_ebase(ebase); + } + } } + mips_probe_watch_registers(c); + #ifndef CONFIG_MIPS_CPS if (cpu_has_mips_r2_r6) { c->core = get_ebase_cpunum(); @@ -846,6 +915,235 @@ static void decode_configs(struct cpuinfo_mips *c) #endif } +/* + * Probe for certain guest capabilities by writing config bits and reading back. + * Finally write back the original value. + */ +#define probe_gc0_config(name, maxconf, bits) \ +do { \ + unsigned int tmp; \ + tmp = read_gc0_##name(); \ + write_gc0_##name(tmp | (bits)); \ + back_to_back_c0_hazard(); \ + maxconf = read_gc0_##name(); \ + write_gc0_##name(tmp); \ +} while (0) + +/* + * Probe for dynamic guest capabilities by changing certain config bits and + * reading back to see if they change. Finally write back the original value. + */ +#define probe_gc0_config_dyn(name, maxconf, dynconf, bits) \ +do { \ + maxconf = read_gc0_##name(); \ + write_gc0_##name(maxconf ^ (bits)); \ + back_to_back_c0_hazard(); \ + dynconf = maxconf ^ read_gc0_##name(); \ + write_gc0_##name(maxconf); \ + maxconf |= dynconf; \ +} while (0) + +static inline unsigned int decode_guest_config0(struct cpuinfo_mips *c) +{ + unsigned int config0; + + probe_gc0_config(config, config0, MIPS_CONF_M); + + if (config0 & MIPS_CONF_M) + c->guest.conf |= BIT(1); + return config0 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config1(struct cpuinfo_mips *c) +{ + unsigned int config1, config1_dyn; + + probe_gc0_config_dyn(config1, config1, config1_dyn, + MIPS_CONF_M | MIPS_CONF1_PC | MIPS_CONF1_WR | + MIPS_CONF1_FP); + + if (config1 & MIPS_CONF1_FP) + c->guest.options |= MIPS_CPU_FPU; + if (config1_dyn & MIPS_CONF1_FP) + c->guest.options_dyn |= MIPS_CPU_FPU; + + if (config1 & MIPS_CONF1_WR) + c->guest.options |= MIPS_CPU_WATCH; + if (config1_dyn & MIPS_CONF1_WR) + c->guest.options_dyn |= MIPS_CPU_WATCH; + + if (config1 & MIPS_CONF1_PC) + c->guest.options |= MIPS_CPU_PERF; + if (config1_dyn & MIPS_CONF1_PC) + c->guest.options_dyn |= MIPS_CPU_PERF; + + if (config1 & MIPS_CONF_M) + c->guest.conf |= BIT(2); + return config1 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config2(struct cpuinfo_mips *c) +{ + unsigned int config2; + + probe_gc0_config(config2, config2, MIPS_CONF_M); + + if (config2 & MIPS_CONF_M) + c->guest.conf |= BIT(3); + return config2 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config3(struct cpuinfo_mips *c) +{ + unsigned int config3, config3_dyn; + + probe_gc0_config_dyn(config3, config3, config3_dyn, + MIPS_CONF_M | MIPS_CONF3_MSA | MIPS_CONF3_CTXTC); + + if (config3 & MIPS_CONF3_CTXTC) + c->guest.options |= MIPS_CPU_CTXTC; + if (config3_dyn & MIPS_CONF3_CTXTC) + c->guest.options_dyn |= MIPS_CPU_CTXTC; + + if (config3 & MIPS_CONF3_PW) + c->guest.options |= MIPS_CPU_HTW; + + if (config3 & MIPS_CONF3_SC) + c->guest.options |= MIPS_CPU_SEGMENTS; + + if (config3 & MIPS_CONF3_BI) + c->guest.options |= MIPS_CPU_BADINSTR; + if (config3 & MIPS_CONF3_BP) + c->guest.options |= MIPS_CPU_BADINSTRP; + + if (config3 & MIPS_CONF3_MSA) + c->guest.ases |= MIPS_ASE_MSA; + if (config3_dyn & MIPS_CONF3_MSA) + c->guest.ases_dyn |= MIPS_ASE_MSA; + + if (config3 & MIPS_CONF_M) + c->guest.conf |= BIT(4); + return config3 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config4(struct cpuinfo_mips *c) +{ + unsigned int config4; + + probe_gc0_config(config4, config4, + MIPS_CONF_M | MIPS_CONF4_KSCREXIST); + + c->guest.kscratch_mask = (config4 & MIPS_CONF4_KSCREXIST) + >> MIPS_CONF4_KSCREXIST_SHIFT; + + if (config4 & MIPS_CONF_M) + c->guest.conf |= BIT(5); + return config4 & MIPS_CONF_M; +} + +static inline unsigned int decode_guest_config5(struct cpuinfo_mips *c) +{ + unsigned int config5, config5_dyn; + + probe_gc0_config_dyn(config5, config5, config5_dyn, + MIPS_CONF_M | MIPS_CONF5_MRP); + + if (config5 & MIPS_CONF5_MRP) + c->guest.options |= MIPS_CPU_MAAR; + if (config5_dyn & MIPS_CONF5_MRP) + c->guest.options_dyn |= MIPS_CPU_MAAR; + + if (config5 & MIPS_CONF5_LLB) + c->guest.options |= MIPS_CPU_RW_LLB; + + if (config5 & MIPS_CONF_M) + c->guest.conf |= BIT(6); + return config5 & MIPS_CONF_M; +} + +static inline void decode_guest_configs(struct cpuinfo_mips *c) +{ + unsigned int ok; + + ok = decode_guest_config0(c); + if (ok) + ok = decode_guest_config1(c); + if (ok) + ok = decode_guest_config2(c); + if (ok) + ok = decode_guest_config3(c); + if (ok) + ok = decode_guest_config4(c); + if (ok) + decode_guest_config5(c); +} + +static inline void cpu_probe_guestctl0(struct cpuinfo_mips *c) +{ + unsigned int guestctl0, temp; + + guestctl0 = read_c0_guestctl0(); + + if (guestctl0 & MIPS_GCTL0_G0E) + c->options |= MIPS_CPU_GUESTCTL0EXT; + if (guestctl0 & MIPS_GCTL0_G1) + c->options |= MIPS_CPU_GUESTCTL1; + if (guestctl0 & MIPS_GCTL0_G2) + c->options |= MIPS_CPU_GUESTCTL2; + if (!(guestctl0 & MIPS_GCTL0_RAD)) { + c->options |= MIPS_CPU_GUESTID; + + /* + * Probe for Direct Root to Guest (DRG). Set GuestCtl1.RID = 0 + * first, otherwise all data accesses will be fully virtualised + * as if they were performed by guest mode. + */ + write_c0_guestctl1(0); + tlbw_use_hazard(); + + write_c0_guestctl0(guestctl0 | MIPS_GCTL0_DRG); + back_to_back_c0_hazard(); + temp = read_c0_guestctl0(); + + if (temp & MIPS_GCTL0_DRG) { + write_c0_guestctl0(guestctl0); + c->options |= MIPS_CPU_DRG; + } + } +} + +static inline void cpu_probe_guestctl1(struct cpuinfo_mips *c) +{ + if (cpu_has_guestid) { + /* determine the number of bits of GuestID available */ + write_c0_guestctl1(MIPS_GCTL1_ID); + back_to_back_c0_hazard(); + c->guestid_mask = (read_c0_guestctl1() & MIPS_GCTL1_ID) + >> MIPS_GCTL1_ID_SHIFT; + write_c0_guestctl1(0); + } +} + +static inline void cpu_probe_gtoffset(struct cpuinfo_mips *c) +{ + /* determine the number of bits of GTOffset available */ + write_c0_gtoffset(0xffffffff); + back_to_back_c0_hazard(); + c->gtoffset_mask = read_c0_gtoffset(); + write_c0_gtoffset(0); +} + +static inline void cpu_probe_vz(struct cpuinfo_mips *c) +{ + cpu_probe_guestctl0(c); + if (cpu_has_guestctl1) + cpu_probe_guestctl1(c); + + cpu_probe_gtoffset(c); + + decode_guest_configs(c); +} + #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \ | MIPS_CPU_COUNTER) @@ -1172,7 +1470,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) set_isa(c, MIPS_CPU_ISA_III); c->fpu_msk31 |= FPU_CSR_CONDX; break; - case PRID_REV_LOONGSON3A: + case PRID_REV_LOONGSON3A_R1: c->cputype = CPU_LOONGSON3; __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3a"); @@ -1314,6 +1612,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_P5600; __cpu_name[cpu] = "MIPS P5600"; break; + case PRID_IMP_P6600: + c->cputype = CPU_P6600; + __cpu_name[cpu] = "MIPS P6600"; + break; case PRID_IMP_I6400: c->cputype = CPU_I6400; __cpu_name[cpu] = "MIPS I6400"; @@ -1322,6 +1624,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_M5150; __cpu_name[cpu] = "MIPS M5150"; break; + case PRID_IMP_M6250: + c->cputype = CPU_M6250; + __cpu_name[cpu] = "MIPS M6250"; + break; } decode_configs(c); @@ -1435,6 +1741,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_BMIPS4380; __cpu_name[cpu] = "Broadcom BMIPS4380"; set_elf_platform(cpu, "bmips4380"); + c->options |= MIPS_CPU_RIXI; } else { c->cputype = CPU_BMIPS4350; __cpu_name[cpu] = "Broadcom BMIPS4350"; @@ -1445,9 +1752,12 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) case PRID_IMP_BMIPS5000: case PRID_IMP_BMIPS5200: c->cputype = CPU_BMIPS5000; - __cpu_name[cpu] = "Broadcom BMIPS5000"; + if ((c->processor_id & PRID_IMP_MASK) == PRID_IMP_BMIPS5200) + __cpu_name[cpu] = "Broadcom BMIPS5200"; + else + __cpu_name[cpu] = "Broadcom BMIPS5000"; set_elf_platform(cpu, "bmips5000"); - c->options |= MIPS_CPU_ULRI; + c->options |= MIPS_CPU_ULRI | MIPS_CPU_RIXI; break; } } @@ -1481,6 +1791,8 @@ platform: set_elf_platform(cpu, "octeon2"); break; case PRID_IMP_CAVIUM_CN70XX: + case PRID_IMP_CAVIUM_CN73XX: + case PRID_IMP_CAVIUM_CNF75XX: case PRID_IMP_CAVIUM_CN78XX: c->cputype = CPU_CAVIUM_OCTEON3; __cpu_name[cpu] = "Cavium Octeon III"; @@ -1493,6 +1805,29 @@ platform: } } +static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) +{ + switch (c->processor_id & PRID_IMP_MASK) { + case PRID_IMP_LOONGSON_64: /* Loongson-2/3 */ + switch (c->processor_id & PRID_REV_MASK) { + case PRID_REV_LOONGSON3A_R2: + c->cputype = CPU_LOONGSON3; + __cpu_name[cpu] = "ICT Loongson-3"; + set_elf_platform(cpu, "loongson3a"); + set_isa(c, MIPS_CPU_ISA_M64R2); + break; + } + + decode_configs(c); + c->options |= MIPS_CPU_TLBINV | MIPS_CPU_LDPTE; + c->writecombine = _CACHE_UNCACHED_ACCELERATED; + break; + default: + panic("Unknown Loongson Processor ID!"); + break; + } +} + static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) { decode_configs(c); @@ -1640,6 +1975,9 @@ void cpu_probe(void) case PRID_COMP_CAVIUM: cpu_probe_cavium(c, cpu); break; + case PRID_COMP_LOONGSON: + cpu_probe_loongson(c, cpu); + break; case PRID_COMP_INGENIC_D0: case PRID_COMP_INGENIC_D1: case PRID_COMP_INGENIC_E1: @@ -1660,6 +1998,15 @@ void cpu_probe(void) */ BUG_ON(current_cpu_type() != c->cputype); + if (cpu_has_rixi) { + /* Enable the RIXI exceptions */ + set_c0_pagegrain(PG_IEC); + back_to_back_c0_hazard(); + /* Verify the IEC bit is set */ + if (read_c0_pagegrain() & PG_IEC) + c->options |= MIPS_CPU_RIXIEX; + } + if (mips_fpu_disabled) c->options &= ~MIPS_CPU_FPU; @@ -1699,6 +2046,9 @@ void cpu_probe(void) elf_hwcap |= HWCAP_MIPS_MSA; } + if (cpu_has_vz) + cpu_probe_vz(c); + cpu_probe_vmbits(c); #ifdef CONFIG_64BIT diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index d434d5d5ae6e..610f0f3bdb34 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -14,12 +14,22 @@ static int crashing_cpu = -1; static cpumask_t cpus_in_crash = CPU_MASK_NONE; #ifdef CONFIG_SMP -static void crash_shutdown_secondary(void *ignore) +static void crash_shutdown_secondary(void *passed_regs) { - struct pt_regs *regs; + struct pt_regs *regs = passed_regs; int cpu = smp_processor_id(); - regs = task_pt_regs(current); + /* + * If we are passed registers, use those. Otherwise get the + * regs from the last interrupt, which should be correct, as + * we are in an interrupt. But if the regs are not there, + * pull them from the top of the stack. They are probably + * wrong, but we need something to keep from crashing again. + */ + if (!regs) + regs = get_irq_regs(); + if (!regs) + regs = task_pt_regs(current); if (!cpu_online(cpu)) return; diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index baa7b6fc0a60..17326a90d53c 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -130,7 +130,7 @@ LEAF(__r4k_wait) /* end of rollback region (the region size must be power of two) */ 1: jr ra - nop + nop .set pop END(__r4k_wait) @@ -172,7 +172,7 @@ NESTED(handle_int, PT_SIZE, sp) mfc0 k0, CP0_EPC .set noreorder j k0 - rfe + rfe #else and k0, ST0_IE bnez k0, 1f @@ -189,7 +189,7 @@ NESTED(handle_int, PT_SIZE, sp) LONG_L s0, TI_REGS($28) LONG_S sp, TI_REGS($28) PTR_LA ra, ret_from_irq - PTR_LA v0, plat_irq_dispatch + PTR_LA v0, plat_irq_dispatch jr v0 #ifdef CONFIG_CPU_MICROMIPS nop @@ -292,7 +292,7 @@ ejtag_return: MFC0 k0, CP0_DESAVE .set mips32 deret - .set pop + .set pop END(ejtag_debug_handler) /* @@ -329,10 +329,10 @@ NESTED(nmi_handler, PT_SIZE, sp) * Clear BEV - required for page fault exception handler to work */ mfc0 k0, CP0_STATUS - ori k0, k0, ST0_EXL + ori k0, k0, ST0_EXL li k1, ~(ST0_BEV | ST0_ERL) - and k0, k0, k1 - mtc0 k0, CP0_STATUS + and k0, k0, k1 + mtc0 k0, CP0_STATUS _ehb SAVE_ALL move a0, sp @@ -396,7 +396,7 @@ NESTED(nmi_handler, PT_SIZE, sp) .macro __BUILD_count exception LONG_L t0,exception_count_\exception - LONG_ADDIU t0, 1 + LONG_ADDIU t0, 1 LONG_S t0,exception_count_\exception .comm exception_count\exception, 8, 8 .endm @@ -455,10 +455,10 @@ NESTED(nmi_handler, PT_SIZE, sp) .set noreorder /* check if TLB contains a entry for EPC */ MFC0 k1, CP0_ENTRYHI - andi k1, 0xff /* ASID_MASK */ + andi k1, MIPS_ENTRYHI_ASID | MIPS_ENTRYHI_ASIDX MFC0 k0, CP0_EPC - PTR_SRL k0, _PAGE_SHIFT + 1 - PTR_SLL k0, _PAGE_SHIFT + 1 + PTR_SRL k0, _PAGE_SHIFT + 1 + PTR_SLL k0, _PAGE_SHIFT + 1 or k1, k0 MTC0 k1, CP0_ENTRYHI mtc0_tlbw_hazard @@ -478,27 +478,27 @@ NESTED(nmi_handler, PT_SIZE, sp) /* microMIPS: 0x007d6b3c: rdhwr v1,$29 */ MFC0 k1, CP0_EPC #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS64_R2) - and k0, k1, 1 - beqz k0, 1f - xor k1, k0 - lhu k0, (k1) - lhu k1, 2(k1) - ins k1, k0, 16, 16 - lui k0, 0x007d - b docheck - ori k0, 0x6b3c + and k0, k1, 1 + beqz k0, 1f + xor k1, k0 + lhu k0, (k1) + lhu k1, 2(k1) + ins k1, k0, 16, 16 + lui k0, 0x007d + b docheck + ori k0, 0x6b3c 1: - lui k0, 0x7c03 - lw k1, (k1) - ori k0, 0xe83b + lui k0, 0x7c03 + lw k1, (k1) + ori k0, 0xe83b #else - andi k0, k1, 1 - bnez k0, handle_ri - lui k0, 0x7c03 - lw k1, (k1) - ori k0, 0xe83b + andi k0, k1, 1 + bnez k0, handle_ri + lui k0, 0x7c03 + lw k1, (k1) + ori k0, 0xe83b #endif - .set reorder + .set reorder docheck: bne k0, k1, handle_ri /* if not ours */ diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 4e4cc5b9a771..56e8fede3fd8 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -21,7 +21,6 @@ #include <asm/asmmacro.h> #include <asm/irqflags.h> #include <asm/regdef.h> -#include <asm/pgtable-bits.h> #include <asm/mipsregs.h> #include <asm/stackframe.h> @@ -132,7 +131,27 @@ not_found: set_saved_sp sp, t0, t1 PTR_SUBU sp, 4 * SZREG # init stack pointer +#ifdef CONFIG_RELOCATABLE + /* Copy kernel and apply the relocations */ + jal relocate_kernel + + /* Repoint the sp into the new kernel image */ + PTR_LI sp, _THREAD_SIZE - 32 - PT_SIZE + PTR_ADDU sp, $28 + set_saved_sp sp, t0, t1 + PTR_SUBU sp, 4 * SZREG # init stack pointer + + /* + * relocate_kernel returns the entry point either + * in the relocated kernel or the original if for + * some reason relocation failed - jump there now + * with instruction hazard barrier because of the + * newly sync'd icache. + */ + jr.hb v0 +#else j start_kernel +#endif END(kernel_entry) #ifdef CONFIG_SMP diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index 46794d64c0bf..60ab4c44d305 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -181,6 +181,11 @@ void __init check_wait(void) case CPU_XLP: cpu_wait = r4k_wait; break; + case CPU_LOONGSON3: + if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON3A_R2) + cpu_wait = r4k_wait; + break; + case CPU_BMIPS5000: cpu_wait = r4k_wait_irqoff; break; diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index 3fff89ae760b..625ee770b1aa 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -28,6 +28,7 @@ #include <asm/inst.h> #include <asm/mips-r2-to-r6-emul.h> #include <asm/local.h> +#include <asm/mipsregs.h> #include <asm/ptrace.h> #include <asm/uaccess.h> @@ -1251,10 +1252,10 @@ fpu_emul: " j 10b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1326,10 +1327,10 @@ fpu_emul: " j 10b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1397,10 +1398,10 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1467,10 +1468,10 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1582,14 +1583,14 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" - " .word 5b,8b\n" - " .word 6b,8b\n" - " .word 7b,8b\n" - " .word 0b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" + STR(PTR) " 5b,8b\n" + STR(PTR) " 6b,8b\n" + STR(PTR) " 7b,8b\n" + STR(PTR) " 0b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1701,14 +1702,14 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" - " .word 5b,8b\n" - " .word 6b,8b\n" - " .word 7b,8b\n" - " .word 0b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" + STR(PTR) " 5b,8b\n" + STR(PTR) " 6b,8b\n" + STR(PTR) " 7b,8b\n" + STR(PTR) " 0b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1820,14 +1821,14 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" - " .word 5b,8b\n" - " .word 6b,8b\n" - " .word 7b,8b\n" - " .word 0b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" + STR(PTR) " 5b,8b\n" + STR(PTR) " 6b,8b\n" + STR(PTR) " 7b,8b\n" + STR(PTR) " 0b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -1938,14 +1939,14 @@ fpu_emul: " j 9b\n" " .previous\n" " .section __ex_table,\"a\"\n" - " .word 1b,8b\n" - " .word 2b,8b\n" - " .word 3b,8b\n" - " .word 4b,8b\n" - " .word 5b,8b\n" - " .word 6b,8b\n" - " .word 7b,8b\n" - " .word 0b,8b\n" + STR(PTR) " 1b,8b\n" + STR(PTR) " 2b,8b\n" + STR(PTR) " 3b,8b\n" + STR(PTR) " 4b,8b\n" + STR(PTR) " 5b,8b\n" + STR(PTR) " 6b,8b\n" + STR(PTR) " 7b,8b\n" + STR(PTR) " 0b,8b\n" " .previous\n" " .set pop\n" : "+&r"(rt), "=&r"(rs), @@ -2000,7 +2001,7 @@ fpu_emul: "j 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" - ".word 1b, 3b\n" + STR(PTR) " 1b,3b\n" ".previous\n" : "=&r"(res), "+&r"(err) : "r"(vaddr), "i"(SIGSEGV) @@ -2058,7 +2059,7 @@ fpu_emul: "j 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" - ".word 1b, 3b\n" + STR(PTR) " 1b,3b\n" ".previous\n" : "+&r"(res), "+&r"(err) : "r"(vaddr), "i"(SIGSEGV)); @@ -2119,7 +2120,7 @@ fpu_emul: "j 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" - ".word 1b, 3b\n" + STR(PTR) " 1b,3b\n" ".previous\n" : "=&r"(res), "+&r"(err) : "r"(vaddr), "i"(SIGSEGV) @@ -2182,7 +2183,7 @@ fpu_emul: "j 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" - ".word 1b, 3b\n" + STR(PTR) " 1b,3b\n" ".previous\n" : "+&r"(res), "+&r"(err) : "r"(vaddr), "i"(SIGSEGV)); diff --git a/arch/mips/kernel/module-rela.c b/arch/mips/kernel/module-rela.c index 9083d63b765c..781168834456 100644 --- a/arch/mips/kernel/module-rela.c +++ b/arch/mips/kernel/module-rela.c @@ -16,6 +16,7 @@ * Copyright (C) 2001 Rusty Russell. * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2005 Thiemo Seufer + * Copyright (C) 2015 Imagination Technologies Ltd. */ #include <linux/elf.h> @@ -35,15 +36,13 @@ static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v) static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v) { if (v % 4) { - pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n", + pr_err("module %s: dangerous R_MIPS_26 RELA relocation\n", me->name); return -ENOEXEC; } if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { - printk(KERN_ERR - "module %s: relocation overflow\n", - me->name); + pr_err("module %s: relocation overflow\n", me->name); return -ENOEXEC; } @@ -67,6 +66,48 @@ static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v) return 0; } +static int apply_r_mips_pc_rela(struct module *me, u32 *location, Elf_Addr v, + unsigned bits) +{ + unsigned long mask = GENMASK(bits - 1, 0); + unsigned long se_bits; + long offset; + + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_PC%u RELA relocation\n", + me->name, bits); + return -ENOEXEC; + } + + offset = ((long)v - (long)location) >> 2; + + /* check the sign bit onwards are identical - ie. we didn't overflow */ + se_bits = (offset & BIT(bits - 1)) ? ~0ul : 0; + if ((offset & ~mask) != (se_bits & ~mask)) { + pr_err("module %s: relocation overflow\n", me->name); + return -ENOEXEC; + } + + *location = (*location & ~mask) | (offset & mask); + + return 0; +} + +static int apply_r_mips_pc16_rela(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rela(me, location, v, 16); +} + +static int apply_r_mips_pc21_rela(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rela(me, location, v, 21); +} + +static int apply_r_mips_pc26_rela(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rela(me, location, v, 26); +} + static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v) { *(Elf_Addr *)location = v; @@ -99,9 +140,12 @@ static int (*reloc_handlers_rela[]) (struct module *me, u32 *location, [R_MIPS_26] = apply_r_mips_26_rela, [R_MIPS_HI16] = apply_r_mips_hi16_rela, [R_MIPS_LO16] = apply_r_mips_lo16_rela, + [R_MIPS_PC16] = apply_r_mips_pc16_rela, [R_MIPS_64] = apply_r_mips_64_rela, [R_MIPS_HIGHER] = apply_r_mips_higher_rela, - [R_MIPS_HIGHEST] = apply_r_mips_highest_rela + [R_MIPS_HIGHEST] = apply_r_mips_highest_rela, + [R_MIPS_PC21_S2] = apply_r_mips_pc21_rela, + [R_MIPS_PC26_S2] = apply_r_mips_pc26_rela, }; int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, @@ -126,11 +170,11 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, /* This is the symbol it is referring to */ sym = (Elf_Sym *)sechdrs[symindex].sh_addr + ELF_MIPS_R_SYM(rel[i]); - if (IS_ERR_VALUE(sym->st_value)) { + if (sym->st_value >= -MAX_ERRNO) { /* Ignore unresolved weak symbol */ if (ELF_ST_BIND(sym->st_info) == STB_WEAK) continue; - printk(KERN_WARNING "%s: Unknown symbol %s\n", + pr_warn("%s: Unknown symbol %s\n", me->name, strtab + sym->st_name); return -ENOENT; } diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index f9b2936d598d..79850e376ef6 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c @@ -73,8 +73,7 @@ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) } if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { - printk(KERN_ERR - "module %s: relocation overflow\n", + pr_err("module %s: relocation overflow\n", me->name); return -ENOEXEC; } @@ -183,13 +182,62 @@ out_danger: return -ENOEXEC; } +static int apply_r_mips_pc_rel(struct module *me, u32 *location, Elf_Addr v, + unsigned bits) +{ + unsigned long mask = GENMASK(bits - 1, 0); + unsigned long se_bits; + long offset; + + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_PC%u REL relocation\n", + me->name, bits); + return -ENOEXEC; + } + + /* retrieve & sign extend implicit addend */ + offset = *location & mask; + offset |= (offset & BIT(bits - 1)) ? ~mask : 0; + + offset += ((long)v - (long)location) >> 2; + + /* check the sign bit onwards are identical - ie. we didn't overflow */ + se_bits = (offset & BIT(bits - 1)) ? ~0ul : 0; + if ((offset & ~mask) != (se_bits & ~mask)) { + pr_err("module %s: relocation overflow\n", me->name); + return -ENOEXEC; + } + + *location = (*location & ~mask) | (offset & mask); + + return 0; +} + +static int apply_r_mips_pc16_rel(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rel(me, location, v, 16); +} + +static int apply_r_mips_pc21_rel(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rel(me, location, v, 21); +} + +static int apply_r_mips_pc26_rel(struct module *me, u32 *location, Elf_Addr v) +{ + return apply_r_mips_pc_rel(me, location, v, 26); +} + static int (*reloc_handlers_rel[]) (struct module *me, u32 *location, Elf_Addr v) = { [R_MIPS_NONE] = apply_r_mips_none, [R_MIPS_32] = apply_r_mips_32_rel, [R_MIPS_26] = apply_r_mips_26_rel, [R_MIPS_HI16] = apply_r_mips_hi16_rel, - [R_MIPS_LO16] = apply_r_mips_lo16_rel + [R_MIPS_LO16] = apply_r_mips_lo16_rel, + [R_MIPS_PC16] = apply_r_mips_pc16_rel, + [R_MIPS_PC21_S2] = apply_r_mips_pc21_rel, + [R_MIPS_PC26_S2] = apply_r_mips_pc26_rel, }; int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, @@ -215,12 +263,12 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, /* This is the symbol it is referring to */ sym = (Elf_Sym *)sechdrs[symindex].sh_addr + ELF_MIPS_R_SYM(rel[i]); - if (IS_ERR_VALUE(sym->st_value)) { + if (sym->st_value >= -MAX_ERRNO) { /* Ignore unresolved weak symbol */ if (ELF_ST_BIND(sym->st_info) == STB_WEAK) continue; - printk(KERN_WARNING "%s: Unknown symbol %s\n", - me->name, strtab + sym->st_name); + pr_warn("%s: Unknown symbol %s\n", + me->name, strtab + sym->st_name); return -ENOENT; } diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index 9bc1191b1ab0..d3ba9f4105b5 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -101,8 +101,6 @@ struct mips_pmu { static struct mips_pmu mipspmu; -#define M_CONFIG1_PC (1 << 4) - #define M_PERFCTL_EXL (1 << 0) #define M_PERFCTL_KERNEL (1 << 1) #define M_PERFCTL_SUPERVISOR (1 << 2) @@ -754,7 +752,7 @@ static void handle_associated_event(struct cpu_hw_events *cpuc, static int __n_counters(void) { - if (!(read_c0_config1() & M_CONFIG1_PC)) + if (!cpu_has_perf) return 0; if (!(read_c0_perfctrl0() & M_PERFCTL_MORE)) return 1; @@ -825,6 +823,16 @@ static const struct mips_perf_event mipsxxcore_event_map2 [PERF_COUNT_HW_BRANCH_MISSES] = { 0x27, CNTR_ODD, T }, }; +static const struct mips_perf_event i6400_event_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD }, + [PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD }, + /* These only count dcache, not icache */ + [PERF_COUNT_HW_CACHE_REFERENCES] = { 0x45, CNTR_EVEN | CNTR_ODD }, + [PERF_COUNT_HW_CACHE_MISSES] = { 0x48, CNTR_EVEN | CNTR_ODD }, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x15, CNTR_EVEN | CNTR_ODD }, + [PERF_COUNT_HW_BRANCH_MISSES] = { 0x16, CNTR_EVEN | CNTR_ODD }, +}; + static const struct mips_perf_event loongson3_event_map[PERF_COUNT_HW_MAX] = { [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN }, [PERF_COUNT_HW_INSTRUCTIONS] = { 0x00, CNTR_ODD }, @@ -1015,6 +1023,46 @@ static const struct mips_perf_event mipsxxcore_cache_map2 }, }; +static const struct mips_perf_event i6400_cache_map + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { +[C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x46, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x49, CNTR_EVEN | CNTR_ODD }, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { 0x47, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x4a, CNTR_EVEN | CNTR_ODD }, + }, +}, +[C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x84, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x85, CNTR_EVEN | CNTR_ODD }, + }, +}, +[C(DTLB)] = { + /* Can't distinguish read & write */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x40, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x41, CNTR_EVEN | CNTR_ODD }, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = { 0x40, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x41, CNTR_EVEN | CNTR_ODD }, + }, +}, +[C(BPU)] = { + /* Conditional branches / mispredicted */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = { 0x15, CNTR_EVEN | CNTR_ODD }, + [C(RESULT_MISS)] = { 0x16, CNTR_EVEN | CNTR_ODD }, + }, +}, +}; + static const struct mips_perf_event loongson3_cache_map [PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_OP_MAX] @@ -1556,6 +1604,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) #endif break; case CPU_P5600: + case CPU_P6600: case CPU_I6400: /* 8-bit event numbers */ raw_id = config & 0x1ff; @@ -1718,11 +1767,16 @@ init_hw_perf_events(void) mipspmu.general_event_map = &mipsxxcore_event_map2; mipspmu.cache_event_map = &mipsxxcore_cache_map2; break; - case CPU_I6400: - mipspmu.name = "mips/I6400"; + case CPU_P6600: + mipspmu.name = "mips/P6600"; mipspmu.general_event_map = &mipsxxcore_event_map2; mipspmu.cache_event_map = &mipsxxcore_cache_map2; break; + case CPU_I6400: + mipspmu.name = "mips/I6400"; + mipspmu.general_event_map = &i6400_event_map; + mipspmu.cache_event_map = &i6400_cache_map; + break; case CPU_1004K: mipspmu.name = "mips/1004K"; mipspmu.general_event_map = &mipsxxcore_event_map; diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index fa3f9ebad8f4..adda3ffb9b78 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -224,11 +224,18 @@ static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, uasm_build_label(pl, *pp, lbl); /* Generate the cache ops */ - for (i = 0; i < unroll_lines; i++) - uasm_i_cache(pp, op, i * cache->linesz, t0); + for (i = 0; i < unroll_lines; i++) { + if (cpu_has_mips_r6) { + uasm_i_cache(pp, op, 0, t0); + uasm_i_addiu(pp, t0, t0, cache->linesz); + } else { + uasm_i_cache(pp, op, i * cache->linesz, t0); + } + } - /* Update the base address */ - uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz); + if (!cpu_has_mips_r6) + /* Update the base address */ + uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz); /* Loop if we haven't reached the end address yet */ uasm_il_bne(pp, pr, t0, t1, lbl); diff --git a/arch/mips/kernel/pm.c b/arch/mips/kernel/pm.c index fefdf39d3df3..dc814892133c 100644 --- a/arch/mips/kernel/pm.c +++ b/arch/mips/kernel/pm.c @@ -56,7 +56,7 @@ static void mips_cpu_restore(void) write_c0_userlocal(current_thread_info()->tp_value); /* Restore watch registers */ - __restore_watch(); + __restore_watch(current); } /** diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 298b2b773d12..97dc01b03631 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -114,6 +114,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_has_smartmips) seq_printf(m, "%s", " smartmips"); if (cpu_has_dsp) seq_printf(m, "%s", " dsp"); if (cpu_has_dsp2) seq_printf(m, "%s", " dsp2"); + if (cpu_has_dsp3) seq_printf(m, "%s", " dsp3"); if (cpu_has_mipsmt) seq_printf(m, "%s", " mt"); if (cpu_has_mmips) seq_printf(m, "%s", " micromips"); if (cpu_has_vz) seq_printf(m, "%s", " vz"); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 92880cee449e..a6b3dc54260a 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -77,10 +77,6 @@ void exit_thread(void) { } -void flush_thread(void) -{ -} - int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { /* @@ -455,7 +451,7 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page, *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) { regs = (struct pt_regs *)*sp; pc = regs->cp0_epc; - if (__kernel_text_address(pc)) { + if (!user_mode(regs) && __kernel_text_address(pc)) { *sp = regs->regs[29]; *ra = regs->regs[31]; return pc; @@ -580,11 +576,19 @@ int mips_get_process_fp_mode(struct task_struct *task) return value; } +static void prepare_for_fp_mode_switch(void *info) +{ + struct mm_struct *mm = info; + + if (current->mm == mm) + lose_fpu(1); +} + int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) { const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE; - unsigned long switch_count; struct task_struct *t; + int max_users; /* Check the value is valid */ if (value & ~known_bits) @@ -601,6 +605,9 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) if (!(value & PR_FP_MODE_FR) && cpu_has_fpu && cpu_has_mips_r6) return -EOPNOTSUPP; + /* Proceed with the mode switch */ + preempt_disable(); + /* Save FP & vector context, then disable FPU & MSA */ if (task->signal == current->signal) lose_fpu(1); @@ -610,31 +617,17 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) smp_mb__after_atomic(); /* - * If there are multiple online CPUs then wait until all threads whose - * FP mode is about to change have been context switched. This approach - * allows us to only worry about whether an FP mode switch is in - * progress when FP is first used in a tasks time slice. Pretty much all - * of the mode switch overhead can thus be confined to cases where mode - * switches are actually occurring. That is, to here. However for the - * thread performing the mode switch it may take a while... + * If there are multiple online CPUs then force any which are running + * threads in this process to lose their FPU context, which they can't + * regain until fp_mode_switching is cleared later. */ if (num_online_cpus() > 1) { - spin_lock_irq(&task->sighand->siglock); - - for_each_thread(task, t) { - if (t == current) - continue; - - switch_count = t->nvcsw + t->nivcsw; + /* No need to send an IPI for the local CPU */ + max_users = (task->mm == current->mm) ? 1 : 0; - do { - spin_unlock_irq(&task->sighand->siglock); - cond_resched(); - spin_lock_irq(&task->sighand->siglock); - } while ((t->nvcsw + t->nivcsw) == switch_count); - } - - spin_unlock_irq(&task->sighand->siglock); + if (atomic_read(¤t->mm->mm_users) > max_users) + smp_call_function(prepare_for_fp_mode_switch, + (void *)current->mm, 1); } /* @@ -659,6 +652,7 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) /* Allow threads to use FP again */ atomic_set(&task->mm->context.fp_mode_switching, 0); + preempt_enable(); return 0; } diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index a5279b2f3198..0dcf69194473 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -57,8 +57,7 @@ static void init_fp_ctx(struct task_struct *target) /* Begin with data registers set to all 1s... */ memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr)); - /* ...and FCSR zeroed */ - target->thread.fpu.fcr31 = 0; + /* FCSR has been preset by `mips_set_personality_nan'. */ /* * Record that the target has "used" math, such that the context @@ -80,6 +79,22 @@ void ptrace_disable(struct task_struct *child) } /* + * Poke at FCSR according to its mask. Don't set the cause bits as + * this is currently not handled correctly in FP context restoration + * and will cause an oops if a corresponding enable bit is set. + */ +static void ptrace_setfcr31(struct task_struct *child, u32 value) +{ + u32 fcr31; + u32 mask; + + value &= ~FPU_CSR_ALL_X; + fcr31 = child->thread.fpu.fcr31; + mask = boot_cpu_data.fpu_msk31; + child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); +} + +/* * Read a general register set. We always use the 64-bit format, even * for 32-bit kernels and for 32-bit processes on a 64-bit kernel. * Registers are sign extended to fill the available space. @@ -159,9 +174,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) { union fpureg *fregs; u64 fpr_val; - u32 fcr31; u32 value; - u32 mask; int i; if (!access_ok(VERIFY_READ, data, 33 * 8)) @@ -176,9 +189,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) } __get_user(value, data + 64); - fcr31 = child->thread.fpu.fcr31; - mask = boot_cpu_data.fpu_msk31; - child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask); + ptrace_setfcr31(child, value); /* FIR may not be written. */ @@ -210,7 +221,8 @@ int ptrace_get_watch_regs(struct task_struct *child, for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) { __put_user(child->thread.watch.mips3264.watchlo[i], &addr->WATCH_STYLE.watchlo[i]); - __put_user(child->thread.watch.mips3264.watchhi[i] & 0xfff, + __put_user(child->thread.watch.mips3264.watchhi[i] & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW), &addr->WATCH_STYLE.watchhi[i]); __put_user(boot_cpu_data.watch_reg_masks[i], &addr->WATCH_STYLE.watch_masks[i]); @@ -252,12 +264,12 @@ int ptrace_set_watch_regs(struct task_struct *child, } #endif __get_user(ht[i], &addr->WATCH_STYLE.watchhi[i]); - if (ht[i] & ~0xff8) + if (ht[i] & ~MIPS_WATCHHI_MASK) return -EINVAL; } /* Install them. */ for (i = 0; i < boot_cpu_data.watch_reg_use_cnt; i++) { - if (lt[i] & 7) + if (lt[i] & MIPS_WATCHLO_IRW) watch_active = 1; child->thread.watch.mips3264.watchlo[i] = lt[i]; /* Set the G bit. */ @@ -805,7 +817,7 @@ long arch_ptrace(struct task_struct *child, long request, break; #endif case FPC_CSR: - child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X; + ptrace_setfcr31(child, data); break; case DSP_BASE ... DSP_BASE + 5: { dspreg_t *dregs; diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 17732f876eff..56d86b09c917 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -244,17 +244,17 @@ LEAF(\name) .set push .set noat #ifdef CONFIG_64BIT - copy_u_d \wr, 1 + copy_s_d \wr, 1 EX sd $1, \off(\base) #elif defined(CONFIG_CPU_LITTLE_ENDIAN) - copy_u_w \wr, 2 + copy_s_w \wr, 2 EX sw $1, \off(\base) - copy_u_w \wr, 3 + copy_s_w \wr, 3 EX sw $1, (\off+4)(\base) #else /* CONFIG_CPU_BIG_ENDIAN */ - copy_u_w \wr, 2 + copy_s_w \wr, 2 EX sw $1, (\off+4)(\base) - copy_u_w \wr, 3 + copy_s_w \wr, 3 EX sw $1, \off(\base) #endif .set pop diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 92cd0516ecf5..2f0a3b223c97 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -15,7 +15,6 @@ #include <asm/fpregdef.h> #include <asm/mipsregs.h> #include <asm/asm-offsets.h> -#include <asm/pgtable-bits.h> #include <asm/regdef.h> #include <asm/stackframe.h> #include <asm/thread_info.h> diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c new file mode 100644 index 000000000000..ca1cc30c0891 --- /dev/null +++ b/arch/mips/kernel/relocate.c @@ -0,0 +1,386 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Support for Kernel relocation at boot time + * + * Copyright (C) 2015, Imagination Technologies Ltd. + * Authors: Matt Redfearn (matt.redfearn@imgtec.com) + */ +#include <asm/bootinfo.h> +#include <asm/cacheflush.h> +#include <asm/fw/fw.h> +#include <asm/sections.h> +#include <asm/setup.h> +#include <asm/timex.h> +#include <linux/elf.h> +#include <linux/kernel.h> +#include <linux/libfdt.h> +#include <linux/of_fdt.h> +#include <linux/sched.h> +#include <linux/start_kernel.h> +#include <linux/string.h> +#include <linux/printk.h> + +#define RELOCATED(x) ((void *)((long)x + offset)) + +extern u32 _relocation_start[]; /* End kernel image / start relocation table */ +extern u32 _relocation_end[]; /* End relocation table */ + +extern long __start___ex_table; /* Start exception table */ +extern long __stop___ex_table; /* End exception table */ + +static inline u32 __init get_synci_step(void) +{ + u32 res; + + __asm__("rdhwr %0, $1" : "=r" (res)); + + return res; +} + +static void __init sync_icache(void *kbase, unsigned long kernel_length) +{ + void *kend = kbase + kernel_length; + u32 step = get_synci_step(); + + do { + __asm__ __volatile__( + "synci 0(%0)" + : /* no output */ + : "r" (kbase)); + + kbase += step; + } while (kbase < kend); + + /* Completion barrier */ + __sync(); +} + +static int __init apply_r_mips_64_rel(u32 *loc_orig, u32 *loc_new, long offset) +{ + *(u64 *)loc_new += offset; + + return 0; +} + +static int __init apply_r_mips_32_rel(u32 *loc_orig, u32 *loc_new, long offset) +{ + *loc_new += offset; + + return 0; +} + +static int __init apply_r_mips_26_rel(u32 *loc_orig, u32 *loc_new, long offset) +{ + unsigned long target_addr = (*loc_orig) & 0x03ffffff; + + if (offset % 4) { + pr_err("Dangerous R_MIPS_26 REL relocation\n"); + return -ENOEXEC; + } + + /* Original target address */ + target_addr <<= 2; + target_addr += (unsigned long)loc_orig & ~0x03ffffff; + + /* Get the new target address */ + target_addr += offset; + + if ((target_addr & 0xf0000000) != ((unsigned long)loc_new & 0xf0000000)) { + pr_err("R_MIPS_26 REL relocation overflow\n"); + return -ENOEXEC; + } + + target_addr -= (unsigned long)loc_new & ~0x03ffffff; + target_addr >>= 2; + + *loc_new = (*loc_new & ~0x03ffffff) | (target_addr & 0x03ffffff); + + return 0; +} + + +static int __init apply_r_mips_hi16_rel(u32 *loc_orig, u32 *loc_new, long offset) +{ + unsigned long insn = *loc_orig; + unsigned long target = (insn & 0xffff) << 16; /* high 16bits of target */ + + target += offset; + + *loc_new = (insn & ~0xffff) | ((target >> 16) & 0xffff); + return 0; +} + +static int (*reloc_handlers_rel[]) (u32 *, u32 *, long) __initdata = { + [R_MIPS_64] = apply_r_mips_64_rel, + [R_MIPS_32] = apply_r_mips_32_rel, + [R_MIPS_26] = apply_r_mips_26_rel, + [R_MIPS_HI16] = apply_r_mips_hi16_rel, +}; + +int __init do_relocations(void *kbase_old, void *kbase_new, long offset) +{ + u32 *r; + u32 *loc_orig; + u32 *loc_new; + int type; + int res; + + for (r = _relocation_start; r < _relocation_end; r++) { + /* Sentinel for last relocation */ + if (*r == 0) + break; + + type = (*r >> 24) & 0xff; + loc_orig = (void *)(kbase_old + ((*r & 0x00ffffff) << 2)); + loc_new = RELOCATED(loc_orig); + + if (reloc_handlers_rel[type] == NULL) { + /* Unsupported relocation */ + pr_err("Unhandled relocation type %d at 0x%pK\n", + type, loc_orig); + return -ENOEXEC; + } + + res = reloc_handlers_rel[type](loc_orig, loc_new, offset); + if (res) + return res; + } + + return 0; +} + +/* + * The exception table is filled in by the relocs tool after vmlinux is linked. + * It must be relocated separately since there will not be any relocation + * information for it filled in by the linker. + */ +static int __init relocate_exception_table(long offset) +{ + unsigned long *etable_start, *etable_end, *e; + + etable_start = RELOCATED(&__start___ex_table); + etable_end = RELOCATED(&__stop___ex_table); + + for (e = etable_start; e < etable_end; e++) + *e += offset; + + return 0; +} + +#ifdef CONFIG_RANDOMIZE_BASE + +static inline __init unsigned long rotate_xor(unsigned long hash, + const void *area, size_t size) +{ + size_t i; + unsigned long *ptr = (unsigned long *)area; + + for (i = 0; i < size / sizeof(hash); i++) { + /* Rotate by odd number of bits and XOR. */ + hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7); + hash ^= ptr[i]; + } + + return hash; +} + +static inline __init unsigned long get_random_boot(void) +{ + unsigned long entropy = random_get_entropy(); + unsigned long hash = 0; + + /* Attempt to create a simple but unpredictable starting entropy. */ + hash = rotate_xor(hash, linux_banner, strlen(linux_banner)); + + /* Add in any runtime entropy we can get */ + hash = rotate_xor(hash, &entropy, sizeof(entropy)); + +#if defined(CONFIG_USE_OF) + /* Get any additional entropy passed in device tree */ + { + int node, len; + u64 *prop; + + node = fdt_path_offset(initial_boot_params, "/chosen"); + if (node >= 0) { + prop = fdt_getprop_w(initial_boot_params, node, + "kaslr-seed", &len); + if (prop && (len == sizeof(u64))) + hash = rotate_xor(hash, prop, sizeof(*prop)); + } + } +#endif /* CONFIG_USE_OF */ + + return hash; +} + +static inline __init bool kaslr_disabled(void) +{ + char *str; + +#if defined(CONFIG_CMDLINE_BOOL) + const char *builtin_cmdline = CONFIG_CMDLINE; + + str = strstr(builtin_cmdline, "nokaslr"); + if (str == builtin_cmdline || + (str > builtin_cmdline && *(str - 1) == ' ')) + return true; +#endif + str = strstr(arcs_cmdline, "nokaslr"); + if (str == arcs_cmdline || (str > arcs_cmdline && *(str - 1) == ' ')) + return true; + + return false; +} + +static inline void __init *determine_relocation_address(void) +{ + /* Choose a new address for the kernel */ + unsigned long kernel_length; + void *dest = &_text; + unsigned long offset; + + if (kaslr_disabled()) + return dest; + + kernel_length = (long)_end - (long)(&_text); + + offset = get_random_boot() << 16; + offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1); + if (offset < kernel_length) + offset += ALIGN(kernel_length, 0xffff); + + return RELOCATED(dest); +} + +#else + +static inline void __init *determine_relocation_address(void) +{ + /* + * Choose a new address for the kernel + * For now we'll hard code the destination + */ + return (void *)0xffffffff81000000; +} + +#endif + +static inline int __init relocation_addr_valid(void *loc_new) +{ + if ((unsigned long)loc_new & 0x0000ffff) { + /* Inappropriately aligned new location */ + return 0; + } + if ((unsigned long)loc_new < (unsigned long)&_end) { + /* New location overlaps original kernel */ + return 0; + } + return 1; +} + +void *__init relocate_kernel(void) +{ + void *loc_new; + unsigned long kernel_length; + unsigned long bss_length; + long offset = 0; + int res = 1; + /* Default to original kernel entry point */ + void *kernel_entry = start_kernel; + + /* Get the command line */ + fw_init_cmdline(); +#if defined(CONFIG_USE_OF) + /* Deal with the device tree */ + early_init_dt_scan(plat_get_fdt()); + if (boot_command_line[0]) { + /* Boot command line was passed in device tree */ + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); + } +#endif /* CONFIG_USE_OF */ + + kernel_length = (long)(&_relocation_start) - (long)(&_text); + bss_length = (long)&__bss_stop - (long)&__bss_start; + + loc_new = determine_relocation_address(); + + /* Sanity check relocation address */ + if (relocation_addr_valid(loc_new)) + offset = (unsigned long)loc_new - (unsigned long)(&_text); + + /* Reset the command line now so we don't end up with a duplicate */ + arcs_cmdline[0] = '\0'; + + if (offset) { + /* Copy the kernel to it's new location */ + memcpy(loc_new, &_text, kernel_length); + + /* Perform relocations on the new kernel */ + res = do_relocations(&_text, loc_new, offset); + if (res < 0) + goto out; + + /* Sync the caches ready for execution of new kernel */ + sync_icache(loc_new, kernel_length); + + res = relocate_exception_table(offset); + if (res < 0) + goto out; + + /* + * The original .bss has already been cleared, and + * some variables such as command line parameters + * stored to it so make a copy in the new location. + */ + memcpy(RELOCATED(&__bss_start), &__bss_start, bss_length); + + /* The current thread is now within the relocated image */ + __current_thread_info = RELOCATED(&init_thread_union); + + /* Return the new kernel's entry point */ + kernel_entry = RELOCATED(start_kernel); + } +out: + return kernel_entry; +} + +/* + * Show relocation information on panic. + */ +void show_kernel_relocation(const char *level) +{ + unsigned long offset; + + offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS); + + if (IS_ENABLED(CONFIG_RELOCATABLE) && offset > 0) { + printk(level); + pr_cont("Kernel relocated by 0x%pK\n", (void *)offset); + pr_cont(" .text @ 0x%pK\n", _text); + pr_cont(" .data @ 0x%pK\n", _sdata); + pr_cont(" .bss @ 0x%pK\n", __bss_start); + } +} + +static int kernel_location_notifier_fn(struct notifier_block *self, + unsigned long v, void *p) +{ + show_kernel_relocation(KERN_EMERG); + return NOTIFY_DONE; +} + +static struct notifier_block kernel_location_notifier = { + .notifier_call = kernel_location_notifier_fn +}; + +static int __init register_kernel_offset_dumper(void) +{ + atomic_notifier_chain_register(&panic_notifier_list, + &kernel_location_notifier); + return 0; +} +__initcall(register_kernel_offset_dumper); diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index d01fe53a6638..c8e43e0c4066 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -35,7 +35,6 @@ NESTED(handle_sys, PT_SIZE, sp) lw t1, PT_EPC(sp) # skip syscall on return - subu v0, v0, __NR_O32_Linux # check syscall number addiu t1, 4 # skip to next instruction sw t1, PT_EPC(sp) @@ -89,6 +88,7 @@ loads_done: and t0, t1 bnez t0, syscall_trace_entry # -> yes syscall_common: + subu v0, v0, __NR_O32_Linux # check syscall number sltiu t0, v0, __NR_O32_Linux_syscalls + 1 beqz t0, illegal_syscall @@ -118,24 +118,23 @@ o32_syscall_exit: syscall_trace_entry: SAVE_STATIC - move s0, v0 move a0, sp /* * syscall number is in v0 unless we called syscall(__NR_###) * where the real syscall number is in a0 */ - addiu a1, v0, __NR_O32_Linux - bnez v0, 1f /* __NR_syscall at offset 0 */ + move a1, v0 + subu t2, v0, __NR_O32_Linux + bnez t2, 1f /* __NR_syscall at offset 0 */ lw a1, PT_R4(sp) 1: jal syscall_trace_enter bltz v0, 1f # seccomp failed? Skip syscall - move v0, s0 # restore syscall - RESTORE_STATIC + lw v0, PT_R2(sp) # Restore syscall (maybe modified) lw a0, PT_R4(sp) # Restore argument registers lw a1, PT_R5(sp) lw a2, PT_R6(sp) diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 6b73ecc02597..e6ede125059f 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -82,15 +82,14 @@ n64_syscall_exit: syscall_trace_entry: SAVE_STATIC - move s0, v0 move a0, sp move a1, v0 jal syscall_trace_enter bltz v0, 1f # seccomp failed? Skip syscall - move v0, s0 RESTORE_STATIC + ld v0, PT_R2(sp) # Restore syscall (maybe modified) ld a0, PT_R4(sp) # Restore argument registers ld a1, PT_R5(sp) ld a2, PT_R6(sp) diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 71f99d5f7a06..9c0b387d6427 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -42,9 +42,6 @@ NESTED(handle_sysn32, PT_SIZE, sp) #endif beqz t0, not_n32_scall - dsll t0, v0, 3 # offset into table - ld t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0) - sd a3, PT_R26(sp) # save a3 for syscall restarting li t1, _TIF_WORK_SYSCALL_ENTRY @@ -53,6 +50,9 @@ NESTED(handle_sysn32, PT_SIZE, sp) bnez t0, n32_syscall_trace_entry syscall_common: + dsll t0, v0, 3 # offset into table + ld t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0) + jalr t2 # Do The Real Thing (TM) li t0, -EMAXERRNO - 1 # error? @@ -71,21 +71,25 @@ syscall_common: n32_syscall_trace_entry: SAVE_STATIC - move s0, t2 move a0, sp move a1, v0 jal syscall_trace_enter bltz v0, 1f # seccomp failed? Skip syscall - move t2, s0 RESTORE_STATIC + ld v0, PT_R2(sp) # Restore syscall (maybe modified) ld a0, PT_R4(sp) # Restore argument registers ld a1, PT_R5(sp) ld a2, PT_R6(sp) ld a3, PT_R7(sp) ld a4, PT_R8(sp) ld a5, PT_R9(sp) + + dsubu t2, v0, __NR_N32_Linux # check (new) syscall number + sltiu t0, t2, __NR_N32_Linux_syscalls + 1 + beqz t0, not_n32_scall + j syscall_common 1: j syscall_exit diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 91b43eea2d5a..f4f28b1580de 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -52,9 +52,6 @@ NESTED(handle_sys, PT_SIZE, sp) sll a2, a2, 0 sll a3, a3, 0 - dsll t0, v0, 3 # offset into table - ld t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0) - sd a3, PT_R26(sp) # save a3 for syscall restarting /* @@ -88,6 +85,9 @@ loads_done: bnez t0, trace_a_syscall syscall_common: + dsll t0, v0, 3 # offset into table + ld t2, (sys32_call_table - (__NR_O32_Linux * 8))(t0) + jalr t2 # Do The Real Thing (TM) li t0, -EMAXERRNO - 1 # error? @@ -112,7 +112,6 @@ trace_a_syscall: sd a6, PT_R10(sp) sd a7, PT_R11(sp) # For indirect syscalls - move s0, t2 # Save syscall pointer move a0, sp /* * absolute syscall number is in v0 unless we called syscall(__NR_###) @@ -133,8 +132,8 @@ trace_a_syscall: bltz v0, 1f # seccomp failed? Skip syscall - move t2, s0 RESTORE_STATIC + ld v0, PT_R2(sp) # Restore syscall (maybe modified) ld a0, PT_R4(sp) # Restore argument registers ld a1, PT_R5(sp) ld a2, PT_R6(sp) @@ -143,6 +142,11 @@ trace_a_syscall: ld a5, PT_R9(sp) ld a6, PT_R10(sp) ld a7, PT_R11(sp) # For indirect syscalls + + dsubu t0, v0, __NR_O32_Linux # check (new) syscall number + sltiu t0, t0, __NR_O32_Linux_syscalls + 1 + beqz t0, not_o32_scall + j syscall_common 1: j syscall_exit diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 4f607341a793..ef408a03e818 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -26,6 +26,7 @@ #include <linux/sizes.h> #include <linux/device.h> #include <linux/dma-contiguous.h> +#include <linux/decompress/generic.h> #include <asm/addrspace.h> #include <asm/bootinfo.h> @@ -52,13 +53,6 @@ struct screen_info screen_info; #endif /* - * Despite it's name this variable is even if we don't have PCI - */ -unsigned int PCI_DMA_BUS_IS_PHYS; - -EXPORT_SYMBOL(PCI_DMA_BUS_IS_PHYS); - -/* * Setup information * * These are initialized so they are in the .data section @@ -250,6 +244,35 @@ disable: return 0; } +/* In some conditions (e.g. big endian bootloader with a little endian + kernel), the initrd might appear byte swapped. Try to detect this and + byte swap it if needed. */ +static void __init maybe_bswap_initrd(void) +{ +#if defined(CONFIG_CPU_CAVIUM_OCTEON) + u64 buf; + + /* Check for CPIO signature */ + if (!memcmp((void *)initrd_start, "070701", 6)) + return; + + /* Check for compressed initrd */ + if (decompress_method((unsigned char *)initrd_start, 8, NULL)) + return; + + /* Try again with a byte swapped header */ + buf = swab64p((u64 *)initrd_start); + if (!memcmp(&buf, "070701", 6) || + decompress_method((unsigned char *)(&buf), 8, NULL)) { + unsigned long i; + + pr_info("Byteswapped initrd detected\n"); + for (i = initrd_start; i < ALIGN(initrd_end, 8); i += 8) + swab64s((u64 *)i); + } +#endif +} + static void __init finalize_initrd(void) { unsigned long size = initrd_end - initrd_start; @@ -263,6 +286,8 @@ static void __init finalize_initrd(void) goto disable; } + maybe_bswap_initrd(); + reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT); initrd_below_start_ok = 1; @@ -469,6 +494,29 @@ static void __init bootmem_init(void) */ reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT); +#ifdef CONFIG_RELOCATABLE + /* + * The kernel reserves all memory below its _end symbol as bootmem, + * but the kernel may now be at a much higher address. The memory + * between the original and new locations may be returned to the system. + */ + if (__pa_symbol(_text) > __pa_symbol(VMLINUX_LOAD_ADDRESS)) { + unsigned long offset; + extern void show_kernel_relocation(const char *level); + + offset = __pa_symbol(_text) - __pa_symbol(VMLINUX_LOAD_ADDRESS); + free_bootmem(__pa_symbol(VMLINUX_LOAD_ADDRESS), offset); + +#if defined(CONFIG_DEBUG_KERNEL) && defined(CONFIG_DEBUG_INFO) + /* + * This information is necessary when debugging the kernel + * But is a security vulnerability otherwise! + */ + show_kernel_relocation(KERN_INFO); +#endif + } +#endif + /* * Reserve initrd memory if needed. */ @@ -624,6 +672,8 @@ static void __init request_crashkernel(struct resource *res) #define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER) #define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) #define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND) +#define BUILTIN_EXTEND_WITH_PROM \ + IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND) static void __init arch_mem_init(char **cmdline_p) { @@ -657,15 +707,23 @@ static void __init arch_mem_init(char **cmdline_p) strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); if (EXTEND_WITH_PROM && arcs_cmdline[0]) { - strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + if (boot_command_line[0]) + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); } #if defined(CONFIG_CMDLINE_BOOL) if (builtin_cmdline[0]) { - strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + if (boot_command_line[0]) + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); } + + if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) { + if (boot_command_line[0]) + strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); + strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE); + } #endif #endif strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); @@ -706,6 +764,9 @@ static void __init arch_mem_init(char **cmdline_p) for_each_memblock(reserved, reg) if (reg->size != 0) reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT); + + reserve_bootmem_region(__pa_symbol(&__nosave_begin), + __pa_symbol(&__nosave_end)); /* Reserve for hibernation */ } static void __init resource_init(void) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index bf792e2839a6..ab042291fbfd 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -195,6 +195,9 @@ static int restore_msa_extcontext(void __user *buf, unsigned int size) unsigned int csr; int i, err; + if (!config_enabled(CONFIG_CPU_HAS_MSA)) + return SIGSYS; + if (size != sizeof(*msa)) return -EINVAL; @@ -398,8 +401,8 @@ int protected_restore_fp_context(void __user *sc) } fp_done: - if (used & USED_EXTCONTEXT) - err |= restore_extcontext(sc_to_extcontext(sc)); + if (!err && (used & USED_EXTCONTEXT)) + err = restore_extcontext(sc_to_extcontext(sc)); return err ?: sig; } @@ -798,7 +801,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) regs->regs[0] = 0; /* Don't deal with this again. */ } - if (sig_uses_siginfo(&ksig->ka)) + if (sig_uses_siginfo(&ksig->ka, abi)) ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn, ksig, regs, oldset); else diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 4909639aa35b..78c8349d151c 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -227,6 +227,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_int, &to->si_int); break; + case __SI_SYS >> 16: + err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr, + sizeof(compat_uptr_t)); + err |= __put_user(from->si_syscall, &to->si_syscall); + err |= __put_user(from->si_arch, &to->si_arch); + break; } } return err; diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 78cf8c2f1de0..e02addc0307f 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -243,6 +243,7 @@ static void bmips_init_secondary(void) break; case CPU_BMIPS5000: write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); + current_cpu_data.core = (read_c0_brcm_config() >> 25) & 3; break; } } @@ -565,3 +566,90 @@ asmlinkage void __weak plat_wired_tlb_setup(void) * once the wired entries are present. */ } + +void __init bmips_cpu_setup(void) +{ + void __iomem __maybe_unused *cbr = BMIPS_GET_CBR(); + u32 __maybe_unused cfg; + + switch (current_cpu_type()) { + case CPU_BMIPS3300: + /* Set BIU to async mode */ + set_c0_brcm_bus_pll(BIT(22)); + __sync(); + + /* put the BIU back in sync mode */ + clear_c0_brcm_bus_pll(BIT(22)); + + /* clear BHTD to enable branch history table */ + clear_c0_brcm_reset(BIT(16)); + + /* Flush and enable RAC */ + cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG); + __raw_writel(cfg | 0x100, BMIPS_RAC_CONFIG); + __raw_readl(cbr + BMIPS_RAC_CONFIG); + + cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG); + __raw_writel(cfg | 0xf, BMIPS_RAC_CONFIG); + __raw_readl(cbr + BMIPS_RAC_CONFIG); + + cfg = __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE); + __raw_writel(cfg | 0x0fff0000, cbr + BMIPS_RAC_ADDRESS_RANGE); + __raw_readl(cbr + BMIPS_RAC_ADDRESS_RANGE); + break; + + case CPU_BMIPS4380: + /* CBG workaround for early BMIPS4380 CPUs */ + switch (read_c0_prid()) { + case 0x2a040: + case 0x2a042: + case 0x2a044: + case 0x2a060: + cfg = __raw_readl(cbr + BMIPS_L2_CONFIG); + __raw_writel(cfg & ~0x07000000, cbr + BMIPS_L2_CONFIG); + __raw_readl(cbr + BMIPS_L2_CONFIG); + } + + /* clear BHTD to enable branch history table */ + clear_c0_brcm_config_0(BIT(21)); + + /* XI/ROTR enable */ + set_c0_brcm_config_0(BIT(23)); + set_c0_brcm_cmt_ctrl(BIT(15)); + break; + + case CPU_BMIPS5000: + /* enable RDHWR, BRDHWR */ + set_c0_brcm_config(BIT(17) | BIT(21)); + + /* Disable JTB */ + __asm__ __volatile__( + " .set noreorder\n" + " li $8, 0x5a455048\n" + " .word 0x4088b00f\n" /* mtc0 t0, $22, 15 */ + " .word 0x4008b008\n" /* mfc0 t0, $22, 8 */ + " li $9, 0x00008000\n" + " or $8, $8, $9\n" + " .word 0x4088b008\n" /* mtc0 t0, $22, 8 */ + " sync\n" + " li $8, 0x0\n" + " .word 0x4088b00f\n" /* mtc0 t0, $22, 15 */ + " .set reorder\n" + : : : "$8", "$9"); + + /* XI enable */ + set_c0_brcm_config(BIT(27)); + + /* enable MIPS32R2 ROR instruction for XI TLB handlers */ + __asm__ __volatile__( + " li $8, 0x5a455048\n" + " .word 0x4088b00f\n" /* mtc0 $8, $22, 15 */ + " nop; nop; nop\n" + " .word 0x4008b008\n" /* mfc0 $8, $22, 8 */ + " lui $9, 0x0100\n" + " or $8, $9\n" + " .word 0x4088b008\n" /* mtc0 $8, $22, 8 */ + : : : "$8", "$9"); + break; + } +} diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 253e1409338c..1061bd2e7e9c 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -27,15 +27,27 @@ #include <asm/time.h> #include <asm/uasm.h> +static bool threads_disabled; static DECLARE_BITMAP(core_power, NR_CPUS); struct core_boot_config *mips_cps_core_bootcfg; +static int __init setup_nothreads(char *s) +{ + threads_disabled = true; + return 0; +} +early_param("nothreads", setup_nothreads); + static unsigned core_vpe_count(unsigned core) { unsigned cfg; - if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) + if (threads_disabled) + return 1; + + if ((!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt) + && (!config_enabled(CONFIG_CPU_MIPSR6) || !cpu_has_vp)) return 1; mips_cm_lock_other(core, 0); @@ -47,11 +59,12 @@ static unsigned core_vpe_count(unsigned core) static void __init cps_smp_setup(void) { unsigned int ncores, nvpes, core_vpes; + unsigned long core_entry; int c, v; /* Detect & record VPE topology */ ncores = mips_cm_numcores(); - pr_info("VPE topology "); + pr_info("%s topology ", cpu_has_mips_r6 ? "VP" : "VPE"); for (c = nvpes = 0; c < ncores; c++) { core_vpes = core_vpe_count(c); pr_cont("%c%u", c ? ',' : '{', core_vpes); @@ -62,7 +75,7 @@ static void __init cps_smp_setup(void) for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) { cpu_data[nvpes + v].core = c; -#ifdef CONFIG_MIPS_MT_SMP +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6) cpu_data[nvpes + v].vpe_id = v; #endif } @@ -91,6 +104,11 @@ static void __init cps_smp_setup(void) /* Make core 0 coherent with everything */ write_gcr_cl_coherence(0xff); + if (mips_cm_revision() >= CM_REV_CM3) { + core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry); + write_gcr_bev_base(core_entry); + } + #ifdef CONFIG_MIPS_MT_FPAFF /* If we have an FPU, enroll ourselves in the FPU-full mask */ if (cpu_has_fpu) @@ -213,6 +231,18 @@ static void boot_core(unsigned core) if (mips_cpc_present()) { /* Reset the core */ mips_cpc_lock_other(core); + + if (mips_cm_revision() >= CM_REV_CM3) { + /* Run VP0 following the reset */ + write_cpc_co_vp_run(0x1); + + /* + * Ensure that the VP_RUN register is written before the + * core leaves reset. + */ + wmb(); + } + write_cpc_co_cmd(CPC_Cx_CMD_RESET); timeout = 100; @@ -250,7 +280,10 @@ static void boot_core(unsigned core) static void remote_vpe_boot(void *dummy) { - mips_cps_boot_vpes(); + unsigned core = current_cpu_data.core; + struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core]; + + mips_cps_boot_vpes(core_cfg, cpu_vpe_id(¤t_cpu_data)); } static void cps_boot_secondary(int cpu, struct task_struct *idle) @@ -259,6 +292,7 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]); struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core]; struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id]; + unsigned long core_entry; unsigned int remote; int err; @@ -276,6 +310,13 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) goto out; } + if (cpu_has_vp) { + mips_cm_lock_other(core, vpe_id); + core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry); + write_gcr_co_reset_base(core_entry); + mips_cm_unlock_other(); + } + if (core != current_cpu_data.core) { /* Boot a VPE on another powered up core */ for (remote = 0; remote < NR_CPUS; remote++) { @@ -293,10 +334,10 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle) goto out; } - BUG_ON(!cpu_has_mipsmt); + BUG_ON(!cpu_has_mipsmt && !cpu_has_vp); /* Boot a VPE on this core */ - mips_cps_boot_vpes(); + mips_cps_boot_vpes(core_cfg, vpe_id); out: preempt_enable(); } @@ -307,6 +348,17 @@ static void cps_init_secondary(void) if (cpu_has_mipsmt) dmt(); + if (mips_cm_revision() >= CM_REV_CM3) { + unsigned ident = gic_read_local_vp_id(); + + /* + * Ensure that our calculation of the VP ID matches up with + * what the GIC reports, otherwise we'll have configured + * interrupts incorrectly. + */ + BUG_ON(ident != mips_cm_vp_id(smp_processor_id())); + } + change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); } diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 27cb638f0824..f9d01e953acb 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -243,18 +243,6 @@ static int __init mips_smp_ipi_init(void) struct irq_domain *ipidomain; struct device_node *node; - /* - * In some cases like qemu-malta, it is desired to try SMP with - * a single core. Qemu-malta has no GIC, so an attempt to set any IPIs - * would cause a BUG_ON() to be triggered since there's no ipidomain. - * - * Since for a single core system IPIs aren't required really, skip the - * initialisation which should generally keep any such configurations - * happy and only fail hard when trying to truely run SMP. - */ - if (cpumask_weight(cpu_possible_mask) == 1) - return 0; - node = of_irq_find_parent(of_root); ipidomain = irq_find_matching_host(node, DOMAIN_BUS_IPI); @@ -266,7 +254,17 @@ static int __init mips_smp_ipi_init(void) if (node && !ipidomain) ipidomain = irq_find_matching_host(NULL, DOMAIN_BUS_IPI); - BUG_ON(!ipidomain); + /* + * There are systems which only use IPI domains some of the time, + * depending upon configuration we don't know until runtime. An + * example is Malta where we may compile in support for GIC & the + * MT ASE, but run on a system which has multiple VPEs in a single + * core and doesn't include a GIC. Until all IPI implementations + * have been converted to use IPI domains the best we can do here + * is to return & hope some other code sets up the IPIs. + */ + if (!ipidomain) + return 0; call_virq = irq_reserve_ipi(ipidomain, cpu_possible_mask); BUG_ON(!call_virq); diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c index 8489c88f9932..d6e6cf75114d 100644 --- a/arch/mips/kernel/spram.c +++ b/arch/mips/kernel/spram.c @@ -210,6 +210,7 @@ void spram_config(void) case CPU_P5600: case CPU_QEMU_GENERIC: case CPU_I6400: + case CPU_P6600: config0 = read_c0_config(); /* FIXME: addresses are Malta specific */ if (config0 & (1<<24)) { diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ae0c89d23ad7..4a1712b5abdf 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -145,7 +145,7 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs) if (!task) task = current; - if (raw_show_trace || !__kernel_text_address(pc)) { + if (raw_show_trace || user_mode(regs) || !__kernel_text_address(pc)) { show_raw_backtrace(sp); return; } @@ -399,11 +399,8 @@ void __noreturn die(const char *str, struct pt_regs *regs) if (in_interrupt()) panic("Fatal exception in interrupt"); - if (panic_on_oops) { - printk(KERN_EMERG "Fatal exception: panic in 5 seconds"); - ssleep(5); + if (panic_on_oops) panic("Fatal exception"); - } if (regs && kexec_should_crash(current)) crash_kexec(regs); @@ -1249,7 +1246,7 @@ static int enable_restore_fp_context(int msa) err = init_fpu(); if (msa && !err) { enable_msa(); - _init_msa_upper(); + init_msa_upper(); set_thread_flag(TIF_USEDMSA); set_thread_flag(TIF_MSA_CTX_LIVE); } @@ -1312,7 +1309,7 @@ static int enable_restore_fp_context(int msa) */ prior_msa = test_and_set_thread_flag(TIF_MSA_CTX_LIVE); if (!prior_msa && was_fpu_owner) { - _init_msa_upper(); + init_msa_upper(); goto out; } @@ -1329,7 +1326,7 @@ static int enable_restore_fp_context(int msa) * of each vector register such that it cannot see data left * behind by another task. */ - _init_msa_upper(); + init_msa_upper(); } else { /* We need to restore the vector context. */ restore_msa(current); @@ -1356,7 +1353,6 @@ asmlinkage void do_cpu(struct pt_regs *regs) unsigned long fcr31; unsigned int cpid; int status, err; - unsigned long __maybe_unused flags; int sig; prev_state = exception_enter(); @@ -1501,16 +1497,13 @@ asmlinkage void do_watch(struct pt_regs *regs) { siginfo_t info = { .si_signo = SIGTRAP, .si_code = TRAP_HWBKPT }; enum ctx_state prev_state; - u32 cause; prev_state = exception_enter(); /* * Clear WP (bit 22) bit of cause register so we don't loop * forever. */ - cause = read_c0_cause(); - cause &= ~(1 << 22); - write_c0_cause(cause); + clear_c0_cause(CAUSEF_WP); /* * If the current thread has the watch registers loaded, save @@ -1647,6 +1640,7 @@ static inline void parity_protection_init(void) case CPU_P5600: case CPU_QEMU_GENERIC: case CPU_I6400: + case CPU_P6600: { #define ERRCTL_PE 0x80000000 #define ERRCTL_L2P 0x00800000 @@ -1777,7 +1771,8 @@ asmlinkage void do_ftlb(void) /* For the moment, report the problem and hang. */ if ((cpu_has_mips_r2_r6) && - ((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS)) { + (((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS) || + ((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_LOONGSON))) { pr_err("FTLB error exception, cp0_ecc=0x%08x:\n", read_c0_ecc()); pr_err("cp0_errorepc == %0*lx\n", field, read_c0_errorepc()); @@ -2119,6 +2114,13 @@ void per_cpu_trap_init(bool is_boot_cpu) * o read IntCtl.IPFDC to determine the fast debug channel interrupt */ if (cpu_has_mips_r2_r6) { + /* + * We shouldn't trust a secondary core has a sane EBASE register + * so use the one calculated by the boot CPU. + */ + if (!is_boot_cpu) + write_c0_ebase(ebase); + cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7; cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7; @@ -2134,7 +2136,7 @@ void per_cpu_trap_init(bool is_boot_cpu) } if (!cpu_data[cpu].asid_cache) - cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; + cpu_data[cpu].asid_cache = asid_first_version(cpu); atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 5c62065cbf22..28b3af73a17b 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -1191,6 +1191,7 @@ static void emulate_load_store_insn(struct pt_regs *regs, case ldc1_op: case swc1_op: case sdc1_op: + case cop1x_op: die_if_kernel("Unaligned FP access in kernel code", regs); BUG_ON(!used_math()); diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 54d653ee17e1..a82c178d0bb9 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -136,6 +136,27 @@ SECTIONS #ifdef CONFIG_SMP PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT) #endif + +#ifdef CONFIG_RELOCATABLE + . = ALIGN(4); + + .data.reloc : { + _relocation_start = .; + /* + * Space for relocation table + * This needs to be filled so that the + * relocs tool can overwrite the content. + * An invalid value is left at the start of the + * section to abort relocation if the table + * has not been filled in. + */ + LONG(0xFFFFFFFF); + FILL(0); + . += CONFIG_RELOCATION_TABLE_SIZE - 4; + _relocation_end = .; + } +#endif + #ifdef CONFIG_MIPS_RAW_APPENDED_DTB __appended_dtb = .; /* leave space for appended DTB */ diff --git a/arch/mips/kernel/watch.c b/arch/mips/kernel/watch.c index 2a03abb5bd2c..19fcab7348b1 100644 --- a/arch/mips/kernel/watch.c +++ b/arch/mips/kernel/watch.c @@ -15,10 +15,9 @@ * Install the watch registers for the current thread. A maximum of * four registers are installed although the machine may have more. */ -void mips_install_watch_registers(void) +void mips_install_watch_registers(struct task_struct *t) { - struct mips3264_watch_reg_state *watches = - ¤t->thread.watch.mips3264; + struct mips3264_watch_reg_state *watches = &t->thread.watch.mips3264; switch (current_cpu_data.watch_reg_use_cnt) { default: BUG(); @@ -26,16 +25,20 @@ void mips_install_watch_registers(void) write_c0_watchlo3(watches->watchlo[3]); /* Write 1 to the I, R, and W bits to clear them, and 1 to G so all ASIDs are trapped. */ - write_c0_watchhi3(0x40000007 | watches->watchhi[3]); + write_c0_watchhi3(MIPS_WATCHHI_G | MIPS_WATCHHI_IRW | + watches->watchhi[3]); case 3: write_c0_watchlo2(watches->watchlo[2]); - write_c0_watchhi2(0x40000007 | watches->watchhi[2]); + write_c0_watchhi2(MIPS_WATCHHI_G | MIPS_WATCHHI_IRW | + watches->watchhi[2]); case 2: write_c0_watchlo1(watches->watchlo[1]); - write_c0_watchhi1(0x40000007 | watches->watchhi[1]); + write_c0_watchhi1(MIPS_WATCHHI_G | MIPS_WATCHHI_IRW | + watches->watchhi[1]); case 1: write_c0_watchlo0(watches->watchlo[0]); - write_c0_watchhi0(0x40000007 | watches->watchhi[0]); + write_c0_watchhi0(MIPS_WATCHHI_G | MIPS_WATCHHI_IRW | + watches->watchhi[0]); } } @@ -52,22 +55,26 @@ void mips_read_watch_registers(void) default: BUG(); case 4: - watches->watchhi[3] = (read_c0_watchhi3() & 0x0fff); + watches->watchhi[3] = (read_c0_watchhi3() & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW)); case 3: - watches->watchhi[2] = (read_c0_watchhi2() & 0x0fff); + watches->watchhi[2] = (read_c0_watchhi2() & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW)); case 2: - watches->watchhi[1] = (read_c0_watchhi1() & 0x0fff); + watches->watchhi[1] = (read_c0_watchhi1() & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW)); case 1: - watches->watchhi[0] = (read_c0_watchhi0() & 0x0fff); + watches->watchhi[0] = (read_c0_watchhi0() & + (MIPS_WATCHHI_MASK | MIPS_WATCHHI_IRW)); } if (current_cpu_data.watch_reg_use_cnt == 1 && - (watches->watchhi[0] & 7) == 0) { + (watches->watchhi[0] & MIPS_WATCHHI_IRW) == 0) { /* Pathological case of release 1 architecture that * doesn't set the condition bits. We assume that * since we got here, the watch condition was met and * signal that the conditions requested in watchlo * were met. */ - watches->watchhi[0] |= (watches->watchlo[0] & 7); + watches->watchhi[0] |= (watches->watchlo[0] & MIPS_WATCHHI_IRW); } } @@ -110,86 +117,86 @@ void mips_probe_watch_registers(struct cpuinfo_mips *c) * Check which of the I,R and W bits are supported, then * disable the register. */ - write_c0_watchlo0(7); + write_c0_watchlo0(MIPS_WATCHLO_IRW); back_to_back_c0_hazard(); t = read_c0_watchlo0(); write_c0_watchlo0(0); - c->watch_reg_masks[0] = t & 7; + c->watch_reg_masks[0] = t & MIPS_WATCHLO_IRW; /* Write the mask bits and read them back to determine which * can be used. */ c->watch_reg_count = 1; c->watch_reg_use_cnt = 1; t = read_c0_watchhi0(); - write_c0_watchhi0(t | 0xff8); + write_c0_watchhi0(t | MIPS_WATCHHI_MASK); back_to_back_c0_hazard(); t = read_c0_watchhi0(); - c->watch_reg_masks[0] |= (t & 0xff8); - if ((t & 0x80000000) == 0) + c->watch_reg_masks[0] |= (t & MIPS_WATCHHI_MASK); + if ((t & MIPS_WATCHHI_M) == 0) return; - write_c0_watchlo1(7); + write_c0_watchlo1(MIPS_WATCHLO_IRW); back_to_back_c0_hazard(); t = read_c0_watchlo1(); write_c0_watchlo1(0); - c->watch_reg_masks[1] = t & 7; + c->watch_reg_masks[1] = t & MIPS_WATCHLO_IRW; c->watch_reg_count = 2; c->watch_reg_use_cnt = 2; t = read_c0_watchhi1(); - write_c0_watchhi1(t | 0xff8); + write_c0_watchhi1(t | MIPS_WATCHHI_MASK); back_to_back_c0_hazard(); t = read_c0_watchhi1(); - c->watch_reg_masks[1] |= (t & 0xff8); - if ((t & 0x80000000) == 0) + c->watch_reg_masks[1] |= (t & MIPS_WATCHHI_MASK); + if ((t & MIPS_WATCHHI_M) == 0) return; - write_c0_watchlo2(7); + write_c0_watchlo2(MIPS_WATCHLO_IRW); back_to_back_c0_hazard(); t = read_c0_watchlo2(); write_c0_watchlo2(0); - c->watch_reg_masks[2] = t & 7; + c->watch_reg_masks[2] = t & MIPS_WATCHLO_IRW; c->watch_reg_count = 3; c->watch_reg_use_cnt = 3; t = read_c0_watchhi2(); - write_c0_watchhi2(t | 0xff8); + write_c0_watchhi2(t | MIPS_WATCHHI_MASK); back_to_back_c0_hazard(); t = read_c0_watchhi2(); - c->watch_reg_masks[2] |= (t & 0xff8); - if ((t & 0x80000000) == 0) + c->watch_reg_masks[2] |= (t & MIPS_WATCHHI_MASK); + if ((t & MIPS_WATCHHI_M) == 0) return; - write_c0_watchlo3(7); + write_c0_watchlo3(MIPS_WATCHLO_IRW); back_to_back_c0_hazard(); t = read_c0_watchlo3(); write_c0_watchlo3(0); - c->watch_reg_masks[3] = t & 7; + c->watch_reg_masks[3] = t & MIPS_WATCHLO_IRW; c->watch_reg_count = 4; c->watch_reg_use_cnt = 4; t = read_c0_watchhi3(); - write_c0_watchhi3(t | 0xff8); + write_c0_watchhi3(t | MIPS_WATCHHI_MASK); back_to_back_c0_hazard(); t = read_c0_watchhi3(); - c->watch_reg_masks[3] |= (t & 0xff8); - if ((t & 0x80000000) == 0) + c->watch_reg_masks[3] |= (t & MIPS_WATCHHI_MASK); + if ((t & MIPS_WATCHHI_M) == 0) return; /* We use at most 4, but probe and report up to 8. */ c->watch_reg_count = 5; t = read_c0_watchhi4(); - if ((t & 0x80000000) == 0) + if ((t & MIPS_WATCHHI_M) == 0) return; c->watch_reg_count = 6; t = read_c0_watchhi5(); - if ((t & 0x80000000) == 0) + if ((t & MIPS_WATCHHI_M) == 0) return; c->watch_reg_count = 7; t = read_c0_watchhi6(); - if ((t & 0x80000000) == 0) + if ((t & MIPS_WATCHHI_M) == 0) return; c->watch_reg_count = 8; diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index b37954cc880d..8e945e866a73 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c @@ -1068,15 +1068,15 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, kvm_read_c0_guest_ebase(cop0)); } else if (rd == MIPS_CP0_TLB_HI && sel == 0) { uint32_t nasid = - vcpu->arch.gprs[rt] & ASID_MASK; + vcpu->arch.gprs[rt] & KVM_ENTRYHI_ASID; if ((KSEGX(vcpu->arch.gprs[rt]) != CKSEG0) && ((kvm_read_c0_guest_entryhi(cop0) & - ASID_MASK) != nasid)) { + KVM_ENTRYHI_ASID) != nasid)) { kvm_debug("MTCz, change ASID from %#lx to %#lx\n", kvm_read_c0_guest_entryhi(cop0) - & ASID_MASK, + & KVM_ENTRYHI_ASID, vcpu->arch.gprs[rt] - & ASID_MASK); + & KVM_ENTRYHI_ASID); /* Blow away the shadow host TLBs */ kvm_mips_flush_host_tlb(1); @@ -1620,7 +1620,7 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, */ index = kvm_mips_guest_tlb_lookup(vcpu, (va & VPN2_MASK) | (kvm_read_c0_guest_entryhi - (cop0) & ASID_MASK)); + (cop0) & KVM_ENTRYHI_ASID)); if (index < 0) { vcpu->arch.host_cp0_entryhi = (va & VPN2_MASK); @@ -1786,7 +1786,7 @@ enum emulation_result kvm_mips_emulate_tlbmiss_ld(unsigned long cause, struct mips_coproc *cop0 = vcpu->arch.cop0; struct kvm_vcpu_arch *arch = &vcpu->arch; unsigned long entryhi = (vcpu->arch. host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { /* save old pc */ @@ -1833,7 +1833,7 @@ enum emulation_result kvm_mips_emulate_tlbinv_ld(unsigned long cause, struct kvm_vcpu_arch *arch = &vcpu->arch; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { /* save old pc */ @@ -1878,7 +1878,7 @@ enum emulation_result kvm_mips_emulate_tlbmiss_st(unsigned long cause, struct mips_coproc *cop0 = vcpu->arch.cop0; struct kvm_vcpu_arch *arch = &vcpu->arch; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { /* save old pc */ @@ -1922,7 +1922,7 @@ enum emulation_result kvm_mips_emulate_tlbinv_st(unsigned long cause, struct mips_coproc *cop0 = vcpu->arch.cop0; struct kvm_vcpu_arch *arch = &vcpu->arch; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { /* save old pc */ @@ -1967,7 +1967,7 @@ enum emulation_result kvm_mips_handle_tlbmod(unsigned long cause, uint32_t *opc, #ifdef DEBUG struct mips_coproc *cop0 = vcpu->arch.cop0; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); int index; /* If address not in the guest TLB, then we are in trouble */ @@ -1994,7 +1994,7 @@ enum emulation_result kvm_mips_emulate_tlbmod(unsigned long cause, { struct mips_coproc *cop0 = vcpu->arch.cop0; unsigned long entryhi = (vcpu->arch.host_cp0_badvaddr & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(cop0) & ASID_MASK); + (kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID); struct kvm_vcpu_arch *arch = &vcpu->arch; if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { @@ -2569,7 +2569,8 @@ enum emulation_result kvm_mips_handle_tlbmiss(unsigned long cause, */ index = kvm_mips_guest_tlb_lookup(vcpu, (va & VPN2_MASK) | - (kvm_read_c0_guest_entryhi(vcpu->arch.cop0) & ASID_MASK)); + (kvm_read_c0_guest_entryhi(vcpu->arch.cop0) & + KVM_ENTRYHI_ASID)); if (index < 0) { if (exccode == EXCCODE_TLBL) { er = kvm_mips_emulate_tlbmiss_ld(cause, opc, run, vcpu); diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S index 81687ab1b523..3ef03009de5f 100644 --- a/arch/mips/kvm/locore.S +++ b/arch/mips/kvm/locore.S @@ -32,7 +32,6 @@ EXPORT(x); /* Overload, Danger Will Robinson!! */ -#define PT_HOST_ASID PT_BVADDR #define PT_HOST_USERLOCAL PT_EPC #define CP0_DDATA_LO $28,3 @@ -49,45 +48,18 @@ * a1: vcpu */ .set noreorder - .set noat FEXPORT(__kvm_mips_vcpu_run) /* k0/k1 not being used in host kernel context */ INT_ADDIU k1, sp, -PT_SIZE - LONG_S $0, PT_R0(k1) - LONG_S $1, PT_R1(k1) - LONG_S $2, PT_R2(k1) - LONG_S $3, PT_R3(k1) - - LONG_S $4, PT_R4(k1) - LONG_S $5, PT_R5(k1) - LONG_S $6, PT_R6(k1) - LONG_S $7, PT_R7(k1) - - LONG_S $8, PT_R8(k1) - LONG_S $9, PT_R9(k1) - LONG_S $10, PT_R10(k1) - LONG_S $11, PT_R11(k1) - LONG_S $12, PT_R12(k1) - LONG_S $13, PT_R13(k1) - LONG_S $14, PT_R14(k1) - LONG_S $15, PT_R15(k1) LONG_S $16, PT_R16(k1) LONG_S $17, PT_R17(k1) - LONG_S $18, PT_R18(k1) LONG_S $19, PT_R19(k1) LONG_S $20, PT_R20(k1) LONG_S $21, PT_R21(k1) LONG_S $22, PT_R22(k1) LONG_S $23, PT_R23(k1) - LONG_S $24, PT_R24(k1) - LONG_S $25, PT_R25(k1) - - /* - * XXXKYMA k0/k1 not saved, not being used if we got here through - * an ioctl() - */ LONG_S $28, PT_R28(k1) LONG_S $29, PT_R29(k1) @@ -104,11 +76,6 @@ FEXPORT(__kvm_mips_vcpu_run) mfc0 v0, CP0_STATUS LONG_S v0, PT_STATUS(k1) - /* Save host ASID, shove it into the BVADDR location */ - mfc0 v1, CP0_ENTRYHI - andi v1, 0xff - LONG_S v1, PT_HOST_ASID(k1) - /* Save DDATA_LO, will be used to store pointer to vcpu */ mfc0 v1, CP0_DDATA_LO LONG_S v1, PT_HOST_USERLOCAL(k1) @@ -170,13 +137,21 @@ FEXPORT(__kvm_mips_load_asid) INT_SLL t2, t2, 2 /* x4 */ REG_ADDU t3, t1, t2 LONG_L k0, (t3) - andi k0, k0, 0xff +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + li t3, CPUINFO_SIZE/4 + mul t2, t2, t3 /* x sizeof(struct cpuinfo_mips)/4 */ + LONG_L t2, (cpu_data + CPUINFO_ASID_MASK)(t2) + and k0, k0, t2 +#else + andi k0, k0, MIPS_ENTRYHI_ASID +#endif mtc0 k0, CP0_ENTRYHI ehb /* Disable RDHWR access */ mtc0 zero, CP0_HWRENA + .set noat /* Now load up the Guest Context from VCPU */ LONG_L $1, VCPU_R1(k1) LONG_L $2, VCPU_R2(k1) @@ -288,6 +263,8 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) LONG_S $30, VCPU_R30(k1) LONG_S $31, VCPU_R31(k1) + .set at + /* We need to save hi/lo and restore them on the way out */ mfhi t0 LONG_S t0, VCPU_HI(k1) @@ -339,9 +316,7 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) /* load up the host EBASE */ mfc0 v0, CP0_STATUS - .set at or k0, v0, ST0_BEV - .set noat mtc0 k0, CP0_STATUS ehb @@ -353,7 +328,6 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) * If FPU is enabled, save FCR31 and clear it so that later ctc1's don't * trigger FPE for pending exceptions. */ - .set at and v1, v0, ST0_CU1 beqz v1, 1f nop @@ -363,7 +337,6 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) sw t0, VCPU_FCR31(k1) ctc1 zero,fcr31 .set pop - .set noat 1: #ifdef CONFIG_CPU_HAS_MSA @@ -386,10 +359,8 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) #endif /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */ - .set at and v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE) or v0, v0, ST0_CU0 - .set noat mtc0 v0, CP0_STATUS ehb @@ -456,18 +427,14 @@ __kvm_mips_return_to_guest: /* Switch EBASE back to the one used by KVM */ mfc0 v1, CP0_STATUS - .set at or k0, v1, ST0_BEV - .set noat mtc0 k0, CP0_STATUS ehb mtc0 t0, CP0_EBASE /* Setup status register for running guest in UM */ - .set at or v1, v1, (ST0_EXL | KSU_USER | ST0_IE) and v1, v1, ~(ST0_CU0 | ST0_MX) - .set noat mtc0 v1, CP0_STATUS ehb @@ -489,13 +456,21 @@ __kvm_mips_return_to_guest: INT_SLL t2, t2, 2 /* x4 */ REG_ADDU t3, t1, t2 LONG_L k0, (t3) - andi k0, k0, 0xff +#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE + li t3, CPUINFO_SIZE/4 + mul t2, t2, t3 /* x sizeof(struct cpuinfo_mips)/4 */ + LONG_L t2, (cpu_data + CPUINFO_ASID_MASK)(t2) + and k0, k0, t2 +#else + andi k0, k0, MIPS_ENTRYHI_ASID +#endif mtc0 k0, CP0_ENTRYHI ehb /* Disable RDHWR access */ mtc0 zero, CP0_HWRENA + .set noat /* load the guest context from VCPU and return */ LONG_L $0, VCPU_R0(k1) LONG_L $1, VCPU_R1(k1) @@ -541,6 +516,7 @@ FEXPORT(__kvm_mips_skip_guest_restore) LONG_L k1, VCPU_R27(k1) eret + .set at __kvm_mips_return_to_host: /* EBASE is already pointing to Linux */ @@ -551,16 +527,6 @@ __kvm_mips_return_to_host: LONG_L k0, PT_HOST_USERLOCAL(k1) mtc0 k0, CP0_DDATA_LO - /* Restore host ASID */ - LONG_L k0, PT_HOST_ASID(sp) - andi k0, 0xff - mtc0 k0,CP0_ENTRYHI - ehb - - /* Load context saved on the host stack */ - LONG_L $0, PT_R0(k1) - LONG_L $1, PT_R1(k1) - /* * r2/v0 is the return code, shift it down by 2 (arithmetic) * to recover the err code @@ -568,19 +534,7 @@ __kvm_mips_return_to_host: INT_SRA k0, v0, 2 move $2, k0 - LONG_L $3, PT_R3(k1) - LONG_L $4, PT_R4(k1) - LONG_L $5, PT_R5(k1) - LONG_L $6, PT_R6(k1) - LONG_L $7, PT_R7(k1) - LONG_L $8, PT_R8(k1) - LONG_L $9, PT_R9(k1) - LONG_L $10, PT_R10(k1) - LONG_L $11, PT_R11(k1) - LONG_L $12, PT_R12(k1) - LONG_L $13, PT_R13(k1) - LONG_L $14, PT_R14(k1) - LONG_L $15, PT_R15(k1) + /* Load context saved on the host stack */ LONG_L $16, PT_R16(k1) LONG_L $17, PT_R17(k1) LONG_L $18, PT_R18(k1) @@ -589,10 +543,6 @@ __kvm_mips_return_to_host: LONG_L $21, PT_R21(k1) LONG_L $22, PT_R22(k1) LONG_L $23, PT_R23(k1) - LONG_L $24, PT_R24(k1) - LONG_L $25, PT_R25(k1) - - /* Host k0/k1 were not saved */ LONG_L $28, PT_R28(k1) LONG_L $29, PT_R29(k1) diff --git a/arch/mips/kvm/tlb.c b/arch/mips/kvm/tlb.c index e0e1d0a611fc..b9c52c1d35d6 100644 --- a/arch/mips/kvm/tlb.c +++ b/arch/mips/kvm/tlb.c @@ -49,12 +49,18 @@ EXPORT_SYMBOL_GPL(kvm_mips_is_error_pfn); uint32_t kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu) { - return vcpu->arch.guest_kernel_asid[smp_processor_id()] & ASID_MASK; + int cpu = smp_processor_id(); + + return vcpu->arch.guest_kernel_asid[cpu] & + cpu_asid_mask(&cpu_data[cpu]); } uint32_t kvm_mips_get_user_asid(struct kvm_vcpu *vcpu) { - return vcpu->arch.guest_user_asid[smp_processor_id()] & ASID_MASK; + int cpu = smp_processor_id(); + + return vcpu->arch.guest_user_asid[cpu] & + cpu_asid_mask(&cpu_data[cpu]); } inline uint32_t kvm_mips_get_commpage_asid(struct kvm_vcpu *vcpu) @@ -78,7 +84,8 @@ void kvm_mips_dump_host_tlbs(void) old_pagemask = read_c0_pagemask(); kvm_info("HOST TLBs:\n"); - kvm_info("ASID: %#lx\n", read_c0_entryhi() & ASID_MASK); + kvm_info("ASID: %#lx\n", read_c0_entryhi() & + cpu_asid_mask(¤t_cpu_data)); for (i = 0; i < current_cpu_data.tlbsize; i++) { write_c0_index(i); @@ -564,15 +571,15 @@ void kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu, { unsigned long asid = asid_cache(cpu); - asid += ASID_INC; - if (!(asid & ASID_MASK)) { + asid += cpu_asid_inc(); + if (!(asid & cpu_asid_mask(&cpu_data[cpu]))) { if (cpu_has_vtag_icache) flush_icache_all(); kvm_local_flush_tlb_all(); /* start new asid cycle */ if (!asid) /* fix version if needed */ - asid = ASID_FIRST_VERSION; + asid = asid_first_version(cpu); } cpu_context(cpu, mm) = asid_cache(cpu) = asid; @@ -627,6 +634,7 @@ static void kvm_mips_migrate_count(struct kvm_vcpu *vcpu) /* Restore ASID once we are scheduled back after preemption */ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { + unsigned long asid_mask = cpu_asid_mask(&cpu_data[cpu]); unsigned long flags; int newasid = 0; @@ -637,7 +645,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) local_irq_save(flags); if ((vcpu->arch.guest_kernel_asid[cpu] ^ asid_cache(cpu)) & - ASID_VERSION_MASK) { + asid_version_mask(cpu)) { kvm_get_new_mmu_context(&vcpu->arch.guest_kernel_mm, cpu, vcpu); vcpu->arch.guest_kernel_asid[cpu] = vcpu->arch.guest_kernel_mm.context.asid[cpu]; @@ -672,7 +680,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) */ if (current->flags & PF_VCPU) { write_c0_entryhi(vcpu->arch. - preempt_entryhi & ASID_MASK); + preempt_entryhi & asid_mask); ehb(); } } else { @@ -687,11 +695,11 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (KVM_GUEST_KERNEL_MODE(vcpu)) write_c0_entryhi(vcpu->arch. guest_kernel_asid[cpu] & - ASID_MASK); + asid_mask); else write_c0_entryhi(vcpu->arch. guest_user_asid[cpu] & - ASID_MASK); + asid_mask); ehb(); } } @@ -721,7 +729,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_mips_callbacks->vcpu_get_regs(vcpu); if (((cpu_context(cpu, current->mm) ^ asid_cache(cpu)) & - ASID_VERSION_MASK)) { + asid_version_mask(cpu))) { kvm_debug("%s: Dropping MMU Context: %#lx\n", __func__, cpu_context(cpu, current->mm)); drop_mmu_context(current->mm, cpu); @@ -748,7 +756,8 @@ uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu) inst = *(opc); } else { vpn2 = (unsigned long) opc & VPN2_MASK; - asid = kvm_read_c0_guest_entryhi(cop0) & ASID_MASK; + asid = kvm_read_c0_guest_entryhi(cop0) & + KVM_ENTRYHI_ASID; index = kvm_mips_guest_tlb_lookup(vcpu, vpn2 | asid); if (index < 0) { kvm_err("%s: get_user_failed for %p, vcpu: %p, ASID: %#lx\n", diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c index c4038d2a724c..fd43f0afdb9f 100644 --- a/arch/mips/kvm/trap_emul.c +++ b/arch/mips/kvm/trap_emul.c @@ -505,7 +505,8 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu) kvm_write_c0_guest_intctl(cop0, 0xFC000000); /* Put in vcpu id as CPUNum into Ebase Reg to handle SMP Guests */ - kvm_write_c0_guest_ebase(cop0, KVM_GUEST_KSEG0 | (vcpu_id & 0xFF)); + kvm_write_c0_guest_ebase(cop0, KVM_GUEST_KSEG0 | + (vcpu_id & MIPS_EBASE_CPUNUM)); return 0; } diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig index e10d33342b30..177769dbb0e8 100644 --- a/arch/mips/lantiq/Kconfig +++ b/arch/mips/lantiq/Kconfig @@ -25,7 +25,17 @@ config SOC_FALCON endchoice choice - prompt "Devicetree" + prompt "Built-in device tree" + help + Legacy bootloaders do not pass a DTB pointer to the kernel, so + if a "wrapper" is not being used, the kernel will need to include + a device tree that matches the target board. + + The builtin DTB will only be used if the firmware does not supply + a valid DTB. + +config LANTIQ_DT_NONE + bool "None" config DT_EASY50712 bool "Easy50712" diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile index 690257ab86d6..2718652e7466 100644 --- a/arch/mips/lantiq/Makefile +++ b/arch/mips/lantiq/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 2010 John Crispin <blogic@openwrt.org> +# Copyright (C) 2010 John Crispin <john@phrozen.org> # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 as published diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c index a0706fd4ce0a..149f0513c4f5 100644 --- a/arch/mips/lantiq/clk.c +++ b/arch/mips/lantiq/clk.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/io.h> #include <linux/export.h> diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h index 7376ce817eda..e806e048ffc2 100644 --- a/arch/mips/lantiq/clk.h +++ b/arch/mips/lantiq/clk.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_CLK_H__ diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c index 9b28d0940ef4..44bccaee822b 100644 --- a/arch/mips/lantiq/early_printk.c +++ b/arch/mips/lantiq/early_printk.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/cpu.h> diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c index aa9497947859..75315c0a9fc3 100644 --- a/arch/mips/lantiq/falcon/prom.c +++ b/arch/mips/lantiq/falcon/prom.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/lantiq/falcon/reset.c b/arch/mips/lantiq/falcon/reset.c index 568248253426..7a535d72f541 100644 --- a/arch/mips/lantiq/falcon/reset.c +++ b/arch/mips/lantiq/falcon/reset.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/init.h> diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c index 7edcd4946fc1..2a1b3021589c 100644 --- a/arch/mips/lantiq/falcon/sysctrl.c +++ b/arch/mips/lantiq/falcon/sysctrl.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com> - * Copyright (C) 2011 John Crispin <blogic@openwrt.org> + * Copyright (C) 2011 John Crispin <john@phrozen.org> */ #include <linux/ioport.h> diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index 2e7f60c9fc5d..ff17669e30a3 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> */ diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c index 297bcaa6b5d3..5f693ac77a0d 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/export.h> @@ -65,6 +65,8 @@ static void __init prom_init_cmdline(void) void __init plat_mem_setup(void) { + void *dtb; + ioport_resource.start = IOPORT_RESOURCE_START; ioport_resource.end = IOPORT_RESOURCE_END; iomem_resource.start = IOMEM_RESOURCE_START; @@ -72,11 +74,18 @@ void __init plat_mem_setup(void) set_io_port_base((unsigned long) KSEG1); + if (fw_arg0 == -2) /* UHI interface */ + dtb = (void *)fw_arg1; + else if (__dtb_start != __dtb_end) + dtb = (void *)__dtb_start; + else + panic("no dtb found"); + /* - * Load the builtin devicetree. This causes the chosen node to be + * Load the devicetree. This causes the chosen node to be * parsed resulting in our memory appearing */ - __dt_setup_arch(__dtb_start); + __dt_setup_arch(dtb); } void __init device_tree_init(void) diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h index bfd2d58c1d69..4b6576c50250 100644 --- a/arch/mips/lantiq/prom.h +++ b/arch/mips/lantiq/prom.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_PROM_H__ diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c index 07f6d5b0b65e..41fc30d8ef89 100644 --- a/arch/mips/lantiq/xway/clk.c +++ b/arch/mips/lantiq/xway/clk.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ diff --git a/arch/mips/lantiq/xway/dcdc.c b/arch/mips/lantiq/xway/dcdc.c index ae8e930f5283..08f7abaadfe5 100644 --- a/arch/mips/lantiq/xway/dcdc.c +++ b/arch/mips/lantiq/xway/dcdc.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> * Copyright (C) 2010 Sameer Ahmad, Lantiq GmbH */ diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c index 34a116e840d8..cef811755123 100644 --- a/arch/mips/lantiq/xway/dma.c +++ b/arch/mips/lantiq/xway/dma.c @@ -12,7 +12,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2011 John Crispin <blogic@openwrt.org> + * Copyright (C) 2011 John Crispin <john@phrozen.org> */ #include <linux/init.h> diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c index f1492b2db017..0f1bbea1a816 100644 --- a/arch/mips/lantiq/xway/gptu.c +++ b/arch/mips/lantiq/xway/gptu.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> * Copyright (C) 2012 Lantiq GmbH */ diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c index 8f6e02f1e965..9475b2510adb 100644 --- a/arch/mips/lantiq/xway/prom.c +++ b/arch/mips/lantiq/xway/prom.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c index bc29bb349e94..83fd65d76e81 100644 --- a/arch/mips/lantiq/xway/reset.c +++ b/arch/mips/lantiq/xway/reset.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ @@ -258,7 +258,7 @@ static int ltq_reset_device(struct reset_controller_dev *rcdev, return ltq_deassert_device(rcdev, id); } -static struct reset_control_ops reset_ops = { +static const struct reset_control_ops reset_ops = { .reset = ltq_reset_device, .assert = ltq_assert_device, .deassert = ltq_deassert_device, diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 80554e8f6037..236193b5210b 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2011-2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2011-2012 John Crispin <john@phrozen.org> * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ diff --git a/arch/mips/lantiq/xway/vmmc.c b/arch/mips/lantiq/xway/vmmc.c index d001bc38908a..4625495f9230 100644 --- a/arch/mips/lantiq/xway/vmmc.c +++ b/arch/mips/lantiq/xway/vmmc.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/module.h> diff --git a/arch/mips/lantiq/xway/xrx200_phy_fw.c b/arch/mips/lantiq/xway/xrx200_phy_fw.c index 199094a40c15..71e518c1e7e7 100644 --- a/arch/mips/lantiq/xway/xrx200_phy_fw.c +++ b/arch/mips/lantiq/xway/xrx200_phy_fw.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/delay.h> @@ -112,6 +112,6 @@ static struct platform_driver xway_phy_driver = { module_platform_driver(xway_phy_driver); -MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +MODULE_AUTHOR("John Crispin <john@phrozen.org>"); MODULE_DESCRIPTION("Lantiq XRX200 PHY Firmware Loader"); MODULE_LICENSE("GPL"); diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 92a37319efbe..0f80b936e75e 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -19,6 +19,8 @@ void dump_tlb_regs(void) pr_info("Index : %0x\n", read_c0_index()); pr_info("PageMask : %0x\n", read_c0_pagemask()); + if (cpu_has_guestid) + pr_info("GuestCtl1: %0x\n", read_c0_guestctl1()); pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); @@ -72,7 +74,10 @@ static void dump_tlb(int first, int last) { unsigned long s_entryhi, entryhi, asid; unsigned long long entrylo0, entrylo1, pa; - unsigned int s_index, s_pagemask, pagemask, c0, c1, i; + unsigned int s_index, s_pagemask, s_guestctl1 = 0; + unsigned int pagemask, guestctl1 = 0, c0, c1, i; + unsigned long asidmask = cpu_asid_mask(¤t_cpu_data); + int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4); #ifdef CONFIG_32BIT bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA); int pwidth = xpa ? 11 : 8; @@ -86,7 +91,9 @@ static void dump_tlb(int first, int last) s_pagemask = read_c0_pagemask(); s_entryhi = read_c0_entryhi(); s_index = read_c0_index(); - asid = s_entryhi & 0xff; + asid = s_entryhi & asidmask; + if (cpu_has_guestid) + s_guestctl1 = read_c0_guestctl1(); for (i = first; i <= last; i++) { write_c0_index(i); @@ -97,6 +104,8 @@ static void dump_tlb(int first, int last) entryhi = read_c0_entryhi(); entrylo0 = read_c0_entrylo0(); entrylo1 = read_c0_entrylo1(); + if (cpu_has_guestid) + guestctl1 = read_c0_guestctl1(); /* EHINV bit marks entire entry as invalid */ if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV) @@ -115,7 +124,7 @@ static void dump_tlb(int first, int last) * due to duplicate TLB entry. */ if (!((entrylo0 | entrylo1) & ENTRYLO_G) && - (entryhi & 0xff) != asid) + (entryhi & asidmask) != asid) continue; /* @@ -126,15 +135,19 @@ static void dump_tlb(int first, int last) c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; - printk("va=%0*lx asid=%02lx\n", + printk("va=%0*lx asid=%0*lx", vwidth, (entryhi & ~0x1fffUL), - entryhi & 0xff); + asidwidth, entryhi & asidmask); + if (cpu_has_guestid) + printk(" gid=%02lx", + (guestctl1 & MIPS_GCTL1_RID) + >> MIPS_GCTL1_RID_SHIFT); /* RI/XI are in awkward places, so mask them off separately */ pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); if (xpa) pa |= (unsigned long long)readx_c0_entrylo0() << 30; pa = (pa << 6) & PAGE_MASK; - printk("\t["); + printk("\n\t["); if (cpu_has_rixi) printk("ri=%d xi=%d ", (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0, @@ -164,6 +177,8 @@ static void dump_tlb(int first, int last) write_c0_entryhi(s_entryhi); write_c0_index(s_index); write_c0_pagemask(s_pagemask); + if (cpu_has_guestid) + write_c0_guestctl1(s_guestctl1); } void dump_tlb_all(void) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 8f0019a2e5c8..18a1ccd4d134 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -228,10 +228,12 @@ .hidden __memset .endif +#ifdef CONFIG_CPU_MIPSR6 .Lbyte_fixup\@: PTR_SUBU a2, $0, t0 jr ra PTR_ADDIU a2, 1 +#endif /* CONFIG_CPU_MIPSR6 */ .Lfirst_fixup\@: jr ra diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index cfcbb5218b59..744f4a7bc49d 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -29,9 +29,10 @@ static void dump_tlb(int first, int last) { int i; unsigned int asid; - unsigned long entryhi, entrylo0; + unsigned long entryhi, entrylo0, asid_mask; - asid = read_c0_entryhi() & ASID_MASK; + asid_mask = cpu_asid_mask(¤t_cpu_data); + asid = read_c0_entryhi() & asid_mask; for (i = first; i <= last; i++) { write_c0_index(i<<8); @@ -46,7 +47,7 @@ static void dump_tlb(int first, int last) /* Unused entries have a virtual address of KSEG0. */ if ((entryhi & PAGE_MASK) != KSEG0 && (entrylo0 & R3K_ENTRYLO_G || - (entryhi & ASID_MASK) == asid)) { + (entryhi & asid_mask) == asid)) { /* * Only print entries in use */ @@ -55,7 +56,7 @@ static void dump_tlb(int first, int last) printk("va=%08lx asid=%08lx" " [pa=%06lx n=%d d=%d v=%d g=%d]", entryhi & PAGE_MASK, - entryhi & ASID_MASK, + entryhi & asid_mask, entrylo0 & PAGE_MASK, (entrylo0 & R3K_ENTRYLO_N) ? 1 : 0, (entrylo0 & R3K_ENTRYLO_D) ? 1 : 0, diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index ddf1d4cbf31e..f2c714d8fb60 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.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 @@ -10,14 +10,17 @@ #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/err.h> +#include <linux/mtd/partitions.h> +#include <linux/sizes.h> #include <linux/phy.h> #include <linux/serial_8250.h> #include <linux/stmmac.h> #include <linux/usb/ehci_pdriver.h> -#include <asm-generic/sizes.h> -#include <cpufreq.h> #include <loongson1.h> +#include <cpufreq.h> +#include <dma.h> +#include <nand.h> /* 8250/16550 compatible UART */ #define LS1X_UART(_id) \ @@ -45,7 +48,7 @@ struct platform_device ls1x_uart_pdev = { }, }; -void __init ls1x_serial_setup(struct platform_device *pdev) +void __init ls1x_serial_set_uartclk(struct platform_device *pdev) { struct clk *clk; struct plat_serial8250_port *p; @@ -77,6 +80,42 @@ struct platform_device ls1x_cpufreq_pdev = { }, }; +/* DMA */ +static struct resource ls1x_dma_resources[] = { + [0] = { + .start = LS1X_DMAC_BASE, + .end = LS1X_DMAC_BASE + SZ_4 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = LS1X_DMA0_IRQ, + .end = LS1X_DMA0_IRQ, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = LS1X_DMA1_IRQ, + .end = LS1X_DMA1_IRQ, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = LS1X_DMA2_IRQ, + .end = LS1X_DMA2_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device ls1x_dma_pdev = { + .name = "ls1x-dma", + .id = -1, + .num_resources = ARRAY_SIZE(ls1x_dma_resources), + .resource = ls1x_dma_resources, +}; + +void __init ls1x_dma_set_platdata(struct plat_ls1x_dma *pdata) +{ + ls1x_dma_pdev.dev.platform_data = pdata; +} + /* Synopsys Ethernet GMAC */ static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { .phy_mask = 0, @@ -198,6 +237,64 @@ struct platform_device ls1x_eth1_pdev = { }, }; +/* GPIO */ +static struct resource ls1x_gpio0_resources[] = { + [0] = { + .start = LS1X_GPIO0_BASE, + .end = LS1X_GPIO0_BASE + SZ_4 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device ls1x_gpio0_pdev = { + .name = "ls1x-gpio", + .id = 0, + .num_resources = ARRAY_SIZE(ls1x_gpio0_resources), + .resource = ls1x_gpio0_resources, +}; + +static struct resource ls1x_gpio1_resources[] = { + [0] = { + .start = LS1X_GPIO1_BASE, + .end = LS1X_GPIO1_BASE + SZ_4 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device ls1x_gpio1_pdev = { + .name = "ls1x-gpio", + .id = 1, + .num_resources = ARRAY_SIZE(ls1x_gpio1_resources), + .resource = ls1x_gpio1_resources, +}; + +/* NAND Flash */ +static struct resource ls1x_nand_resources[] = { + [0] = { + .start = LS1X_NAND_BASE, + .end = LS1X_NAND_BASE + SZ_32 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* DMA channel 0 is dedicated to NAND */ + .start = LS1X_DMA_CHANNEL0, + .end = LS1X_DMA_CHANNEL0, + .flags = IORESOURCE_DMA, + }, +}; + +struct platform_device ls1x_nand_pdev = { + .name = "ls1x-nand", + .id = -1, + .num_resources = ARRAY_SIZE(ls1x_nand_resources), + .resource = ls1x_nand_resources, +}; + +void __init ls1x_nand_set_platdata(struct plat_ls1x_nand *pdata) +{ + ls1x_nand_pdev.dev.platform_data = pdata; +} + /* USB EHCI */ static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32); diff --git a/arch/mips/loongson32/common/reset.c b/arch/mips/loongson32/common/reset.c index c41e4ca56ab4..8a1d9cc5a134 100644 --- a/arch/mips/loongson32/common/reset.c +++ b/arch/mips/loongson32/common/reset.c @@ -9,12 +9,13 @@ #include <linux/io.h> #include <linux/pm.h> +#include <linux/sizes.h> #include <asm/idle.h> #include <asm/reboot.h> #include <loongson1.h> -static void __iomem *wdt_base; +static void __iomem *wdt_reg_base; static void ls1x_halt(void) { @@ -26,9 +27,9 @@ static void ls1x_halt(void) static void ls1x_restart(char *command) { - __raw_writel(0x1, wdt_base + WDT_EN); - __raw_writel(0x1, wdt_base + WDT_TIMER); - __raw_writel(0x1, wdt_base + WDT_SET); + __raw_writel(0x1, wdt_reg_base + WDT_EN); + __raw_writel(0x1, wdt_reg_base + WDT_TIMER); + __raw_writel(0x1, wdt_reg_base + WDT_SET); ls1x_halt(); } @@ -40,8 +41,8 @@ static void ls1x_power_off(void) static int __init ls1x_reboot_setup(void) { - wdt_base = ioremap_nocache(LS1X_WDT_BASE, 0x0f); - if (!wdt_base) + wdt_reg_base = ioremap_nocache(LS1X_WDT_BASE, (SZ_4 + SZ_8)); + if (!wdt_reg_base) panic("Failed to remap watchdog registers"); _machine_restart = ls1x_restart; diff --git a/arch/mips/loongson32/common/time.c b/arch/mips/loongson32/common/time.c index 0996b025eeef..ff224f0020e5 100644 --- a/arch/mips/loongson32/common/time.c +++ b/arch/mips/loongson32/common/time.c @@ -9,6 +9,7 @@ #include <linux/clk.h> #include <linux/interrupt.h> +#include <linux/sizes.h> #include <asm/time.h> #include <loongson1.h> @@ -35,25 +36,25 @@ DEFINE_RAW_SPINLOCK(ls1x_timer_lock); -static void __iomem *timer_base; +static void __iomem *timer_reg_base; static uint32_t ls1x_jiffies_per_tick; static inline void ls1x_pwmtimer_set_period(uint32_t period) { - __raw_writel(period, timer_base + PWM_HRC); - __raw_writel(period, timer_base + PWM_LRC); + __raw_writel(period, timer_reg_base + PWM_HRC); + __raw_writel(period, timer_reg_base + PWM_LRC); } static inline void ls1x_pwmtimer_restart(void) { - __raw_writel(0x0, timer_base + PWM_CNT); - __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + __raw_writel(0x0, timer_reg_base + PWM_CNT); + __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); } void __init ls1x_pwmtimer_init(void) { - timer_base = ioremap(LS1X_TIMER_BASE, 0xf); - if (!timer_base) + timer_reg_base = ioremap_nocache(LS1X_TIMER_BASE, SZ_16); + if (!timer_reg_base) panic("Failed to remap timer registers"); ls1x_jiffies_per_tick = DIV_ROUND_CLOSEST(mips_hpt_frequency, HZ); @@ -86,7 +87,7 @@ static cycle_t ls1x_clocksource_read(struct clocksource *cs) */ jifs = jiffies; /* read the count */ - count = __raw_readl(timer_base + PWM_CNT); + count = __raw_readl(timer_reg_base + PWM_CNT); /* * It's possible for count to appear to go the wrong way for this @@ -131,7 +132,7 @@ static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) raw_spin_lock(&ls1x_timer_lock); ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); ls1x_pwmtimer_restart(); - __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); raw_spin_unlock(&ls1x_timer_lock); return 0; @@ -140,7 +141,7 @@ static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) static int ls1x_clockevent_tick_resume(struct clock_event_device *cd) { raw_spin_lock(&ls1x_timer_lock); - __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + __raw_writel(INT_EN | CNT_EN, timer_reg_base + PWM_CTRL); raw_spin_unlock(&ls1x_timer_lock); return 0; @@ -149,8 +150,8 @@ static int ls1x_clockevent_tick_resume(struct clock_event_device *cd) static int ls1x_clockevent_set_state_shutdown(struct clock_event_device *cd) { raw_spin_lock(&ls1x_timer_lock); - __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, - timer_base + PWM_CTRL); + __raw_writel(__raw_readl(timer_reg_base + PWM_CTRL) & ~CNT_EN, + timer_reg_base + PWM_CTRL); raw_spin_unlock(&ls1x_timer_lock); return 0; @@ -220,7 +221,7 @@ void __init plat_time_init(void) #ifdef CONFIG_CEVT_CSRC_LS1X /* setup LS1X PWM timer */ - clk = clk_get(NULL, "ls1x_pwmtimer"); + clk = clk_get(NULL, "ls1x-pwmtimer"); if (IS_ERR(clk)) panic("unable to get timer clock, err=%ld", PTR_ERR(clk)); diff --git a/arch/mips/loongson32/ls1b/board.c b/arch/mips/loongson32/ls1b/board.c index 58daeea25739..38a1d404be1b 100644 --- a/arch/mips/loongson32/ls1b/board.c +++ b/arch/mips/loongson32/ls1b/board.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.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 @@ -7,26 +7,83 @@ * option) any later version. */ +#include <linux/leds.h> +#include <linux/mtd/partitions.h> +#include <linux/sizes.h> + +#include <loongson1.h> +#include <dma.h> +#include <nand.h> #include <platform.h> +struct plat_ls1x_dma ls1x_dma_pdata = { + .nr_channels = 3, +}; + +static struct mtd_partition ls1x_nand_parts[] = { + { + .name = "kernel", + .offset = 0, + .size = SZ_16M, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +struct plat_ls1x_nand ls1x_nand_pdata = { + .parts = ls1x_nand_parts, + .nr_parts = ARRAY_SIZE(ls1x_nand_parts), + .hold_cycle = 0x2, + .wait_cycle = 0xc, +}; + +static const struct gpio_led ls1x_gpio_leds[] __initconst = { + { + .name = "LED9", + .default_trigger = "heartbeat", + .gpio = 38, + .active_low = 1, + .default_state = LEDS_GPIO_DEFSTATE_OFF, + }, { + .name = "LED6", + .default_trigger = "nand-disk", + .gpio = 39, + .active_low = 1, + .default_state = LEDS_GPIO_DEFSTATE_OFF, + }, +}; + +static const struct gpio_led_platform_data ls1x_led_pdata __initconst = { + .num_leds = ARRAY_SIZE(ls1x_gpio_leds), + .leds = ls1x_gpio_leds, +}; + static struct platform_device *ls1b_platform_devices[] __initdata = { &ls1x_uart_pdev, &ls1x_cpufreq_pdev, + &ls1x_dma_pdev, &ls1x_eth0_pdev, &ls1x_eth1_pdev, &ls1x_ehci_pdev, + &ls1x_gpio0_pdev, + &ls1x_gpio1_pdev, + &ls1x_nand_pdev, &ls1x_rtc_pdev, }; static int __init ls1b_platform_init(void) { - int err; + ls1x_serial_set_uartclk(&ls1x_uart_pdev); + ls1x_dma_set_platdata(&ls1x_dma_pdata); + ls1x_nand_set_platdata(&ls1x_nand_pdata); - ls1x_serial_setup(&ls1x_uart_pdev); + gpio_led_register_device(-1, &ls1x_led_pdata); - err = platform_add_devices(ls1b_platform_devices, + return platform_add_devices(ls1b_platform_devices, ARRAY_SIZE(ls1b_platform_devices)); - return err; } arch_initcall(ls1b_platform_init); diff --git a/arch/mips/loongson64/Platform b/arch/mips/loongson64/Platform index 85d808924c94..0fce4608aa88 100644 --- a/arch/mips/loongson64/Platform +++ b/arch/mips/loongson64/Platform @@ -31,7 +31,7 @@ cflags-$(CONFIG_CPU_LOONGSON3) += -Wa,--trap # can't easily be used safely within the kbuild framework. # ifeq ($(call cc-ifversion, -ge, 0409, y), y) - ifeq ($(call ld-ifversion, -ge, 22500000, y), y) + ifeq ($(call ld-ifversion, -ge, 225000000, y), y) cflags-$(CONFIG_CPU_LOONGSON3) += \ $(call cc-option,-march=loongson3a -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) else diff --git a/arch/mips/loongson64/common/env.c b/arch/mips/loongson64/common/env.c index d6d07ad56180..57d590ac8004 100644 --- a/arch/mips/loongson64/common/env.c +++ b/arch/mips/loongson64/common/env.c @@ -105,6 +105,10 @@ void __init prom_init_env(void) loongson_chiptemp[1] = 0x900010001fe0019c; loongson_chiptemp[2] = 0x900020001fe0019c; loongson_chiptemp[3] = 0x900030001fe0019c; + loongson_freqctrl[0] = 0x900000001fe001d0; + loongson_freqctrl[1] = 0x900010001fe001d0; + loongson_freqctrl[2] = 0x900020001fe001d0; + loongson_freqctrl[3] = 0x900030001fe001d0; loongson_sysconf.ht_control_base = 0x90000EFDFB000000; loongson_sysconf.workarounds = WORKAROUND_CPUFREQ; } else if (ecpu->cputype == Loongson_3B) { @@ -187,7 +191,8 @@ void __init prom_init_env(void) case PRID_REV_LOONGSON2F: cpu_clock_freq = 797000000; break; - case PRID_REV_LOONGSON3A: + case PRID_REV_LOONGSON3A_R1: + case PRID_REV_LOONGSON3A_R2: cpu_clock_freq = 900000000; break; case PRID_REV_LOONGSON3B_R1: diff --git a/arch/mips/loongson64/loongson-3/Makefile b/arch/mips/loongson64/loongson-3/Makefile index 622fead5ebc9..44bc1482158b 100644 --- a/arch/mips/loongson64/loongson-3/Makefile +++ b/arch/mips/loongson64/loongson-3/Makefile @@ -1,7 +1,7 @@ # # Makefile for Loongson-3 family machines # -obj-y += irq.o cop2-ex.o platform.o +obj-y += irq.o cop2-ex.o platform.o acpi_init.o obj-$(CONFIG_SMP) += smp.o diff --git a/drivers/platform/mips/acpi_init.c b/arch/mips/loongson64/loongson-3/acpi_init.c index dbdad79ead8f..dbdad79ead8f 100644 --- a/drivers/platform/mips/acpi_init.c +++ b/arch/mips/loongson64/loongson-3/acpi_init.c diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c index 0f75b6b3d218..8e7649088353 100644 --- a/arch/mips/loongson64/loongson-3/irq.c +++ b/arch/mips/loongson64/loongson-3/irq.c @@ -24,19 +24,21 @@ static void ht_irqdispatch(void) } } +#define UNUSED_IPS (CAUSEF_IP5 | CAUSEF_IP4 | CAUSEF_IP1 | CAUSEF_IP0) + void mach_irq_dispatch(unsigned int pending) { if (pending & CAUSEF_IP7) do_IRQ(LOONGSON_TIMER_IRQ); #if defined(CONFIG_SMP) - else if (pending & CAUSEF_IP6) + if (pending & CAUSEF_IP6) loongson3_ipi_interrupt(NULL); #endif - else if (pending & CAUSEF_IP3) + if (pending & CAUSEF_IP3) ht_irqdispatch(); - else if (pending & CAUSEF_IP2) + if (pending & CAUSEF_IP2) do_IRQ(LOONGSON_UART_IRQ); - else { + if (pending & UNUSED_IPS) { pr_err("%s : spurious interrupt\n", __func__); spurious_interrupt(); } diff --git a/arch/mips/loongson64/loongson-3/numa.c b/arch/mips/loongson64/loongson-3/numa.c index 6f9e010cec4d..282c5a8c2fcd 100644 --- a/arch/mips/loongson64/loongson-3/numa.c +++ b/arch/mips/loongson64/loongson-3/numa.c @@ -213,10 +213,10 @@ static void __init node_mem_init(unsigned int node) BOOTMEM_DEFAULT); if (node == 0 && node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) { - /* Reserve 0xff800000~0xffffffff for RS780E integrated GPU */ + /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */ reserve_bootmem_node(NODE_DATA(node), - (node_addrspace_offset | 0xff800000), - 8 << 20, BOOTMEM_DEFAULT); + (node_addrspace_offset | 0xfe000000), + 32 << 20, BOOTMEM_DEFAULT); } sparse_memory_present_with_active_regions(node); diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index 509832a9836c..e59759af63d9 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -421,7 +421,6 @@ static int loongson3_cpu_disable(void) local_irq_save(flags); fixup_irqs(); local_irq_restore(flags); - flush_cache_all(); local_flush_tlb_all(); return 0; @@ -440,7 +439,7 @@ static void loongson3_cpu_die(unsigned int cpu) * flush all L1 entries at first. Then, another core (usually Core 0) can * safely disable the clock of the target core. loongson3_play_dead() is * called via CKSEG1 (uncached and unmmaped) */ -static void loongson3a_play_dead(int *state_addr) +static void loongson3a_r1_play_dead(int *state_addr) { register int val; register long cpuid, core, node, count; @@ -502,6 +501,89 @@ static void loongson3a_play_dead(int *state_addr) : "a1"); } +static void loongson3a_r2_play_dead(int *state_addr) +{ + register int val; + register long cpuid, core, node, count; + register void *addr, *base, *initfunc; + + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " li %[addr], 0x80000000 \n" /* KSEG0 */ + "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */ + " cache 0, 1(%[addr]) \n" + " cache 0, 2(%[addr]) \n" + " cache 0, 3(%[addr]) \n" + " cache 1, 0(%[addr]) \n" /* flush L1 DCache */ + " cache 1, 1(%[addr]) \n" + " cache 1, 2(%[addr]) \n" + " cache 1, 3(%[addr]) \n" + " addiu %[sets], %[sets], -1 \n" + " bnez %[sets], 1b \n" + " addiu %[addr], %[addr], 0x40 \n" + " li %[addr], 0x80000000 \n" /* KSEG0 */ + "2: cache 2, 0(%[addr]) \n" /* flush L1 VCache */ + " cache 2, 1(%[addr]) \n" + " cache 2, 2(%[addr]) \n" + " cache 2, 3(%[addr]) \n" + " cache 2, 4(%[addr]) \n" + " cache 2, 5(%[addr]) \n" + " cache 2, 6(%[addr]) \n" + " cache 2, 7(%[addr]) \n" + " cache 2, 8(%[addr]) \n" + " cache 2, 9(%[addr]) \n" + " cache 2, 10(%[addr]) \n" + " cache 2, 11(%[addr]) \n" + " cache 2, 12(%[addr]) \n" + " cache 2, 13(%[addr]) \n" + " cache 2, 14(%[addr]) \n" + " cache 2, 15(%[addr]) \n" + " addiu %[vsets], %[vsets], -1 \n" + " bnez %[vsets], 2b \n" + " addiu %[addr], %[addr], 0x40 \n" + " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */ + " sw %[val], (%[state_addr]) \n" + " sync \n" + " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */ + " .set pop \n" + : [addr] "=&r" (addr), [val] "=&r" (val) + : [state_addr] "r" (state_addr), + [sets] "r" (cpu_data[smp_processor_id()].dcache.sets), + [vsets] "r" (cpu_data[smp_processor_id()].vcache.sets)); + + __asm__ __volatile__( + " .set push \n" + " .set noreorder \n" + " .set mips64 \n" + " mfc0 %[cpuid], $15, 1 \n" + " andi %[cpuid], 0x3ff \n" + " dli %[base], 0x900000003ff01000 \n" + " andi %[core], %[cpuid], 0x3 \n" + " sll %[core], 8 \n" /* get core id */ + " or %[base], %[base], %[core] \n" + " andi %[node], %[cpuid], 0xc \n" + " dsll %[node], 42 \n" /* get node id */ + " or %[base], %[base], %[node] \n" + "1: li %[count], 0x100 \n" /* wait for init loop */ + "2: bnez %[count], 2b \n" /* limit mailbox access */ + " addiu %[count], -1 \n" + " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */ + " beqz %[initfunc], 1b \n" + " nop \n" + " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */ + " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */ + " ld $a1, 0x38(%[base]) \n" + " jr %[initfunc] \n" /* jump to initial PC */ + " nop \n" + " .set pop \n" + : [core] "=&r" (core), [node] "=&r" (node), + [base] "=&r" (base), [cpuid] "=&r" (cpuid), + [count] "=&r" (count), [initfunc] "=&r" (initfunc) + : /* No Input */ + : "a1"); +} + static void loongson3b_play_dead(int *state_addr) { register int val; @@ -573,13 +655,18 @@ void play_dead(void) void (*play_dead_at_ckseg1)(int *); idle_task_exit(); - switch (loongson_sysconf.cputype) { - case Loongson_3A: + switch (read_c0_prid() & PRID_REV_MASK) { + case PRID_REV_LOONGSON3A_R1: default: play_dead_at_ckseg1 = - (void *)CKSEG1ADDR((unsigned long)loongson3a_play_dead); + (void *)CKSEG1ADDR((unsigned long)loongson3a_r1_play_dead); + break; + case PRID_REV_LOONGSON3A_R2: + play_dead_at_ckseg1 = + (void *)CKSEG1ADDR((unsigned long)loongson3a_r2_play_dead); break; - case Loongson_3B: + case PRID_REV_LOONGSON3B_R1: + case PRID_REV_LOONGSON3B_R2: play_dead_at_ckseg1 = (void *)CKSEG1ADDR((unsigned long)loongson3b_play_dead); break; @@ -594,9 +681,9 @@ void loongson3_disable_clock(int cpu) uint64_t core_id = cpu_data[cpu].core; uint64_t package_id = cpu_data[cpu].package; - if (loongson_sysconf.cputype == Loongson_3A) { + if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) { LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id)); - } else if (loongson_sysconf.cputype == Loongson_3B) { + } else { if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG)) LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3)); } @@ -607,9 +694,9 @@ void loongson3_enable_clock(int cpu) uint64_t core_id = cpu_data[cpu].core; uint64_t package_id = cpu_data[cpu].package; - if (loongson_sysconf.cputype == Loongson_3A) { + if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) { LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id); - } else if (loongson_sysconf.cputype == Loongson_3B) { + } else { if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG)) LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3); } diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index a19641d3ac23..e9bbc2a6526f 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_2008class.o dp_fmin.o dp_fmax.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o sp_fmax.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_2008class.o sp_fmin.o sp_fmax.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index cdfd44ffa51c..d96e912b9d44 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -445,9 +445,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case spec_op: switch (insn.r_format.func) { case jalr_op: - regs->regs[insn.r_format.rd] = - regs->cp0_epc + dec_insn.pc_inc + - dec_insn.next_pc_inc; + if (insn.r_format.rd != 0) { + regs->regs[insn.r_format.rd] = + regs->cp0_epc + dec_insn.pc_inc + + dec_insn.next_pc_inc; + } /* Fall through */ case jr_op: /* For R6, JR already emulated in jalr_op */ @@ -973,9 +975,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, struct mm_decoded_insn dec_insn, void *__user *fault_addr) { unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; - unsigned int cond, cbit; + unsigned int cond, cbit, bit0; mips_instruction ir; int likely, pc_inc; + union fpureg *fpr; u32 __user *wva; u64 __user *dva; u32 wval; @@ -1187,14 +1190,14 @@ emul: return SIGILL; cond = likely = 0; + fpr = ¤t->thread.fpu.fpr[MIPSInst_RT(ir)]; + bit0 = get_fpr32(fpr, 0) & 0x1; switch (MIPSInst_RS(ir)) { case bc1eqz_op: - if (get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1) - cond = 1; + cond = bit0 == 0; break; case bc1nez_op: - if (!(get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)) - cond = 1; + cond = bit0 != 0; break; } goto branch_common; @@ -1674,7 +1677,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, union ieee754sp(*b) (union ieee754sp, union ieee754sp); union ieee754sp(*u) (union ieee754sp); } handler; - union ieee754sp fs, ft; + union ieee754sp fd, fs, ft; switch (MIPSInst_FUNC(ir)) { /* binary ops */ @@ -1945,6 +1948,17 @@ copcsr: rfmt = w_fmt; goto copcsr; + case fsel_op: + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(fd, MIPSInst_FD(ir)); + if (fd.bits & 0x1) + SPFROMREG(rv.s, MIPSInst_FT(ir)); + else + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fcvtl_op: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; @@ -1993,7 +2007,7 @@ copcsr: } case d_fmt: { - union ieee754dp fs, ft; + union ieee754dp fd, fs, ft; union { union ieee754dp(*b) (union ieee754dp, union ieee754dp); union ieee754dp(*u) (union ieee754dp); @@ -2243,6 +2257,17 @@ dcopuop: rfmt = w_fmt; goto copcsr; + case fsel_op: + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(fd, MIPSInst_FD(ir)); + if (fd.bits & 0x1) + DPFROMREG(rv.d, MIPSInst_FT(ir)); + else + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fcvtl_op: if (!cpu_has_mips_3_4_5_64_r2_r6) return SIGILL; diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c index 119eda9fa1ea..4a2d03c72959 100644 --- a/arch/mips/math-emu/dp_maddf.c +++ b/arch/mips/math-emu/dp_maddf.c @@ -14,8 +14,12 @@ #include "ieee754dp.h" -union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, - union ieee754dp y) +enum maddf_flags { + maddf_negate_product = 1 << 0, +}; + +static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y, enum maddf_flags flags) { int re; int rs; @@ -32,16 +36,15 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, COMPXDP; COMPYDP; - - u64 zm; int ze; int zs __maybe_unused; int zc; + COMPZDP; EXPLODEXDP; EXPLODEYDP; - EXPLODEDP(z, zc, zs, ze, zm) + EXPLODEZDP; FLUSHXDP; FLUSHYDP; - FLUSHDP(z, zc, zs, ze, zm); + FLUSHZDP; ieee754_clearcx(); @@ -50,7 +53,7 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754dp_nanxcpt(z); case IEEE754_CLASS_DNORM: - DPDNORMx(zm, ze); + DPDNORMZ; /* QNAN is handled separately below */ } @@ -154,13 +157,15 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, re = xe + ye; rs = xs ^ ys; + if (flags & maddf_negate_product) + rs ^= 1; /* shunt to top of word */ xm <<= 64 - (DP_FBITS + 1); ym <<= 64 - (DP_FBITS + 1); /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. */ /* 32 * 32 => 64 */ @@ -198,7 +203,7 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, if ((s64) rm < 0) { rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; + re++; } else { rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); @@ -263,3 +268,15 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, return ieee754dp_format(zs, ze, zm); } + +union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + return _dp_maddf(z, x, y, 0); +} + +union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + return _dp_maddf(z, x, y, maddf_negate_product); +} diff --git a/arch/mips/math-emu/dp_msubf.c b/arch/mips/math-emu/dp_msubf.c deleted file mode 100644 index 12241262f856..000000000000 --- a/arch/mips/math-emu/dp_msubf.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * IEEE754 floating point arithmetic - * double precision: MSUB.f (Fused Multiply Subtract) - * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) - * - * MIPS floating point support - * Copyright (C) 2015 Imagination Technologies, Ltd. - * Author: Markos Chandras <markos.chandras@imgtec.com> - * - * This program is free software; you can distribute 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. - */ - -#include "ieee754dp.h" - -union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, - union ieee754dp y) -{ - int re; - int rs; - u64 rm; - unsigned lxm; - unsigned hxm; - unsigned lym; - unsigned hym; - u64 lrm; - u64 hrm; - u64 t; - u64 at; - int s; - - COMPXDP; - COMPYDP; - - u64 zm; int ze; int zs __maybe_unused; int zc; - - EXPLODEXDP; - EXPLODEYDP; - EXPLODEDP(z, zc, zs, ze, zm) - - FLUSHXDP; - FLUSHYDP; - FLUSHDP(z, zc, zs, ze, zm); - - ieee754_clearcx(); - - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754dp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - DPDNORMx(zm, ze); - /* QNAN is handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754dp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754dp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): - return y; - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; - - - /* - * Infinity handling - */ - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754dp_indef(); - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - return ieee754dp_inf(xs ^ ys); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - /* Multiplication is 0 so just return z */ - return z; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): - DPDNORMX; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - DPDNORMY; - break; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - DPDNORMX; - break; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754dp_inf(zs); - /* fall through to real computations */ - } - - /* Finally get to do some computation */ - - /* - * Do the multiplication bit first - * - * rm = xm * ym, re = xe + ye basically - * - * At this point xm and ym should have been normalized. - */ - assert(xm & DP_HIDDEN_BIT); - assert(ym & DP_HIDDEN_BIT); - - re = xe + ye; - rs = xs ^ ys; - - /* shunt to top of word */ - xm <<= 64 - (DP_FBITS + 1); - ym <<= 64 - (DP_FBITS + 1); - - /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. - */ - - /* 32 * 32 => 64 */ -#define DPXMULT(x, y) ((u64)(x) * (u64)y) - - lxm = xm; - hxm = xm >> 32; - lym = ym; - hym = ym >> 32; - - lrm = DPXMULT(lxm, lym); - hrm = DPXMULT(hxm, hym); - - t = DPXMULT(lxm, hym); - - at = lrm + (t << 32); - hrm += at < lrm; - lrm = at; - - hrm = hrm + (t >> 32); - - t = DPXMULT(hxm, lym); - - at = lrm + (t << 32); - hrm += at < lrm; - lrm = at; - - hrm = hrm + (t >> 32); - - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((s64) rm < 0) { - rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | - ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; - } else { - rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | - ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); - } - assert(rm & (DP_HIDDEN_BIT << 3)); - - /* And now the subtraction */ - - /* flip sign of r and handle as add */ - rs ^= 1; - - assert(zm & DP_HIDDEN_BIT); - - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; - - if (ze > re) { - /* - * Have to shift y fraction right to align. - */ - s = ze - re; - rm = XDPSRS(rm, s); - re += s; - } else if (re > ze) { - /* - * Have to shift x fraction right to align. - */ - s = re - ze; - zm = XDPSRS(zm, s); - ze += s; - } - assert(ze == re); - assert(ze <= DP_EMAX); - - if (zs == rs) { - /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in xm, xs and xe. - */ - zm = zm + rm; - - if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ - zm = XDPSRS1(zm); - ze++; - } - } else { - if (zm >= rm) { - zm = zm - rm; - } else { - zm = rm - zm; - zs = rs; - } - if (zm == 0) - return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); - - /* - * Normalize to rounding precision. - */ - while ((zm >> (DP_FBITS + 3)) == 0) { - zm <<= 1; - ze--; - } - } - - return ieee754dp_format(zs, ze, zm); -} diff --git a/arch/mips/math-emu/dp_mul.c b/arch/mips/math-emu/dp_mul.c index d0901f03fa19..87d0b44b0614 100644 --- a/arch/mips/math-emu/dp_mul.c +++ b/arch/mips/math-emu/dp_mul.c @@ -125,7 +125,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) ym <<= 64 - (DP_FBITS + 1); /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + * Multiply 64 bits xm, ym to give high 64 bits rm with stickness. */ /* 32 * 32 => 64 */ @@ -163,7 +163,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y) if ((s64) rm < 0) { rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | ((rm << (DP_FBITS + 1 + 3)) != 0); - re++; + re++; } else { rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 46b964d2b79c..d4ceacd4fa12 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -60,7 +60,7 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) unsigned int rs; s32 v; - rs = (((insn.mm_a_format.rs + 0x1e) & 0xf) + 2); + rs = (((insn.mm_a_format.rs + 0xe) & 0xf) + 2); v = regs->cp0_epc & ~3; v += insn.mm_a_format.simmediate << 2; regs->regs[rs] = (long)v; diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c index 47d26c805eac..465a0342ed4c 100644 --- a/arch/mips/math-emu/ieee754dp.c +++ b/arch/mips/math-emu/ieee754dp.c @@ -54,10 +54,13 @@ union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r) assert(ieee754dp_issnan(r)); ieee754_setcx(IEEE754_INVALID_OPERATION); - if (ieee754_csr.nan2008) + if (ieee754_csr.nan2008) { DPMANT(r) |= DP_MBIT(DP_FBITS - 1); - else - r = ieee754dp_indef(); + } else { + DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1); + if (!ieee754dp_isnan(r)) + DPMANT(r) |= DP_MBIT(DP_FBITS - 2); + } return r; } diff --git a/arch/mips/math-emu/ieee754dp.h b/arch/mips/math-emu/ieee754dp.h index e2babd98fee3..9ba023004eb6 100644 --- a/arch/mips/math-emu/ieee754dp.h +++ b/arch/mips/math-emu/ieee754dp.h @@ -60,6 +60,7 @@ static inline int ieee754dp_finite(union ieee754dp x) while ((m >> DP_FBITS) == 0) { m <<= 1; e--; } #define DPDNORMX DPDNORMx(xm, xe) #define DPDNORMY DPDNORMx(ym, ye) +#define DPDNORMZ DPDNORMx(zm, ze) static inline union ieee754dp builddp(int s, int bx, u64 m) { diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index ed7bb277b3e0..8bc2f6963324 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -55,6 +55,9 @@ static inline int ieee754_class_nan(int xc) #define COMPYSP \ unsigned ym; int ye; int ys; int yc +#define COMPZSP \ + unsigned zm; int ze; int zs; int zc + #define EXPLODESP(v, vc, vs, ve, vm) \ { \ vs = SPSIGN(v); \ @@ -81,6 +84,7 @@ static inline int ieee754_class_nan(int xc) } #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) +#define EXPLODEZSP EXPLODESP(z, zc, zs, ze, zm) #define COMPXDP \ @@ -89,6 +93,9 @@ static inline int ieee754_class_nan(int xc) #define COMPYDP \ u64 ym; int ye; int ys; int yc +#define COMPZDP \ + u64 zm; int ze; int zs; int zc + #define EXPLODEDP(v, vc, vs, ve, vm) \ { \ vm = DPMANT(v); \ @@ -115,6 +122,7 @@ static inline int ieee754_class_nan(int xc) } #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) +#define EXPLODEZDP EXPLODEDP(z, zc, zs, ze, zm) #define FLUSHDP(v, vc, vs, ve, vm) \ if (vc==IEEE754_CLASS_DNORM) { \ @@ -140,7 +148,9 @@ static inline int ieee754_class_nan(int xc) #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) +#define FLUSHZDP FLUSHDP(z, zc, zs, ze, zm) #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) +#define FLUSHZSP FLUSHSP(z, zc, zs, ze, zm) #endif /* __IEEE754INT_H */ diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index e0b2c450b963..260e68965907 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -54,10 +54,13 @@ union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) assert(ieee754sp_issnan(r)); ieee754_setcx(IEEE754_INVALID_OPERATION); - if (ieee754_csr.nan2008) + if (ieee754_csr.nan2008) { SPMANT(r) |= SP_MBIT(SP_FBITS - 1); - else - r = ieee754sp_indef(); + } else { + SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1); + if (!ieee754sp_isnan(r)) + SPMANT(r) |= SP_MBIT(SP_FBITS - 2); + } return r; } @@ -138,7 +141,8 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) } else { /* sticky right shift es bits */ - SPXSRSXn(es); + xm = XSPSRS(xm, es); + xe += es; assert((xm & (SP_HIDDEN_BIT << 3)) == 0); assert(xe == SP_EMIN); } diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h index 374a3f00a589..8476067075fe 100644 --- a/arch/mips/math-emu/ieee754sp.h +++ b/arch/mips/math-emu/ieee754sp.h @@ -46,25 +46,24 @@ static inline int ieee754sp_finite(union ieee754sp x) } /* 3bit extended single precision sticky right shift */ -#define SPXSRSXn(rs) \ - (xe += rs, \ - xm = (rs > (SP_FBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) +#define XSPSRS(v, rs) \ + ((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0)) -#define SPXSRSX1() \ - (xe++, (xm = (xm >> 1) | (xm & 1))) +#define XSPSRS1(m) \ + ((m >> 1) | (m & 1)) -#define SPXSRSYn(rs) \ - (ye+=rs, \ - ym = (rs > (SP_FBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) +#define SPXSRSX1() \ + (xe++, (xm = XSPSRS1(xm))) #define SPXSRSY1() \ - (ye++, (ym = (ym >> 1) | (ym & 1))) + (ye++, (ym = XSPSRS1(ym))) /* convert denormal to normalized with extended exponent */ #define SPDNORMx(m,e) \ while ((m >> SP_FBITS) == 0) { m <<= 1; e--; } #define SPDNORMX SPDNORMx(xm, xe) #define SPDNORMY SPDNORMx(ym, ye) +#define SPDNORMZ SPDNORMx(zm, ze) static inline union ieee754sp buildsp(int s, int bx, unsigned m) { diff --git a/arch/mips/math-emu/sp_add.c b/arch/mips/math-emu/sp_add.c index f1c87b07d3b4..c55c0c00bca8 100644 --- a/arch/mips/math-emu/sp_add.c +++ b/arch/mips/math-emu/sp_add.c @@ -132,13 +132,15 @@ union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y) * Have to shift y fraction right to align. */ s = xe - ye; - SPXSRSYn(s); + ym = XSPSRS(ym, s); + ye += s; } else if (ye > xe) { /* * Have to shift x fraction right to align. */ s = ye - xe; - SPXSRSXn(s); + xm = XSPSRS(xm, s); + xe += s; } assert(xe == ye); assert(xe <= SP_EMAX); diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c index dd1dd83e34eb..a8cd8b4f235e 100644 --- a/arch/mips/math-emu/sp_maddf.c +++ b/arch/mips/math-emu/sp_maddf.c @@ -14,8 +14,12 @@ #include "ieee754sp.h" -union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, - union ieee754sp y) +enum maddf_flags { + maddf_negate_product = 1 << 0, +}; + +static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y, enum maddf_flags flags) { int re; int rs; @@ -32,15 +36,15 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, COMPXSP; COMPYSP; - u32 zm; int ze; int zs __maybe_unused; int zc; + COMPZSP; EXPLODEXSP; EXPLODEYSP; - EXPLODESP(z, zc, zs, ze, zm) + EXPLODEZSP; FLUSHXSP; FLUSHYSP; - FLUSHSP(z, zc, zs, ze, zm); + FLUSHZSP; ieee754_clearcx(); @@ -49,7 +53,7 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, ieee754_setcx(IEEE754_INVALID_OPERATION); return ieee754sp_nanxcpt(z); case IEEE754_CLASS_DNORM: - SPDNORMx(zm, ze); + SPDNORMZ; /* QNAN is handled separately below */ } @@ -154,6 +158,8 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, re = xe + ye; rs = xs ^ ys; + if (flags & maddf_negate_product) + rs ^= 1; /* shunt to top of word */ xm <<= 32 - (SP_FBITS + 1); @@ -208,16 +214,18 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, if (ze > re) { /* - * Have to shift y fraction right to align. + * Have to shift r fraction right to align. */ s = ze - re; - SPXSRSYn(s); + rm = XSPSRS(rm, s); + re += s; } else if (re > ze) { /* - * Have to shift x fraction right to align. + * Have to shift z fraction right to align. */ s = re - ze; - SPXSRSYn(s); + zm = XSPSRS(zm, s); + ze += s; } assert(ze == re); assert(ze <= SP_EMAX); @@ -230,7 +238,8 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, zm = zm + rm; if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ - SPXSRSX1(); + zm = XSPSRS1(zm); + ze++; } } else { if (zm >= rm) { @@ -253,3 +262,15 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, } return ieee754sp_format(zs, ze, zm); } + +union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + return _sp_maddf(z, x, y, 0); +} + +union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + return _sp_maddf(z, x, y, maddf_negate_product); +} diff --git a/arch/mips/math-emu/sp_msubf.c b/arch/mips/math-emu/sp_msubf.c deleted file mode 100644 index 81c38b980d69..000000000000 --- a/arch/mips/math-emu/sp_msubf.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * IEEE754 floating point arithmetic - * single precision: MSUB.f (Fused Multiply Subtract) - * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) - * - * MIPS floating point support - * Copyright (C) 2015 Imagination Technologies, Ltd. - * Author: Markos Chandras <markos.chandras@imgtec.com> - * - * This program is free software; you can distribute 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. - */ - -#include "ieee754sp.h" - -union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, - union ieee754sp y) -{ - int re; - int rs; - unsigned rm; - unsigned short lxm; - unsigned short hxm; - unsigned short lym; - unsigned short hym; - unsigned lrm; - unsigned hrm; - unsigned t; - unsigned at; - int s; - - COMPXSP; - COMPYSP; - u32 zm; int ze; int zs __maybe_unused; int zc; - - EXPLODEXSP; - EXPLODEYSP; - EXPLODESP(z, zc, zs, ze, zm) - - FLUSHXSP; - FLUSHYSP; - FLUSHSP(z, zc, zs, ze, zm); - - ieee754_clearcx(); - - switch (zc) { - case IEEE754_CLASS_SNAN: - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754sp_nanxcpt(z); - case IEEE754_CLASS_DNORM: - SPDNORMx(zm, ze); - /* QNAN is handled separately below */ - } - - switch (CLPAIR(xc, yc)) { - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): - return ieee754sp_nanxcpt(y); - - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): - return ieee754sp_nanxcpt(x); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): - return y; - - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): - return x; - - /* - * Infinity handling - */ - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - ieee754_setcx(IEEE754_INVALID_OPERATION); - return ieee754sp_indef(); - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): - if (zc == IEEE754_CLASS_QNAN) - return z; - return ieee754sp_inf(xs ^ ys); - - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): - case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): - if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - /* Multiplication is 0 so just return z */ - return z; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): - SPDNORMX; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - SPDNORMY; - break; - - case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - SPDNORMX; - break; - - case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): - if (zc == IEEE754_CLASS_QNAN) - return z; - else if (zc == IEEE754_CLASS_INF) - return ieee754sp_inf(zs); - /* fall through to real compuation */ - } - - /* Finally get to do some computation */ - - /* - * Do the multiplication bit first - * - * rm = xm * ym, re = xe + ye basically - * - * At this point xm and ym should have been normalized. - */ - - /* rm = xm * ym, re = xe+ye basically */ - assert(xm & SP_HIDDEN_BIT); - assert(ym & SP_HIDDEN_BIT); - - re = xe + ye; - rs = xs ^ ys; - - /* shunt to top of word */ - xm <<= 32 - (SP_FBITS + 1); - ym <<= 32 - (SP_FBITS + 1); - - /* - * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. - */ - lxm = xm & 0xffff; - hxm = xm >> 16; - lym = ym & 0xffff; - hym = ym >> 16; - - lrm = lxm * lym; /* 16 * 16 => 32 */ - hrm = hxm * hym; /* 16 * 16 => 32 */ - - t = lxm * hym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - t = hxm * lym; /* 16 * 16 => 32 */ - at = lrm + (t << 16); - hrm += at < lrm; - lrm = at; - hrm = hrm + (t >> 16); - - rm = hrm | (lrm != 0); - - /* - * Sticky shift down to normal rounding precision. - */ - if ((int) rm < 0) { - rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | - ((rm << (SP_FBITS + 1 + 3)) != 0); - re++; - } else { - rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | - ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); - } - assert(rm & (SP_HIDDEN_BIT << 3)); - - /* And now the subtraction */ - - /* Flip sign of r and handle as add */ - rs ^= 1; - - assert(zm & SP_HIDDEN_BIT); - - /* - * Provide guard,round and stick bit space. - */ - zm <<= 3; - - if (ze > re) { - /* - * Have to shift y fraction right to align. - */ - s = ze - re; - SPXSRSYn(s); - } else if (re > ze) { - /* - * Have to shift x fraction right to align. - */ - s = re - ze; - SPXSRSYn(s); - } - assert(ze == re); - assert(ze <= SP_EMAX); - - if (zs == rs) { - /* - * Generate 28 bit result of adding two 27 bit numbers - * leaving result in zm, zs and ze. - */ - zm = zm + rm; - - if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ - SPXSRSX1(); /* shift preserving sticky */ - } - } else { - if (zm >= rm) { - zm = zm - rm; - } else { - zm = rm - zm; - zs = rs; - } - if (zm == 0) - return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); - - /* - * Normalize in extended single precision - */ - while ((zm >> (SP_MBITS + 3)) == 0) { - zm <<= 1; - ze--; - } - - } - return ieee754sp_format(zs, ze, zm); -} diff --git a/arch/mips/math-emu/sp_sub.c b/arch/mips/math-emu/sp_sub.c index ec5f937a8b3e..dc998ed47295 100644 --- a/arch/mips/math-emu/sp_sub.c +++ b/arch/mips/math-emu/sp_sub.c @@ -134,13 +134,15 @@ union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y) * have to shift y fraction right to align */ s = xe - ye; - SPXSRSYn(s); + ym = XSPSRS(ym, s); + ye += s; } else if (ye > xe) { /* * have to shift x fraction right to align */ s = ye - xe; - SPXSRSXn(s); + xm = XSPSRS(xm, s); + xe += s; } assert(xe == ye); assert(xe <= SP_EMAX); diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index caac3d747a90..ef7f925dd1b0 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -77,6 +77,7 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info) */ static unsigned long icache_size __read_mostly; static unsigned long dcache_size __read_mostly; +static unsigned long vcache_size __read_mostly; static unsigned long scache_size __read_mostly; /* @@ -447,6 +448,11 @@ static inline void local_r4k___flush_cache_all(void * args) r4k_blast_scache(); break; + case CPU_BMIPS5000: + r4k_blast_scache(); + __sync(); + break; + default: r4k_blast_dcache(); r4k_blast_icache(); @@ -492,7 +498,14 @@ static inline void local_r4k_flush_cache_range(void * args) if (!(has_valid_asid(vma->vm_mm))) return; - r4k_blast_dcache(); + /* + * If dcache can alias, we must blast it since mapping is changing. + * If executable, we must ensure any dirty lines are written back far + * enough to be visible to icache. + */ + if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) + r4k_blast_dcache(); + /* If executable, blast stale lines from icache */ if (exec) r4k_blast_icache(); } @@ -502,7 +515,7 @@ static void r4k_flush_cache_range(struct vm_area_struct *vma, { int exec = vma->vm_flags & VM_EXEC; - if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) + if (cpu_has_dc_aliases || exec) r4k_on_each_cpu(local_r4k_flush_cache_range, vma); } @@ -1148,6 +1161,8 @@ static void probe_pcache(void) c->dcache.ways * c->dcache.linesz; c->dcache.waybit = 0; + if ((prid & PRID_REV_MASK) >= PRID_REV_LOONGSON3A_R2) + c->options |= MIPS_CPU_PREFETCH; break; case CPU_CAVIUM_OCTEON3: @@ -1278,6 +1293,8 @@ static void probe_pcache(void) case CPU_M5150: case CPU_QEMU_GENERIC: case CPU_I6400: + case CPU_P6600: + case CPU_M6250: if (!(read_c0_config7() & MIPS_CONF7_IAR) && (c->icache.waysize > PAGE_SIZE)) c->icache.flags |= MIPS_CACHE_ALIASES; @@ -1304,7 +1321,14 @@ static void probe_pcache(void) break; case CPU_ALCHEMY: + case CPU_I6400: + c->icache.flags |= MIPS_CACHE_IC_F_DC; + break; + + case CPU_BMIPS5000: c->icache.flags |= MIPS_CACHE_IC_F_DC; + /* Cache aliases are handled in hardware; allow HIGHMEM */ + c->dcache.flags &= ~MIPS_CACHE_ALIASES; break; case CPU_LOONGSON2: @@ -1328,6 +1352,31 @@ static void probe_pcache(void) c->dcache.linesz); } +static void probe_vcache(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int config2, lsize; + + if (current_cpu_type() != CPU_LOONGSON3) + return; + + config2 = read_c0_config2(); + if ((lsize = ((config2 >> 20) & 15))) + c->vcache.linesz = 2 << lsize; + else + c->vcache.linesz = lsize; + + c->vcache.sets = 64 << ((config2 >> 24) & 15); + c->vcache.ways = 1 + ((config2 >> 16) & 15); + + vcache_size = c->vcache.sets * c->vcache.ways * c->vcache.linesz; + + c->vcache.waybit = 0; + + pr_info("Unified victim cache %ldkB %s, linesize %d bytes.\n", + vcache_size >> 10, way_string[c->vcache.ways], c->vcache.linesz); +} + /* * If you even _breathe_ on this function, look at the gcc output and make sure * it does not pop things on and off the stack for the cache sizing loop that @@ -1650,6 +1699,7 @@ void r4k_cache_init(void) struct cpuinfo_mips *c = ¤t_cpu_data; probe_pcache(); + probe_vcache(); setup_scache(); r4k_blast_dcache_page_setup(); @@ -1671,7 +1721,7 @@ void r4k_cache_init(void) * This code supports virtually indexed processors and will be * unnecessarily inefficient on physically indexed processors. */ - if (c->dcache.linesz) + if (c->dcache.linesz && cpu_has_dc_aliases) shm_align_mask = max_t( unsigned long, c->dcache.sets * c->dcache.linesz - 1, PAGE_SIZE - 1); @@ -1744,12 +1794,24 @@ void r4k_cache_init(void) flush_icache_range = (void *)b5k_instruction_hazard; local_flush_icache_range = (void *)b5k_instruction_hazard; - /* Cache aliases are handled in hardware; allow HIGHMEM */ - current_cpu_data.dcache.flags &= ~MIPS_CACHE_ALIASES; /* Optimization: an L2 flush implicitly flushes the L1 */ current_cpu_data.options |= MIPS_CPU_INCLUSIVE_CACHES; break; + case CPU_LOONGSON3: + /* Loongson-3 maintains cache coherency by hardware */ + __flush_cache_all = cache_noop; + __flush_cache_vmap = cache_noop; + __flush_cache_vunmap = cache_noop; + __flush_kernel_vmap_range = (void *)cache_noop; + flush_cache_mm = (void *)cache_noop; + flush_cache_page = (void *)cache_noop; + flush_cache_range = (void *)cache_noop; + flush_cache_sigtramp = (void *)cache_noop; + flush_icache_all = (void *)cache_noop; + flush_data_cache_page = (void *)cache_noop; + local_flush_data_cache_page = (void *)cache_noop; + break; } } diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 3f159caf6dbc..bf04c6c479a4 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -16,6 +16,7 @@ #include <linux/mm.h> #include <asm/cacheflush.h> +#include <asm/highmem.h> #include <asm/processor.h> #include <asm/cpu.h> #include <asm/cpu-features.h> @@ -83,8 +84,6 @@ void __flush_dcache_page(struct page *page) struct address_space *mapping = page_mapping(page); unsigned long addr; - if (PageHighMem(page)) - return; if (mapping && !mapping_mapped(mapping)) { SetPageDcacheDirty(page); return; @@ -95,8 +94,15 @@ void __flush_dcache_page(struct page *page) * case is for exec env/arg pages and those are %99 certainly going to * get faulted into the tlb (and thus flushed) anyways. */ - addr = (unsigned long) page_address(page); + if (PageHighMem(page)) + addr = (unsigned long)kmap_atomic(page); + else + addr = (unsigned long)page_address(page); + flush_data_cache_page(addr); + + if (PageHighMem(page)) + __kunmap_atomic((void *)addr); } EXPORT_SYMBOL(__flush_dcache_page); @@ -119,33 +125,28 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) EXPORT_SYMBOL(__flush_anon_page); -void __flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - unsigned long addr; - - if (PageHighMem(page)) - return; - - addr = (unsigned long) page_address(page); - flush_data_cache_page(addr); -} -EXPORT_SYMBOL_GPL(__flush_icache_page); - -void __update_cache(struct vm_area_struct *vma, unsigned long address, - pte_t pte) +void __update_cache(unsigned long address, pte_t pte) { struct page *page; unsigned long pfn, addr; - int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; + int exec = !pte_no_exec(pte) && !cpu_has_ic_fills_f_dc; pfn = pte_pfn(pte); if (unlikely(!pfn_valid(pfn))) return; page = pfn_to_page(pfn); - if (page_mapping(page) && Page_dcache_dirty(page)) { - addr = (unsigned long) page_address(page); + if (Page_dcache_dirty(page)) { + if (PageHighMem(page)) + addr = (unsigned long)kmap_atomic(page); + else + addr = (unsigned long)page_address(page); + if (exec || pages_do_alias(addr, address & PAGE_MASK)) flush_data_cache_page(addr); + + if (PageHighMem(page)) + __kunmap_atomic((void *)addr); + ClearPageDcacheDirty(page); } } diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 730d394ce5f0..cb557d28cb21 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -88,19 +88,20 @@ static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp) else #endif #if defined(CONFIG_ZONE_DMA32) && defined(CONFIG_ZONE_DMA) - if (dev->coherent_dma_mask < DMA_BIT_MASK(32)) + if (dev == NULL || dev->coherent_dma_mask < DMA_BIT_MASK(32)) dma_flag = __GFP_DMA; else if (dev->coherent_dma_mask < DMA_BIT_MASK(64)) dma_flag = __GFP_DMA32; else #endif #if defined(CONFIG_ZONE_DMA32) && !defined(CONFIG_ZONE_DMA) - if (dev->coherent_dma_mask < DMA_BIT_MASK(64)) + if (dev == NULL || dev->coherent_dma_mask < DMA_BIT_MASK(64)) dma_flag = __GFP_DMA32; else #endif #if defined(CONFIG_ZONE_DMA) && !defined(CONFIG_ZONE_DMA32) - if (dev->coherent_dma_mask < DMA_BIT_MASK(sizeof(phys_addr_t) * 8)) + if (dev == NULL || + dev->coherent_dma_mask < DMA_BIT_MASK(sizeof(phys_addr_t) * 8)) dma_flag = __GFP_DMA; else #endif diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 7e5fa0938c21..9b58eb5fd0d5 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -98,8 +98,10 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) idx += in_interrupt() ? FIX_N_COLOURS : 0; vaddr = __fix_to_virt(FIX_CMAP_END - idx); pte = mk_pte(page, prot); -#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_XPA) entrylo = pte_to_entrylo(pte.pte_high); +#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) + entrylo = pte.pte_high; #else entrylo = pte_to_entrylo(pte_val(pte)); #endif @@ -110,9 +112,11 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) write_c0_entrylo0(entrylo); write_c0_entrylo1(entrylo); #ifdef CONFIG_XPA - entrylo = (pte.pte_low & _PFNX_MASK); - writex_c0_entrylo0(entrylo); - writex_c0_entrylo1(entrylo); + if (cpu_has_xpa) { + entrylo = (pte.pte_low & _PFNX_MASK); + writex_c0_entrylo0(entrylo); + writex_c0_entrylo1(entrylo); + } #endif tlbidx = read_c0_wired(); write_c0_wired(tlbidx + 1); @@ -196,7 +200,7 @@ void copy_to_user_page(struct vm_area_struct *vma, if (cpu_has_dc_aliases) SetPageDcacheDirty(page); } - if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) + if (vma->vm_flags & VM_EXEC) flush_cache_page(vma, vaddr, page_to_pfn(page)); } diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c index 885d73ffd6fb..c41953ca6605 100644 --- a/arch/mips/mm/page.c +++ b/arch/mips/mm/page.c @@ -188,6 +188,15 @@ static void set_prefetch_parameters(void) } break; + case CPU_LOONGSON3: + /* Loongson-3 only support the Pref_Load/Pref_Store. */ + pref_bias_clear_store = 128; + pref_bias_copy_load = 128; + pref_bias_copy_store = 128; + pref_src_mode = Pref_Load; + pref_dst_mode = Pref_Store; + break; + default: pref_bias_clear_store = 128; pref_bias_copy_load = 256; diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 91dec32c77b7..286a4d5a1884 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -141,6 +141,7 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) case CPU_P5600: case CPU_BMIPS5000: case CPU_QEMU_GENERIC: + case CPU_P6600: if (config2 & (1 << 12)) return 0; } diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c index b4f366f7c0f5..1290b995695d 100644 --- a/arch/mips/mm/tlb-r3k.c +++ b/arch/mips/mm/tlb-r3k.c @@ -43,7 +43,7 @@ static void local_flush_tlb_from(int entry) { unsigned long old_ctx; - old_ctx = read_c0_entryhi() & ASID_MASK; + old_ctx = read_c0_entryhi() & cpu_asid_mask(¤t_cpu_data); write_c0_entrylo0(0); while (entry < current_cpu_data.tlbsize) { write_c0_index(entry << 8); @@ -81,6 +81,7 @@ void local_flush_tlb_mm(struct mm_struct *mm) void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { + unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data); struct mm_struct *mm = vma->vm_mm; int cpu = smp_processor_id(); @@ -89,13 +90,13 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, #ifdef DEBUG_TLB printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", - cpu_context(cpu, mm) & ASID_MASK, start, end); + cpu_context(cpu, mm) & asid_mask, start, end); #endif local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (size <= current_cpu_data.tlbsize) { - int oldpid = read_c0_entryhi() & ASID_MASK; - int newpid = cpu_context(cpu, mm) & ASID_MASK; + int oldpid = read_c0_entryhi() & asid_mask; + int newpid = cpu_context(cpu, mm) & asid_mask; start &= PAGE_MASK; end += PAGE_SIZE - 1; @@ -159,6 +160,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { + unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data); int cpu = smp_processor_id(); if (cpu_context(cpu, vma->vm_mm) != 0) { @@ -168,10 +170,10 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) #ifdef DEBUG_TLB printk("[tlbpage<%lu,0x%08lx>]", cpu_context(cpu, vma->vm_mm), page); #endif - newpid = cpu_context(cpu, vma->vm_mm) & ASID_MASK; + newpid = cpu_context(cpu, vma->vm_mm) & asid_mask; page &= PAGE_MASK; local_irq_save(flags); - oldpid = read_c0_entryhi() & ASID_MASK; + oldpid = read_c0_entryhi() & asid_mask; write_c0_entryhi(page | newpid); BARRIER; tlb_probe(); @@ -190,6 +192,7 @@ finish: void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) { + unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data); unsigned long flags; int idx, pid; @@ -199,10 +202,10 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) if (current->active_mm != vma->vm_mm) return; - pid = read_c0_entryhi() & ASID_MASK; + pid = read_c0_entryhi() & asid_mask; #ifdef DEBUG_TLB - if ((pid != (cpu_context(cpu, vma->vm_mm) & ASID_MASK)) || (cpu_context(cpu, vma->vm_mm) == 0)) { + if ((pid != (cpu_context(cpu, vma->vm_mm) & asid_mask)) || (cpu_context(cpu, vma->vm_mm) == 0)) { printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n", (cpu_context(cpu, vma->vm_mm)), pid); } @@ -228,6 +231,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask) { + unsigned long asid_mask = cpu_asid_mask(¤t_cpu_data); unsigned long flags; unsigned long old_ctx; static unsigned long wired = 0; @@ -243,7 +247,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, local_irq_save(flags); /* Save old context and create impossible VPN2 value */ - old_ctx = read_c0_entryhi() & ASID_MASK; + old_ctx = read_c0_entryhi() & asid_mask; old_pagemask = read_c0_pagemask(); w = read_c0_wired(); write_c0_wired(w + 1); @@ -266,7 +270,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, #endif local_irq_save(flags); - old_ctx = read_c0_entryhi() & ASID_MASK; + old_ctx = read_c0_entryhi() & asid_mask; write_c0_entrylo0(entrylo0); write_c0_entryhi(entryhi); write_c0_index(wired); diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index c17d7627f872..5a5c7fec645e 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -28,25 +28,28 @@ extern void build_tlb_refill_handler(void); /* - * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb, - * unfortunately, itlb is not totally transparent to software. + * LOONGSON-2 has a 4 entry itlb which is a subset of jtlb, LOONGSON-3 has + * a 4 entry itlb and a 4 entry dtlb which are subsets of jtlb. Unfortunately, + * itlb/dtlb are not totally transparent to software. */ -static inline void flush_itlb(void) +static inline void flush_micro_tlb(void) { switch (current_cpu_type()) { case CPU_LOONGSON2: + write_c0_diag(LOONGSON_DIAG_ITLB); + break; case CPU_LOONGSON3: - write_c0_diag(4); + write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB); break; default: break; } } -static inline void flush_itlb_vm(struct vm_area_struct *vma) +static inline void flush_micro_tlb_vm(struct vm_area_struct *vma) { if (vma->vm_flags & VM_EXEC) - flush_itlb(); + flush_micro_tlb(); } void local_flush_tlb_all(void) @@ -93,7 +96,7 @@ void local_flush_tlb_all(void) tlbw_use_hazard(); write_c0_entryhi(old_ctx); htw_start(); - flush_itlb(); + flush_micro_tlb(); local_irq_restore(flags); } EXPORT_SYMBOL(local_flush_tlb_all); @@ -159,7 +162,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, } else { drop_mmu_context(mm, cpu); } - flush_itlb(); + flush_micro_tlb(); local_irq_restore(flags); } } @@ -205,7 +208,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) } else { local_flush_tlb_all(); } - flush_itlb(); + flush_micro_tlb(); local_irq_restore(flags); } @@ -240,7 +243,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: write_c0_entryhi(oldpid); htw_start(); - flush_itlb_vm(vma); + flush_micro_tlb_vm(vma); local_irq_restore(flags); } } @@ -274,7 +277,7 @@ void local_flush_tlb_one(unsigned long page) } write_c0_entryhi(oldpid); htw_start(); - flush_itlb(); + flush_micro_tlb(); local_irq_restore(flags); } @@ -301,7 +304,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) local_irq_save(flags); htw_stop(); - pid = read_c0_entryhi() & ASID_MASK; + pid = read_c0_entryhi() & cpu_asid_mask(¤t_cpu_data); address &= (PAGE_MASK << 1); write_c0_entryhi(address | pid); pgdp = pgd_offset(vma->vm_mm, address); @@ -336,10 +339,12 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) #ifdef CONFIG_XPA write_c0_entrylo0(pte_to_entrylo(ptep->pte_high)); - writex_c0_entrylo0(ptep->pte_low & _PFNX_MASK); + if (cpu_has_xpa) + writex_c0_entrylo0(ptep->pte_low & _PFNX_MASK); ptep++; write_c0_entrylo1(pte_to_entrylo(ptep->pte_high)); - writex_c0_entrylo1(ptep->pte_low & _PFNX_MASK); + if (cpu_has_xpa) + writex_c0_entrylo1(ptep->pte_low & _PFNX_MASK); #else write_c0_entrylo0(ptep->pte_high); ptep++; @@ -357,7 +362,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) } tlbw_use_hazard(); htw_start(); - flush_itlb_vm(vma); + flush_micro_tlb_vm(vma); local_irq_restore(flags); } diff --git a/arch/mips/mm/tlb-r8k.c b/arch/mips/mm/tlb-r8k.c index 138a2ec7cc6b..e86e2e55ad3e 100644 --- a/arch/mips/mm/tlb-r8k.c +++ b/arch/mips/mm/tlb-r8k.c @@ -194,7 +194,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) if (current->active_mm != vma->vm_mm) return; - pid = read_c0_entryhi() & ASID_MASK; + pid = read_c0_entryhi() & cpu_asid_mask(¤t_cpu_data); local_irq_save(flags); address &= PAGE_MASK; diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 84c6e3fda84a..274da90adf0d 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -234,20 +234,16 @@ static void output_pgtable_bits_defines(void) pr_debug("\n"); pr_define("_PAGE_PRESENT_SHIFT %d\n", _PAGE_PRESENT_SHIFT); - pr_define("_PAGE_READ_SHIFT %d\n", _PAGE_READ_SHIFT); + pr_define("_PAGE_NO_READ_SHIFT %d\n", _PAGE_NO_READ_SHIFT); pr_define("_PAGE_WRITE_SHIFT %d\n", _PAGE_WRITE_SHIFT); pr_define("_PAGE_ACCESSED_SHIFT %d\n", _PAGE_ACCESSED_SHIFT); pr_define("_PAGE_MODIFIED_SHIFT %d\n", _PAGE_MODIFIED_SHIFT); #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT pr_define("_PAGE_HUGE_SHIFT %d\n", _PAGE_HUGE_SHIFT); #endif -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) - if (cpu_has_rixi) { #ifdef _PAGE_NO_EXEC_SHIFT + if (cpu_has_rixi) pr_define("_PAGE_NO_EXEC_SHIFT %d\n", _PAGE_NO_EXEC_SHIFT); - pr_define("_PAGE_NO_READ_SHIFT %d\n", _PAGE_NO_READ_SHIFT); -#endif - } #endif pr_define("_PAGE_GLOBAL_SHIFT %d\n", _PAGE_GLOBAL_SHIFT); pr_define("_PAGE_VALID_SHIFT %d\n", _PAGE_VALID_SHIFT); @@ -284,7 +280,12 @@ static inline void dump_handler(const char *symbol, const u32 *handler, int coun #define C0_ENTRYLO1 3, 0 #define C0_CONTEXT 4, 0 #define C0_PAGEMASK 5, 0 +#define C0_PWBASE 5, 5 +#define C0_PWFIELD 5, 6 +#define C0_PWSIZE 5, 7 +#define C0_PWCTL 6, 6 #define C0_BADVADDR 8, 0 +#define C0_PGD 9, 7 #define C0_ENTRYHI 10, 0 #define C0_EPC 14, 0 #define C0_XCONTEXT 20, 0 @@ -630,6 +631,11 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l, static __maybe_unused void build_convert_pte_to_entrylo(u32 **p, unsigned int reg) { + if (_PAGE_GLOBAL_SHIFT == 0) { + /* pte_t is already in EntryLo format */ + return; + } + if (cpu_has_rixi && _PAGE_NO_EXEC) { if (fill_includes_sw_bits) { UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL)); @@ -808,7 +814,10 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, if (pgd_reg != -1) { /* pgd is in pgd_reg */ - UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg); + if (cpu_has_ldpte) + UASM_i_MFC0(p, ptr, C0_PWBASE); + else + UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg); } else { #if defined(CONFIG_MIPS_PGD_C0_CONTEXT) /* @@ -1007,39 +1016,40 @@ static void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr) static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep) { - /* - * 64bit address support (36bit on a 32bit CPU) in a 32bit - * Kernel is a special case. Only a few CPUs use it. - */ - if (config_enabled(CONFIG_PHYS_ADDR_T_64BIT) && !cpu_has_64bits) { - int pte_off_even = sizeof(pte_t) / 2; - int pte_off_odd = pte_off_even + sizeof(pte_t); -#ifdef CONFIG_XPA - const int scratch = 1; /* Our extra working register */ + int pte_off_even = 0; + int pte_off_odd = sizeof(pte_t); - uasm_i_addu(p, scratch, 0, ptep); +#if defined(CONFIG_CPU_MIPS32) && defined(CONFIG_PHYS_ADDR_T_64BIT) + /* The low 32 bits of EntryLo is stored in pte_high */ + pte_off_even += offsetof(pte_t, pte_high); + pte_off_odd += offsetof(pte_t, pte_high); #endif + + if (config_enabled(CONFIG_XPA)) { uasm_i_lw(p, tmp, pte_off_even, ptep); /* even pte */ - uasm_i_lw(p, ptep, pte_off_odd, ptep); /* odd pte */ UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); - UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); UASM_i_MTC0(p, tmp, C0_ENTRYLO0); - UASM_i_MTC0(p, ptep, C0_ENTRYLO1); -#ifdef CONFIG_XPA - uasm_i_lw(p, tmp, 0, scratch); - uasm_i_lw(p, ptep, sizeof(pte_t), scratch); - uasm_i_lui(p, scratch, 0xff); - uasm_i_ori(p, scratch, scratch, 0xffff); - uasm_i_and(p, tmp, scratch, tmp); - uasm_i_and(p, ptep, scratch, ptep); - uasm_i_mthc0(p, tmp, C0_ENTRYLO0); - uasm_i_mthc0(p, ptep, C0_ENTRYLO1); -#endif + + if (cpu_has_xpa && !mips_xpa_disabled) { + uasm_i_lw(p, tmp, 0, ptep); + uasm_i_ext(p, tmp, tmp, 0, 24); + uasm_i_mthc0(p, tmp, C0_ENTRYLO0); + } + + uasm_i_lw(p, tmp, pte_off_odd, ptep); /* odd pte */ + UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); + UASM_i_MTC0(p, tmp, C0_ENTRYLO1); + + if (cpu_has_xpa && !mips_xpa_disabled) { + uasm_i_lw(p, tmp, sizeof(pte_t), ptep); + uasm_i_ext(p, tmp, tmp, 0, 24); + uasm_i_mthc0(p, tmp, C0_ENTRYLO1); + } return; } - UASM_i_LW(p, tmp, 0, ptep); /* get even pte */ - UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ + UASM_i_LW(p, tmp, pte_off_even, ptep); /* get even pte */ + UASM_i_LW(p, ptep, pte_off_odd, ptep); /* get odd pte */ if (r45k_bvahwbug()) build_tlb_probe_entry(p); build_convert_pte_to_entrylo(p, tmp); @@ -1421,6 +1431,108 @@ static void build_r4000_tlb_refill_handler(void) dump_handler("r4000_tlb_refill", (u32 *)ebase, 64); } +static void setup_pw(void) +{ + unsigned long pgd_i, pgd_w; +#ifndef __PAGETABLE_PMD_FOLDED + unsigned long pmd_i, pmd_w; +#endif + unsigned long pt_i, pt_w; + unsigned long pte_i, pte_w; +#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT + unsigned long psn; + + psn = ilog2(_PAGE_HUGE); /* bit used to indicate huge page */ +#endif + pgd_i = PGDIR_SHIFT; /* 1st level PGD */ +#ifndef __PAGETABLE_PMD_FOLDED + pgd_w = PGDIR_SHIFT - PMD_SHIFT + PGD_ORDER; + + pmd_i = PMD_SHIFT; /* 2nd level PMD */ + pmd_w = PMD_SHIFT - PAGE_SHIFT; +#else + pgd_w = PGDIR_SHIFT - PAGE_SHIFT + PGD_ORDER; +#endif + + pt_i = PAGE_SHIFT; /* 3rd level PTE */ + pt_w = PAGE_SHIFT - 3; + + pte_i = ilog2(_PAGE_GLOBAL); + pte_w = 0; + +#ifndef __PAGETABLE_PMD_FOLDED + write_c0_pwfield(pgd_i << 24 | pmd_i << 12 | pt_i << 6 | pte_i); + write_c0_pwsize(1 << 30 | pgd_w << 24 | pmd_w << 12 | pt_w << 6 | pte_w); +#else + write_c0_pwfield(pgd_i << 24 | pt_i << 6 | pte_i); + write_c0_pwsize(1 << 30 | pgd_w << 24 | pt_w << 6 | pte_w); +#endif + +#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT + write_c0_pwctl(1 << 6 | psn); +#endif + write_c0_kpgd(swapper_pg_dir); + kscratch_used_mask |= (1 << 7); /* KScratch6 is used for KPGD */ +} + +static void build_loongson3_tlb_refill_handler(void) +{ + u32 *p = tlb_handler; + struct uasm_label *l = labels; + struct uasm_reloc *r = relocs; + + memset(labels, 0, sizeof(labels)); + memset(relocs, 0, sizeof(relocs)); + memset(tlb_handler, 0, sizeof(tlb_handler)); + + if (check_for_high_segbits) { + uasm_i_dmfc0(&p, K0, C0_BADVADDR); + uasm_i_dsrl_safe(&p, K1, K0, PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3); + uasm_il_beqz(&p, &r, K1, label_vmalloc); + uasm_i_nop(&p); + + uasm_il_bgez(&p, &r, K0, label_large_segbits_fault); + uasm_i_nop(&p); + uasm_l_vmalloc(&l, p); + } + + uasm_i_dmfc0(&p, K1, C0_PGD); + + uasm_i_lddir(&p, K0, K1, 3); /* global page dir */ +#ifndef __PAGETABLE_PMD_FOLDED + uasm_i_lddir(&p, K1, K0, 1); /* middle page dir */ +#endif + uasm_i_ldpte(&p, K1, 0); /* even */ + uasm_i_ldpte(&p, K1, 1); /* odd */ + uasm_i_tlbwr(&p); + + /* restore page mask */ + if (PM_DEFAULT_MASK >> 16) { + uasm_i_lui(&p, K0, PM_DEFAULT_MASK >> 16); + uasm_i_ori(&p, K0, K0, PM_DEFAULT_MASK & 0xffff); + uasm_i_mtc0(&p, K0, C0_PAGEMASK); + } else if (PM_DEFAULT_MASK) { + uasm_i_ori(&p, K0, 0, PM_DEFAULT_MASK); + uasm_i_mtc0(&p, K0, C0_PAGEMASK); + } else { + uasm_i_mtc0(&p, 0, C0_PAGEMASK); + } + + uasm_i_eret(&p); + + if (check_for_high_segbits) { + uasm_l_large_segbits_fault(&l, p); + UASM_i_LA(&p, K1, (unsigned long)tlb_do_page_fault_0); + uasm_i_jr(&p, K1); + uasm_i_nop(&p); + } + + uasm_resolve_relocs(relocs, labels); + memcpy((void *)(ebase + 0x80), tlb_handler, 0x80); + local_flush_icache_range(ebase + 0x80, ebase + 0x100); + dump_handler("loongson3_tlb_refill", (u32 *)(ebase + 0x80), 32); +} + extern u32 handle_tlbl[], handle_tlbl_end[]; extern u32 handle_tlbs[], handle_tlbs_end[]; extern u32 handle_tlbm[], handle_tlbm_end[]; @@ -1468,7 +1580,10 @@ static void build_setup_pgd(void) } else { /* PGD in c0_KScratch */ uasm_i_jr(&p, 31); - UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); + if (cpu_has_ldpte) + UASM_i_MTC0(&p, a0, C0_PWBASE); + else + UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); } #else #ifdef CONFIG_SMP @@ -1523,19 +1638,19 @@ iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) static void iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, - unsigned int mode) + unsigned int mode, unsigned int scratch) { -#ifdef CONFIG_PHYS_ADDR_T_64BIT unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY); + unsigned int swmode = mode & ~hwmode; - if (!cpu_has_64bits) { - const int scratch = 1; /* Our extra working register */ - - uasm_i_lui(p, scratch, (mode >> 16)); + if (config_enabled(CONFIG_XPA) && !cpu_has_64bits) { + uasm_i_lui(p, scratch, swmode >> 16); uasm_i_or(p, pte, pte, scratch); - } else -#endif - uasm_i_ori(p, pte, pte, mode); + BUG_ON(swmode & 0xffff); + } else { + uasm_i_ori(p, pte, pte, mode); + } + #ifdef CONFIG_SMP # ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits) @@ -1554,6 +1669,7 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, /* no uasm_i_nop needed */ uasm_i_ll(p, pte, sizeof(pte_t) / 2, ptr); uasm_i_ori(p, pte, pte, hwmode); + BUG_ON(hwmode & ~0xffff); uasm_i_sc(p, pte, sizeof(pte_t) / 2, ptr); uasm_il_beqz(p, r, pte, label_smp_pgtable_change); /* no uasm_i_nop needed */ @@ -1575,6 +1691,7 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, if (!cpu_has_64bits) { uasm_i_lw(p, pte, sizeof(pte_t) / 2, ptr); uasm_i_ori(p, pte, pte, hwmode); + BUG_ON(hwmode & ~0xffff); uasm_i_sw(p, pte, sizeof(pte_t) / 2, ptr); uasm_i_lw(p, pte, 0, ptr); } @@ -1615,9 +1732,8 @@ build_pte_present(u32 **p, struct uasm_reloc **r, cur = t; } uasm_i_andi(p, t, cur, - (_PAGE_PRESENT | _PAGE_READ) >> _PAGE_PRESENT_SHIFT); - uasm_i_xori(p, t, t, - (_PAGE_PRESENT | _PAGE_READ) >> _PAGE_PRESENT_SHIFT); + (_PAGE_PRESENT | _PAGE_NO_READ) >> _PAGE_PRESENT_SHIFT); + uasm_i_xori(p, t, t, _PAGE_PRESENT >> _PAGE_PRESENT_SHIFT); uasm_il_bnez(p, r, t, lid); if (pte == t) /* You lose the SMP race :-(*/ @@ -1628,11 +1744,11 @@ build_pte_present(u32 **p, struct uasm_reloc **r, /* Make PTE valid, store result in PTR. */ static void build_make_valid(u32 **p, struct uasm_reloc **r, unsigned int pte, - unsigned int ptr) + unsigned int ptr, unsigned int scratch) { unsigned int mode = _PAGE_VALID | _PAGE_ACCESSED; - iPTE_SW(p, r, pte, ptr, mode); + iPTE_SW(p, r, pte, ptr, mode, scratch); } /* @@ -1668,12 +1784,12 @@ build_pte_writable(u32 **p, struct uasm_reloc **r, */ static void build_make_write(u32 **p, struct uasm_reloc **r, unsigned int pte, - unsigned int ptr) + unsigned int ptr, unsigned int scratch) { unsigned int mode = (_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY); - iPTE_SW(p, r, pte, ptr, mode); + iPTE_SW(p, r, pte, ptr, mode, scratch); } /* @@ -1778,7 +1894,7 @@ static void build_r3000_tlb_load_handler(void) build_r3000_tlbchange_handler_head(&p, K0, K1); build_pte_present(&p, &r, K0, K1, -1, label_nopage_tlbl); uasm_i_nop(&p); /* load delay */ - build_make_valid(&p, &r, K0, K1); + build_make_valid(&p, &r, K0, K1, -1); build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); uasm_l_nopage_tlbl(&l, p); @@ -1809,7 +1925,7 @@ static void build_r3000_tlb_store_handler(void) build_r3000_tlbchange_handler_head(&p, K0, K1); build_pte_writable(&p, &r, K0, K1, -1, label_nopage_tlbs); uasm_i_nop(&p); /* load delay */ - build_make_write(&p, &r, K0, K1); + build_make_write(&p, &r, K0, K1, -1); build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); uasm_l_nopage_tlbs(&l, p); @@ -1840,7 +1956,7 @@ static void build_r3000_tlb_modify_handler(void) build_r3000_tlbchange_handler_head(&p, K0, K1); build_pte_modifiable(&p, &r, K0, K1, -1, label_nopage_tlbm); uasm_i_nop(&p); /* load delay */ - build_make_write(&p, &r, K0, K1); + build_make_write(&p, &r, K0, K1, -1); build_r3000_pte_reload_tlbwi(&p, K0, K1); uasm_l_nopage_tlbm(&l, p); @@ -2008,7 +2124,7 @@ static void build_r4000_tlb_load_handler(void) } uasm_l_tlbl_goaround1(&l, p); } - build_make_valid(&p, &r, wr.r1, wr.r2); + build_make_valid(&p, &r, wr.r1, wr.r2, wr.r3); build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2); #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT @@ -2122,7 +2238,7 @@ static void build_r4000_tlb_store_handler(void) build_pte_writable(&p, &r, wr.r1, wr.r2, wr.r3, label_nopage_tlbs); if (m4kc_tlbp_war()) build_tlb_probe_entry(&p); - build_make_write(&p, &r, wr.r1, wr.r2); + build_make_write(&p, &r, wr.r1, wr.r2, wr.r3); build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2); #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT @@ -2178,7 +2294,7 @@ static void build_r4000_tlb_modify_handler(void) if (m4kc_tlbp_war()) build_tlb_probe_entry(&p); /* Present and writable bits set, set accessed and dirty bits. */ - build_make_write(&p, &r, wr.r1, wr.r2); + build_make_write(&p, &r, wr.r1, wr.r2, wr.r3); build_r4000_tlbchange_handler_tail(&p, &l, &r, wr.r1, wr.r2); #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT @@ -2311,9 +2427,7 @@ static void config_htw_params(void) if (CONFIG_PGTABLE_LEVELS >= 3) pwsize |= ilog2(PTRS_PER_PMD) << MIPS_PWSIZE_MDW_SHIFT; - /* If XPA has been enabled, PTEs are 64-bit in size. */ - if (config_enabled(CONFIG_64BITS) || (read_c0_pagegrain() & PG_ELPA)) - pwsize |= 1; + pwsize |= ilog2(sizeof(pte_t)/4) << MIPS_PWSIZE_PTEW_SHIFT; write_c0_pwsize(pwsize); @@ -2394,6 +2508,9 @@ void build_tlb_refill_handler(void) */ static int run_once = 0; + if (config_enabled(CONFIG_XPA) && !cpu_has_rixi) + panic("Kernels supporting XPA currently require CPUs with RIXI"); + output_pgtable_bits_defines(); check_pabits(); @@ -2437,13 +2554,18 @@ void build_tlb_refill_handler(void) break; default: + if (cpu_has_ldpte) + setup_pw(); + if (!run_once) { scratch_reg = allocate_kscratch(); build_setup_pgd(); build_r4000_tlb_load_handler(); build_r4000_tlb_store_handler(); build_r4000_tlb_modify_handler(); - if (!cpu_has_local_ebase) + if (cpu_has_ldpte) + build_loongson3_tlb_refill_handler(); + else if (!cpu_has_local_ebase) build_r4000_tlb_refill_handler(); flush_tlb_handlers(); run_once++; diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c index b4a837893562..9c2220a45189 100644 --- a/arch/mips/mm/uasm-mips.c +++ b/arch/mips/mm/uasm-mips.c @@ -153,6 +153,8 @@ static struct insn insn_table[] = { { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD }, { insn_yield, M(spec3_op, 0, 0, 0, 0, yield_op), RS | RD }, + { insn_ldpte, M(lwc2_op, 0, 0, 0, ldpte_op, mult_op), RS | RD }, + { insn_lddir, M(lwc2_op, 0, 0, 0, lddir_op, mult_op), RS | RT | RD }, { insn_invalid, 0, 0 } }; diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index 319051c34343..ad718debc35a 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -60,6 +60,7 @@ enum opcode { insn_sltiu, insn_sltu, insn_sra, insn_srl, insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait, insn_wsbh, insn_xor, insn_xori, insn_yield, + insn_lddir, insn_ldpte, }; struct insn { @@ -335,6 +336,8 @@ I_u1u2s3(_bbit0); I_u1u2s3(_bbit1); I_u3u1u2(_lwx) I_u3u1u2(_ldx) +I_u1u2(_ldpte) +I_u2u1u3(_lddir) #ifdef CONFIG_CPU_CAVIUM_OCTEON #include <asm/octeon/octeon.h> diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c index 4740c82fb97a..33d5ff5069e5 100644 --- a/arch/mips/mti-malta/malta-setup.c +++ b/arch/mips/mti-malta/malta-setup.c @@ -248,10 +248,15 @@ static void __init bonito_quirks_setup(void) #endif } +void __init *plat_get_fdt(void) +{ + return (void *)__dtb_start; +} + void __init plat_mem_setup(void) { unsigned int i; - void *fdt = __dtb_start; + void *fdt = plat_get_fdt(); fdt = malta_dt_shim(fdt); __dt_setup_arch(fdt); diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index b7bf721eabf5..7407da04f8d6 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -21,6 +21,7 @@ #include <linux/i8253.h> #include <linux/init.h> #include <linux/kernel_stat.h> +#include <linux/math64.h> #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/interrupt.h> @@ -72,6 +73,8 @@ static void __init estimate_frequencies(void) { unsigned long flags; unsigned int count, start; + unsigned char secs1, secs2, ctrl; + int secs; cycle_t giccount = 0, gicstart = 0; #if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ @@ -81,32 +84,51 @@ static void __init estimate_frequencies(void) local_irq_save(flags); - /* Start counter exactly on falling edge of update flag. */ + if (gic_present) + gic_start_count(); + + /* + * Read counters exactly on rising edge of update flag. + * This helps get an accurate reading under virtualisation. + */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - - /* Initialize counters. */ start = read_c0_count(); - if (gic_present) { - gic_start_count(); + if (gic_present) gicstart = gic_read_count(); - } - /* Read counter exactly on falling edge of update flag. */ + /* Wait for falling edge before reading RTC. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); - while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + secs1 = CMOS_READ(RTC_SECONDS); + /* Read counters again exactly on rising edge of update flag. */ + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); count = read_c0_count(); if (gic_present) giccount = gic_read_count(); + /* Wait for falling edge before reading RTC again. */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + secs2 = CMOS_READ(RTC_SECONDS); + + ctrl = CMOS_READ(RTC_CONTROL); + local_irq_restore(flags); + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + secs1 = bcd2bin(secs1); + secs2 = bcd2bin(secs2); + } + secs = secs2 - secs1; + if (secs < 1) + secs += 60; + count -= start; + count /= secs; mips_hpt_frequency = count; if (gic_present) { - giccount -= gicstart; + giccount = div_u64(giccount - gicstart, secs); gic_frequency = giccount; } } diff --git a/arch/mips/mti-sead3/sead3-setup.c b/arch/mips/mti-sead3/sead3-setup.c index e43f4801a245..9f2f9b2b23ce 100644 --- a/arch/mips/mti-sead3/sead3-setup.c +++ b/arch/mips/mti-sead3/sead3-setup.c @@ -83,6 +83,11 @@ static void __init parse_memsize_param(void) } } +void __init *plat_get_fdt(void) +{ + return (void *)__dtb_start; +} + void __init plat_mem_setup(void) { /* allow command line/bootloader env to override memory size in DT */ diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S index edbab9b8691f..c474981a6c0d 100644 --- a/arch/mips/netlogic/common/reset.S +++ b/arch/mips/netlogic/common/reset.S @@ -50,7 +50,6 @@ #include <asm/netlogic/xlp-hal/sys.h> #include <asm/netlogic/xlp-hal/cpucontrol.h> -#define CP0_EBASE $15 #define SYS_CPU_COHERENT_BASE CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \ SYS_CPU_NONCOHERENT_MODE * 4 @@ -92,7 +91,7 @@ * registers. On XLPII CPUs, usual cache instructions work. */ .macro xlp_flush_l1_dcache - mfc0 t0, CP0_EBASE, 0 + mfc0 t0, CP0_PRID andi t0, t0, PRID_IMP_MASK slt t1, t0, 0x1200 beqz t1, 15f @@ -171,7 +170,7 @@ FEXPORT(nlm_reset_entry) nop 1: /* Entry point on core wakeup */ - mfc0 t0, CP0_EBASE, 0 /* processor ID */ + mfc0 t0, CP0_PRID /* processor ID */ andi t0, PRID_IMP_MASK li t1, 0x1500 /* XLP 9xx */ beq t0, t1, 2f /* does not need to set coherent */ @@ -182,8 +181,8 @@ FEXPORT(nlm_reset_entry) nop /* set bit in SYS coherent register for the core */ - mfc0 t0, CP0_EBASE, 1 - mfc0 t1, CP0_EBASE, 1 + mfc0 t0, CP0_EBASE + mfc0 t1, CP0_EBASE srl t1, 5 andi t1, 0x3 /* t1 <- node */ li t2, 0x40000 @@ -232,7 +231,7 @@ EXPORT(nlm_boot_siblings) * NOTE: All GPR contents are lost after the mtcr above! */ - mfc0 v0, CP0_EBASE, 1 + mfc0 v0, CP0_EBASE andi v0, 0x3ff /* v0 <- node/core */ /* diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index 805355b0bd05..f0cc4c9de2bb 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -48,8 +48,6 @@ #include <asm/netlogic/xlp-hal/sys.h> #include <asm/netlogic/xlp-hal/cpucontrol.h> -#define CP0_EBASE $15 - .set noreorder .set noat .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ @@ -86,7 +84,7 @@ NESTED(nlm_boot_secondary_cpus, 16, sp) PTR_L gp, 0(t1) /* a0 has the processor id */ - mfc0 a0, CP0_EBASE, 1 + mfc0 a0, CP0_EBASE andi a0, 0x3ff /* a0 <- node/core */ PTR_LA t0, nlm_early_init_secondary jalr t0 diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index 80ec929747c3..25ee69489e5e 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -58,7 +58,7 @@ void nlm_node_init(int node) nodep->coremask = 1; /* node 0, boot cpu */ nodep->sysbase = nlm_get_sys_regbase(node); nodep->picbase = nlm_get_pic_regbase(node); - nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); + nodep->ebase = read_c0_ebase() & MIPS_EBASE_BASE; if (cpu_is_xlp9xx()) nodep->socbus = xlp9xx_get_socbus(node); else diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index d118b9aa7647..72ceddc9a03f 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -168,7 +168,7 @@ static void nlm_init_node(void) nodep = nlm_current_node(); nodep->picbase = nlm_mmio_base(NETLOGIC_IO_PIC_OFFSET); - nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1)); + nodep->ebase = read_c0_ebase() & MIPS_EBASE_BASE; spin_lock_init(&nodep->piclock); } diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index 3c9ec3ddca84..2f33992f6dff 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -77,7 +77,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) struct op_mips_model *lmodel = NULL; int res; - switch (current_cpu_type()) { + switch (boot_cpu_type()) { case CPU_5KC: case CPU_M14KC: case CPU_M14KEC: diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 8f988a61b7a8..45cb27469fba 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -269,11 +269,9 @@ static int mipsxx_perfcount_handler(void) return handled; } -#define M_CONFIG1_PC (1 << 4) - static inline int __n_counters(void) { - if (!(read_c0_config1() & M_CONFIG1_PC)) + if (!cpu_has_perf) return 0; if (!(read_c0_perfctrl0() & M_PERFCTL_MORE)) return 1; diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c index c2ce41ea61d7..2b5427d3f35c 100644 --- a/arch/mips/pci/fixup-lantiq.c +++ b/arch/mips/pci/fixup-lantiq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + * Copyright (C) 2012 John Crispin <john@phrozen.org> */ #include <linux/of_irq.h> diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c index e5738ee26f4f..f51e10899cc2 100644 --- a/arch/mips/pci/ops-lantiq.c +++ b/arch/mips/pci/ops-lantiq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/types.h> diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c index 28952637a862..c8994c156e2d 100644 --- a/arch/mips/pci/pci-alchemy.c +++ b/arch/mips/pci/pci-alchemy.c @@ -76,7 +76,7 @@ static void mod_wired_entry(int entry, unsigned long entrylo0, unsigned long old_ctx; /* Save old context and create impossible VPN2 value */ - old_ctx = read_c0_entryhi() & 0xff; + old_ctx = read_c0_entryhi() & MIPS_ENTRYHI_ASID; old_pagemask = read_c0_pagemask(); write_c0_index(entry); write_c0_pagemask(pagemask); diff --git a/arch/mips/pci/pci-ip32.c b/arch/mips/pci/pci-ip32.c index b1e061f7fdc7..7ae89d0c7099 100644 --- a/arch/mips/pci/pci-ip32.c +++ b/arch/mips/pci/pci-ip32.c @@ -116,7 +116,6 @@ static struct pci_controller mace_pci_controller = { .pci_ops = &mace_pci_ops, .mem_resource = &mace_pci_mem_resource, .io_resource = &mace_pci_io_resource, - .iommu = 0, .mem_offset = MACE_PCI_MEM_OFFSET, .io_offset = 0, .io_map_base = CKSEG1ADDR(MACEPCI_LOW_IO), diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index 6a15dbd085aa..b9deab17ccf2 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/types.h> diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h index 66bf6cd6be3c..0cc71253a497 100644 --- a/arch/mips/pci/pci-lantiq.h +++ b/arch/mips/pci/pci-lantiq.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #ifndef _LTQ_PCI_H__ diff --git a/arch/mips/pci/pci-mt7620.c b/arch/mips/pci/pci-mt7620.c index 1ae932c2d78b..6ce816201699 100644 --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c @@ -2,7 +2,7 @@ * Ralink MT7620A SoC PCI support * * Copyright (C) 2007-2013 Bruce Chang (Mediatek) - * Copyright (C) 2013-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013-2016 John Crispin <john@phrozen.org> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c index a245cad4372a..f2a1050168d9 100644 --- a/arch/mips/pci/pci-rt2880.c +++ b/arch/mips/pci/pci-rt2880.c @@ -1,7 +1,7 @@ /* * Ralink RT288x SoC PCI register definitions * - * Copyright (C) 2009 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009 John Crispin <john@phrozen.org> * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> * * Parts of this file are based on Ralink's 2.6.21 BSP diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index b8a0bf5766f2..f1b11f0dea2d 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -83,9 +83,6 @@ static void pcibios_scanbus(struct pci_controller *hose) LIST_HEAD(resources); struct pci_bus *bus; - if (!hose->iommu) - PCI_DMA_BUS_IS_PHYS = 1; - if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY)) next_busno = (*hose->get_busno)(); diff --git a/arch/mips/pic32/pic32mzda/time.c b/arch/mips/pic32/pic32mzda/time.c index ca6a62bb10db..62a0a78b6c64 100644 --- a/arch/mips/pic32/pic32mzda/time.c +++ b/arch/mips/pic32/pic32mzda/time.c @@ -11,13 +11,12 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ -#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clocksource.h> #include <linux/init.h> +#include <linux/irqdomain.h> #include <linux/of.h> #include <linux/of_irq.h> -#include <linux/irqdomain.h> #include <asm/time.h> @@ -58,16 +57,12 @@ unsigned int get_c0_compare_int(void) void __init plat_time_init(void) { - struct clk *clk; + unsigned long rate = pic32_get_pbclk(7); of_clk_init(NULL); - clk = clk_get_sys("cpu_clk", NULL); - if (IS_ERR(clk)) - panic("unable to get CPU clock, err=%ld", PTR_ERR(clk)); - clk_prepare_enable(clk); - pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); - mips_hpt_frequency = clk_get_rate(clk) / 2; + pr_info("CPU Clock: %ldMHz\n", rate / 1000000); + mips_hpt_frequency = rate / 2; clocksource_probe(); } diff --git a/arch/mips/pistachio/init.c b/arch/mips/pistachio/init.c index 96ba2cc9ad3e..956c92eabfab 100644 --- a/arch/mips/pistachio/init.c +++ b/arch/mips/pistachio/init.c @@ -2,6 +2,7 @@ * Pistachio platform setup * * Copyright (C) 2014 Google, Inc. + * Copyright (C) 2016 Imagination Technologies * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -9,6 +10,7 @@ */ #include <linux/init.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/of_address.h> #include <linux/of_fdt.h> @@ -24,9 +26,38 @@ #include <asm/smp-ops.h> #include <asm/traps.h> +/* + * Core revision register decoding + * Bits 23 to 20: Major rev + * Bits 15 to 8: Minor rev + * Bits 7 to 0: Maintenance rev + */ +#define PISTACHIO_CORE_REV_REG 0xB81483D0 +#define PISTACHIO_CORE_REV_A1 0x00100006 +#define PISTACHIO_CORE_REV_B0 0x00100106 + const char *get_system_type(void) { - return "IMG Pistachio SoC"; + u32 core_rev; + const char *sys_type; + + core_rev = __raw_readl((const void *)PISTACHIO_CORE_REV_REG); + + switch (core_rev) { + case PISTACHIO_CORE_REV_B0: + sys_type = "IMG Pistachio SoC (B0)"; + break; + + case PISTACHIO_CORE_REV_A1: + sys_type = "IMG Pistachio SoC (A1)"; + break; + + default: + sys_type = "IMG Pistachio SoC"; + break; + } + + return sys_type; } static void __init plat_setup_iocoherency(void) @@ -109,6 +140,8 @@ void __init prom_init(void) mips_cm_probe(); mips_cpc_probe(); register_cps_smp_ops(); + + pr_info("SoC Type: %s\n", get_system_type()); } void __init prom_free_prom_memory(void) diff --git a/arch/mips/pmcs-msp71xx/msp_setup.c b/arch/mips/pmcs-msp71xx/msp_setup.c index 9d293b3e9130..a63b73610fd4 100644 --- a/arch/mips/pmcs-msp71xx/msp_setup.c +++ b/arch/mips/pmcs-msp71xx/msp_setup.c @@ -118,7 +118,7 @@ void msp_restart(char *command) /* No chip-specific reset code, just jump to the ROM reset vector */ set_c0_status(ST0_BEV | ST0_ERL); change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); - flush_cache_all(); + __flush_cache_all(); write_c0_wired(0); __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); diff --git a/arch/mips/pnx833x/common/setup.c b/arch/mips/pnx833x/common/setup.c index 99b4d94236cc..8a7443b2535e 100644 --- a/arch/mips/pnx833x/common/setup.c +++ b/arch/mips/pnx833x/common/setup.c @@ -38,9 +38,6 @@ extern void pnx833x_machine_power_off(void); int __init plat_mem_setup(void) { - /* fake pci bus to avoid bounce buffers */ - PCI_DMA_BUS_IS_PHYS = 1; - /* set mips clock to 320MHz */ #if defined(CONFIG_SOC_PNX8335) PNX8335_WRITEFIELD(0x17, CLOCK_PLL_CPU_CTL, FREQ); diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile index 0d1795a0321e..fe3471533820 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -4,7 +4,7 @@ # Makefile for the Ralink common stuff # # Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> -# Copyright (C) 2013 John Crispin <blogic@openwrt.org> +# Copyright (C) 2013 John Crispin <john@phrozen.org> obj-y := prom.o of.o reset.o diff --git a/arch/mips/ralink/bootrom.c b/arch/mips/ralink/bootrom.c index 5403468394fb..e1fa5972a81d 100644 --- a/arch/mips/ralink/bootrom.c +++ b/arch/mips/ralink/bootrom.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/debugfs.h> diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index e46f91f971c5..3ad0b0794f7d 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2013 by John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 by John Crispin <john@phrozen.org> */ #include <linux/clockchips.h> diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c index 25c4a61779f1..ebaa7cc0e995 100644 --- a/arch/mips/ralink/clk.c +++ b/arch/mips/ralink/clk.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h index 8e7d8e618fb9..b8245d0940d6 100644 --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #ifndef _RALINK_COMMON_H__ diff --git a/arch/mips/ralink/ill_acc.c b/arch/mips/ralink/ill_acc.c index e10d10b9e82a..765d5ba98fa2 100644 --- a/arch/mips/ralink/ill_acc.c +++ b/arch/mips/ralink/ill_acc.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/interrupt.h> diff --git a/arch/mips/ralink/irq-gic.c b/arch/mips/ralink/irq-gic.c index 50d6c55ab1de..2058280450b5 100644 --- a/arch/mips/ralink/irq-gic.c +++ b/arch/mips/ralink/irq-gic.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2015 Nikolay Martynov <mar.kolya@gmail.com> - * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2015 John Crispin <john@phrozen.org> */ #include <linux/init.h> diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c index 4cf77f358395..4911c1445f1a 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/io.h> diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index 0d3d1a97895f..88b82fe21ae6 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> @@ -581,11 +581,14 @@ void prom_soc_init(struct ralink_soc_info *soc_info) (rev & CHIP_REV_ECO_MASK)); cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0); - if (is_mt76x8()) + if (is_mt76x8()) { dram_type = cfg0 & DRAM_TYPE_MT7628_MASK; - else + } else { dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) & SYSCFG0_DRAM_TYPE_MASK; + if (dram_type == SYSCFG0_DRAM_TYPE_UNKNOWN) + dram_type = SYSCFG0_DRAM_TYPE_SDRAM; + } soc_info->mem_base = MT7620_DRAM_BASE; if (is_mt76x8()) diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c index e9b9fa3e1e51..a45bbbe97ac5 100644 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2015 Nikolay Martynov <mar.kolya@gmail.com> - * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2015 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c index f9eda5d8f82c..0aa67a2d0ae6 100644 --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c @@ -5,7 +5,7 @@ * * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/io.h> diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c index 39a9142f71be..5a73c5e14221 100644 --- a/arch/mips/ralink/prom.c +++ b/arch/mips/ralink/prom.c @@ -5,7 +5,7 @@ * * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2010 Joonas Lahtinen <joonas.lahtinen@gmail.com> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/string.h> diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c index ee117c4bc4a3..64543d66e76b 100644 --- a/arch/mips/ralink/reset.c +++ b/arch/mips/ralink/reset.c @@ -5,7 +5,7 @@ * * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/pm.h> @@ -61,7 +61,7 @@ static int ralink_reset_device(struct reset_controller_dev *rcdev, return ralink_deassert_device(rcdev, id); } -static struct reset_control_ops reset_ops = { +static const struct reset_control_ops reset_ops = { .reset = ralink_reset_device, .assert = ralink_assert_device, .deassert = ralink_deassert_device, diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index 3c84166ebcb7..285796e6d75c 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index d7c4ba43a428..c8a28c4bf29e 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -7,7 +7,7 @@ * * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index fafec947b27d..4cef9162bd9b 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -7,7 +7,7 @@ * * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/kernel.h> diff --git a/arch/mips/ralink/timer-gic.c b/arch/mips/ralink/timer-gic.c index 5b4f186bcf95..069771dbec42 100644 --- a/arch/mips/ralink/timer-gic.c +++ b/arch/mips/ralink/timer-gic.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2015 Nikolay Martynov <mar.kolya@gmail.com> - * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2015 John Crispin <john@phrozen.org> */ #include <linux/init.h> diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c index 82c72a15bf75..b0343ff336c5 100644 --- a/arch/mips/ralink/timer.c +++ b/arch/mips/ralink/timer.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2013 John Crispin <john@phrozen.org> */ #include <linux/module.h> @@ -180,5 +180,5 @@ static struct platform_driver rt_timer_driver = { module_platform_driver(rt_timer_driver); MODULE_DESCRIPTION("Ralink RT2880 timer"); -MODULE_AUTHOR("John Crispin <blogic@openwrt.org"); +MODULE_AUTHOR("John Crispin <john@phrozen.org"); MODULE_LICENSE("GPL"); diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index cb9a095f5c5e..707b88441567 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -143,7 +143,8 @@ config SIBYTE_CFE_CONSOLE config SIBYTE_BUS_WATCHER bool "Support for Bus Watcher statistics" depends on SIBYTE_SB1xxx_SOC && \ - (SIBYTE_BCM112X || SIBYTE_SB1250) + (SIBYTE_BCM112X || SIBYTE_SB1250 || \ + SIBYTE_BCM1x55 || SIBYTE_BCM1x80) help Handle and keep statistics on the bus error interrupts (COR_ECC, BAD_ECC, IO_BUS). diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index ee3617c0c5e2..b369509e9753 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -50,13 +50,17 @@ quiet_cmd_vdsold = VDSO $@ cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \ -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@ +# Strip rule for the raw .so files +$(obj)/%.so.raw: OBJCOPYFLAGS := -S +$(obj)/%.so.raw: $(obj)/%.so.dbg.raw FORCE + $(call if_changed,objcopy) + hostprogs-y := genvdso quiet_cmd_genvdso = GENVDSO $@ define cmd_genvdso - cp $< $(<:%.dbg=%) && \ - $(OBJCOPY) -S $< $(<:%.dbg=%) && \ - $(obj)/genvdso $< $(<:%.dbg=%) $@ $(VDSO_NAME) + $(foreach file,$(filter %.raw,$^),cp $(file) $(file:%.raw=%) &&) \ + $(obj)/genvdso $(<:%.raw=%) $(<:%.dbg.raw=%) $@ $(VDSO_NAME) endef # @@ -66,7 +70,10 @@ endef native-abi := $(filter -mabi=%,$(KBUILD_CFLAGS)) targets += $(obj-vdso-y) -targets += vdso.lds vdso.so.dbg vdso.so vdso-image.c +targets += vdso.lds +targets += vdso.so.dbg.raw vdso.so.raw +targets += vdso.so.dbg vdso.so +targets += vdso-image.c obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o) @@ -75,10 +82,11 @@ $(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi) $(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi) -$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE +$(obj)/vdso.so.dbg.raw: $(obj)/vdso.lds $(obj-vdso) FORCE $(call if_changed,vdsold) -$(obj)/vdso-image.c: $(obj)/vdso.so.dbg $(obj)/genvdso FORCE +$(obj)/vdso-image.c: $(obj)/vdso.so.dbg.raw $(obj)/vdso.so.raw \ + $(obj)/genvdso FORCE $(call if_changed,genvdso) obj-y += vdso-image.o @@ -89,7 +97,10 @@ obj-y += vdso-image.o # Define these outside the ifdef to ensure they are picked up by clean. targets += $(obj-vdso-y:%.o=%-o32.o) -targets += vdso-o32.lds vdso-o32.so.dbg vdso-o32.so vdso-o32-image.c +targets += vdso-o32.lds +targets += vdso-o32.so.dbg.raw vdso-o32.so.raw +targets += vdso-o32.so.dbg vdso-o32.so +targets += vdso-o32-image.c ifdef CONFIG_MIPS32_O32 @@ -109,11 +120,12 @@ $(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := -mabi=32 $(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE $(call if_changed_dep,cpp_lds_S) -$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE +$(obj)/vdso-o32.so.dbg.raw: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE $(call if_changed,vdsold) $(obj)/vdso-o32-image.c: VDSO_NAME := o32 -$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg $(obj)/genvdso FORCE +$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg.raw $(obj)/vdso-o32.so.raw \ + $(obj)/genvdso FORCE $(call if_changed,genvdso) obj-y += vdso-o32-image.o @@ -125,7 +137,10 @@ endif # targets += $(obj-vdso-y:%.o=%-n32.o) -targets += vdso-n32.lds vdso-n32.so.dbg vdso-n32.so vdso-n32-image.c +targets += vdso-n32.lds +targets += vdso-n32.so.dbg.raw vdso-n32.so.raw +targets += vdso-n32.so.dbg vdso-n32.so +targets += vdso-n32-image.c ifdef CONFIG_MIPS32_N32 @@ -145,11 +160,12 @@ $(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := -mabi=n32 $(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE $(call if_changed_dep,cpp_lds_S) -$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE +$(obj)/vdso-n32.so.dbg.raw: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE $(call if_changed,vdsold) $(obj)/vdso-n32-image.c: VDSO_NAME := n32 -$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg $(obj)/genvdso FORCE +$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg.raw $(obj)/vdso-n32.so.raw \ + $(obj)/genvdso FORCE $(call if_changed,genvdso) obj-y += vdso-n32-image.o diff --git a/arch/mips/vr41xx/common/pmu.c b/arch/mips/vr41xx/common/pmu.c index d7f755833c3f..39a0db3e2b34 100644 --- a/arch/mips/vr41xx/common/pmu.c +++ b/arch/mips/vr41xx/common/pmu.c @@ -73,7 +73,7 @@ static inline void software_reset(void) default: set_c0_status(ST0_BEV | ST0_ERL); change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); - flush_cache_all(); + __flush_cache_all(); write_c0_wired(0); __asm__("jr %0"::"r"(0xbfc00000)); break; diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index f364fa4d24eb..72fe0a5a8bf3 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -30,6 +30,10 @@ #include <asm/signal.h> #endif +#ifdef CONFIG_MIPS +#include <asm/traps.h> +#endif + #define ARB_ERR_CAP_CLEAR (1 << 0) #define ARB_ERR_CAP_STATUS_TIMEOUT (1 << 12) #define ARB_ERR_CAP_STATUS_TEA (1 << 11) @@ -238,6 +242,29 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr, } #endif +#ifdef CONFIG_MIPS +static int brcmstb_bus_error_handler(struct pt_regs *regs, int is_fixup) +{ + int ret = 0; + struct brcmstb_gisb_arb_device *gdev; + u32 cap_status; + + list_for_each_entry(gdev, &brcmstb_gisb_arb_device_list, next) { + cap_status = gisb_read(gdev, ARB_ERR_CAP_STATUS); + + /* Invalid captured address, bail out */ + if (!(cap_status & ARB_ERR_CAP_STATUS_VALID)) { + is_fixup = 1; + goto out; + } + + ret |= brcmstb_gisb_arb_decode_addr(gdev, "bus error"); + } +out: + return is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; +} +#endif + static irqreturn_t brcmstb_gisb_timeout_handler(int irq, void *dev_id) { brcmstb_gisb_arb_decode_addr(dev_id, "timeout"); @@ -355,6 +382,9 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0, "imprecise external abort"); #endif +#ifdef CONFIG_MIPS + board_be_handler = brcmstb_bus_error_handler; +#endif dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n", gdev->base, timeout_irq, tea_irq); diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c index 1c543effe062..cad49bc38b3e 100644 --- a/drivers/bus/mips_cdmm.c +++ b/drivers/bus/mips_cdmm.c @@ -599,8 +599,8 @@ BUILD_PERDEV_HELPER(cpu_up) /* int mips_cdmm_cpu_up_helper(...) */ * mips_cdmm_bus_down() - Tear down the CDMM bus. * @data: Pointer to unsigned int CPU number. * - * This work_on_cpu callback function is executed on a given CPU to call the - * CDMM driver cpu_down callback for all devices on that CPU. + * This function is executed on the hotplugged CPU and calls the CDMM + * driver cpu_down callback for all devices on that CPU. */ static long mips_cdmm_bus_down(void *data) { @@ -630,7 +630,9 @@ static long mips_cdmm_bus_down(void *data) * CDMM devices on that CPU, or to call the CDMM driver cpu_up callback for all * devices already discovered on that CPU. * - * It is used during initialisation and when CPUs are brought online. + * It is used as work_on_cpu callback function during + * initialisation. When CPUs are brought online the function is + * invoked directly on the hotplugged CPU. */ static long mips_cdmm_bus_up(void *data) { @@ -677,10 +679,10 @@ static int mips_cdmm_cpu_notify(struct notifier_block *nb, switch (action & ~CPU_TASKS_FROZEN) { case CPU_ONLINE: case CPU_DOWN_FAILED: - work_on_cpu(cpu, mips_cdmm_bus_up, &cpu); + mips_cdmm_bus_up(&cpu); break; case CPU_DOWN_PREPARE: - work_on_cpu(cpu, mips_cdmm_bus_down, &cpu); + mips_cdmm_bus_down(&cpu); break; default: return NOTIFY_DONE; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c45554957499..90518cd7fc9c 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -197,6 +197,9 @@ config COMMON_CLK_PXA ---help--- Support for the Marvell PXA SoC. +config COMMON_CLK_PIC32 + def_bool COMMON_CLK && MACH_PIC32 + source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/mvebu/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 46869d696e4d..18e64bbeeaf4 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_MACH_INGENIC) += ingenic/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ +obj-$(CONFIG_MACH_PIC32) += microchip/ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ endif diff --git a/drivers/clk/microchip/Makefile b/drivers/clk/microchip/Makefile new file mode 100644 index 000000000000..2152f418106a --- /dev/null +++ b/drivers/clk/microchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_COMMON_CLK_PIC32) += clk-core.o +obj-$(CONFIG_PIC32MZDA) += clk-pic32mzda.o diff --git a/drivers/clk/microchip/clk-core.c b/drivers/clk/microchip/clk-core.c new file mode 100644 index 000000000000..ca85cea17839 --- /dev/null +++ b/drivers/clk/microchip/clk-core.c @@ -0,0 +1,1031 @@ +/* + * Purna Chandra Mandal,<purna.mandal@microchip.com> + * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <asm/mach-pic32/pic32.h> +#include <asm/traps.h> + +#include "clk-core.h" + +/* OSCCON Reg fields */ +#define OSC_CUR_MASK 0x07 +#define OSC_CUR_SHIFT 12 +#define OSC_NEW_MASK 0x07 +#define OSC_NEW_SHIFT 8 +#define OSC_SWEN BIT(0) + +/* SPLLCON Reg fields */ +#define PLL_RANGE_MASK 0x07 +#define PLL_RANGE_SHIFT 0 +#define PLL_ICLK_MASK 0x01 +#define PLL_ICLK_SHIFT 7 +#define PLL_IDIV_MASK 0x07 +#define PLL_IDIV_SHIFT 8 +#define PLL_ODIV_MASK 0x07 +#define PLL_ODIV_SHIFT 24 +#define PLL_MULT_MASK 0x7F +#define PLL_MULT_SHIFT 16 +#define PLL_MULT_MAX 128 +#define PLL_ODIV_MIN 1 +#define PLL_ODIV_MAX 5 + +/* Peripheral Bus Clock Reg Fields */ +#define PB_DIV_MASK 0x7f +#define PB_DIV_SHIFT 0 +#define PB_DIV_READY BIT(11) +#define PB_DIV_ENABLE BIT(15) +#define PB_DIV_MAX 128 +#define PB_DIV_MIN 0 + +/* Reference Oscillator Control Reg fields */ +#define REFO_SEL_MASK 0x0f +#define REFO_SEL_SHIFT 0 +#define REFO_ACTIVE BIT(8) +#define REFO_DIVSW_EN BIT(9) +#define REFO_OE BIT(12) +#define REFO_ON BIT(15) +#define REFO_DIV_SHIFT 16 +#define REFO_DIV_MASK 0x7fff + +/* Reference Oscillator Trim Register Fields */ +#define REFO_TRIM_REG 0x10 +#define REFO_TRIM_MASK 0x1ff +#define REFO_TRIM_SHIFT 23 +#define REFO_TRIM_MAX 511 + +/* Mux Slew Control Register fields */ +#define SLEW_BUSY BIT(0) +#define SLEW_DOWNEN BIT(1) +#define SLEW_UPEN BIT(2) +#define SLEW_DIV 0x07 +#define SLEW_DIV_SHIFT 8 +#define SLEW_SYSDIV 0x0f +#define SLEW_SYSDIV_SHIFT 20 + +/* Clock Poll Timeout */ +#define LOCK_TIMEOUT_US USEC_PER_MSEC + +/* SoC specific clock needed during SPLL clock rate switch */ +static struct clk_hw *pic32_sclk_hw; + +/* add instruction pipeline delay while CPU clock is in-transition. */ +#define cpu_nop5() \ +do { \ + __asm__ __volatile__("nop"); \ + __asm__ __volatile__("nop"); \ + __asm__ __volatile__("nop"); \ + __asm__ __volatile__("nop"); \ + __asm__ __volatile__("nop"); \ +} while (0) + +/* Perpheral bus clocks */ +struct pic32_periph_clk { + struct clk_hw hw; + void __iomem *ctrl_reg; + struct pic32_clk_common *core; +}; + +#define clkhw_to_pbclk(_hw) container_of(_hw, struct pic32_periph_clk, hw) + +static int pbclk_is_enabled(struct clk_hw *hw) +{ + struct pic32_periph_clk *pb = clkhw_to_pbclk(hw); + + return readl(pb->ctrl_reg) & PB_DIV_ENABLE; +} + +static int pbclk_enable(struct clk_hw *hw) +{ + struct pic32_periph_clk *pb = clkhw_to_pbclk(hw); + + writel(PB_DIV_ENABLE, PIC32_SET(pb->ctrl_reg)); + return 0; +} + +static void pbclk_disable(struct clk_hw *hw) +{ + struct pic32_periph_clk *pb = clkhw_to_pbclk(hw); + + writel(PB_DIV_ENABLE, PIC32_CLR(pb->ctrl_reg)); +} + +static unsigned long calc_best_divided_rate(unsigned long rate, + unsigned long parent_rate, + u32 divider_max, + u32 divider_min) +{ + unsigned long divided_rate, divided_rate_down, best_rate; + unsigned long div, div_up; + + /* eq. clk_rate = parent_rate / divider. + * + * Find best divider to produce closest of target divided rate. + */ + div = parent_rate / rate; + div = clamp_val(div, divider_min, divider_max); + div_up = clamp_val(div + 1, divider_min, divider_max); + + divided_rate = parent_rate / div; + divided_rate_down = parent_rate / div_up; + if (abs(rate - divided_rate_down) < abs(rate - divided_rate)) + best_rate = divided_rate_down; + else + best_rate = divided_rate; + + return best_rate; +} + +static inline u32 pbclk_read_pbdiv(struct pic32_periph_clk *pb) +{ + return ((readl(pb->ctrl_reg) >> PB_DIV_SHIFT) & PB_DIV_MASK) + 1; +} + +static unsigned long pbclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct pic32_periph_clk *pb = clkhw_to_pbclk(hw); + + return parent_rate / pbclk_read_pbdiv(pb); +} + +static long pbclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return calc_best_divided_rate(rate, *parent_rate, + PB_DIV_MAX, PB_DIV_MIN); +} + +static int pbclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct pic32_periph_clk *pb = clkhw_to_pbclk(hw); + unsigned long flags; + u32 v, div; + int err; + + /* check & wait for DIV_READY */ + err = readl_poll_timeout(pb->ctrl_reg, v, v & PB_DIV_READY, + 1, LOCK_TIMEOUT_US); + if (err) + return err; + + /* calculate clkdiv and best rate */ + div = DIV_ROUND_CLOSEST(parent_rate, rate); + + spin_lock_irqsave(&pb->core->reg_lock, flags); + + /* apply new div */ + v = readl(pb->ctrl_reg); + v &= ~PB_DIV_MASK; + v |= (div - 1); + + pic32_syskey_unlock(); + + writel(v, pb->ctrl_reg); + + spin_unlock_irqrestore(&pb->core->reg_lock, flags); + + /* wait again, for pbdivready */ + err = readl_poll_timeout_atomic(pb->ctrl_reg, v, v & PB_DIV_READY, + 1, LOCK_TIMEOUT_US); + if (err) + return err; + + /* confirm that new div is applied correctly */ + return (pbclk_read_pbdiv(pb) == div) ? 0 : -EBUSY; +} + +const struct clk_ops pic32_pbclk_ops = { + .enable = pbclk_enable, + .disable = pbclk_disable, + .is_enabled = pbclk_is_enabled, + .recalc_rate = pbclk_recalc_rate, + .round_rate = pbclk_round_rate, + .set_rate = pbclk_set_rate, +}; + +struct clk *pic32_periph_clk_register(const struct pic32_periph_clk_data *desc, + struct pic32_clk_common *core) +{ + struct pic32_periph_clk *pbclk; + struct clk *clk; + + pbclk = devm_kzalloc(core->dev, sizeof(*pbclk), GFP_KERNEL); + if (!pbclk) + return ERR_PTR(-ENOMEM); + + pbclk->hw.init = &desc->init_data; + pbclk->core = core; + pbclk->ctrl_reg = desc->ctrl_reg + core->iobase; + + clk = devm_clk_register(core->dev, &pbclk->hw); + if (IS_ERR(clk)) { + dev_err(core->dev, "%s: clk_register() failed\n", __func__); + devm_kfree(core->dev, pbclk); + } + + return clk; +} + +/* Reference oscillator operations */ +struct pic32_ref_osc { + struct clk_hw hw; + void __iomem *ctrl_reg; + const u32 *parent_map; + struct pic32_clk_common *core; +}; + +#define clkhw_to_refosc(_hw) container_of(_hw, struct pic32_ref_osc, hw) + +static int roclk_is_enabled(struct clk_hw *hw) +{ + struct pic32_ref_osc *refo = clkhw_to_refosc(hw); + + return readl(refo->ctrl_reg) & REFO_ON; +} + +static int roclk_enable(struct clk_hw *hw) +{ + struct pic32_ref_osc *refo = clkhw_to_refosc(hw); + + writel(REFO_ON | REFO_OE, PIC32_SET(refo->ctrl_reg)); + return 0; +} + +static void roclk_disable(struct clk_hw *hw) +{ + struct pic32_ref_osc *refo = clkhw_to_refosc(hw); + + writel(REFO_ON | REFO_OE, PIC32_CLR(refo->ctrl_reg)); +} + +static void roclk_init(struct clk_hw *hw) +{ + /* initialize clock in disabled state */ + roclk_disable(hw); +} + +static u8 roclk_get_parent(struct clk_hw *hw) +{ + struct pic32_ref_osc *refo = clkhw_to_refosc(hw); + u32 v, i; + + v = (readl(refo->ctrl_reg) >> REFO_SEL_SHIFT) & REFO_SEL_MASK; + + if (!refo->parent_map) + return v; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) + if (refo->parent_map[i] == v) + return i; + + return -EINVAL; +} + +static unsigned long roclk_calc_rate(unsigned long parent_rate, + u32 rodiv, u32 rotrim) +{ + u64 rate64; + + /* fout = fin / [2 * {div + (trim / 512)}] + * = fin * 512 / [1024 * div + 2 * trim] + * = fin * 256 / (512 * div + trim) + * = (fin << 8) / ((div << 9) + trim) + */ + if (rotrim) { + rodiv = (rodiv << 9) + rotrim; + rate64 = parent_rate; + rate64 <<= 8; + do_div(rate64, rodiv); + } else if (rodiv) { + rate64 = parent_rate / (rodiv << 1); + } else { + rate64 = parent_rate; + } + return rate64; +} + +static void roclk_calc_div_trim(unsigned long rate, + unsigned long parent_rate, + u32 *rodiv_p, u32 *rotrim_p) +{ + u32 div, rotrim, rodiv; + u64 frac; + + /* Find integer approximation of floating-point arithmetic. + * fout = fin / [2 * {rodiv + (rotrim / 512)}] ... (1) + * i.e. fout = fin / 2 * DIV + * whereas DIV = rodiv + (rotrim / 512) + * + * Since kernel does not perform floating-point arithmatic so + * (rotrim/512) will be zero. And DIV & rodiv will result same. + * + * ie. fout = (fin * 256) / [(512 * rodiv) + rotrim] ... from (1) + * ie. rotrim = ((fin * 256) / fout) - (512 * DIV) + */ + if (parent_rate <= rate) { + div = 0; + frac = 0; + rodiv = 0; + rotrim = 0; + } else { + div = parent_rate / (rate << 1); + frac = parent_rate; + frac <<= 8; + do_div(frac, rate); + frac -= (u64)(div << 9); + + rodiv = (div > REFO_DIV_MASK) ? REFO_DIV_MASK : div; + rotrim = (frac >= REFO_TRIM_MAX) ? REFO_TRIM_MAX : frac; + } + + if (rodiv_p) + *rodiv_p = rodiv; + + if (rotrim_p) + *rotrim_p = rotrim; +} + +static unsigned long roclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct pic32_ref_osc *refo = clkhw_to_refosc(hw); + u32 v, rodiv, rotrim; + + /* get rodiv */ + v = readl(refo->ctrl_reg); + rodiv = (v >> REFO_DIV_SHIFT) & REFO_DIV_MASK; + + /* get trim */ + v = readl(refo->ctrl_reg + REFO_TRIM_REG); + rotrim = (v >> REFO_TRIM_SHIFT) & REFO_TRIM_MASK; + + return roclk_calc_rate(parent_rate, rodiv, rotrim); +} + +static long roclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + u32 rotrim, rodiv; + + /* calculate dividers for new rate */ + roclk_calc_div_trim(rate, *parent_rate, &rodiv, &rotrim); + + /* caclulate new rate (rounding) based on new rodiv & rotrim */ + return roclk_calc_rate(*parent_rate, rodiv, rotrim); +} + +static int roclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_hw *parent_clk, *best_parent_clk = NULL; + unsigned int i, delta, best_delta = -1; + unsigned long parent_rate, best_parent_rate = 0; + unsigned long best = 0, nearest_rate; + + /* find a parent which can generate nearest clkrate >= rate */ + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + /* get parent */ + parent_clk = clk_hw_get_parent_by_index(hw, i); + if (!parent_clk) + continue; + + /* skip if parent runs slower than target rate */ + parent_rate = clk_hw_get_rate(parent_clk); + if (req->rate > parent_rate) + continue; + + nearest_rate = roclk_round_rate(hw, req->rate, &parent_rate); + delta = abs(nearest_rate - req->rate); + if ((nearest_rate >= req->rate) && (delta < best_delta)) { + best_parent_clk = parent_clk; + best_parent_rate = parent_rate; + best = nearest_rate; + best_delta = delta; + + if (delta == 0) + break; + } + } + + /* if no match found, retain old rate */ + if (!best_parent_clk) { + pr_err("%s:%s, no parent found for rate %lu.\n", + __func__, clk_hw_get_name(hw), req->rate); + return clk_hw_get_rate(hw); + } + + pr_debug("%s,rate %lu, best_parent(%s, %lu), best %lu, delta %d\n", + clk_hw_get_name(hw), req->rate, + clk_hw_get_name(best_parent_clk), best_parent_rate, + best, best_delta); + + if (req->best_parent_rate) + req->best_parent_rate = best_parent_rate; + + if (req->best_parent_hw) + req->best_parent_hw = best_parent_clk; + + return best; +} + +static int roclk_set_parent(struct clk_hw *hw, u8 index) +{ + struct pic32_ref_osc *refo = clkhw_to_refosc(hw); + unsigned long flags; + u32 v; + int err; + + if (refo->parent_map) + index = refo->parent_map[index]; + + /* wait until ACTIVE bit is zero or timeout */ + err = readl_poll_timeout(refo->ctrl_reg, v, !(v & REFO_ACTIVE), + 1, LOCK_TIMEOUT_US); + if (err) { + pr_err("%s: poll failed, clk active\n", clk_hw_get_name(hw)); + return err; + } + + spin_lock_irqsave(&refo->core->reg_lock, flags); + + pic32_syskey_unlock(); + + /* calculate & apply new */ + v = readl(refo->ctrl_reg); + v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT); + v |= index << REFO_SEL_SHIFT; + + writel(v, refo->ctrl_reg); + + spin_unlock_irqrestore(&refo->core->reg_lock, flags); + + return 0; +} + +static int roclk_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index) +{ + struct pic32_ref_osc *refo = clkhw_to_refosc(hw); + unsigned long flags; + u32 trim, rodiv, v; + int err; + + /* calculate new rodiv & rotrim for new rate */ + roclk_calc_div_trim(rate, parent_rate, &rodiv, &trim); + + pr_debug("parent_rate = %lu, rate = %lu, div = %d, trim = %d\n", + parent_rate, rate, rodiv, trim); + + /* wait till source change is active */ + err = readl_poll_timeout(refo->ctrl_reg, v, + !(v & (REFO_ACTIVE | REFO_DIVSW_EN)), + 1, LOCK_TIMEOUT_US); + if (err) { + pr_err("%s: poll timedout, clock is still active\n", __func__); + return err; + } + + spin_lock_irqsave(&refo->core->reg_lock, flags); + v = readl(refo->ctrl_reg); + + pic32_syskey_unlock(); + + /* apply parent, if required */ + if (refo->parent_map) + index = refo->parent_map[index]; + + v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT); + v |= index << REFO_SEL_SHIFT; + + /* apply RODIV */ + v &= ~(REFO_DIV_MASK << REFO_DIV_SHIFT); + v |= rodiv << REFO_DIV_SHIFT; + writel(v, refo->ctrl_reg); + + /* apply ROTRIM */ + v = readl(refo->ctrl_reg + REFO_TRIM_REG); + v &= ~(REFO_TRIM_MASK << REFO_TRIM_SHIFT); + v |= trim << REFO_TRIM_SHIFT; + writel(v, refo->ctrl_reg + REFO_TRIM_REG); + + /* enable & activate divider switching */ + writel(REFO_ON | REFO_DIVSW_EN, PIC32_SET(refo->ctrl_reg)); + + /* wait till divswen is in-progress */ + err = readl_poll_timeout_atomic(refo->ctrl_reg, v, !(v & REFO_DIVSW_EN), + 1, LOCK_TIMEOUT_US); + /* leave the clk gated as it was */ + writel(REFO_ON, PIC32_CLR(refo->ctrl_reg)); + + spin_unlock_irqrestore(&refo->core->reg_lock, flags); + + return err; +} + +static int roclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + u8 index = roclk_get_parent(hw); + + return roclk_set_rate_and_parent(hw, rate, parent_rate, index); +} + +const struct clk_ops pic32_roclk_ops = { + .enable = roclk_enable, + .disable = roclk_disable, + .is_enabled = roclk_is_enabled, + .get_parent = roclk_get_parent, + .set_parent = roclk_set_parent, + .determine_rate = roclk_determine_rate, + .recalc_rate = roclk_recalc_rate, + .set_rate_and_parent = roclk_set_rate_and_parent, + .set_rate = roclk_set_rate, + .init = roclk_init, +}; + +struct clk *pic32_refo_clk_register(const struct pic32_ref_osc_data *data, + struct pic32_clk_common *core) +{ + struct pic32_ref_osc *refo; + struct clk *clk; + + refo = devm_kzalloc(core->dev, sizeof(*refo), GFP_KERNEL); + if (!refo) + return ERR_PTR(-ENOMEM); + + refo->core = core; + refo->hw.init = &data->init_data; + refo->ctrl_reg = data->ctrl_reg + core->iobase; + refo->parent_map = data->parent_map; + + clk = devm_clk_register(core->dev, &refo->hw); + if (IS_ERR(clk)) + dev_err(core->dev, "%s: clk_register() failed\n", __func__); + + return clk; +} + +struct pic32_sys_pll { + struct clk_hw hw; + void __iomem *ctrl_reg; + void __iomem *status_reg; + u32 lock_mask; + u32 idiv; /* PLL iclk divider, treated fixed */ + struct pic32_clk_common *core; +}; + +#define clkhw_to_spll(_hw) container_of(_hw, struct pic32_sys_pll, hw) + +static inline u32 spll_odiv_to_divider(u32 odiv) +{ + odiv = clamp_val(odiv, PLL_ODIV_MIN, PLL_ODIV_MAX); + + return 1 << odiv; +} + +static unsigned long spll_calc_mult_div(struct pic32_sys_pll *pll, + unsigned long rate, + unsigned long parent_rate, + u32 *mult_p, u32 *odiv_p) +{ + u32 mul, div, best_mul = 1, best_div = 1; + unsigned long new_rate, best_rate = rate; + unsigned int best_delta = -1, delta, match_found = 0; + u64 rate64; + + parent_rate /= pll->idiv; + + for (mul = 1; mul <= PLL_MULT_MAX; mul++) { + for (div = PLL_ODIV_MIN; div <= PLL_ODIV_MAX; div++) { + rate64 = parent_rate; + rate64 *= mul; + do_div(rate64, 1 << div); + new_rate = rate64; + delta = abs(rate - new_rate); + if ((new_rate >= rate) && (delta < best_delta)) { + best_delta = delta; + best_rate = new_rate; + best_mul = mul; + best_div = div; + match_found = 1; + } + } + } + + if (!match_found) { + pr_warn("spll: no match found\n"); + return 0; + } + + pr_debug("rate %lu, par_rate %lu/mult %u, div %u, best_rate %lu\n", + rate, parent_rate, best_mul, best_div, best_rate); + + if (mult_p) + *mult_p = best_mul - 1; + + if (odiv_p) + *odiv_p = best_div; + + return best_rate; +} + +static unsigned long spll_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct pic32_sys_pll *pll = clkhw_to_spll(hw); + unsigned long pll_in_rate; + u32 mult, odiv, div, v; + u64 rate64; + + v = readl(pll->ctrl_reg); + odiv = ((v >> PLL_ODIV_SHIFT) & PLL_ODIV_MASK); + mult = ((v >> PLL_MULT_SHIFT) & PLL_MULT_MASK) + 1; + div = spll_odiv_to_divider(odiv); + + /* pll_in_rate = parent_rate / idiv + * pll_out_rate = pll_in_rate * mult / div; + */ + pll_in_rate = parent_rate / pll->idiv; + rate64 = pll_in_rate; + rate64 *= mult; + do_div(rate64, div); + + return rate64; +} + +static long spll_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct pic32_sys_pll *pll = clkhw_to_spll(hw); + + return spll_calc_mult_div(pll, rate, *parent_rate, NULL, NULL); +} + +static int spll_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct pic32_sys_pll *pll = clkhw_to_spll(hw); + unsigned long ret, flags; + u32 mult, odiv, v; + int err; + + ret = spll_calc_mult_div(pll, rate, parent_rate, &mult, &odiv); + if (!ret) + return -EINVAL; + + /* + * We can't change SPLL counters when it is in-active use + * by SYSCLK. So check before applying new counters/rate. + */ + + /* Is spll_clk active parent of sys_clk ? */ + if (unlikely(clk_hw_get_parent(pic32_sclk_hw) == hw)) { + pr_err("%s: failed, clk in-use\n", __func__); + return -EBUSY; + } + + spin_lock_irqsave(&pll->core->reg_lock, flags); + + /* apply new multiplier & divisor */ + v = readl(pll->ctrl_reg); + v &= ~(PLL_MULT_MASK << PLL_MULT_SHIFT); + v &= ~(PLL_ODIV_MASK << PLL_ODIV_SHIFT); + v |= (mult << PLL_MULT_SHIFT) | (odiv << PLL_ODIV_SHIFT); + + /* sys unlock before write */ + pic32_syskey_unlock(); + + writel(v, pll->ctrl_reg); + cpu_relax(); + + /* insert few nops (5-stage) to ensure CPU does not hang */ + cpu_nop5(); + cpu_nop5(); + + /* Wait until PLL is locked (maximum 100 usecs). */ + err = readl_poll_timeout_atomic(pll->status_reg, v, + v & pll->lock_mask, 1, 100); + spin_unlock_irqrestore(&pll->core->reg_lock, flags); + + return err; +} + +/* SPLL clock operation */ +const struct clk_ops pic32_spll_ops = { + .recalc_rate = spll_clk_recalc_rate, + .round_rate = spll_clk_round_rate, + .set_rate = spll_clk_set_rate, +}; + +struct clk *pic32_spll_clk_register(const struct pic32_sys_pll_data *data, + struct pic32_clk_common *core) +{ + struct pic32_sys_pll *spll; + struct clk *clk; + + spll = devm_kzalloc(core->dev, sizeof(*spll), GFP_KERNEL); + if (!spll) + return ERR_PTR(-ENOMEM); + + spll->core = core; + spll->hw.init = &data->init_data; + spll->ctrl_reg = data->ctrl_reg + core->iobase; + spll->status_reg = data->status_reg + core->iobase; + spll->lock_mask = data->lock_mask; + + /* cache PLL idiv; PLL driver uses it as constant.*/ + spll->idiv = (readl(spll->ctrl_reg) >> PLL_IDIV_SHIFT) & PLL_IDIV_MASK; + spll->idiv += 1; + + clk = devm_clk_register(core->dev, &spll->hw); + if (IS_ERR(clk)) + dev_err(core->dev, "sys_pll: clk_register() failed\n"); + + return clk; +} + +/* System mux clock(aka SCLK) */ + +struct pic32_sys_clk { + struct clk_hw hw; + void __iomem *mux_reg; + void __iomem *slew_reg; + u32 slew_div; + const u32 *parent_map; + struct pic32_clk_common *core; +}; + +#define clkhw_to_sys_clk(_hw) container_of(_hw, struct pic32_sys_clk, hw) + +static unsigned long sclk_get_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw); + u32 div; + + div = (readl(sclk->slew_reg) >> SLEW_SYSDIV_SHIFT) & SLEW_SYSDIV; + div += 1; /* sys-div to divider */ + + return parent_rate / div; +} + +static long sclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return calc_best_divided_rate(rate, *parent_rate, SLEW_SYSDIV, 1); +} + +static int sclk_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw); + unsigned long flags; + u32 v, div; + int err; + + div = parent_rate / rate; + + spin_lock_irqsave(&sclk->core->reg_lock, flags); + + /* apply new div */ + v = readl(sclk->slew_reg); + v &= ~(SLEW_SYSDIV << SLEW_SYSDIV_SHIFT); + v |= (div - 1) << SLEW_SYSDIV_SHIFT; + + pic32_syskey_unlock(); + + writel(v, sclk->slew_reg); + + /* wait until BUSY is cleared */ + err = readl_poll_timeout_atomic(sclk->slew_reg, v, + !(v & SLEW_BUSY), 1, LOCK_TIMEOUT_US); + + spin_unlock_irqrestore(&sclk->core->reg_lock, flags); + + return err; +} + +static u8 sclk_get_parent(struct clk_hw *hw) +{ + struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw); + u32 i, v; + + v = (readl(sclk->mux_reg) >> OSC_CUR_SHIFT) & OSC_CUR_MASK; + + if (!sclk->parent_map) + return v; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) + if (sclk->parent_map[i] == v) + return i; + return -EINVAL; +} + +static int sclk_set_parent(struct clk_hw *hw, u8 index) +{ + struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw); + unsigned long flags; + u32 nosc, cosc, v; + int err; + + spin_lock_irqsave(&sclk->core->reg_lock, flags); + + /* find new_osc */ + nosc = sclk->parent_map ? sclk->parent_map[index] : index; + + /* set new parent */ + v = readl(sclk->mux_reg); + v &= ~(OSC_NEW_MASK << OSC_NEW_SHIFT); + v |= nosc << OSC_NEW_SHIFT; + + pic32_syskey_unlock(); + + writel(v, sclk->mux_reg); + + /* initate switch */ + writel(OSC_SWEN, PIC32_SET(sclk->mux_reg)); + cpu_relax(); + + /* add nop to flush pipeline (as cpu_clk is in-flux) */ + cpu_nop5(); + + /* wait for SWEN bit to clear */ + err = readl_poll_timeout_atomic(sclk->slew_reg, v, + !(v & OSC_SWEN), 1, LOCK_TIMEOUT_US); + + spin_unlock_irqrestore(&sclk->core->reg_lock, flags); + + /* + * SCLK clock-switching logic might reject a clock switching request + * if pre-requisites (like new clk_src not present or unstable) are + * not met. + * So confirm before claiming success. + */ + cosc = (readl(sclk->mux_reg) >> OSC_CUR_SHIFT) & OSC_CUR_MASK; + if (cosc != nosc) { + pr_err("%s: err, failed to set_parent() to %d, current %d\n", + clk_hw_get_name(hw), nosc, cosc); + err = -EBUSY; + } + + return err; +} + +static void sclk_init(struct clk_hw *hw) +{ + struct pic32_sys_clk *sclk = clkhw_to_sys_clk(hw); + unsigned long flags; + u32 v; + + /* Maintain reference to this clk, required in spll_clk_set_rate() */ + pic32_sclk_hw = hw; + + /* apply slew divider on both up and down scaling */ + if (sclk->slew_div) { + spin_lock_irqsave(&sclk->core->reg_lock, flags); + v = readl(sclk->slew_reg); + v &= ~(SLEW_DIV << SLEW_DIV_SHIFT); + v |= sclk->slew_div << SLEW_DIV_SHIFT; + v |= SLEW_DOWNEN | SLEW_UPEN; + writel(v, sclk->slew_reg); + spin_unlock_irqrestore(&sclk->core->reg_lock, flags); + } +} + +/* sclk with post-divider */ +const struct clk_ops pic32_sclk_ops = { + .get_parent = sclk_get_parent, + .set_parent = sclk_set_parent, + .round_rate = sclk_round_rate, + .set_rate = sclk_set_rate, + .recalc_rate = sclk_get_rate, + .init = sclk_init, + .determine_rate = __clk_mux_determine_rate, +}; + +/* sclk with no slew and no post-divider */ +const struct clk_ops pic32_sclk_no_div_ops = { + .get_parent = sclk_get_parent, + .set_parent = sclk_set_parent, + .init = sclk_init, + .determine_rate = __clk_mux_determine_rate, +}; + +struct clk *pic32_sys_clk_register(const struct pic32_sys_clk_data *data, + struct pic32_clk_common *core) +{ + struct pic32_sys_clk *sclk; + struct clk *clk; + + sclk = devm_kzalloc(core->dev, sizeof(*sclk), GFP_KERNEL); + if (!sclk) + return ERR_PTR(-ENOMEM); + + sclk->core = core; + sclk->hw.init = &data->init_data; + sclk->mux_reg = data->mux_reg + core->iobase; + sclk->slew_reg = data->slew_reg + core->iobase; + sclk->slew_div = data->slew_div; + sclk->parent_map = data->parent_map; + + clk = devm_clk_register(core->dev, &sclk->hw); + if (IS_ERR(clk)) + dev_err(core->dev, "%s: clk register failed\n", __func__); + + return clk; +} + +/* secondary oscillator */ +struct pic32_sec_osc { + struct clk_hw hw; + void __iomem *enable_reg; + void __iomem *status_reg; + u32 enable_mask; + u32 status_mask; + unsigned long fixed_rate; + struct pic32_clk_common *core; +}; + +#define clkhw_to_sosc(_hw) container_of(_hw, struct pic32_sec_osc, hw) +static int sosc_clk_enable(struct clk_hw *hw) +{ + struct pic32_sec_osc *sosc = clkhw_to_sosc(hw); + u32 v; + + /* enable SOSC */ + pic32_syskey_unlock(); + writel(sosc->enable_mask, PIC32_SET(sosc->enable_reg)); + + /* wait till warm-up period expires or ready-status is updated */ + return readl_poll_timeout_atomic(sosc->status_reg, v, + v & sosc->status_mask, 1, 100); +} + +static void sosc_clk_disable(struct clk_hw *hw) +{ + struct pic32_sec_osc *sosc = clkhw_to_sosc(hw); + + pic32_syskey_unlock(); + writel(sosc->enable_mask, PIC32_CLR(sosc->enable_reg)); +} + +static int sosc_clk_is_enabled(struct clk_hw *hw) +{ + struct pic32_sec_osc *sosc = clkhw_to_sosc(hw); + u32 enabled, ready; + + /* check enabled and ready status */ + enabled = readl(sosc->enable_reg) & sosc->enable_mask; + ready = readl(sosc->status_reg) & sosc->status_mask; + + return enabled && ready; +} + +static unsigned long sosc_clk_calc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return clkhw_to_sosc(hw)->fixed_rate; +} + +const struct clk_ops pic32_sosc_ops = { + .enable = sosc_clk_enable, + .disable = sosc_clk_disable, + .is_enabled = sosc_clk_is_enabled, + .recalc_rate = sosc_clk_calc_rate, +}; + +struct clk *pic32_sosc_clk_register(const struct pic32_sec_osc_data *data, + struct pic32_clk_common *core) +{ + struct pic32_sec_osc *sosc; + + sosc = devm_kzalloc(core->dev, sizeof(*sosc), GFP_KERNEL); + if (!sosc) + return ERR_PTR(-ENOMEM); + + sosc->core = core; + sosc->hw.init = &data->init_data; + sosc->fixed_rate = data->fixed_rate; + sosc->enable_mask = data->enable_mask; + sosc->status_mask = data->status_mask; + sosc->enable_reg = data->enable_reg + core->iobase; + sosc->status_reg = data->status_reg + core->iobase; + + return devm_clk_register(core->dev, &sosc->hw); +} diff --git a/drivers/clk/microchip/clk-core.h b/drivers/clk/microchip/clk-core.h new file mode 100644 index 000000000000..856664277a29 --- /dev/null +++ b/drivers/clk/microchip/clk-core.h @@ -0,0 +1,84 @@ +/* + * Purna Chandra Mandal,<purna.mandal@microchip.com> + * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#ifndef __MICROCHIP_CLK_PIC32_H_ +#define __MICROCHIP_CLK_PIC32_H_ + +#include <linux/clk-provider.h> + +/* PIC32 clock data */ +struct pic32_clk_common { + struct device *dev; + void __iomem *iobase; + spinlock_t reg_lock; /* clock lock */ +}; + +/* System PLL clock */ +struct pic32_sys_pll_data { + struct clk_init_data init_data; + const u32 ctrl_reg; + const u32 status_reg; + const u32 lock_mask; +}; + +/* System clock */ +struct pic32_sys_clk_data { + struct clk_init_data init_data; + const u32 mux_reg; + const u32 slew_reg; + const u32 *parent_map; + const u32 slew_div; +}; + +/* Reference Oscillator clock */ +struct pic32_ref_osc_data { + struct clk_init_data init_data; + const u32 ctrl_reg; + const u32 *parent_map; +}; + +/* Peripheral Bus clock */ +struct pic32_periph_clk_data { + struct clk_init_data init_data; + const u32 ctrl_reg; +}; + +/* External Secondary Oscillator clock */ +struct pic32_sec_osc_data { + struct clk_init_data init_data; + const u32 enable_reg; + const u32 status_reg; + const u32 enable_mask; + const u32 status_mask; + const unsigned long fixed_rate; +}; + +extern const struct clk_ops pic32_pbclk_ops; +extern const struct clk_ops pic32_sclk_ops; +extern const struct clk_ops pic32_sclk_no_div_ops; +extern const struct clk_ops pic32_spll_ops; +extern const struct clk_ops pic32_roclk_ops; +extern const struct clk_ops pic32_sosc_ops; + +struct clk *pic32_periph_clk_register(const struct pic32_periph_clk_data *data, + struct pic32_clk_common *core); +struct clk *pic32_refo_clk_register(const struct pic32_ref_osc_data *data, + struct pic32_clk_common *core); +struct clk *pic32_sys_clk_register(const struct pic32_sys_clk_data *data, + struct pic32_clk_common *core); +struct clk *pic32_spll_clk_register(const struct pic32_sys_pll_data *data, + struct pic32_clk_common *core); +struct clk *pic32_sosc_clk_register(const struct pic32_sec_osc_data *data, + struct pic32_clk_common *core); + +#endif /* __MICROCHIP_CLK_PIC32_H_*/ diff --git a/drivers/clk/microchip/clk-pic32mzda.c b/drivers/clk/microchip/clk-pic32mzda.c new file mode 100644 index 000000000000..020a29acc5b0 --- /dev/null +++ b/drivers/clk/microchip/clk-pic32mzda.c @@ -0,0 +1,275 @@ +/* + * Purna Chandra Mandal,<purna.mandal@microchip.com> + * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include <dt-bindings/clock/microchip,pic32-clock.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <asm/traps.h> + +#include "clk-core.h" + +/* FRC Postscaler */ +#define OSC_FRCDIV_MASK 0x07 +#define OSC_FRCDIV_SHIFT 24 + +/* SPLL fields */ +#define PLL_ICLK_MASK 0x01 +#define PLL_ICLK_SHIFT 7 + +#define DECLARE_PERIPHERAL_CLOCK(__clk_name, __reg, __flags) \ + { \ + .ctrl_reg = (__reg), \ + .init_data = { \ + .name = (__clk_name), \ + .parent_names = (const char *[]) { \ + "sys_clk" \ + }, \ + .num_parents = 1, \ + .ops = &pic32_pbclk_ops, \ + .flags = (__flags), \ + }, \ + } + +#define DECLARE_REFO_CLOCK(__clkid, __reg) \ + { \ + .ctrl_reg = (__reg), \ + .init_data = { \ + .name = "refo" #__clkid "_clk", \ + .parent_names = (const char *[]) { \ + "sys_clk", "pb1_clk", "posc_clk", \ + "frc_clk", "lprc_clk", "sosc_clk", \ + "sys_pll", "refi" #__clkid "_clk", \ + "bfrc_clk", \ + }, \ + .num_parents = 9, \ + .flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE,\ + .ops = &pic32_roclk_ops, \ + }, \ + .parent_map = (const u32[]) { \ + 0, 1, 2, 3, 4, 5, 7, 8, 9 \ + }, \ + } + +static const struct pic32_ref_osc_data ref_clks[] = { + DECLARE_REFO_CLOCK(1, 0x80), + DECLARE_REFO_CLOCK(2, 0xa0), + DECLARE_REFO_CLOCK(3, 0xc0), + DECLARE_REFO_CLOCK(4, 0xe0), + DECLARE_REFO_CLOCK(5, 0x100), +}; + +static const struct pic32_periph_clk_data periph_clocks[] = { + DECLARE_PERIPHERAL_CLOCK("pb1_clk", 0x140, 0), + DECLARE_PERIPHERAL_CLOCK("pb2_clk", 0x150, CLK_IGNORE_UNUSED), + DECLARE_PERIPHERAL_CLOCK("pb3_clk", 0x160, 0), + DECLARE_PERIPHERAL_CLOCK("pb4_clk", 0x170, 0), + DECLARE_PERIPHERAL_CLOCK("pb5_clk", 0x180, 0), + DECLARE_PERIPHERAL_CLOCK("pb6_clk", 0x190, 0), + DECLARE_PERIPHERAL_CLOCK("cpu_clk", 0x1a0, CLK_IGNORE_UNUSED), +}; + +static const struct pic32_sys_clk_data sys_mux_clk = { + .slew_reg = 0x1c0, + .slew_div = 2, /* step of div_4 -> div_2 -> no_div */ + .init_data = { + .name = "sys_clk", + .parent_names = (const char *[]) { + "frcdiv_clk", "sys_pll", "posc_clk", + "sosc_clk", "lprc_clk", "frcdiv_clk", + }, + .num_parents = 6, + .ops = &pic32_sclk_ops, + }, + .parent_map = (const u32[]) { + 0, 1, 2, 4, 5, 7, + }, +}; + +static const struct pic32_sys_pll_data sys_pll = { + .ctrl_reg = 0x020, + .status_reg = 0x1d0, + .lock_mask = BIT(7), + .init_data = { + .name = "sys_pll", + .parent_names = (const char *[]) { + "spll_mux_clk" + }, + .num_parents = 1, + .ops = &pic32_spll_ops, + }, +}; + +static const struct pic32_sec_osc_data sosc_clk = { + .status_reg = 0x1d0, + .enable_mask = BIT(1), + .status_mask = BIT(4), + .init_data = { + .name = "sosc_clk", + .parent_names = NULL, + .ops = &pic32_sosc_ops, + }, +}; + +static int pic32mzda_critical_clks[] = { + PB2CLK, PB7CLK +}; + +/* PIC32MZDA clock data */ +struct pic32mzda_clk_data { + struct clk *clks[MAXCLKS]; + struct pic32_clk_common core; + struct clk_onecell_data onecell_data; + struct notifier_block failsafe_notifier; +}; + +static int pic32_fscm_nmi(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct pic32mzda_clk_data *cd; + + cd = container_of(nb, struct pic32mzda_clk_data, failsafe_notifier); + + /* SYSCLK is now running from BFRCCLK. Report clock failure. */ + if (readl(cd->core.iobase) & BIT(2)) + pr_alert("pic32-clk: FSCM detected clk failure.\n"); + + /* TODO: detect reason of failure and recover accordingly */ + + return NOTIFY_OK; +} + +static int pic32mzda_clk_probe(struct platform_device *pdev) +{ + const char *const pll_mux_parents[] = {"posc_clk", "frc_clk"}; + struct device_node *np = pdev->dev.of_node; + struct pic32mzda_clk_data *cd; + struct pic32_clk_common *core; + struct clk *pll_mux_clk, *clk; + struct clk **clks; + int nr_clks, i, ret; + + cd = devm_kzalloc(&pdev->dev, sizeof(*cd), GFP_KERNEL); + if (!cd) + return -ENOMEM; + + core = &cd->core; + core->iobase = of_io_request_and_map(np, 0, of_node_full_name(np)); + if (IS_ERR(core->iobase)) { + dev_err(&pdev->dev, "pic32-clk: failed to map registers\n"); + return PTR_ERR(core->iobase); + } + + spin_lock_init(&core->reg_lock); + core->dev = &pdev->dev; + clks = &cd->clks[0]; + + /* register fixed rate clocks */ + clks[POSCCLK] = clk_register_fixed_rate(&pdev->dev, "posc_clk", NULL, + CLK_IS_ROOT, 24000000); + clks[FRCCLK] = clk_register_fixed_rate(&pdev->dev, "frc_clk", NULL, + CLK_IS_ROOT, 8000000); + clks[BFRCCLK] = clk_register_fixed_rate(&pdev->dev, "bfrc_clk", NULL, + CLK_IS_ROOT, 8000000); + clks[LPRCCLK] = clk_register_fixed_rate(&pdev->dev, "lprc_clk", NULL, + CLK_IS_ROOT, 32000); + clks[UPLLCLK] = clk_register_fixed_rate(&pdev->dev, "usbphy_clk", NULL, + CLK_IS_ROOT, 24000000); + /* fixed rate (optional) clock */ + if (of_find_property(np, "microchip,pic32mzda-sosc", NULL)) { + pr_info("pic32-clk: dt requests SOSC.\n"); + clks[SOSCCLK] = pic32_sosc_clk_register(&sosc_clk, core); + } + /* divider clock */ + clks[FRCDIVCLK] = clk_register_divider(&pdev->dev, "frcdiv_clk", + "frc_clk", 0, + core->iobase, + OSC_FRCDIV_SHIFT, + OSC_FRCDIV_MASK, + CLK_DIVIDER_POWER_OF_TWO, + &core->reg_lock); + /* PLL ICLK mux */ + pll_mux_clk = clk_register_mux(&pdev->dev, "spll_mux_clk", + pll_mux_parents, 2, 0, + core->iobase + 0x020, + PLL_ICLK_SHIFT, 1, 0, &core->reg_lock); + if (IS_ERR(pll_mux_clk)) + pr_err("spll_mux_clk: clk register failed\n"); + + /* PLL */ + clks[PLLCLK] = pic32_spll_clk_register(&sys_pll, core); + /* SYSTEM clock */ + clks[SCLK] = pic32_sys_clk_register(&sys_mux_clk, core); + /* Peripheral bus clocks */ + for (nr_clks = PB1CLK, i = 0; nr_clks <= PB7CLK; i++, nr_clks++) + clks[nr_clks] = pic32_periph_clk_register(&periph_clocks[i], + core); + /* Reference oscillator clock */ + for (nr_clks = REF1CLK, i = 0; nr_clks <= REF5CLK; i++, nr_clks++) + clks[nr_clks] = pic32_refo_clk_register(&ref_clks[i], core); + + /* register clkdev */ + for (i = 0; i < MAXCLKS; i++) { + if (IS_ERR(clks[i])) + continue; + clk_register_clkdev(clks[i], NULL, __clk_get_name(clks[i])); + } + + /* register clock provider */ + cd->onecell_data.clks = clks; + cd->onecell_data.clk_num = MAXCLKS; + ret = of_clk_add_provider(np, of_clk_src_onecell_get, + &cd->onecell_data); + if (ret) + return ret; + + /* force enable critical clocks */ + for (i = 0; i < ARRAY_SIZE(pic32mzda_critical_clks); i++) { + clk = clks[pic32mzda_critical_clks[i]]; + if (clk_prepare_enable(clk)) + dev_err(&pdev->dev, "clk_prepare_enable(%s) failed\n", + __clk_get_name(clk)); + } + + /* register NMI for failsafe clock monitor */ + cd->failsafe_notifier.notifier_call = pic32_fscm_nmi; + return register_nmi_notifier(&cd->failsafe_notifier); +} + +static const struct of_device_id pic32mzda_clk_match_table[] = { + { .compatible = "microchip,pic32mzda-clk", }, + { } +}; +MODULE_DEVICE_TABLE(of, pic32mzda_clk_match_table); + +static struct platform_driver pic32mzda_clk_driver = { + .probe = pic32mzda_clk_probe, + .driver = { + .name = "clk-pic32mzda", + .of_match_table = pic32mzda_clk_match_table, + }, +}; + +static int __init microchip_pic32mzda_clk_init(void) +{ + return platform_driver_register(&pic32mzda_clk_driver); +} +core_initcall(microchip_pic32mzda_clk_init); + +MODULE_DESCRIPTION("Microchip PIC32MZDA Clock Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:clk-pic32mzda"); diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index e1eb11ee3570..0a9b6a093646 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -102,7 +102,7 @@ obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o -obj-$(CONFIG_LOONGSON1_CPUFREQ) += ls1x-cpufreq.o +obj-$(CONFIG_LOONGSON1_CPUFREQ) += loongson1-cpufreq.o obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o diff --git a/drivers/cpufreq/ls1x-cpufreq.c b/drivers/cpufreq/loongson1-cpufreq.c index 262581b3318d..be89416e2358 100644 --- a/drivers/cpufreq/ls1x-cpufreq.c +++ b/drivers/cpufreq/loongson1-cpufreq.c @@ -1,7 +1,7 @@ /* * CPU Frequency Scaling for Loongson 1 SoC * - * Copyright (C) 2014 Zhang, Keguang <keguang.zhang@gmail.com> + * Copyright (C) 2014-2016 Zhang, Keguang <keguang.zhang@gmail.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -20,7 +20,7 @@ #include <cpufreq.h> #include <loongson1.h> -static struct { +struct ls1x_cpufreq { struct device *dev; struct clk *clk; /* CPU clk */ struct clk *mux_clk; /* MUX of CPU clk */ @@ -28,7 +28,9 @@ static struct { struct clk *osc_clk; /* OSC clk */ unsigned int max_freq; unsigned int min_freq; -} ls1x_cpufreq; +}; + +static struct ls1x_cpufreq *cpufreq; static int ls1x_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) @@ -46,6 +48,7 @@ static struct notifier_block ls1x_cpufreq_notifier_block = { static int ls1x_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) { + struct device *cpu_dev = get_cpu_device(policy->cpu); unsigned int old_freq, new_freq; old_freq = policy->cur; @@ -60,53 +63,49 @@ static int ls1x_cpufreq_target(struct cpufreq_policy *policy, * - Reparent CPU clk back to CPU DIV clk */ - dev_dbg(ls1x_cpufreq.dev, "%u KHz --> %u KHz\n", old_freq, new_freq); - clk_set_parent(policy->clk, ls1x_cpufreq.osc_clk); + clk_set_parent(policy->clk, cpufreq->osc_clk); __raw_writel(__raw_readl(LS1X_CLK_PLL_DIV) | RST_CPU_EN | RST_CPU, LS1X_CLK_PLL_DIV); __raw_writel(__raw_readl(LS1X_CLK_PLL_DIV) & ~(RST_CPU_EN | RST_CPU), LS1X_CLK_PLL_DIV); - clk_set_rate(ls1x_cpufreq.mux_clk, new_freq * 1000); - clk_set_parent(policy->clk, ls1x_cpufreq.mux_clk); + clk_set_rate(cpufreq->mux_clk, new_freq * 1000); + clk_set_parent(policy->clk, cpufreq->mux_clk); + dev_dbg(cpu_dev, "%u KHz --> %u KHz\n", old_freq, new_freq); return 0; } static int ls1x_cpufreq_init(struct cpufreq_policy *policy) { + struct device *cpu_dev = get_cpu_device(policy->cpu); struct cpufreq_frequency_table *freq_tbl; unsigned int pll_freq, freq; int steps, i, ret; - pll_freq = clk_get_rate(ls1x_cpufreq.pll_clk) / 1000; + pll_freq = clk_get_rate(cpufreq->pll_clk) / 1000; steps = 1 << DIV_CPU_WIDTH; - freq_tbl = kzalloc(sizeof(*freq_tbl) * steps, GFP_KERNEL); - if (!freq_tbl) { - dev_err(ls1x_cpufreq.dev, - "failed to alloc cpufreq_frequency_table\n"); - ret = -ENOMEM; - goto out; - } + freq_tbl = kcalloc(steps, sizeof(*freq_tbl), GFP_KERNEL); + if (!freq_tbl) + return -ENOMEM; for (i = 0; i < (steps - 1); i++) { freq = pll_freq / (i + 1); - if ((freq < ls1x_cpufreq.min_freq) || - (freq > ls1x_cpufreq.max_freq)) + if ((freq < cpufreq->min_freq) || (freq > cpufreq->max_freq)) freq_tbl[i].frequency = CPUFREQ_ENTRY_INVALID; else freq_tbl[i].frequency = freq; - dev_dbg(ls1x_cpufreq.dev, + dev_dbg(cpu_dev, "cpufreq table: index %d: frequency %d\n", i, freq_tbl[i].frequency); } freq_tbl[i].frequency = CPUFREQ_TABLE_END; - policy->clk = ls1x_cpufreq.clk; + policy->clk = cpufreq->clk; ret = cpufreq_generic_init(policy, freq_tbl, 0); if (ret) kfree(freq_tbl); -out: + return ret; } @@ -138,85 +137,86 @@ static int ls1x_cpufreq_remove(struct platform_device *pdev) static int ls1x_cpufreq_probe(struct platform_device *pdev) { - struct plat_ls1x_cpufreq *pdata = pdev->dev.platform_data; + struct plat_ls1x_cpufreq *pdata = dev_get_platdata(&pdev->dev); struct clk *clk; int ret; - if (!pdata || !pdata->clk_name || !pdata->osc_clk_name) + if (!pdata || !pdata->clk_name || !pdata->osc_clk_name) { + dev_err(&pdev->dev, "platform data missing\n"); return -EINVAL; + } - ls1x_cpufreq.dev = &pdev->dev; + cpufreq = + devm_kzalloc(&pdev->dev, sizeof(struct ls1x_cpufreq), GFP_KERNEL); + if (!cpufreq) + return -ENOMEM; + + cpufreq->dev = &pdev->dev; clk = devm_clk_get(&pdev->dev, pdata->clk_name); if (IS_ERR(clk)) { - dev_err(ls1x_cpufreq.dev, "unable to get %s clock\n", + dev_err(&pdev->dev, "unable to get %s clock\n", pdata->clk_name); - ret = PTR_ERR(clk); - goto out; + return PTR_ERR(clk); } - ls1x_cpufreq.clk = clk; + cpufreq->clk = clk; clk = clk_get_parent(clk); if (IS_ERR(clk)) { - dev_err(ls1x_cpufreq.dev, "unable to get parent of %s clock\n", - __clk_get_name(ls1x_cpufreq.clk)); - ret = PTR_ERR(clk); - goto out; + dev_err(&pdev->dev, "unable to get parent of %s clock\n", + __clk_get_name(cpufreq->clk)); + return PTR_ERR(clk); } - ls1x_cpufreq.mux_clk = clk; + cpufreq->mux_clk = clk; clk = clk_get_parent(clk); if (IS_ERR(clk)) { - dev_err(ls1x_cpufreq.dev, "unable to get parent of %s clock\n", - __clk_get_name(ls1x_cpufreq.mux_clk)); - ret = PTR_ERR(clk); - goto out; + dev_err(&pdev->dev, "unable to get parent of %s clock\n", + __clk_get_name(cpufreq->mux_clk)); + return PTR_ERR(clk); } - ls1x_cpufreq.pll_clk = clk; + cpufreq->pll_clk = clk; clk = devm_clk_get(&pdev->dev, pdata->osc_clk_name); if (IS_ERR(clk)) { - dev_err(ls1x_cpufreq.dev, "unable to get %s clock\n", + dev_err(&pdev->dev, "unable to get %s clock\n", pdata->osc_clk_name); - ret = PTR_ERR(clk); - goto out; + return PTR_ERR(clk); } - ls1x_cpufreq.osc_clk = clk; + cpufreq->osc_clk = clk; - ls1x_cpufreq.max_freq = pdata->max_freq; - ls1x_cpufreq.min_freq = pdata->min_freq; + cpufreq->max_freq = pdata->max_freq; + cpufreq->min_freq = pdata->min_freq; ret = cpufreq_register_driver(&ls1x_cpufreq_driver); if (ret) { - dev_err(ls1x_cpufreq.dev, - "failed to register cpufreq driver: %d\n", ret); - goto out; + dev_err(&pdev->dev, + "failed to register CPUFreq driver: %d\n", ret); + return ret; } ret = cpufreq_register_notifier(&ls1x_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); - if (!ret) - goto out; - - dev_err(ls1x_cpufreq.dev, "failed to register cpufreq notifier: %d\n", - ret); + if (ret) { + dev_err(&pdev->dev, + "failed to register CPUFreq notifier: %d\n",ret); + cpufreq_unregister_driver(&ls1x_cpufreq_driver); + } - cpufreq_unregister_driver(&ls1x_cpufreq_driver); -out: return ret; } static struct platform_driver ls1x_cpufreq_platdrv = { - .driver = { + .probe = ls1x_cpufreq_probe, + .remove = ls1x_cpufreq_remove, + .driver = { .name = "ls1x-cpufreq", }, - .probe = ls1x_cpufreq_probe, - .remove = ls1x_cpufreq_remove, }; module_platform_driver(ls1x_cpufreq_platdrv); MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>"); -MODULE_DESCRIPTION("Loongson 1 CPUFreq driver"); +MODULE_DESCRIPTION("Loongson1 CPUFreq driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/broadcom/Kconfig b/drivers/firmware/broadcom/Kconfig index 6bed119930dd..3c7e5b741e37 100644 --- a/drivers/firmware/broadcom/Kconfig +++ b/drivers/firmware/broadcom/Kconfig @@ -9,3 +9,14 @@ config BCM47XX_NVRAM This driver provides an easy way to get value of requested parameter. It simply reads content of NVRAM and parses it. It doesn't control any hardware part itself. + +config BCM47XX_SPROM + bool "Broadcom SPROM driver" + depends on BCM47XX_NVRAM + help + Broadcom devices store configuration data in SPROM. Accessing it is + specific to the bus host type, e.g. PCI(e) devices have it mapped in + a PCI BAR. + In case of SoC devices SPROM content is stored on a flash used by + bootloader firmware CFE. This driver provides method to ssb and bcma + drivers to read SPROM on SoC. diff --git a/drivers/firmware/broadcom/Makefile b/drivers/firmware/broadcom/Makefile index d0e683583cd6..f93efc479b8b 100644 --- a/drivers/firmware/broadcom/Makefile +++ b/drivers/firmware/broadcom/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_BCM47XX_NVRAM) += bcm47xx_nvram.o +obj-$(CONFIG_BCM47XX_SPROM) += bcm47xx_sprom.o diff --git a/arch/mips/bcm47xx/sprom.c b/drivers/firmware/broadcom/bcm47xx_sprom.c index ca7ad131d057..b6eb875d4af3 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/drivers/firmware/broadcom/bcm47xx_sprom.c @@ -26,9 +26,11 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <bcm47xx.h> -#include <linux/if_ether.h> +#include <linux/bcm47xx_nvram.h> +#include <linux/bcma/bcma.h> #include <linux/etherdevice.h> +#include <linux/if_ether.h> +#include <linux/ssb/ssb.h> static void create_key(const char *prefix, const char *postfix, const char *name, char *buf, int len) @@ -599,7 +601,7 @@ void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix, bcm47xx_sprom_fill_auto(sprom, prefix, fallback); } -#if defined(CONFIG_BCM47XX_SSB) +#if IS_BUILTIN(CONFIG_SSB) && IS_ENABLED(CONFIG_SSB_SPROM) static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) { char prefix[10]; @@ -622,7 +624,7 @@ static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) } #endif -#if defined(CONFIG_BCM47XX_BCMA) +#if IS_BUILTIN(CONFIG_BCMA) /* * Having many NVRAM entries for PCI devices led to repeating prefixes like * pci/1/1/ all the time and wasting flash space. So at some point Broadcom @@ -706,19 +708,30 @@ static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out) } #endif +static unsigned int bcm47xx_sprom_registered; + /* * On bcm47xx we need to register SPROM fallback handler very early, so we can't * use anything like platform device / driver for this. */ -void bcm47xx_sprom_register_fallbacks(void) +int bcm47xx_sprom_register_fallbacks(void) { -#if defined(CONFIG_BCM47XX_SSB) + if (bcm47xx_sprom_registered) + return 0; + +#if IS_BUILTIN(CONFIG_SSB) && IS_ENABLED(CONFIG_SSB_SPROM) if (ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb)) pr_warn("Failed to register ssb SPROM handler\n"); #endif -#if defined(CONFIG_BCM47XX_BCMA) +#if IS_BUILTIN(CONFIG_BCMA) if (bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma)) pr_warn("Failed to register bcma SPROM handler\n"); #endif + + bcm47xx_sprom_registered = 1; + + return 0; } + +fs_initcall(bcm47xx_sprom_register_fallbacks); diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 4dffccf532a2..c089f49b63fb 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -197,7 +197,7 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) local_irq_save(flags); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), mips_cm_vp_id(cpu)); if (mips_cm_is64) { gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt); @@ -246,6 +246,14 @@ void gic_stop_count(void) #endif +unsigned gic_read_local_vp_id(void) +{ + unsigned long ident; + + ident = gic_read(GIC_REG(VPE_LOCAL, GIC_VP_IDENT)); + return ident & GIC_VP_IDENT_VCNUM_MSK; +} + static bool gic_local_irq_is_routable(int intr) { u32 vpe_ctl; @@ -553,7 +561,8 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); @@ -567,7 +576,8 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); @@ -607,7 +617,8 @@ static void __init gic_basic_init(void) for (i = 0; i < gic_vpes; i++) { unsigned int j; - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { if (!gic_local_irq_is_routable(j)) continue; @@ -652,7 +663,8 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, for (i = 0; i < gic_vpes; i++) { u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin; - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), + mips_cm_vp_id(i)); switch (intr) { case GIC_LOCAL_INT_WD: diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig index 125e569017be..b3ae30a4c67b 100644 --- a/drivers/platform/mips/Kconfig +++ b/drivers/platform/mips/Kconfig @@ -15,10 +15,6 @@ menuconfig MIPS_PLATFORM_DEVICES if MIPS_PLATFORM_DEVICES -config MIPS_ACPI - bool - default y if LOONGSON_MACH3X - config CPU_HWMON tristate "Loongson CPU HWMon Driver" depends on LOONGSON_MACH3X diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile index 43412849b195..8dfd03924c37 100644 --- a/drivers/platform/mips/Makefile +++ b/drivers/platform/mips/Makefile @@ -1,2 +1 @@ -obj-$(CONFIG_MIPS_ACPI) += acpi_init.o obj-$(CONFIG_CPU_HWMON) += cpu_hwmon.o diff --git a/drivers/platform/mips/cpu_hwmon.c b/drivers/platform/mips/cpu_hwmon.c index 4993e19f1531..4300a558d0f3 100644 --- a/drivers/platform/mips/cpu_hwmon.c +++ b/drivers/platform/mips/cpu_hwmon.c @@ -20,9 +20,9 @@ int loongson3_cpu_temp(int cpu) u32 reg; reg = LOONGSON_CHIPTEMP(cpu); - if (loongson_sysconf.cputype == Loongson_3A) + if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) reg = (reg >> 8) & 0xff; - else if (loongson_sysconf.cputype == Loongson_3B) + else reg = ((reg >> 8) & 0xff) - 100; return (int)reg * 1000; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 13d4ed6caac4..7711b260dacf 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -900,6 +900,27 @@ config SERIAL_SGI_L1_CONSOLE controller serial port as your console (you want this!), say Y. Otherwise, say N. +config SERIAL_PIC32 + tristate "Microchip PIC32 serial support" + depends on MACH_PIC32 + select SERIAL_CORE + help + If you have a PIC32, this driver supports the serial ports. + + Say Y or M to use PIC32 serial ports, otherwise say N. Note that + to use a serial port as a console, this must be included in kernel and + not as a module. + +config SERIAL_PIC32_CONSOLE + bool "PIC32 serial console support" + depends on SERIAL_PIC32 + select SERIAL_CORE_CONSOLE + help + If you have a PIC32, this driver supports the putting a console on one + of the serial ports. + + Say Y to use the PIC32 console, otherwise say N. + config SERIAL_MPC52xx tristate "Freescale MPC52xx/MPC512x family PSC serial support" depends on PPC_MPC52xx || PPC_MPC512x diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 8c261adac04e..74914aafac61 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o +obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c new file mode 100644 index 000000000000..62a43bf5698e --- /dev/null +++ b/drivers/tty/serial/pic32_uart.c @@ -0,0 +1,960 @@ +/* + * PIC32 Integrated Serial Driver. + * + * Copyright (C) 2015 Microchip Technology, Inc. + * + * Authors: + * Sorin-Andrei Pistirica <andrei.pistirica@microchip.com> + * + * Licensed under GPLv2 or later. + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/of_gpio.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/console.h> +#include <linux/clk.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_core.h> +#include <linux/delay.h> + +#include <asm/mach-pic32/pic32.h> +#include "pic32_uart.h" + +/* UART name and device definitions */ +#define PIC32_DEV_NAME "pic32-uart" +#define PIC32_MAX_UARTS 6 +#define PIC32_SDEV_NAME "ttyPIC" + +/* pic32_sport pointer for console use */ +static struct pic32_sport *pic32_sports[PIC32_MAX_UARTS]; + +static inline void pic32_wait_deplete_txbuf(struct pic32_sport *sport) +{ + /* wait for tx empty, otherwise chars will be lost or corrupted */ + while (!(pic32_uart_readl(sport, PIC32_UART_STA) & PIC32_UART_STA_TRMT)) + udelay(1); +} + +static inline int pic32_enable_clock(struct pic32_sport *sport) +{ + int ret = clk_prepare_enable(sport->clk); + + if (ret) + return ret; + + sport->ref_clk++; + return 0; +} + +static inline void pic32_disable_clock(struct pic32_sport *sport) +{ + sport->ref_clk--; + clk_disable_unprepare(sport->clk); +} + +/* serial core request to check if uart tx buffer is empty */ +static unsigned int pic32_uart_tx_empty(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + u32 val = pic32_uart_readl(sport, PIC32_UART_STA); + + return (val & PIC32_UART_STA_TRMT) ? 1 : 0; +} + +/* serial core request to set UART outputs */ +static void pic32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct pic32_sport *sport = to_pic32_sport(port); + + /* set loopback mode */ + if (mctrl & TIOCM_LOOP) + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE), + PIC32_UART_MODE_LPBK); + else + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_LPBK); +} + +/* get the state of CTS input pin for this port */ +static unsigned int get_cts_state(struct pic32_sport *sport) +{ + /* read and invert UxCTS */ + if (gpio_is_valid(sport->cts_gpio)) + return !gpio_get_value(sport->cts_gpio); + + return 1; +} + +/* serial core request to return the state of misc UART input pins */ +static unsigned int pic32_uart_get_mctrl(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + unsigned int mctrl = 0; + + if (!sport->hw_flow_ctrl) + mctrl |= TIOCM_CTS; + else if (get_cts_state(sport)) + mctrl |= TIOCM_CTS; + + /* DSR and CD are not supported in PIC32, so return 1 + * RI is not supported in PIC32, so return 0 + */ + mctrl |= TIOCM_CD; + mctrl |= TIOCM_DSR; + + return mctrl; +} + +/* stop tx and start tx are not called in pairs, therefore a flag indicates + * the status of irq to control the irq-depth. + */ +static inline void pic32_uart_irqtxen(struct pic32_sport *sport, u8 en) +{ + if (en && !tx_irq_enabled(sport)) { + enable_irq(sport->irq_tx); + tx_irq_enabled(sport) = 1; + } else if (!en && tx_irq_enabled(sport)) { + /* use disable_irq_nosync() and not disable_irq() to avoid self + * imposed deadlock by not waiting for irq handler to end, + * since this callback is called from interrupt context. + */ + disable_irq_nosync(sport->irq_tx); + tx_irq_enabled(sport) = 0; + } +} + +/* serial core request to disable tx ASAP (used for flow control) */ +static void pic32_uart_stop_tx(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + + if (!(pic32_uart_readl(sport, PIC32_UART_MODE) & PIC32_UART_MODE_ON)) + return; + + if (!(pic32_uart_readl(sport, PIC32_UART_STA) & PIC32_UART_STA_UTXEN)) + return; + + /* wait for tx empty */ + pic32_wait_deplete_txbuf(sport); + + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), + PIC32_UART_STA_UTXEN); + pic32_uart_irqtxen(sport, 0); +} + +/* serial core request to (re)enable tx */ +static void pic32_uart_start_tx(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + + pic32_uart_irqtxen(sport, 1); + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_STA), + PIC32_UART_STA_UTXEN); +} + +/* serial core request to stop rx, called before port shutdown */ +static void pic32_uart_stop_rx(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + + /* disable rx interrupts */ + disable_irq(sport->irq_rx); + + /* receiver Enable bit OFF */ + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), + PIC32_UART_STA_URXEN); +} + +/* serial core request to start/stop emitting break char */ +static void pic32_uart_break_ctl(struct uart_port *port, int ctl) +{ + struct pic32_sport *sport = to_pic32_sport(port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + if (ctl) + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_STA), + PIC32_UART_STA_UTXBRK); + else + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), + PIC32_UART_STA_UTXBRK); + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* get port type in string format */ +static const char *pic32_uart_type(struct uart_port *port) +{ + return (port->type == PORT_PIC32) ? PIC32_DEV_NAME : NULL; +} + +/* read all chars in rx fifo and send them to core */ +static void pic32_uart_do_rx(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + struct tty_port *tty; + unsigned int max_count; + + /* limit number of char read in interrupt, should not be + * higher than fifo size anyway since we're much faster than + * serial port + */ + max_count = PIC32_UART_RX_FIFO_DEPTH; + + spin_lock(&port->lock); + + tty = &port->state->port; + + do { + u32 sta_reg, c; + char flag; + + /* get overrun/fifo empty information from status register */ + sta_reg = pic32_uart_readl(sport, PIC32_UART_STA); + if (unlikely(sta_reg & PIC32_UART_STA_OERR)) { + + /* fifo reset is required to clear interrupt */ + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), + PIC32_UART_STA_OERR); + + port->icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + /* Can at least one more character can be read? */ + if (!(sta_reg & PIC32_UART_STA_URXDA)) + break; + + /* read the character and increment the rx counter */ + c = pic32_uart_readl(sport, PIC32_UART_RX); + + port->icount.rx++; + flag = TTY_NORMAL; + c &= 0xff; + + if (unlikely((sta_reg & PIC32_UART_STA_PERR) || + (sta_reg & PIC32_UART_STA_FERR))) { + + /* do stats first */ + if (sta_reg & PIC32_UART_STA_PERR) + port->icount.parity++; + if (sta_reg & PIC32_UART_STA_FERR) + port->icount.frame++; + + /* update flag wrt read_status_mask */ + sta_reg &= port->read_status_mask; + + if (sta_reg & PIC32_UART_STA_FERR) + flag = TTY_FRAME; + if (sta_reg & PIC32_UART_STA_PERR) + flag = TTY_PARITY; + } + + if (uart_handle_sysrq_char(port, c)) + continue; + + if ((sta_reg & port->ignore_status_mask) == 0) + tty_insert_flip_char(tty, c, flag); + + } while (--max_count); + + spin_unlock(&port->lock); + + tty_flip_buffer_push(tty); +} + +/* fill tx fifo with chars to send, stop when fifo is about to be full + * or when all chars have been sent. + */ +static void pic32_uart_do_tx(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + struct circ_buf *xmit = &port->state->xmit; + unsigned int max_count = PIC32_UART_TX_FIFO_DEPTH; + + if (port->x_char) { + pic32_uart_writel(sport, PIC32_UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_tx_stopped(port)) { + pic32_uart_stop_tx(port); + return; + } + + if (uart_circ_empty(xmit)) + goto txq_empty; + + /* keep stuffing chars into uart tx buffer + * 1) until uart fifo is full + * or + * 2) until the circ buffer is empty + * (all chars have been sent) + * or + * 3) until the max count is reached + * (prevents lingering here for too long in certain cases) + */ + while (!(PIC32_UART_STA_UTXBF & + pic32_uart_readl(sport, PIC32_UART_STA))) { + unsigned int c = xmit->buf[xmit->tail]; + + pic32_uart_writel(sport, PIC32_UART_TX, c); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + if (--max_count == 0) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + goto txq_empty; + + return; + +txq_empty: + pic32_uart_irqtxen(sport, 0); +} + +/* RX interrupt handler */ +static irqreturn_t pic32_uart_rx_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + + pic32_uart_do_rx(port); + + return IRQ_HANDLED; +} + +/* TX interrupt handler */ +static irqreturn_t pic32_uart_tx_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + pic32_uart_do_tx(port); + spin_unlock_irqrestore(&port->lock, flags); + + return IRQ_HANDLED; +} + +/* FAULT interrupt handler */ +static irqreturn_t pic32_uart_fault_interrupt(int irq, void *dev_id) +{ + /* do nothing: pic32_uart_do_rx() handles faults. */ + return IRQ_HANDLED; +} + +/* enable rx & tx operation on uart */ +static void pic32_uart_en_and_unmask(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_STA), + PIC32_UART_STA_UTXEN | PIC32_UART_STA_URXEN); + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE), + PIC32_UART_MODE_ON); +} + +/* disable rx & tx operation on uart */ +static void pic32_uart_dsbl_and_mask(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + + /* wait for tx empty, otherwise chars will be lost or corrupted */ + pic32_wait_deplete_txbuf(sport); + + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), + PIC32_UART_STA_UTXEN | PIC32_UART_STA_URXEN); + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_ON); +} + +/* serial core request to initialize uart and start rx operation */ +static int pic32_uart_startup(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + u32 dflt_baud = (port->uartclk / PIC32_UART_DFLT_BRATE / 16) - 1; + unsigned long flags; + int ret; + + local_irq_save(flags); + + ret = pic32_enable_clock(sport); + if (ret) { + local_irq_restore(flags); + goto out_done; + } + + /* clear status and mode registers */ + pic32_uart_writel(sport, PIC32_UART_MODE, 0); + pic32_uart_writel(sport, PIC32_UART_STA, 0); + + /* disable uart and mask all interrupts */ + pic32_uart_dsbl_and_mask(port); + + /* set default baud */ + pic32_uart_writel(sport, PIC32_UART_BRG, dflt_baud); + + local_irq_restore(flags); + + /* Each UART of a PIC32 has three interrupts therefore, + * we setup driver to register the 3 irqs for the device. + * + * For each irq request_irq() is called with interrupt disabled. + * And the irq is enabled as soon as we are ready to handle them. + */ + tx_irq_enabled(sport) = 0; + + sport->irq_fault_name = kasprintf(GFP_KERNEL, "%s%d-fault", + pic32_uart_type(port), + sport->idx); + if (!sport->irq_fault_name) { + dev_err(port->dev, "%s: kasprintf err!", __func__); + ret = -ENOMEM; + goto out_done; + } + irq_set_status_flags(sport->irq_fault, IRQ_NOAUTOEN); + ret = request_irq(sport->irq_fault, pic32_uart_fault_interrupt, + sport->irqflags_fault, sport->irq_fault_name, port); + if (ret) { + dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n", + __func__, sport->irq_fault, ret, + pic32_uart_type(port)); + goto out_f; + } + + sport->irq_rx_name = kasprintf(GFP_KERNEL, "%s%d-rx", + pic32_uart_type(port), + sport->idx); + if (!sport->irq_rx_name) { + dev_err(port->dev, "%s: kasprintf err!", __func__); + kfree(sport->irq_fault_name); + ret = -ENOMEM; + goto out_f; + } + irq_set_status_flags(sport->irq_rx, IRQ_NOAUTOEN); + ret = request_irq(sport->irq_rx, pic32_uart_rx_interrupt, + sport->irqflags_rx, sport->irq_rx_name, port); + if (ret) { + dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n", + __func__, sport->irq_rx, ret, + pic32_uart_type(port)); + goto out_r; + } + + sport->irq_tx_name = kasprintf(GFP_KERNEL, "%s%d-tx", + pic32_uart_type(port), + sport->idx); + if (!sport->irq_tx_name) { + dev_err(port->dev, "%s: kasprintf err!", __func__); + ret = -ENOMEM; + goto out_r; + } + irq_set_status_flags(sport->irq_tx, IRQ_NOAUTOEN); + ret = request_irq(sport->irq_tx, pic32_uart_tx_interrupt, + sport->irqflags_tx, sport->irq_tx_name, port); + if (ret) { + dev_err(port->dev, "%s: request irq(%d) err! ret:%d name:%s\n", + __func__, sport->irq_tx, ret, + pic32_uart_type(port)); + goto out_t; + } + + local_irq_save(flags); + + /* set rx interrupt on first receive */ + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), + PIC32_UART_STA_URXISEL1 | PIC32_UART_STA_URXISEL0); + + /* set interrupt on empty */ + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA), + PIC32_UART_STA_UTXISEL1); + + /* enable all interrupts and eanable uart */ + pic32_uart_en_and_unmask(port); + + enable_irq(sport->irq_rx); + + return 0; + +out_t: + kfree(sport->irq_tx_name); + free_irq(sport->irq_tx, sport); +out_r: + kfree(sport->irq_rx_name); + free_irq(sport->irq_rx, sport); +out_f: + kfree(sport->irq_fault_name); + free_irq(sport->irq_fault, sport); +out_done: + return ret; +} + +/* serial core request to flush & disable uart */ +static void pic32_uart_shutdown(struct uart_port *port) +{ + struct pic32_sport *sport = to_pic32_sport(port); + unsigned long flags; + + /* disable uart */ + spin_lock_irqsave(&port->lock, flags); + pic32_uart_dsbl_and_mask(port); + spin_unlock_irqrestore(&port->lock, flags); + pic32_disable_clock(sport); + + /* free all 3 interrupts for this UART */ + free_irq(sport->irq_fault, port); + free_irq(sport->irq_tx, port); + free_irq(sport->irq_rx, port); +} + +/* serial core request to change current uart setting */ +static void pic32_uart_set_termios(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + struct pic32_sport *sport = to_pic32_sport(port); + unsigned int baud; + unsigned int quot; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* disable uart and mask all interrupts while changing speed */ + pic32_uart_dsbl_and_mask(port); + + /* stop bit options */ + if (new->c_cflag & CSTOPB) + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE), + PIC32_UART_MODE_STSEL); + else + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_STSEL); + + /* parity options */ + if (new->c_cflag & PARENB) { + if (new->c_cflag & PARODD) { + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE), + PIC32_UART_MODE_PDSEL1); + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_PDSEL0); + } else { + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE), + PIC32_UART_MODE_PDSEL0); + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_PDSEL1); + } + } else { + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_PDSEL1 | + PIC32_UART_MODE_PDSEL0); + } + /* if hw flow ctrl, then the pins must be specified in device tree */ + if ((new->c_cflag & CRTSCTS) && sport->hw_flow_ctrl) { + /* enable hardware flow control */ + pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE), + PIC32_UART_MODE_UEN1); + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_UEN0); + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_RTSMD); + } else { + /* disable hardware flow control */ + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_UEN1); + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_UEN0); + pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE), + PIC32_UART_MODE_RTSMD); + } + + /* Always 8-bit */ + new->c_cflag |= CS8; + + /* Mark/Space parity is not supported */ + new->c_cflag &= ~CMSPAR; + + /* update baud */ + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + quot = uart_get_divisor(port, baud) - 1; + pic32_uart_writel(sport, PIC32_UART_BRG, quot); + uart_update_timeout(port, new->c_cflag, baud); + + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); + + /* enable uart */ + pic32_uart_en_and_unmask(port); + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* serial core request to claim uart iomem */ +static int pic32_uart_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *res_mem; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!res_mem)) + return -EINVAL; + + if (!request_mem_region(port->mapbase, resource_size(res_mem), + "pic32_uart_mem")) + return -EBUSY; + + port->membase = devm_ioremap_nocache(port->dev, port->mapbase, + resource_size(res_mem)); + if (!port->membase) { + dev_err(port->dev, "Unable to map registers\n"); + release_mem_region(port->mapbase, resource_size(res_mem)); + return -ENOMEM; + } + + return 0; +} + +/* serial core request to release uart iomem */ +static void pic32_uart_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *res_mem; + unsigned int res_size; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!res_mem)) + return; + res_size = resource_size(res_mem); + + release_mem_region(port->mapbase, res_size); +} + +/* serial core request to do any port required auto-configuration */ +static void pic32_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + if (pic32_uart_request_port(port)) + return; + port->type = PORT_PIC32; + } +} + +/* serial core request to check that port information in serinfo are suitable */ +static int pic32_uart_verify_port(struct uart_port *port, + struct serial_struct *serinfo) +{ + if (port->type != PORT_PIC32) + return -EINVAL; + if (port->irq != serinfo->irq) + return -EINVAL; + if (port->iotype != serinfo->io_type) + return -EINVAL; + if (port->mapbase != (unsigned long)serinfo->iomem_base) + return -EINVAL; + + return 0; +} + +/* serial core callbacks */ +static const struct uart_ops pic32_uart_ops = { + .tx_empty = pic32_uart_tx_empty, + .get_mctrl = pic32_uart_get_mctrl, + .set_mctrl = pic32_uart_set_mctrl, + .start_tx = pic32_uart_start_tx, + .stop_tx = pic32_uart_stop_tx, + .stop_rx = pic32_uart_stop_rx, + .break_ctl = pic32_uart_break_ctl, + .startup = pic32_uart_startup, + .shutdown = pic32_uart_shutdown, + .set_termios = pic32_uart_set_termios, + .type = pic32_uart_type, + .release_port = pic32_uart_release_port, + .request_port = pic32_uart_request_port, + .config_port = pic32_uart_config_port, + .verify_port = pic32_uart_verify_port, +}; + +#ifdef CONFIG_SERIAL_PIC32_CONSOLE +/* output given char */ +static void pic32_console_putchar(struct uart_port *port, int ch) +{ + struct pic32_sport *sport = to_pic32_sport(port); + + if (!(pic32_uart_readl(sport, PIC32_UART_MODE) & PIC32_UART_MODE_ON)) + return; + + if (!(pic32_uart_readl(sport, PIC32_UART_STA) & PIC32_UART_STA_UTXEN)) + return; + + /* wait for tx empty */ + pic32_wait_deplete_txbuf(sport); + + pic32_uart_writel(sport, PIC32_UART_TX, ch & 0xff); +} + +/* console core request to output given string */ +static void pic32_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct pic32_sport *sport = pic32_sports[co->index]; + struct uart_port *port = pic32_get_port(sport); + + /* call uart helper to deal with \r\n */ + uart_console_write(port, s, count, pic32_console_putchar); +} + +/* console core request to setup given console, find matching uart + * port and setup it. + */ +static int pic32_console_setup(struct console *co, char *options) +{ + struct pic32_sport *sport; + struct uart_port *port = NULL; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret = 0; + + if (unlikely(co->index < 0 || co->index >= PIC32_MAX_UARTS)) + return -ENODEV; + + sport = pic32_sports[co->index]; + if (!sport) + return -ENODEV; + port = pic32_get_port(sport); + + ret = pic32_enable_clock(sport); + if (ret) + return ret; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver pic32_uart_driver; +static struct console pic32_console = { + .name = PIC32_SDEV_NAME, + .write = pic32_console_write, + .device = uart_console_device, + .setup = pic32_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &pic32_uart_driver, +}; +#define PIC32_SCONSOLE (&pic32_console) + +static int __init pic32_console_init(void) +{ + register_console(&pic32_console); + return 0; +} +console_initcall(pic32_console_init); + +static inline bool is_pic32_console_port(struct uart_port *port) +{ + return port->cons && port->cons->index == port->line; +} + +/* + * Late console initialization. + */ +static int __init pic32_late_console_init(void) +{ + if (!(pic32_console.flags & CON_ENABLED)) + register_console(&pic32_console); + + return 0; +} + +core_initcall(pic32_late_console_init); + +#else +#define PIC32_SCONSOLE NULL +#endif + +static struct uart_driver pic32_uart_driver = { + .owner = THIS_MODULE, + .driver_name = PIC32_DEV_NAME, + .dev_name = PIC32_SDEV_NAME, + .nr = PIC32_MAX_UARTS, + .cons = PIC32_SCONSOLE, +}; + +static int pic32_uart_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct pic32_sport *sport; + int uart_idx = 0; + struct resource *res_mem; + struct uart_port *port; + int ret; + + uart_idx = of_alias_get_id(np, "serial"); + if (uart_idx < 0 || uart_idx >= PIC32_MAX_UARTS) + return -EINVAL; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) + return -EINVAL; + + sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); + if (!sport) + return -ENOMEM; + + sport->idx = uart_idx; + sport->irq_fault = irq_of_parse_and_map(np, 0); + sport->irqflags_fault = IRQF_NO_THREAD; + sport->irq_rx = irq_of_parse_and_map(np, 1); + sport->irqflags_rx = IRQF_NO_THREAD; + sport->irq_tx = irq_of_parse_and_map(np, 2); + sport->irqflags_tx = IRQF_NO_THREAD; + sport->clk = devm_clk_get(&pdev->dev, NULL); + sport->cts_gpio = -EINVAL; + sport->dev = &pdev->dev; + + /* Hardware flow control: gpios + * !Note: Basically, CTS is needed for reading the status. + */ + sport->hw_flow_ctrl = false; + sport->cts_gpio = of_get_named_gpio(np, "cts-gpios", 0); + if (gpio_is_valid(sport->cts_gpio)) { + sport->hw_flow_ctrl = true; + + ret = devm_gpio_request(sport->dev, + sport->cts_gpio, "CTS"); + if (ret) { + dev_err(&pdev->dev, + "error requesting CTS GPIO\n"); + goto err; + } + + ret = gpio_direction_input(sport->cts_gpio); + if (ret) { + dev_err(&pdev->dev, "error setting CTS GPIO\n"); + goto err; + } + } + + pic32_sports[uart_idx] = sport; + port = &sport->port; + memset(port, 0, sizeof(*port)); + port->iotype = UPIO_MEM; + port->mapbase = res_mem->start; + port->ops = &pic32_uart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = &pdev->dev; + port->fifosize = PIC32_UART_TX_FIFO_DEPTH; + port->uartclk = clk_get_rate(sport->clk); + port->line = uart_idx; + + ret = uart_add_one_port(&pic32_uart_driver, port); + if (ret) { + port->membase = NULL; + dev_err(port->dev, "%s: uart add port error!\n", __func__); + goto err; + } + +#ifdef CONFIG_SERIAL_PIC32_CONSOLE + if (is_pic32_console_port(port) && + (pic32_console.flags & CON_ENABLED)) { + /* The peripheral clock has been enabled by console_setup, + * so disable it till the port is used. + */ + pic32_disable_clock(sport); + } +#endif + + platform_set_drvdata(pdev, port); + + dev_info(&pdev->dev, "%s: uart(%d) driver initialized.\n", + __func__, uart_idx); + + return 0; +err: + /* automatic unroll of sport and gpios */ + return ret; +} + +static int pic32_uart_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + struct pic32_sport *sport = to_pic32_sport(port); + + uart_remove_one_port(&pic32_uart_driver, port); + pic32_disable_clock(sport); + platform_set_drvdata(pdev, NULL); + pic32_sports[sport->idx] = NULL; + + /* automatic unroll of sport and gpios */ + return 0; +} + +static const struct of_device_id pic32_serial_dt_ids[] = { + { .compatible = "microchip,pic32mzda-uart" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pic32_serial_dt_ids); + +static struct platform_driver pic32_uart_platform_driver = { + .probe = pic32_uart_probe, + .remove = pic32_uart_remove, + .driver = { + .name = PIC32_DEV_NAME, + .of_match_table = of_match_ptr(pic32_serial_dt_ids), + }, +}; + +static int __init pic32_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&pic32_uart_driver); + if (ret) { + pr_err("failed to register %s:%d\n", + pic32_uart_driver.driver_name, ret); + return ret; + } + + ret = platform_driver_register(&pic32_uart_platform_driver); + if (ret) { + pr_err("fail to register pic32 uart\n"); + uart_unregister_driver(&pic32_uart_driver); + } + + return ret; +} +arch_initcall(pic32_uart_init); + +static void __exit pic32_uart_exit(void) +{ +#ifdef CONFIG_SERIAL_PIC32_CONSOLE + unregister_console(&pic32_console); +#endif + platform_driver_unregister(&pic32_uart_platform_driver); + uart_unregister_driver(&pic32_uart_driver); +} +module_exit(pic32_uart_exit); + +MODULE_AUTHOR("Sorin-Andrei Pistirica <andrei.pistirica@microchip.com>"); +MODULE_DESCRIPTION("Microchip PIC32 integrated serial port driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/pic32_uart.h b/drivers/tty/serial/pic32_uart.h new file mode 100644 index 000000000000..ec379da55ebb --- /dev/null +++ b/drivers/tty/serial/pic32_uart.h @@ -0,0 +1,126 @@ +/* + * PIC32 Integrated Serial Driver. + * + * Copyright (C) 2015 Microchip Technology, Inc. + * + * Authors: + * Sorin-Andrei Pistirica <andrei.pistirica@microchip.com> + * + * Licensed under GPLv2 or later. + */ +#ifndef __DT_PIC32_UART_H__ +#define __DT_PIC32_UART_H__ + +#define PIC32_UART_DFLT_BRATE (9600) +#define PIC32_UART_TX_FIFO_DEPTH (8) +#define PIC32_UART_RX_FIFO_DEPTH (8) + +#define PIC32_UART_MODE 0x00 +#define PIC32_UART_STA 0x10 +#define PIC32_UART_TX 0x20 +#define PIC32_UART_RX 0x30 +#define PIC32_UART_BRG 0x40 + +struct pic32_console_opt { + int baud; + int parity; + int bits; + int flow; +}; + +/* struct pic32_sport - pic32 serial port descriptor + * @port: uart port descriptor + * @idx: port index + * @irq_fault: virtual fault interrupt number + * @irqflags_fault: flags related to fault irq + * @irq_fault_name: irq fault name + * @irq_rx: virtual rx interrupt number + * @irqflags_rx: flags related to rx irq + * @irq_rx_name: irq rx name + * @irq_tx: virtual tx interrupt number + * @irqflags_tx: : flags related to tx irq + * @irq_tx_name: irq tx name + * @cts_gpio: clear to send gpio + * @dev: device descriptor + **/ +struct pic32_sport { + struct uart_port port; + struct pic32_console_opt opt; + int idx; + + int irq_fault; + int irqflags_fault; + const char *irq_fault_name; + int irq_rx; + int irqflags_rx; + const char *irq_rx_name; + int irq_tx; + int irqflags_tx; + const char *irq_tx_name; + u8 enable_tx_irq; + + bool hw_flow_ctrl; + int cts_gpio; + + int ref_clk; + struct clk *clk; + + struct device *dev; +}; +#define to_pic32_sport(c) container_of(c, struct pic32_sport, port) +#define pic32_get_port(sport) (&sport->port) +#define pic32_get_opt(sport) (&sport->opt) +#define tx_irq_enabled(sport) (sport->enable_tx_irq) + +static inline void pic32_uart_writel(struct pic32_sport *sport, + u32 reg, u32 val) +{ + struct uart_port *port = pic32_get_port(sport); + + __raw_writel(val, port->membase + reg); +} + +static inline u32 pic32_uart_readl(struct pic32_sport *sport, u32 reg) +{ + struct uart_port *port = pic32_get_port(sport); + + return __raw_readl(port->membase + reg); +} + +/* pic32 uart mode register bits */ +#define PIC32_UART_MODE_ON BIT(15) +#define PIC32_UART_MODE_FRZ BIT(14) +#define PIC32_UART_MODE_SIDL BIT(13) +#define PIC32_UART_MODE_IREN BIT(12) +#define PIC32_UART_MODE_RTSMD BIT(11) +#define PIC32_UART_MODE_RESV1 BIT(10) +#define PIC32_UART_MODE_UEN1 BIT(9) +#define PIC32_UART_MODE_UEN0 BIT(8) +#define PIC32_UART_MODE_WAKE BIT(7) +#define PIC32_UART_MODE_LPBK BIT(6) +#define PIC32_UART_MODE_ABAUD BIT(5) +#define PIC32_UART_MODE_RXINV BIT(4) +#define PIC32_UART_MODE_BRGH BIT(3) +#define PIC32_UART_MODE_PDSEL1 BIT(2) +#define PIC32_UART_MODE_PDSEL0 BIT(1) +#define PIC32_UART_MODE_STSEL BIT(0) + +/* pic32 uart status register bits */ +#define PIC32_UART_STA_UTXISEL1 BIT(15) +#define PIC32_UART_STA_UTXISEL0 BIT(14) +#define PIC32_UART_STA_UTXINV BIT(13) +#define PIC32_UART_STA_URXEN BIT(12) +#define PIC32_UART_STA_UTXBRK BIT(11) +#define PIC32_UART_STA_UTXEN BIT(10) +#define PIC32_UART_STA_UTXBF BIT(9) +#define PIC32_UART_STA_TRMT BIT(8) +#define PIC32_UART_STA_URXISEL1 BIT(7) +#define PIC32_UART_STA_URXISEL0 BIT(6) +#define PIC32_UART_STA_ADDEN BIT(5) +#define PIC32_UART_STA_RIDLE BIT(4) +#define PIC32_UART_STA_PERR BIT(3) +#define PIC32_UART_STA_FERR BIT(2) +#define PIC32_UART_STA_OERR BIT(1) +#define PIC32_UART_STA_URXDA BIT(0) + +#endif /* __DT_PIC32_UART_H__ */ diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 04dcedfdebf8..0449235d4f22 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1245,11 +1245,6 @@ MODULE_LICENSE ("GPL"); #define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver #endif -#ifdef CONFIG_MACH_JZ4740 -#include "ohci-jz4740.c" -#define PLATFORM_DRIVER ohci_hcd_jz4740_driver -#endif - #ifdef CONFIG_TILE_USB #include "ohci-tilegx.c" #define PLATFORM_DRIVER ohci_hcd_tilegx_driver diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c deleted file mode 100644 index 4db78f169256..000000000000 --- a/drivers/usb/host/ohci-jz4740.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> - * - * 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/regulator/consumer.h> - -struct jz4740_ohci_hcd { - struct ohci_hcd ohci_hcd; - - struct regulator *vbus; - bool vbus_enabled; - struct clk *clk; -}; - -static inline struct jz4740_ohci_hcd *hcd_to_jz4740_hcd(struct usb_hcd *hcd) -{ - return (struct jz4740_ohci_hcd *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *jz4740_hcd_to_hcd(struct jz4740_ohci_hcd *jz4740_ohci) -{ - return container_of((void *)jz4740_ohci, struct usb_hcd, hcd_priv); -} - -static int ohci_jz4740_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - - ohci->num_ports = 1; - - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "Can not start %s", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd *jz4740_ohci, - bool enabled) -{ - int ret = 0; - - if (!jz4740_ohci->vbus) - return 0; - - if (enabled && !jz4740_ohci->vbus_enabled) { - ret = regulator_enable(jz4740_ohci->vbus); - if (ret) - dev_err(jz4740_hcd_to_hcd(jz4740_ohci)->self.controller, - "Could not power vbus\n"); - } else if (!enabled && jz4740_ohci->vbus_enabled) { - ret = regulator_disable(jz4740_ohci->vbus); - } - - if (ret == 0) - jz4740_ohci->vbus_enabled = enabled; - - return ret; -} - -static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); - int ret = 0; - - switch (typeReq) { - case SetPortFeature: - if (wValue == USB_PORT_FEAT_POWER) - ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true); - break; - case ClearPortFeature: - if (wValue == USB_PORT_FEAT_POWER) - ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false); - break; - } - - if (ret) - return ret; - - return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); -} - - -static const struct hc_driver ohci_jz4740_hc_driver = { - .description = hcd_name, - .product_desc = "JZ4740 OHCI", - .hcd_priv_size = sizeof(struct jz4740_ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_jz4740_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_jz4740_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - - -static int jz4740_ohci_probe(struct platform_device *pdev) -{ - int ret; - struct usb_hcd *hcd; - struct jz4740_ohci_hcd *jz4740_ohci; - struct resource *res; - int irq; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq\n"); - return irq; - } - - hcd = usb_create_hcd(&ohci_jz4740_hc_driver, &pdev->dev, "jz4740"); - if (!hcd) { - dev_err(&pdev->dev, "Failed to create hcd.\n"); - return -ENOMEM; - } - - jz4740_ohci = hcd_to_jz4740_hcd(hcd); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(hcd->regs)) { - ret = PTR_ERR(hcd->regs); - goto err_free; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - jz4740_ohci->clk = devm_clk_get(&pdev->dev, "uhc"); - if (IS_ERR(jz4740_ohci->clk)) { - ret = PTR_ERR(jz4740_ohci->clk); - dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); - goto err_free; - } - - jz4740_ohci->vbus = devm_regulator_get(&pdev->dev, "vbus"); - if (IS_ERR(jz4740_ohci->vbus)) - jz4740_ohci->vbus = NULL; - - - clk_set_rate(jz4740_ohci->clk, 48000000); - clk_enable(jz4740_ohci->clk); - if (jz4740_ohci->vbus) - ohci_jz4740_set_vbus_power(jz4740_ohci, true); - - platform_set_drvdata(pdev, hcd); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - ret = usb_add_hcd(hcd, irq, 0); - if (ret) { - dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret); - goto err_disable; - } - device_wakeup_enable(hcd->self.controller); - - return 0; - -err_disable: - if (jz4740_ohci->vbus) - regulator_disable(jz4740_ohci->vbus); - clk_disable(jz4740_ohci->clk); - -err_free: - usb_put_hcd(hcd); - - return ret; -} - -static int jz4740_ohci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); - - usb_remove_hcd(hcd); - - if (jz4740_ohci->vbus) - regulator_disable(jz4740_ohci->vbus); - - clk_disable(jz4740_ohci->clk); - - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ohci_hcd_jz4740_driver = { - .probe = jz4740_ohci_probe, - .remove = jz4740_ohci_remove, - .driver = { - .name = "jz4740-ohci", - }, -}; - -MODULE_ALIAS("platform:jz4740-ohci"); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index fb947655badd..9c4143112e6c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1475,6 +1475,32 @@ config MT7621_WDT help Hardware driver for the Mediatek/Ralink MT7621/8 SoC Watchdog Timer. +config PIC32_WDT + tristate "Microchip PIC32 hardware watchdog" + select WATCHDOG_CORE + depends on MACH_PIC32 + help + Watchdog driver for the built in watchdog hardware in a PIC32. + + Configuration bits must be set appropriately for the watchdog to be + controlled by this driver. + + To compile this driver as a loadable module, choose M here. + The module will be called pic32-wdt. + +config PIC32_DMT + tristate "Microchip PIC32 Deadman Timer" + select WATCHDOG_CORE + depends on MACH_PIC32 + help + Watchdog driver for PIC32 instruction fetch counting timer. This specific + timer is typically be used in misson critical and safety critical + applications, where any single failure of the software functionality + and sequencing must be detected. + + To compile this driver as a loadable module, choose M here. + The module will be called pic32-dmt. + # PARISC Architecture # POWERPC Architecture diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index feb6270fdbde..9bde095ff691 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -157,6 +157,8 @@ obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o +obj-$(CONFIG_PIC32_WDT) += pic32-wdt.o +obj-$(CONFIG_PIC32_DMT) += pic32-dmt.o # PARISC Architecture diff --git a/drivers/watchdog/pic32-dmt.c b/drivers/watchdog/pic32-dmt.c new file mode 100644 index 000000000000..962f58c03353 --- /dev/null +++ b/drivers/watchdog/pic32-dmt.c @@ -0,0 +1,257 @@ +/* + * PIC32 deadman timer driver + * + * Purna Chandra Mandal <purna.mandal@microchip.com> + * Copyright (c) 2016, Microchip Technology Inc. + * + * 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 <linux/clk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/watchdog.h> + +#include <asm/mach-pic32/pic32.h> + +/* Deadman Timer Regs */ +#define DMTCON_REG 0x00 +#define DMTPRECLR_REG 0x10 +#define DMTCLR_REG 0x20 +#define DMTSTAT_REG 0x30 +#define DMTCNT_REG 0x40 +#define DMTPSCNT_REG 0x60 +#define DMTPSINTV_REG 0x70 + +/* Deadman Timer Regs fields */ +#define DMT_ON BIT(15) +#define DMT_STEP1_KEY BIT(6) +#define DMT_STEP2_KEY BIT(3) +#define DMTSTAT_WINOPN BIT(0) +#define DMTSTAT_EVENT BIT(5) +#define DMTSTAT_BAD2 BIT(6) +#define DMTSTAT_BAD1 BIT(7) + +/* Reset Control Register fields for watchdog */ +#define RESETCON_DMT_TIMEOUT BIT(5) + +struct pic32_dmt { + void __iomem *regs; + struct clk *clk; +}; + +static inline void dmt_enable(struct pic32_dmt *dmt) +{ + writel(DMT_ON, PIC32_SET(dmt->regs + DMTCON_REG)); +} + +static inline void dmt_disable(struct pic32_dmt *dmt) +{ + writel(DMT_ON, PIC32_CLR(dmt->regs + DMTCON_REG)); + /* + * Cannot touch registers in the CPU cycle following clearing the + * ON bit. + */ + nop(); +} + +static inline int dmt_bad_status(struct pic32_dmt *dmt) +{ + u32 val; + + val = readl(dmt->regs + DMTSTAT_REG); + val &= (DMTSTAT_BAD1 | DMTSTAT_BAD2 | DMTSTAT_EVENT); + if (val) + return -EAGAIN; + + return 0; +} + +static inline int dmt_keepalive(struct pic32_dmt *dmt) +{ + u32 v; + u32 timeout = 500; + + /* set pre-clear key */ + writel(DMT_STEP1_KEY << 8, dmt->regs + DMTPRECLR_REG); + + /* wait for DMT window to open */ + while (--timeout) { + v = readl(dmt->regs + DMTSTAT_REG) & DMTSTAT_WINOPN; + if (v == DMTSTAT_WINOPN) + break; + } + + /* apply key2 */ + writel(DMT_STEP2_KEY, dmt->regs + DMTCLR_REG); + + /* check whether keys are latched correctly */ + return dmt_bad_status(dmt); +} + +static inline u32 pic32_dmt_get_timeout_secs(struct pic32_dmt *dmt) +{ + unsigned long rate; + + rate = clk_get_rate(dmt->clk); + if (rate) + return readl(dmt->regs + DMTPSCNT_REG) / rate; + + return 0; +} + +static inline u32 pic32_dmt_bootstatus(struct pic32_dmt *dmt) +{ + u32 v; + void __iomem *rst_base; + + rst_base = ioremap(PIC32_BASE_RESET, 0x10); + if (!rst_base) + return 0; + + v = readl(rst_base); + + writel(RESETCON_DMT_TIMEOUT, PIC32_CLR(rst_base)); + + iounmap(rst_base); + return v & RESETCON_DMT_TIMEOUT; +} + +static int pic32_dmt_start(struct watchdog_device *wdd) +{ + struct pic32_dmt *dmt = watchdog_get_drvdata(wdd); + + dmt_enable(dmt); + return dmt_keepalive(dmt); +} + +static int pic32_dmt_stop(struct watchdog_device *wdd) +{ + struct pic32_dmt *dmt = watchdog_get_drvdata(wdd); + + dmt_disable(dmt); + + return 0; +} + +static int pic32_dmt_ping(struct watchdog_device *wdd) +{ + struct pic32_dmt *dmt = watchdog_get_drvdata(wdd); + + return dmt_keepalive(dmt); +} + +static const struct watchdog_ops pic32_dmt_fops = { + .owner = THIS_MODULE, + .start = pic32_dmt_start, + .stop = pic32_dmt_stop, + .ping = pic32_dmt_ping, +}; + +static const struct watchdog_info pic32_dmt_ident = { + .options = WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .identity = "PIC32 Deadman Timer", +}; + +static struct watchdog_device pic32_dmt_wdd = { + .info = &pic32_dmt_ident, + .ops = &pic32_dmt_fops, +}; + +static int pic32_dmt_probe(struct platform_device *pdev) +{ + int ret; + struct pic32_dmt *dmt; + struct resource *mem; + struct watchdog_device *wdd = &pic32_dmt_wdd; + + dmt = devm_kzalloc(&pdev->dev, sizeof(*dmt), GFP_KERNEL); + if (IS_ERR(dmt)) + return PTR_ERR(dmt); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dmt->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(dmt->regs)) + return PTR_ERR(dmt->regs); + + dmt->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dmt->clk)) { + dev_err(&pdev->dev, "clk not found\n"); + return PTR_ERR(dmt->clk); + } + + ret = clk_prepare_enable(dmt->clk); + if (ret) + return ret; + + wdd->timeout = pic32_dmt_get_timeout_secs(dmt); + if (!wdd->timeout) { + dev_err(&pdev->dev, + "failed to read watchdog register timeout\n"); + ret = -EINVAL; + goto out_disable_clk; + } + + dev_info(&pdev->dev, "timeout %d\n", wdd->timeout); + + wdd->bootstatus = pic32_dmt_bootstatus(dmt) ? WDIOF_CARDRESET : 0; + + watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT); + watchdog_set_drvdata(wdd, dmt); + + ret = watchdog_register_device(wdd); + if (ret) { + dev_err(&pdev->dev, "watchdog register failed, err %d\n", ret); + goto out_disable_clk; + } + + platform_set_drvdata(pdev, wdd); + return 0; + +out_disable_clk: + clk_disable_unprepare(dmt->clk); + return ret; +} + +static int pic32_dmt_remove(struct platform_device *pdev) +{ + struct watchdog_device *wdd = platform_get_drvdata(pdev); + struct pic32_dmt *dmt = watchdog_get_drvdata(wdd); + + watchdog_unregister_device(wdd); + clk_disable_unprepare(dmt->clk); + + return 0; +} + +static const struct of_device_id pic32_dmt_of_ids[] = { + { .compatible = "microchip,pic32mzda-dmt",}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pic32_dmt_of_ids); + +static struct platform_driver pic32_dmt_driver = { + .probe = pic32_dmt_probe, + .remove = pic32_dmt_remove, + .driver = { + .name = "pic32-dmt", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pic32_dmt_of_ids), + } +}; + +module_platform_driver(pic32_dmt_driver); + +MODULE_AUTHOR("Purna Chandra Mandal <purna.mandal@microchip.com>"); +MODULE_DESCRIPTION("Microchip PIC32 DMT Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/watchdog/pic32-wdt.c b/drivers/watchdog/pic32-wdt.c new file mode 100644 index 000000000000..6047aa89a4d3 --- /dev/null +++ b/drivers/watchdog/pic32-wdt.c @@ -0,0 +1,263 @@ +/* + * PIC32 watchdog driver + * + * Joshua Henderson <joshua.henderson@microchip.com> + * Copyright (c) 2016, Microchip Technology Inc. + * + * 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 <linux/clk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/watchdog.h> + +#include <asm/mach-pic32/pic32.h> + +/* Watchdog Timer Registers */ +#define WDTCON_REG 0x00 + +/* Watchdog Timer Control Register fields */ +#define WDTCON_WIN_EN BIT(0) +#define WDTCON_RMCS_MASK 0x0003 +#define WDTCON_RMCS_SHIFT 0x0006 +#define WDTCON_RMPS_MASK 0x001F +#define WDTCON_RMPS_SHIFT 0x0008 +#define WDTCON_ON BIT(15) +#define WDTCON_CLR_KEY 0x5743 + +/* Reset Control Register fields for watchdog */ +#define RESETCON_TIMEOUT_IDLE BIT(2) +#define RESETCON_TIMEOUT_SLEEP BIT(3) +#define RESETCON_WDT_TIMEOUT BIT(4) + +struct pic32_wdt { + void __iomem *regs; + void __iomem *rst_base; + struct clk *clk; +}; + +static inline bool pic32_wdt_is_win_enabled(struct pic32_wdt *wdt) +{ + return !!(readl(wdt->regs + WDTCON_REG) & WDTCON_WIN_EN); +} + +static inline u32 pic32_wdt_get_post_scaler(struct pic32_wdt *wdt) +{ + u32 v = readl(wdt->regs + WDTCON_REG); + + return (v >> WDTCON_RMPS_SHIFT) & WDTCON_RMPS_MASK; +} + +static inline u32 pic32_wdt_get_clk_id(struct pic32_wdt *wdt) +{ + u32 v = readl(wdt->regs + WDTCON_REG); + + return (v >> WDTCON_RMCS_SHIFT) & WDTCON_RMCS_MASK; +} + +static int pic32_wdt_bootstatus(struct pic32_wdt *wdt) +{ + u32 v = readl(wdt->rst_base); + + writel(RESETCON_WDT_TIMEOUT, PIC32_CLR(wdt->rst_base)); + + return v & RESETCON_WDT_TIMEOUT; +} + +static u32 pic32_wdt_get_timeout_secs(struct pic32_wdt *wdt, struct device *dev) +{ + unsigned long rate; + u32 period, ps, terminal; + + rate = clk_get_rate(wdt->clk); + + dev_dbg(dev, "wdt: clk_id %d, clk_rate %lu (prescale)\n", + pic32_wdt_get_clk_id(wdt), rate); + + /* default, prescaler of 32 (i.e. div-by-32) is implicit. */ + rate >>= 5; + if (!rate) + return 0; + + /* calculate terminal count from postscaler. */ + ps = pic32_wdt_get_post_scaler(wdt); + terminal = BIT(ps); + + /* find time taken (in secs) to reach terminal count */ + period = terminal / rate; + dev_dbg(dev, + "wdt: clk_rate %lu (postscale) / terminal %d, timeout %dsec\n", + rate, terminal, period); + + return period; +} + +static void pic32_wdt_keepalive(struct pic32_wdt *wdt) +{ + /* write key through single half-word */ + writew(WDTCON_CLR_KEY, wdt->regs + WDTCON_REG + 2); +} + +static int pic32_wdt_start(struct watchdog_device *wdd) +{ + struct pic32_wdt *wdt = watchdog_get_drvdata(wdd); + + writel(WDTCON_ON, PIC32_SET(wdt->regs + WDTCON_REG)); + pic32_wdt_keepalive(wdt); + + return 0; +} + +static int pic32_wdt_stop(struct watchdog_device *wdd) +{ + struct pic32_wdt *wdt = watchdog_get_drvdata(wdd); + + writel(WDTCON_ON, PIC32_CLR(wdt->regs + WDTCON_REG)); + + /* + * Cannot touch registers in the CPU cycle following clearing the + * ON bit. + */ + nop(); + + return 0; +} + +static int pic32_wdt_ping(struct watchdog_device *wdd) +{ + struct pic32_wdt *wdt = watchdog_get_drvdata(wdd); + + pic32_wdt_keepalive(wdt); + + return 0; +} + +static const struct watchdog_ops pic32_wdt_fops = { + .owner = THIS_MODULE, + .start = pic32_wdt_start, + .stop = pic32_wdt_stop, + .ping = pic32_wdt_ping, +}; + +static const struct watchdog_info pic32_wdt_ident = { + .options = WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE | WDIOF_CARDRESET, + .identity = "PIC32 Watchdog", +}; + +static struct watchdog_device pic32_wdd = { + .info = &pic32_wdt_ident, + .ops = &pic32_wdt_fops, +}; + +static const struct of_device_id pic32_wdt_dt_ids[] = { + { .compatible = "microchip,pic32mzda-wdt", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pic32_wdt_dt_ids); + +static int pic32_wdt_drv_probe(struct platform_device *pdev) +{ + int ret; + struct watchdog_device *wdd = &pic32_wdd; + struct pic32_wdt *wdt; + struct resource *mem; + + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (IS_ERR(wdt)) + return PTR_ERR(wdt); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + wdt->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(wdt->regs)) + return PTR_ERR(wdt->regs); + + wdt->rst_base = devm_ioremap(&pdev->dev, PIC32_BASE_RESET, 0x10); + if (IS_ERR(wdt->rst_base)) + return PTR_ERR(wdt->rst_base); + + wdt->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(wdt->clk)) { + dev_err(&pdev->dev, "clk not found\n"); + return PTR_ERR(wdt->clk); + } + + ret = clk_prepare_enable(wdt->clk); + if (ret) { + dev_err(&pdev->dev, "clk enable failed\n"); + return ret; + } + + if (pic32_wdt_is_win_enabled(wdt)) { + dev_err(&pdev->dev, "windowed-clear mode is not supported.\n"); + ret = -ENODEV; + goto out_disable_clk; + } + + wdd->timeout = pic32_wdt_get_timeout_secs(wdt, &pdev->dev); + if (!wdd->timeout) { + dev_err(&pdev->dev, + "failed to read watchdog register timeout\n"); + ret = -EINVAL; + goto out_disable_clk; + } + + dev_info(&pdev->dev, "timeout %d\n", wdd->timeout); + + wdd->bootstatus = pic32_wdt_bootstatus(wdt) ? WDIOF_CARDRESET : 0; + + watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT); + watchdog_set_drvdata(wdd, wdt); + + ret = watchdog_register_device(wdd); + if (ret) { + dev_err(&pdev->dev, "watchdog register failed, err %d\n", ret); + goto out_disable_clk; + } + + platform_set_drvdata(pdev, wdd); + + return 0; + +out_disable_clk: + clk_disable_unprepare(wdt->clk); + + return ret; +} + +static int pic32_wdt_drv_remove(struct platform_device *pdev) +{ + struct watchdog_device *wdd = platform_get_drvdata(pdev); + struct pic32_wdt *wdt = watchdog_get_drvdata(wdd); + + watchdog_unregister_device(wdd); + clk_disable_unprepare(wdt->clk); + + return 0; +} + +static struct platform_driver pic32_wdt_driver = { + .probe = pic32_wdt_drv_probe, + .remove = pic32_wdt_drv_remove, + .driver = { + .name = "pic32-wdt", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pic32_wdt_dt_ids), + } +}; + +module_platform_driver(pic32_wdt_driver); + +MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>"); +MODULE_DESCRIPTION("Microchip PIC32 Watchdog Timer"); +MODULE_LICENSE("GPL"); diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 8afe10cf7df8..8ab782d8b33d 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -1071,7 +1071,7 @@ static int __init parse_crash_elf32_headers(void) /* Do some basic Verification. */ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || (ehdr.e_type != ET_CORE) || - !elf_check_arch(&ehdr) || + !vmcore_elf32_check_arch(&ehdr) || ehdr.e_ident[EI_CLASS] != ELFCLASS32|| ehdr.e_ident[EI_VERSION] != EV_CURRENT || ehdr.e_version != EV_CURRENT || diff --git a/include/asm-generic/seccomp.h b/include/asm-generic/seccomp.h index c9ccafa0d99a..e74072d23e69 100644 --- a/include/asm-generic/seccomp.h +++ b/include/asm-generic/seccomp.h @@ -29,4 +29,18 @@ #define __NR_seccomp_sigreturn __NR_rt_sigreturn #endif +#ifdef CONFIG_COMPAT +#ifndef get_compat_mode1_syscalls +static inline const int *get_compat_mode1_syscalls(void) +{ + static const int mode1_syscalls_32[] = { + __NR_seccomp_read_32, __NR_seccomp_write_32, + __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32, + 0, /* null terminated */ + }; + return mode1_syscalls_32; +} +#endif +#endif /* CONFIG_COMPAT */ + #endif /* _ASM_GENERIC_SECCOMP_H */ diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h index 3d1a3af5cf59..a2508a8f9a9c 100644 --- a/include/asm-generic/siginfo.h +++ b/include/asm-generic/siginfo.h @@ -17,21 +17,6 @@ struct siginfo; void do_schedule_next_timer(struct siginfo *info); -#ifndef HAVE_ARCH_COPY_SIGINFO - -#include <linux/string.h> - -static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) -{ - if (from->si_code < 0) - memcpy(to, from, sizeof(*to)); - else - /* _sigchld is currently the largest know union member */ - memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld)); -} - -#endif - extern int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); #endif diff --git a/include/dt-bindings/clock/ath79-clk.h b/include/dt-bindings/clock/ath79-clk.h new file mode 100644 index 000000000000..27359ad83904 --- /dev/null +++ b/include/dt-bindings/clock/ath79-clk.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014, 2016 Antony Pavlov <antonynpavlov@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __DT_BINDINGS_ATH79_CLK_H +#define __DT_BINDINGS_ATH79_CLK_H + +#define ATH79_CLK_CPU 0 +#define ATH79_CLK_DDR 1 +#define ATH79_CLK_AHB 2 + +#define ATH79_CLK_END 3 + +#endif /* __DT_BINDINGS_ATH79_CLK_H */ diff --git a/include/dt-bindings/clock/microchip,pic32-clock.h b/include/dt-bindings/clock/microchip,pic32-clock.h new file mode 100644 index 000000000000..184647a6a8de --- /dev/null +++ b/include/dt-bindings/clock/microchip,pic32-clock.h @@ -0,0 +1,42 @@ +/* + * Purna Chandra Mandal,<purna.mandal@microchip.com> + * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MICROCHIP_PIC32_H_ +#define _DT_BINDINGS_CLK_MICROCHIP_PIC32_H_ + +/* clock output indices */ +#define POSCCLK 0 +#define FRCCLK 1 +#define BFRCCLK 2 +#define LPRCCLK 3 +#define SOSCCLK 4 +#define FRCDIVCLK 5 +#define PLLCLK 6 +#define SCLK 7 +#define PB1CLK 8 +#define PB2CLK 9 +#define PB3CLK 10 +#define PB4CLK 11 +#define PB5CLK 12 +#define PB6CLK 13 +#define PB7CLK 14 +#define REF1CLK 15 +#define REF2CLK 16 +#define REF3CLK 17 +#define REF4CLK 18 +#define REF5CLK 19 +#define UPLLCLK 20 +#define MAXCLKS 21 + +#endif /* _DT_BINDINGS_CLK_MICROCHIP_PIC32_H_ */ diff --git a/include/linux/bcm47xx_sprom.h b/include/linux/bcm47xx_sprom.h new file mode 100644 index 000000000000..c06b47c84e1a --- /dev/null +++ b/include/linux/bcm47xx_sprom.h @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#ifndef __BCM47XX_SPROM_H +#define __BCM47XX_SPROM_H + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> + +#ifdef CONFIG_BCM47XX_SPROM +int bcm47xx_sprom_register_fallbacks(void); +#else +static inline int bcm47xx_sprom_register_fallbacks(void) +{ + return -ENOTSUPP; +}; +#endif + +#endif /* __BCM47XX_SPROM_H */ diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h index 3849fce7ecfe..3873697ba21c 100644 --- a/include/linux/crash_dump.h +++ b/include/linux/crash_dump.h @@ -34,9 +34,13 @@ void vmcore_cleanup(void); /* * Architecture code can redefine this if there are any special checks - * needed for 64-bit ELF vmcores. In case of 32-bit only architecture, - * this can be set to zero. + * needed for 32-bit ELF or 64-bit ELF vmcores. In case of 32-bit + * only architecture, vmcore_elf64_check_arch can be set to zero. */ +#ifndef vmcore_elf32_check_arch +#define vmcore_elf32_check_arch(x) elf_check_arch(x) +#endif + #ifndef vmcore_elf64_check_arch #define vmcore_elf64_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x)) #endif diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index 80f89e4a29ac..81f930b0bca9 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -103,6 +103,7 @@ #define GIC_VPE_SWINT0_MAP_OFS 0x0054 #define GIC_VPE_SWINT1_MAP_OFS 0x0058 #define GIC_VPE_OTHER_ADDR_OFS 0x0080 +#define GIC_VP_IDENT_OFS 0x0088 #define GIC_VPE_WD_CONFIG0_OFS 0x0090 #define GIC_VPE_WD_COUNT0_OFS 0x0094 #define GIC_VPE_WD_INITIAL0_OFS 0x0098 @@ -211,6 +212,10 @@ #define GIC_VPE_SMASK_FDC_SHF 6 #define GIC_VPE_SMASK_FDC_MSK (MSK(1) << GIC_VPE_SMASK_FDC_SHF) +/* GIC_VP_IDENT fields */ +#define GIC_VP_IDENT_VCNUM_SHF 0 +#define GIC_VP_IDENT_VCNUM_MSK (MSK(6) << GIC_VP_IDENT_VCNUM_SHF) + /* GIC nomenclature for Core Interrupt Pins. */ #define GIC_CPU_INT0 0 /* Core Interrupt 2 */ #define GIC_CPU_INT1 1 /* . */ @@ -278,4 +283,16 @@ static inline int gic_get_usm_range(struct resource *gic_usm_res) #endif /* CONFIG_MIPS_GIC */ +/** + * gic_read_local_vp_id() - read the local VPs VCNUM + * + * Read the VCNUM of the local VP from the GIC_VP_IDENT register and + * return it to the caller. This ID should be used to refer to the VP + * via the GICs VP-other region, or when calculating an offset to a + * bit representing the VP in interrupt masks. + * + * Return: The VCNUM value for the local VP. + */ +extern unsigned gic_read_local_vp_id(void); + #endif /* __LINUX_IRQCHIP_MIPS_GIC_H */ diff --git a/include/linux/signal.h b/include/linux/signal.h index 3fbe81444d31..639be264f5f9 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -28,6 +28,21 @@ struct sigpending { sigset_t signal; }; +#ifndef HAVE_ARCH_COPY_SIGINFO + +#include <linux/string.h> + +static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) +{ + if (from->si_code < 0) + memcpy(to, from, sizeof(*to)); + else + /* _sigchld is currently the largest know union member */ + memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld)); +} + +#endif + /* * Define some primitives to manipulate sigset_t. */ diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index e513a4ee369b..24da334af7f1 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -264,4 +264,7 @@ /* MVEBU UART */ #define PORT_MVEBU 114 +/* Microchip PIC32 UART */ +#define PORT_PIC32 115 + #endif /* _UAPILINUX_SERIAL_CORE_H */ diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 6c9bb62ed046..7002796f14a4 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -513,24 +513,17 @@ static void seccomp_send_sigsys(int syscall, int reason) * To be fully secure this must be combined with rlimit * to limit the stack allocations too. */ -static int mode1_syscalls[] = { +static const int mode1_syscalls[] = { __NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn, 0, /* null terminated */ }; -#ifdef CONFIG_COMPAT -static int mode1_syscalls_32[] = { - __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32, - 0, /* null terminated */ -}; -#endif - static void __secure_computing_strict(int this_syscall) { - int *syscall_whitelist = mode1_syscalls; + const int *syscall_whitelist = mode1_syscalls; #ifdef CONFIG_COMPAT if (in_compat_syscall()) - syscall_whitelist = mode1_syscalls_32; + syscall_whitelist = get_compat_mode1_syscalls(); #endif do { if (*syscall_whitelist == this_syscall) diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh index 7bfe9fa1c8dc..d135882e2c40 100755 --- a/scripts/ld-version.sh +++ b/scripts/ld-version.sh @@ -5,6 +5,6 @@ gsub(".*version ", ""); gsub("-.*", ""); split($1,a, "."); - print a[1]*100000000 + a[2]*1000000 + a[3]*10000 + a[4]*100 + a[5]; + print a[1]*100000000 + a[2]*1000000 + a[3]*10000; exit } diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 150829dd7998..7947e568e057 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -5,6 +5,7 @@ * Test code for seccomp bpf. */ +#include <sys/types.h> #include <asm/siginfo.h> #define __have_siginfo_t 1 #define __have_sigval_t 1 @@ -14,7 +15,6 @@ #include <linux/filter.h> #include <sys/prctl.h> #include <sys/ptrace.h> -#include <sys/types.h> #include <sys/user.h> #include <linux/prctl.h> #include <linux/ptrace.h> @@ -1242,6 +1242,12 @@ TEST_F(TRACE_poke, getpid_runs_normally) # define ARCH_REGS s390_regs # define SYSCALL_NUM gprs[2] # define SYSCALL_RET gprs[2] +#elif defined(__mips__) +# define ARCH_REGS struct pt_regs +# define SYSCALL_NUM regs[2] +# define SYSCALL_SYSCALL_NUM regs[4] +# define SYSCALL_RET regs[2] +# define SYSCALL_NUM_RET_SHARE_REG #else # error "Do not know how to find your architecture's registers and syscalls" #endif @@ -1249,7 +1255,7 @@ TEST_F(TRACE_poke, getpid_runs_normally) /* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux). */ -#if defined(__x86_64__) || defined(__i386__) +#if defined(__x86_64__) || defined(__i386__) || defined(__mips__) #define HAVE_GETREGS #endif @@ -1273,6 +1279,10 @@ int get_syscall(struct __test_metadata *_metadata, pid_t tracee) } #endif +#if defined(__mips__) + if (regs.SYSCALL_NUM == __NR_O32_Linux) + return regs.SYSCALL_SYSCALL_NUM; +#endif return regs.SYSCALL_NUM; } @@ -1297,6 +1307,13 @@ void change_syscall(struct __test_metadata *_metadata, { regs.SYSCALL_NUM = syscall; } +#elif defined(__mips__) + { + if (regs.SYSCALL_NUM == __NR_O32_Linux) + regs.SYSCALL_SYSCALL_NUM = syscall; + else + regs.SYSCALL_NUM = syscall; + } #elif defined(__arm__) # ifndef PTRACE_SET_SYSCALL @@ -1327,7 +1344,11 @@ void change_syscall(struct __test_metadata *_metadata, /* If syscall is skipped, change return value. */ if (syscall == -1) +#ifdef SYSCALL_NUM_RET_SHARE_REG + TH_LOG("Can't modify syscall return on this architecture"); +#else regs.SYSCALL_RET = 1; +#endif #ifdef HAVE_GETREGS ret = ptrace(PTRACE_SETREGS, tracee, 0, ®s); @@ -1465,8 +1486,13 @@ TEST_F(TRACE_syscall, syscall_dropped) ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->prog, 0, 0); ASSERT_EQ(0, ret); +#ifdef SYSCALL_NUM_RET_SHARE_REG + /* gettid has been skipped */ + EXPECT_EQ(-1, syscall(__NR_gettid)); +#else /* gettid has been skipped and an altered return value stored. */ EXPECT_EQ(1, syscall(__NR_gettid)); +#endif EXPECT_NE(self->mytid, syscall(__NR_gettid)); } |