diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 17:56:37 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 17:56:37 -0800 |
commit | c0222ac086669a631814bbf857f8c8023452a4d7 (patch) | |
tree | bb1d9908031fcf69016eeefa7b35a4f68f414333 | |
parent | 140cd7fb04a4a2bc09a30980bc8104cc89e09330 (diff) | |
parent | e2965cd0003f222bd49f67907c2bc6ed691c6d20 (diff) | |
download | op-kernel-dev-c0222ac086669a631814bbf857f8c8023452a4d7.zip op-kernel-dev-c0222ac086669a631814bbf857f8c8023452a4d7.tar.gz |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"This is an unusually large pull request for MIPS - in parts because
lots of patches missed the 3.18 deadline but primarily because some
folks opened the flood gates.
- Retire the MIPS-specific phys_t with the generic phys_addr_t.
- Improvments for the backtrace code used by oprofile.
- Better backtraces on SMP systems.
- Cleanups for the Octeon platform code.
- Cleanups and fixes for the Loongson platform code.
- Cleanups and fixes to the firmware library.
- Switch ATH79 platform to use the firmware library.
- Grand overhault to the SEAD3 and Malta interrupt code.
- Move the GIC interrupt code to drivers/irqchip
- Lots of GIC cleanups and updates to the GIC code to use modern IRQ
infrastructures and features of the kernel.
- OF documentation updates for the GIC bindings
- Move GIC clocksource driver to drivers/clocksource
- Merge GIC clocksource driver with clockevent driver.
- Further updates to bring the GIC clocksource driver up to date.
- R3000 TLB code cleanups
- Improvments to the Loongson 3 platform code.
- Convert pr_warning to pr_warn.
- Merge a bunch of small lantiq and ralink fixes that have been
staged/lingering inside the openwrt tree for a while.
- Update archhelp for IP22/IP32
- Fix a number of issues for Loongson 1B.
- New clocksource and clockevent driver for Loongson 1B.
- Further work on clk handling for Loongson 1B.
- Platform work for Broadcom BMIPS.
- Error handling cleanups for TurboChannel.
- Fixes and optimization to the microMIPS support.
- Option to disable the FTLB.
- Dump more relevant information on machine check exception
- Change binfmt to allow arch to examine PT_*PROC headers
- Support for new style FPU register model in O32
- VDSO randomization.
- BCM47xx cleanups
- BCM47xx reimplement the way the kernel accesses NVRAM information.
- Random cleanups
- Add support for ATH25 platforms
- Remove pointless locking code in some PCI platforms.
- Some improvments to EVA support
- Minor Alchemy cleanup"
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (185 commits)
MIPS: Add MFHC0 and MTHC0 instructions to uasm.
MIPS: Cosmetic cleanups of page table headers.
MIPS: Add CP0 macros for extended EntryLo registers
MIPS: Remove now unused definition of phys_t.
MIPS: Replace use of phys_t with phys_addr_t.
MIPS: Replace MIPS-specific 64BIT_PHYS_ADDR with generic PHYS_ADDR_T_64BIT
PCMCIA: Alchemy Don't select 64BIT_PHYS_ADDR in Kconfig.
MIPS: lib: memset: Clean up some MIPS{EL,EB} ifdefery
MIPS: iomap: Use __mem_{read,write}{b,w,l} for MMIO
MIPS: <asm/types.h> fix indentation.
MAINTAINERS: Add entry for BMIPS multiplatform kernel
MIPS: Enable VDSO randomization
MIPS: Remove a temporary hack for debugging cache flushes in SMTC configuration
MIPS: Remove declaration of obsolete arch_init_clk_ops()
MIPS: atomic.h: Reformat to fit in 79 columns
MIPS: Apply `.insn' to fixup labels throughout
MIPS: Fix microMIPS LL/SC immediate offsets
MIPS: Kconfig: Only allow 32-bit microMIPS builds
MIPS: signal.c: Fix an invalid cast in ISA mode bit handling
MIPS: mm: Only build one microassembler that is suitable
...
289 files changed, 9835 insertions, 3443 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt b/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt new file mode 100644 index 0000000..5a65478 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/mips-gic.txt @@ -0,0 +1,55 @@ +MIPS Global Interrupt Controller (GIC) + +The MIPS GIC routes external interrupts to individual VPEs and IRQ pins. +It also supports local (per-processor) interrupts and software-generated +interrupts which can be used as IPIs. The GIC also includes a free-running +global timer, per-CPU count/compare timers, and a watchdog. + +Required properties: +- compatible : Should be "mti,gic". +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt specifier. Should be 3. + - The first cell is the type of interrupt, local or shared. + See <include/dt-bindings/interrupt-controller/mips-gic.h>. + - The second cell is the GIC interrupt number. + - The third cell encodes the interrupt flags. + See <include/dt-bindings/interrupt-controller/irq.h> for a list of valid + flags. + +Optional properties: +- reg : Base address and length of the GIC registers. If not present, + the base address reported by the hardware GCR_GIC_BASE will be used. +- mti,reserved-cpu-vectors : Specifies the list of CPU interrupt vectors + to which the GIC may not route interrupts. Valid values are 2 - 7. + This property is ignored if the CPU is started in EIC mode. + +Required properties for timer sub-node: +- compatible : Should be "mti,gic-timer". +- interrupts : Interrupt for the GIC local timer. +- clock-frequency : Clock frequency at which the GIC timers operate. + +Example: + + gic: interrupt-controller@1bdc0000 { + compatible = "mti,gic"; + reg = <0x1bdc0000 0x20000>; + + interrupt-controller; + #interrupt-cells = <3>; + + mti,reserved-cpu-vectors = <7>; + + timer { + compatible = "mti,gic-timer"; + interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>; + clock-frequency = <50000000>; + }; + }; + + uart@18101400 { + ... + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>; + ... + }; diff --git a/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt b/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt new file mode 100644 index 0000000..d4e0141d --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/bcm3384-intc.txt @@ -0,0 +1,37 @@ +* Interrupt Controller + +Properties: +- compatible: "brcm,bcm3384-intc" + + Compatibility with BCM3384 and possibly other BCM33xx/BCM63xx SoCs. + +- reg: Address/length pairs for each mask/status register set. Length must + be 8. If multiple register sets are specified, the first set will + handle IRQ offsets 0..31, the second set 32..63, and so on. + +- interrupt-controller: This is an interrupt controller. + +- #interrupt-cells: Must be <1>. Just a simple IRQ offset; no level/edge + or polarity configuration is possible with this controller. + +- interrupt-parent: This controller is cascaded from a MIPS CPU HW IRQ, or + from another INTC. + +- interrupts: The IRQ on the parent controller. + +Example: + periph_intc: periph_intc@14e00038 { + compatible = "brcm,bcm3384-intc"; + + /* + * IRQs 0..31: mask reg 0x14e00038, status reg 0x14e0003c + * IRQs 32..63: mask reg 0x14e00340, status reg 0x14e00344 + */ + reg = <0x14e00038 0x8 0x14e00340 0x8>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <4>; + }; diff --git a/Documentation/devicetree/bindings/mips/brcm/bmips.txt b/Documentation/devicetree/bindings/mips/brcm/bmips.txt new file mode 100644 index 0000000..8ef71b4 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/bmips.txt @@ -0,0 +1,8 @@ +* Broadcom MIPS (BMIPS) CPUs + +Required properties: +- compatible: "brcm,bmips3300", "brcm,bmips4350", "brcm,bmips4380", + "brcm,bmips5000" + +- mips-hpt-frequency: This is common to all CPUs in the system so it lives + under the "cpus" node. diff --git a/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt b/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt new file mode 100644 index 0000000..8a139cb3 --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/cm-dsl.txt @@ -0,0 +1,11 @@ +* Broadcom cable/DSL platforms + +SoCs: + +Required properties: +- compatible: "brcm,bcm3384", "brcm,bcm33843" + +Boards: + +Required properties: +- compatible: "brcm,bcm93384wvg" diff --git a/Documentation/devicetree/bindings/mips/brcm/usb.txt b/Documentation/devicetree/bindings/mips/brcm/usb.txt new file mode 100644 index 0000000..452c45c --- /dev/null +++ b/Documentation/devicetree/bindings/mips/brcm/usb.txt @@ -0,0 +1,11 @@ +* Broadcom USB controllers + +Required properties: +- compatible: "brcm,bcm3384-ohci", "brcm,bcm3384-ehci" + + These currently use the generic-ohci and generic-ehci drivers. On some + systems, special handling may be needed in the following cases: + + - Restoring state after systemwide power save modes + - Sharing PHYs with the USBD (UDC) hardware + - Figuring out which controllers are disabled on ASIC bondout variants diff --git a/Documentation/devicetree/bindings/mips/cpu_irq.txt b/Documentation/devicetree/bindings/mips/cpu_irq.txt index 13aa4b6..fc149f3 100644 --- a/Documentation/devicetree/bindings/mips/cpu_irq.txt +++ b/Documentation/devicetree/bindings/mips/cpu_irq.txt @@ -1,6 +1,6 @@ MIPS CPU interrupt controller -On MIPS the mips_cpu_intc_init() helper can be used to initialize the 8 CPU +On MIPS the mips_cpu_irq_of_init() helper can be used to initialize the 8 CPU IRQs from a devicetree file and create a irq_domain for IRQ controller. With the irq_domain in place we can describe how the 8 IRQs are wired to the @@ -36,7 +36,7 @@ Example devicetree: Example platform irq.c: static struct of_device_id __initdata of_irq_ids[] = { - { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init }, + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, {}, }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 2417cb0..cc6151c 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -101,6 +101,7 @@ mitsubishi Mitsubishi Electric Corporation mosaixtech Mosaix Technologies, Inc. moxa Moxa mpl MPL AG +mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.) mundoreader Mundo Reader S.L. murata Murata Manufacturing Co., Ltd. mxicy Macronix International Co., Ltd. diff --git a/MAINTAINERS b/MAINTAINERS index 34b4b84..e186bf9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2085,6 +2085,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rpi/linux-rpi.git S: Maintained N: bcm2835 +BROADCOM BCM33XX MIPS ARCHITECTURE +M: Kevin Cernekee <cernekee@gmail.com> +L: linux-mips@linux-mips.org +S: Maintained +F: arch/mips/bcm3384/* +F: arch/mips/include/asm/mach-bcm3384/* +F: arch/mips/kernel/*bmips* + BROADCOM BCM5301X ARM ARCHITECTURE M: Hauke Mehrtens <hauke@hauke-m.de> L: linux-arm-kernel@lists.infradead.org @@ -2101,6 +2109,12 @@ S: Maintained F: arch/arm/mach-bcm/bcm63xx.c F: arch/arm/include/debug/bcm63xx.S +BROADCOM BCM63XX/BCM33XX UDC DRIVER +M: Kevin Cernekee <cernekee@gmail.com> +L: linux-usb@vger.kernel.org +S: Maintained +F: drivers/usb/gadget/udc/bcm63xx_udc.* + BROADCOM BCM7XXX ARM ARCHITECTURE M: Marc Carino <marc.ceeeee@gmail.com> M: Brian Norris <computersforpeace@gmail.com> @@ -2112,6 +2126,18 @@ F: arch/arm/mach-bcm/*brcmstb* F: arch/arm/boot/dts/bcm7*.dts* F: drivers/bus/brcmstb_gisb.c +BROADCOM BMIPS MIPS ARCHITECTURE +M: Kevin Cernekee <cernekee@gmail.com> +M: Florian Fainelli <f.fainelli@gmail.com> +L: linux-mips@linux-mips.org +S: Maintained +F: arch/mips/bmips/* +F: arch/mips/include/asm/mach-bmips/* +F: arch/mips/kernel/*bmips* +F: arch/mips/boot/dts/bcm*.dts* +F: drivers/irqchip/irq-bcm7* +F: drivers/irqchip/irq-brcmstb* + BROADCOM TG3 GIGABIT ETHERNET DRIVER M: Prashant Sreedharan <prashant@broadcom.com> M: Michael Chan <mchan@broadcom.com> diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index f5e18bf3..e5fc463 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -2,7 +2,9 @@ platforms += alchemy platforms += ar7 +platforms += ath25 platforms += ath79 +platforms += bcm3384 platforms += bcm47xx platforms += bcm63xx platforms += cavium-octeon diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 9536ef9..3289969 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -53,6 +53,7 @@ config MIPS select HAVE_CC_STACKPROTECTOR select CPU_PM if CPU_IDLE select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST + select ARCH_BINFMT_ELF_STATE menu "Machine selection" @@ -62,7 +63,7 @@ choice config MIPS_ALCHEMY bool "Alchemy processor based machines" - select 64BIT_PHYS_ADDR + select ARCH_PHYS_ADDR_T_64BIT select CEVT_R4K select CSRC_R4K select IRQ_CPU @@ -96,6 +97,20 @@ config AR7 Support for the Texas Instruments AR7 System-on-a-Chip family: TNETD7100, 7200 and 7300. +config ATH25 + bool "Atheros AR231x/AR531x SoC support" + select CEVT_R4K + select CSRC_R4K + select DMA_NONCOHERENT + select IRQ_CPU + select IRQ_DOMAIN + select SYS_HAS_CPU_MIPS32_R1 + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_HAS_EARLY_PRINTK + help + Support for Atheros AR231x and Atheros AR531x based boards + config ATH79 bool "Atheros AR71XX/AR724X/AR913X based boards" select ARCH_REQUIRE_GPIOLIB @@ -115,6 +130,32 @@ config ATH79 help Support for the Atheros AR71XX/AR724X/AR913X SoCs. +config BCM3384 + bool "Broadcom BCM3384 based boards" + select BOOT_RAW + select NO_EXCEPT_FILL + select USE_OF + select CEVT_R4K + select CSRC_R4K + select SYNC_R4K + select COMMON_CLK + select DMA_NONCOHERENT + select IRQ_CPU + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_HIGHMEM + select SYS_HAS_CPU_BMIPS5000 + select SWAP_IO_SPACE + select USB_EHCI_BIG_ENDIAN_DESC + select USB_EHCI_BIG_ENDIAN_MMIO + select USB_OHCI_BIG_ENDIAN_DESC + select USB_OHCI_BIG_ENDIAN_MMIO + help + Support for BCM3384 based boards. BCM3384/BCM33843 is a cable modem + chipset with a Linux application processor that is often used to + provide Samba services, a CUPS print server, and/or advanced routing + features. + config BCM47XX bool "Broadcom BCM47XX based boards" select ARCH_WANT_OPTIONAL_GPIOLIB @@ -269,6 +310,8 @@ config LANTIQ select USE_OF select PINCTRL select PINCTRL_LANTIQ + select ARCH_HAS_RESET_CONTROLLER + select RESET_CONTROLLER config LASAT bool "LASAT Networks platforms" @@ -315,17 +358,18 @@ config MIPS_MALTA select BOOT_RAW select CEVT_R4K select CSRC_R4K - select CSRC_GIC + select CLKSRC_MIPS_GIC select DMA_MAYBE_COHERENT select GENERIC_ISA_DMA select HAVE_PCSPKR_PLATFORM select IRQ_CPU - select IRQ_GIC + select MIPS_GIC select HW_HAS_PCI select I8253 select I8259 select MIPS_BONITO64 select MIPS_CPU_SCACHE + select MIPS_L1_CACHE_SHIFT_6 select PCI_GT64XXX_PCI0 select MIPS_MSC select SWAP_IO_SPACE @@ -340,6 +384,7 @@ config MIPS_MALTA select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_MICROMIPS select SYS_SUPPORTS_MIPS_CMP select SYS_SUPPORTS_MIPS_CPS select SYS_SUPPORTS_MIPS16 @@ -357,12 +402,12 @@ config MIPS_SEAD3 select BUILTIN_DTB select CEVT_R4K select CSRC_R4K - select CSRC_GIC + select CLKSRC_MIPS_GIC select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select DMA_NONCOHERENT select IRQ_CPU - select IRQ_GIC + select MIPS_GIC select LIBFDT select MIPS_MSC select SYS_HAS_CPU_MIPS32_R1 @@ -726,7 +771,7 @@ config MIKROTIK_RB532 config CAVIUM_OCTEON_SOC bool "Cavium Networks Octeon SoC based boards" select CEVT_R4K - select 64BIT_PHYS_ADDR + select ARCH_PHYS_ADDR_T_64BIT select DMA_COHERENT select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN @@ -768,7 +813,7 @@ config NLM_XLR_BOARD select SWAP_IO_SPACE select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL - select 64BIT_PHYS_ADDR + select ARCH_PHYS_ADDR_T_64BIT select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_HIGHMEM select DMA_COHERENT @@ -794,7 +839,7 @@ config NLM_XLP_BOARD select HW_HAS_PCI select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL - select 64BIT_PHYS_ADDR + select ARCH_PHYS_ADDR_T_64BIT select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_HIGHMEM @@ -835,6 +880,7 @@ config MIPS_PARAVIRT endchoice source "arch/mips/alchemy/Kconfig" +source "arch/mips/ath25/Kconfig" source "arch/mips/ath79/Kconfig" source "arch/mips/bcm47xx/Kconfig" source "arch/mips/bcm63xx/Kconfig" @@ -907,10 +953,6 @@ config CEVT_GT641XX config CEVT_R4K bool -config CEVT_GIC - select MIPS_CM - bool - config CEVT_SB1250 bool @@ -926,10 +968,6 @@ config CSRC_IOASIC config CSRC_R4K bool -config CSRC_GIC - select MIPS_CM - bool - config CSRC_SB1250 bool @@ -941,7 +979,7 @@ config FW_CFE bool config ARCH_DMA_ADDR_T_64BIT - def_bool (HIGHMEM && 64BIT_PHYS_ADDR) || 64BIT + def_bool (HIGHMEM && ARCH_PHYS_ADDR_T_64BIT) || 64BIT config DMA_MAYBE_COHERENT select DMA_NONCOHERENT @@ -975,6 +1013,7 @@ config SYS_SUPPORTS_HOTPLUG_CPU config I8259 bool + select IRQ_DOMAIN config MIPS_BONITO64 bool @@ -1055,6 +1094,7 @@ config MIPS_HUGE_TLB_SUPPORT config IRQ_CPU bool + select IRQ_DOMAIN config IRQ_CPU_RM7K bool @@ -1071,10 +1111,6 @@ config IRQ_TXX9 config IRQ_GT641XX bool -config IRQ_GIC - select MIPS_CM - bool - config PCI_GT64XXX_PCI0 bool @@ -1574,6 +1610,7 @@ config CPU_LOONGSON1 select CPU_HAS_PREFETCH select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_HIGHMEM + select CPU_SUPPORTS_CPUFREQ config CPU_BMIPS32_3300 select SMP_UP if SMP @@ -1586,12 +1623,14 @@ config CPU_BMIPS4350 config CPU_BMIPS4380 bool + select MIPS_L1_CACHE_SHIFT_6 select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU config CPU_BMIPS5000 bool select MIPS_CPU_SCACHE + select MIPS_L1_CACHE_SHIFT_7 select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU @@ -1886,15 +1925,6 @@ config FORCE_MAX_ZONEORDER The page size is not necessarily 4KB. Keep this in mind when choosing a value for this option. -config CEVT_GIC - bool "Use GIC global counter for clock events" - depends on IRQ_GIC && !MIPS_SEAD3 - help - Use the GIC global counter for the clock events. The R4K clock - event driver is always present, so if the platform ends up not - detecting a GIC, it will fall back to the R4K timer for the - generation of clock events. - config BOARD_SCACHE bool @@ -1908,7 +1938,6 @@ config IP22_CPU_SCACHE config MIPS_CPU_SCACHE bool select BOARD_SCACHE - select MIPS_L1_CACHE_SHIFT_6 config R5000_CPU_SCACHE bool @@ -2095,11 +2124,8 @@ config SB1_PASS_2_1_WORKAROUNDS default y -config 64BIT_PHYS_ADDR - bool - config ARCH_PHYS_ADDR_T_64BIT - def_bool 64BIT_PHYS_ADDR + bool choice prompt "SmartMIPS or microMIPS ASE support" @@ -2122,7 +2148,7 @@ config CPU_HAS_SMARTMIPS here. config CPU_MICROMIPS - depends on SYS_SUPPORTS_MICROMIPS + depends on 32BIT && SYS_SUPPORTS_MICROMIPS bool "microMIPS" help When this option is enabled the kernel will be built using the diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index 3a2b775..88a9f43 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -122,4 +122,17 @@ config SPINLOCK_TEST help Add several files to the debugfs to test spinlock speed. +config FP32XX_HYBRID_FPRS + bool "Run FP32 & FPXX code with hybrid FPRs" + depends on MIPS_O32_FP64_SUPPORT + help + The hybrid FPR scheme is normally used only when a program needs to + execute a mix of FP32 & FP64A code, since the trapping & emulation + that it entails is expensive. When enabled, this option will lead + to the kernel running programs which use the FP32 & FPXX FP ABIs + using the hybrid FPR scheme, which can be useful for debugging + purposes. + + If unsure, say N. + endmenu diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 5807647..2563a08 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -380,6 +380,7 @@ define archhelp echo ' vmlinux.ecoff - ECOFF boot image' echo ' vmlinux.bin - Raw binary boot image' echo ' vmlinux.srec - SREC boot image' + echo ' vmlinux.32 - 64-bit boot image wrapped in 32bits (IP22/IP32)' echo ' vmlinuz - Compressed boot(zboot) image' echo ' vmlinuz.ecoff - ECOFF zboot image' echo ' vmlinuz.bin - Raw binary zboot image' diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index d7557cd..203e440 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -37,7 +37,6 @@ #include <linux/io.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> -#include <linux/clk-private.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/types.h> @@ -397,10 +396,10 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, break; /* if this parent is currently unused, remember it. - * XXX: I know it's a layering violation, but it works - * so well.. (if (!clk_has_active_children(pc)) ) + * XXX: we would actually want clk_has_active_children() + * but this is a good-enough approximation for now. */ - if (pc->prepare_count == 0) { + if (!__clk_is_prepared(pc)) { if (!free) free = pc; } diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index ea8f418..4e72daf 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -70,9 +70,9 @@ void __init plat_mem_setup(void) iomem_resource.end = IOMEM_RESOURCE_END; } -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_PCI) +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_PCI) /* This routine should be valid for all Au1x based boards */ -phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) +phys_addr_t __fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) { unsigned long start = ALCHEMY_PCI_MEMWIN_START; unsigned long end = ALCHEMY_PCI_MEMWIN_END; @@ -83,7 +83,7 @@ phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) /* Check for PCI memory window */ if (phys_addr >= start && (phys_addr + size - 1) <= end) - return (phys_t)(AU1500_PCI_MEM_PHYS_ADDR + phys_addr); + return (phys_addr_t)(AU1500_PCI_MEM_PHYS_ADDR + phys_addr); /* default nop */ return phys_addr; diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index 7e2356f..af2441d 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -311,8 +311,7 @@ static void __init cpmac_get_mac(int instance, unsigned char *dev_addr) &dev_addr[0], &dev_addr[1], &dev_addr[2], &dev_addr[3], &dev_addr[4], &dev_addr[5]) != 6) { - pr_warning("cannot parse mac address, " - "using random address\n"); + pr_warn("cannot parse mac address, using random address\n"); eth_random_addr(dev_addr); } } else @@ -665,7 +664,7 @@ static int __init ar7_register_devices(void) res = platform_device_register(&physmap_flash); if (res) - pr_warning("unable to register physmap-flash: %d\n", res); + pr_warn("unable to register physmap-flash: %d\n", res); if (ar7_is_titan()) titan_fixup_devices(); @@ -673,13 +672,13 @@ static int __init ar7_register_devices(void) ar7_device_disable(vlynq_low_data.reset_bit); res = platform_device_register(&vlynq_low); if (res) - pr_warning("unable to register vlynq-low: %d\n", res); + pr_warn("unable to register vlynq-low: %d\n", res); if (ar7_has_high_vlynq()) { ar7_device_disable(vlynq_high_data.reset_bit); res = platform_device_register(&vlynq_high); if (res) - pr_warning("unable to register vlynq-high: %d\n", res); + pr_warn("unable to register vlynq-high: %d\n", res); } if (ar7_has_high_cpmac()) { @@ -689,9 +688,10 @@ static int __init ar7_register_devices(void) res = platform_device_register(&cpmac_high); if (res) - pr_warning("unable to register cpmac-high: %d\n", res); + pr_warn("unable to register cpmac-high: %d\n", + res); } else - pr_warning("unable to add cpmac-high phy: %d\n", res); + pr_warn("unable to add cpmac-high phy: %d\n", res); } else cpmac_low_data.phy_mask = 0xffffffff; @@ -700,18 +700,18 @@ static int __init ar7_register_devices(void) cpmac_get_mac(0, cpmac_low_data.dev_addr); res = platform_device_register(&cpmac_low); if (res) - pr_warning("unable to register cpmac-low: %d\n", res); + pr_warn("unable to register cpmac-low: %d\n", res); } else - pr_warning("unable to add cpmac-low phy: %d\n", res); + pr_warn("unable to add cpmac-low phy: %d\n", res); detect_leds(); res = platform_device_register(&ar7_gpio_leds); if (res) - pr_warning("unable to register leds: %d\n", res); + pr_warn("unable to register leds: %d\n", res); res = platform_device_register(&ar7_udc); if (res) - pr_warning("unable to register usb slave: %d\n", res); + pr_warn("unable to register usb slave: %d\n", res); /* Register watchdog only if enabled in hardware */ bootcr = ioremap_nocache(AR7_REGS_DCL, 4); @@ -726,7 +726,7 @@ static int __init ar7_register_devices(void) ar7_wdt_res.end = ar7_wdt_res.start + 0x20; res = platform_device_register(&ar7_wdt); if (res) - pr_warning("unable to register watchdog: %d\n", res); + pr_warn("unable to register watchdog: %d\n", res); } return 0; diff --git a/arch/mips/ath25/Kconfig b/arch/mips/ath25/Kconfig new file mode 100644 index 0000000..fc19dd5 --- /dev/null +++ b/arch/mips/ath25/Kconfig @@ -0,0 +1,16 @@ +config SOC_AR5312 + bool "Atheros AR5312/AR2312+ SoC support" + depends on ATH25 + default y + +config SOC_AR2315 + bool "Atheros AR2315+ SoC support" + depends on ATH25 + default y + +config PCI_AR2315 + bool "Atheros AR2315 PCI controller support" + depends on SOC_AR2315 + select HW_HAS_PCI + select PCI + default y diff --git a/arch/mips/ath25/Makefile b/arch/mips/ath25/Makefile new file mode 100644 index 0000000..eabad7d --- /dev/null +++ b/arch/mips/ath25/Makefile @@ -0,0 +1,16 @@ +# +# 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) 2006 FON Technology, SL. +# Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> +# Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org> +# + +obj-y += board.o prom.o devices.o + +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +obj-$(CONFIG_SOC_AR5312) += ar5312.o +obj-$(CONFIG_SOC_AR2315) += ar2315.o diff --git a/arch/mips/ath25/Platform b/arch/mips/ath25/Platform new file mode 100644 index 0000000..ef3f81f --- /dev/null +++ b/arch/mips/ath25/Platform @@ -0,0 +1,6 @@ +# +# Atheros AR531X/AR231X WiSoC +# +platform-$(CONFIG_ATH25) += ath25/ +cflags-$(CONFIG_ATH25) += -I$(srctree)/arch/mips/include/asm/mach-ath25 +load-$(CONFIG_ATH25) += 0xffffffff80041000 diff --git a/arch/mips/ath25/ar2315.c b/arch/mips/ath25/ar2315.c new file mode 100644 index 0000000..2befa7d --- /dev/null +++ b/arch/mips/ath25/ar2315.c @@ -0,0 +1,364 @@ +/* + * 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) 2003 Atheros Communications, Inc., All Rights Reserved. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com> + */ + +/* + * Platform devices for Atheros AR2315 SoCs + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/irqdomain.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <asm/bootinfo.h> +#include <asm/reboot.h> +#include <asm/time.h> + +#include <ath25_platform.h> + +#include "devices.h" +#include "ar2315.h" +#include "ar2315_regs.h" + +static void __iomem *ar2315_rst_base; +static struct irq_domain *ar2315_misc_irq_domain; + +static inline u32 ar2315_rst_reg_read(u32 reg) +{ + return __raw_readl(ar2315_rst_base + reg); +} + +static inline void ar2315_rst_reg_write(u32 reg, u32 val) +{ + __raw_writel(val, ar2315_rst_base + reg); +} + +static inline void ar2315_rst_reg_mask(u32 reg, u32 mask, u32 val) +{ + u32 ret = ar2315_rst_reg_read(reg); + + ret &= ~mask; + ret |= val; + ar2315_rst_reg_write(reg, ret); +} + +static irqreturn_t ar2315_ahb_err_handler(int cpl, void *dev_id) +{ + ar2315_rst_reg_write(AR2315_AHB_ERR0, AR2315_AHB_ERROR_DET); + ar2315_rst_reg_read(AR2315_AHB_ERR1); + + pr_emerg("AHB fatal error\n"); + machine_restart("AHB error"); /* Catastrophic failure */ + + return IRQ_HANDLED; +} + +static struct irqaction ar2315_ahb_err_interrupt = { + .handler = ar2315_ahb_err_handler, + .name = "ar2315-ahb-error", +}; + +static void ar2315_misc_irq_handler(unsigned irq, struct irq_desc *desc) +{ + u32 pending = ar2315_rst_reg_read(AR2315_ISR) & + ar2315_rst_reg_read(AR2315_IMR); + unsigned nr, misc_irq = 0; + + if (pending) { + struct irq_domain *domain = irq_get_handler_data(irq); + + nr = __ffs(pending); + misc_irq = irq_find_mapping(domain, nr); + } + + if (misc_irq) { + if (nr == AR2315_MISC_IRQ_GPIO) + ar2315_rst_reg_write(AR2315_ISR, AR2315_ISR_GPIO); + else if (nr == AR2315_MISC_IRQ_WATCHDOG) + ar2315_rst_reg_write(AR2315_ISR, AR2315_ISR_WD); + generic_handle_irq(misc_irq); + } else { + spurious_interrupt(); + } +} + +static void ar2315_misc_irq_unmask(struct irq_data *d) +{ + ar2315_rst_reg_mask(AR2315_IMR, 0, BIT(d->hwirq)); +} + +static void ar2315_misc_irq_mask(struct irq_data *d) +{ + ar2315_rst_reg_mask(AR2315_IMR, BIT(d->hwirq), 0); +} + +static struct irq_chip ar2315_misc_irq_chip = { + .name = "ar2315-misc", + .irq_unmask = ar2315_misc_irq_unmask, + .irq_mask = ar2315_misc_irq_mask, +}; + +static int ar2315_misc_irq_map(struct irq_domain *d, unsigned irq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &ar2315_misc_irq_chip, handle_level_irq); + return 0; +} + +static struct irq_domain_ops ar2315_misc_irq_domain_ops = { + .map = ar2315_misc_irq_map, +}; + +/* + * Called when an interrupt is received, this function + * determines exactly which interrupt it was, and it + * invokes the appropriate handler. + * + * Implicitly, we also define interrupt priority by + * choosing which to dispatch first. + */ +static void ar2315_irq_dispatch(void) +{ + u32 pending = read_c0_status() & read_c0_cause(); + + if (pending & CAUSEF_IP3) + do_IRQ(AR2315_IRQ_WLAN0); +#ifdef CONFIG_PCI_AR2315 + else if (pending & CAUSEF_IP5) + do_IRQ(AR2315_IRQ_LCBUS_PCI); +#endif + else if (pending & CAUSEF_IP2) + do_IRQ(AR2315_IRQ_MISC); + else if (pending & CAUSEF_IP7) + do_IRQ(ATH25_IRQ_CPU_CLOCK); + else + spurious_interrupt(); +} + +void __init ar2315_arch_init_irq(void) +{ + struct irq_domain *domain; + unsigned irq; + + ath25_irq_dispatch = ar2315_irq_dispatch; + + domain = irq_domain_add_linear(NULL, AR2315_MISC_IRQ_COUNT, + &ar2315_misc_irq_domain_ops, NULL); + if (!domain) + panic("Failed to add IRQ domain"); + + irq = irq_create_mapping(domain, AR2315_MISC_IRQ_AHB); + setup_irq(irq, &ar2315_ahb_err_interrupt); + + irq_set_chained_handler(AR2315_IRQ_MISC, ar2315_misc_irq_handler); + irq_set_handler_data(AR2315_IRQ_MISC, domain); + + ar2315_misc_irq_domain = domain; +} + +void __init ar2315_init_devices(void) +{ + /* Find board configuration */ + ath25_find_config(AR2315_SPI_READ_BASE, AR2315_SPI_READ_SIZE); + + ath25_add_wmac(0, AR2315_WLAN0_BASE, AR2315_IRQ_WLAN0); +} + +static void ar2315_restart(char *command) +{ + void (*mips_reset_vec)(void) = (void *)0xbfc00000; + + local_irq_disable(); + + /* try reset the system via reset control */ + ar2315_rst_reg_write(AR2315_COLD_RESET, AR2317_RESET_SYSTEM); + + /* Cold reset does not work on the AR2315/6, use the GPIO reset bits + * a workaround. Give it some time to attempt a gpio based hardware + * reset (atheros reference design workaround) */ + + /* TODO: implement the GPIO reset workaround */ + + /* Some boards (e.g. Senao EOC-2610) don't implement the reset logic + * workaround. Attempt to jump to the mips reset location - + * the boot loader itself might be able to recover the system */ + mips_reset_vec(); +} + +/* + * This table is indexed by bits 5..4 of the CLOCKCTL1 register + * to determine the predevisor value. + */ +static int clockctl1_predivide_table[4] __initdata = { 1, 2, 4, 5 }; +static int pllc_divide_table[5] __initdata = { 2, 3, 4, 6, 3 }; + +static unsigned __init ar2315_sys_clk(u32 clock_ctl) +{ + unsigned int pllc_ctrl, cpu_div; + unsigned int pllc_out, refdiv, fdiv, divby2; + unsigned int clk_div; + + pllc_ctrl = ar2315_rst_reg_read(AR2315_PLLC_CTL); + refdiv = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_REF_DIV); + refdiv = clockctl1_predivide_table[refdiv]; + fdiv = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_FDBACK_DIV); + divby2 = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_ADD_FDBACK_DIV) + 1; + pllc_out = (40000000 / refdiv) * (2 * divby2) * fdiv; + + /* clkm input selected */ + switch (clock_ctl & AR2315_CPUCLK_CLK_SEL_M) { + case 0: + case 1: + clk_div = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_CLKM_DIV); + clk_div = pllc_divide_table[clk_div]; + break; + case 2: + clk_div = ATH25_REG_MS(pllc_ctrl, AR2315_PLLC_CLKC_DIV); + clk_div = pllc_divide_table[clk_div]; + break; + default: + pllc_out = 40000000; + clk_div = 1; + break; + } + + cpu_div = ATH25_REG_MS(clock_ctl, AR2315_CPUCLK_CLK_DIV); + cpu_div = cpu_div * 2 ?: 1; + + return pllc_out / (clk_div * cpu_div); +} + +static inline unsigned ar2315_cpu_frequency(void) +{ + return ar2315_sys_clk(ar2315_rst_reg_read(AR2315_CPUCLK)); +} + +static inline unsigned ar2315_apb_frequency(void) +{ + return ar2315_sys_clk(ar2315_rst_reg_read(AR2315_AMBACLK)); +} + +void __init ar2315_plat_time_init(void) +{ + mips_hpt_frequency = ar2315_cpu_frequency() / 2; +} + +void __init ar2315_plat_mem_setup(void) +{ + void __iomem *sdram_base; + u32 memsize, memcfg; + u32 devid; + u32 config; + + /* Detect memory size */ + sdram_base = ioremap_nocache(AR2315_SDRAMCTL_BASE, + AR2315_SDRAMCTL_SIZE); + memcfg = __raw_readl(sdram_base + AR2315_MEM_CFG); + memsize = 1 + ATH25_REG_MS(memcfg, AR2315_MEM_CFG_DATA_WIDTH); + memsize <<= 1 + ATH25_REG_MS(memcfg, AR2315_MEM_CFG_COL_WIDTH); + memsize <<= 1 + ATH25_REG_MS(memcfg, AR2315_MEM_CFG_ROW_WIDTH); + memsize <<= 3; + add_memory_region(0, memsize, BOOT_MEM_RAM); + iounmap(sdram_base); + + ar2315_rst_base = ioremap_nocache(AR2315_RST_BASE, AR2315_RST_SIZE); + + /* Detect the hardware based on the device ID */ + devid = ar2315_rst_reg_read(AR2315_SREV) & AR2315_REV_CHIP; + switch (devid) { + case 0x91: /* Need to check */ + ath25_soc = ATH25_SOC_AR2318; + break; + case 0x90: + ath25_soc = ATH25_SOC_AR2317; + break; + case 0x87: + ath25_soc = ATH25_SOC_AR2316; + break; + case 0x86: + default: + ath25_soc = ATH25_SOC_AR2315; + break; + } + ath25_board.devid = devid; + + /* Clear any lingering AHB errors */ + config = read_c0_config(); + write_c0_config(config & ~0x3); + ar2315_rst_reg_write(AR2315_AHB_ERR0, AR2315_AHB_ERROR_DET); + ar2315_rst_reg_read(AR2315_AHB_ERR1); + ar2315_rst_reg_write(AR2315_WDT_CTRL, AR2315_WDT_CTRL_IGNORE); + + _machine_restart = ar2315_restart; +} + +#ifdef CONFIG_PCI_AR2315 +static struct resource ar2315_pci_res[] = { + { + .name = "ar2315-pci-ctrl", + .flags = IORESOURCE_MEM, + .start = AR2315_PCI_BASE, + .end = AR2315_PCI_BASE + AR2315_PCI_SIZE - 1, + }, + { + .name = "ar2315-pci-ext", + .flags = IORESOURCE_MEM, + .start = AR2315_PCI_EXT_BASE, + .end = AR2315_PCI_EXT_BASE + AR2315_PCI_EXT_SIZE - 1, + }, + { + .name = "ar2315-pci", + .flags = IORESOURCE_IRQ, + .start = AR2315_IRQ_LCBUS_PCI, + .end = AR2315_IRQ_LCBUS_PCI, + }, +}; +#endif + +void __init ar2315_arch_init(void) +{ + unsigned irq = irq_create_mapping(ar2315_misc_irq_domain, + AR2315_MISC_IRQ_UART0); + + ath25_serial_setup(AR2315_UART0_BASE, irq, ar2315_apb_frequency()); + +#ifdef CONFIG_PCI_AR2315 + if (ath25_soc == ATH25_SOC_AR2315) { + /* Reset PCI DMA logic */ + ar2315_rst_reg_mask(AR2315_RESET, 0, AR2315_RESET_PCIDMA); + msleep(20); + ar2315_rst_reg_mask(AR2315_RESET, AR2315_RESET_PCIDMA, 0); + msleep(20); + + /* Configure endians */ + ar2315_rst_reg_mask(AR2315_ENDIAN_CTL, 0, AR2315_CONFIG_PCIAHB | + AR2315_CONFIG_PCIAHB_BRIDGE); + + /* Configure as PCI host with DMA */ + ar2315_rst_reg_write(AR2315_PCICLK, AR2315_PCICLK_PLLC_CLKM | + (AR2315_PCICLK_IN_FREQ_DIV_6 << + AR2315_PCICLK_DIV_S)); + ar2315_rst_reg_mask(AR2315_AHB_ARB_CTL, 0, AR2315_ARB_PCI); + ar2315_rst_reg_mask(AR2315_IF_CTL, AR2315_IF_PCI_CLK_MASK | + AR2315_IF_MASK, AR2315_IF_PCI | + AR2315_IF_PCI_HOST | AR2315_IF_PCI_INTR | + (AR2315_IF_PCI_CLK_OUTPUT_CLK << + AR2315_IF_PCI_CLK_SHIFT)); + + platform_device_register_simple("ar2315-pci", -1, + ar2315_pci_res, + ARRAY_SIZE(ar2315_pci_res)); + } +#endif +} diff --git a/arch/mips/ath25/ar2315.h b/arch/mips/ath25/ar2315.h new file mode 100644 index 0000000..877afe6 --- /dev/null +++ b/arch/mips/ath25/ar2315.h @@ -0,0 +1,22 @@ +#ifndef __AR2315_H +#define __AR2315_H + +#ifdef CONFIG_SOC_AR2315 + +void ar2315_arch_init_irq(void); +void ar2315_init_devices(void); +void ar2315_plat_time_init(void); +void ar2315_plat_mem_setup(void); +void ar2315_arch_init(void); + +#else + +static inline void ar2315_arch_init_irq(void) {} +static inline void ar2315_init_devices(void) {} +static inline void ar2315_plat_time_init(void) {} +static inline void ar2315_plat_mem_setup(void) {} +static inline void ar2315_arch_init(void) {} + +#endif + +#endif /* __AR2315_H */ diff --git a/arch/mips/ath25/ar2315_regs.h b/arch/mips/ath25/ar2315_regs.h new file mode 100644 index 0000000..16e8614 --- /dev/null +++ b/arch/mips/ath25/ar2315_regs.h @@ -0,0 +1,410 @@ +/* + * Register definitions for AR2315+ + * + * 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) 2003 Atheros Communications, Inc., All Rights Reserved. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2006-2008 Felix Fietkau <nbd@openwrt.org> + */ + +#ifndef __ASM_MACH_ATH25_AR2315_REGS_H +#define __ASM_MACH_ATH25_AR2315_REGS_H + +/* + * IRQs + */ +#define AR2315_IRQ_MISC (MIPS_CPU_IRQ_BASE + 2) /* C0_CAUSE: 0x0400 */ +#define AR2315_IRQ_WLAN0 (MIPS_CPU_IRQ_BASE + 3) /* C0_CAUSE: 0x0800 */ +#define AR2315_IRQ_ENET0 (MIPS_CPU_IRQ_BASE + 4) /* C0_CAUSE: 0x1000 */ +#define AR2315_IRQ_LCBUS_PCI (MIPS_CPU_IRQ_BASE + 5) /* C0_CAUSE: 0x2000 */ +#define AR2315_IRQ_WLAN0_POLL (MIPS_CPU_IRQ_BASE + 6) /* C0_CAUSE: 0x4000 */ + +/* + * Miscellaneous interrupts, which share IP2. + */ +#define AR2315_MISC_IRQ_UART0 0 +#define AR2315_MISC_IRQ_I2C_RSVD 1 +#define AR2315_MISC_IRQ_SPI 2 +#define AR2315_MISC_IRQ_AHB 3 +#define AR2315_MISC_IRQ_APB 4 +#define AR2315_MISC_IRQ_TIMER 5 +#define AR2315_MISC_IRQ_GPIO 6 +#define AR2315_MISC_IRQ_WATCHDOG 7 +#define AR2315_MISC_IRQ_IR_RSVD 8 +#define AR2315_MISC_IRQ_COUNT 9 + +/* + * Address map + */ +#define AR2315_SPI_READ_BASE 0x08000000 /* SPI flash */ +#define AR2315_SPI_READ_SIZE 0x01000000 +#define AR2315_WLAN0_BASE 0x10000000 /* Wireless MMR */ +#define AR2315_PCI_BASE 0x10100000 /* PCI MMR */ +#define AR2315_PCI_SIZE 0x00001000 +#define AR2315_SDRAMCTL_BASE 0x10300000 /* SDRAM MMR */ +#define AR2315_SDRAMCTL_SIZE 0x00000020 +#define AR2315_LOCAL_BASE 0x10400000 /* Local bus MMR */ +#define AR2315_ENET0_BASE 0x10500000 /* Ethernet MMR */ +#define AR2315_RST_BASE 0x11000000 /* Reset control MMR */ +#define AR2315_RST_SIZE 0x00000100 +#define AR2315_UART0_BASE 0x11100000 /* UART MMR */ +#define AR2315_SPI_MMR_BASE 0x11300000 /* SPI flash MMR */ +#define AR2315_SPI_MMR_SIZE 0x00000010 +#define AR2315_PCI_EXT_BASE 0x80000000 /* PCI external */ +#define AR2315_PCI_EXT_SIZE 0x40000000 + +/* + * Configuration registers + */ + +/* Cold reset register */ +#define AR2315_COLD_RESET 0x0000 + +#define AR2315_RESET_COLD_AHB 0x00000001 +#define AR2315_RESET_COLD_APB 0x00000002 +#define AR2315_RESET_COLD_CPU 0x00000004 +#define AR2315_RESET_COLD_CPUWARM 0x00000008 +#define AR2315_RESET_SYSTEM (RESET_COLD_CPU |\ + RESET_COLD_APB |\ + RESET_COLD_AHB) /* full system */ +#define AR2317_RESET_SYSTEM 0x00000010 + +/* Reset register */ +#define AR2315_RESET 0x0004 + +#define AR2315_RESET_WARM_WLAN0_MAC 0x00000001 /* warm reset WLAN0 MAC */ +#define AR2315_RESET_WARM_WLAN0_BB 0x00000002 /* warm reset WLAN0 BB */ +#define AR2315_RESET_MPEGTS_RSVD 0x00000004 /* warm reset MPEG-TS */ +#define AR2315_RESET_PCIDMA 0x00000008 /* warm reset PCI ahb/dma */ +#define AR2315_RESET_MEMCTL 0x00000010 /* warm reset mem control */ +#define AR2315_RESET_LOCAL 0x00000020 /* warm reset local bus */ +#define AR2315_RESET_I2C_RSVD 0x00000040 /* warm reset I2C bus */ +#define AR2315_RESET_SPI 0x00000080 /* warm reset SPI iface */ +#define AR2315_RESET_UART0 0x00000100 /* warm reset UART0 */ +#define AR2315_RESET_IR_RSVD 0x00000200 /* warm reset IR iface */ +#define AR2315_RESET_EPHY0 0x00000400 /* cold reset ENET0 phy */ +#define AR2315_RESET_ENET0 0x00000800 /* cold reset ENET0 MAC */ + +/* AHB master arbitration control */ +#define AR2315_AHB_ARB_CTL 0x0008 + +#define AR2315_ARB_CPU 0x00000001 /* CPU, default */ +#define AR2315_ARB_WLAN 0x00000002 /* WLAN */ +#define AR2315_ARB_MPEGTS_RSVD 0x00000004 /* MPEG-TS */ +#define AR2315_ARB_LOCAL 0x00000008 /* Local bus */ +#define AR2315_ARB_PCI 0x00000010 /* PCI bus */ +#define AR2315_ARB_ETHERNET 0x00000020 /* Ethernet */ +#define AR2315_ARB_RETRY 0x00000100 /* Retry policy (debug) */ + +/* Config Register */ +#define AR2315_ENDIAN_CTL 0x000c + +#define AR2315_CONFIG_AHB 0x00000001 /* EC-AHB bridge endian */ +#define AR2315_CONFIG_WLAN 0x00000002 /* WLAN byteswap */ +#define AR2315_CONFIG_MPEGTS_RSVD 0x00000004 /* MPEG-TS byteswap */ +#define AR2315_CONFIG_PCI 0x00000008 /* PCI byteswap */ +#define AR2315_CONFIG_MEMCTL 0x00000010 /* Mem controller endian */ +#define AR2315_CONFIG_LOCAL 0x00000020 /* Local bus byteswap */ +#define AR2315_CONFIG_ETHERNET 0x00000040 /* Ethernet byteswap */ +#define AR2315_CONFIG_MERGE 0x00000200 /* CPU write buffer merge */ +#define AR2315_CONFIG_CPU 0x00000400 /* CPU big endian */ +#define AR2315_CONFIG_BIG 0x00000400 +#define AR2315_CONFIG_PCIAHB 0x00000800 +#define AR2315_CONFIG_PCIAHB_BRIDGE 0x00001000 +#define AR2315_CONFIG_SPI 0x00008000 /* SPI byteswap */ +#define AR2315_CONFIG_CPU_DRAM 0x00010000 +#define AR2315_CONFIG_CPU_PCI 0x00020000 +#define AR2315_CONFIG_CPU_MMR 0x00040000 + +/* NMI control */ +#define AR2315_NMI_CTL 0x0010 + +#define AR2315_NMI_EN 1 + +/* Revision Register - Initial value is 0x3010 (WMAC 3.0, AR231X 1.0). */ +#define AR2315_SREV 0x0014 + +#define AR2315_REV_MAJ 0x000000f0 +#define AR2315_REV_MAJ_S 4 +#define AR2315_REV_MIN 0x0000000f +#define AR2315_REV_MIN_S 0 +#define AR2315_REV_CHIP (AR2315_REV_MAJ | AR2315_REV_MIN) + +/* Interface Enable */ +#define AR2315_IF_CTL 0x0018 + +#define AR2315_IF_MASK 0x00000007 +#define AR2315_IF_DISABLED 0 /* Disable all */ +#define AR2315_IF_PCI 1 /* PCI */ +#define AR2315_IF_TS_LOCAL 2 /* Local bus */ +#define AR2315_IF_ALL 3 /* Emulation only */ +#define AR2315_IF_LOCAL_HOST 0x00000008 +#define AR2315_IF_PCI_HOST 0x00000010 +#define AR2315_IF_PCI_INTR 0x00000020 +#define AR2315_IF_PCI_CLK_MASK 0x00030000 +#define AR2315_IF_PCI_CLK_INPUT 0 +#define AR2315_IF_PCI_CLK_OUTPUT_LOW 1 +#define AR2315_IF_PCI_CLK_OUTPUT_CLK 2 +#define AR2315_IF_PCI_CLK_OUTPUT_HIGH 3 +#define AR2315_IF_PCI_CLK_SHIFT 16 + +/* APB Interrupt control */ +#define AR2315_ISR 0x0020 +#define AR2315_IMR 0x0024 +#define AR2315_GISR 0x0028 + +#define AR2315_ISR_UART0 0x00000001 /* high speed UART */ +#define AR2315_ISR_I2C_RSVD 0x00000002 /* I2C bus */ +#define AR2315_ISR_SPI 0x00000004 /* SPI bus */ +#define AR2315_ISR_AHB 0x00000008 /* AHB error */ +#define AR2315_ISR_APB 0x00000010 /* APB error */ +#define AR2315_ISR_TIMER 0x00000020 /* Timer */ +#define AR2315_ISR_GPIO 0x00000040 /* GPIO */ +#define AR2315_ISR_WD 0x00000080 /* Watchdog */ +#define AR2315_ISR_IR_RSVD 0x00000100 /* IR */ + +#define AR2315_GISR_MISC 0x00000001 /* Misc */ +#define AR2315_GISR_WLAN0 0x00000002 /* WLAN0 */ +#define AR2315_GISR_MPEGTS_RSVD 0x00000004 /* MPEG-TS */ +#define AR2315_GISR_LOCALPCI 0x00000008 /* Local/PCI bus */ +#define AR2315_GISR_WMACPOLL 0x00000010 +#define AR2315_GISR_TIMER 0x00000020 +#define AR2315_GISR_ETHERNET 0x00000040 /* Ethernet */ + +/* Generic timer */ +#define AR2315_TIMER 0x0030 +#define AR2315_RELOAD 0x0034 + +/* Watchdog timer */ +#define AR2315_WDT_TIMER 0x0038 +#define AR2315_WDT_CTRL 0x003c + +#define AR2315_WDT_CTRL_IGNORE 0x00000000 /* ignore expiration */ +#define AR2315_WDT_CTRL_NMI 0x00000001 /* NMI on watchdog */ +#define AR2315_WDT_CTRL_RESET 0x00000002 /* reset on watchdog */ + +/* CPU Performance Counters */ +#define AR2315_PERFCNT0 0x0048 +#define AR2315_PERFCNT1 0x004c + +#define AR2315_PERF0_DATAHIT 0x00000001 /* Count Data Cache Hits */ +#define AR2315_PERF0_DATAMISS 0x00000002 /* Count Data Cache Misses */ +#define AR2315_PERF0_INSTHIT 0x00000004 /* Count Instruction Cache Hits */ +#define AR2315_PERF0_INSTMISS 0x00000008 /* Count Instruction Cache Misses */ +#define AR2315_PERF0_ACTIVE 0x00000010 /* Count Active Processor Cycles */ +#define AR2315_PERF0_WBHIT 0x00000020 /* Count CPU Write Buffer Hits */ +#define AR2315_PERF0_WBMISS 0x00000040 /* Count CPU Write Buffer Misses */ + +#define AR2315_PERF1_EB_ARDY 0x00000001 /* Count EB_ARdy signal */ +#define AR2315_PERF1_EB_AVALID 0x00000002 /* Count EB_AValid signal */ +#define AR2315_PERF1_EB_WDRDY 0x00000004 /* Count EB_WDRdy signal */ +#define AR2315_PERF1_EB_RDVAL 0x00000008 /* Count EB_RdVal signal */ +#define AR2315_PERF1_VRADDR 0x00000010 /* Count valid read address cycles*/ +#define AR2315_PERF1_VWADDR 0x00000020 /* Count valid write address cycl.*/ +#define AR2315_PERF1_VWDATA 0x00000040 /* Count valid write data cycles */ + +/* AHB Error Reporting */ +#define AR2315_AHB_ERR0 0x0050 /* error */ +#define AR2315_AHB_ERR1 0x0054 /* haddr */ +#define AR2315_AHB_ERR2 0x0058 /* hwdata */ +#define AR2315_AHB_ERR3 0x005c /* hrdata */ +#define AR2315_AHB_ERR4 0x0060 /* status */ + +#define AR2315_AHB_ERROR_DET 1 /* AHB Error has been detected, */ + /* write 1 to clear all bits in ERR0 */ +#define AR2315_AHB_ERROR_OVR 2 /* AHB Error overflow has been detected */ +#define AR2315_AHB_ERROR_WDT 4 /* AHB Error due to wdt instead of hresp */ + +#define AR2315_PROCERR_HMAST 0x0000000f +#define AR2315_PROCERR_HMAST_DFLT 0 +#define AR2315_PROCERR_HMAST_WMAC 1 +#define AR2315_PROCERR_HMAST_ENET 2 +#define AR2315_PROCERR_HMAST_PCIENDPT 3 +#define AR2315_PROCERR_HMAST_LOCAL 4 +#define AR2315_PROCERR_HMAST_CPU 5 +#define AR2315_PROCERR_HMAST_PCITGT 6 +#define AR2315_PROCERR_HMAST_S 0 +#define AR2315_PROCERR_HWRITE 0x00000010 +#define AR2315_PROCERR_HSIZE 0x00000060 +#define AR2315_PROCERR_HSIZE_S 5 +#define AR2315_PROCERR_HTRANS 0x00000180 +#define AR2315_PROCERR_HTRANS_S 7 +#define AR2315_PROCERR_HBURST 0x00000e00 +#define AR2315_PROCERR_HBURST_S 9 + +/* Clock Control */ +#define AR2315_PLLC_CTL 0x0064 +#define AR2315_PLLV_CTL 0x0068 +#define AR2315_CPUCLK 0x006c +#define AR2315_AMBACLK 0x0070 +#define AR2315_SYNCCLK 0x0074 +#define AR2315_DSL_SLEEP_CTL 0x0080 +#define AR2315_DSL_SLEEP_DUR 0x0084 + +/* PLLc Control fields */ +#define AR2315_PLLC_REF_DIV_M 0x00000003 +#define AR2315_PLLC_REF_DIV_S 0 +#define AR2315_PLLC_FDBACK_DIV_M 0x0000007c +#define AR2315_PLLC_FDBACK_DIV_S 2 +#define AR2315_PLLC_ADD_FDBACK_DIV_M 0x00000080 +#define AR2315_PLLC_ADD_FDBACK_DIV_S 7 +#define AR2315_PLLC_CLKC_DIV_M 0x0001c000 +#define AR2315_PLLC_CLKC_DIV_S 14 +#define AR2315_PLLC_CLKM_DIV_M 0x00700000 +#define AR2315_PLLC_CLKM_DIV_S 20 + +/* CPU CLK Control fields */ +#define AR2315_CPUCLK_CLK_SEL_M 0x00000003 +#define AR2315_CPUCLK_CLK_SEL_S 0 +#define AR2315_CPUCLK_CLK_DIV_M 0x0000000c +#define AR2315_CPUCLK_CLK_DIV_S 2 + +/* AMBA CLK Control fields */ +#define AR2315_AMBACLK_CLK_SEL_M 0x00000003 +#define AR2315_AMBACLK_CLK_SEL_S 0 +#define AR2315_AMBACLK_CLK_DIV_M 0x0000000c +#define AR2315_AMBACLK_CLK_DIV_S 2 + +/* PCI Clock Control */ +#define AR2315_PCICLK 0x00a4 + +#define AR2315_PCICLK_INPUT_M 0x00000003 +#define AR2315_PCICLK_INPUT_S 0 +#define AR2315_PCICLK_PLLC_CLKM 0 +#define AR2315_PCICLK_PLLC_CLKM1 1 +#define AR2315_PCICLK_PLLC_CLKC 2 +#define AR2315_PCICLK_REF_CLK 3 +#define AR2315_PCICLK_DIV_M 0x0000000c +#define AR2315_PCICLK_DIV_S 2 +#define AR2315_PCICLK_IN_FREQ 0 +#define AR2315_PCICLK_IN_FREQ_DIV_6 1 +#define AR2315_PCICLK_IN_FREQ_DIV_8 2 +#define AR2315_PCICLK_IN_FREQ_DIV_10 3 + +/* Observation Control Register */ +#define AR2315_OCR 0x00b0 + +#define AR2315_OCR_GPIO0_IRIN 0x00000040 +#define AR2315_OCR_GPIO1_IROUT 0x00000080 +#define AR2315_OCR_GPIO3_RXCLR 0x00000200 + +/* General Clock Control */ +#define AR2315_MISCCLK 0x00b4 + +#define AR2315_MISCCLK_PLLBYPASS_EN 0x00000001 +#define AR2315_MISCCLK_PROCREFCLK 0x00000002 + +/* + * SDRAM Controller + * - No read or write buffers are included. + */ +#define AR2315_MEM_CFG 0x0000 +#define AR2315_MEM_CTRL 0x000c +#define AR2315_MEM_REF 0x0010 + +#define AR2315_MEM_CFG_DATA_WIDTH_M 0x00006000 +#define AR2315_MEM_CFG_DATA_WIDTH_S 13 +#define AR2315_MEM_CFG_COL_WIDTH_M 0x00001e00 +#define AR2315_MEM_CFG_COL_WIDTH_S 9 +#define AR2315_MEM_CFG_ROW_WIDTH_M 0x000001e0 +#define AR2315_MEM_CFG_ROW_WIDTH_S 5 +#define AR2315_MEM_CFG_BANKADDR_BITS_M 0x00000018 +#define AR2315_MEM_CFG_BANKADDR_BITS_S 3 + +/* + * Local Bus Interface Registers + */ +#define AR2315_LB_CONFIG 0x0000 + +#define AR2315_LBCONF_OE 0x00000001 /* =1 OE is low-true */ +#define AR2315_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */ +#define AR2315_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */ +#define AR2315_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */ +#define AR2315_LBCONF_WE 0x00000010 /* =1 Write En is low-true */ +#define AR2315_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */ +#define AR2315_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */ +#define AR2315_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */ +#define AR2315_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */ +#define AR2315_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */ +#define AR2315_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */ +#define AR2315_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */ +#define AR2315_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */ +#define AR2315_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */ +#define AR2315_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */ +#define AR2315_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */ +#define AR2315_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */ +#define AR2315_LBCONF_INT 0x00020000 /* =1 Intr is low true */ +#define AR2315_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */ +#define AR2315_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */ +#define AR2315_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */ +#define AR2315_LBCONF_INT_CTR3 0x000c0000 /* GND drive, Vdd drive */ +#define AR2315_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */ +#define AR2315_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */ +#define AR2315_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */ + +#define AR2315_LB_CLKSEL 0x0004 + +#define AR2315_LBCLK_EXT 0x00000001 /* use external clk for lb */ + +#define AR2315_LB_1MS 0x0008 + +#define AR2315_LB1MS_MASK 0x0003ffff /* # of AHB clk cycles in 1ms */ + +#define AR2315_LB_MISCCFG 0x000c + +#define AR2315_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */ +#define AR2315_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */ +#define AR2315_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */ +#define AR2315_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */ +#define AR2315_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */ +#define AR2315_LBM_TIMEOUT_M 0x00ffff80 +#define AR2315_LBM_TIMEOUT_S 7 +#define AR2315_LBM_PORTMUX 0x07000000 + +#define AR2315_LB_RXTSOFF 0x0010 + +#define AR2315_LB_TX_CHAIN_EN 0x0100 + +#define AR2315_LB_TXEN_0 0x00000001 +#define AR2315_LB_TXEN_1 0x00000002 +#define AR2315_LB_TXEN_2 0x00000004 +#define AR2315_LB_TXEN_3 0x00000008 + +#define AR2315_LB_TX_CHAIN_DIS 0x0104 +#define AR2315_LB_TX_DESC_PTR 0x0200 + +#define AR2315_LB_RX_CHAIN_EN 0x0400 + +#define AR2315_LB_RXEN 0x00000001 + +#define AR2315_LB_RX_CHAIN_DIS 0x0404 +#define AR2315_LB_RX_DESC_PTR 0x0408 + +#define AR2315_LB_INT_STATUS 0x0500 + +#define AR2315_LB_INT_TX_DESC 0x00000001 +#define AR2315_LB_INT_TX_OK 0x00000002 +#define AR2315_LB_INT_TX_ERR 0x00000004 +#define AR2315_LB_INT_TX_EOF 0x00000008 +#define AR2315_LB_INT_RX_DESC 0x00000010 +#define AR2315_LB_INT_RX_OK 0x00000020 +#define AR2315_LB_INT_RX_ERR 0x00000040 +#define AR2315_LB_INT_RX_EOF 0x00000080 +#define AR2315_LB_INT_TX_TRUNC 0x00000100 +#define AR2315_LB_INT_TX_STARVE 0x00000200 +#define AR2315_LB_INT_LB_TIMEOUT 0x00000400 +#define AR2315_LB_INT_LB_ERR 0x00000800 +#define AR2315_LB_INT_MBOX_WR 0x00001000 +#define AR2315_LB_INT_MBOX_RD 0x00002000 + +/* Bit definitions for INT MASK are the same as INT_STATUS */ +#define AR2315_LB_INT_MASK 0x0504 + +#define AR2315_LB_INT_EN 0x0508 +#define AR2315_LB_MBOX 0x0600 + +#endif /* __ASM_MACH_ATH25_AR2315_REGS_H */ diff --git a/arch/mips/ath25/ar5312.c b/arch/mips/ath25/ar5312.c new file mode 100644 index 0000000..b6887f7 --- /dev/null +++ b/arch/mips/ath25/ar5312.c @@ -0,0 +1,393 @@ +/* + * 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) 2003 Atheros Communications, Inc., All Rights Reserved. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com> + */ + +/* + * Platform devices for Atheros AR5312 SoCs + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/irqdomain.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/reboot.h> +#include <asm/bootinfo.h> +#include <asm/reboot.h> +#include <asm/time.h> + +#include <ath25_platform.h> + +#include "devices.h" +#include "ar5312.h" +#include "ar5312_regs.h" + +static void __iomem *ar5312_rst_base; +static struct irq_domain *ar5312_misc_irq_domain; + +static inline u32 ar5312_rst_reg_read(u32 reg) +{ + return __raw_readl(ar5312_rst_base + reg); +} + +static inline void ar5312_rst_reg_write(u32 reg, u32 val) +{ + __raw_writel(val, ar5312_rst_base + reg); +} + +static inline void ar5312_rst_reg_mask(u32 reg, u32 mask, u32 val) +{ + u32 ret = ar5312_rst_reg_read(reg); + + ret &= ~mask; + ret |= val; + ar5312_rst_reg_write(reg, ret); +} + +static irqreturn_t ar5312_ahb_err_handler(int cpl, void *dev_id) +{ + u32 proc1 = ar5312_rst_reg_read(AR5312_PROC1); + u32 proc_addr = ar5312_rst_reg_read(AR5312_PROCADDR); /* clears error */ + u32 dma1 = ar5312_rst_reg_read(AR5312_DMA1); + u32 dma_addr = ar5312_rst_reg_read(AR5312_DMAADDR); /* clears error */ + + pr_emerg("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n", + proc_addr, proc1, dma_addr, dma1); + + machine_restart("AHB error"); /* Catastrophic failure */ + return IRQ_HANDLED; +} + +static struct irqaction ar5312_ahb_err_interrupt = { + .handler = ar5312_ahb_err_handler, + .name = "ar5312-ahb-error", +}; + +static void ar5312_misc_irq_handler(unsigned irq, struct irq_desc *desc) +{ + u32 pending = ar5312_rst_reg_read(AR5312_ISR) & + ar5312_rst_reg_read(AR5312_IMR); + unsigned nr, misc_irq = 0; + + if (pending) { + struct irq_domain *domain = irq_get_handler_data(irq); + + nr = __ffs(pending); + misc_irq = irq_find_mapping(domain, nr); + } + + if (misc_irq) { + generic_handle_irq(misc_irq); + if (nr == AR5312_MISC_IRQ_TIMER) + ar5312_rst_reg_read(AR5312_TIMER); + } else { + spurious_interrupt(); + } +} + +/* Enable the specified AR5312_MISC_IRQ interrupt */ +static void ar5312_misc_irq_unmask(struct irq_data *d) +{ + ar5312_rst_reg_mask(AR5312_IMR, 0, BIT(d->hwirq)); +} + +/* Disable the specified AR5312_MISC_IRQ interrupt */ +static void ar5312_misc_irq_mask(struct irq_data *d) +{ + ar5312_rst_reg_mask(AR5312_IMR, BIT(d->hwirq), 0); + ar5312_rst_reg_read(AR5312_IMR); /* flush write buffer */ +} + +static struct irq_chip ar5312_misc_irq_chip = { + .name = "ar5312-misc", + .irq_unmask = ar5312_misc_irq_unmask, + .irq_mask = ar5312_misc_irq_mask, +}; + +static int ar5312_misc_irq_map(struct irq_domain *d, unsigned irq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &ar5312_misc_irq_chip, handle_level_irq); + return 0; +} + +static struct irq_domain_ops ar5312_misc_irq_domain_ops = { + .map = ar5312_misc_irq_map, +}; + +static void ar5312_irq_dispatch(void) +{ + u32 pending = read_c0_status() & read_c0_cause(); + + if (pending & CAUSEF_IP2) + do_IRQ(AR5312_IRQ_WLAN0); + else if (pending & CAUSEF_IP5) + do_IRQ(AR5312_IRQ_WLAN1); + else if (pending & CAUSEF_IP6) + do_IRQ(AR5312_IRQ_MISC); + else if (pending & CAUSEF_IP7) + do_IRQ(ATH25_IRQ_CPU_CLOCK); + else + spurious_interrupt(); +} + +void __init ar5312_arch_init_irq(void) +{ + struct irq_domain *domain; + unsigned irq; + + ath25_irq_dispatch = ar5312_irq_dispatch; + + domain = irq_domain_add_linear(NULL, AR5312_MISC_IRQ_COUNT, + &ar5312_misc_irq_domain_ops, NULL); + if (!domain) + panic("Failed to add IRQ domain"); + + irq = irq_create_mapping(domain, AR5312_MISC_IRQ_AHB_PROC); + setup_irq(irq, &ar5312_ahb_err_interrupt); + + irq_set_chained_handler(AR5312_IRQ_MISC, ar5312_misc_irq_handler); + irq_set_handler_data(AR5312_IRQ_MISC, domain); + + ar5312_misc_irq_domain = domain; +} + +static struct physmap_flash_data ar5312_flash_data = { + .width = 2, +}; + +static struct resource ar5312_flash_resource = { + .start = AR5312_FLASH_BASE, + .end = AR5312_FLASH_BASE + AR5312_FLASH_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ar5312_physmap_flash = { + .name = "physmap-flash", + .id = 0, + .dev.platform_data = &ar5312_flash_data, + .resource = &ar5312_flash_resource, + .num_resources = 1, +}; + +static void __init ar5312_flash_init(void) +{ + void __iomem *flashctl_base; + u32 ctl; + + flashctl_base = ioremap_nocache(AR5312_FLASHCTL_BASE, + AR5312_FLASHCTL_SIZE); + + ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL0); + ctl &= AR5312_FLASHCTL_MW; + + /* fixup flash width */ + switch (ctl) { + case AR5312_FLASHCTL_MW16: + ar5312_flash_data.width = 2; + break; + case AR5312_FLASHCTL_MW8: + default: + ar5312_flash_data.width = 1; + break; + } + + /* + * Configure flash bank 0. + * Assume 8M window size. Flash will be aliased if it's smaller + */ + ctl |= AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC_8M | AR5312_FLASHCTL_RBLE; + ctl |= 0x01 << AR5312_FLASHCTL_IDCY_S; + ctl |= 0x07 << AR5312_FLASHCTL_WST1_S; + ctl |= 0x07 << AR5312_FLASHCTL_WST2_S; + __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL0); + + /* Disable other flash banks */ + ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL1); + ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC); + __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL1); + ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL2); + ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC); + __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL2); + + iounmap(flashctl_base); +} + +void __init ar5312_init_devices(void) +{ + struct ath25_boarddata *config; + + ar5312_flash_init(); + + /* Locate board/radio config data */ + ath25_find_config(AR5312_FLASH_BASE, AR5312_FLASH_SIZE); + config = ath25_board.config; + + /* AR2313 has CPU minor rev. 10 */ + if ((current_cpu_data.processor_id & 0xff) == 0x0a) + ath25_soc = ATH25_SOC_AR2313; + + /* AR2312 shares the same Silicon ID as AR5312 */ + else if (config->flags & BD_ISCASPER) + ath25_soc = ATH25_SOC_AR2312; + + /* Everything else is probably AR5312 or compatible */ + else + ath25_soc = ATH25_SOC_AR5312; + + platform_device_register(&ar5312_physmap_flash); + + switch (ath25_soc) { + case ATH25_SOC_AR5312: + if (!ath25_board.radio) + return; + + if (!(config->flags & BD_WLAN0)) + break; + + ath25_add_wmac(0, AR5312_WLAN0_BASE, AR5312_IRQ_WLAN0); + break; + case ATH25_SOC_AR2312: + case ATH25_SOC_AR2313: + if (!ath25_board.radio) + return; + break; + default: + break; + } + + if (config->flags & BD_WLAN1) + ath25_add_wmac(1, AR5312_WLAN1_BASE, AR5312_IRQ_WLAN1); +} + +static void ar5312_restart(char *command) +{ + /* reset the system */ + local_irq_disable(); + while (1) + ar5312_rst_reg_write(AR5312_RESET, AR5312_RESET_SYSTEM); +} + +/* + * This table is indexed by bits 5..4 of the CLOCKCTL1 register + * to determine the predevisor value. + */ +static unsigned clockctl1_predivide_table[4] __initdata = { 1, 2, 4, 5 }; + +static unsigned __init ar5312_cpu_frequency(void) +{ + u32 scratch, devid, clock_ctl1; + u32 predivide_mask, multiplier_mask, doubler_mask; + unsigned predivide_shift, multiplier_shift; + unsigned predivide_select, predivisor, multiplier; + + /* Trust the bootrom's idea of cpu frequency. */ + scratch = ar5312_rst_reg_read(AR5312_SCRATCH); + if (scratch) + return scratch; + + devid = ar5312_rst_reg_read(AR5312_REV); + devid = (devid & AR5312_REV_MAJ) >> AR5312_REV_MAJ_S; + if (devid == AR5312_REV_MAJ_AR2313) { + predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK; + predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT; + multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK; + multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT; + doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK; + } else { /* AR5312 and AR2312 */ + predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK; + predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT; + multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK; + multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT; + doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK; + } + + /* + * Clocking is derived from a fixed 40MHz input clock. + * + * cpu_freq = input_clock * MULT (where MULT is PLL multiplier) + * sys_freq = cpu_freq / 4 (used for APB clock, serial, + * flash, Timer, Watchdog Timer) + * + * cnt_freq = cpu_freq / 2 (use for CPU count/compare) + * + * So, for example, with a PLL multiplier of 5, we have + * + * cpu_freq = 200MHz + * sys_freq = 50MHz + * cnt_freq = 100MHz + * + * We compute the CPU frequency, based on PLL settings. + */ + + clock_ctl1 = ar5312_rst_reg_read(AR5312_CLOCKCTL1); + predivide_select = (clock_ctl1 & predivide_mask) >> predivide_shift; + predivisor = clockctl1_predivide_table[predivide_select]; + multiplier = (clock_ctl1 & multiplier_mask) >> multiplier_shift; + + if (clock_ctl1 & doubler_mask) + multiplier <<= 1; + + return (40000000 / predivisor) * multiplier; +} + +static inline unsigned ar5312_sys_frequency(void) +{ + return ar5312_cpu_frequency() / 4; +} + +void __init ar5312_plat_time_init(void) +{ + mips_hpt_frequency = ar5312_cpu_frequency() / 2; +} + +void __init ar5312_plat_mem_setup(void) +{ + void __iomem *sdram_base; + u32 memsize, memcfg, bank0_ac, bank1_ac; + u32 devid; + + /* Detect memory size */ + sdram_base = ioremap_nocache(AR5312_SDRAMCTL_BASE, + AR5312_SDRAMCTL_SIZE); + memcfg = __raw_readl(sdram_base + AR5312_MEM_CFG1); + bank0_ac = ATH25_REG_MS(memcfg, AR5312_MEM_CFG1_AC0); + bank1_ac = ATH25_REG_MS(memcfg, AR5312_MEM_CFG1_AC1); + memsize = (bank0_ac ? (1 << (bank0_ac + 1)) : 0) + + (bank1_ac ? (1 << (bank1_ac + 1)) : 0); + memsize <<= 20; + add_memory_region(0, memsize, BOOT_MEM_RAM); + iounmap(sdram_base); + + ar5312_rst_base = ioremap_nocache(AR5312_RST_BASE, AR5312_RST_SIZE); + + devid = ar5312_rst_reg_read(AR5312_REV); + devid >>= AR5312_REV_WMAC_MIN_S; + devid &= AR5312_REV_CHIP; + ath25_board.devid = (u16)devid; + + /* Clear any lingering AHB errors */ + ar5312_rst_reg_read(AR5312_PROCADDR); + ar5312_rst_reg_read(AR5312_DMAADDR); + ar5312_rst_reg_write(AR5312_WDT_CTRL, AR5312_WDT_CTRL_IGNORE); + + _machine_restart = ar5312_restart; +} + +void __init ar5312_arch_init(void) +{ + unsigned irq = irq_create_mapping(ar5312_misc_irq_domain, + AR5312_MISC_IRQ_UART0); + + ath25_serial_setup(AR5312_UART0_BASE, irq, ar5312_sys_frequency()); +} diff --git a/arch/mips/ath25/ar5312.h b/arch/mips/ath25/ar5312.h new file mode 100644 index 0000000..470abb0 --- /dev/null +++ b/arch/mips/ath25/ar5312.h @@ -0,0 +1,22 @@ +#ifndef __AR5312_H +#define __AR5312_H + +#ifdef CONFIG_SOC_AR5312 + +void ar5312_arch_init_irq(void); +void ar5312_init_devices(void); +void ar5312_plat_time_init(void); +void ar5312_plat_mem_setup(void); +void ar5312_arch_init(void); + +#else + +static inline void ar5312_arch_init_irq(void) {} +static inline void ar5312_init_devices(void) {} +static inline void ar5312_plat_time_init(void) {} +static inline void ar5312_plat_mem_setup(void) {} +static inline void ar5312_arch_init(void) {} + +#endif + +#endif /* __AR5312_H */ diff --git a/arch/mips/ath25/ar5312_regs.h b/arch/mips/ath25/ar5312_regs.h new file mode 100644 index 0000000..4b947f9 --- /dev/null +++ b/arch/mips/ath25/ar5312_regs.h @@ -0,0 +1,224 @@ +/* + * 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) 2003 Atheros Communications, Inc., All Rights Reserved. + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + */ + +#ifndef __ASM_MACH_ATH25_AR5312_REGS_H +#define __ASM_MACH_ATH25_AR5312_REGS_H + +/* + * IRQs + */ +#define AR5312_IRQ_WLAN0 (MIPS_CPU_IRQ_BASE + 2) /* C0_CAUSE: 0x0400 */ +#define AR5312_IRQ_ENET0 (MIPS_CPU_IRQ_BASE + 3) /* C0_CAUSE: 0x0800 */ +#define AR5312_IRQ_ENET1 (MIPS_CPU_IRQ_BASE + 4) /* C0_CAUSE: 0x1000 */ +#define AR5312_IRQ_WLAN1 (MIPS_CPU_IRQ_BASE + 5) /* C0_CAUSE: 0x2000 */ +#define AR5312_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6) /* C0_CAUSE: 0x4000 */ + +/* + * Miscellaneous interrupts, which share IP6. + */ +#define AR5312_MISC_IRQ_TIMER 0 +#define AR5312_MISC_IRQ_AHB_PROC 1 +#define AR5312_MISC_IRQ_AHB_DMA 2 +#define AR5312_MISC_IRQ_GPIO 3 +#define AR5312_MISC_IRQ_UART0 4 +#define AR5312_MISC_IRQ_UART0_DMA 5 +#define AR5312_MISC_IRQ_WATCHDOG 6 +#define AR5312_MISC_IRQ_LOCAL 7 +#define AR5312_MISC_IRQ_SPI 8 +#define AR5312_MISC_IRQ_COUNT 9 + +/* + * Address Map + * + * The AR5312 supports 2 enet MACS, even though many reference boards only + * actually use 1 of them (i.e. Only MAC 0 is actually connected to an enet + * PHY or PHY switch. The AR2312 supports 1 enet MAC. + */ +#define AR5312_WLAN0_BASE 0x18000000 +#define AR5312_ENET0_BASE 0x18100000 +#define AR5312_ENET1_BASE 0x18200000 +#define AR5312_SDRAMCTL_BASE 0x18300000 +#define AR5312_SDRAMCTL_SIZE 0x00000010 +#define AR5312_FLASHCTL_BASE 0x18400000 +#define AR5312_FLASHCTL_SIZE 0x00000010 +#define AR5312_WLAN1_BASE 0x18500000 +#define AR5312_UART0_BASE 0x1c000000 /* UART MMR */ +#define AR5312_GPIO_BASE 0x1c002000 +#define AR5312_GPIO_SIZE 0x00000010 +#define AR5312_RST_BASE 0x1c003000 +#define AR5312_RST_SIZE 0x00000100 +#define AR5312_FLASH_BASE 0x1e000000 +#define AR5312_FLASH_SIZE 0x00800000 + +/* + * Need these defines to determine true number of ethernet MACs + */ +#define AR5312_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ +#define AR5312_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ +#define AR5312_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */ + +/* Reset/Timer Block Address Map */ +#define AR5312_TIMER 0x0000 /* countdown timer */ +#define AR5312_RELOAD 0x0004 /* timer reload value */ +#define AR5312_WDT_CTRL 0x0008 /* watchdog cntrl */ +#define AR5312_WDT_TIMER 0x000c /* watchdog timer */ +#define AR5312_ISR 0x0010 /* Intr Status Reg */ +#define AR5312_IMR 0x0014 /* Intr Mask Reg */ +#define AR5312_RESET 0x0020 +#define AR5312_CLOCKCTL1 0x0064 +#define AR5312_SCRATCH 0x006c +#define AR5312_PROCADDR 0x0070 +#define AR5312_PROC1 0x0074 +#define AR5312_DMAADDR 0x0078 +#define AR5312_DMA1 0x007c +#define AR5312_ENABLE 0x0080 /* interface enb */ +#define AR5312_REV 0x0090 /* revision */ + +/* AR5312_WDT_CTRL register bit field definitions */ +#define AR5312_WDT_CTRL_IGNORE 0x00000000 /* ignore expiration */ +#define AR5312_WDT_CTRL_NMI 0x00000001 +#define AR5312_WDT_CTRL_RESET 0x00000002 + +/* AR5312_ISR register bit field definitions */ +#define AR5312_ISR_TIMER 0x00000001 +#define AR5312_ISR_AHBPROC 0x00000002 +#define AR5312_ISR_AHBDMA 0x00000004 +#define AR5312_ISR_GPIO 0x00000008 +#define AR5312_ISR_UART0 0x00000010 +#define AR5312_ISR_UART0DMA 0x00000020 +#define AR5312_ISR_WD 0x00000040 +#define AR5312_ISR_LOCAL 0x00000080 + +/* AR5312_RESET register bit field definitions */ +#define AR5312_RESET_SYSTEM 0x00000001 /* cold reset full system */ +#define AR5312_RESET_PROC 0x00000002 /* cold reset MIPS core */ +#define AR5312_RESET_WLAN0 0x00000004 /* cold reset WLAN MAC/BB */ +#define AR5312_RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */ +#define AR5312_RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */ +#define AR5312_RESET_ENET0 0x00000020 /* cold reset ENET0 MAC */ +#define AR5312_RESET_ENET1 0x00000040 /* cold reset ENET1 MAC */ +#define AR5312_RESET_UART0 0x00000100 /* cold reset UART0 */ +#define AR5312_RESET_WLAN1 0x00000200 /* cold reset WLAN MAC/BB */ +#define AR5312_RESET_APB 0x00000400 /* cold reset APB ar5312 */ +#define AR5312_RESET_WARM_PROC 0x00001000 /* warm reset MIPS core */ +#define AR5312_RESET_WARM_WLAN0_MAC 0x00002000 /* warm reset WLAN0 MAC */ +#define AR5312_RESET_WARM_WLAN0_BB 0x00004000 /* warm reset WLAN0 BB */ +#define AR5312_RESET_NMI 0x00010000 /* send an NMI to the CPU */ +#define AR5312_RESET_WARM_WLAN1_MAC 0x00020000 /* warm reset WLAN1 MAC */ +#define AR5312_RESET_WARM_WLAN1_BB 0x00040000 /* warm reset WLAN1 BB */ +#define AR5312_RESET_LOCAL_BUS 0x00080000 /* reset local bus */ +#define AR5312_RESET_WDOG 0x00100000 /* last reset was a wdt */ + +#define AR5312_RESET_WMAC0_BITS (AR5312_RESET_WLAN0 |\ + AR5312_RESET_WARM_WLAN0_MAC |\ + AR5312_RESET_WARM_WLAN0_BB) + +#define AR5312_RESET_WMAC1_BITS (AR5312_RESET_WLAN1 |\ + AR5312_RESET_WARM_WLAN1_MAC |\ + AR5312_RESET_WARM_WLAN1_BB) + +/* AR5312_CLOCKCTL1 register bit field definitions */ +#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 +#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 +#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 +#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 +#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 + +/* Valid for AR5312 and AR2312 */ +#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030 +#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4 +#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00 +#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8 +#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000 + +/* Valid for AR2313 */ +#define AR2313_CLOCKCTL1_PREDIVIDE_MASK 0x00003000 +#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT 12 +#define AR2313_CLOCKCTL1_MULTIPLIER_MASK 0x001f0000 +#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT 16 +#define AR2313_CLOCKCTL1_DOUBLER_MASK 0x00000000 + +/* AR5312_ENABLE register bit field definitions */ +#define AR5312_ENABLE_WLAN0 0x00000001 +#define AR5312_ENABLE_ENET0 0x00000002 +#define AR5312_ENABLE_ENET1 0x00000004 +#define AR5312_ENABLE_UART_AND_WLAN1_PIO 0x00000008/* UART & WLAN1 PIO */ +#define AR5312_ENABLE_WLAN1_DMA 0x00000010/* WLAN1 DMAs */ +#define AR5312_ENABLE_WLAN1 (AR5312_ENABLE_UART_AND_WLAN1_PIO |\ + AR5312_ENABLE_WLAN1_DMA) + +/* AR5312_REV register bit field definitions */ +#define AR5312_REV_WMAC_MAJ 0x0000f000 +#define AR5312_REV_WMAC_MAJ_S 12 +#define AR5312_REV_WMAC_MIN 0x00000f00 +#define AR5312_REV_WMAC_MIN_S 8 +#define AR5312_REV_MAJ 0x000000f0 +#define AR5312_REV_MAJ_S 4 +#define AR5312_REV_MIN 0x0000000f +#define AR5312_REV_MIN_S 0 +#define AR5312_REV_CHIP (AR5312_REV_MAJ|AR5312_REV_MIN) + +/* Major revision numbers, bits 7..4 of Revision ID register */ +#define AR5312_REV_MAJ_AR5312 0x4 +#define AR5312_REV_MAJ_AR2313 0x5 + +/* Minor revision numbers, bits 3..0 of Revision ID register */ +#define AR5312_REV_MIN_DUAL 0x0 /* Dual WLAN version */ +#define AR5312_REV_MIN_SINGLE 0x1 /* Single WLAN version */ + +/* + * ARM Flash Controller -- 3 flash banks with either x8 or x16 devices + */ +#define AR5312_FLASHCTL0 0x0000 +#define AR5312_FLASHCTL1 0x0004 +#define AR5312_FLASHCTL2 0x0008 + +/* AR5312_FLASHCTL register bit field definitions */ +#define AR5312_FLASHCTL_IDCY 0x0000000f /* Idle cycle turnaround time */ +#define AR5312_FLASHCTL_IDCY_S 0 +#define AR5312_FLASHCTL_WST1 0x000003e0 /* Wait state 1 */ +#define AR5312_FLASHCTL_WST1_S 5 +#define AR5312_FLASHCTL_RBLE 0x00000400 /* Read byte lane enable */ +#define AR5312_FLASHCTL_WST2 0x0000f800 /* Wait state 2 */ +#define AR5312_FLASHCTL_WST2_S 11 +#define AR5312_FLASHCTL_AC 0x00070000 /* Flash addr check (added) */ +#define AR5312_FLASHCTL_AC_S 16 +#define AR5312_FLASHCTL_AC_128K 0x00000000 +#define AR5312_FLASHCTL_AC_256K 0x00010000 +#define AR5312_FLASHCTL_AC_512K 0x00020000 +#define AR5312_FLASHCTL_AC_1M 0x00030000 +#define AR5312_FLASHCTL_AC_2M 0x00040000 +#define AR5312_FLASHCTL_AC_4M 0x00050000 +#define AR5312_FLASHCTL_AC_8M 0x00060000 +#define AR5312_FLASHCTL_AC_RES 0x00070000 /* 16MB is not supported */ +#define AR5312_FLASHCTL_E 0x00080000 /* Flash bank enable (added) */ +#define AR5312_FLASHCTL_BUSERR 0x01000000 /* Bus transfer error flag */ +#define AR5312_FLASHCTL_WPERR 0x02000000 /* Write protect error flag */ +#define AR5312_FLASHCTL_WP 0x04000000 /* Write protect */ +#define AR5312_FLASHCTL_BM 0x08000000 /* Burst mode */ +#define AR5312_FLASHCTL_MW 0x30000000 /* Mem width */ +#define AR5312_FLASHCTL_MW8 0x00000000 /* Mem width x8 */ +#define AR5312_FLASHCTL_MW16 0x10000000 /* Mem width x16 */ +#define AR5312_FLASHCTL_MW32 0x20000000 /* Mem width x32 (not supp) */ +#define AR5312_FLASHCTL_ATNR 0x00000000 /* Access == no retry */ +#define AR5312_FLASHCTL_ATR 0x80000000 /* Access == retry every */ +#define AR5312_FLASHCTL_ATR4 0xc0000000 /* Access == retry every 4 */ + +/* + * ARM SDRAM Controller -- just enough to determine memory size + */ +#define AR5312_MEM_CFG1 0x0004 + +#define AR5312_MEM_CFG1_AC0_M 0x00000700 /* bank 0: SDRAM addr check */ +#define AR5312_MEM_CFG1_AC0_S 8 +#define AR5312_MEM_CFG1_AC1_M 0x00007000 /* bank 1: SDRAM addr check */ +#define AR5312_MEM_CFG1_AC1_S 12 + +#endif /* __ASM_MACH_ATH25_AR5312_REGS_H */ diff --git a/arch/mips/ath25/board.c b/arch/mips/ath25/board.c new file mode 100644 index 0000000..b8bb782 --- /dev/null +++ b/arch/mips/ath25/board.c @@ -0,0 +1,234 @@ +/* + * 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) 2003 Atheros Communications, Inc., All Rights Reserved. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org> + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <asm/irq_cpu.h> +#include <asm/reboot.h> +#include <asm/bootinfo.h> +#include <asm/time.h> + +#include <ath25_platform.h> +#include "devices.h" +#include "ar5312.h" +#include "ar2315.h" + +void (*ath25_irq_dispatch)(void); + +static inline bool check_radio_magic(const void __iomem *addr) +{ + addr += 0x7a; /* offset for flash magic */ + return (__raw_readb(addr) == 0x5a) && (__raw_readb(addr + 1) == 0xa5); +} + +static inline bool check_notempty(const void __iomem *addr) +{ + return __raw_readl(addr) != 0xffffffff; +} + +static inline bool check_board_data(const void __iomem *addr, bool broken) +{ + /* config magic found */ + if (__raw_readl(addr) == ATH25_BD_MAGIC) + return true; + + if (!broken) + return false; + + /* broken board data detected, use radio data to find the + * offset, user will fix this */ + + if (check_radio_magic(addr + 0x1000)) + return true; + if (check_radio_magic(addr + 0xf8)) + return true; + + return false; +} + +static const void __iomem * __init find_board_config(const void __iomem *limit, + const bool broken) +{ + const void __iomem *addr; + const void __iomem *begin = limit - 0x1000; + const void __iomem *end = limit - 0x30000; + + for (addr = begin; addr >= end; addr -= 0x1000) + if (check_board_data(addr, broken)) + return addr; + + return NULL; +} + +static const void __iomem * __init find_radio_config(const void __iomem *limit, + const void __iomem *bcfg) +{ + const void __iomem *rcfg, *begin, *end; + + /* + * Now find the start of Radio Configuration data, using heuristics: + * Search forward from Board Configuration data by 0x1000 bytes + * at a time until we find non-0xffffffff. + */ + begin = bcfg + 0x1000; + end = limit; + for (rcfg = begin; rcfg < end; rcfg += 0x1000) + if (check_notempty(rcfg) && check_radio_magic(rcfg)) + return rcfg; + + /* AR2316 relocates radio config to new location */ + begin = bcfg + 0xf8; + end = limit - 0x1000 + 0xf8; + for (rcfg = begin; rcfg < end; rcfg += 0x1000) + if (check_notempty(rcfg) && check_radio_magic(rcfg)) + return rcfg; + + return NULL; +} + +/* + * NB: Search region size could be larger than the actual flash size, + * but this shouldn't be a problem here, because the flash + * will simply be mapped multiple times. + */ +int __init ath25_find_config(phys_addr_t base, unsigned long size) +{ + const void __iomem *flash_base, *flash_limit; + struct ath25_boarddata *config; + unsigned int rcfg_size; + int broken_boarddata = 0; + const void __iomem *bcfg, *rcfg; + u8 *board_data; + u8 *radio_data; + u8 *mac_addr; + u32 offset; + + flash_base = ioremap_nocache(base, size); + flash_limit = flash_base + size; + + ath25_board.config = NULL; + ath25_board.radio = NULL; + + /* Copy the board and radio data to RAM, because accessing the mapped + * memory of the flash directly after booting is not safe */ + + /* Try to find valid board and radio data */ + bcfg = find_board_config(flash_limit, false); + + /* If that fails, try to at least find valid radio data */ + if (!bcfg) { + bcfg = find_board_config(flash_limit, true); + broken_boarddata = 1; + } + + if (!bcfg) { + pr_warn("WARNING: No board configuration data found!\n"); + goto error; + } + + board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL); + ath25_board.config = (struct ath25_boarddata *)board_data; + memcpy_fromio(board_data, bcfg, 0x100); + if (broken_boarddata) { + pr_warn("WARNING: broken board data detected\n"); + config = ath25_board.config; + if (is_zero_ether_addr(config->enet0_mac)) { + pr_info("Fixing up empty mac addresses\n"); + config->reset_config_gpio = 0xffff; + config->sys_led_gpio = 0xffff; + random_ether_addr(config->wlan0_mac); + config->wlan0_mac[0] &= ~0x06; + random_ether_addr(config->enet0_mac); + random_ether_addr(config->enet1_mac); + } + } + + /* Radio config starts 0x100 bytes after board config, regardless + * of what the physical layout on the flash chip looks like */ + + rcfg = find_radio_config(flash_limit, bcfg); + if (!rcfg) { + pr_warn("WARNING: Could not find Radio Configuration data\n"); + goto error; + } + + radio_data = board_data + 0x100 + ((rcfg - bcfg) & 0xfff); + ath25_board.radio = radio_data; + offset = radio_data - board_data; + pr_info("Radio config found at offset 0x%x (0x%x)\n", rcfg - bcfg, + offset); + rcfg_size = BOARD_CONFIG_BUFSZ - offset; + memcpy_fromio(radio_data, rcfg, rcfg_size); + + mac_addr = &radio_data[0x1d * 2]; + if (is_broadcast_ether_addr(mac_addr)) { + pr_info("Radio MAC is blank; using board-data\n"); + ether_addr_copy(mac_addr, ath25_board.config->wlan0_mac); + } + + iounmap(flash_base); + + return 0; + +error: + iounmap(flash_base); + return -ENODEV; +} + +static void ath25_halt(void) +{ + local_irq_disable(); + unreachable(); +} + +void __init plat_mem_setup(void) +{ + _machine_halt = ath25_halt; + pm_power_off = ath25_halt; + + if (is_ar5312()) + ar5312_plat_mem_setup(); + else + ar2315_plat_mem_setup(); + + /* Disable data watchpoints */ + write_c0_watchlo0(0); +} + +asmlinkage void plat_irq_dispatch(void) +{ + ath25_irq_dispatch(); +} + +void __init plat_time_init(void) +{ + if (is_ar5312()) + ar5312_plat_time_init(); + else + ar2315_plat_time_init(); +} + +unsigned int __cpuinit get_c0_compare_int(void) +{ + return CP0_LEGACY_COMPARE_IRQ; +} + +void __init arch_init_irq(void) +{ + clear_c0_status(ST0_IM); + mips_cpu_irq_init(); + + /* Initialize interrupt controllers */ + if (is_ar5312()) + ar5312_arch_init_irq(); + else + ar2315_arch_init_irq(); +} diff --git a/arch/mips/ath25/devices.c b/arch/mips/ath25/devices.c new file mode 100644 index 0000000..7a64567 --- /dev/null +++ b/arch/mips/ath25/devices.c @@ -0,0 +1,125 @@ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/serial_8250.h> +#include <linux/platform_device.h> +#include <asm/bootinfo.h> + +#include <ath25_platform.h> +#include "devices.h" +#include "ar5312.h" +#include "ar2315.h" + +struct ar231x_board_config ath25_board; +enum ath25_soc_type ath25_soc = ATH25_SOC_UNKNOWN; + +static struct resource ath25_wmac0_res[] = { + { + .name = "wmac0_membase", + .flags = IORESOURCE_MEM, + }, + { + .name = "wmac0_irq", + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource ath25_wmac1_res[] = { + { + .name = "wmac1_membase", + .flags = IORESOURCE_MEM, + }, + { + .name = "wmac1_irq", + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device ath25_wmac[] = { + { + .id = 0, + .name = "ar231x-wmac", + .resource = ath25_wmac0_res, + .num_resources = ARRAY_SIZE(ath25_wmac0_res), + .dev.platform_data = &ath25_board, + }, + { + .id = 1, + .name = "ar231x-wmac", + .resource = ath25_wmac1_res, + .num_resources = ARRAY_SIZE(ath25_wmac1_res), + .dev.platform_data = &ath25_board, + }, +}; + +static const char * const soc_type_strings[] = { + [ATH25_SOC_AR5312] = "Atheros AR5312", + [ATH25_SOC_AR2312] = "Atheros AR2312", + [ATH25_SOC_AR2313] = "Atheros AR2313", + [ATH25_SOC_AR2315] = "Atheros AR2315", + [ATH25_SOC_AR2316] = "Atheros AR2316", + [ATH25_SOC_AR2317] = "Atheros AR2317", + [ATH25_SOC_AR2318] = "Atheros AR2318", + [ATH25_SOC_UNKNOWN] = "Atheros (unknown)", +}; + +const char *get_system_type(void) +{ + if ((ath25_soc >= ARRAY_SIZE(soc_type_strings)) || + !soc_type_strings[ath25_soc]) + return soc_type_strings[ATH25_SOC_UNKNOWN]; + return soc_type_strings[ath25_soc]; +} + +void __init ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk) +{ + struct uart_port s; + + memset(&s, 0, sizeof(s)); + + s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP; + s.iotype = UPIO_MEM32; + s.irq = irq; + s.regshift = 2; + s.mapbase = mapbase; + s.uartclk = uartclk; + + early_serial_setup(&s); +} + +int __init ath25_add_wmac(int nr, u32 base, int irq) +{ + struct resource *res; + + ath25_wmac[nr].dev.platform_data = &ath25_board; + res = &ath25_wmac[nr].resource[0]; + res->start = base; + res->end = base + 0x10000 - 1; + res++; + res->start = irq; + res->end = irq; + return platform_device_register(&ath25_wmac[nr]); +} + +static int __init ath25_register_devices(void) +{ + if (is_ar5312()) + ar5312_init_devices(); + else + ar2315_init_devices(); + + return 0; +} + +device_initcall(ath25_register_devices); + +static int __init ath25_arch_init(void) +{ + if (is_ar5312()) + ar5312_arch_init(); + else + ar2315_arch_init(); + + return 0; +} + +arch_initcall(ath25_arch_init); diff --git a/arch/mips/ath25/devices.h b/arch/mips/ath25/devices.h new file mode 100644 index 0000000..04d4141 --- /dev/null +++ b/arch/mips/ath25/devices.h @@ -0,0 +1,43 @@ +#ifndef __ATH25_DEVICES_H +#define __ATH25_DEVICES_H + +#include <linux/cpu.h> + +#define ATH25_REG_MS(_val, _field) (((_val) & _field##_M) >> _field##_S) + +#define ATH25_IRQ_CPU_CLOCK (MIPS_CPU_IRQ_BASE + 7) /* C0_CAUSE: 0x8000 */ + +enum ath25_soc_type { + /* handled by ar5312.c */ + ATH25_SOC_AR2312, + ATH25_SOC_AR2313, + ATH25_SOC_AR5312, + + /* handled by ar2315.c */ + ATH25_SOC_AR2315, + ATH25_SOC_AR2316, + ATH25_SOC_AR2317, + ATH25_SOC_AR2318, + + ATH25_SOC_UNKNOWN +}; + +extern enum ath25_soc_type ath25_soc; +extern struct ar231x_board_config ath25_board; +extern void (*ath25_irq_dispatch)(void); + +int ath25_find_config(phys_addr_t offset, unsigned long size); +void ath25_serial_setup(u32 mapbase, int irq, unsigned int uartclk); +int ath25_add_wmac(int nr, u32 base, int irq); + +static inline bool is_ar2315(void) +{ + return (current_cpu_data.cputype == CPU_4KEC); +} + +static inline bool is_ar5312(void) +{ + return !is_ar2315(); +} + +#endif diff --git a/arch/mips/ath25/early_printk.c b/arch/mips/ath25/early_printk.c new file mode 100644 index 0000000..36035b6 --- /dev/null +++ b/arch/mips/ath25/early_printk.c @@ -0,0 +1,44 @@ +/* + * 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) 2010 Gabor Juhos <juhosg@openwrt.org> + */ + +#include <linux/mm.h> +#include <linux/io.h> +#include <linux/serial_reg.h> + +#include "devices.h" +#include "ar2315_regs.h" +#include "ar5312_regs.h" + +static inline void prom_uart_wr(void __iomem *base, unsigned reg, + unsigned char ch) +{ + __raw_writel(ch, base + 4 * reg); +} + +static inline unsigned char prom_uart_rr(void __iomem *base, unsigned reg) +{ + return __raw_readl(base + 4 * reg); +} + +void prom_putchar(unsigned char ch) +{ + static void __iomem *base; + + if (unlikely(base == NULL)) { + if (is_ar2315()) + base = (void __iomem *)(KSEG1ADDR(AR2315_UART0_BASE)); + else + base = (void __iomem *)(KSEG1ADDR(AR5312_UART0_BASE)); + } + + while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0) + ; + prom_uart_wr(base, UART_TX, ch); + while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0) + ; +} diff --git a/arch/mips/ath25/prom.c b/arch/mips/ath25/prom.c new file mode 100644 index 0000000..edf82be --- /dev/null +++ b/arch/mips/ath25/prom.c @@ -0,0 +1,26 @@ +/* + * 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 MontaVista Software Inc + * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + */ + +/* + * Prom setup file for AR5312/AR231x SoCs + */ + +#include <linux/init.h> +#include <asm/bootinfo.h> + +void __init prom_init(void) +{ +} + +void __init prom_free_prom_memory(void) +{ +} diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index 9c0e176..6adae36 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -359,7 +359,6 @@ void __init arch_init_irq(void) BUG(); } - cp0_perfcount_irq = ATH79_MISC_IRQ(5); mips_cpu_irq_init(); ath79_misc_irq_init(); diff --git a/arch/mips/ath79/prom.c b/arch/mips/ath79/prom.c index e9cbd7c..e1fe630 100644 --- a/arch/mips/ath79/prom.c +++ b/arch/mips/ath79/prom.c @@ -13,42 +13,24 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/string.h> +#include <linux/initrd.h> #include <asm/bootinfo.h> #include <asm/addrspace.h> +#include <asm/fw/fw.h> #include "common.h" -static inline int is_valid_ram_addr(void *addr) -{ - if (((u32) addr > KSEG0) && - ((u32) addr < (KSEG0 + ATH79_MEM_SIZE_MAX))) - return 1; - - if (((u32) addr > KSEG1) && - ((u32) addr < (KSEG1 + ATH79_MEM_SIZE_MAX))) - return 1; - - return 0; -} - -static __init void ath79_prom_init_cmdline(int argc, char **argv) -{ - int i; - - if (!is_valid_ram_addr(argv)) - return; - - for (i = 0; i < argc; i++) - if (is_valid_ram_addr(argv[i])) { - strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); - strlcat(arcs_cmdline, argv[i], sizeof(arcs_cmdline)); - } -} - void __init prom_init(void) { - ath79_prom_init_cmdline(fw_arg0, (char **)fw_arg1); + fw_init_cmdline(); + + /* Read the initrd address from the firmware environment */ + initrd_start = fw_getenvl("initrd_start"); + if (initrd_start) { + initrd_start = KSEG0ADDR(initrd_start); + initrd_end = initrd_start + fw_getenvl("initrd_size"); + } } void __init prom_free_prom_memory(void) diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index 64807a4..a73c93c 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -182,6 +182,11 @@ const char *get_system_type(void) return ath79_sys_type; } +int get_c0_perfcount_int(void) +{ + return ATH79_MISC_IRQ(5); +} + unsigned int get_c0_compare_int(void) { return CP0_LEGACY_COMPARE_IRQ; diff --git a/arch/mips/bcm3384/Makefile b/arch/mips/bcm3384/Makefile new file mode 100644 index 0000000..a393955 --- /dev/null +++ b/arch/mips/bcm3384/Makefile @@ -0,0 +1 @@ +obj-y += setup.o irq.o dma.o diff --git a/arch/mips/bcm3384/Platform b/arch/mips/bcm3384/Platform new file mode 100644 index 0000000..8e1ca08 --- /dev/null +++ b/arch/mips/bcm3384/Platform @@ -0,0 +1,7 @@ +# +# Broadcom BCM3384 boards +# +platform-$(CONFIG_BCM3384) += bcm3384/ +cflags-$(CONFIG_BCM3384) += \ + -I$(srctree)/arch/mips/include/asm/mach-bcm3384/ +load-$(CONFIG_BCM3384) := 0xffffffff80010000 diff --git a/arch/mips/bcm3384/dma.c b/arch/mips/bcm3384/dma.c new file mode 100644 index 0000000..ea42012 --- /dev/null +++ b/arch/mips/bcm3384/dma.c @@ -0,0 +1,81 @@ +/* + * 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) 2014 Kevin Cernekee <cernekee@gmail.com> + */ + +#include <linux/device.h> +#include <linux/dma-direction.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/of.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <dma-coherence.h> + +/* + * BCM3384 has configurable address translation windows which allow the + * peripherals' DMA addresses to be different from the Zephyr-visible + * physical addresses. e.g. usb_dma_addr = zephyr_pa ^ 0x08000000 + * + * If our DT "memory" node has a "dma-xor-mask" property we will enable this + * translation using the provided offset. + */ +static u32 bcm3384_dma_xor_mask; +static u32 bcm3384_dma_xor_limit = 0xffffffff; + +/* + * PCI collapses the memory hole at 0x10000000 - 0x1fffffff. + * On systems with a dma-xor-mask, this range is guaranteed to live above + * the dma-xor-limit. + */ +#define BCM3384_MEM_HOLE_PA 0x10000000 +#define BCM3384_MEM_HOLE_SIZE 0x10000000 + +static dma_addr_t bcm3384_phys_to_dma(struct device *dev, phys_addr_t pa) +{ + if (dev && dev_is_pci(dev) && + pa >= (BCM3384_MEM_HOLE_PA + BCM3384_MEM_HOLE_SIZE)) + return pa - BCM3384_MEM_HOLE_SIZE; + if (pa <= bcm3384_dma_xor_limit) + return pa ^ bcm3384_dma_xor_mask; + return pa; +} + +dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) +{ + return bcm3384_phys_to_dma(dev, virt_to_phys(addr)); +} + +dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) +{ + return bcm3384_phys_to_dma(dev, page_to_phys(page)); +} + +unsigned long plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr) +{ + if (dev && dev_is_pci(dev) && + dma_addr >= BCM3384_MEM_HOLE_PA) + return dma_addr + BCM3384_MEM_HOLE_SIZE; + if ((dma_addr ^ bcm3384_dma_xor_mask) <= bcm3384_dma_xor_limit) + return dma_addr ^ bcm3384_dma_xor_mask; + return dma_addr; +} + +static int __init bcm3384_init_dma_xor(void) +{ + struct device_node *np = of_find_node_by_type(NULL, "memory"); + + if (!np) + return 0; + + of_property_read_u32(np, "dma-xor-mask", &bcm3384_dma_xor_mask); + of_property_read_u32(np, "dma-xor-limit", &bcm3384_dma_xor_limit); + + of_node_put(np); + return 0; +} +arch_initcall(bcm3384_init_dma_xor); diff --git a/arch/mips/bcm3384/irq.c b/arch/mips/bcm3384/irq.c new file mode 100644 index 0000000..0fb5134 --- /dev/null +++ b/arch/mips/bcm3384/irq.c @@ -0,0 +1,193 @@ +/* + * 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. + * + * Partially based on arch/mips/ralink/irq.c + * + * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + * Copyright (C) 2014 Kevin Cernekee <cernekee@gmail.com> + */ + +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/irqdomain.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include <asm/bmips.h> +#include <asm/irq_cpu.h> +#include <asm/mipsregs.h> + +/* INTC register offsets */ +#define INTC_REG_ENABLE 0x00 +#define INTC_REG_STATUS 0x04 + +#define MAX_WORDS 2 +#define IRQS_PER_WORD 32 + +struct bcm3384_intc { + int n_words; + void __iomem *reg[MAX_WORDS]; + u32 enable[MAX_WORDS]; + spinlock_t lock; +}; + +static void bcm3384_intc_irq_unmask(struct irq_data *d) +{ + struct bcm3384_intc *priv = d->domain->host_data; + unsigned long flags; + int idx = d->hwirq / IRQS_PER_WORD; + int bit = d->hwirq % IRQS_PER_WORD; + + spin_lock_irqsave(&priv->lock, flags); + priv->enable[idx] |= BIT(bit); + __raw_writel(priv->enable[idx], priv->reg[idx] + INTC_REG_ENABLE); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void bcm3384_intc_irq_mask(struct irq_data *d) +{ + struct bcm3384_intc *priv = d->domain->host_data; + unsigned long flags; + int idx = d->hwirq / IRQS_PER_WORD; + int bit = d->hwirq % IRQS_PER_WORD; + + spin_lock_irqsave(&priv->lock, flags); + priv->enable[idx] &= ~BIT(bit); + __raw_writel(priv->enable[idx], priv->reg[idx] + INTC_REG_ENABLE); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static struct irq_chip bcm3384_intc_irq_chip = { + .name = "INTC", + .irq_unmask = bcm3384_intc_irq_unmask, + .irq_mask = bcm3384_intc_irq_mask, + .irq_mask_ack = bcm3384_intc_irq_mask, +}; + +unsigned int get_c0_compare_int(void) +{ + return CP0_LEGACY_COMPARE_IRQ; +} + +static void bcm3384_intc_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct irq_domain *domain = irq_get_handler_data(irq); + struct bcm3384_intc *priv = domain->host_data; + unsigned long flags; + unsigned int idx; + + for (idx = 0; idx < priv->n_words; idx++) { + unsigned long pending; + int hwirq; + + spin_lock_irqsave(&priv->lock, flags); + pending = __raw_readl(priv->reg[idx] + INTC_REG_STATUS) & + priv->enable[idx]; + spin_unlock_irqrestore(&priv->lock, flags); + + for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { + generic_handle_irq(irq_find_mapping(domain, + hwirq + idx * IRQS_PER_WORD)); + } + } +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned long pending = + (read_c0_status() & read_c0_cause() & ST0_IM) >> STATUSB_IP0; + int bit; + + for_each_set_bit(bit, &pending, 8) + do_IRQ(MIPS_CPU_IRQ_BASE + bit); +} + +static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &bcm3384_intc_irq_chip, handle_level_irq); + return 0; +} + +static const struct irq_domain_ops irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = intc_map, +}; + +static int __init ioremap_one_pair(struct bcm3384_intc *priv, + struct device_node *node, + int idx) +{ + struct resource res; + + if (of_address_to_resource(node, idx, &res)) + return 0; + + if (request_mem_region(res.start, resource_size(&res), + res.name) < 0) + pr_err("Failed to request INTC register region\n"); + + priv->reg[idx] = ioremap_nocache(res.start, resource_size(&res)); + if (!priv->reg[idx]) + panic("Failed to ioremap INTC register range"); + + /* start up with everything masked before we hook the parent IRQ */ + __raw_writel(0, priv->reg[idx] + INTC_REG_ENABLE); + priv->enable[idx] = 0; + + return IRQS_PER_WORD; +} + +static int __init intc_of_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *domain; + unsigned int parent_irq, n_irqs = 0; + struct bcm3384_intc *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + panic("Failed to allocate bcm3384_intc struct"); + + spin_lock_init(&priv->lock); + + parent_irq = irq_of_parse_and_map(node, 0); + if (!parent_irq) + panic("Failed to get INTC IRQ"); + + n_irqs += ioremap_one_pair(priv, node, 0); + n_irqs += ioremap_one_pair(priv, node, 1); + + if (!n_irqs) + panic("Failed to map INTC registers"); + + priv->n_words = n_irqs / IRQS_PER_WORD; + domain = irq_domain_add_linear(node, n_irqs, &irq_domain_ops, priv); + if (!domain) + panic("Failed to add irqdomain"); + + irq_set_chained_handler(parent_irq, bcm3384_intc_irq_handler); + irq_set_handler_data(parent_irq, domain); + + return 0; +} + +static struct of_device_id of_irq_ids[] __initdata = { + { .compatible = "mti,cpu-interrupt-controller", + .data = mips_cpu_intc_init }, + { .compatible = "brcm,bcm3384-intc", + .data = intc_of_init }, + {}, +}; + +void __init arch_init_irq(void) +{ + bmips_tp1_irqs = 0; + of_irq_init(of_irq_ids); +} diff --git a/arch/mips/bcm3384/setup.c b/arch/mips/bcm3384/setup.c new file mode 100644 index 0000000..d84b840 --- /dev/null +++ b/arch/mips/bcm3384/setup.c @@ -0,0 +1,97 @@ +/* + * 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) 2008 Maxime Bizon <mbizon@freebox.fr> + * Copyright (C) 2014 Kevin Cernekee <cernekee@gmail.com> + */ + +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/clk-provider.h> +#include <linux/ioport.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/of_platform.h> +#include <linux/smp.h> +#include <asm/addrspace.h> +#include <asm/bmips.h> +#include <asm/bootinfo.h> +#include <asm/prom.h> +#include <asm/smp-ops.h> +#include <asm/time.h> + +void __init prom_init(void) +{ + register_bmips_smp_ops(); +} + +void __init prom_free_prom_memory(void) +{ +} + +const char *get_system_type(void) +{ + return "BCM3384"; +} + +void __init plat_time_init(void) +{ + struct device_node *np; + u32 freq; + + np = of_find_node_by_name(NULL, "cpus"); + if (!np) + panic("missing 'cpus' DT node"); + if (of_property_read_u32(np, "mips-hpt-frequency", &freq) < 0) + panic("missing 'mips-hpt-frequency' property"); + of_node_put(np); + + mips_hpt_frequency = freq; +} + +void __init plat_mem_setup(void) +{ + void *dtb = __dtb_start; + + set_io_port_base(0); + ioport_resource.start = 0; + ioport_resource.end = ~0; + + /* intended to somewhat resemble ARM; see Documentation/arm/Booting */ + if (fw_arg0 == 0 && fw_arg1 == 0xffffffff) + dtb = phys_to_virt(fw_arg2); + + __dt_setup_arch(dtb); + + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); +} + +void __init device_tree_init(void) +{ + struct device_node *np; + + unflatten_and_copy_device_tree(); + + /* Disable SMP boot unless both CPUs are listed in DT and !disabled */ + np = of_find_node_by_name(NULL, "cpus"); + if (np && of_get_available_child_count(np) <= 1) + bmips_smp_enabled = 0; + of_node_put(np); +} + +int __init plat_of_setup(void) +{ + return __dt_register_buses("brcm,bcm3384", "simple-bus"); +} + +arch_initcall(plat_of_setup); + +static int __init plat_dev_init(void) +{ + of_clk_init(NULL); + return 0; +} + +device_initcall(plat_dev_init); diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h index f1cc9d0..ea909a5 100644 --- a/arch/mips/bcm47xx/bcm47xx_private.h +++ b/arch/mips/bcm47xx/bcm47xx_private.h @@ -6,12 +6,18 @@ /* 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); /* leds.c */ void __init bcm47xx_leds_register(void); +/* setup.c */ +void __init bcm47xx_bus_setup(void); + /* workarounds.c */ void __init bcm47xx_workarounds(void); diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c index e0585b7..21b4497 100644 --- a/arch/mips/bcm47xx/irq.c +++ b/arch/mips/bcm47xx/irq.c @@ -22,6 +22,8 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "bcm47xx_private.h" + #include <linux/types.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -65,6 +67,12 @@ DEFINE_HWx_IRQDISPATCH(7) void __init arch_init_irq(void) { + /* + * This is the first arch callback after mm_init (we can use kmalloc), + * so let's finish bus initialization now. + */ + bcm47xx_bus_setup(); + #ifdef CONFIG_BCM47XX_BCMA if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA) { bcma_write32(bcm47xx_bus.bcma.bus.drv_mips.core, diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index 2bed73a..c5c381c 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -13,24 +13,35 @@ #include <linux/types.h> #include <linux/module.h> -#include <linux/ssb/ssb.h> #include <linux/kernel.h> #include <linux/string.h> -#include <asm/addrspace.h> +#include <linux/mtd/mtd.h> #include <bcm47xx_nvram.h> -#include <asm/mach-bcm47xx/bcm47xx.h> + +#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */ +#define NVRAM_SPACE 0x8000 + +#define FLASH_MIN 0x00020000 /* Minimum flash size */ + +struct nvram_header { + u32 magic; + u32 len; + u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ + u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ + u32 config_ncdl; /* ncdl values for memc */ +}; static char nvram_buf[NVRAM_SPACE]; static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000}; -static u32 find_nvram_size(u32 end) +static u32 find_nvram_size(void __iomem *end) { - struct nvram_header *header; + struct nvram_header __iomem *header; int i; for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { - header = (struct nvram_header *)KSEG1ADDR(end - nvram_sizes[i]); - if (header->magic == NVRAM_HEADER) + header = (struct nvram_header *)(end - nvram_sizes[i]); + if (header->magic == NVRAM_MAGIC) return nvram_sizes[i]; } @@ -38,36 +49,40 @@ static u32 find_nvram_size(u32 end) } /* Probe for NVRAM header */ -static int nvram_find_and_copy(u32 base, u32 lim) +static int nvram_find_and_copy(void __iomem *iobase, u32 lim) { - struct nvram_header *header; + struct nvram_header __iomem *header; int i; u32 off; u32 *src, *dst; u32 size; + if (nvram_buf[0]) { + pr_warn("nvram already initialized\n"); + return -EEXIST; + } + /* TODO: when nvram is on nand flash check for bad blocks first. */ off = FLASH_MIN; while (off <= lim) { /* Windowed flash access */ - size = find_nvram_size(base + off); + size = find_nvram_size(iobase + off); if (size) { - header = (struct nvram_header *)KSEG1ADDR(base + off - - size); + header = (struct nvram_header *)(iobase + off - size); goto found; } off <<= 1; } /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ - header = (struct nvram_header *) KSEG1ADDR(base + 4096); - if (header->magic == NVRAM_HEADER) { + header = (struct nvram_header *)(iobase + 4096); + if (header->magic == NVRAM_MAGIC) { size = NVRAM_SPACE; goto found; } - header = (struct nvram_header *) KSEG1ADDR(base + 1024); - if (header->magic == NVRAM_HEADER) { + header = (struct nvram_header *)(iobase + 1024); + if (header->magic == NVRAM_MAGIC) { size = NVRAM_SPACE; goto found; } @@ -94,71 +109,73 @@ found: return 0; } -#ifdef CONFIG_BCM47XX_SSB -static int nvram_init_ssb(void) +/* + * On bcm47xx we need access to the NVRAM very early, so we can't use mtd + * subsystem to access flash. We can't even use platform device / driver to + * store memory offset. + * To handle this we provide following symbol. It's supposed to be called as + * soon as we get info about flash device, before any NVRAM entry is needed. + */ +int bcm47xx_nvram_init_from_mem(u32 base, u32 lim) { - struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore; - u32 base; - u32 lim; - - if (mcore->pflash.present) { - base = mcore->pflash.window; - lim = mcore->pflash.window_size; - } else { - pr_err("Couldn't find supported flash memory\n"); - return -ENXIO; - } + void __iomem *iobase; + int err; - return nvram_find_and_copy(base, lim); -} -#endif + iobase = ioremap_nocache(base, lim); + if (!iobase) + return -ENOMEM; -#ifdef CONFIG_BCM47XX_BCMA -static int nvram_init_bcma(void) -{ - struct bcma_drv_cc *cc = &bcm47xx_bus.bcma.bus.drv_cc; - u32 base; - u32 lim; - -#ifdef CONFIG_BCMA_NFLASH - if (cc->nflash.boot) { - base = BCMA_SOC_FLASH1; - lim = BCMA_SOC_FLASH1_SZ; - } else -#endif - if (cc->pflash.present) { - base = cc->pflash.window; - lim = cc->pflash.window_size; -#ifdef CONFIG_BCMA_SFLASH - } else if (cc->sflash.present) { - base = cc->sflash.window; - lim = cc->sflash.size; -#endif - } else { - pr_err("Couldn't find supported flash memory\n"); - return -ENXIO; - } + err = nvram_find_and_copy(iobase, lim); + + iounmap(iobase); - return nvram_find_and_copy(base, lim); + return err; } -#endif static int nvram_init(void) { - switch (bcm47xx_bus_type) { -#ifdef CONFIG_BCM47XX_SSB - case BCM47XX_BUS_TYPE_SSB: - return nvram_init_ssb(); -#endif -#ifdef CONFIG_BCM47XX_BCMA - case BCM47XX_BUS_TYPE_BCMA: - return nvram_init_bcma(); -#endif +#ifdef CONFIG_MTD + struct mtd_info *mtd; + struct nvram_header header; + size_t bytes_read; + int err, i; + + mtd = get_mtd_device_nm("nvram"); + if (IS_ERR(mtd)) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { + loff_t from = mtd->size - nvram_sizes[i]; + + if (from < 0) + continue; + + err = mtd_read(mtd, from, sizeof(header), &bytes_read, + (uint8_t *)&header); + if (!err && header.magic == NVRAM_MAGIC) { + u8 *dst = (uint8_t *)nvram_buf; + size_t len = header.len; + + if (header.len > NVRAM_SPACE) { + pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", + header.len, NVRAM_SPACE); + len = NVRAM_SPACE; + } + + err = mtd_read(mtd, from, len, &bytes_read, dst); + if (err) + return err; + memset(dst + bytes_read, 0x0, NVRAM_SPACE - bytes_read); + + return 0; + } } +#endif + return -ENXIO; } -int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len) +int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len) { char *var, *value, *end, *eq; int err; diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index c00585d..e43b504 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -102,23 +102,6 @@ static void bcm47xx_machine_halt(void) } #ifdef CONFIG_BCM47XX_SSB -static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) -{ - char prefix[10]; - - if (bus->bustype == SSB_BUSTYPE_PCI) { - memset(out, 0, sizeof(struct ssb_sprom)); - snprintf(prefix, sizeof(prefix), "pci/%u/%u/", - bus->host_pci->bus->number + 1, - PCI_SLOT(bus->host_pci->devfn)); - bcm47xx_fill_sprom(out, prefix, false); - return 0; - } else { - printk(KERN_WARNING "bcm47xx: unable to fill SPROM for given bustype.\n"); - return -EINVAL; - } -} - static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) { @@ -144,11 +127,6 @@ static void __init bcm47xx_register_ssb(void) char buf[100]; struct ssb_mipscore *mcore; - err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb); - if (err) - printk(KERN_WARNING "bcm47xx: someone else already registered" - " a ssb SPROM callback handler (err %d)\n", err); - err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE, bcm47xx_get_invariants); if (err) @@ -171,56 +149,21 @@ static void __init bcm47xx_register_ssb(void) #endif #ifdef CONFIG_BCM47XX_BCMA -static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out) -{ - char prefix[10]; - struct bcma_device *core; - - switch (bus->hosttype) { - case BCMA_HOSTTYPE_PCI: - memset(out, 0, sizeof(struct ssb_sprom)); - snprintf(prefix, sizeof(prefix), "pci/%u/%u/", - bus->host_pci->bus->number + 1, - PCI_SLOT(bus->host_pci->devfn)); - bcm47xx_fill_sprom(out, prefix, false); - return 0; - case BCMA_HOSTTYPE_SOC: - memset(out, 0, sizeof(struct ssb_sprom)); - core = bcma_find_core(bus, BCMA_CORE_80211); - if (core) { - snprintf(prefix, sizeof(prefix), "sb/%u/", - core->core_index); - bcm47xx_fill_sprom(out, prefix, true); - } else { - bcm47xx_fill_sprom(out, NULL, false); - } - return 0; - default: - pr_warn("bcm47xx: unable to fill SPROM for given bustype.\n"); - return -EINVAL; - } -} - static void __init bcm47xx_register_bcma(void) { int err; - err = bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma); - if (err) - pr_warn("bcm47xx: someone else already registered a bcma SPROM callback handler (err %d)\n", err); - err = bcma_host_soc_register(&bcm47xx_bus.bcma); if (err) panic("Failed to register BCMA bus (err %d)", err); - - err = bcma_host_soc_init(&bcm47xx_bus.bcma); - if (err) - panic("Failed to initialize BCMA bus (err %d)", err); - - bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL); } #endif +/* + * Memory setup is done in the early part of MIPS's arch_mem_init. It's supposed + * to detect memory and record it with add_memory_region. + * Any extra initializaion performed here must not use kmalloc or bootmem. + */ void __init plat_mem_setup(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -229,6 +172,7 @@ void __init plat_mem_setup(void) printk(KERN_INFO "bcm47xx: 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 @@ -239,6 +183,7 @@ void __init plat_mem_setup(void) printk(KERN_INFO "bcm47xx: using ssb bus\n"); #ifdef CONFIG_BCM47XX_SSB bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB; + bcm47xx_sprom_register_fallbacks(); bcm47xx_register_ssb(); bcm47xx_set_system_type(bcm47xx_bus.ssb.chip_id); #endif @@ -247,6 +192,28 @@ void __init plat_mem_setup(void) _machine_restart = bcm47xx_machine_restart; _machine_halt = bcm47xx_machine_halt; pm_power_off = bcm47xx_machine_halt; +} + +/* + * This finishes bus initialization doing things that were not possible without + * kmalloc. Make sure to call it late enough (after mm_init). + */ +void __init bcm47xx_bus_setup(void) +{ +#ifdef CONFIG_BCM47XX_BCMA + if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA) { + int err; + + err = bcma_host_soc_init(&bcm47xx_bus.bcma); + if (err) + panic("Failed to initialize BCMA bus (err %d)", err); + + bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, + NULL); + } +#endif + + /* With bus initialized we can access NVRAM and detect the board */ bcm47xx_board_detect(); mips_set_machine_name(bcm47xx_board_get_name()); } diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 41226b6..2eff7fe 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -136,6 +136,20 @@ static void nvram_read_leddc(const char *prefix, const char *name, *leddc_off_time = (val >> 16) & 0xff; } +static void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6]) +{ + if (strchr(buf, ':')) + sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], + &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], + &macaddr[5]); + else if (strchr(buf, '-')) + sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0], + &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], + &macaddr[5]); + else + pr_warn("Can not parse mac address: %s\n", buf); +} + static void nvram_read_macaddr(const char *prefix, const char *name, u8 val[6], bool fallback) { @@ -801,3 +815,71 @@ void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo, nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0, true); } #endif + +#if defined(CONFIG_BCM47XX_SSB) +static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) +{ + char prefix[10]; + + if (bus->bustype == SSB_BUSTYPE_PCI) { + memset(out, 0, sizeof(struct ssb_sprom)); + snprintf(prefix, sizeof(prefix), "pci/%u/%u/", + bus->host_pci->bus->number + 1, + PCI_SLOT(bus->host_pci->devfn)); + bcm47xx_fill_sprom(out, prefix, false); + return 0; + } else { + pr_warn("bcm47xx: unable to fill SPROM for given bustype.\n"); + return -EINVAL; + } +} +#endif + +#if defined(CONFIG_BCM47XX_BCMA) +static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out) +{ + char prefix[10]; + struct bcma_device *core; + + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: + memset(out, 0, sizeof(struct ssb_sprom)); + snprintf(prefix, sizeof(prefix), "pci/%u/%u/", + bus->host_pci->bus->number + 1, + PCI_SLOT(bus->host_pci->devfn)); + bcm47xx_fill_sprom(out, prefix, false); + return 0; + case BCMA_HOSTTYPE_SOC: + memset(out, 0, sizeof(struct ssb_sprom)); + core = bcma_find_core(bus, BCMA_CORE_80211); + if (core) { + snprintf(prefix, sizeof(prefix), "sb/%u/", + core->core_index); + bcm47xx_fill_sprom(out, prefix, true); + } else { + bcm47xx_fill_sprom(out, NULL, false); + } + return 0; + default: + pr_warn("bcm47xx: unable to fill SPROM for given bustype.\n"); + return -EINVAL; + } +} +#endif + +/* + * 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) +{ +#if defined(CONFIG_BCM47XX_SSB) + if (ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb)) + pr_warn("Failed to registered ssb SPROM handler\n"); +#endif + +#if defined(CONFIG_BCM47XX_BCMA) + if (bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma)) + pr_warn("Failed to registered bcma SPROM handler\n"); +#endif +} diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c index 536f644..307ec8b 100644 --- a/arch/mips/bcm63xx/cpu.c +++ b/arch/mips/bcm63xx/cpu.c @@ -263,7 +263,7 @@ static unsigned int detect_memory_size(void) if (BCMCPU_IS_6345()) { val = bcm_sdram_readl(SDRAM_MBASE_REG); - return (val * 8 * 1024 * 1024); + return val * 8 * 1024 * 1024; } if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) { diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile index ca9c90e..4f49fa4 100644 --- a/arch/mips/boot/dts/Makefile +++ b/arch/mips/boot/dts/Makefile @@ -1,3 +1,4 @@ +dtb-$(CONFIG_BCM3384) += bcm93384wvg.dtb dtb-$(CONFIG_CAVIUM_OCTEON_SOC) += octeon_3xxx.dtb octeon_68xx.dtb dtb-$(CONFIG_DT_EASY50712) += easy50712.dtb dtb-$(CONFIG_DT_XLP_EVP) += xlp_evp.dtb diff --git a/arch/mips/boot/dts/bcm3384.dtsi b/arch/mips/boot/dts/bcm3384.dtsi new file mode 100644 index 0000000..21b074a --- /dev/null +++ b/arch/mips/boot/dts/bcm3384.dtsi @@ -0,0 +1,109 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "brcm,bcm3384", "brcm,bcm33843"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + /* On BMIPS5000 this is 1/8th of the CPU core clock */ + mips-hpt-frequency = <100000000>; + + cpu@0 { + compatible = "brcm,bmips5000"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "brcm,bmips5000"; + device_type = "cpu"; + reg = <1>; + }; + }; + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + periph_clk: periph_clk@0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <54000000>; + }; + }; + + aliases { + uart0 = &uart0; + }; + + cpu_intc: cpu_intc@0 { + #address-cells = <0>; + compatible = "mti,cpu-interrupt-controller"; + + interrupt-controller; + #interrupt-cells = <1>; + }; + + periph_intc: periph_intc@14e00038 { + compatible = "brcm,bcm3384-intc"; + reg = <0x14e00038 0x8 0x14e00340 0x8>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <4>; + }; + + zmips_intc: zmips_intc@104b0060 { + compatible = "brcm,bcm3384-intc"; + reg = <0x104b0060 0x8>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&periph_intc>; + interrupts = <29>; + }; + + iop_intc: iop_intc@14e00058 { + compatible = "brcm,bcm3384-intc"; + reg = <0x14e00058 0x8>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <6>; + }; + + uart0: serial@14e00520 { + compatible = "brcm,bcm6345-uart"; + reg = <0x14e00520 0x18>; + interrupt-parent = <&periph_intc>; + interrupts = <2>; + clocks = <&periph_clk>; + status = "disabled"; + }; + + ehci0: usb@15400300 { + compatible = "brcm,bcm3384-ehci", "generic-ehci"; + reg = <0x15400300 0x100>; + big-endian; + interrupt-parent = <&periph_intc>; + interrupts = <41>; + status = "disabled"; + }; + + ohci0: usb@15400400 { + compatible = "brcm,bcm3384-ohci", "generic-ohci"; + reg = <0x15400400 0x100>; + big-endian; + no-big-frame-no; + interrupt-parent = <&periph_intc>; + interrupts = <40>; + status = "disabled"; + }; +}; diff --git a/arch/mips/boot/dts/bcm93384wvg.dts b/arch/mips/boot/dts/bcm93384wvg.dts new file mode 100644 index 0000000..8317411 --- /dev/null +++ b/arch/mips/boot/dts/bcm93384wvg.dts @@ -0,0 +1,32 @@ +/dts-v1/; + +/include/ "bcm3384.dtsi" + +/ { + compatible = "brcm,bcm93384wvg", "brcm,bcm3384"; + model = "Broadcom BCM93384WVG"; + + chosen { + bootargs = "console=ttyS0,115200"; + stdout-path = &uart0; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x04000000>; + dma-xor-mask = <0x08000000>; + dma-xor-limit = <0x0fffffff>; + }; +}; + +&uart0 { + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c index 02f2444..3778655 100644 --- a/arch/mips/cavium-octeon/dma-octeon.c +++ b/arch/mips/cavium-octeon/dma-octeon.c @@ -262,8 +262,8 @@ char *octeon_swiotlb; void __init plat_swiotlb_setup(void) { int i; - phys_t max_addr; - phys_t addr_size; + phys_addr_t max_addr; + phys_addr_t addr_size; size_t swiotlbsize; unsigned long swiotlb_nslabs; diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c index f4c1b36..e15b049 100644 --- a/arch/mips/cavium-octeon/executive/octeon-model.c +++ b/arch/mips/cavium-octeon/executive/octeon-model.c @@ -28,22 +28,23 @@ #include <asm/octeon/octeon.h> /** - * Given the chip processor ID from COP0, this function returns a - * string representing the chip model number. The string is of the - * form CNXXXXpX.X-FREQ-SUFFIX. - * - XXXX = The chip model number - * - X.X = Chip pass number - * - FREQ = Current frequency in Mhz - * - SUFFIX = NSP, EXP, SCP, SSP, or CP - * - * @chip_id: Chip ID + * Read a byte of fuse data + * @byte_addr: address to read * - * Returns Model string + * Returns fuse value: 0 or 1 */ -const char *octeon_model_get_string(uint32_t chip_id) +static uint8_t __init cvmx_fuse_read_byte(int byte_addr) { - static char buffer[32]; - return octeon_model_get_string_buffer(chip_id, buffer); + union cvmx_mio_fus_rcmd read_cmd; + + read_cmd.u64 = 0; + read_cmd.s.addr = byte_addr; + read_cmd.s.pend = 1; + cvmx_write_csr(CVMX_MIO_FUS_RCMD, read_cmd.u64); + while ((read_cmd.u64 = cvmx_read_csr(CVMX_MIO_FUS_RCMD)) + && read_cmd.s.pend) + ; + return read_cmd.s.dat; } /* @@ -51,7 +52,8 @@ const char *octeon_model_get_string(uint32_t chip_id) * as running early in u-boot static/global variables don't work when * running from flash. */ -const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) +static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, + char *buffer) { const char *family; const char *core_model; @@ -407,3 +409,22 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) sprintf(buffer, "CN%s%sp%s-%d-%s", family, core_model, pass, clock_mhz, suffix); return buffer; } + +/** + * Given the chip processor ID from COP0, this function returns a + * string representing the chip model number. The string is of the + * form CNXXXXpX.X-FREQ-SUFFIX. + * - XXXX = The chip model number + * - X.X = Chip pass number + * - FREQ = Current frequency in Mhz + * - SUFFIX = NSP, EXP, SCP, SSP, or CP + * + * @chip_id: Chip ID + * + * Returns Model string + */ +const char *__init octeon_model_get_string(uint32_t chip_id) +{ + static char buffer[32]; + return octeon_model_get_string_buffer(chip_id, buffer); +} diff --git a/arch/mips/configs/bcm3384_defconfig b/arch/mips/configs/bcm3384_defconfig new file mode 100644 index 0000000..88711c2 --- /dev/null +++ b/arch/mips/configs/bcm3384_defconfig @@ -0,0 +1,78 @@ +CONFIG_BCM3384=y +CONFIG_HIGHMEM=y +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +# CONFIG_SECCOMP is not set +CONFIG_MIPS_O32_FP64_SUPPORT=y +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +CONFIG_NO_HZ=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_GZIP is not set +CONFIG_EXPERT=y +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_SLUB_DEBUG is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +CONFIG_MAC80211=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_MTD=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP=y +# CONFIG_BLK_DEV is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_NETDEVICES=y +CONFIG_USB_USBNET=y +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_EARLYCON_FORCE=y +CONFIG_SERIAL_BCM63XX=y +CONFIG_SERIAL_BCM63XX_CONSOLE=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_CIFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_CRYPTO_HW is not set diff --git a/arch/mips/fw/lib/cmdline.c b/arch/mips/fw/lib/cmdline.c index ffd0345..6ecda64 100644 --- a/arch/mips/fw/lib/cmdline.c +++ b/arch/mips/fw/lib/cmdline.c @@ -68,7 +68,7 @@ char *fw_getenv(char *envname) result = fw_envp(index + 1); break; } else if (fw_envp(index)[i] == '=') { - result = (fw_envp(index + 1) + i); + result = fw_envp(index) + i + 1; break; } } @@ -88,13 +88,13 @@ unsigned long fw_getenvl(char *envname) { unsigned long envl = 0UL; char *str; - long val; int tmp; str = fw_getenv(envname); if (str) { - tmp = kstrtol(str, 0, &val); - envl = (unsigned long)val; + tmp = kstrtoul(str, 0, &envl); + if (tmp) + envl = 0; } return envl; diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 6dd6bfc..857da84 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -17,6 +17,7 @@ #include <linux/irqflags.h> #include <linux/types.h> #include <asm/barrier.h> +#include <asm/compiler.h> #include <asm/cpu-features.h> #include <asm/cmpxchg.h> #include <asm/war.h> @@ -40,95 +41,97 @@ */ #define atomic_set(v, i) ((v)->counter = (i)) -#define ATOMIC_OP(op, c_op, asm_op) \ -static __inline__ void atomic_##op(int i, atomic_t * v) \ -{ \ - if (kernel_uses_llsc && R10000_LLSC_WAR) { \ - int temp; \ - \ - __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - "1: ll %0, %1 # atomic_" #op " \n" \ - " " #asm_op " %0, %2 \n" \ - " sc %0, %1 \n" \ - " beqzl %0, 1b \n" \ - " .set mips0 \n" \ - : "=&r" (temp), "+m" (v->counter) \ - : "Ir" (i)); \ - } else if (kernel_uses_llsc) { \ - int temp; \ - \ - do { \ - __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - " ll %0, %1 # atomic_" #op "\n" \ - " " #asm_op " %0, %2 \n" \ - " sc %0, %1 \n" \ - " .set mips0 \n" \ - : "=&r" (temp), "+m" (v->counter) \ - : "Ir" (i)); \ - } while (unlikely(!temp)); \ - } else { \ - unsigned long flags; \ - \ - raw_local_irq_save(flags); \ - v->counter c_op i; \ - raw_local_irq_restore(flags); \ - } \ -} \ - -#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ -static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ -{ \ - int result; \ - \ - smp_mb__before_llsc(); \ - \ - if (kernel_uses_llsc && R10000_LLSC_WAR) { \ - int temp; \ - \ - __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - "1: ll %1, %2 # atomic_" #op "_return \n" \ - " " #asm_op " %0, %1, %3 \n" \ - " sc %0, %2 \n" \ - " beqzl %0, 1b \n" \ - " " #asm_op " %0, %1, %3 \n" \ - " .set mips0 \n" \ - : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ - : "Ir" (i)); \ - } else if (kernel_uses_llsc) { \ - int temp; \ - \ - do { \ - __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - " ll %1, %2 # atomic_" #op "_return \n" \ - " " #asm_op " %0, %1, %3 \n" \ - " sc %0, %2 \n" \ - " .set mips0 \n" \ - : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ - : "Ir" (i)); \ - } while (unlikely(!result)); \ - \ - result = temp; result c_op i; \ - } else { \ - unsigned long flags; \ - \ - raw_local_irq_save(flags); \ - result = v->counter; \ - result c_op i; \ - v->counter = result; \ - raw_local_irq_restore(flags); \ - } \ - \ - smp_llsc_mb(); \ - \ - return result; \ +#define ATOMIC_OP(op, c_op, asm_op) \ +static __inline__ void atomic_##op(int i, atomic_t * v) \ +{ \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + int temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: ll %0, %1 # atomic_" #op " \n" \ + " " #asm_op " %0, %2 \n" \ + " sc %0, %1 \n" \ + " beqzl %0, 1b \n" \ + " .set mips0 \n" \ + : "=&r" (temp), "+" GCC_OFF12_ASM() (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + int temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + " ll %0, %1 # atomic_" #op "\n" \ + " " #asm_op " %0, %2 \n" \ + " sc %0, %1 \n" \ + " .set mips0 \n" \ + : "=&r" (temp), "+" GCC_OFF12_ASM() (v->counter) \ + : "Ir" (i)); \ + } while (unlikely(!temp)); \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ + } \ } -#define ATOMIC_OPS(op, c_op, asm_op) \ - ATOMIC_OP(op, c_op, asm_op) \ +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ +static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ +{ \ + int result; \ + \ + smp_mb__before_llsc(); \ + \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + int temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: ll %1, %2 # atomic_" #op "_return \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " sc %0, %2 \n" \ + " beqzl %0, 1b \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "+" GCC_OFF12_ASM() (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + int temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + " ll %1, %2 # atomic_" #op "_return \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " sc %0, %2 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "+" GCC_OFF12_ASM() (v->counter) \ + : "Ir" (i)); \ + } while (unlikely(!result)); \ + \ + result = temp; result c_op i; \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + result = v->counter; \ + result c_op i; \ + v->counter = result; \ + raw_local_irq_restore(flags); \ + } \ + \ + smp_llsc_mb(); \ + \ + return result; \ +} + +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ ATOMIC_OP_RETURN(op, c_op, asm_op) ATOMIC_OPS(add, +=, addu) @@ -167,8 +170,9 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) " .set reorder \n" "1: \n" " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "+m" (v->counter) - : "Ir" (i), "m" (v->counter) + : "=&r" (result), "=&r" (temp), + "+" GCC_OFF12_ASM() (v->counter) + : "Ir" (i), GCC_OFF12_ASM() (v->counter) : "memory"); } else if (kernel_uses_llsc) { int temp; @@ -185,7 +189,8 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) " .set reorder \n" "1: \n" " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "+m" (v->counter) + : "=&r" (result), "=&r" (temp), + "+" GCC_OFF12_ASM() (v->counter) : "Ir" (i)); } else { unsigned long flags; @@ -315,96 +320,98 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) */ #define atomic64_set(v, i) ((v)->counter = (i)) -#define ATOMIC64_OP(op, c_op, asm_op) \ -static __inline__ void atomic64_##op(long i, atomic64_t * v) \ -{ \ - if (kernel_uses_llsc && R10000_LLSC_WAR) { \ - long temp; \ - \ - __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - "1: lld %0, %1 # atomic64_" #op " \n" \ - " " #asm_op " %0, %2 \n" \ - " scd %0, %1 \n" \ - " beqzl %0, 1b \n" \ - " .set mips0 \n" \ - : "=&r" (temp), "+m" (v->counter) \ - : "Ir" (i)); \ - } else if (kernel_uses_llsc) { \ - long temp; \ - \ - do { \ - __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - " lld %0, %1 # atomic64_" #op "\n" \ - " " #asm_op " %0, %2 \n" \ - " scd %0, %1 \n" \ - " .set mips0 \n" \ - : "=&r" (temp), "+m" (v->counter) \ - : "Ir" (i)); \ - } while (unlikely(!temp)); \ - } else { \ - unsigned long flags; \ - \ - raw_local_irq_save(flags); \ - v->counter c_op i; \ - raw_local_irq_restore(flags); \ - } \ -} \ - -#define ATOMIC64_OP_RETURN(op, c_op, asm_op) \ -static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ -{ \ - long result; \ - \ - smp_mb__before_llsc(); \ - \ - if (kernel_uses_llsc && R10000_LLSC_WAR) { \ - long temp; \ - \ - __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - "1: lld %1, %2 # atomic64_" #op "_return\n" \ - " " #asm_op " %0, %1, %3 \n" \ - " scd %0, %2 \n" \ - " beqzl %0, 1b \n" \ - " " #asm_op " %0, %1, %3 \n" \ - " .set mips0 \n" \ - : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ - : "Ir" (i)); \ - } else if (kernel_uses_llsc) { \ - long temp; \ - \ - do { \ - __asm__ __volatile__( \ - " .set arch=r4000 \n" \ - " lld %1, %2 # atomic64_" #op "_return\n" \ - " " #asm_op " %0, %1, %3 \n" \ - " scd %0, %2 \n" \ - " .set mips0 \n" \ - : "=&r" (result), "=&r" (temp), "=m" (v->counter) \ - : "Ir" (i), "m" (v->counter) \ - : "memory"); \ - } while (unlikely(!result)); \ - \ - result = temp; result c_op i; \ - } else { \ - unsigned long flags; \ - \ - raw_local_irq_save(flags); \ - result = v->counter; \ - result c_op i; \ - v->counter = result; \ - raw_local_irq_restore(flags); \ - } \ - \ - smp_llsc_mb(); \ - \ - return result; \ +#define ATOMIC64_OP(op, c_op, asm_op) \ +static __inline__ void atomic64_##op(long i, atomic64_t * v) \ +{ \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + long temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: lld %0, %1 # atomic64_" #op " \n" \ + " " #asm_op " %0, %2 \n" \ + " scd %0, %1 \n" \ + " beqzl %0, 1b \n" \ + " .set mips0 \n" \ + : "=&r" (temp), "+" GCC_OFF12_ASM() (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + long temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + " lld %0, %1 # atomic64_" #op "\n" \ + " " #asm_op " %0, %2 \n" \ + " scd %0, %1 \n" \ + " .set mips0 \n" \ + : "=&r" (temp), "+" GCC_OFF12_ASM() (v->counter) \ + : "Ir" (i)); \ + } while (unlikely(!temp)); \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ + } \ +} + +#define ATOMIC64_OP_RETURN(op, c_op, asm_op) \ +static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ +{ \ + long result; \ + \ + smp_mb__before_llsc(); \ + \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + long temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: lld %1, %2 # atomic64_" #op "_return\n" \ + " " #asm_op " %0, %1, %3 \n" \ + " scd %0, %2 \n" \ + " beqzl %0, 1b \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "+" GCC_OFF12_ASM() (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + long temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + " lld %1, %2 # atomic64_" #op "_return\n" \ + " " #asm_op " %0, %1, %3 \n" \ + " scd %0, %2 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "=" GCC_OFF12_ASM() (v->counter) \ + : "Ir" (i), GCC_OFF12_ASM() (v->counter) \ + : "memory"); \ + } while (unlikely(!result)); \ + \ + result = temp; result c_op i; \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + result = v->counter; \ + result c_op i; \ + v->counter = result; \ + raw_local_irq_restore(flags); \ + } \ + \ + smp_llsc_mb(); \ + \ + return result; \ } -#define ATOMIC64_OPS(op, c_op, asm_op) \ - ATOMIC64_OP(op, c_op, asm_op) \ +#define ATOMIC64_OPS(op, c_op, asm_op) \ + ATOMIC64_OP(op, c_op, asm_op) \ ATOMIC64_OP_RETURN(op, c_op, asm_op) ATOMIC64_OPS(add, +=, daddu) @@ -415,7 +422,8 @@ ATOMIC64_OPS(sub, -=, dsubu) #undef ATOMIC64_OP /* - * atomic64_sub_if_positive - conditionally subtract integer from atomic variable + * atomic64_sub_if_positive - conditionally subtract integer from atomic + * variable * @i: integer value to subtract * @v: pointer of type atomic64_t * @@ -443,8 +451,9 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) " .set reorder \n" "1: \n" " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter) + : "=&r" (result), "=&r" (temp), + "=" GCC_OFF12_ASM() (v->counter) + : "Ir" (i), GCC_OFF12_ASM() (v->counter) : "memory"); } else if (kernel_uses_llsc) { long temp; @@ -461,7 +470,8 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) " .set reorder \n" "1: \n" " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "+m" (v->counter) + : "=&r" (result), "=&r" (temp), + "+" GCC_OFF12_ASM() (v->counter) : "Ir" (i)); } else { unsigned long flags; diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h index bae6b0f..6663bcc 100644 --- a/arch/mips/include/asm/bitops.h +++ b/arch/mips/include/asm/bitops.h @@ -17,6 +17,7 @@ #include <linux/types.h> #include <asm/barrier.h> #include <asm/byteorder.h> /* sigh ... */ +#include <asm/compiler.h> #include <asm/cpu-features.h> #include <asm/sgidefs.h> #include <asm/war.h> @@ -78,8 +79,8 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) " " __SC "%0, %1 \n" " beqzl %0, 1b \n" " .set mips0 \n" - : "=&r" (temp), "=m" (*m) - : "ir" (1UL << bit), "m" (*m)); + : "=&r" (temp), "=" GCC_OFF12_ASM() (*m) + : "ir" (1UL << bit), GCC_OFF12_ASM() (*m)); #ifdef CONFIG_CPU_MIPSR2 } else if (kernel_uses_llsc && __builtin_constant_p(bit)) { do { @@ -87,7 +88,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) " " __LL "%0, %1 # set_bit \n" " " __INS "%0, %3, %2, 1 \n" " " __SC "%0, %1 \n" - : "=&r" (temp), "+m" (*m) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m) : "ir" (bit), "r" (~0)); } while (unlikely(!temp)); #endif /* CONFIG_CPU_MIPSR2 */ @@ -99,7 +100,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) " or %0, %2 \n" " " __SC "%0, %1 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m) : "ir" (1UL << bit)); } while (unlikely(!temp)); } else @@ -130,7 +131,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) " " __SC "%0, %1 \n" " beqzl %0, 1b \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m) : "ir" (~(1UL << bit))); #ifdef CONFIG_CPU_MIPSR2 } else if (kernel_uses_llsc && __builtin_constant_p(bit)) { @@ -139,7 +140,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) " " __LL "%0, %1 # clear_bit \n" " " __INS "%0, $0, %2, 1 \n" " " __SC "%0, %1 \n" - : "=&r" (temp), "+m" (*m) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m) : "ir" (bit)); } while (unlikely(!temp)); #endif /* CONFIG_CPU_MIPSR2 */ @@ -151,7 +152,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) " and %0, %2 \n" " " __SC "%0, %1 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m) : "ir" (~(1UL << bit))); } while (unlikely(!temp)); } else @@ -196,7 +197,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) " " __SC "%0, %1 \n" " beqzl %0, 1b \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m) : "ir" (1UL << bit)); } else if (kernel_uses_llsc) { unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG); @@ -209,7 +210,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) " xor %0, %2 \n" " " __SC "%0, %1 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m) : "ir" (1UL << bit)); } while (unlikely(!temp)); } else @@ -244,7 +245,7 @@ static inline int test_and_set_bit(unsigned long nr, " beqzl %2, 1b \n" " and %2, %0, %3 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m), "=&r" (res) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res) : "r" (1UL << bit) : "memory"); } else if (kernel_uses_llsc) { @@ -258,7 +259,7 @@ static inline int test_and_set_bit(unsigned long nr, " or %2, %0, %3 \n" " " __SC "%2, %1 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m), "=&r" (res) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res) : "r" (1UL << bit) : "memory"); } while (unlikely(!res)); @@ -312,7 +313,7 @@ static inline int test_and_set_bit_lock(unsigned long nr, " or %2, %0, %3 \n" " " __SC "%2, %1 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m), "=&r" (res) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res) : "r" (1UL << bit) : "memory"); } while (unlikely(!res)); @@ -354,7 +355,7 @@ static inline int test_and_clear_bit(unsigned long nr, " beqzl %2, 1b \n" " and %2, %0, %3 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m), "=&r" (res) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res) : "r" (1UL << bit) : "memory"); #ifdef CONFIG_CPU_MIPSR2 @@ -368,7 +369,7 @@ static inline int test_and_clear_bit(unsigned long nr, " " __EXT "%2, %0, %3, 1 \n" " " __INS "%0, $0, %3, 1 \n" " " __SC "%0, %1 \n" - : "=&r" (temp), "+m" (*m), "=&r" (res) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res) : "ir" (bit) : "memory"); } while (unlikely(!temp)); @@ -385,7 +386,7 @@ static inline int test_and_clear_bit(unsigned long nr, " xor %2, %3 \n" " " __SC "%2, %1 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m), "=&r" (res) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res) : "r" (1UL << bit) : "memory"); } while (unlikely(!res)); @@ -427,7 +428,7 @@ static inline int test_and_change_bit(unsigned long nr, " beqzl %2, 1b \n" " and %2, %0, %3 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m), "=&r" (res) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res) : "r" (1UL << bit) : "memory"); } else if (kernel_uses_llsc) { @@ -441,7 +442,7 @@ static inline int test_and_change_bit(unsigned long nr, " xor %2, %0, %3 \n" " " __SC "\t%2, %1 \n" " .set mips0 \n" - : "=&r" (temp), "+m" (*m), "=&r" (res) + : "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res) : "r" (1UL << bit) : "memory"); } while (unlikely(!res)); diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h index cbacceb..30939b0 100644 --- a/arch/mips/include/asm/bmips.h +++ b/arch/mips/include/asm/bmips.h @@ -84,6 +84,7 @@ extern char bmips_smp_int_vec_end; extern int bmips_smp_enabled; extern int bmips_cpu_offset; extern cpumask_t bmips_booted_mask; +extern unsigned long bmips_tp1_irqs; extern void bmips_ebase_setup(void); extern asmlinkage void plat_wired_tlb_setup(void); diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index 1f7ca8b..b603804 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -70,10 +70,7 @@ enum loongson_machine_type { MACH_DEXXON_GDIUM2F10, MACH_LEMOTE_NAS, MACH_LEMOTE_LL2F, - MACH_LEMOTE_A1004, - MACH_LEMOTE_A1101, - MACH_LEMOTE_A1201, - MACH_LEMOTE_A1205, + MACH_LOONGSON_GENERIC, MACH_LOONGSON_END }; @@ -101,16 +98,16 @@ extern unsigned long mips_machtype; struct boot_mem_map { int nr_map; struct boot_mem_map_entry { - phys_t addr; /* start of memory segment */ - phys_t size; /* size of memory segment */ + phys_addr_t addr; /* start of memory segment */ + phys_addr_t size; /* size of memory segment */ long type; /* type of memory segment */ } map[BOOT_MEM_MAP_MAX]; }; extern struct boot_mem_map boot_mem_map; -extern void add_memory_region(phys_t start, phys_t size, long type); -extern void detect_memory_region(phys_t start, phys_t sz_min, phys_t sz_max); +extern void add_memory_region(phys_addr_t start, phys_addr_t size, long type); +extern void detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max); extern void prom_init(void); extern void prom_free_prom_memory(void); diff --git a/arch/mips/include/asm/clock.h b/arch/mips/include/asm/clock.h index 778e32d..4809c29 100644 --- a/arch/mips/include/asm/clock.h +++ b/arch/mips/include/asm/clock.h @@ -35,9 +35,6 @@ struct clk { #define CLK_ALWAYS_ENABLED (1 << 0) #define CLK_RATE_PROPAGATES (1 << 1) -/* Should be defined by processor-specific code */ -void arch_init_clk_ops(struct clk_ops **, int type); - int clk_init(void); int __clk_enable(struct clk *); diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h index eefcaa3..28b1edf 100644 --- a/arch/mips/include/asm/cmpxchg.h +++ b/arch/mips/include/asm/cmpxchg.h @@ -10,6 +10,7 @@ #include <linux/bug.h> #include <linux/irqflags.h> +#include <asm/compiler.h> #include <asm/war.h> static inline unsigned long __xchg_u32(volatile int * m, unsigned int val) @@ -30,8 +31,8 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val) " sc %2, %1 \n" " beqzl %2, 1b \n" " .set mips0 \n" - : "=&r" (retval), "=m" (*m), "=&r" (dummy) - : "R" (*m), "Jr" (val) + : "=&r" (retval), "=" GCC_OFF12_ASM() (*m), "=&r" (dummy) + : GCC_OFF12_ASM() (*m), "Jr" (val) : "memory"); } else if (kernel_uses_llsc) { unsigned long dummy; @@ -45,8 +46,9 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val) " .set arch=r4000 \n" " sc %2, %1 \n" " .set mips0 \n" - : "=&r" (retval), "=m" (*m), "=&r" (dummy) - : "R" (*m), "Jr" (val) + : "=&r" (retval), "=" GCC_OFF12_ASM() (*m), + "=&r" (dummy) + : GCC_OFF12_ASM() (*m), "Jr" (val) : "memory"); } while (unlikely(!dummy)); } else { @@ -80,8 +82,8 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val) " scd %2, %1 \n" " beqzl %2, 1b \n" " .set mips0 \n" - : "=&r" (retval), "=m" (*m), "=&r" (dummy) - : "R" (*m), "Jr" (val) + : "=&r" (retval), "=" GCC_OFF12_ASM() (*m), "=&r" (dummy) + : GCC_OFF12_ASM() (*m), "Jr" (val) : "memory"); } else if (kernel_uses_llsc) { unsigned long dummy; @@ -93,8 +95,9 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val) " move %2, %z4 \n" " scd %2, %1 \n" " .set mips0 \n" - : "=&r" (retval), "=m" (*m), "=&r" (dummy) - : "R" (*m), "Jr" (val) + : "=&r" (retval), "=" GCC_OFF12_ASM() (*m), + "=&r" (dummy) + : GCC_OFF12_ASM() (*m), "Jr" (val) : "memory"); } while (unlikely(!dummy)); } else { @@ -155,8 +158,8 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz " beqzl $1, 1b \n" \ "2: \n" \ " .set pop \n" \ - : "=&r" (__ret), "=R" (*m) \ - : "R" (*m), "Jr" (old), "Jr" (new) \ + : "=&r" (__ret), "=" GCC_OFF12_ASM() (*m) \ + : GCC_OFF12_ASM() (*m), "Jr" (old), "Jr" (new) \ : "memory"); \ } else if (kernel_uses_llsc) { \ __asm__ __volatile__( \ @@ -172,8 +175,8 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz " beqz $1, 1b \n" \ " .set pop \n" \ "2: \n" \ - : "=&r" (__ret), "=R" (*m) \ - : "R" (*m), "Jr" (old), "Jr" (new) \ + : "=&r" (__ret), "=" GCC_OFF12_ASM() (*m) \ + : GCC_OFF12_ASM() (*m), "Jr" (old), "Jr" (new) \ : "memory"); \ } else { \ unsigned long __flags; \ diff --git a/arch/mips/include/asm/compiler.h b/arch/mips/include/asm/compiler.h index 71f5c5c..c73815e 100644 --- a/arch/mips/include/asm/compiler.h +++ b/arch/mips/include/asm/compiler.h @@ -16,4 +16,12 @@ #define GCC_REG_ACCUM "accum" #endif +#ifndef CONFIG_CPU_MICROMIPS +#define GCC_OFF12_ASM() "R" +#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) +#define GCC_OFF12_ASM() "ZC" +#else +#error "microMIPS compilation unsupported with GCC older than 4.9" +#endif + #endif /* _ASM_COMPILER_H */ diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index 3325f3e..2897cfa 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -344,4 +344,8 @@ # define cpu_has_msa 0 #endif +#ifndef cpu_has_fre +# define cpu_has_fre (cpu_data[0].options & MIPS_CPU_FRE) +#endif + #endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index dfdc77e..33866fc 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -142,6 +142,7 @@ #define PRID_IMP_BMIPS3300_BUG 0x0000 #define PRID_IMP_BMIPS43XX 0xa000 #define PRID_IMP_BMIPS5000 0x5a00 +#define PRID_IMP_BMIPS5200 0x5b00 #define PRID_REV_BMIPS4380_LO 0x0040 #define PRID_REV_BMIPS4380_HI 0x006f @@ -368,6 +369,7 @@ enum cpu_type_enum { #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 */ /* * CPU ASE encodings diff --git a/arch/mips/include/asm/edac.h b/arch/mips/include/asm/edac.h index 4da0c1f..ae6fedc 100644 --- a/arch/mips/include/asm/edac.h +++ b/arch/mips/include/asm/edac.h @@ -1,6 +1,8 @@ #ifndef ASM_EDAC_H #define ASM_EDAC_H +#include <asm/compiler.h> + /* ECC atomic, DMA, SMP and interrupt safe scrub function */ static inline void atomic_scrub(void *va, u32 size) @@ -24,8 +26,8 @@ static inline void atomic_scrub(void *va, u32 size) " sc %0, %1 \n" " beqz %0, 1b \n" " .set mips0 \n" - : "=&r" (temp), "=m" (*virt_addr) - : "m" (*virt_addr)); + : "=&r" (temp), "=" GCC_OFF12_ASM() (*virt_addr) + : GCC_OFF12_ASM() (*virt_addr)); virt_addr++; } diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 1d38fe0..eb4d95d 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -8,6 +8,8 @@ #ifndef _ASM_ELF_H #define _ASM_ELF_H +#include <linux/fs.h> +#include <uapi/linux/elf.h> /* ELF header e_flags defines. */ /* MIPS architecture level. */ @@ -28,6 +30,7 @@ #define PT_MIPS_REGINFO 0x70000000 #define PT_MIPS_RTPROC 0x70000001 #define PT_MIPS_OPTIONS 0x70000002 +#define PT_MIPS_ABIFLAGS 0x70000003 /* Flags in the e_flags field of the header */ #define EF_MIPS_NOREORDER 0x00000001 @@ -174,6 +177,30 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; +struct mips_elf_abiflags_v0 { + uint16_t version; /* Version of flags structure */ + uint8_t isa_level; /* The level of the ISA: 1-5, 32, 64 */ + uint8_t isa_rev; /* The revision of ISA: 0 for MIPS V and below, + 1-n otherwise */ + uint8_t gpr_size; /* The size of general purpose registers */ + uint8_t cpr1_size; /* The size of co-processor 1 registers */ + uint8_t cpr2_size; /* The size of co-processor 2 registers */ + uint8_t fp_abi; /* The floating-point ABI */ + uint32_t isa_ext; /* Mask of processor-specific extensions */ + uint32_t ases; /* Mask of ASEs used */ + uint32_t flags1; /* Mask of general flags */ + 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 */ + #ifdef CONFIG_32BIT /* @@ -262,16 +289,13 @@ extern struct mips_abi mips_abi_n32; #ifdef CONFIG_32BIT -#define SET_PERSONALITY(ex) \ +#define SET_PERSONALITY2(ex, state) \ do { \ - if ((ex).e_flags & EF_MIPS_FP64) \ - clear_thread_flag(TIF_32BIT_FPREGS); \ - else \ - set_thread_flag(TIF_32BIT_FPREGS); \ - \ if (personality(current->personality) != PER_LINUX) \ set_personality(PER_LINUX); \ \ + mips_set_personality_fp(state); \ + \ current->thread.abi = &mips_abi; \ } while (0) @@ -291,44 +315,44 @@ do { \ #endif #ifdef CONFIG_MIPS32_O32 -#define __SET_PERSONALITY32_O32(ex) \ +#define __SET_PERSONALITY32_O32(ex, state) \ do { \ set_thread_flag(TIF_32BIT_REGS); \ set_thread_flag(TIF_32BIT_ADDR); \ \ - if (!((ex).e_flags & EF_MIPS_FP64)) \ - set_thread_flag(TIF_32BIT_FPREGS); \ + mips_set_personality_fp(state); \ \ current->thread.abi = &mips_abi_32; \ } while (0) #else -#define __SET_PERSONALITY32_O32(ex) \ +#define __SET_PERSONALITY32_O32(ex, state) \ do { } while (0) #endif #ifdef CONFIG_MIPS32_COMPAT -#define __SET_PERSONALITY32(ex) \ +#define __SET_PERSONALITY32(ex, state) \ do { \ if ((((ex).e_flags & EF_MIPS_ABI2) != 0) && \ ((ex).e_flags & EF_MIPS_ABI) == 0) \ __SET_PERSONALITY32_N32(); \ else \ - __SET_PERSONALITY32_O32(ex); \ + __SET_PERSONALITY32_O32(ex, state); \ } while (0) #else -#define __SET_PERSONALITY32(ex) do { } while (0) +#define __SET_PERSONALITY32(ex, state) do { } while (0) #endif -#define SET_PERSONALITY(ex) \ +#define SET_PERSONALITY2(ex, state) \ do { \ unsigned int p; \ \ clear_thread_flag(TIF_32BIT_REGS); \ clear_thread_flag(TIF_32BIT_FPREGS); \ + clear_thread_flag(TIF_HYBRID_FPREGS); \ clear_thread_flag(TIF_32BIT_ADDR); \ \ if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ - __SET_PERSONALITY32(ex); \ + __SET_PERSONALITY32(ex, state); \ else \ current->thread.abi = &mips_abi; \ \ @@ -390,4 +414,24 @@ struct mm_struct; extern unsigned long arch_randomize_brk(struct mm_struct *mm); #define arch_randomize_brk arch_randomize_brk +struct arch_elf_state { + int fp_abi; + int interp_fp_abi; + int overall_abi; +}; + +#define INIT_ARCH_ELF_STATE { \ + .fp_abi = -1, \ + .interp_fp_abi = -1, \ + .overall_abi = -1, \ +} + +extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, + bool is_interp, struct arch_elf_state *state); + +extern int arch_check_elf(void *ehdr, bool has_interpreter, + struct arch_elf_state *state); + +extern void mips_set_personality_fp(struct arch_elf_state *state); + #endif /* _ASM_ELF_H */ diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index dd56241..994d219 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -36,14 +36,16 @@ extern void _restore_fp(struct task_struct *); /* * This enum specifies a mode in which we want the FPU to operate, for cores - * which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT - * purposefully have the values 0 & 1 respectively, so that an integer value - * of Status.FR can be trivially casted to the corresponding enum fpu_mode. + * which implement the Status.FR bit. Note that the bottom bit of the value + * purposefully matches the desired value of the Status.FR bit. */ enum fpu_mode { FPU_32BIT = 0, /* FR = 0 */ - FPU_64BIT, /* FR = 1 */ + FPU_64BIT, /* FR = 1, FRE = 0 */ FPU_AS_IS, + FPU_HYBRID, /* FR = 1, FRE = 1 */ + +#define FPU_FR_MASK 0x1 }; static inline int __enable_fpu(enum fpu_mode mode) @@ -57,6 +59,14 @@ static inline int __enable_fpu(enum fpu_mode mode) enable_fpu_hazard(); return 0; + case FPU_HYBRID: + if (!cpu_has_fre) + return SIGFPE; + + /* set FRE */ + write_c0_config5(read_c0_config5() | MIPS_CONF5_FRE); + goto fr_common; + case FPU_64BIT: #if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_64BIT)) /* we only have a 32-bit FPU */ @@ -64,8 +74,11 @@ static inline int __enable_fpu(enum fpu_mode mode) #endif /* fall through */ case FPU_32BIT: + /* clear FRE */ + write_c0_config5(read_c0_config5() & ~MIPS_CONF5_FRE); +fr_common: /* set CU1 & change FR appropriately */ - fr = (int)mode; + fr = (int)mode & FPU_FR_MASK; change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0)); enable_fpu_hazard(); @@ -102,13 +115,17 @@ static inline int __own_fpu(void) enum fpu_mode mode; int ret; - mode = !test_thread_flag(TIF_32BIT_FPREGS); + if (test_thread_flag(TIF_HYBRID_FPREGS)) + mode = FPU_HYBRID; + else + mode = !test_thread_flag(TIF_32BIT_FPREGS); + ret = __enable_fpu(mode); if (ret) return ret; KSTK_STATUS(current) |= ST0_CU1; - if (mode == FPU_64BIT) + if (mode == FPU_64BIT || mode == FPU_HYBRID) KSTK_STATUS(current) |= ST0_FR; else /* mode == FPU_32BIT */ KSTK_STATUS(current) &= ~ST0_FR; @@ -166,8 +183,24 @@ static inline int init_fpu(void) if (cpu_has_fpu) { ret = __own_fpu(); - if (!ret) + if (!ret) { + unsigned int config5 = read_c0_config5(); + + /* + * Ensure FRE is clear whilst running _init_fpu, since + * single precision FP instructions are used. If FRE + * was set then we'll just end up initialising all 32 + * 64b registers. + */ + write_c0_config5(config5 & ~MIPS_CONF5_FRE); + enable_fpu_hazard(); + _init_fpu(); + + /* Restore FRE */ + write_c0_config5(config5); + enable_fpu_hazard(); + } } else fpu_emulator_init_fpu(); diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h index 194cda0..ef9987a 100644 --- a/arch/mips/include/asm/futex.h +++ b/arch/mips/include/asm/futex.h @@ -14,6 +14,7 @@ #include <linux/uaccess.h> #include <asm/asm-eva.h> #include <asm/barrier.h> +#include <asm/compiler.h> #include <asm/errno.h> #include <asm/war.h> @@ -32,6 +33,7 @@ " beqzl $1, 1b \n" \ __WEAK_LLSC_MB \ "3: \n" \ + " .insn \n" \ " .set pop \n" \ " .set mips0 \n" \ " .section .fixup,\"ax\" \n" \ @@ -42,8 +44,10 @@ " "__UA_ADDR "\t1b, 4b \n" \ " "__UA_ADDR "\t2b, 4b \n" \ " .previous \n" \ - : "=r" (ret), "=&r" (oldval), "=R" (*uaddr) \ - : "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT) \ + : "=r" (ret), "=&r" (oldval), \ + "=" GCC_OFF12_ASM() (*uaddr) \ + : "0" (0), GCC_OFF12_ASM() (*uaddr), "Jr" (oparg), \ + "i" (-EFAULT) \ : "memory"); \ } else if (cpu_has_llsc) { \ __asm__ __volatile__( \ @@ -58,6 +62,7 @@ " beqz $1, 1b \n" \ __WEAK_LLSC_MB \ "3: \n" \ + " .insn \n" \ " .set pop \n" \ " .set mips0 \n" \ " .section .fixup,\"ax\" \n" \ @@ -68,8 +73,10 @@ " "__UA_ADDR "\t1b, 4b \n" \ " "__UA_ADDR "\t2b, 4b \n" \ " .previous \n" \ - : "=r" (ret), "=&r" (oldval), "=R" (*uaddr) \ - : "0" (0), "R" (*uaddr), "Jr" (oparg), "i" (-EFAULT) \ + : "=r" (ret), "=&r" (oldval), \ + "=" GCC_OFF12_ASM() (*uaddr) \ + : "0" (0), GCC_OFF12_ASM() (*uaddr), "Jr" (oparg), \ + "i" (-EFAULT) \ : "memory"); \ } else \ ret = -ENOSYS; \ @@ -157,6 +164,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " beqzl $1, 1b \n" __WEAK_LLSC_MB "3: \n" + " .insn \n" " .set pop \n" " .section .fixup,\"ax\" \n" "4: li %0, %6 \n" @@ -166,8 +174,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " "__UA_ADDR "\t1b, 4b \n" " "__UA_ADDR "\t2b, 4b \n" " .previous \n" - : "+r" (ret), "=&r" (val), "=R" (*uaddr) - : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) + : "+r" (ret), "=&r" (val), "=" GCC_OFF12_ASM() (*uaddr) + : GCC_OFF12_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), + "i" (-EFAULT) : "memory"); } else if (cpu_has_llsc) { __asm__ __volatile__( @@ -184,6 +193,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " beqz $1, 1b \n" __WEAK_LLSC_MB "3: \n" + " .insn \n" " .set pop \n" " .section .fixup,\"ax\" \n" "4: li %0, %6 \n" @@ -193,8 +203,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " "__UA_ADDR "\t1b, 4b \n" " "__UA_ADDR "\t2b, 4b \n" " .previous \n" - : "+r" (ret), "=&r" (val), "=R" (*uaddr) - : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) + : "+r" (ret), "=&r" (val), "=" GCC_OFF12_ASM() (*uaddr) + : GCC_OFF12_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), + "i" (-EFAULT) : "memory"); } else return -ENOSYS; diff --git a/arch/mips/include/asm/hpet.h b/arch/mips/include/asm/hpet.h new file mode 100644 index 0000000..18a8f77 --- /dev/null +++ b/arch/mips/include/asm/hpet.h @@ -0,0 +1,73 @@ +#ifndef _ASM_HPET_H +#define _ASM_HPET_H + +#ifdef CONFIG_RS780_HPET + +#define HPET_MMAP_SIZE 1024 + +#define HPET_ID 0x000 +#define HPET_PERIOD 0x004 +#define HPET_CFG 0x010 +#define HPET_STATUS 0x020 +#define HPET_COUNTER 0x0f0 + +#define HPET_Tn_CFG(n) (0x100 + 0x20 * n) +#define HPET_Tn_CMP(n) (0x108 + 0x20 * n) +#define HPET_Tn_ROUTE(n) (0x110 + 0x20 * n) + +#define HPET_T0_IRS 0x001 +#define HPET_T1_IRS 0x002 +#define HPET_T3_IRS 0x004 + +#define HPET_T0_CFG 0x100 +#define HPET_T0_CMP 0x108 +#define HPET_T0_ROUTE 0x110 +#define HPET_T1_CFG 0x120 +#define HPET_T1_CMP 0x128 +#define HPET_T1_ROUTE 0x130 +#define HPET_T2_CFG 0x140 +#define HPET_T2_CMP 0x148 +#define HPET_T2_ROUTE 0x150 + +#define HPET_ID_REV 0x000000ff +#define HPET_ID_NUMBER 0x00001f00 +#define HPET_ID_64BIT 0x00002000 +#define HPET_ID_LEGSUP 0x00008000 +#define HPET_ID_VENDOR 0xffff0000 +#define HPET_ID_NUMBER_SHIFT 8 +#define HPET_ID_VENDOR_SHIFT 16 + +#define HPET_CFG_ENABLE 0x001 +#define HPET_CFG_LEGACY 0x002 +#define HPET_LEGACY_8254 2 +#define HPET_LEGACY_RTC 8 + +#define HPET_TN_LEVEL 0x0002 +#define HPET_TN_ENABLE 0x0004 +#define HPET_TN_PERIODIC 0x0008 +#define HPET_TN_PERIODIC_CAP 0x0010 +#define HPET_TN_64BIT_CAP 0x0020 +#define HPET_TN_SETVAL 0x0040 +#define HPET_TN_32BIT 0x0100 +#define HPET_TN_ROUTE 0x3e00 +#define HPET_TN_FSB 0x4000 +#define HPET_TN_FSB_CAP 0x8000 +#define HPET_TN_ROUTE_SHIFT 9 + +/* Max HPET Period is 10^8 femto sec as in HPET spec */ +#define HPET_MAX_PERIOD 100000000UL +/* + * Min HPET period is 10^5 femto sec just for safety. If it is less than this, + * then 32 bit HPET counter wrapsaround in less than 0.5 sec. + */ +#define HPET_MIN_PERIOD 100000UL + +#define HPET_ADDR 0x20000 +#define HPET_MMIO_ADDR 0x90000e0000020000 +#define HPET_FREQ 14318780 +#define HPET_COMPARE_VAL ((HPET_FREQ + HZ / 2) / HZ) +#define HPET_T0_IRQ 0 + +extern void __init setup_hpet_timer(void); +#endif /* CONFIG_RS780_HPET */ +#endif /* _ASM_HPET_H */ diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 933b50e..9e777cd 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -167,7 +167,7 @@ static inline void * isa_bus_to_virt(unsigned long address) */ #define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) -extern void __iomem * __ioremap(phys_t offset, phys_t size, unsigned long flags); +extern void __iomem * __ioremap(phys_addr_t offset, phys_addr_t size, unsigned long flags); extern void __iounmap(const volatile void __iomem *addr); #ifndef CONFIG_PCI @@ -175,7 +175,7 @@ struct pci_dev; static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {} #endif -static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size, +static inline void __iomem * __ioremap_mode(phys_addr_t offset, unsigned long size, unsigned long flags) { void __iomem *addr = plat_ioremap(offset, size, flags); @@ -183,7 +183,7 @@ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size, if (addr) return addr; -#define __IS_LOW512(addr) (!((phys_t)(addr) & (phys_t) ~0x1fffffffULL)) +#define __IS_LOW512(addr) (!((phys_addr_t)(addr) & (phys_addr_t) ~0x1fffffffULL)) if (cpu_has_64bit_addresses) { u64 base = UNCAC_BASE; @@ -197,7 +197,7 @@ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size, return (void __iomem *) (unsigned long) (base + offset); } else if (__builtin_constant_p(offset) && __builtin_constant_p(size) && __builtin_constant_p(flags)) { - phys_t phys_addr, last_addr; + phys_addr_t phys_addr, last_addr; phys_addr = fixup_bigphys_addr(offset, size); diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 39f07ae..5a4e1bb 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -48,4 +48,7 @@ extern int cp0_compare_irq; extern int cp0_compare_irq_shift; extern int cp0_perfcount_irq; +void arch_trigger_all_cpu_backtrace(bool); +#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace + #endif /* _ASM_IRQ_H */ diff --git a/arch/mips/include/asm/irq_cpu.h b/arch/mips/include/asm/irq_cpu.h index 3f11fdb..39a160b 100644 --- a/arch/mips/include/asm/irq_cpu.h +++ b/arch/mips/include/asm/irq_cpu.h @@ -19,8 +19,8 @@ extern void rm9k_cpu_irq_init(void); #ifdef CONFIG_IRQ_DOMAIN struct device_node; -extern int mips_cpu_intc_init(struct device_node *of_node, - struct device_node *parent); +extern int mips_cpu_irq_of_init(struct device_node *of_node, + struct device_node *parent); #endif #endif /* _ASM_IRQ_CPU_H */ diff --git a/arch/mips/include/asm/mach-ath25/ath25_platform.h b/arch/mips/include/asm/mach-ath25/ath25_platform.h new file mode 100644 index 0000000..4f4ee4f --- /dev/null +++ b/arch/mips/include/asm/mach-ath25/ath25_platform.h @@ -0,0 +1,73 @@ +#ifndef __ASM_MACH_ATH25_PLATFORM_H +#define __ASM_MACH_ATH25_PLATFORM_H + +#include <linux/etherdevice.h> + +/* + * This is board-specific data that is stored in a "fixed" location in flash. + * It is shared across operating systems, so it should not be changed lightly. + * The main reason we need it is in order to extract the ethernet MAC + * address(es). + */ +struct ath25_boarddata { + u32 magic; /* board data is valid */ +#define ATH25_BD_MAGIC 0x35333131 /* "5311", for all 531x/231x platforms */ + u16 cksum; /* checksum (starting with BD_REV 2) */ + u16 rev; /* revision of this struct */ +#define BD_REV 4 + char board_name[64]; /* Name of board */ + u16 major; /* Board major number */ + u16 minor; /* Board minor number */ + u32 flags; /* Board configuration */ +#define BD_ENET0 0x00000001 /* ENET0 is stuffed */ +#define BD_ENET1 0x00000002 /* ENET1 is stuffed */ +#define BD_UART1 0x00000004 /* UART1 is stuffed */ +#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */ +#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */ +#define BD_SYSLED 0x00000020 /* System LED stuffed */ +#define BD_EXTUARTCLK 0x00000040 /* External UART clock */ +#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */ +#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */ +#define BD_WLAN0 0x00000200 /* Enable WLAN0 */ +#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ mem_cap for testing */ +#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */ +#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */ +#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */ +#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */ +#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */ +#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */ +#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */ + u16 reset_config_gpio; /* Reset factory GPIO pin */ + u16 sys_led_gpio; /* System LED GPIO pin */ + + u32 cpu_freq; /* CPU core frequency in Hz */ + u32 sys_freq; /* System frequency in Hz */ + u32 cnt_freq; /* Calculated C0_COUNT frequency */ + + u8 wlan0_mac[ETH_ALEN]; + u8 enet0_mac[ETH_ALEN]; + u8 enet1_mac[ETH_ALEN]; + + u16 pci_id; /* Pseudo PCIID for common code */ + u16 mem_cap; /* cap bank1 in MB */ + + /* version 3 */ + u8 wlan1_mac[ETH_ALEN]; /* (ar5212) */ +}; + +#define BOARD_CONFIG_BUFSZ 0x1000 + +/* + * Platform device information for the Wireless MAC + */ +struct ar231x_board_config { + u16 devid; + + /* board config data */ + struct ath25_boarddata *config; + + /* radio calibration data */ + const char *radio; +}; + +#endif /* __ASM_MACH_ATH25_PLATFORM_H */ diff --git a/arch/mips/include/asm/mach-ath25/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ath25/cpu-feature-overrides.h new file mode 100644 index 0000000..ade0356 --- /dev/null +++ b/arch/mips/include/asm/mach-ath25/cpu-feature-overrides.h @@ -0,0 +1,64 @@ +/* + * Atheros AR231x/AR531x SoC specific CPU feature overrides + * + * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org> + * + * This file was derived from: include/asm-mips/cpu-features.h + * Copyright (C) 2003, 2004 Ralf Baechle + * Copyright (C) 2004 Maciej W. Rozycki + * + * 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 __ASM_MACH_ATH25_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_ATH25_CPU_FEATURE_OVERRIDES_H + +/* + * The Atheros AR531x/AR231x SoCs have MIPS 4Kc/4KEc core. + */ +#define cpu_has_tlb 1 +#define cpu_has_4kex 1 +#define cpu_has_3k_cache 0 +#define cpu_has_4k_cache 1 +#define cpu_has_tx39_cache 0 +#define cpu_has_sb1_cache 0 +#define cpu_has_fpu 0 +#define cpu_has_32fpr 0 +#define cpu_has_counter 1 +#define cpu_has_ejtag 1 + +#if !defined(CONFIG_SOC_AR5312) +# define cpu_has_llsc 1 +#else +/* + * The MIPS 4Kc V0.9 core in the AR5312/AR2312 have problems with the + * ll/sc instructions. + */ +# define cpu_has_llsc 0 +#endif + +#define cpu_has_mips16 0 +#define cpu_has_mdmx 0 +#define cpu_has_mips3d 0 +#define cpu_has_smartmips 0 + +#define cpu_has_mips32r1 1 + +#if !defined(CONFIG_SOC_AR5312) +# define cpu_has_mips32r2 1 +#endif + +#define cpu_has_mips64r1 0 +#define cpu_has_mips64r2 0 + +#define cpu_has_dsp 0 +#define cpu_has_mipsmt 0 + +#define cpu_has_64bits 0 +#define cpu_has_64bit_zero_reg 0 +#define cpu_has_64bit_gp_regs 0 +#define cpu_has_64bit_addresses 0 + +#endif /* __ASM_MACH_ATH25_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-ath25/dma-coherence.h b/arch/mips/include/asm/mach-ath25/dma-coherence.h new file mode 100644 index 0000000..d8009c9 --- /dev/null +++ b/arch/mips/include/asm/mach-ath25/dma-coherence.h @@ -0,0 +1,82 @@ +/* + * 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) 2006 Ralf Baechle <ralf@linux-mips.org> + * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> + * + */ +#ifndef __ASM_MACH_ATH25_DMA_COHERENCE_H +#define __ASM_MACH_ATH25_DMA_COHERENCE_H + +#include <linux/device.h> + +/* + * We need some arbitrary non-zero value to be programmed to the BAR1 register + * of PCI host controller to enable DMA. The same value should be used as the + * offset to calculate the physical address of DMA buffer for PCI devices. + */ +#define AR2315_PCI_HOST_SDRAM_BASEADDR 0x20000000 + +static inline dma_addr_t ath25_dev_offset(struct device *dev) +{ +#ifdef CONFIG_PCI + extern struct bus_type pci_bus_type; + + if (dev && dev->bus == &pci_bus_type) + return AR2315_PCI_HOST_SDRAM_BASEADDR; +#endif + return 0; +} + +static inline dma_addr_t +plat_map_dma_mem(struct device *dev, void *addr, size_t size) +{ + return virt_to_phys(addr) + ath25_dev_offset(dev); +} + +static inline dma_addr_t +plat_map_dma_mem_page(struct device *dev, struct page *page) +{ + return page_to_phys(page) + ath25_dev_offset(dev); +} + +static inline unsigned long +plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr) +{ + return dma_addr - ath25_dev_offset(dev); +} + +static inline void +plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ +} + +static inline int plat_dma_supported(struct device *dev, u64 mask) +{ + return 1; +} + +static inline void plat_extra_sync_for_device(struct device *dev) +{ +} + +static inline int plat_dma_mapping_error(struct device *dev, + dma_addr_t dma_addr) +{ + return 0; +} + +static inline int plat_device_is_coherent(struct device *dev) +{ +#ifdef CONFIG_DMA_COHERENT + return 1; +#endif +#ifdef CONFIG_DMA_NONCOHERENT + return 0; +#endif +} + +#endif /* __ASM_MACH_ATH25_DMA_COHERENCE_H */ diff --git a/arch/mips/include/asm/mach-ath25/gpio.h b/arch/mips/include/asm/mach-ath25/gpio.h new file mode 100644 index 0000000..713564b --- /dev/null +++ b/arch/mips/include/asm/mach-ath25/gpio.h @@ -0,0 +1,16 @@ +#ifndef __ASM_MACH_ATH25_GPIO_H +#define __ASM_MACH_ATH25_GPIO_H + +#include <asm-generic/gpio.h> + +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value +#define gpio_cansleep __gpio_cansleep +#define gpio_to_irq __gpio_to_irq + +static inline int irq_to_gpio(unsigned irq) +{ + return -EINVAL; +} + +#endif /* __ASM_MACH_ATH25_GPIO_H */ diff --git a/arch/mips/include/asm/mach-ath25/war.h b/arch/mips/include/asm/mach-ath25/war.h new file mode 100644 index 0000000..e3a5250 --- /dev/null +++ b/arch/mips/include/asm/mach-ath25/war.h @@ -0,0 +1,25 @@ +/* + * 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) 2008 Felix Fietkau <nbd@openwrt.org> + */ +#ifndef __ASM_MACH_ATH25_WAR_H +#define __ASM_MACH_ATH25_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MACH_ATH25_WAR_H */ diff --git a/arch/mips/include/asm/mach-au1x00/ioremap.h b/arch/mips/include/asm/mach-au1x00/ioremap.h index 75a94ad..99fea1f 100644 --- a/arch/mips/include/asm/mach-au1x00/ioremap.h +++ b/arch/mips/include/asm/mach-au1x00/ioremap.h @@ -11,10 +11,10 @@ #include <linux/types.h> -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_PCI) -extern phys_t __fixup_bigphys_addr(phys_t, phys_t); +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_PCI) +extern phys_addr_t __fixup_bigphys_addr(phys_addr_t, phys_addr_t); #else -static inline phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) +static inline phys_addr_t __fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) { return phys_addr; } @@ -23,12 +23,12 @@ static inline phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) /* * Allow physical addresses to be fixed up to help 36-bit peripherals. */ -static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) { return __fixup_bigphys_addr(phys_addr, size); } -static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size, +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, unsigned long flags) { return NULL; diff --git a/arch/mips/include/asm/mach-bcm3384/dma-coherence.h b/arch/mips/include/asm/mach-bcm3384/dma-coherence.h new file mode 100644 index 0000000..a3be8e5 --- /dev/null +++ b/arch/mips/include/asm/mach-bcm3384/dma-coherence.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Ralf Baechle <ralf@linux-mips.org> + * Copyright (C) 2009 Broadcom Corporation + * + * 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. + * + * This program is distributed in the hope that 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 __ASM_MACH_BCM3384_DMA_COHERENCE_H +#define __ASM_MACH_BCM3384_DMA_COHERENCE_H + +struct device; + +extern dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size); +extern dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page); +extern unsigned long plat_dma_addr_to_phys(struct device *dev, + dma_addr_t dma_addr); + +static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction direction) +{ +} + +static inline int plat_dma_supported(struct device *dev, u64 mask) +{ + /* + * we fall back to GFP_DMA when the mask isn't all 1s, + * so we can't guarantee allocations that must be + * within a tighter range than GFP_DMA.. + */ + if (mask < DMA_BIT_MASK(24)) + return 0; + + return 1; +} + +static inline int plat_device_is_coherent(struct device *dev) +{ + return 0; +} + +#endif /* __ASM_MACH_BCM3384_DMA_COHERENCE_H */ diff --git a/arch/mips/include/asm/mach-bcm3384/war.h b/arch/mips/include/asm/mach-bcm3384/war.h new file mode 100644 index 0000000..59d7599 --- /dev/null +++ b/arch/mips/include/asm/mach-bcm3384/war.h @@ -0,0 +1,24 @@ +/* + * 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) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org> + */ +#ifndef __ASM_MIPS_MACH_BCM3384_WAR_H +#define __ASM_MIPS_MACH_BCM3384_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_BCM3384_WAR_H */ diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h index 36a3fc1..ee59ffe 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx_nvram.h @@ -14,40 +14,8 @@ #include <linux/types.h> #include <linux/kernel.h> -struct nvram_header { - u32 magic; - u32 len; - u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ - u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ - u32 config_ncdl; /* ncdl values for memc */ -}; - -#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */ -#define NVRAM_VERSION 1 -#define NVRAM_HEADER_SIZE 20 -#define NVRAM_SPACE 0x8000 - -#define FLASH_MIN 0x00020000 /* Minimum flash size */ - -#define NVRAM_MAX_VALUE_LEN 255 -#define NVRAM_MAX_PARAM_LEN 64 - -extern int bcm47xx_nvram_getenv(char *name, char *val, size_t val_len); - -static inline void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6]) -{ - if (strchr(buf, ':')) - sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], - &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], - &macaddr[5]); - else if (strchr(buf, '-')) - sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0], - &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], - &macaddr[5]); - else - printk(KERN_WARNING "Can not parse mac address: %s\n", buf); -} - +int bcm47xx_nvram_init_from_mem(u32 base, u32 lim); +int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len); int bcm47xx_nvram_gpio_pin(const char *name); #endif /* __BCM47XX_NVRAM_H */ diff --git a/arch/mips/include/asm/mach-bcm63xx/ioremap.h b/arch/mips/include/asm/mach-bcm63xx/ioremap.h index ff15e3b..aea6e64 100644 --- a/arch/mips/include/asm/mach-bcm63xx/ioremap.h +++ b/arch/mips/include/asm/mach-bcm63xx/ioremap.h @@ -3,12 +3,12 @@ #include <bcm63xx_cpu.h> -static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) { return phys_addr; } -static inline int is_bcm63xx_internal_registers(phys_t offset) +static inline int is_bcm63xx_internal_registers(phys_addr_t offset) { switch (bcm63xx_get_cpu_id()) { case BCM3368_CPU_ID: @@ -32,7 +32,7 @@ static inline int is_bcm63xx_internal_registers(phys_t offset) return 0; } -static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size, +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, unsigned long flags) { if (is_bcm63xx_internal_registers(offset)) diff --git a/arch/mips/include/asm/mach-generic/ioremap.h b/arch/mips/include/asm/mach-generic/ioremap.h index b379938..513371f 100644 --- a/arch/mips/include/asm/mach-generic/ioremap.h +++ b/arch/mips/include/asm/mach-generic/ioremap.h @@ -15,12 +15,12 @@ * Allow physical addresses to be fixed up to help peripherals located * outside the low 32-bit range -- generic pass-through version. */ -static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) { return phys_addr; } -static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size, +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, unsigned long flags) { return NULL; diff --git a/arch/mips/include/asm/mach-generic/irq.h b/arch/mips/include/asm/mach-generic/irq.h index 139cd20..050e18b 100644 --- a/arch/mips/include/asm/mach-generic/irq.h +++ b/arch/mips/include/asm/mach-generic/irq.h @@ -36,4 +36,10 @@ #endif /* CONFIG_IRQ_CPU */ +#ifdef CONFIG_MIPS_GIC +#ifndef MIPS_GIC_IRQ_BASE +#define MIPS_GIC_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8) +#endif +#endif /* CONFIG_MIPS_GIC */ + #endif /* __ASM_MACH_GENERIC_IRQ_H */ diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h index f196cce..4e5ae65 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -48,6 +48,8 @@ extern struct clk *clk_get_ppe(void); extern unsigned char ltq_boot_select(void); /* find out what caused the last cpu reset */ extern int ltq_reset_cause(void); +/* find out the soc type */ +extern int ltq_soc_type(void); #define IOPORT_RESOURCE_START 0x10000000 #define IOPORT_RESOURCE_END 0xffffffff diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h b/arch/mips/include/asm/mach-loongson/boot_param.h index 3388fc5..fa80292 100644 --- a/arch/mips/include/asm/mach-loongson/boot_param.h +++ b/arch/mips/include/asm/mach-loongson/boot_param.h @@ -10,7 +10,8 @@ #define VIDEO_ROM 7 #define ADAPTER_ROM 8 #define ACPI_TABLE 9 -#define MAX_MEMORY_TYPE 10 +#define SMBIOS_TABLE 10 +#define MAX_MEMORY_TYPE 11 #define LOONGSON3_BOOT_MEM_MAP_MAX 128 struct efi_memory_map_loongson { @@ -42,15 +43,49 @@ struct efi_cpuinfo_loongson { u32 processor_id; /* PRID, e.g. 6305, 6306 */ u32 cputype; /* Loongson_3A/3B, etc. */ u32 total_node; /* num of total numa nodes */ - u32 cpu_startup_core_id; /* Core id */ + u16 cpu_startup_core_id; /* Boot core id */ + u16 reserved_cores_mask; u32 cpu_clock_freq; /* cpu_clock */ u32 nr_cpus; } __packed; +#define MAX_UARTS 64 +struct uart_device { + u32 iotype; /* see include/linux/serial_core.h */ + u32 uartclk; + u32 int_offset; + u64 uart_base; +} __packed; + +#define MAX_SENSORS 64 +#define SENSOR_TEMPER 0x00000001 +#define SENSOR_VOLTAGE 0x00000002 +#define SENSOR_FAN 0x00000004 +struct sensor_device { + char name[32]; /* a formal name */ + char label[64]; /* a flexible description */ + u32 type; /* SENSOR_* */ + u32 id; /* instance id of a sensor-class */ + u32 fan_policy; /* see loongson_hwmon.h */ + u32 fan_percent;/* only for constant speed policy */ + u64 base_addr; /* base address of device registers */ +} __packed; + struct system_loongson { u16 vers; /* version of system_loongson */ u32 ccnuma_smp; /* 0: no numa; 1: has numa */ u32 sing_double_channel; /* 1:single; 2:double */ + u32 nr_uarts; + struct uart_device uarts[MAX_UARTS]; + u32 nr_sensors; + struct sensor_device sensors[MAX_SENSORS]; + char has_ec; + char ec_name[32]; + u64 ec_base_addr; + char has_tcm; + char tcm_name[32]; + u64 tcm_base_addr; + u64 workarounds; /* see workarounds.h */ } __packed; struct irq_source_routing_table { @@ -149,6 +184,8 @@ struct loongson_system_configuration { u32 nr_nodes; int cores_per_node; int cores_per_package; + u16 boot_cpu_id; + u16 reserved_cpus_mask; enum loongson_cpu_type cputype; u64 ht_control_base; u64 pci_mem_start_addr; @@ -159,9 +196,15 @@ struct loongson_system_configuration { u64 suspend_addr; u64 vgabios_addr; u32 dma_mask_bits; + char ecname[32]; + u32 nr_uarts; + struct uart_device uarts[MAX_UARTS]; + u32 nr_sensors; + struct sensor_device sensors[MAX_SENSORS]; + u64 workarounds; }; extern struct efi_memory_map_loongson *loongson_memmap; extern struct loongson_system_configuration loongson_sysconf; -extern int cpuhotplug_workaround; + #endif diff --git a/arch/mips/include/asm/mach-loongson/dma-coherence.h b/arch/mips/include/asm/mach-loongson/dma-coherence.h index 6a90275..a905341 100644 --- a/arch/mips/include/asm/mach-loongson/dma-coherence.h +++ b/arch/mips/include/asm/mach-loongson/dma-coherence.h @@ -23,7 +23,7 @@ static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size) { #ifdef CONFIG_CPU_LOONGSON3 - return virt_to_phys(addr); + return phys_to_dma(dev, virt_to_phys(addr)); #else return virt_to_phys(addr) | 0x80000000; #endif @@ -33,7 +33,7 @@ static inline dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page) { #ifdef CONFIG_CPU_LOONGSON3 - return page_to_phys(page); + return phys_to_dma(dev, page_to_phys(page)); #else return page_to_phys(page) | 0x80000000; #endif @@ -43,7 +43,7 @@ static inline unsigned long plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr) { #if defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_64BIT) - return dma_addr; + return dma_to_phys(dev, dma_addr); #elif defined(CONFIG_CPU_LOONGSON2F) && defined(CONFIG_64BIT) return (dma_addr > 0x8fffffff) ? dma_addr : (dma_addr & 0x0fffffff); #else diff --git a/arch/mips/include/asm/mach-loongson/irq.h b/arch/mips/include/asm/mach-loongson/irq.h index 34560bd..a281cca 100644 --- a/arch/mips/include/asm/mach-loongson/irq.h +++ b/arch/mips/include/asm/mach-loongson/irq.h @@ -32,8 +32,7 @@ #define LOONGSON_INT_ROUTER_LPC LOONGSON_INT_ROUTER_ENTRY(0x0a) #define LOONGSON_INT_ROUTER_HT1(n) LOONGSON_INT_ROUTER_ENTRY(n + 0x18) -#define LOONGSON_INT_CORE0_INT0 0x11 /* route to int 0 of core 0 */ -#define LOONGSON_INT_CORE0_INT1 0x21 /* route to int 1 of core 0 */ +#define LOONGSON_INT_COREx_INTy(x, y) (1<<(x) | 1<<(y+4)) /* route to int y of core x */ #endif diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h index 92bf76c..5459ac0 100644 --- a/arch/mips/include/asm/mach-loongson/loongson.h +++ b/arch/mips/include/asm/mach-loongson/loongson.h @@ -35,7 +35,7 @@ extern void __init prom_init_cmdline(void); extern void __init prom_init_machtype(void); extern void __init prom_init_env(void); #ifdef CONFIG_LOONGSON_UART_BASE -extern unsigned long _loongson_uart_base, loongson_uart_base; +extern unsigned long _loongson_uart_base[], loongson_uart_base[]; extern void prom_init_loongson_uart_base(void); #endif diff --git a/arch/mips/include/asm/mach-loongson/loongson_hwmon.h b/arch/mips/include/asm/mach-loongson/loongson_hwmon.h new file mode 100644 index 0000000..4431fc5 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson/loongson_hwmon.h @@ -0,0 +1,55 @@ +#ifndef __LOONGSON_HWMON_H_ +#define __LOONGSON_HWMON_H_ + +#include <linux/types.h> + +#define MIN_TEMP 0 +#define MAX_TEMP 255 +#define NOT_VALID_TEMP 999 + +typedef int (*get_temp_fun)(int); +extern int loongson3_cpu_temp(int); + +/* 0:Max speed, 1:Manual, 2:Auto */ +enum fan_control_mode { + FAN_FULL_MODE = 0, + FAN_MANUAL_MODE = 1, + FAN_AUTO_MODE = 2, + FAN_MODE_END +}; + +struct temp_range { + u8 low; + u8 high; + u8 level; +}; + +#define CONSTANT_SPEED_POLICY 0 /* at constent speed */ +#define STEP_SPEED_POLICY 1 /* use up/down arrays to describe policy */ +#define KERNEL_HELPER_POLICY 2 /* kernel as a helper to fan control */ + +#define MAX_STEP_NUM 16 +#define MAX_FAN_LEVEL 255 + +/* loongson_fan_policy works when fan work at FAN_AUTO_MODE */ +struct loongson_fan_policy { + u8 type; + + /* percent only used when type is CONSTANT_SPEED_POLICY */ + u8 percent; + + /* period between two check. (Unit: S) */ + u8 adjust_period; + + /* fan adjust usually depend on a temprature input */ + get_temp_fun depend_temp; + + /* up_step/down_step used when type is STEP_SPEED_POLICY */ + u8 up_step_num; + u8 down_step_num; + struct temp_range up_step[MAX_STEP_NUM]; + struct temp_range down_step[MAX_STEP_NUM]; + struct delayed_work work; +}; + +#endif /* __LOONGSON_HWMON_H_*/ diff --git a/arch/mips/include/asm/mach-loongson/machine.h b/arch/mips/include/asm/mach-loongson/machine.h index 228e3784..cb2b602 100644 --- a/arch/mips/include/asm/mach-loongson/machine.h +++ b/arch/mips/include/asm/mach-loongson/machine.h @@ -26,7 +26,7 @@ #ifdef CONFIG_LOONGSON_MACH3X -#define LOONGSON_MACHTYPE MACH_LEMOTE_A1101 +#define LOONGSON_MACHTYPE MACH_LOONGSON_GENERIC #endif /* CONFIG_LOONGSON_MACH3X */ diff --git a/arch/mips/include/asm/mach-loongson/topology.h b/arch/mips/include/asm/mach-loongson/topology.h index 5598ba7..0d8f3b5 100644 --- a/arch/mips/include/asm/mach-loongson/topology.h +++ b/arch/mips/include/asm/mach-loongson/topology.h @@ -3,7 +3,7 @@ #ifdef CONFIG_NUMA -#define cpu_to_node(cpu) ((cpu) >> 2) +#define cpu_to_node(cpu) (cpu_logical_map(cpu) >> 2) #define parent_node(node) (node) #define cpumask_of_node(node) (&__node_data[(node)]->cpumask) diff --git a/arch/mips/include/asm/mach-loongson/workarounds.h b/arch/mips/include/asm/mach-loongson/workarounds.h new file mode 100644 index 0000000..e180c14 --- /dev/null +++ b/arch/mips/include/asm/mach-loongson/workarounds.h @@ -0,0 +1,7 @@ +#ifndef __ASM_MACH_LOONGSON_WORKAROUNDS_H_ +#define __ASM_MACH_LOONGSON_WORKAROUNDS_H_ + +#define WORKAROUND_CPUFREQ 0x00000001 +#define WORKAROUND_CPUHOTPLUG 0x00000002 + +#endif diff --git a/arch/mips/include/asm/mach-loongson1/cpufreq.h b/arch/mips/include/asm/mach-loongson1/cpufreq.h new file mode 100644 index 0000000..e7765ce --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/cpufreq.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2014 Zhang, Keguang <keguang.zhang@gmail.com> + * + * Loongson 1 CPUFreq 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_LOONGSON1_CPUFREQ_H +#define __ASM_MACH_LOONGSON1_CPUFREQ_H + +struct plat_ls1x_cpufreq { + const char *clk_name; /* CPU clk */ + const char *osc_clk_name; /* OSC clk */ + unsigned int max_freq; /* in kHz */ + unsigned int min_freq; /* in kHz */ +}; + +#endif /* __ASM_MACH_LOONGSON1_CPUFREQ_H */ diff --git a/arch/mips/include/asm/mach-loongson1/loongson1.h b/arch/mips/include/asm/mach-loongson1/loongson1.h index 5c437c2..20e0c2b 100644 --- a/arch/mips/include/asm/mach-loongson1/loongson1.h +++ b/arch/mips/include/asm/mach-loongson1/loongson1.h @@ -16,6 +16,7 @@ #define DEFAULT_MEMSIZE 256 /* If no memsize provided */ /* Loongson 1 Register Bases */ +#define LS1X_MUX_BASE 0x1fd00420 #define LS1X_INTC_BASE 0x1fd01040 #define LS1X_EHCI_BASE 0x1fe00000 #define LS1X_OHCI_BASE 0x1fe08000 @@ -31,7 +32,10 @@ #define LS1X_I2C0_BASE 0x1fe58000 #define LS1X_I2C1_BASE 0x1fe68000 #define LS1X_I2C2_BASE 0x1fe70000 -#define LS1X_PWM_BASE 0x1fe5c000 +#define LS1X_PWM0_BASE 0x1fe5c000 +#define LS1X_PWM1_BASE 0x1fe5c010 +#define LS1X_PWM2_BASE 0x1fe5c020 +#define LS1X_PWM3_BASE 0x1fe5c030 #define LS1X_WDT_BASE 0x1fe5c060 #define LS1X_RTC_BASE 0x1fe64000 #define LS1X_AC97_BASE 0x1fe74000 @@ -39,6 +43,8 @@ #define LS1X_CLK_BASE 0x1fe78030 #include <regs-clk.h> +#include <regs-mux.h> +#include <regs-pwm.h> #include <regs-wdt.h> #endif /* __ASM_MACH_LOONGSON1_LOONGSON1_H */ diff --git a/arch/mips/include/asm/mach-loongson1/platform.h b/arch/mips/include/asm/mach-loongson1/platform.h index 30c13e5..47de55e 100644 --- a/arch/mips/include/asm/mach-loongson1/platform.h +++ b/arch/mips/include/asm/mach-loongson1/platform.h @@ -13,10 +13,12 @@ #include <linux/platform_device.h> -extern struct platform_device ls1x_uart_device; -extern struct platform_device ls1x_eth0_device; -extern struct platform_device ls1x_ehci_device; -extern struct platform_device ls1x_rtc_device; +extern struct platform_device ls1x_uart_pdev; +extern struct platform_device ls1x_cpufreq_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_rtc_pdev; extern void __init ls1x_clk_init(void); extern void __init ls1x_serial_setup(struct platform_device *pdev); diff --git a/arch/mips/include/asm/mach-loongson1/regs-clk.h b/arch/mips/include/asm/mach-loongson1/regs-clk.h index fb6a3ff..ee2445b 100644 --- a/arch/mips/include/asm/mach-loongson1/regs-clk.h +++ b/arch/mips/include/asm/mach-loongson1/regs-clk.h @@ -20,15 +20,32 @@ /* 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_SHIFT 26 #define DIV_CPU_SHIFT 20 #define DIV_DDR_SHIFT 14 -#define DIV_DC_WIDTH 5 -#define DIV_CPU_WIDTH 5 -#define DIV_DDR_WIDTH 5 +#define DIV_DC_WIDTH 4 +#define DIV_CPU_WIDTH 4 +#define DIV_DDR_WIDTH 4 + +#define BYPASS_DC_SHIFT 12 +#define BYPASS_DDR_SHIFT 10 +#define BYPASS_CPU_SHIFT 8 + +#define BYPASS_DC_WIDTH 1 +#define BYPASS_DDR_WIDTH 1 +#define BYPASS_CPU_WIDTH 1 #endif /* __ASM_MACH_LOONGSON1_REGS_CLK_H */ diff --git a/arch/mips/include/asm/mach-loongson1/regs-mux.h b/arch/mips/include/asm/mach-loongson1/regs-mux.h new file mode 100644 index 0000000..fb1e36e --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/regs-mux.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014 Zhang, Keguang <keguang.zhang@gmail.com> + * + * Loongson 1 MUX Register Definitions. + * + * 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_LOONGSON1_REGS_MUX_H +#define __ASM_MACH_LOONGSON1_REGS_MUX_H + +#define LS1X_MUX_REG(x) \ + ((void __iomem *)KSEG1ADDR(LS1X_MUX_BASE + (x))) + +#define LS1X_MUX_CTRL0 LS1X_MUX_REG(0x0) +#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 + +/* 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 + +#endif /* __ASM_MACH_LOONGSON1_REGS_MUX_H */ diff --git a/arch/mips/include/asm/mach-loongson1/regs-pwm.h b/arch/mips/include/asm/mach-loongson1/regs-pwm.h new file mode 100644 index 0000000..99f2bcc --- /dev/null +++ b/arch/mips/include/asm/mach-loongson1/regs-pwm.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 Zhang, Keguang <keguang.zhang@gmail.com> + * + * Loongson 1 PWM Register Definitions. + * + * 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_LOONGSON1_REGS_PWM_H +#define __ASM_MACH_LOONGSON1_REGS_PWM_H + +/* Loongson 1 PWM Timer Register Definitions */ +#define PWM_CNT 0x0 +#define PWM_HRC 0x4 +#define PWM_LRC 0x8 +#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 + +#endif /* __ASM_MACH_LOONGSON1_REGS_PWM_H */ diff --git a/arch/mips/include/asm/mach-loongson1/regs-wdt.h b/arch/mips/include/asm/mach-loongson1/regs-wdt.h index 6574568..c39ee98 100644 --- a/arch/mips/include/asm/mach-loongson1/regs-wdt.h +++ b/arch/mips/include/asm/mach-loongson1/regs-wdt.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> * - * Loongson 1 watchdog register definitions. + * Loongson 1 Watchdog Register Definitions. * * 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 @@ -12,11 +12,8 @@ #ifndef __ASM_MACH_LOONGSON1_REGS_WDT_H #define __ASM_MACH_LOONGSON1_REGS_WDT_H -#define LS1X_WDT_REG(x) \ - ((void __iomem *)KSEG1ADDR(LS1X_WDT_BASE + (x))) - -#define LS1X_WDT_EN LS1X_WDT_REG(0x0) -#define LS1X_WDT_SET LS1X_WDT_REG(0x4) -#define LS1X_WDT_TIMER LS1X_WDT_REG(0x8) +#define WDT_EN 0x0 +#define WDT_TIMER 0x4 +#define WDT_SET 0x8 #endif /* __ASM_MACH_LOONGSON1_REGS_WDT_H */ diff --git a/arch/mips/include/asm/mach-malta/irq.h b/arch/mips/include/asm/mach-malta/irq.h index f2c13d2..47cfe64 100644 --- a/arch/mips/include/asm/mach-malta/irq.h +++ b/arch/mips/include/asm/mach-malta/irq.h @@ -2,7 +2,6 @@ #define __ASM_MACH_MIPS_IRQ_H -#define GIC_NUM_INTRS (24 + NR_CPUS * 2) #define NR_IRQS 256 #include_next <irq.h> diff --git a/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h b/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h index fc946c8..2e54b4b 100644 --- a/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h +++ b/arch/mips/include/asm/mach-pmcs-msp71xx/msp_regops.h @@ -49,6 +49,7 @@ #include <linux/types.h> +#include <asm/compiler.h> #include <asm/war.h> #ifndef R10000_LLSC_WAR @@ -84,8 +85,8 @@ static inline void set_value_reg32(volatile u32 *const addr, " "__beqz"%0, 1b \n" " nop \n" " .set pop \n" - : "=&r" (temp), "=m" (*addr) - : "ir" (~mask), "ir" (value), "m" (*addr)); + : "=&r" (temp), "=" GCC_OFF12_ASM() (*addr) + : "ir" (~mask), "ir" (value), GCC_OFF12_ASM() (*addr)); } /* @@ -105,8 +106,8 @@ static inline void set_reg32(volatile u32 *const addr, " "__beqz"%0, 1b \n" " nop \n" " .set pop \n" - : "=&r" (temp), "=m" (*addr) - : "ir" (mask), "m" (*addr)); + : "=&r" (temp), "=" GCC_OFF12_ASM() (*addr) + : "ir" (mask), GCC_OFF12_ASM() (*addr)); } /* @@ -126,8 +127,8 @@ static inline void clear_reg32(volatile u32 *const addr, " "__beqz"%0, 1b \n" " nop \n" " .set pop \n" - : "=&r" (temp), "=m" (*addr) - : "ir" (~mask), "m" (*addr)); + : "=&r" (temp), "=" GCC_OFF12_ASM() (*addr) + : "ir" (~mask), GCC_OFF12_ASM() (*addr)); } /* @@ -147,8 +148,8 @@ static inline void toggle_reg32(volatile u32 *const addr, " "__beqz"%0, 1b \n" " nop \n" " .set pop \n" - : "=&r" (temp), "=m" (*addr) - : "ir" (mask), "m" (*addr)); + : "=&r" (temp), "=" GCC_OFF12_ASM() (*addr) + : "ir" (mask), GCC_OFF12_ASM() (*addr)); } /* @@ -219,8 +220,8 @@ static inline u32 blocking_read_reg32(volatile u32 *const addr) " .set arch=r4000 \n" \ "1: ll %0, %1 #custom_read_reg32 \n" \ " .set pop \n" \ - : "=r" (tmp), "=m" (*address) \ - : "m" (*address)) + : "=r" (tmp), "=" GCC_OFF12_ASM() (*address) \ + : GCC_OFF12_ASM() (*address)) #define custom_write_reg32(address, tmp) \ __asm__ __volatile__( \ @@ -230,7 +231,7 @@ static inline u32 blocking_read_reg32(volatile u32 *const addr) " "__beqz"%0, 1b \n" \ " nop \n" \ " .set pop \n" \ - : "=&r" (tmp), "=m" (*address) \ - : "0" (tmp), "m" (*address)) + : "=&r" (tmp), "=" GCC_OFF12_ASM() (*address) \ + : "0" (tmp), GCC_OFF12_ASM() (*address)) #endif /* __ASM_REGOPS_H__ */ diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h index 6f9b24f..1976fb8 100644 --- a/arch/mips/include/asm/mach-ralink/mt7620.h +++ b/arch/mips/include/asm/mach-ralink/mt7620.h @@ -13,6 +13,13 @@ #ifndef _MT7620_REGS_H_ #define _MT7620_REGS_H_ +enum mt762x_soc_type { + MT762X_SOC_UNKNOWN = 0, + MT762X_SOC_MT7620A, + MT762X_SOC_MT7620N, + MT762X_SOC_MT7628AN, +}; + #define MT7620_SYSC_BASE 0x10000000 #define SYSC_REG_CHIP_NAME0 0x00 @@ -25,11 +32,9 @@ #define SYSC_REG_CPLL_CONFIG0 0x54 #define SYSC_REG_CPLL_CONFIG1 0x58 -#define MT7620N_CHIP_NAME0 0x33365452 -#define MT7620N_CHIP_NAME1 0x20203235 - -#define MT7620A_CHIP_NAME0 0x3637544d -#define MT7620A_CHIP_NAME1 0x20203032 +#define MT7620_CHIP_NAME0 0x3637544d +#define MT7620_CHIP_NAME1 0x20203032 +#define MT7628_CHIP_NAME1 0x20203832 #define SYSCFG0_XTAL_FREQ_SEL BIT(6) @@ -74,6 +79,9 @@ #define SYSCFG0_DRAM_TYPE_DDR1 1 #define SYSCFG0_DRAM_TYPE_DDR2 2 +#define SYSCFG0_DRAM_TYPE_DDR2_MT7628 0 +#define SYSCFG0_DRAM_TYPE_DDR1_MT7628 1 + #define MT7620_DRAM_BASE 0x0 #define MT7620_SDRAM_SIZE_MIN 2 #define MT7620_SDRAM_SIZE_MAX 64 @@ -82,7 +90,6 @@ #define MT7620_DDR2_SIZE_MIN 32 #define MT7620_DDR2_SIZE_MAX 256 -#define MT7620_GPIO_MODE_I2C BIT(0) #define MT7620_GPIO_MODE_UART0_SHIFT 2 #define MT7620_GPIO_MODE_UART0_MASK 0x7 #define MT7620_GPIO_MODE_UART0(x) ((x) << MT7620_GPIO_MODE_UART0_SHIFT) @@ -94,15 +101,40 @@ #define MT7620_GPIO_MODE_GPIO_UARTF 0x5 #define MT7620_GPIO_MODE_GPIO_I2S 0x6 #define MT7620_GPIO_MODE_GPIO 0x7 -#define MT7620_GPIO_MODE_UART1 BIT(5) -#define MT7620_GPIO_MODE_MDIO BIT(8) -#define MT7620_GPIO_MODE_RGMII1 BIT(9) -#define MT7620_GPIO_MODE_RGMII2 BIT(10) -#define MT7620_GPIO_MODE_SPI BIT(11) -#define MT7620_GPIO_MODE_SPI_REF_CLK BIT(12) -#define MT7620_GPIO_MODE_WLED BIT(13) -#define MT7620_GPIO_MODE_JTAG BIT(15) -#define MT7620_GPIO_MODE_EPHY BIT(15) -#define MT7620_GPIO_MODE_WDT BIT(22) + +#define MT7620_GPIO_MODE_NAND 0 +#define MT7620_GPIO_MODE_SD 1 +#define MT7620_GPIO_MODE_ND_SD_GPIO 2 +#define MT7620_GPIO_MODE_ND_SD_MASK 0x3 +#define MT7620_GPIO_MODE_ND_SD_SHIFT 18 + +#define MT7620_GPIO_MODE_PCIE_RST 0 +#define MT7620_GPIO_MODE_PCIE_REF 1 +#define MT7620_GPIO_MODE_PCIE_GPIO 2 +#define MT7620_GPIO_MODE_PCIE_MASK 0x3 +#define MT7620_GPIO_MODE_PCIE_SHIFT 16 + +#define MT7620_GPIO_MODE_WDT_RST 0 +#define MT7620_GPIO_MODE_WDT_REF 1 +#define MT7620_GPIO_MODE_WDT_GPIO 2 +#define MT7620_GPIO_MODE_WDT_MASK 0x3 +#define MT7620_GPIO_MODE_WDT_SHIFT 21 + +#define MT7620_GPIO_MODE_I2C 0 +#define MT7620_GPIO_MODE_UART1 5 +#define MT7620_GPIO_MODE_MDIO 8 +#define MT7620_GPIO_MODE_RGMII1 9 +#define MT7620_GPIO_MODE_RGMII2 10 +#define MT7620_GPIO_MODE_SPI 11 +#define MT7620_GPIO_MODE_SPI_REF_CLK 12 +#define MT7620_GPIO_MODE_WLED 13 +#define MT7620_GPIO_MODE_JTAG 15 +#define MT7620_GPIO_MODE_EPHY 15 +#define MT7620_GPIO_MODE_PA 20 + +static inline int mt7620_get_eco(void) +{ + return rt_sysc_r32(SYSC_REG_CHIP_REV) & CHIP_REV_ECO_MASK; +} #endif diff --git a/arch/mips/include/asm/mach-ralink/pinmux.h b/arch/mips/include/asm/mach-ralink/pinmux.h new file mode 100644 index 0000000..be106cb --- /dev/null +++ b/arch/mips/include/asm/mach-ralink/pinmux.h @@ -0,0 +1,55 @@ +/* + * 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 + * publishhed by the Free Software Foundation. + * + * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + */ + +#ifndef _RT288X_PINMUX_H__ +#define _RT288X_PINMUX_H__ + +#define FUNC(name, value, pin_first, pin_count) \ + { name, value, pin_first, pin_count } + +#define GRP(_name, _func, _mask, _shift) \ + { .name = _name, .mask = _mask, .shift = _shift, \ + .func = _func, .gpio = _mask, \ + .func_count = ARRAY_SIZE(_func) } + +#define GRP_G(_name, _func, _mask, _gpio, _shift) \ + { .name = _name, .mask = _mask, .shift = _shift, \ + .func = _func, .gpio = _gpio, \ + .func_count = ARRAY_SIZE(_func) } + +struct rt2880_pmx_group; + +struct rt2880_pmx_func { + const char *name; + const char value; + + int pin_first; + int pin_count; + int *pins; + + int *groups; + int group_count; + + int enabled; +}; + +struct rt2880_pmx_group { + const char *name; + int enabled; + + const u32 shift; + const char mask; + const char gpio; + + struct rt2880_pmx_func *func; + int func_count; +}; + +extern struct rt2880_pmx_group *rt2880_pinmux_data; + +#endif diff --git a/arch/mips/include/asm/mach-ralink/ralink_regs.h b/arch/mips/include/asm/mach-ralink/ralink_regs.h index 5a508f9..bd93014 100644 --- a/arch/mips/include/asm/mach-ralink/ralink_regs.h +++ b/arch/mips/include/asm/mach-ralink/ralink_regs.h @@ -26,6 +26,13 @@ static inline u32 rt_sysc_r32(unsigned reg) return __raw_readl(rt_sysc_membase + reg); } +static inline void rt_sysc_m32(u32 clr, u32 set, unsigned reg) +{ + u32 val = rt_sysc_r32(reg) & ~clr; + + __raw_writel(val | set, rt_sysc_membase + reg); +} + static inline void rt_memc_w32(u32 val, unsigned reg) { __raw_writel(val, rt_memc_membase + reg); diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h index 069bf37..96f731b 100644 --- a/arch/mips/include/asm/mach-ralink/rt305x.h +++ b/arch/mips/include/asm/mach-ralink/rt305x.h @@ -125,24 +125,29 @@ static inline int soc_is_rt5350(void) #define RT305X_GPIO_GE0_TXD0 40 #define RT305X_GPIO_GE0_RXCLK 51 -#define RT305X_GPIO_MODE_I2C BIT(0) -#define RT305X_GPIO_MODE_SPI BIT(1) #define RT305X_GPIO_MODE_UART0_SHIFT 2 #define RT305X_GPIO_MODE_UART0_MASK 0x7 #define RT305X_GPIO_MODE_UART0(x) ((x) << RT305X_GPIO_MODE_UART0_SHIFT) -#define RT305X_GPIO_MODE_UARTF 0x0 -#define RT305X_GPIO_MODE_PCM_UARTF 0x1 -#define RT305X_GPIO_MODE_PCM_I2S 0x2 -#define RT305X_GPIO_MODE_I2S_UARTF 0x3 -#define RT305X_GPIO_MODE_PCM_GPIO 0x4 -#define RT305X_GPIO_MODE_GPIO_UARTF 0x5 -#define RT305X_GPIO_MODE_GPIO_I2S 0x6 -#define RT305X_GPIO_MODE_GPIO 0x7 -#define RT305X_GPIO_MODE_UART1 BIT(5) -#define RT305X_GPIO_MODE_JTAG BIT(6) -#define RT305X_GPIO_MODE_MDIO BIT(7) -#define RT305X_GPIO_MODE_SDRAM BIT(8) -#define RT305X_GPIO_MODE_RGMII BIT(9) +#define RT305X_GPIO_MODE_UARTF 0 +#define RT305X_GPIO_MODE_PCM_UARTF 1 +#define RT305X_GPIO_MODE_PCM_I2S 2 +#define RT305X_GPIO_MODE_I2S_UARTF 3 +#define RT305X_GPIO_MODE_PCM_GPIO 4 +#define RT305X_GPIO_MODE_GPIO_UARTF 5 +#define RT305X_GPIO_MODE_GPIO_I2S 6 +#define RT305X_GPIO_MODE_GPIO 7 + +#define RT305X_GPIO_MODE_I2C 0 +#define RT305X_GPIO_MODE_SPI 1 +#define RT305X_GPIO_MODE_UART1 5 +#define RT305X_GPIO_MODE_JTAG 6 +#define RT305X_GPIO_MODE_MDIO 7 +#define RT305X_GPIO_MODE_SDRAM 8 +#define RT305X_GPIO_MODE_RGMII 9 +#define RT5350_GPIO_MODE_PHY_LED 14 +#define RT5350_GPIO_MODE_SPI_CS1 21 +#define RT3352_GPIO_MODE_LNA 18 +#define RT3352_GPIO_MODE_PA 20 #define RT3352_SYSC_REG_SYSCFG0 0x010 #define RT3352_SYSC_REG_SYSCFG1 0x014 diff --git a/arch/mips/include/asm/mach-ralink/rt3883.h b/arch/mips/include/asm/mach-ralink/rt3883.h index 058382f..0fbe6f9 100644 --- a/arch/mips/include/asm/mach-ralink/rt3883.h +++ b/arch/mips/include/asm/mach-ralink/rt3883.h @@ -112,8 +112,6 @@ #define RT3883_CLKCFG1_PCI_CLK_EN BIT(19) #define RT3883_CLKCFG1_UPHY0_CLK_EN BIT(18) -#define RT3883_GPIO_MODE_I2C BIT(0) -#define RT3883_GPIO_MODE_SPI BIT(1) #define RT3883_GPIO_MODE_UART0_SHIFT 2 #define RT3883_GPIO_MODE_UART0_MASK 0x7 #define RT3883_GPIO_MODE_UART0(x) ((x) << RT3883_GPIO_MODE_UART0_SHIFT) @@ -125,11 +123,15 @@ #define RT3883_GPIO_MODE_GPIO_UARTF 0x5 #define RT3883_GPIO_MODE_GPIO_I2S 0x6 #define RT3883_GPIO_MODE_GPIO 0x7 -#define RT3883_GPIO_MODE_UART1 BIT(5) -#define RT3883_GPIO_MODE_JTAG BIT(6) -#define RT3883_GPIO_MODE_MDIO BIT(7) -#define RT3883_GPIO_MODE_GE1 BIT(9) -#define RT3883_GPIO_MODE_GE2 BIT(10) + +#define RT3883_GPIO_MODE_I2C 0 +#define RT3883_GPIO_MODE_SPI 1 +#define RT3883_GPIO_MODE_UART1 5 +#define RT3883_GPIO_MODE_JTAG 6 +#define RT3883_GPIO_MODE_MDIO 7 +#define RT3883_GPIO_MODE_GE1 9 +#define RT3883_GPIO_MODE_GE2 10 + #define RT3883_GPIO_MODE_PCI_SHIFT 11 #define RT3883_GPIO_MODE_PCI_MASK 0x7 #define RT3883_GPIO_MODE_PCI (RT3883_GPIO_MODE_PCI_MASK << RT3883_GPIO_MODE_PCI_SHIFT) diff --git a/arch/mips/include/asm/mach-sead3/irq.h b/arch/mips/include/asm/mach-sead3/irq.h index d8106f7..5d154cf 100644 --- a/arch/mips/include/asm/mach-sead3/irq.h +++ b/arch/mips/include/asm/mach-sead3/irq.h @@ -1,7 +1,6 @@ #ifndef __ASM_MACH_MIPS_IRQ_H #define __ASM_MACH_MIPS_IRQ_H -#define GIC_NUM_INTRS (24 + NR_CPUS * 2) #define NR_IRQS 256 diff --git a/arch/mips/include/asm/mach-tx39xx/ioremap.h b/arch/mips/include/asm/mach-tx39xx/ioremap.h index 93c6c04..0874cd2 100644 --- a/arch/mips/include/asm/mach-tx39xx/ioremap.h +++ b/arch/mips/include/asm/mach-tx39xx/ioremap.h @@ -15,12 +15,12 @@ * Allow physical addresses to be fixed up to help peripherals located * outside the low 32-bit range -- generic pass-through version. */ -static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) { return phys_addr; } -static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size, +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, unsigned long flags) { #define TXX9_DIRECTMAP_BASE 0xff000000ul diff --git a/arch/mips/include/asm/mach-tx49xx/ioremap.h b/arch/mips/include/asm/mach-tx49xx/ioremap.h index 1e7beae..4b6a8441 100644 --- a/arch/mips/include/asm/mach-tx49xx/ioremap.h +++ b/arch/mips/include/asm/mach-tx49xx/ioremap.h @@ -15,12 +15,12 @@ * Allow physical addresses to be fixed up to help peripherals located * outside the low 32-bit range -- generic pass-through version. */ -static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) { return phys_addr; } -static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size, +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, unsigned long flags) { #ifdef CONFIG_64BIT diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h index e330732..987ff58 100644 --- a/arch/mips/include/asm/mips-boards/maltaint.h +++ b/arch/mips/include/asm/mips-boards/maltaint.h @@ -10,7 +10,7 @@ #ifndef _MIPS_MALTAINT_H #define _MIPS_MALTAINT_H -#define MIPS_GIC_IRQ_BASE (MIPS_CPU_IRQ_BASE + 8) +#include <linux/irqchip/mips-gic.h> /* * Interrupts 0..15 are used for Malta ISA compatible interrupts @@ -22,29 +22,28 @@ #define MIPSCPU_INT_SW1 1 #define MIPSCPU_INT_MB0 2 #define MIPSCPU_INT_I8259A MIPSCPU_INT_MB0 +#define MIPSCPU_INT_GIC MIPSCPU_INT_MB0 /* GIC chained interrupt */ #define MIPSCPU_INT_MB1 3 #define MIPSCPU_INT_SMI MIPSCPU_INT_MB1 -#define MIPSCPU_INT_IPI0 MIPSCPU_INT_MB1 /* GIC IPI */ #define MIPSCPU_INT_MB2 4 -#define MIPSCPU_INT_IPI1 MIPSCPU_INT_MB2 /* GIC IPI */ #define MIPSCPU_INT_MB3 5 #define MIPSCPU_INT_COREHI MIPSCPU_INT_MB3 #define MIPSCPU_INT_MB4 6 #define MIPSCPU_INT_CORELO MIPSCPU_INT_MB4 /* - * Interrupts 64..127 are used for Soc-it Classic interrupts + * Interrupts 96..127 are used for Soc-it Classic interrupts */ -#define MSC01C_INT_BASE 64 +#define MSC01C_INT_BASE 96 /* SOC-it Classic interrupt offsets */ #define MSC01C_INT_TMR 0 #define MSC01C_INT_PCI 1 /* - * Interrupts 64..127 are used for Soc-it EIC interrupts + * Interrupts 96..127 are used for Soc-it EIC interrupts */ -#define MSC01E_INT_BASE 64 +#define MSC01E_INT_BASE 96 /* SOC-it EIC interrupt offsets */ #define MSC01E_INT_SW0 1 @@ -63,14 +62,7 @@ #define MSC01E_INT_PERFCTR 10 #define MSC01E_INT_CPUCTR 11 -/* External Interrupts used for IPI */ -#define GIC_IPI_EXT_INTR_RESCHED_VPE0 16 -#define GIC_IPI_EXT_INTR_CALLFNC_VPE0 17 -#define GIC_IPI_EXT_INTR_RESCHED_VPE1 18 -#define GIC_IPI_EXT_INTR_CALLFNC_VPE1 19 -#define GIC_IPI_EXT_INTR_RESCHED_VPE2 20 -#define GIC_IPI_EXT_INTR_CALLFNC_VPE2 21 -#define GIC_IPI_EXT_INTR_RESCHED_VPE3 22 -#define GIC_IPI_EXT_INTR_CALLFNC_VPE3 23 +/* GIC external interrupts */ +#define GIC_INT_I8259A GIC_SHARED_TO_HWIRQ(3) #endif /* !(_MIPS_MALTAINT_H) */ diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h index 6b17aaf..8932c7d 100644 --- a/arch/mips/include/asm/mips-boards/sead3int.h +++ b/arch/mips/include/asm/mips-boards/sead3int.h @@ -10,10 +10,23 @@ #ifndef _MIPS_SEAD3INT_H #define _MIPS_SEAD3INT_H +#include <linux/irqchip/mips-gic.h> + /* SEAD-3 GIC address space definitions. */ #define GIC_BASE_ADDR 0x1b1c0000 #define GIC_ADDRSPACE_SZ (128 * 1024) -#define MIPS_GIC_IRQ_BASE (MIPS_CPU_IRQ_BASE + 0) +/* CPU interrupt offsets */ +#define CPU_INT_GIC 2 +#define CPU_INT_EHCI 2 +#define CPU_INT_UART0 4 +#define CPU_INT_UART1 4 +#define CPU_INT_NET 6 + +/* GIC interrupt offsets */ +#define GIC_INT_NET GIC_SHARED_TO_HWIRQ(0) +#define GIC_INT_UART1 GIC_SHARED_TO_HWIRQ(2) +#define GIC_INT_UART0 GIC_SHARED_TO_HWIRQ(3) +#define GIC_INT_EHCI GIC_SHARED_TO_HWIRQ(5) #endif /* !(_MIPS_SEAD3INT_H) */ diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 6a9d2dd..b95a827 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -30,7 +30,7 @@ extern void __iomem *mips_cm_l2sync_base; * different way by defining a function with the same prototype except for the * name mips_cm_phys_base (without underscores). */ -extern phys_t __mips_cm_phys_base(void); +extern phys_addr_t __mips_cm_phys_base(void); /** * mips_cm_probe - probe for a Coherence Manager diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index e139a53..1cebe8c 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h @@ -25,7 +25,7 @@ extern void __iomem *mips_cpc_base; * memory mapped registers. This is platform dependant & must therefore be * implemented per-platform. */ -extern phys_t mips_cpc_default_phys_base(void); +extern phys_addr_t mips_cpc_default_phys_base(void); /** * mips_cpc_phys_base - retrieve the physical base address of the CPC @@ -35,7 +35,7 @@ extern phys_t mips_cpc_default_phys_base(void); * is present. It may be overriden by individual platforms which determine * this address in a different way. */ -extern phys_t __weak mips_cpc_phys_base(void); +extern phys_addr_t __weak mips_cpc_phys_base(void); /** * mips_cpc_probe - probe for a Cluster Power Controller diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 22a135a..5e4aef3 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -653,6 +653,9 @@ #define MIPS_CONF5_NF (_ULCAST_(1) << 0) #define MIPS_CONF5_UFR (_ULCAST_(1) << 2) #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) +#define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_FRE (_ULCAST_(1) << 8) +#define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27) #define MIPS_CONF5_EVA (_ULCAST_(1) << 28) #define MIPS_CONF5_CV (_ULCAST_(1) << 29) @@ -694,6 +697,7 @@ #define MIPS_FPIR_W (_ULCAST_(1) << 20) #define MIPS_FPIR_L (_ULCAST_(1) << 21) #define MIPS_FPIR_F64 (_ULCAST_(1) << 22) +#define MIPS_FPIR_FREP (_ULCAST_(1) << 29) /* * Bits in the MIPS32 Memory Segmentation registers. @@ -994,6 +998,39 @@ do { \ local_irq_restore(__flags); \ } while (0) +#define __readx_32bit_c0_register(source) \ +({ \ + unsigned int __res; \ + \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " .set mips32r2 \n" \ + " .insn \n" \ + " # mfhc0 $1, %1 \n" \ + " .word (0x40410000 | ((%1 & 0x1f) << 11)) \n" \ + " move %0, $1 \n" \ + " .set pop \n" \ + : "=r" (__res) \ + : "i" (source)); \ + __res; \ +}) + +#define __writex_32bit_c0_register(register, value) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set noat \n" \ + " .set mips32r2 \n" \ + " move $1, %0 \n" \ + " # mthc0 $1, %1 \n" \ + " .insn \n" \ + " .word (0x40c10000 | ((%1 & 0x1f) << 11)) \n" \ + " .set pop \n" \ + : \ + : "r" (value), "i" (register)); \ +} while (0) + #define read_c0_index() __read_32bit_c0_register($0, 0) #define write_c0_index(val) __write_32bit_c0_register($0, 0, val) @@ -1003,9 +1040,15 @@ do { \ #define read_c0_entrylo0() __read_ulong_c0_register($2, 0) #define write_c0_entrylo0(val) __write_ulong_c0_register($2, 0, val) +#define readx_c0_entrylo0() __readx_32bit_c0_register(2) +#define writex_c0_entrylo0(val) __writex_32bit_c0_register(2, val) + #define read_c0_entrylo1() __read_ulong_c0_register($3, 0) #define write_c0_entrylo1(val) __write_ulong_c0_register($3, 0, val) +#define readx_c0_entrylo1() __readx_32bit_c0_register(3) +#define writex_c0_entrylo1(val) __writex_32bit_c0_register(3, val) + #define read_c0_conf() __read_32bit_c0_register($3, 0) #define write_c0_conf(val) __write_32bit_c0_register($3, 0, val) diff --git a/arch/mips/include/asm/octeon/cvmx-cmd-queue.h b/arch/mips/include/asm/octeon/cvmx-cmd-queue.h index 024a71b..75739c8 100644 --- a/arch/mips/include/asm/octeon/cvmx-cmd-queue.h +++ b/arch/mips/include/asm/octeon/cvmx-cmd-queue.h @@ -76,6 +76,8 @@ #include <linux/prefetch.h> +#include <asm/compiler.h> + #include <asm/octeon/cvmx-fpa.h> /** * By default we disable the max depth support. Most programs @@ -273,7 +275,7 @@ static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t queue_id, " lbu %[ticket], %[now_serving]\n" "4:\n" ".set pop\n" : - [ticket_ptr] "=m"(__cvmx_cmd_queue_state_ptr->ticket[__cvmx_cmd_queue_get_index(queue_id)]), + [ticket_ptr] "=" GCC_OFF12_ASM()(__cvmx_cmd_queue_state_ptr->ticket[__cvmx_cmd_queue_get_index(queue_id)]), [now_serving] "=m"(qptr->now_serving), [ticket] "=r"(tmp), [my_ticket] "=r"(my_ticket) ); diff --git a/arch/mips/include/asm/octeon/cvmx-pow.h b/arch/mips/include/asm/octeon/cvmx-pow.h index 4b4d0ec..2188e65 100644 --- a/arch/mips/include/asm/octeon/cvmx-pow.h +++ b/arch/mips/include/asm/octeon/cvmx-pow.h @@ -1066,7 +1066,7 @@ static inline void __cvmx_pow_warn_if_pending_switch(const char *function) uint64_t switch_complete; CVMX_MF_CHORD(switch_complete); if (!switch_complete) - pr_warning("%s called with tag switch in progress\n", function); + pr_warn("%s called with tag switch in progress\n", function); } /** @@ -1084,8 +1084,7 @@ static inline void cvmx_pow_tag_sw_wait(void) if (unlikely(switch_complete)) break; if (unlikely(cvmx_get_cycle() > start_cycle + MAX_CYCLES)) { - pr_warning("Tag switch is taking a long time, " - "possible deadlock\n"); + pr_warn("Tag switch is taking a long time, possible deadlock\n"); start_cycle = -MAX_CYCLES - 1; } } @@ -1296,19 +1295,16 @@ static inline void cvmx_pow_tag_sw_nocheck(uint32_t tag, __cvmx_pow_warn_if_pending_switch(__func__); current_tag = cvmx_pow_get_current_tag(); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); + pr_warn("%s called with NULL_NULL tag\n", __func__); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called with NULL tag\n", __func__); + pr_warn("%s called with NULL tag\n", __func__); if ((current_tag.s.type == tag_type) && (current_tag.s.tag == tag)) - pr_warning("%s called to perform a tag switch to the " - "same tag\n", - __func__); + pr_warn("%s called to perform a tag switch to the same tag\n", + __func__); if (tag_type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called to perform a tag switch to " - "NULL. Use cvmx_pow_tag_sw_null() instead\n", - __func__); + pr_warn("%s called to perform a tag switch to NULL. Use cvmx_pow_tag_sw_null() instead\n", + __func__); } /* @@ -1407,23 +1403,19 @@ static inline void cvmx_pow_tag_sw_full_nocheck(cvmx_wqe_t *wqp, uint32_t tag, __cvmx_pow_warn_if_pending_switch(__func__); current_tag = cvmx_pow_get_current_tag(); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); + pr_warn("%s called with NULL_NULL tag\n", __func__); if ((current_tag.s.type == tag_type) && (current_tag.s.tag == tag)) - pr_warning("%s called to perform a tag switch to " - "the same tag\n", - __func__); + pr_warn("%s called to perform a tag switch to the same tag\n", + __func__); if (tag_type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called to perform a tag switch to " - "NULL. Use cvmx_pow_tag_sw_null() instead\n", - __func__); + pr_warn("%s called to perform a tag switch to NULL. Use cvmx_pow_tag_sw_null() instead\n", + __func__); if (wqp != cvmx_phys_to_ptr(0x80)) if (wqp != cvmx_pow_get_current_wqp()) - pr_warning("%s passed WQE(%p) doesn't match " - "the address in the POW(%p)\n", - __func__, wqp, - cvmx_pow_get_current_wqp()); + pr_warn("%s passed WQE(%p) doesn't match the address in the POW(%p)\n", + __func__, wqp, + cvmx_pow_get_current_wqp()); } /* @@ -1507,12 +1499,10 @@ static inline void cvmx_pow_tag_sw_null_nocheck(void) __cvmx_pow_warn_if_pending_switch(__func__); current_tag = cvmx_pow_get_current_tag(); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); + pr_warn("%s called with NULL_NULL tag\n", __func__); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called when we already have a " - "NULL tag\n", - __func__); + pr_warn("%s called when we already have a NULL tag\n", + __func__); } tag_req.u64 = 0; @@ -1725,17 +1715,14 @@ static inline void cvmx_pow_tag_sw_desched_nocheck( __cvmx_pow_warn_if_pending_switch(__func__); current_tag = cvmx_pow_get_current_tag(); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); + pr_warn("%s called with NULL_NULL tag\n", __func__); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called with NULL tag. Deschedule not " - "allowed from NULL state\n", - __func__); + pr_warn("%s called with NULL tag. Deschedule not allowed from NULL state\n", + __func__); if ((current_tag.s.type != CVMX_POW_TAG_TYPE_ATOMIC) && (tag_type != CVMX_POW_TAG_TYPE_ATOMIC)) - pr_warning("%s called where neither the before or " - "after tag is ATOMIC\n", - __func__); + pr_warn("%s called where neither the before or after tag is ATOMIC\n", + __func__); } tag_req.u64 = 0; @@ -1832,12 +1819,10 @@ static inline void cvmx_pow_desched(uint64_t no_sched) __cvmx_pow_warn_if_pending_switch(__func__); current_tag = cvmx_pow_get_current_tag(); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); + pr_warn("%s called with NULL_NULL tag\n", __func__); if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called with NULL tag. Deschedule not " - "expected from NULL state\n", - __func__); + pr_warn("%s called with NULL tag. Deschedule not expected from NULL state\n", + __func__); } /* Need to make sure any writes to the work queue entry are complete */ diff --git a/arch/mips/include/asm/octeon/cvmx.h b/arch/mips/include/asm/octeon/cvmx.h index f991e77..33db1c8 100644 --- a/arch/mips/include/asm/octeon/cvmx.h +++ b/arch/mips/include/asm/octeon/cvmx.h @@ -451,67 +451,4 @@ static inline uint32_t cvmx_octeon_num_cores(void) return cvmx_pop(ciu_fuse); } -/** - * Read a byte of fuse data - * @byte_addr: address to read - * - * Returns fuse value: 0 or 1 - */ -static uint8_t cvmx_fuse_read_byte(int byte_addr) -{ - union cvmx_mio_fus_rcmd read_cmd; - - read_cmd.u64 = 0; - read_cmd.s.addr = byte_addr; - read_cmd.s.pend = 1; - cvmx_write_csr(CVMX_MIO_FUS_RCMD, read_cmd.u64); - while ((read_cmd.u64 = cvmx_read_csr(CVMX_MIO_FUS_RCMD)) - && read_cmd.s.pend) - ; - return read_cmd.s.dat; -} - -/** - * Read a single fuse bit - * - * @fuse: Fuse number (0-1024) - * - * Returns fuse value: 0 or 1 - */ -static inline int cvmx_fuse_read(int fuse) -{ - return (cvmx_fuse_read_byte(fuse >> 3) >> (fuse & 0x7)) & 1; -} - -static inline int cvmx_octeon_model_CN36XX(void) -{ - return OCTEON_IS_MODEL(OCTEON_CN38XX) - && !cvmx_octeon_is_pass1() - && cvmx_fuse_read(264); -} - -static inline int cvmx_octeon_zip_present(void) -{ - return octeon_has_feature(OCTEON_FEATURE_ZIP); -} - -static inline int cvmx_octeon_dfa_present(void) -{ - if (!OCTEON_IS_MODEL(OCTEON_CN38XX) - && !OCTEON_IS_MODEL(OCTEON_CN31XX) - && !OCTEON_IS_MODEL(OCTEON_CN58XX)) - return 0; - else if (OCTEON_IS_MODEL(OCTEON_CN3020)) - return 0; - else if (cvmx_octeon_is_pass1()) - return 1; - else - return !cvmx_fuse_read(120); -} - -static inline int cvmx_octeon_crypto_present(void) -{ - return octeon_has_feature(OCTEON_FEATURE_CRYPTO); -} - #endif /* __CVMX_H__ */ diff --git a/arch/mips/include/asm/octeon/octeon-feature.h b/arch/mips/include/asm/octeon/octeon-feature.h index 90e05a8..c4fe81f 100644 --- a/arch/mips/include/asm/octeon/octeon-feature.h +++ b/arch/mips/include/asm/octeon/octeon-feature.h @@ -86,8 +86,6 @@ enum octeon_feature { OCTEON_MAX_FEATURE }; -static inline int cvmx_fuse_read(int fuse); - /** * Determine if the current Octeon supports a specific feature. These * checks have been optimized to be fairly quick, but they should still @@ -105,33 +103,6 @@ static inline int octeon_has_feature(enum octeon_feature feature) case OCTEON_FEATURE_SAAD: return !OCTEON_IS_MODEL(OCTEON_CN3XXX); - case OCTEON_FEATURE_ZIP: - if (OCTEON_IS_MODEL(OCTEON_CN30XX) - || OCTEON_IS_MODEL(OCTEON_CN50XX) - || OCTEON_IS_MODEL(OCTEON_CN52XX)) - return 0; - else if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS1)) - return 1; - else - return !cvmx_fuse_read(121); - - case OCTEON_FEATURE_CRYPTO: - if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { - union cvmx_mio_fus_dat2 fus_2; - fus_2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); - if (fus_2.s.nocrypto || fus_2.s.nomul) { - return 0; - } else if (!fus_2.s.dorm_crypto) { - return 1; - } else { - union cvmx_rnm_ctl_status st; - st.u64 = cvmx_read_csr(CVMX_RNM_CTL_STATUS); - return st.s.eer_val; - } - } else { - return !cvmx_fuse_read(90); - } - case OCTEON_FEATURE_DORM_CRYPTO: if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { union cvmx_mio_fus_dat2 fus_2; @@ -188,29 +159,6 @@ static inline int octeon_has_feature(enum octeon_feature feature) && !OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X); - case OCTEON_FEATURE_DFA: - if (!OCTEON_IS_MODEL(OCTEON_CN38XX) - && !OCTEON_IS_MODEL(OCTEON_CN31XX) - && !OCTEON_IS_MODEL(OCTEON_CN58XX)) - return 0; - else if (OCTEON_IS_MODEL(OCTEON_CN3020)) - return 0; - else - return !cvmx_fuse_read(120); - - case OCTEON_FEATURE_HFA: - if (!OCTEON_IS_MODEL(OCTEON_CN6XXX)) - return 0; - else - return !cvmx_fuse_read(90); - - case OCTEON_FEATURE_DFM: - if (!(OCTEON_IS_MODEL(OCTEON_CN63XX) - || OCTEON_IS_MODEL(OCTEON_CN66XX))) - return 0; - else - return !cvmx_fuse_read(90); - case OCTEON_FEATURE_MDIO_CLAUSE_45: return !(OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) diff --git a/arch/mips/include/asm/octeon/octeon-model.h b/arch/mips/include/asm/octeon/octeon-model.h index e2c122c..e8a1c2f 100644 --- a/arch/mips/include/asm/octeon/octeon-model.h +++ b/arch/mips/include/asm/octeon/octeon-model.h @@ -326,8 +326,7 @@ static inline int __octeon_is_model_runtime__(uint32_t model) #define OCTEON_IS_COMMON_BINARY() 1 #undef OCTEON_MODEL -const char *octeon_model_get_string(uint32_t chip_id); -const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer); +const char *__init octeon_model_get_string(uint32_t chip_id); /* * Return the octeon family, i.e., ProcessorID of the PrID register. diff --git a/arch/mips/include/asm/paccess.h b/arch/mips/include/asm/paccess.h index 2474fc5..af81ab0 100644 --- a/arch/mips/include/asm/paccess.h +++ b/arch/mips/include/asm/paccess.h @@ -56,6 +56,7 @@ struct __large_pstruct { unsigned long buf[100]; }; "1:\t" insn "\t%1,%2\n\t" \ "move\t%0,$0\n" \ "2:\n\t" \ + ".insn\n\t" \ ".section\t.fixup,\"ax\"\n" \ "3:\tli\t%0,%3\n\t" \ "move\t%1,$0\n\t" \ @@ -94,6 +95,7 @@ extern void __get_dbe_unknown(void); "1:\t" insn "\t%1,%2\n\t" \ "move\t%0,$0\n" \ "2:\n\t" \ + ".insn\n\t" \ ".section\t.fixup,\"ax\"\n" \ "3:\tli\t%0,%3\n\t" \ "j\t2b\n\t" \ diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index 3be8180..154b70a 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -116,7 +116,7 @@ extern void copy_user_highpage(struct page *to, struct page *from, /* * These are used to make use of C type-checking.. */ -#ifdef CONFIG_64BIT_PHYS_ADDR +#ifdef CONFIG_PHYS_ADDR_T_64BIT #ifdef CONFIG_CPU_MIPS32 typedef struct { unsigned long pte_low, pte_high; } pte_t; #define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 974b0e3..6952962 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -84,7 +84,7 @@ static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, const struct resource *rsrc, resource_size_t *start, resource_size_t *end) { - phys_t size = resource_size(rsrc); + phys_addr_t size = resource_size(rsrc); *start = fixup_bigphys_addr(rsrc->start, size); *end = rsrc->start + size; diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h index cd7d606..68984b6 100644 --- a/arch/mips/include/asm/pgtable-32.h +++ b/arch/mips/include/asm/pgtable-32.h @@ -69,7 +69,7 @@ extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, # define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) #endif -#ifdef CONFIG_64BIT_PHYS_ADDR +#ifdef CONFIG_PHYS_ADDR_T_64BIT #define pte_ERROR(e) \ printk("%s:%d: bad pte %016Lx.\n", __FILE__, __LINE__, pte_val(e)) #else @@ -103,7 +103,7 @@ static inline void pmd_clear(pmd_t *pmdp) pmd_val(*pmdp) = ((unsigned long) invalid_pte_table); } -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#if 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 @@ -126,7 +126,7 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #define pte_pfn(x) ((unsigned long)((x).pte >> _PFN_SHIFT)) #define pfn_pte(pfn, prot) __pte(((unsigned long long)(pfn) << _PFN_SHIFT) | pgprot_val(prot)) #endif -#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */ +#endif /* defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) */ #define __pgd_offset(address) pgd_index(address) #define __pud_offset(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) @@ -155,73 +155,75 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) /* Swap entries must have VALID bit cleared. */ -#define __swp_type(x) (((x).val >> 10) & 0x1f) -#define __swp_offset(x) ((x).val >> 15) -#define __swp_entry(type,offset) \ - ((swp_entry_t) { ((type) << 10) | ((offset) << 15) }) +#define __swp_type(x) (((x).val >> 10) & 0x1f) +#define __swp_offset(x) ((x).val >> 15) +#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 10) | ((offset) << 15) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) /* - * Bits 0, 4, 8, and 9 are taken, split up 28 bits of offset into this range: + * Encode and decode a nonlinear file mapping entry */ -#define PTE_FILE_MAX_BITS 28 - -#define pte_to_pgoff(_pte) ((((_pte).pte >> 1 ) & 0x07) | \ - (((_pte).pte >> 2 ) & 0x38) | \ - (((_pte).pte >> 10) << 6 )) +#define pte_to_pgoff(_pte) ((((_pte).pte >> 1 ) & 0x07) | \ + (((_pte).pte >> 2 ) & 0x38) | \ + (((_pte).pte >> 10) << 6 )) -#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x07) << 1 ) | \ - (((off) & 0x38) << 2 ) | \ - (((off) >> 6 ) << 10) | \ - _PAGE_FILE }) +#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x07) << 1 ) | \ + (((off) & 0x38) << 2 ) | \ + (((off) >> 6 ) << 10) | \ + _PAGE_FILE }) +/* + * Bits 0, 4, 8, and 9 are taken, split up 28 bits of offset into this range: + */ +#define PTE_FILE_MAX_BITS 28 #else +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) + /* Swap entries must have VALID and GLOBAL bits cleared. */ -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) -#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) }) -#else -#define __swp_type(x) (((x).val >> 8) & 0x1f) -#define __swp_offset(x) ((x).val >> 13) -#define __swp_entry(type,offset) \ - ((swp_entry_t) { ((type) << 8) | ((offset) << 13) }) -#endif /* defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) */ +#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 }) -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) /* * Bits 0 and 1 of pte_high are taken, use the rest for the page offset... */ -#define PTE_FILE_MAX_BITS 30 - -#define pte_to_pgoff(_pte) ((_pte).pte_high >> 2) -#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) << 2 }) +#define pte_to_pgoff(_pte) ((_pte).pte_high >> 2) +#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) << 2 }) +#define PTE_FILE_MAX_BITS 30 #else /* - * Bits 0, 4, 6, and 7 are taken, split up 28 bits of offset into this range: + * Constraints: + * _PAGE_PRESENT at bit 0 + * _PAGE_MODIFIED at bit 4 + * _PAGE_GLOBAL at bit 6 + * _PAGE_VALID at bit 7 */ -#define PTE_FILE_MAX_BITS 28 +#define __swp_type(x) (((x).val >> 8) & 0x1f) +#define __swp_offset(x) ((x).val >> 13) +#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 8) | ((offset) << 13) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#define pte_to_pgoff(_pte) ((((_pte).pte >> 1) & 0x7) | \ - (((_pte).pte >> 2) & 0x8) | \ - (((_pte).pte >> 8) << 4)) +/* + * Encode and decode a nonlinear file mapping entry + */ +#define pte_to_pgoff(_pte) ((((_pte).pte >> 1) & 0x7) | \ + (((_pte).pte >> 2) & 0x8) | \ + (((_pte).pte >> 8) << 4)) -#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x7) << 1) | \ - (((off) & 0x8) << 2) | \ - (((off) >> 4) << 8) | \ - _PAGE_FILE }) -#endif +#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x7) << 1) | \ + (((off) & 0x8) << 2) | \ + (((off) >> 4) << 8) | \ + _PAGE_FILE }) -#endif +#define PTE_FILE_MAX_BITS 28 +#endif /* defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) */ -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) -#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high }) -#define __swp_entry_to_pte(x) ((pte_t) { 0, (x).val }) -#else -#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#endif +#endif /* defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) */ #endif /* _ASM_PGTABLE_32_H */ diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index e747bfa..ca11f14 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -32,39 +32,41 @@ * 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_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) /* * The following bits are directly used by the TLB hardware */ -#define _PAGE_R4KBUG (1 << 0) /* workaround for r4k bug */ -#define _PAGE_GLOBAL (1 << 0) -#define _PAGE_VALID_SHIFT 1 +#define _PAGE_GLOBAL_SHIFT 0 +#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) +#define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) #define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -#define _PAGE_SILENT_READ (1 << 1) /* synonym */ -#define _PAGE_DIRTY_SHIFT 2 -#define _PAGE_DIRTY (1 << _PAGE_DIRTY_SHIFT) /* The MIPS dirty bit */ -#define _PAGE_SILENT_WRITE (1 << 2) -#define _CACHE_SHIFT 3 -#define _CACHE_MASK (7 << 3) +#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 * * _PAGE_FILE semantics: set:pagecache unset:swap */ -#define _PAGE_PRESENT_SHIFT 6 +#define _PAGE_PRESENT_SHIFT (_CACHE_SHIFT + 3) #define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) -#define _PAGE_READ_SHIFT 7 +#define _PAGE_READ_SHIFT (_PAGE_PRESENT_SHIFT + 1) #define _PAGE_READ (1 << _PAGE_READ_SHIFT) -#define _PAGE_WRITE_SHIFT 8 +#define _PAGE_WRITE_SHIFT (_PAGE_READ_SHIFT + 1) #define _PAGE_WRITE (1 << _PAGE_WRITE_SHIFT) -#define _PAGE_ACCESSED_SHIFT 9 +#define _PAGE_ACCESSED_SHIFT (_PAGE_WRITE_SHIFT + 1) #define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) -#define _PAGE_MODIFIED_SHIFT 10 +#define _PAGE_MODIFIED_SHIFT (_PAGE_ACCESSED_SHIFT + 1) #define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) -#define _PAGE_FILE (1 << 10) +#define _PAGE_SILENT_READ _PAGE_VALID +#define _PAGE_SILENT_WRITE _PAGE_DIRTY +#define _PAGE_FILE _PAGE_MODIFIED + +#define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) #elif defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) @@ -172,7 +174,7 @@ #define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) -#endif /* defined(CONFIG_64BIT_PHYS_ADDR && defined(CONFIG_CPU_MIPS32) */ +#endif /* defined(CONFIG_PHYS_ADDR_T_64BIT && defined(CONFIG_CPU_MIPS32) */ #ifndef _PFN_SHIFT #define _PFN_SHIFT PAGE_SHIFT diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index d6d1928..62a6ba3 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -125,7 +125,7 @@ do { \ extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval); -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) #define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL)) #define pte_present(pte) ((pte).pte_low & _PAGE_PRESENT) @@ -227,7 +227,7 @@ extern pgd_t swapper_pg_dir[]; * The following only work if pte_present() is true. * Undefined behaviour if not.. */ -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) static inline int pte_write(pte_t pte) { return pte.pte_low & _PAGE_WRITE; } static inline int pte_dirty(pte_t pte) { return pte.pte_low & _PAGE_MODIFIED; } static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; } @@ -297,13 +297,13 @@ static inline pte_t pte_wrprotect(pte_t pte) static inline pte_t pte_mkclean(pte_t pte) { - pte_val(pte) &= ~(_PAGE_MODIFIED|_PAGE_SILENT_WRITE); + pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); return pte; } static inline pte_t pte_mkold(pte_t pte) { - pte_val(pte) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ); + pte_val(pte) &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ); return pte; } @@ -382,13 +382,13 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot) */ #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#if 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 &= ~0x3f; + pte.pte_high &= (_PFN_MASK | _CACHE_MASK); pte.pte_low |= pgprot_val(newprot); - pte.pte_high |= pgprot_val(newprot) & 0x3f; + pte.pte_high |= pgprot_val(newprot) & ~(_PFN_MASK | _CACHE_MASK); return pte; } #else @@ -419,7 +419,7 @@ static inline void update_mmu_cache_pmd(struct vm_area_struct *vma, #define kern_addr_valid(addr) (1) -#ifdef CONFIG_64BIT_PHYS_ADDR +#ifdef CONFIG_PHYS_ADDR_T_64BIT extern int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot); static inline int io_remap_pfn_range(struct vm_area_struct *vma, @@ -428,7 +428,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long size, pgprot_t prot) { - phys_t phys_addr_high = fixup_bigphys_addr(pfn << PAGE_SHIFT, size); + phys_addr_t phys_addr_high = fixup_bigphys_addr(pfn << PAGE_SHIFT, size); return remap_pfn_range(vma, vaddr, phys_addr_high >> PAGE_SHIFT, size, prot); } #define io_remap_pfn_range io_remap_pfn_range diff --git a/arch/mips/include/asm/prom.h b/arch/mips/include/asm/prom.h index a9494c0..eaa2627 100644 --- a/arch/mips/include/asm/prom.h +++ b/arch/mips/include/asm/prom.h @@ -22,6 +22,7 @@ extern void device_tree_init(void); struct boot_param_header; extern void __dt_setup_arch(void *bph); +extern int __dt_register_buses(const char *bus0, const char *bus1); #define dt_setup_arch(sym) \ ({ \ diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index cd6e0af..e293a8d 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h @@ -47,79 +47,20 @@ extern void (*r4k_blast_icache)(void); #ifdef CONFIG_MIPS_MT -/* - * Optionally force single-threaded execution during I-cache flushes. - */ -#define PROTECT_CACHE_FLUSHES 1 - -#ifdef PROTECT_CACHE_FLUSHES - -extern int mt_protiflush; -extern int mt_protdflush; -extern void mt_cflush_lockdown(void); -extern void mt_cflush_release(void); - -#define BEGIN_MT_IPROT \ - unsigned long flags = 0; \ - unsigned long mtflags = 0; \ - if(mt_protiflush) { \ - local_irq_save(flags); \ - ehb(); \ - mtflags = dvpe(); \ - mt_cflush_lockdown(); \ - } - -#define END_MT_IPROT \ - if(mt_protiflush) { \ - mt_cflush_release(); \ - evpe(mtflags); \ - local_irq_restore(flags); \ - } - -#define BEGIN_MT_DPROT \ - unsigned long flags = 0; \ - unsigned long mtflags = 0; \ - if(mt_protdflush) { \ - local_irq_save(flags); \ - ehb(); \ - mtflags = dvpe(); \ - mt_cflush_lockdown(); \ - } - -#define END_MT_DPROT \ - if(mt_protdflush) { \ - mt_cflush_release(); \ - evpe(mtflags); \ - local_irq_restore(flags); \ - } - -#else - -#define BEGIN_MT_IPROT -#define BEGIN_MT_DPROT -#define END_MT_IPROT -#define END_MT_DPROT - -#endif /* PROTECT_CACHE_FLUSHES */ - #define __iflush_prologue \ unsigned long redundance; \ extern int mt_n_iflushes; \ - BEGIN_MT_IPROT \ for (redundance = 0; redundance < mt_n_iflushes; redundance++) { #define __iflush_epilogue \ - END_MT_IPROT \ } #define __dflush_prologue \ unsigned long redundance; \ extern int mt_n_dflushes; \ - BEGIN_MT_DPROT \ for (redundance = 0; redundance < mt_n_dflushes; redundance++) { #define __dflush_epilogue \ - END_MT_DPROT \ } #define __inv_dflush_prologue __dflush_prologue diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h index 78d201f..c6d06d3 100644 --- a/arch/mips/include/asm/spinlock.h +++ b/arch/mips/include/asm/spinlock.h @@ -12,6 +12,7 @@ #include <linux/compiler.h> #include <asm/barrier.h> +#include <asm/compiler.h> #include <asm/war.h> /* @@ -88,7 +89,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) " subu %[ticket], %[ticket], 1 \n" " .previous \n" " .set pop \n" - : [ticket_ptr] "+m" (lock->lock), + : [ticket_ptr] "+" GCC_OFF12_ASM() (lock->lock), [serving_now_ptr] "+m" (lock->h.serving_now), [ticket] "=&r" (tmp), [my_ticket] "=&r" (my_ticket) @@ -121,7 +122,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) " subu %[ticket], %[ticket], 1 \n" " .previous \n" " .set pop \n" - : [ticket_ptr] "+m" (lock->lock), + : [ticket_ptr] "+" GCC_OFF12_ASM() (lock->lock), [serving_now_ptr] "+m" (lock->h.serving_now), [ticket] "=&r" (tmp), [my_ticket] "=&r" (my_ticket) @@ -163,7 +164,7 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock) " li %[ticket], 0 \n" " .previous \n" " .set pop \n" - : [ticket_ptr] "+m" (lock->lock), + : [ticket_ptr] "+" GCC_OFF12_ASM() (lock->lock), [ticket] "=&r" (tmp), [my_ticket] "=&r" (tmp2), [now_serving] "=&r" (tmp3) @@ -187,7 +188,7 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock) " li %[ticket], 0 \n" " .previous \n" " .set pop \n" - : [ticket_ptr] "+m" (lock->lock), + : [ticket_ptr] "+" GCC_OFF12_ASM() (lock->lock), [ticket] "=&r" (tmp), [my_ticket] "=&r" (tmp2), [now_serving] "=&r" (tmp3) @@ -234,8 +235,8 @@ static inline void arch_read_lock(arch_rwlock_t *rw) " beqzl %1, 1b \n" " nop \n" " .set reorder \n" - : "=m" (rw->lock), "=&r" (tmp) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } else { do { @@ -244,8 +245,8 @@ static inline void arch_read_lock(arch_rwlock_t *rw) " bltz %1, 1b \n" " addu %1, 1 \n" "2: sc %1, %0 \n" - : "=m" (rw->lock), "=&r" (tmp) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } while (unlikely(!tmp)); } @@ -268,8 +269,8 @@ static inline void arch_read_unlock(arch_rwlock_t *rw) " sub %1, 1 \n" " sc %1, %0 \n" " beqzl %1, 1b \n" - : "=m" (rw->lock), "=&r" (tmp) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } else { do { @@ -277,8 +278,8 @@ static inline void arch_read_unlock(arch_rwlock_t *rw) "1: ll %1, %2 # arch_read_unlock \n" " sub %1, 1 \n" " sc %1, %0 \n" - : "=m" (rw->lock), "=&r" (tmp) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } while (unlikely(!tmp)); } @@ -298,8 +299,8 @@ static inline void arch_write_lock(arch_rwlock_t *rw) " beqzl %1, 1b \n" " nop \n" " .set reorder \n" - : "=m" (rw->lock), "=&r" (tmp) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } else { do { @@ -308,8 +309,8 @@ static inline void arch_write_lock(arch_rwlock_t *rw) " bnez %1, 1b \n" " lui %1, 0x8000 \n" "2: sc %1, %0 \n" - : "=m" (rw->lock), "=&r" (tmp) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } while (unlikely(!tmp)); } @@ -348,8 +349,8 @@ static inline int arch_read_trylock(arch_rwlock_t *rw) __WEAK_LLSC_MB " li %2, 1 \n" "2: \n" - : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } else { __asm__ __volatile__( @@ -365,8 +366,8 @@ static inline int arch_read_trylock(arch_rwlock_t *rw) __WEAK_LLSC_MB " li %2, 1 \n" "2: \n" - : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } @@ -392,8 +393,8 @@ static inline int arch_write_trylock(arch_rwlock_t *rw) " li %2, 1 \n" " .set reorder \n" "2: \n" - : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } else { do { @@ -405,8 +406,9 @@ static inline int arch_write_trylock(arch_rwlock_t *rw) " sc %1, %0 \n" " li %2, 1 \n" "2: \n" - : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret) - : "m" (rw->lock) + : "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp), + "=&r" (ret) + : GCC_OFF12_ASM() (rw->lock) : "memory"); } while (unlikely(!tmp)); diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index 7de8658..99eea59 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -116,6 +116,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_LOAD_WATCH 25 /* If set, load watch registers */ #define TIF_SYSCALL_TRACEPOINT 26 /* syscall tracepoint instrumentation */ #define TIF_32BIT_FPREGS 27 /* 32-bit floating point registers */ +#define TIF_HYBRID_FPREGS 28 /* 64b FP registers, odd singles in bits 63:32 of even doubles */ #define TIF_USEDMSA 29 /* MSA has been used this quantum */ #define TIF_MSA_CTX_LIVE 30 /* MSA context must be preserved */ #define TIF_SYSCALL_TRACE 31 /* syscall trace active */ @@ -135,6 +136,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_FPUBOUND (1<<TIF_FPUBOUND) #define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH) #define _TIF_32BIT_FPREGS (1<<TIF_32BIT_FPREGS) +#define _TIF_HYBRID_FPREGS (1<<TIF_HYBRID_FPREGS) #define _TIF_USEDMSA (1<<TIF_USEDMSA) #define _TIF_MSA_CTX_LIVE (1<<TIF_MSA_CTX_LIVE) #define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h index 8f3047d..8ab2874 100644 --- a/arch/mips/include/asm/time.h +++ b/arch/mips/include/asm/time.h @@ -46,19 +46,17 @@ extern unsigned int mips_hpt_frequency; * so it lives here. */ extern int (*perf_irq)(void); +extern int __weak get_c0_perfcount_int(void); /* * Initialize the calling CPU's compare interrupt as clockevent device */ extern unsigned int __weak get_c0_compare_int(void); extern int r4k_clockevent_init(void); -extern int gic_clockevent_init(void); static inline int mips_clockevent_init(void) { -#if defined(CONFIG_CEVT_GIC) - return (gic_clockevent_init() | r4k_clockevent_init()); -#elif defined(CONFIG_CEVT_R4K) +#ifdef CONFIG_CEVT_R4K return r4k_clockevent_init(); #else return -ENXIO; diff --git a/arch/mips/include/asm/types.h b/arch/mips/include/asm/types.h index a845aaf..148d42a 100644 --- a/arch/mips/include/asm/types.h +++ b/arch/mips/include/asm/types.h @@ -11,23 +11,7 @@ #ifndef _ASM_TYPES_H #define _ASM_TYPES_H -# include <asm-generic/int-ll64.h> +#include <asm-generic/int-ll64.h> #include <uapi/asm/types.h> -/* - * These aren't exported outside the kernel to avoid name space clashes - */ -#ifndef __ASSEMBLY__ - -/* - * Don't use phys_t. You've been warned. - */ -#ifdef CONFIG_64BIT_PHYS_ADDR -typedef unsigned long long phys_t; -#else -typedef unsigned long phys_t; -#endif - -#endif /* __ASSEMBLY__ */ - #endif /* _ASM_TYPES_H */ diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index 22a5624..bf8b324 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h @@ -1325,33 +1325,6 @@ strncpy_from_user(char *__to, const char __user *__from, long __len) return res; } -/* Returns: 0 if bad, string length+1 (memory size) of string if ok */ -static inline long __strlen_user(const char __user *s) -{ - long res; - - if (segment_eq(get_fs(), get_ds())) { - __asm__ __volatile__( - "move\t$4, %1\n\t" - __MODULE_JAL(__strlen_kernel_nocheck_asm) - "move\t%0, $2" - : "=r" (res) - : "r" (s) - : "$2", "$4", __UA_t0, "$31"); - } else { - might_fault(); - __asm__ __volatile__( - "move\t$4, %1\n\t" - __MODULE_JAL(__strlen_user_nocheck_asm) - "move\t%0, $2" - : "=r" (res) - : "r" (s) - : "$2", "$4", __UA_t0, "$31"); - } - - return res; -} - /* * strlen_user: - Get the size of a string in user space. * @str: The string to measure. diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index 708c5d4..fc1cdd2 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h @@ -136,9 +136,11 @@ Ip_u1s2(_lui); Ip_u2s3u1(_lw); Ip_u3u1u2(_lwx); Ip_u1u2u3(_mfc0); +Ip_u1u2u3(_mfhc0); Ip_u1(_mfhi); Ip_u1(_mflo); Ip_u1u2u3(_mtc0); +Ip_u1u2u3(_mthc0); Ip_u3u1u2(_mul); Ip_u3u1u2(_or); Ip_u2u1u3(_ori); diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index 4bfdb9d..89c2243 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -108,9 +108,10 @@ enum rt_op { */ enum cop_op { mfc_op = 0x00, dmfc_op = 0x01, - cfc_op = 0x02, mfhc_op = 0x03, - mtc_op = 0x04, dmtc_op = 0x05, - ctc_op = 0x06, mthc_op = 0x07, + cfc_op = 0x02, mfhc0_op = 0x02, + mfhc_op = 0x03, mtc_op = 0x04, + dmtc_op = 0x05, ctc_op = 0x06, + mthc0_op = 0x06, mthc_op = 0x07, bc_op = 0x08, cop_op = 0x10, copm_op = 0x18 }; diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c index 76eafcb..ef796f9 100644 --- a/arch/mips/jz4740/setup.c +++ b/arch/mips/jz4740/setup.c @@ -32,7 +32,7 @@ static void __init jz4740_detect_mem(void) { void __iomem *jz_emc_base; u32 ctrl, bus, bank, rows, cols; - phys_t size; + phys_addr_t size; jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100); ctrl = readl(jz_emc_base + JZ4740_EMC_SDRAM_CTRL); diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 008a2fe..92987d1 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -4,9 +4,10 @@ extra-y := head.o vmlinux.lds -obj-y += cpu-probe.o branch.o entry.o genex.o idle.o irq.o process.o \ - prom.o ptrace.o reset.o setup.o signal.o syscall.o \ - time.o topology.o traps.o unaligned.o watch.o vdso.o +obj-y += cpu-probe.o branch.o elf.o entry.o genex.o idle.o irq.o \ + process.o prom.o ptrace.o reset.o setup.o signal.o \ + syscall.o time.o topology.o traps.o unaligned.o watch.o \ + vdso.o ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_ftrace.o = -pg @@ -18,12 +19,10 @@ endif obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o obj-$(CONFIG_CEVT_DS1287) += cevt-ds1287.o -obj-$(CONFIG_CEVT_GIC) += cevt-gic.o obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o -obj-$(CONFIG_CSRC_GIC) += csrc-gic.o obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o @@ -68,7 +67,6 @@ obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o obj-$(CONFIG_MIPS_MSC) += irq-msc01.o obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o -obj-$(CONFIG_IRQ_GIC) += irq-gic.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_32BIT) += scall32-o32.o diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c deleted file mode 100644 index 6093716..0000000 --- a/arch/mips/kernel/cevt-gic.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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) 2013 Imagination Technologies Ltd. - */ -#include <linux/clockchips.h> -#include <linux/interrupt.h> -#include <linux/percpu.h> -#include <linux/smp.h> -#include <linux/irq.h> - -#include <asm/time.h> -#include <asm/gic.h> -#include <asm/mips-boards/maltaint.h> - -DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device); -int gic_timer_irq_installed; - - -static int gic_next_event(unsigned long delta, struct clock_event_device *evt) -{ - u64 cnt; - int res; - - cnt = gic_read_count(); - cnt += (u64)delta; - gic_write_cpu_compare(cnt, cpumask_first(evt->cpumask)); - res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0; - return res; -} - -void gic_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - -irqreturn_t gic_compare_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *cd; - int cpu = smp_processor_id(); - - gic_write_compare(gic_read_compare()); - cd = &per_cpu(gic_clockevent_device, cpu); - cd->event_handler(cd); - return IRQ_HANDLED; -} - -struct irqaction gic_compare_irqaction = { - .handler = gic_compare_interrupt, - .flags = IRQF_PERCPU | IRQF_TIMER, - .name = "timer", -}; - - -void gic_event_handler(struct clock_event_device *dev) -{ -} - -int gic_clockevent_init(void) -{ - unsigned int cpu = smp_processor_id(); - struct clock_event_device *cd; - unsigned int irq; - - if (!cpu_has_counter || !gic_frequency) - return -ENXIO; - - irq = MIPS_GIC_IRQ_BASE; - - cd = &per_cpu(gic_clockevent_device, cpu); - - cd->name = "MIPS GIC"; - cd->features = CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_C3STOP; - - clockevent_set_clock(cd, gic_frequency); - - /* Calculate the min / max delta */ - cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); - cd->min_delta_ns = clockevent_delta2ns(0x300, cd); - - cd->rating = 300; - cd->irq = irq; - cd->cpumask = cpumask_of(cpu); - cd->set_next_event = gic_next_event; - cd->set_mode = gic_set_clock_mode; - cd->event_handler = gic_event_handler; - - clockevents_register_device(cd); - - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002); - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK); - - if (gic_timer_irq_installed) - return 0; - - gic_timer_irq_installed = 1; - - setup_irq(irq, &gic_compare_irqaction); - irq_set_handler(irq, handle_percpu_irq); - return 0; -} diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index bc127e2..6acaad0 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -11,10 +11,10 @@ #include <linux/percpu.h> #include <linux/smp.h> #include <linux/irq.h> +#include <linux/irqchip/mips-gic.h> #include <asm/time.h> #include <asm/cevt-r4k.h> -#include <asm/gic.h> static int mips_next_event(unsigned long delta, struct clock_event_device *evt) @@ -85,8 +85,8 @@ void mips_event_handler(struct clock_event_device *dev) */ static int c0_compare_int_pending(void) { -#ifdef CONFIG_IRQ_GIC - if (cpu_has_veic) +#ifdef CONFIG_MIPS_GIC + if (gic_present) return gic_get_timer_pending(); #endif return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP); diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index dc49cf3..5342674 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -69,6 +69,63 @@ static int __init htw_disable(char *s) __setup("nohtw", htw_disable); +static int mips_ftlb_disabled; +static int mips_has_ftlb_configured; + +static void set_ftlb_enable(struct cpuinfo_mips *c, int enable); + +static int __init ftlb_disable(char *s) +{ + unsigned int config4, mmuextdef; + + /* + * If the core hasn't done any FTLB configuration, there is nothing + * for us to do here. + */ + if (!mips_has_ftlb_configured) + return 1; + + /* Disable it in the boot cpu */ + set_ftlb_enable(&cpu_data[0], 0); + + back_to_back_c0_hazard(); + + config4 = read_c0_config4(); + + /* Check that FTLB has been disabled */ + mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; + /* MMUSIZEEXT == VTLB ON, FTLB OFF */ + if (mmuextdef == MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT) { + /* This should never happen */ + pr_warn("FTLB could not be disabled!\n"); + return 1; + } + + mips_ftlb_disabled = 1; + mips_has_ftlb_configured = 0; + + /* + * noftlb is mainly used for debug purposes so print + * an informative message instead of using pr_debug() + */ + pr_info("FTLB has been disabled\n"); + + /* + * Some of these bits are duplicated in the decode_config4. + * MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT is the only possible case + * once FTLB has been disabled so undo what decode_config4 did. + */ + cpu_data[0].tlbsize -= cpu_data[0].tlbsizeftlbways * + cpu_data[0].tlbsizeftlbsets; + cpu_data[0].tlbsizeftlbsets = 0; + cpu_data[0].tlbsizeftlbways = 0; + + return 1; +} + +__setup("noftlb", ftlb_disable); + + static inline void check_errata(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -140,7 +197,7 @@ static inline unsigned long cpu_get_fpu_id(void) */ static inline int __cpu_has_fpu(void) { - return ((cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE); + return (cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE; } static inline unsigned long cpu_get_msa_id(void) @@ -399,6 +456,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) ftlb_page = MIPS_CONF4_VFTLBPAGESIZE; /* fall through */ case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT: + if (mips_ftlb_disabled) + break; newcf4 = (config4 & ~ftlb_page) | (page_size_ftlb(mmuextdef) << MIPS_CONF4_FTLBPAGESIZE_SHIFT); @@ -418,6 +477,7 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >> MIPS_CONF4_FTLBWAYS_SHIFT) + 2; c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets; + mips_has_ftlb_configured = 1; break; } } @@ -432,7 +492,7 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c) unsigned int config5; config5 = read_c0_config5(); - config5 &= ~MIPS_CONF5_UFR; + config5 &= ~(MIPS_CONF5_UFR | MIPS_CONF5_UFE); write_c0_config5(config5); if (config5 & MIPS_CONF5_EVA) @@ -453,8 +513,8 @@ static void decode_configs(struct cpuinfo_mips *c) c->scache.flags = MIPS_CACHE_NOT_PRESENT; - /* Enable FTLB if present */ - set_ftlb_enable(c, 1); + /* Enable FTLB if present and not disabled */ + set_ftlb_enable(c, !mips_ftlb_disabled); ok = decode_config0(c); /* Read Config registers. */ BUG_ON(!ok); /* Arch spec violation! */ @@ -1058,6 +1118,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) break; } case PRID_IMP_BMIPS5000: + case PRID_IMP_BMIPS5200: c->cputype = CPU_BMIPS5000; __cpu_name[cpu] = "Broadcom BMIPS5000"; set_elf_platform(cpu, "bmips5000"); @@ -1288,6 +1349,8 @@ void cpu_probe(void) MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) { if (c->fpu_id & MIPS_FPIR_3D) c->ases |= MIPS_ASE_MIPS3D; + if (c->fpu_id & MIPS_FPIR_FREP) + c->options |= MIPS_CPU_FRE; } } diff --git a/arch/mips/kernel/crash_dump.c b/arch/mips/kernel/crash_dump.c index f291cf9..6fe7790 100644 --- a/arch/mips/kernel/crash_dump.c +++ b/arch/mips/kernel/crash_dump.c @@ -38,7 +38,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, kunmap_atomic(vaddr); } else { if (!kdump_buf_page) { - pr_warning("Kdump: Kdump buffer page not allocated\n"); + pr_warn("Kdump: Kdump buffer page not allocated\n"); return -EFAULT; } @@ -57,7 +57,7 @@ static int __init kdump_buf_page_init(void) kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!kdump_buf_page) { - pr_warning("Kdump: Failed to allocate kdump buffer page\n"); + pr_warn("Kdump: Failed to allocate kdump buffer page\n"); ret = -ENOMEM; } diff --git a/arch/mips/kernel/csrc-gic.c b/arch/mips/kernel/csrc-gic.c deleted file mode 100644 index e026209..0000000 --- a/arch/mips/kernel/csrc-gic.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include <linux/init.h> -#include <linux/time.h> - -#include <asm/gic.h> - -static cycle_t gic_hpt_read(struct clocksource *cs) -{ - return gic_read_count(); -} - -static struct clocksource gic_clocksource = { - .name = "GIC", - .read = gic_hpt_read, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -void __init gic_clocksource_init(unsigned int frequency) -{ - unsigned int config, bits; - - /* Calculate the clocksource mask. */ - GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), config); - bits = 32 + ((config & GIC_SH_CONFIG_COUNTBITS_MSK) >> - (GIC_SH_CONFIG_COUNTBITS_SHF - 2)); - - /* Set clocksource mask. */ - gic_clocksource.mask = CLOCKSOURCE_MASK(bits); - - /* Calculate a somewhat reasonable rating value. */ - gic_clocksource.rating = 200 + frequency / 10000000; - - clocksource_register_hz(&gic_clocksource, frequency); -} diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c new file mode 100644 index 0000000..c92b15d --- /dev/null +++ b/arch/mips/kernel/elf.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2014 Imagination Technologies + * Author: Paul Burton <paul.burton@imgtec.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/elf.h> +#include <linux/sched.h> + +enum { + FP_ERROR = -1, + FP_DOUBLE_64A = -2, +}; + +int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, + bool is_interp, struct arch_elf_state *state) +{ + struct elfhdr *ehdr = _ehdr; + struct elf_phdr *phdr = _phdr; + struct mips_elf_abiflags_v0 abiflags; + int ret; + + if (config_enabled(CONFIG_64BIT) && + (ehdr->e_ident[EI_CLASS] != ELFCLASS32)) + return 0; + if (phdr->p_type != PT_MIPS_ABIFLAGS) + return 0; + if (phdr->p_filesz < sizeof(abiflags)) + return -EINVAL; + + ret = kernel_read(elf, phdr->p_offset, (char *)&abiflags, + sizeof(abiflags)); + if (ret < 0) + return ret; + if (ret != sizeof(abiflags)) + return -EIO; + + /* Record the required FP ABIs for use by mips_check_elf */ + if (is_interp) + state->interp_fp_abi = abiflags.fp_abi; + else + state->fp_abi = abiflags.fp_abi; + + return 0; +} + +static inline unsigned get_fp_abi(struct elfhdr *ehdr, int in_abi) +{ + /* If the ABI requirement is provided, simply return that */ + if (in_abi != -1) + return in_abi; + + /* If the EF_MIPS_FP64 flag was set, return MIPS_ABI_FP_64 */ + if (ehdr->e_flags & EF_MIPS_FP64) + return MIPS_ABI_FP_64; + + /* Default to MIPS_ABI_FP_DOUBLE */ + return MIPS_ABI_FP_DOUBLE; +} + +int arch_check_elf(void *_ehdr, bool has_interpreter, + struct arch_elf_state *state) +{ + struct elfhdr *ehdr = _ehdr; + unsigned fp_abi, interp_fp_abi, abi0, abi1; + + /* Ignore non-O32 binaries */ + if (config_enabled(CONFIG_64BIT) && + (ehdr->e_ident[EI_CLASS] != ELFCLASS32)) + return 0; + + fp_abi = get_fp_abi(ehdr, state->fp_abi); + + if (has_interpreter) { + interp_fp_abi = get_fp_abi(ehdr, state->interp_fp_abi); + + abi0 = min(fp_abi, interp_fp_abi); + abi1 = max(fp_abi, interp_fp_abi); + } else { + abi0 = abi1 = fp_abi; + } + + state->overall_abi = FP_ERROR; + + if (abi0 == abi1) { + state->overall_abi = abi0; + } else if (abi0 == MIPS_ABI_FP_ANY) { + state->overall_abi = abi1; + } else if (abi0 == MIPS_ABI_FP_DOUBLE) { + switch (abi1) { + case MIPS_ABI_FP_XX: + state->overall_abi = MIPS_ABI_FP_DOUBLE; + break; + + case MIPS_ABI_FP_64A: + state->overall_abi = FP_DOUBLE_64A; + break; + } + } else if (abi0 == MIPS_ABI_FP_SINGLE || + abi0 == MIPS_ABI_FP_SOFT) { + /* Cannot link with other ABIs */ + } else if (abi0 == MIPS_ABI_FP_OLD_64) { + switch (abi1) { + case MIPS_ABI_FP_XX: + case MIPS_ABI_FP_64: + case MIPS_ABI_FP_64A: + state->overall_abi = MIPS_ABI_FP_64; + break; + } + } else if (abi0 == MIPS_ABI_FP_XX || + abi0 == MIPS_ABI_FP_64 || + abi0 == MIPS_ABI_FP_64A) { + state->overall_abi = MIPS_ABI_FP_64; + } + + switch (state->overall_abi) { + case MIPS_ABI_FP_64: + case MIPS_ABI_FP_64A: + case FP_DOUBLE_64A: + if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) + return -ELIBBAD; + break; + + case FP_ERROR: + return -ELIBBAD; + } + + return 0; +} + +void mips_set_personality_fp(struct arch_elf_state *state) +{ + if (config_enabled(CONFIG_FP32XX_HYBRID_FPRS)) { + /* + * Use hybrid FPRs for all code which can correctly execute + * with that mode. + */ + switch (state->overall_abi) { + case MIPS_ABI_FP_DOUBLE: + case MIPS_ABI_FP_SINGLE: + case MIPS_ABI_FP_SOFT: + case MIPS_ABI_FP_XX: + case MIPS_ABI_FP_ANY: + /* FR=1, FRE=1 */ + clear_thread_flag(TIF_32BIT_FPREGS); + set_thread_flag(TIF_HYBRID_FPREGS); + return; + } + } + + switch (state->overall_abi) { + case MIPS_ABI_FP_DOUBLE: + case MIPS_ABI_FP_SINGLE: + case MIPS_ABI_FP_SOFT: + /* FR=0 */ + set_thread_flag(TIF_32BIT_FPREGS); + clear_thread_flag(TIF_HYBRID_FPREGS); + break; + + case FP_DOUBLE_64A: + /* FR=1, FRE=1 */ + clear_thread_flag(TIF_32BIT_FPREGS); + set_thread_flag(TIF_HYBRID_FPREGS); + break; + + case MIPS_ABI_FP_64: + case MIPS_ABI_FP_64A: + /* FR=1, FRE=0 */ + clear_thread_flag(TIF_32BIT_FPREGS); + clear_thread_flag(TIF_HYBRID_FPREGS); + break; + + case MIPS_ABI_FP_XX: + case MIPS_ABI_FP_ANY: + if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) + set_thread_flag(TIF_32BIT_FPREGS); + else + clear_thread_flag(TIF_32BIT_FPREGS); + + clear_thread_flag(TIF_HYBRID_FPREGS); + break; + + default: + case FP_ERROR: + BUG(); + } +} diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 50b3648..a74ec3a 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/interrupt.h> +#include <linux/irqdomain.h> #include <linux/kernel.h> #include <linux/spinlock.h> #include <linux/syscore_ops.h> @@ -308,6 +309,19 @@ static struct resource pic2_io_resource = { .flags = IORESOURCE_BUSY }; +static int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq); + irq_set_probe(virq); + return 0; +} + +static struct irq_domain_ops i8259A_ops = { + .map = i8259A_irq_domain_map, + .xlate = irq_domain_xlate_onecell, +}; + /* * On systems with i8259-style interrupt controllers we assume for * driver compatibility reasons interrupts 0 - 15 to be the i8259 @@ -315,17 +329,17 @@ static struct resource pic2_io_resource = { */ void __init init_i8259_irqs(void) { - int i; + struct irq_domain *domain; insert_resource(&ioport_resource, &pic1_io_resource); insert_resource(&ioport_resource, &pic2_io_resource); init_8259A(0); - for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) { - irq_set_chip_and_handler(i, &i8259A_chip, handle_level_irq); - irq_set_probe(i); - } + domain = irq_domain_add_legacy(NULL, 16, I8259A_IRQ_BASE, 0, + &i8259A_ops, NULL); + if (!domain) + panic("Failed to add i8259 IRQ domain"); setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); } diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c deleted file mode 100644 index 9e9d8b9..0000000 --- a/arch/mips/kernel/irq-gic.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * 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) 2008 Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include <linux/bitmap.h> -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/irq.h> -#include <linux/clocksource.h> - -#include <asm/io.h> -#include <asm/gic.h> -#include <asm/setup.h> -#include <asm/traps.h> -#include <linux/hardirq.h> -#include <asm-generic/bitops/find.h> - -unsigned int gic_frequency; -unsigned int gic_present; -unsigned long _gic_base; -unsigned int gic_irq_base; -unsigned int gic_irq_flags[GIC_NUM_INTRS]; - -/* The index into this array is the vector # of the interrupt. */ -struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS]; - -struct gic_pcpu_mask { - DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS); -}; - -struct gic_pending_regs { - DECLARE_BITMAP(pending, GIC_NUM_INTRS); -}; - -struct gic_intrmask_regs { - DECLARE_BITMAP(intrmask, GIC_NUM_INTRS); -}; - -static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; -static struct gic_pending_regs pending_regs[NR_CPUS]; -static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; - -#if defined(CONFIG_CSRC_GIC) || defined(CONFIG_CEVT_GIC) -cycle_t gic_read_count(void) -{ - unsigned int hi, hi2, lo; - - do { - GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi); - GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo); - GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2); - } while (hi2 != hi); - - return (((cycle_t) hi) << 32) + lo; -} - -void gic_write_compare(cycle_t cnt) -{ - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), - (int)(cnt >> 32)); - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), - (int)(cnt & 0xffffffff)); -} - -void gic_write_cpu_compare(cycle_t cnt, int cpu) -{ - unsigned long flags; - - local_irq_save(flags); - - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); - GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), - (int)(cnt >> 32)); - GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), - (int)(cnt & 0xffffffff)); - - local_irq_restore(flags); -} - -cycle_t gic_read_compare(void) -{ - unsigned int hi, lo; - - GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), hi); - GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), lo); - - return (((cycle_t) hi) << 32) + lo; -} -#endif - -unsigned int gic_get_timer_pending(void) -{ - unsigned int vpe_pending; - - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0); - GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending); - return (vpe_pending & GIC_VPE_PEND_TIMER_MSK); -} - -void gic_bind_eic_interrupt(int irq, int set) -{ - /* Convert irq vector # to hw int # */ - irq -= GIC_PIN_TO_VEC_OFFSET; - - /* Set irq to use shadow set */ - GICWRITE(GIC_REG_ADDR(VPE_LOCAL, GIC_VPE_EIC_SS(irq)), set); -} - -void gic_send_ipi(unsigned int intr) -{ - GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); -} - -static void gic_eic_irq_dispatch(void) -{ - unsigned int cause = read_c0_cause(); - int irq; - - irq = (cause & ST0_IM) >> STATUSB_IP2; - if (irq == 0) - irq = -1; - - if (irq >= 0) - do_IRQ(gic_irq_base + irq); - else - spurious_interrupt(); -} - -static void __init vpe_local_setup(unsigned int numvpes) -{ - unsigned long timer_intr = GIC_INT_TMR; - unsigned long perf_intr = GIC_INT_PERFCTR; - unsigned int vpe_ctl; - int i; - - if (cpu_has_veic) { - /* - * GIC timer interrupt -> CPU HW Int X (vector X+2) -> - * map to pin X+2-1 (since GIC adds 1) - */ - timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); - /* - * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) -> - * map to pin X+2-1 (since GIC adds 1) - */ - perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); - } - - /* - * Setup the default performance counter timer interrupts - * for all VPEs - */ - for (i = 0; i < numvpes; i++) { - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); - - /* Are Interrupts locally routable? */ - GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); - if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) - GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), - GIC_MAP_TO_PIN_MSK | timer_intr); - if (cpu_has_veic) { - set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET, - gic_eic_irq_dispatch); - gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK; - } - - if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) - GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), - GIC_MAP_TO_PIN_MSK | perf_intr); - if (cpu_has_veic) { - set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch); - gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK; - } - } -} - -unsigned int gic_compare_int(void) -{ - unsigned int pending; - - GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending); - if (pending & GIC_VPE_PEND_CMP_MSK) - return 1; - else - return 0; -} - -void gic_get_int_mask(unsigned long *dst, const unsigned long *src) -{ - unsigned int i; - unsigned long *pending, *intrmask, *pcpu_mask; - unsigned long *pending_abs, *intrmask_abs; - - /* Get per-cpu bitmaps */ - pending = pending_regs[smp_processor_id()].pending; - intrmask = intrmask_regs[smp_processor_id()].intrmask; - pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask; - - pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, - GIC_SH_PEND_31_0_OFS); - intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, - GIC_SH_MASK_31_0_OFS); - - for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) { - GICREAD(*pending_abs, pending[i]); - GICREAD(*intrmask_abs, intrmask[i]); - pending_abs++; - intrmask_abs++; - } - - bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS); - bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS); - bitmap_and(dst, src, pending, GIC_NUM_INTRS); -} - -unsigned int gic_get_int(void) -{ - DECLARE_BITMAP(interrupts, GIC_NUM_INTRS); - - bitmap_fill(interrupts, GIC_NUM_INTRS); - gic_get_int_mask(interrupts, interrupts); - - return find_first_bit(interrupts, GIC_NUM_INTRS); -} - -static void gic_mask_irq(struct irq_data *d) -{ - GIC_CLR_INTR_MASK(d->irq - gic_irq_base); -} - -static void gic_unmask_irq(struct irq_data *d) -{ - GIC_SET_INTR_MASK(d->irq - gic_irq_base); -} - -#ifdef CONFIG_SMP -static DEFINE_SPINLOCK(gic_lock); - -static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, - bool force) -{ - unsigned int irq = (d->irq - gic_irq_base); - cpumask_t tmp = CPU_MASK_NONE; - unsigned long flags; - int i; - - cpumask_and(&tmp, cpumask, cpu_online_mask); - if (cpus_empty(tmp)) - return -1; - - /* Assumption : cpumask refers to a single CPU */ - spin_lock_irqsave(&gic_lock, flags); - - /* Re-route this IRQ */ - GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp)); - - /* Update the pcpu_masks */ - for (i = 0; i < NR_CPUS; i++) - clear_bit(irq, pcpu_masks[i].pcpu_mask); - set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); - - cpumask_copy(d->affinity, cpumask); - spin_unlock_irqrestore(&gic_lock, flags); - - return IRQ_SET_MASK_OK_NOCOPY; -} -#endif - -static struct irq_chip gic_irq_controller = { - .name = "MIPS GIC", - .irq_ack = gic_irq_ack, - .irq_mask = gic_mask_irq, - .irq_mask_ack = gic_mask_irq, - .irq_unmask = gic_unmask_irq, - .irq_eoi = gic_finish_irq, -#ifdef CONFIG_SMP - .irq_set_affinity = gic_set_affinity, -#endif -}; - -static void __init gic_setup_intr(unsigned int intr, unsigned int cpu, - unsigned int pin, unsigned int polarity, unsigned int trigtype, - unsigned int flags) -{ - struct gic_shared_intr_map *map_ptr; - - /* Setup Intr to Pin mapping */ - if (pin & GIC_MAP_TO_NMI_MSK) { - int i; - - GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); - /* FIXME: hack to route NMI to all cpu's */ - for (i = 0; i < NR_CPUS; i += 32) { - GICWRITE(GIC_REG_ADDR(SHARED, - GIC_SH_MAP_TO_VPE_REG_OFF(intr, i)), - 0xffffffff); - } - } else { - GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), - GIC_MAP_TO_PIN_MSK | pin); - /* Setup Intr to CPU mapping */ - GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); - if (cpu_has_veic) { - set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET, - gic_eic_irq_dispatch); - map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET]; - if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR) - BUG(); - map_ptr->intr_list[map_ptr->num_shared_intr++] = intr; - } - } - - /* Setup Intr Polarity */ - GIC_SET_POLARITY(intr, polarity); - - /* Setup Intr Trigger Type */ - GIC_SET_TRIGGER(intr, trigtype); - - /* Init Intr Masks */ - GIC_CLR_INTR_MASK(intr); - - /* Initialise per-cpu Interrupt software masks */ - set_bit(intr, pcpu_masks[cpu].pcpu_mask); - - if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0)) - GIC_SET_INTR_MASK(intr); - if (trigtype == GIC_TRIG_EDGE) - gic_irq_flags[intr] |= GIC_TRIG_EDGE; -} - -static void __init gic_basic_init(int numintrs, int numvpes, - struct gic_intr_map *intrmap, int mapsize) -{ - unsigned int i, cpu; - unsigned int pin_offset = 0; - - board_bind_eic_interrupt = &gic_bind_eic_interrupt; - - /* Setup defaults */ - for (i = 0; i < numintrs; i++) { - GIC_SET_POLARITY(i, GIC_POL_POS); - GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL); - GIC_CLR_INTR_MASK(i); - if (i < GIC_NUM_INTRS) { - gic_irq_flags[i] = 0; - gic_shared_intr_map[i].num_shared_intr = 0; - gic_shared_intr_map[i].local_intr_mask = 0; - } - } - - /* - * In EIC mode, the HW_INT# is offset by (2-1). Need to subtract - * one because the GIC will add one (since 0=no intr). - */ - if (cpu_has_veic) - pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); - - /* Setup specifics */ - for (i = 0; i < mapsize; i++) { - cpu = intrmap[i].cpunum; - if (cpu == GIC_UNUSED) - continue; - gic_setup_intr(i, - intrmap[i].cpunum, - intrmap[i].pin + pin_offset, - intrmap[i].polarity, - intrmap[i].trigtype, - intrmap[i].flags); - } - - vpe_local_setup(numvpes); -} - -void __init gic_init(unsigned long gic_base_addr, - unsigned long gic_addrspace_size, - struct gic_intr_map *intr_map, unsigned int intr_map_size, - unsigned int irqbase) -{ - unsigned int gicconfig; - int numvpes, numintrs; - - _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, - gic_addrspace_size); - gic_irq_base = irqbase; - - GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); - numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> - GIC_SH_CONFIG_NUMINTRS_SHF; - numintrs = ((numintrs + 1) * 8); - - numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> - GIC_SH_CONFIG_NUMVPES_SHF; - numvpes = numvpes + 1; - - gic_basic_init(numintrs, numvpes, intr_map, intr_map_size); - - gic_platform_init(numintrs, &gic_irq_controller); -} diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index e498f2b..590c2c9 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -36,6 +36,7 @@ #include <asm/irq_cpu.h> #include <asm/mipsregs.h> #include <asm/mipsmtregs.h> +#include <asm/setup.h> static inline void unmask_mips_irq(struct irq_data *d) { @@ -94,28 +95,24 @@ static struct irq_chip mips_mt_cpu_irq_controller = { .irq_eoi = unmask_mips_irq, }; -void __init mips_cpu_irq_init(void) +asmlinkage void __weak plat_irq_dispatch(void) { - int irq_base = MIPS_CPU_IRQ_BASE; - int i; + unsigned long pending = read_c0_cause() & read_c0_status() & ST0_IM; + int irq; - /* Mask interrupts. */ - clear_c0_status(ST0_IM); - clear_c0_cause(CAUSEF_IP); - - /* Software interrupts are used for MT/CMT IPI */ - for (i = irq_base; i < irq_base + 2; i++) - irq_set_chip_and_handler(i, cpu_has_mipsmt ? - &mips_mt_cpu_irq_controller : - &mips_cpu_irq_controller, - handle_percpu_irq); + if (!pending) { + spurious_interrupt(); + return; + } - for (i = irq_base + 2; i < irq_base + 8; i++) - irq_set_chip_and_handler(i, &mips_cpu_irq_controller, - handle_percpu_irq); + pending >>= CAUSEB_IP; + while (pending) { + irq = fls(pending) - 1; + do_IRQ(MIPS_CPU_IRQ_BASE + irq); + pending &= ~BIT(irq); + } } -#ifdef CONFIG_IRQ_DOMAIN static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { @@ -128,6 +125,9 @@ static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq, chip = &mips_cpu_irq_controller; } + if (cpu_has_vint) + set_vi_handler(hw, plat_irq_dispatch); + irq_set_chip_and_handler(irq, chip, handle_percpu_irq); return 0; @@ -138,8 +138,7 @@ static const struct irq_domain_ops mips_cpu_intc_irq_domain_ops = { .xlate = irq_domain_xlate_onecell, }; -int __init mips_cpu_intc_init(struct device_node *of_node, - struct device_node *parent) +static void __init __mips_cpu_irq_init(struct device_node *of_node) { struct irq_domain *domain; @@ -151,7 +150,16 @@ int __init mips_cpu_intc_init(struct device_node *of_node, &mips_cpu_intc_irq_domain_ops, NULL); if (!domain) panic("Failed to add irqdomain for MIPS CPU"); +} +void __init mips_cpu_irq_init(void) +{ + __mips_cpu_irq_init(NULL); +} + +int __init mips_cpu_irq_of_init(struct device_node *of_node, + struct device_node *parent) +{ + __mips_cpu_irq_init(of_node); return 0; } -#endif /* CONFIG_IRQ_DOMAIN */ diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index f76f7a0..85bbe9b 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -16,7 +16,7 @@ void __iomem *mips_cm_base; void __iomem *mips_cm_l2sync_base; -phys_t __mips_cm_phys_base(void) +phys_addr_t __mips_cm_phys_base(void) { u32 config3 = read_c0_config3(); u32 cmgcr; @@ -30,10 +30,10 @@ phys_t __mips_cm_phys_base(void) return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32); } -phys_t mips_cm_phys_base(void) +phys_addr_t mips_cm_phys_base(void) __attribute__((weak, alias("__mips_cm_phys_base"))); -phys_t __mips_cm_l2sync_phys_base(void) +phys_addr_t __mips_cm_l2sync_phys_base(void) { u32 base_reg; @@ -49,13 +49,13 @@ phys_t __mips_cm_l2sync_phys_base(void) return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; } -phys_t mips_cm_l2sync_phys_base(void) +phys_addr_t mips_cm_l2sync_phys_base(void) __attribute__((weak, alias("__mips_cm_l2sync_phys_base"))); static void mips_cm_probe_l2sync(void) { unsigned major_rev; - phys_t addr; + phys_addr_t addr; /* L2-only sync was introduced with CM major revision 6 */ major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR_MSK) >> @@ -78,7 +78,7 @@ static void mips_cm_probe_l2sync(void) int mips_cm_probe(void) { - phys_t addr; + phys_addr_t addr; u32 base_reg; addr = mips_cm_phys_base(); diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index ba47360..1196450 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -21,7 +21,7 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); -phys_t __weak mips_cpc_phys_base(void) +phys_addr_t __weak mips_cpc_phys_base(void) { u32 cpc_base; @@ -44,7 +44,7 @@ phys_t __weak mips_cpc_phys_base(void) int mips_cpc_probe(void) { - phys_t addr; + phys_addr_t addr; unsigned cpu; for_each_possible_cpu(cpu) diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 2607c3a..17eaf0c 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -24,9 +24,7 @@ extern long __strncpy_from_user_nocheck_asm(char *__to, const char *__from, long __len); extern long __strncpy_from_user_asm(char *__to, const char *__from, long __len); -extern long __strlen_kernel_nocheck_asm(const char *s); extern long __strlen_kernel_asm(const char *s); -extern long __strlen_user_nocheck_asm(const char *s); extern long __strlen_user_asm(const char *s); extern long __strnlen_kernel_nocheck_asm(const char *s); extern long __strnlen_kernel_asm(const char *s); @@ -62,9 +60,7 @@ EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm); EXPORT_SYMBOL(__strncpy_from_kernel_asm); EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm); EXPORT_SYMBOL(__strncpy_from_user_asm); -EXPORT_SYMBOL(__strlen_kernel_nocheck_asm); EXPORT_SYMBOL(__strlen_kernel_asm); -EXPORT_SYMBOL(__strlen_user_nocheck_asm); EXPORT_SYMBOL(__strlen_user_asm); EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm); EXPORT_SYMBOL(__strnlen_kernel_asm); diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index a8f9cdc..9466184 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -561,8 +561,8 @@ static int mipspmu_get_irq(void) IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_THREAD, "mips_perf_pmu", NULL); if (err) { - pr_warning("Unable to request IRQ%d for MIPS " - "performance counters!\n", mipspmu.irq); + pr_warn("Unable to request IRQ%d for MIPS performance counters!\n", + mipspmu.irq); } } else if (cp0_perfcount_irq < 0) { /* @@ -572,8 +572,7 @@ static int mipspmu_get_irq(void) perf_irq = mipsxx_pmu_handle_shared_irq; err = 0; } else { - pr_warning("The platform hasn't properly defined its " - "interrupt controller.\n"); + pr_warn("The platform hasn't properly defined its interrupt controller\n"); err = -ENOENT; } @@ -1614,22 +1613,13 @@ init_hw_perf_events(void) counters = counters_total_to_per_cpu(counters); #endif -#ifdef MSC01E_INT_BASE - if (cpu_has_veic) { - /* - * Using platform specific interrupt controller defines. - */ - irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; - } else { -#endif - if ((cp0_perfcount_irq >= 0) && - (cp0_compare_irq != cp0_perfcount_irq)) - irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; - else - irq = -1; -#ifdef MSC01E_INT_BASE - } -#endif + if (get_c0_perfcount_int) + irq = get_c0_perfcount_int(); + else if ((cp0_perfcount_irq >= 0) && + (cp0_compare_irq != cp0_perfcount_irq)) + irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + else + irq = -1; mipspmu.map_raw_event = mipsxx_pmu_map_raw_event; diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 636b074..eb76434 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -42,6 +42,7 @@ #include <asm/isadep.h> #include <asm/inst.h> #include <asm/stacktrace.h> +#include <asm/irq_regs.h> #ifdef CONFIG_HOTPLUG_CPU void arch_cpu_idle_dead(void) @@ -187,21 +188,21 @@ static inline int is_ra_save_ins(union mips_instruction *ip) */ if (mm_insn_16bit(ip->halfword[0])) { mmi.word = (ip->halfword[0] << 16); - return ((mmi.mm16_r5_format.opcode == mm_swsp16_op && - mmi.mm16_r5_format.rt == 31) || - (mmi.mm16_m_format.opcode == mm_pool16c_op && - mmi.mm16_m_format.func == mm_swm16_op)); + return (mmi.mm16_r5_format.opcode == mm_swsp16_op && + mmi.mm16_r5_format.rt == 31) || + (mmi.mm16_m_format.opcode == mm_pool16c_op && + mmi.mm16_m_format.func == mm_swm16_op); } else { mmi.halfword[0] = ip->halfword[1]; mmi.halfword[1] = ip->halfword[0]; - return ((mmi.mm_m_format.opcode == mm_pool32b_op && - mmi.mm_m_format.rd > 9 && - mmi.mm_m_format.base == 29 && - mmi.mm_m_format.func == mm_swm32_func) || - (mmi.i_format.opcode == mm_sw32_op && - mmi.i_format.rs == 29 && - mmi.i_format.rt == 31)); + return (mmi.mm_m_format.opcode == mm_pool32b_op && + mmi.mm_m_format.rd > 9 && + mmi.mm_m_format.base == 29 && + mmi.mm_m_format.func == mm_swm32_func) || + (mmi.i_format.opcode == mm_sw32_op && + mmi.i_format.rs == 29 && + mmi.i_format.rt == 31); } #else /* sw / sd $ra, offset($sp) */ @@ -233,7 +234,7 @@ static inline int is_jump_ins(union mips_instruction *ip) if (ip->r_format.opcode != mm_pool32a_op || ip->r_format.func != mm_pool32axf_op) return 0; - return (((ip->u_format.uimmediate >> 6) & mm_jalr_op) == mm_jalr_op); + return ((ip->u_format.uimmediate >> 6) & mm_jalr_op) == mm_jalr_op; #else if (ip->j_format.opcode == j_op) return 1; @@ -260,13 +261,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip) union mips_instruction mmi; mmi.word = (ip->halfword[0] << 16); - return ((mmi.mm16_r3_format.opcode == mm_pool16d_op && - mmi.mm16_r3_format.simmediate && mm_addiusp_func) || - (mmi.mm16_r5_format.opcode == mm_pool16d_op && - mmi.mm16_r5_format.rt == 29)); + return (mmi.mm16_r3_format.opcode == mm_pool16d_op && + mmi.mm16_r3_format.simmediate && mm_addiusp_func) || + (mmi.mm16_r5_format.opcode == mm_pool16d_op && + mmi.mm16_r5_format.rt == 29); } - return (ip->mm_i_format.opcode == mm_addiu32_op && - ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29); + return ip->mm_i_format.opcode == mm_addiu32_op && + ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29; #else /* addiu/daddiu sp,sp,-imm */ if (ip->i_format.rs != 29 || ip->i_format.rt != 29) @@ -532,3 +533,20 @@ unsigned long arch_align_stack(unsigned long sp) return sp & ALMASK; } + +static void arch_dump_stack(void *info) +{ + struct pt_regs *regs; + + regs = get_irq_regs(); + + if (regs) + show_regs(regs); + + dump_stack(); +} + +void arch_trigger_all_cpu_backtrace(bool include_self) +{ + smp_call_function(arch_dump_stack, NULL, 1); +} diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 5d39bb8..452d435 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -16,6 +16,7 @@ #include <linux/debugfs.h> #include <linux/of.h> #include <linux/of_fdt.h> +#include <linux/of_platform.h> #include <asm/page.h> #include <asm/prom.h> @@ -54,4 +55,21 @@ void __init __dt_setup_arch(void *bph) mips_set_machine_name(of_flat_dt_get_machine_name()); } + +int __init __dt_register_buses(const char *bus0, const char *bus1) +{ + static struct of_device_id of_ids[3]; + + if (!of_have_populated_dt()) + panic("device tree not present"); + + strlcpy(of_ids[0].compatible, bus0, sizeof(of_ids[0].compatible)); + strlcpy(of_ids[1].compatible, bus1, sizeof(of_ids[1].compatible)); + + if (of_platform_populate(NULL, of_ids, NULL, NULL)) + panic("failed to populate DT"); + + return 0; +} + #endif diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f3b635f..a8c20af 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -82,14 +82,14 @@ static struct resource data_resource = { .name = "Kernel data", }; static void *detect_magic __initdata = detect_memory_region; -void __init add_memory_region(phys_t start, phys_t size, long type) +void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type) { int x = boot_mem_map.nr_map; int i; /* Sanity check */ if (start + size < start) { - pr_warning("Trying to add an invalid memory region, skipped\n"); + pr_warn("Trying to add an invalid memory region, skipped\n"); return; } @@ -127,10 +127,10 @@ void __init add_memory_region(phys_t start, phys_t size, long type) boot_mem_map.nr_map++; } -void __init detect_memory_region(phys_t start, phys_t sz_min, phys_t sz_max) +void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max) { void *dm = &detect_magic; - phys_t size; + phys_addr_t size; for (size = sz_min; size < sz_max; size <<= 1) { if (!memcmp(dm, dm + size, sizeof(detect_magic))) @@ -545,9 +545,9 @@ static int __init early_parse_elfcorehdr(char *p) early_param("elfcorehdr", early_parse_elfcorehdr); #endif -static void __init arch_mem_addpart(phys_t mem, phys_t end, int type) +static void __init arch_mem_addpart(phys_addr_t mem, phys_addr_t end, int type) { - phys_t size; + phys_addr_t size; int i; size = end - mem; diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 16f1e4f..545bf11 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -530,7 +530,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) struct mips_abi *abi = current->thread.abi; #ifdef CONFIG_CPU_MICROMIPS void *vdso; - unsigned int tmp = (unsigned int)current->mm->context.vdso; + unsigned long tmp = (unsigned long)current->mm->context.vdso; set_isa16_mode(tmp); vdso = (void *)tmp; diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 06bb5ed..b8bd934 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -35,6 +35,7 @@ #include <asm/bmips.h> #include <asm/traps.h> #include <asm/barrier.h> +#include <asm/cpu-features.h> static int __maybe_unused max_cpus = 1; @@ -42,6 +43,12 @@ static int __maybe_unused max_cpus = 1; int bmips_smp_enabled = 1; int bmips_cpu_offset; cpumask_t bmips_booted_mask; +unsigned long bmips_tp1_irqs = IE_IRQ1; + +#define RESET_FROM_KSEG0 0x80080800 +#define RESET_FROM_KSEG1 0xa0080800 + +static void bmips_set_reset_vec(int cpu, u32 val); #ifdef CONFIG_SMP @@ -194,6 +201,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) pr_info("SMP: Booting CPU%d...\n", cpu); if (cpumask_test_cpu(cpu, &bmips_booted_mask)) { + /* kseg1 might not exist if this CPU enabled XKS01 */ + bmips_set_reset_vec(cpu, RESET_FROM_KSEG0); + switch (current_cpu_type()) { case CPU_BMIPS4350: case CPU_BMIPS4380: @@ -203,8 +213,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) bmips5000_send_ipi_single(cpu, 0); break; } - } - else { + } else { + bmips_set_reset_vec(cpu, RESET_FROM_KSEG1); + switch (current_cpu_type()) { case CPU_BMIPS4350: case CPU_BMIPS4380: @@ -213,17 +224,7 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) set_c0_brcm_cmt_ctrl(0x01); break; case CPU_BMIPS5000: - if (cpu & 0x01) - write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); - else { - /* - * core N thread 0 was already booted; just - * pulse the NMI line - */ - bmips_write_zscm_reg(0x210, 0xc0000000); - udelay(10); - bmips_write_zscm_reg(0x210, 0x00); - } + write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); break; } cpumask_set_cpu(cpu, &bmips_booted_mask); @@ -235,31 +236,12 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) */ static void bmips_init_secondary(void) { - /* move NMI vector to kseg0, in case XKS01 is enabled */ - - void __iomem *cbr; - unsigned long old_vec; - unsigned long relo_vector; - int boot_cpu; - switch (current_cpu_type()) { case CPU_BMIPS4350: case CPU_BMIPS4380: - cbr = BMIPS_GET_CBR(); - - boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31)); - relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 : - BMIPS_RELO_VECTOR_CONTROL_1; - - old_vec = __raw_readl(cbr + relo_vector); - __raw_writel(old_vec & ~0x20000000, cbr + relo_vector); - clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); break; case CPU_BMIPS5000: - write_c0_brcm_bootvec(read_c0_brcm_bootvec() & - (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000)); - write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); break; } @@ -276,7 +258,7 @@ static void bmips_smp_finish(void) write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); irq_enable_hazard(); - set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE); + set_c0_status(IE_SW0 | IE_SW1 | bmips_tp1_irqs | IE_IRQ5 | ST0_IE); irq_enable_hazard(); } @@ -381,6 +363,7 @@ static int bmips_cpu_disable(void) set_cpu_online(cpu, false); cpu_clear(cpu, cpu_callin_map); + clear_c0_status(IE_IRQ5); local_flush_tlb_all(); local_flush_icache_range(0, ~0); @@ -405,7 +388,8 @@ void __ref play_dead(void) * IRQ handlers; this clears ST0_IE and returns immediately. */ clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1); - change_c0_status(IE_IRQ5 | IE_IRQ1 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV, + change_c0_status( + IE_IRQ5 | bmips_tp1_irqs | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV, IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV); irq_disable_hazard(); @@ -473,10 +457,61 @@ static inline void bmips_nmi_handler_setup(void) &bmips_smp_int_vec_end); } +struct reset_vec_info { + int cpu; + u32 val; +}; + +static void bmips_set_reset_vec_remote(void *vinfo) +{ + struct reset_vec_info *info = vinfo; + int shift = info->cpu & 0x01 ? 16 : 0; + u32 mask = ~(0xffff << shift), val = info->val >> 16; + + preempt_disable(); + if (smp_processor_id() > 0) { + smp_call_function_single(0, &bmips_set_reset_vec_remote, + info, 1); + } else { + if (info->cpu & 0x02) { + /* BMIPS5200 "should" use mask/shift, but it's buggy */ + bmips_write_zscm_reg(0xa0, (val << 16) | val); + bmips_read_zscm_reg(0xa0); + } else { + write_c0_brcm_bootvec((read_c0_brcm_bootvec() & mask) | + (val << shift)); + } + } + preempt_enable(); +} + +static void bmips_set_reset_vec(int cpu, u32 val) +{ + struct reset_vec_info info; + + if (current_cpu_type() == CPU_BMIPS5000) { + /* this needs to run from CPU0 (which is always online) */ + info.cpu = cpu; + info.val = val; + bmips_set_reset_vec_remote(&info); + } else { + void __iomem *cbr = BMIPS_GET_CBR(); + + if (cpu == 0) + __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0); + else { + if (current_cpu_type() != CPU_BMIPS4380) + return; + __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_1); + } + } + __sync(); + back_to_back_c0_hazard(); +} + void bmips_ebase_setup(void) { unsigned long new_ebase = ebase; - void __iomem __maybe_unused *cbr; BUG_ON(ebase != CKSEG0); @@ -496,15 +531,14 @@ void bmips_ebase_setup(void) &bmips_smp_int_vec, 0x80); __sync(); return; + case CPU_BMIPS3300: case CPU_BMIPS4380: /* * 0x8000_0000: reset/NMI (initially in kseg1) * 0x8000_0400: normal vectors */ new_ebase = 0x80000400; - cbr = BMIPS_GET_CBR(); - __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0); - __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1); + bmips_set_reset_vec(0, RESET_FROM_KSEG0); break; case CPU_BMIPS5000: /* @@ -512,10 +546,8 @@ void bmips_ebase_setup(void) * 0x8000_1000: normal vectors */ new_ebase = 0x80001000; - write_c0_brcm_bootvec(0xa0088008); + bmips_set_reset_vec(0, RESET_FROM_KSEG0); write_c0_ebase(new_ebase); - if (max_cpus > 2) - bmips_write_zscm_reg(0xa0, 0xa008a008); break; default: return; diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c index fc8a515..1e0a93c 100644 --- a/arch/mips/kernel/smp-cmp.c +++ b/arch/mips/kernel/smp-cmp.c @@ -24,6 +24,7 @@ #include <linux/cpumask.h> #include <linux/interrupt.h> #include <linux/compiler.h> +#include <linux/irqchip/mips-gic.h> #include <linux/atomic.h> #include <asm/cacheflush.h> @@ -37,7 +38,6 @@ #include <asm/mipsmtregs.h> #include <asm/mips_mt.h> #include <asm/amon.h> -#include <asm/gic.h> static void cmp_init_secondary(void) { diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index e6e16a1..bed7590 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -9,13 +9,13 @@ */ #include <linux/io.h> +#include <linux/irqchip/mips-gic.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/smp.h> #include <linux/types.h> #include <asm/bcache.h> -#include <asm/gic.h> #include <asm/mips-cm.h> #include <asm/mips-cpc.h> #include <asm/mips_mt.h> @@ -273,8 +273,8 @@ static void cps_init_secondary(void) if (cpu_has_mipsmt) dmt(); - change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | - STATUSF_IP6 | STATUSF_IP7); + change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | + STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); } static void cps_smp_finish(void) diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c index 3b21a96..5f0ab5b 100644 --- a/arch/mips/kernel/smp-gic.c +++ b/arch/mips/kernel/smp-gic.c @@ -12,9 +12,9 @@ * option) any later version. */ +#include <linux/irqchip/mips-gic.h> #include <linux/printk.h> -#include <asm/gic.h> #include <asm/mips-cpc.h> #include <asm/smp-ops.h> diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 21f23ad..ad86951 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -21,6 +21,7 @@ #include <linux/sched.h> #include <linux/cpumask.h> #include <linux/interrupt.h> +#include <linux/irqchip/mips-gic.h> #include <linux/compiler.h> #include <linux/smp.h> @@ -34,7 +35,6 @@ #include <asm/mipsregs.h> #include <asm/mipsmtregs.h> #include <asm/mips_mt.h> -#include <asm/gic.h> static void __init smvp_copy_vpe_config(void) { @@ -119,7 +119,7 @@ static void vsmp_send_ipi_single(int cpu, unsigned int action) unsigned long flags; int vpflags; -#ifdef CONFIG_IRQ_GIC +#ifdef CONFIG_MIPS_GIC if (gic_present) { gic_send_ipi_single(cpu, action); return; @@ -158,7 +158,7 @@ static void vsmp_send_ipi_mask(const struct cpumask *mask, unsigned int action) static void vsmp_init_secondary(void) { -#ifdef CONFIG_IRQ_GIC +#ifdef CONFIG_MIPS_GIC /* This is Malta specific: IPI,performance and timer interrupts */ if (gic_present) change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 4a4f9dd..604b558 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -117,6 +117,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) "2: sc %[tmp], (%[addr]) \n" " beqzl %[tmp], 1b \n" "3: \n" + " .insn \n" " .section .fixup,\"ax\" \n" "4: li %[err], %[efault] \n" " j 3b \n" @@ -142,6 +143,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) "2: sc %[tmp], (%[addr]) \n" " bnez %[tmp], 4f \n" "3: \n" + " .insn \n" " .subsection 2 \n" "4: b 1b \n" " .previous \n" diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 22b19c2..ad3d203 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -724,6 +724,50 @@ int process_fpemu_return(int sig, void __user *fault_addr) } } +static int simulate_fp(struct pt_regs *regs, unsigned int opcode, + unsigned long old_epc, unsigned long old_ra) +{ + union mips_instruction inst = { .word = opcode }; + void __user *fault_addr = NULL; + int sig; + + /* If it's obviously not an FP instruction, skip it */ + switch (inst.i_format.opcode) { + case cop1_op: + case cop1x_op: + case lwc1_op: + case ldc1_op: + case swc1_op: + case sdc1_op: + break; + + default: + return -1; + } + + /* + * do_ri skipped over the instruction via compute_return_epc, undo + * that for the FPU emulator. + */ + regs->cp0_epc = old_epc; + regs->regs[31] = old_ra; + + /* Save the FP context to struct thread_struct */ + lose_fpu(1); + + /* Run the emulator */ + sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, + &fault_addr); + + /* If something went wrong, signal */ + process_fpemu_return(sig, fault_addr); + + /* Restore the hardware register state */ + own_fpu(1); + + return 0; +} + /* * XXX Delayed fp exceptions when doing a lazy ctx switch XXX */ @@ -1016,6 +1060,9 @@ asmlinkage void do_ri(struct pt_regs *regs) if (status < 0) status = simulate_sync(regs, opcode); + + if (status < 0) + status = simulate_fp(regs, opcode, old_epc, old31); } if (status < 0) @@ -1380,12 +1427,19 @@ asmlinkage void do_mcheck(struct pt_regs *regs) show_regs(regs); if (multi_match) { - printk("Index : %0x\n", read_c0_index()); - printk("Pagemask: %0x\n", read_c0_pagemask()); - printk("EntryHi : %0*lx\n", field, read_c0_entryhi()); - printk("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); - printk("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); - printk("\n"); + pr_err("Index : %0x\n", read_c0_index()); + pr_err("Pagemask: %0x\n", read_c0_pagemask()); + pr_err("EntryHi : %0*lx\n", field, read_c0_entryhi()); + pr_err("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); + pr_err("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); + pr_err("Wired : %0x\n", read_c0_wired()); + pr_err("Pagegrain: %0x\n", read_c0_pagegrain()); + if (cpu_has_htw) { + pr_err("PWField : %0*lx\n", field, read_c0_pwfield()); + pr_err("PWSize : %0*lx\n", field, read_c0_pwsize()); + pr_err("PWCtl : %0x\n", read_c0_pwctl()); + } + pr_err("\n"); dump_tlb_all(); } diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index 0f1af58..ed2a278 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -16,9 +16,11 @@ #include <linux/elf.h> #include <linux/vmalloc.h> #include <linux/unistd.h> +#include <linux/random.h> #include <asm/vdso.h> #include <asm/uasm.h> +#include <asm/processor.h> /* * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... @@ -67,7 +69,18 @@ subsys_initcall(init_vdso); static unsigned long vdso_addr(unsigned long start) { - return STACK_TOP; + unsigned long offset = 0UL; + + if (current->flags & PF_RANDOMIZE) { + offset = get_random_int(); + offset <<= PAGE_SHIFT; + if (TASK_IS_32BIT_ADDR) + offset &= 0xfffffful; + else + offset &= 0xffffffful; + } + + return STACK_TOP + offset; } int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c index 468ffa0..7edcd49 100644 --- a/arch/mips/lantiq/falcon/sysctrl.c +++ b/arch/mips/lantiq/falcon/sysctrl.c @@ -49,6 +49,7 @@ /* Activation Status Register */ #define ACTS_ASC0_ACT 0x00001000 +#define ACTS_SSC0 0x00002000 #define ACTS_ASC1_ACT 0x00000800 #define ACTS_I2C_ACT 0x00004000 #define ACTS_P0 0x00010000 @@ -147,12 +148,11 @@ static void falcon_gpe_enable(void) if (status & (1 << (GPPC_OFFSET + 1))) return; - if (status_r32(STATUS_CONFIG) == 0) + freq = (status_r32(STATUS_CONFIG) & + GPEFREQ_MASK) >> + GPEFREQ_OFFSET; + if (freq == 0) freq = 1; /* use 625MHz on unfused chip */ - else - freq = (status_r32(STATUS_CONFIG) & - GPEFREQ_MASK) >> - GPEFREQ_OFFSET; /* apply new frequency */ sysctl_w32_mask(SYSCTL_SYS1, 7 << (GPPC_OFFSET + 1), @@ -260,5 +260,6 @@ void __init ltq_soc_init(void) clkdev_add_sys("1e800600.pad", SYSCTL_SYS1, ACTS_PADCTRL4); clkdev_add_sys("1e100b00.serial", SYSCTL_SYS1, ACTS_ASC1_ACT); clkdev_add_sys("1e100c00.serial", SYSCTL_SYS1, ACTS_ASC0_ACT); + clkdev_add_sys("1e100d00.spi", SYSCTL_SYS1, ACTS_SSC0); clkdev_add_sys("1e200000.i2c", SYSCTL_SYS1, ACTS_I2C_ACT); } diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index 030568a..6ab1057 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -70,6 +70,7 @@ static struct resource ltq_eiu_irq[MAX_EIU]; static void __iomem *ltq_icu_membase[MAX_IM]; static void __iomem *ltq_eiu_membase; static struct irq_domain *ltq_domain; +static int ltq_perfcount_irq; int ltq_eiu_get_irq(int exin) { @@ -378,30 +379,6 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) panic("Failed to remap icu memory"); } - /* the external interrupts are optional and xway only */ - eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); - if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { - /* find out how many external irq sources we have */ - exin_avail = of_irq_count(eiu_node); - - if (exin_avail > MAX_EIU) - exin_avail = MAX_EIU; - - ret = of_irq_to_resource_table(eiu_node, - ltq_eiu_irq, exin_avail); - if (ret != exin_avail) - panic("failed to load external irq resources"); - - if (request_mem_region(res.start, resource_size(&res), - res.name) < 0) - pr_err("Failed to request eiu memory"); - - ltq_eiu_membase = ioremap_nocache(res.start, - resource_size(&res)); - if (!ltq_eiu_membase) - panic("Failed to remap eiu memory"); - } - /* turn off all irqs by default */ for (i = 0; i < MAX_IM; i++) { /* make sure all irqs are turned off by default */ @@ -449,7 +426,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) #endif /* tell oprofile which irq to use */ - cp0_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ); + ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ); /* * if the timer irq is not one of the mips irqs we need to @@ -458,9 +435,38 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) if (MIPS_CPU_TIMER_IRQ != 7) irq_create_mapping(ltq_domain, MIPS_CPU_TIMER_IRQ); + /* the external interrupts are optional and xway only */ + eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); + if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { + /* find out how many external irq sources we have */ + exin_avail = of_irq_count(eiu_node); + + if (exin_avail > MAX_EIU) + exin_avail = MAX_EIU; + + ret = of_irq_to_resource_table(eiu_node, + ltq_eiu_irq, exin_avail); + if (ret != exin_avail) + panic("failed to load external irq resources"); + + if (request_mem_region(res.start, resource_size(&res), + res.name) < 0) + pr_err("Failed to request eiu memory"); + + ltq_eiu_membase = ioremap_nocache(res.start, + resource_size(&res)); + if (!ltq_eiu_membase) + panic("Failed to remap eiu memory"); + } + return 0; } +int get_c0_perfcount_int(void) +{ + return ltq_perfcount_irq; +} + unsigned int get_c0_compare_int(void) { return MIPS_CPU_TIMER_IRQ; diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c index 7447d32..39ab3e7 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c @@ -36,6 +36,11 @@ const char *get_system_type(void) return soc_info.sys_type; } +int ltq_soc_type(void) +{ + return soc_info.type; +} + void prom_free_prom_memory(void) { } @@ -72,6 +77,8 @@ void __init plat_mem_setup(void) * parsed resulting in our memory appearing */ __dt_setup_arch(__dtb_start); + + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); } void __init device_tree_init(void) @@ -97,16 +104,7 @@ void __init prom_init(void) int __init plat_of_setup(void) { - static struct of_device_id of_ids[3]; - - if (!of_have_populated_dt()) - panic("device tree not present"); - - strlcpy(of_ids[0].compatible, soc_info.compatible, - sizeof(of_ids[0].compatible)); - strncpy(of_ids[1].compatible, "simple-bus", - sizeof(of_ids[1].compatible)); - return of_platform_populate(NULL, of_ids, NULL, NULL); + return __dt_register_buses(soc_info.compatible, "simple-bus"); } arch_initcall(plat_of_setup); diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile index 087497d..a2edc53 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -1,3 +1,5 @@ obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o dcdc.o +obj-y += vmmc.o + obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c index 1fa0f17..fe68f9a 100644 --- a/arch/mips/lantiq/xway/reset.c +++ b/arch/mips/lantiq/xway/reset.c @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/of_address.h> #include <linux/of_platform.h> +#include <linux/reset-controller.h> #include <asm/reboot.h> @@ -113,10 +114,77 @@ void ltq_reset_once(unsigned int module, ulong u) ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~module, RCU_RST_REQ); } +static int ltq_assert_device(struct reset_controller_dev *rcdev, + unsigned long id) +{ + u32 val; + + if (id < 8) + return -1; + + val = ltq_rcu_r32(RCU_RST_REQ); + val |= BIT(id); + ltq_rcu_w32(val, RCU_RST_REQ); + + return 0; +} + +static int ltq_deassert_device(struct reset_controller_dev *rcdev, + unsigned long id) +{ + u32 val; + + if (id < 8) + return -1; + + val = ltq_rcu_r32(RCU_RST_REQ); + val &= ~BIT(id); + ltq_rcu_w32(val, RCU_RST_REQ); + + return 0; +} + +static int ltq_reset_device(struct reset_controller_dev *rcdev, + unsigned long id) +{ + ltq_assert_device(rcdev, id); + return ltq_deassert_device(rcdev, id); +} + +static struct reset_control_ops reset_ops = { + .reset = ltq_reset_device, + .assert = ltq_assert_device, + .deassert = ltq_deassert_device, +}; + +static struct reset_controller_dev reset_dev = { + .ops = &reset_ops, + .owner = THIS_MODULE, + .nr_resets = 32, + .of_reset_n_cells = 1, +}; + +void ltq_rst_init(void) +{ + reset_dev.of_node = of_find_compatible_node(NULL, NULL, + "lantiq,xway-reset"); + if (!reset_dev.of_node) + pr_err("Failed to find reset controller node"); + else + reset_controller_register(&reset_dev); +} + static void ltq_machine_restart(char *command) { + u32 val = ltq_rcu_r32(RCU_RST_REQ); + + if (of_device_is_compatible(ltq_rcu_np, "lantiq,rcu-xrx200")) + val |= RCU_RD_GPHY1_XRX200 | RCU_RD_GPHY0_XRX200; + + val |= RCU_RD_SRST; + local_irq_disable(); - ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | RCU_RD_SRST, RCU_RST_REQ); + ltq_rcu_w32(val, RCU_RST_REQ); unreachable(); } diff --git a/arch/mips/lantiq/xway/vmmc.c b/arch/mips/lantiq/xway/vmmc.c new file mode 100644 index 0000000..696cd57 --- /dev/null +++ b/arch/mips/lantiq/xway/vmmc.c @@ -0,0 +1,69 @@ +/* + * 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. + * + * Copyright (C) 2012 John Crispin <blogic@openwrt.org> + */ + +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/dma-mapping.h> + +#include <lantiq_soc.h> + +static unsigned int *cp1_base; + +unsigned int *ltq_get_cp1_base(void) +{ + if (!cp1_base) + panic("no cp1 base was set\n"); + + return cp1_base; +} +EXPORT_SYMBOL(ltq_get_cp1_base); + +static int vmmc_probe(struct platform_device *pdev) +{ +#define CP1_SIZE (1 << 20) + int gpio_count; + dma_addr_t dma; + + cp1_base = + (void *) CPHYSADDR(dma_alloc_coherent(NULL, CP1_SIZE, + &dma, GFP_ATOMIC)); + + gpio_count = of_gpio_count(pdev->dev.of_node); + while (gpio_count > 0) { + enum of_gpio_flags flags; + int gpio = of_get_gpio_flags(pdev->dev.of_node, + --gpio_count, &flags); + if (gpio_request(gpio, "vmmc-relay")) + continue; + dev_info(&pdev->dev, "requested GPIO %d\n", gpio); + gpio_direction_output(gpio, + (flags & OF_GPIO_ACTIVE_LOW) ? (0) : (1)); + } + + dev_info(&pdev->dev, "reserved %dMB at 0x%p", CP1_SIZE >> 20, cp1_base); + + return 0; +} + +static const struct of_device_id vmmc_match[] = { + { .compatible = "lantiq,vmmc-xway" }, + {}, +}; +MODULE_DEVICE_TABLE(of, vmmc_match); + +static struct platform_driver vmmc_driver = { + .probe = vmmc_probe, + .driver = { + .name = "lantiq,vmmc", + .owner = THIS_MODULE, + .of_match_table = vmmc_match, + }, +}; + +module_platform_driver(vmmc_driver); diff --git a/arch/mips/lantiq/xway/xrx200_phy_fw.c b/arch/mips/lantiq/xway/xrx200_phy_fw.c index d4d9d31..7c1e54c 100644 --- a/arch/mips/lantiq/xway/xrx200_phy_fw.c +++ b/arch/mips/lantiq/xway/xrx200_phy_fw.c @@ -24,7 +24,28 @@ static dma_addr_t xway_gphy_load(struct platform_device *pdev) void *fw_addr; size_t size; - if (of_property_read_string(pdev->dev.of_node, "firmware", &fw_name)) { + if (of_get_property(pdev->dev.of_node, "firmware1", NULL) || + of_get_property(pdev->dev.of_node, "firmware2", NULL)) { + switch (ltq_soc_type()) { + case SOC_TYPE_VR9: + if (of_property_read_string(pdev->dev.of_node, + "firmware1", &fw_name)) { + dev_err(&pdev->dev, + "failed to load firmware filename\n"); + return 0; + } + break; + case SOC_TYPE_VR9_2: + if (of_property_read_string(pdev->dev.of_node, + "firmware2", &fw_name)) { + dev_err(&pdev->dev, + "failed to load firmware filename\n"); + return 0; + } + break; + } + } else if (of_property_read_string(pdev->dev.of_node, + "firmware", &fw_name)) { dev_err(&pdev->dev, "failed to load firmware filename\n"); return 0; } diff --git a/arch/mips/lib/iomap.c b/arch/mips/lib/iomap.c index e3acb2d..8e7e378 100644 --- a/arch/mips/lib/iomap.c +++ b/arch/mips/lib/iomap.c @@ -97,14 +97,14 @@ EXPORT_SYMBOL(iowrite32be); /* * These are the "repeat MMIO read/write" functions. - * Note the "__raw" accesses, since we don't want to - * convert to CPU byte order. We write in "IO byte - * order" (we also don't have IO barriers). + * Note the "__mem" accesses, since we want to convert + * to CPU byte order if the host bus happens to not match the + * endianness of PCI/ISA (see mach-generic/mangle-port.h). */ static inline void mmio_insb(void __iomem *addr, u8 *dst, int count) { while (--count >= 0) { - u8 data = __raw_readb(addr); + u8 data = __mem_readb(addr); *dst = data; dst++; } @@ -113,7 +113,7 @@ static inline void mmio_insb(void __iomem *addr, u8 *dst, int count) static inline void mmio_insw(void __iomem *addr, u16 *dst, int count) { while (--count >= 0) { - u16 data = __raw_readw(addr); + u16 data = __mem_readw(addr); *dst = data; dst++; } @@ -122,7 +122,7 @@ static inline void mmio_insw(void __iomem *addr, u16 *dst, int count) static inline void mmio_insl(void __iomem *addr, u32 *dst, int count) { while (--count >= 0) { - u32 data = __raw_readl(addr); + u32 data = __mem_readl(addr); *dst = data; dst++; } @@ -131,7 +131,7 @@ static inline void mmio_insl(void __iomem *addr, u32 *dst, int count) static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count) { while (--count >= 0) { - __raw_writeb(*src, addr); + __mem_writeb(*src, addr); src++; } } @@ -139,7 +139,7 @@ static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count) static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count) { while (--count >= 0) { - __raw_writew(*src, addr); + __mem_writew(*src, addr); src++; } } @@ -147,7 +147,7 @@ static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count) static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count) { while (--count >= 0) { - __raw_writel(*src, addr); + __mem_writel(*src, addr); src++; } } diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 7b0e546..c8fe6b1 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -114,8 +114,7 @@ R10KCBARRIER(0(ra)) #ifdef __MIPSEB__ EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */ -#endif -#ifdef __MIPSEL__ +#else EX(LONG_S_R, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */ #endif PTR_SUBU a0, t0 /* long align ptr */ @@ -164,8 +163,7 @@ R10KCBARRIER(0(ra)) #ifdef __MIPSEB__ EX(LONG_S_R, a1, -1(a0), .Llast_fixup\@) -#endif -#ifdef __MIPSEL__ +#else EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@) #endif 1: jr ra diff --git a/arch/mips/lib/mips-atomic.c b/arch/mips/lib/mips-atomic.c index 57bcdaf1..be777d9 100644 --- a/arch/mips/lib/mips-atomic.c +++ b/arch/mips/lib/mips-atomic.c @@ -42,15 +42,11 @@ notrace void arch_local_irq_disable(void) __asm__ __volatile__( " .set push \n" " .set noat \n" -#if defined(CONFIG_CPU_MIPSR2) - /* see irqflags.h for inline function */ -#else " mfc0 $1,$12 \n" " ori $1,0x1f \n" " xori $1,0x1f \n" " .set noreorder \n" " mtc0 $1,$12 \n" -#endif " " __stringify(__irq_disable_hazard) " \n" " .set pop \n" : /* no outputs */ @@ -72,15 +68,11 @@ notrace unsigned long arch_local_irq_save(void) " .set push \n" " .set reorder \n" " .set noat \n" -#if defined(CONFIG_CPU_MIPSR2) - /* see irqflags.h for inline function */ -#else " mfc0 %[flags], $12 \n" " ori $1, %[flags], 0x1f \n" " xori $1, 0x1f \n" " .set noreorder \n" " mtc0 $1, $12 \n" -#endif " " __stringify(__irq_disable_hazard) " \n" " .set pop \n" : [flags] "=r" (flags) @@ -103,18 +95,12 @@ notrace void arch_local_irq_restore(unsigned long flags) " .set push \n" " .set noreorder \n" " .set noat \n" -#if defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) - /* see irqflags.h for inline function */ -#elif defined(CONFIG_CPU_MIPSR2) - /* see irqflags.h for inline function */ -#else " mfc0 $1, $12 \n" " andi %[flags], 1 \n" " ori $1, 0x1f \n" " xori $1, 0x1f \n" " or %[flags], $1 \n" " mtc0 %[flags], $12 \n" -#endif " " __stringify(__irq_disable_hazard) " \n" " .set pop \n" : [flags] "=r" (__tmp1) @@ -136,18 +122,12 @@ notrace void __arch_local_irq_restore(unsigned long flags) " .set push \n" " .set noreorder \n" " .set noat \n" -#if defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) - /* see irqflags.h for inline function */ -#elif defined(CONFIG_CPU_MIPSR2) - /* see irqflags.h for inline function */ -#else " mfc0 $1, $12 \n" " andi %[flags], 1 \n" " ori $1, 0x1f \n" " xori $1, 0x1f \n" " or %[flags], $1 \n" " mtc0 %[flags], $12 \n" -#endif " " __stringify(__irq_disable_hazard) " \n" " .set pop \n" : [flags] "=r" (__tmp1) diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index 1ef365a..975a138 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -9,6 +9,7 @@ #include <linux/mm.h> #include <asm/mipsregs.h> +#include <asm/mmu_context.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/tlbdebug.h> @@ -21,7 +22,7 @@ static void dump_tlb(int first, int last) unsigned int asid; unsigned long entryhi, entrylo0; - asid = read_c0_entryhi() & 0xfc0; + asid = read_c0_entryhi() & ASID_MASK; for (i = first; i <= last; i++) { write_c0_index(i<<8); @@ -34,8 +35,8 @@ static void dump_tlb(int first, int last) entrylo0 = read_c0_entrylo0(); /* Unused entries have a virtual address of KSEG0. */ - if ((entryhi & 0xfffff000) != 0x80000000 - && (entryhi & 0xfc0) == asid) { + if ((entryhi & PAGE_MASK) != KSEG0 + && (entryhi & ASID_MASK) == asid) { /* * Only print entries in use */ @@ -43,8 +44,8 @@ static void dump_tlb(int first, int last) printk("va=%08lx asid=%08lx" " [pa=%06lx n=%d d=%d v=%d g=%d]", - (entryhi & 0xfffff000), - entryhi & 0xfc0, + entryhi & PAGE_MASK, + entryhi & ASID_MASK, entrylo0 & PAGE_MASK, (entrylo0 & (1 << 11)) ? 1 : 0, (entrylo0 & (1 << 10)) ? 1 : 0, diff --git a/arch/mips/lib/strlen_user.S b/arch/mips/lib/strlen_user.S index bef65c9..929bbac 100644 --- a/arch/mips/lib/strlen_user.S +++ b/arch/mips/lib/strlen_user.S @@ -28,7 +28,6 @@ LEAF(__strlen_\func\()_asm) and v0, a0 bnez v0, .Lfault\@ -FEXPORT(__strlen_\func\()_nocheck_asm) move v0, a0 .ifeqs "\func", "kernel" 1: EX(lbu, v1, (v0), .Lfault\@) @@ -48,9 +47,7 @@ FEXPORT(__strlen_\func\()_nocheck_asm) #ifndef CONFIG_EVA /* Set aliases */ .global __strlen_user_asm - .global __strlen_user_nocheck_asm .set __strlen_user_asm, __strlen_kernel_asm - .set __strlen_user_nocheck_asm, __strlen_kernel_nocheck_asm #endif __BUILD_STRLEN_ASM kernel diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig index 1b91fc6..156de85 100644 --- a/arch/mips/loongson/Kconfig +++ b/arch/mips/loongson/Kconfig @@ -86,6 +86,7 @@ config LOONGSON_MACH3X select LOONGSON_MC146818 select ZONE_DMA32 select LEFI_FIRMWARE_INTERFACE + select PHYS48_TO_HT40 help Generic Loongson 3 family machines utilize the 3A/3B revision of Loongson processor and RS780/SBX00 chipset. @@ -107,6 +108,18 @@ config CS5536_MFGPT If unsure, say Yes. +config RS780_HPET + bool "RS780/SBX00 HPET Timer" + depends on LOONGSON_MACH3X + select MIPS_EXTERNAL_TIMER + help + This option enables the hpet timer of AMD RS780/SBX00. + + If you want to enable the Loongson3 CPUFreq Driver, Please enable + this option at first, otherwise, You will get wrong system time. + + If unsure, say Yes. + config LOONGSON_SUSPEND bool default y @@ -131,6 +144,10 @@ config SWIOTLB select NEED_SG_DMA_LENGTH select NEED_DMA_MAP_STATE +config PHYS48_TO_HT40 + bool + default y if CPU_LOONGSON3 + config LOONGSON_MC146818 bool default n diff --git a/arch/mips/loongson/common/cs5536/cs5536_pci.c b/arch/mips/loongson/common/cs5536/cs5536_pci.c index 81bed9d..b739723 100644 --- a/arch/mips/loongson/common/cs5536/cs5536_pci.c +++ b/arch/mips/loongson/common/cs5536/cs5536_pci.c @@ -21,6 +21,7 @@ */ #include <linux/types.h> +#include <cs5536/cs5536_pci.h> #include <cs5536/cs5536_vsm.h> enum { @@ -35,21 +36,21 @@ enum { }; static const cs5536_pci_vsm_write vsm_conf_write[] = { - [CS5536_ISA_FUNC] pci_isa_write_reg, - [reserved_func] NULL, - [CS5536_IDE_FUNC] pci_ide_write_reg, - [CS5536_ACC_FUNC] pci_acc_write_reg, - [CS5536_OHCI_FUNC] pci_ohci_write_reg, - [CS5536_EHCI_FUNC] pci_ehci_write_reg, + [CS5536_ISA_FUNC] = pci_isa_write_reg, + [reserved_func] = NULL, + [CS5536_IDE_FUNC] = pci_ide_write_reg, + [CS5536_ACC_FUNC] = pci_acc_write_reg, + [CS5536_OHCI_FUNC] = pci_ohci_write_reg, + [CS5536_EHCI_FUNC] = pci_ehci_write_reg, }; static const cs5536_pci_vsm_read vsm_conf_read[] = { - [CS5536_ISA_FUNC] pci_isa_read_reg, - [reserved_func] NULL, - [CS5536_IDE_FUNC] pci_ide_read_reg, - [CS5536_ACC_FUNC] pci_acc_read_reg, - [CS5536_OHCI_FUNC] pci_ohci_read_reg, - [CS5536_EHCI_FUNC] pci_ehci_read_reg, + [CS5536_ISA_FUNC] = pci_isa_read_reg, + [reserved_func] = NULL, + [CS5536_IDE_FUNC] = pci_ide_read_reg, + [CS5536_ACC_FUNC] = pci_acc_read_reg, + [CS5536_OHCI_FUNC] = pci_ohci_read_reg, + [CS5536_EHCI_FUNC] = pci_ehci_read_reg, }; /* diff --git a/arch/mips/loongson/common/dma-swiotlb.c b/arch/mips/loongson/common/dma-swiotlb.c index c2be01f..2c6b989 100644 --- a/arch/mips/loongson/common/dma-swiotlb.c +++ b/arch/mips/loongson/common/dma-swiotlb.c @@ -105,11 +105,25 @@ static int loongson_dma_set_mask(struct device *dev, u64 mask) dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) { + long nid; +#ifdef CONFIG_PHYS48_TO_HT40 + /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from + * Loongson-3's 48bit address space and embed it into 40bit */ + nid = (paddr >> 44) & 0x3; + paddr = ((nid << 44) ^ paddr) | (nid << 37); +#endif return paddr; } phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) { + long nid; +#ifdef CONFIG_PHYS48_TO_HT40 + /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from + * Loongson-3's 48bit address space and embed it into 40bit */ + nid = (daddr >> 37) & 0x3; + daddr = ((nid << 37) ^ daddr) | (nid << 44); +#endif return daddr; } diff --git a/arch/mips/loongson/common/early_printk.c b/arch/mips/loongson/common/early_printk.c index ced461b..6ca632e 100644 --- a/arch/mips/loongson/common/early_printk.c +++ b/arch/mips/loongson/common/early_printk.c @@ -30,7 +30,7 @@ void prom_putchar(char c) int timeout; unsigned char *uart_base; - uart_base = (unsigned char *)_loongson_uart_base; + uart_base = (unsigned char *)_loongson_uart_base[0]; timeout = 1024; while (((serial_in(uart_base, UART_LSR) & UART_LSR_THRE) == 0) && diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index f152285..045ea3d 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c @@ -21,6 +21,7 @@ #include <asm/bootinfo.h> #include <loongson.h> #include <boot_param.h> +#include <workarounds.h> u32 cpu_clock_freq; EXPORT_SYMBOL(cpu_clock_freq); @@ -31,7 +32,6 @@ u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180}; u64 loongson_freqctrl[MAX_PACKAGES]; unsigned long long smp_group[4]; -int cpuhotplug_workaround = 0; #define parse_even_earlier(res, option, p) \ do { \ @@ -67,6 +67,7 @@ void __init prom_init_env(void) #else struct boot_params *boot_p; struct loongson_params *loongson_p; + struct system_loongson *esys; struct efi_cpuinfo_loongson *ecpu; struct irq_source_routing_table *eirq_source; @@ -74,6 +75,8 @@ void __init prom_init_env(void) boot_p = (struct boot_params *)fw_arg2; loongson_p = &(boot_p->efi.smbios.lp); + esys = (struct system_loongson *) + ((u64)loongson_p + loongson_p->system_offset); ecpu = (struct efi_cpuinfo_loongson *) ((u64)loongson_p + loongson_p->cpu_offset); eirq_source = (struct irq_source_routing_table *) @@ -95,6 +98,7 @@ void __init prom_init_env(void) loongson_chipcfg[2] = 0x900020001fe00180; loongson_chipcfg[3] = 0x900030001fe00180; loongson_sysconf.ht_control_base = 0x90000EFDFB000000; + loongson_sysconf.workarounds = WORKAROUND_CPUFREQ; } else if (ecpu->cputype == Loongson_3B) { loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */ loongson_sysconf.cores_per_package = 8; @@ -111,7 +115,7 @@ void __init prom_init_env(void) loongson_freqctrl[2] = 0x900040001fe001d0; loongson_freqctrl[3] = 0x900060001fe001d0; loongson_sysconf.ht_control_base = 0x90001EFDFB000000; - cpuhotplug_workaround = 1; + loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG; } else { loongson_sysconf.cores_per_node = 1; loongson_sysconf.cores_per_package = 1; @@ -119,6 +123,8 @@ void __init prom_init_env(void) } loongson_sysconf.nr_cpus = ecpu->nr_cpus; + loongson_sysconf.boot_cpu_id = ecpu->cpu_startup_core_id; + loongson_sysconf.reserved_cpus_mask = ecpu->reserved_cores_mask; if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0) loongson_sysconf.nr_cpus = NR_CPUS; loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus + @@ -141,6 +147,24 @@ void __init prom_init_env(void) pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n", loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr, loongson_sysconf.vgabios_addr); + + memset(loongson_sysconf.ecname, 0, 32); + if (esys->has_ec) + memcpy(loongson_sysconf.ecname, esys->ec_name, 32); + loongson_sysconf.workarounds |= esys->workarounds; + + loongson_sysconf.nr_uarts = esys->nr_uarts; + if (esys->nr_uarts < 1 || esys->nr_uarts > MAX_UARTS) + loongson_sysconf.nr_uarts = 1; + memcpy(loongson_sysconf.uarts, esys->uarts, + sizeof(struct uart_device) * loongson_sysconf.nr_uarts); + + loongson_sysconf.nr_sensors = esys->nr_sensors; + if (loongson_sysconf.nr_sensors > MAX_SENSORS) + loongson_sysconf.nr_sensors = 0; + if (loongson_sysconf.nr_sensors) + memcpy(loongson_sysconf.sensors, esys->sensors, + sizeof(struct sensor_device) * loongson_sysconf.nr_sensors); #endif if (cpu_clock_freq == 0) { processor_id = (¤t_cpu_data)->processor_id; diff --git a/arch/mips/loongson/common/gpio.c b/arch/mips/loongson/common/gpio.c index 2186990..29dbaa2 100644 --- a/arch/mips/loongson/common/gpio.c +++ b/arch/mips/loongson/common/gpio.c @@ -37,7 +37,7 @@ int gpio_get_value(unsigned gpio) val = LOONGSON_GPIODATA; spin_unlock(&gpio_lock); - return ((val & mask) != 0); + return (val & mask) != 0; } EXPORT_SYMBOL(gpio_get_value); diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c index f6af3ab..9b987fe 100644 --- a/arch/mips/loongson/common/init.c +++ b/arch/mips/loongson/common/init.c @@ -9,6 +9,7 @@ */ #include <linux/bootmem.h> +#include <asm/bootinfo.h> #include <asm/smp-ops.h> #include <loongson.h> diff --git a/arch/mips/loongson/common/machtype.c b/arch/mips/loongson/common/machtype.c index 1a47979..f2807bc 100644 --- a/arch/mips/loongson/common/machtype.c +++ b/arch/mips/loongson/common/machtype.c @@ -19,19 +19,16 @@ #define MACHTYPE_LEN 50 static const char *system_types[] = { - [MACH_LOONGSON_UNKNOWN] "unknown loongson machine", - [MACH_LEMOTE_FL2E] "lemote-fuloong-2e-box", - [MACH_LEMOTE_FL2F] "lemote-fuloong-2f-box", - [MACH_LEMOTE_ML2F7] "lemote-mengloong-2f-7inches", - [MACH_LEMOTE_YL2F89] "lemote-yeeloong-2f-8.9inches", - [MACH_DEXXON_GDIUM2F10] "dexxon-gdium-2f", - [MACH_LEMOTE_NAS] "lemote-nas-2f", - [MACH_LEMOTE_LL2F] "lemote-lynloong-2f", - [MACH_LEMOTE_A1004] "lemote-3a-notebook-a1004", - [MACH_LEMOTE_A1101] "lemote-3a-itx-a1101", - [MACH_LEMOTE_A1201] "lemote-2gq-notebook-a1201", - [MACH_LEMOTE_A1205] "lemote-2gq-aio-a1205", - [MACH_LOONGSON_END] NULL, + [MACH_LOONGSON_UNKNOWN] = "unknown loongson machine", + [MACH_LEMOTE_FL2E] = "lemote-fuloong-2e-box", + [MACH_LEMOTE_FL2F] = "lemote-fuloong-2f-box", + [MACH_LEMOTE_ML2F7] = "lemote-mengloong-2f-7inches", + [MACH_LEMOTE_YL2F89] = "lemote-yeeloong-2f-8.9inches", + [MACH_DEXXON_GDIUM2F10] = "dexxon-gdium-2f", + [MACH_LEMOTE_NAS] = "lemote-nas-2f", + [MACH_LEMOTE_LL2F] = "lemote-lynloong-2f", + [MACH_LOONGSON_GENERIC] = "generic-loongson-machine", + [MACH_LOONGSON_END] = NULL, }; const char *get_system_type(void) diff --git a/arch/mips/loongson/common/rtc.c b/arch/mips/loongson/common/rtc.c index a90d87c..b5709af 100644 --- a/arch/mips/loongson/common/rtc.c +++ b/arch/mips/loongson/common/rtc.c @@ -14,7 +14,7 @@ #include <linux/platform_device.h> #include <linux/mc146818rtc.h> -struct resource loongson_rtc_resources[] = { +static struct resource loongson_rtc_resources[] = { { .start = RTC_PORT(0), .end = RTC_PORT(1), diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c index bd2b709..c23fa13 100644 --- a/arch/mips/loongson/common/serial.c +++ b/arch/mips/loongson/common/serial.c @@ -38,20 +38,17 @@ .regshift = 0, \ } -static struct plat_serial8250_port uart8250_data[][2] = { - [MACH_LOONGSON_UNKNOWN] {}, - [MACH_LEMOTE_FL2E] {PORT(4, 1843200), {} }, - [MACH_LEMOTE_FL2F] {PORT(3, 1843200), {} }, - [MACH_LEMOTE_ML2F7] {PORT_M(3, 3686400), {} }, - [MACH_LEMOTE_YL2F89] {PORT_M(3, 3686400), {} }, - [MACH_DEXXON_GDIUM2F10] {PORT_M(3, 3686400), {} }, - [MACH_LEMOTE_NAS] {PORT_M(3, 3686400), {} }, - [MACH_LEMOTE_LL2F] {PORT(3, 1843200), {} }, - [MACH_LEMOTE_A1004] {PORT_M(2, 33177600), {} }, - [MACH_LEMOTE_A1101] {PORT_M(2, 25000000), {} }, - [MACH_LEMOTE_A1201] {PORT_M(2, 25000000), {} }, - [MACH_LEMOTE_A1205] {PORT_M(2, 25000000), {} }, - [MACH_LOONGSON_END] {}, +static struct plat_serial8250_port uart8250_data[][MAX_UARTS + 1] = { + [MACH_LOONGSON_UNKNOWN] = {}, + [MACH_LEMOTE_FL2E] = {PORT(4, 1843200), {} }, + [MACH_LEMOTE_FL2F] = {PORT(3, 1843200), {} }, + [MACH_LEMOTE_ML2F7] = {PORT_M(3, 3686400), {} }, + [MACH_LEMOTE_YL2F89] = {PORT_M(3, 3686400), {} }, + [MACH_DEXXON_GDIUM2F10] = {PORT_M(3, 3686400), {} }, + [MACH_LEMOTE_NAS] = {PORT_M(3, 3686400), {} }, + [MACH_LEMOTE_LL2F] = {PORT(3, 1843200), {} }, + [MACH_LOONGSON_GENERIC] = {PORT_M(2, 25000000), {} }, + [MACH_LOONGSON_END] = {}, }; static struct platform_device uart8250_device = { @@ -61,17 +58,52 @@ static struct platform_device uart8250_device = { static int __init serial_init(void) { + int i; unsigned char iotype; iotype = uart8250_data[mips_machtype][0].iotype; - if (UPIO_MEM == iotype) + if (UPIO_MEM == iotype) { + uart8250_data[mips_machtype][0].mapbase = + loongson_uart_base[0]; uart8250_data[mips_machtype][0].membase = - (void __iomem *)_loongson_uart_base; + (void __iomem *)_loongson_uart_base[0]; + } else if (UPIO_PORT == iotype) uart8250_data[mips_machtype][0].iobase = - loongson_uart_base - LOONGSON_PCIIO_BASE; + loongson_uart_base[0] - LOONGSON_PCIIO_BASE; + if (loongson_sysconf.uarts[0].uartclk) + uart8250_data[mips_machtype][0].uartclk = + loongson_sysconf.uarts[0].uartclk; + + for (i = 1; i < loongson_sysconf.nr_uarts; i++) { + iotype = loongson_sysconf.uarts[i].iotype; + uart8250_data[mips_machtype][i].iotype = iotype; + loongson_uart_base[i] = loongson_sysconf.uarts[i].uart_base; + + if (UPIO_MEM == iotype) { + uart8250_data[mips_machtype][i].irq = + MIPS_CPU_IRQ_BASE + loongson_sysconf.uarts[i].int_offset; + uart8250_data[mips_machtype][i].mapbase = + loongson_uart_base[i]; + uart8250_data[mips_machtype][i].membase = + ioremap_nocache(loongson_uart_base[i], 8); + } else if (UPIO_PORT == iotype) { + uart8250_data[mips_machtype][i].irq = + loongson_sysconf.uarts[i].int_offset; + uart8250_data[mips_machtype][i].iobase = + loongson_uart_base[i] - LOONGSON_PCIIO_BASE; + } + + uart8250_data[mips_machtype][i].uartclk = + loongson_sysconf.uarts[i].uartclk; + uart8250_data[mips_machtype][i].flags = + UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + } + + memset(&uart8250_data[mips_machtype][loongson_sysconf.nr_uarts], + 0, sizeof(struct plat_serial8250_port)); uart8250_device.dev.platform_data = uart8250_data[mips_machtype]; return platform_device_register(&uart8250_device); diff --git a/arch/mips/loongson/common/setup.c b/arch/mips/loongson/common/setup.c index bb4ac92..d477dd6 100644 --- a/arch/mips/loongson/common/setup.c +++ b/arch/mips/loongson/common/setup.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <asm/wbflush.h> +#include <asm/bootinfo.h> #include <loongson.h> diff --git a/arch/mips/loongson/common/time.c b/arch/mips/loongson/common/time.c index 262a1f6..e1a5382a 100644 --- a/arch/mips/loongson/common/time.c +++ b/arch/mips/loongson/common/time.c @@ -12,6 +12,7 @@ */ #include <asm/mc146818-time.h> #include <asm/time.h> +#include <asm/hpet.h> #include <loongson.h> #include <cs5536/cs5536_mfgpt.h> @@ -21,7 +22,11 @@ void __init plat_time_init(void) /* setup mips r4k timer */ mips_hpt_frequency = cpu_clock_freq / 2; +#ifdef CONFIG_RS780_HPET + setup_hpet_timer(); +#else setup_mfgpt0_timer(); +#endif } void read_persistent_clock(struct timespec *ts) diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c index 1e1eeea..9de559d 100644 --- a/arch/mips/loongson/common/uart_base.c +++ b/arch/mips/loongson/common/uart_base.c @@ -13,22 +13,27 @@ #include <loongson.h> -/* ioremapped */ -unsigned long _loongson_uart_base; -EXPORT_SYMBOL(_loongson_uart_base); /* raw */ -unsigned long loongson_uart_base; +unsigned long loongson_uart_base[MAX_UARTS] = {}; +/* ioremapped */ +unsigned long _loongson_uart_base[MAX_UARTS] = {}; + EXPORT_SYMBOL(loongson_uart_base); +EXPORT_SYMBOL(_loongson_uart_base); void prom_init_loongson_uart_base(void) { switch (mips_machtype) { + case MACH_LOONGSON_GENERIC: + /* The CPU provided serial port (CPU) */ + loongson_uart_base[0] = LOONGSON_REG_BASE + 0x1e0; + break; case MACH_LEMOTE_FL2E: - loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8; + loongson_uart_base[0] = LOONGSON_PCIIO_BASE + 0x3f8; break; case MACH_LEMOTE_FL2F: case MACH_LEMOTE_LL2F: - loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8; + loongson_uart_base[0] = LOONGSON_PCIIO_BASE + 0x2f8; break; case MACH_LEMOTE_ML2F7: case MACH_LEMOTE_YL2F89: @@ -36,17 +41,10 @@ void prom_init_loongson_uart_base(void) case MACH_LEMOTE_NAS: default: /* The CPU provided serial port (LPC) */ - loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8; - break; - case MACH_LEMOTE_A1004: - case MACH_LEMOTE_A1101: - case MACH_LEMOTE_A1201: - case MACH_LEMOTE_A1205: - /* The CPU provided serial port (CPU) */ - loongson_uart_base = LOONGSON_REG_BASE + 0x1e0; + loongson_uart_base[0] = LOONGSON_LIO1_BASE + 0x3f8; break; } - _loongson_uart_base = - (unsigned long)ioremap_nocache(loongson_uart_base, 8); + _loongson_uart_base[0] = + (unsigned long)ioremap_nocache(loongson_uart_base[0], 8); } diff --git a/arch/mips/loongson/lemote-2f/irq.c b/arch/mips/loongson/lemote-2f/irq.c index 6f8682e..cab5f43 100644 --- a/arch/mips/loongson/lemote-2f/irq.c +++ b/arch/mips/loongson/lemote-2f/irq.c @@ -93,13 +93,13 @@ static irqreturn_t ip6_action(int cpl, void *dev_id) return IRQ_HANDLED; } -struct irqaction ip6_irqaction = { +static struct irqaction ip6_irqaction = { .handler = ip6_action, .name = "cascade", .flags = IRQF_SHARED | IRQF_NO_THREAD, }; -struct irqaction cascade_irqaction = { +static struct irqaction cascade_irqaction = { .handler = no_action, .name = "cascade", .flags = IRQF_NO_THREAD, diff --git a/arch/mips/loongson/lemote-2f/reset.c b/arch/mips/loongson/lemote-2f/reset.c index 79ac694..a26ca7f 100644 --- a/arch/mips/loongson/lemote-2f/reset.c +++ b/arch/mips/loongson/lemote-2f/reset.c @@ -76,7 +76,7 @@ static void fl2f_shutdown(void) /* reset support for yeeloong2f and mengloong2f notebook */ -void ml2f_reboot(void) +static void ml2f_reboot(void) { reset_cpu(); diff --git a/arch/mips/loongson/loongson-3/Makefile b/arch/mips/loongson/loongson-3/Makefile index b4df775..622fead 100644 --- a/arch/mips/loongson/loongson-3/Makefile +++ b/arch/mips/loongson/loongson-3/Makefile @@ -1,8 +1,10 @@ # # Makefile for Loongson-3 family machines # -obj-y += irq.o cop2-ex.o +obj-y += irq.o cop2-ex.o platform.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_NUMA) += numa.o + +obj-$(CONFIG_RS780_HPET) += hpet.o diff --git a/arch/mips/loongson/loongson-3/hpet.c b/arch/mips/loongson/loongson-3/hpet.c new file mode 100644 index 0000000..e898d68 --- /dev/null +++ b/arch/mips/loongson/loongson-3/hpet.c @@ -0,0 +1,257 @@ +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/percpu.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> + +#include <asm/hpet.h> +#include <asm/time.h> + +#define SMBUS_CFG_BASE (loongson_sysconf.ht_control_base + 0x0300a000) +#define SMBUS_PCI_REG40 0x40 +#define SMBUS_PCI_REG64 0x64 +#define SMBUS_PCI_REGB4 0xb4 + +static DEFINE_SPINLOCK(hpet_lock); +DEFINE_PER_CPU(struct clock_event_device, hpet_clockevent_device); + +static unsigned int smbus_read(int offset) +{ + return *(volatile unsigned int *)(SMBUS_CFG_BASE + offset); +} + +static void smbus_write(int offset, int data) +{ + *(volatile unsigned int *)(SMBUS_CFG_BASE + offset) = data; +} + +static void smbus_enable(int offset, int bit) +{ + unsigned int cfg = smbus_read(offset); + + cfg |= bit; + smbus_write(offset, cfg); +} + +static int hpet_read(int offset) +{ + return *(volatile unsigned int *)(HPET_MMIO_ADDR + offset); +} + +static void hpet_write(int offset, int data) +{ + *(volatile unsigned int *)(HPET_MMIO_ADDR + offset) = data; +} + +static void hpet_start_counter(void) +{ + unsigned int cfg = hpet_read(HPET_CFG); + + cfg |= HPET_CFG_ENABLE; + hpet_write(HPET_CFG, cfg); +} + +static void hpet_stop_counter(void) +{ + unsigned int cfg = hpet_read(HPET_CFG); + + cfg &= ~HPET_CFG_ENABLE; + hpet_write(HPET_CFG, cfg); +} + +static void hpet_reset_counter(void) +{ + hpet_write(HPET_COUNTER, 0); + hpet_write(HPET_COUNTER + 4, 0); +} + +static void hpet_restart_counter(void) +{ + hpet_stop_counter(); + hpet_reset_counter(); + hpet_start_counter(); +} + +static void hpet_enable_legacy_int(void) +{ + /* Do nothing on Loongson-3 */ +} + +static void hpet_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + int cfg = 0; + + spin_lock(&hpet_lock); + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + pr_info("set clock event to periodic mode!\n"); + /* stop counter */ + hpet_stop_counter(); + + /* enables the timer0 to generate a periodic interrupt */ + cfg = hpet_read(HPET_T0_CFG); + cfg &= ~HPET_TN_LEVEL; + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | + HPET_TN_SETVAL | HPET_TN_32BIT; + hpet_write(HPET_T0_CFG, cfg); + + /* set the comparator */ + hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); + udelay(1); + hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); + + /* start counter */ + hpet_start_counter(); + break; + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + cfg = hpet_read(HPET_T0_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_write(HPET_T0_CFG, cfg); + break; + case CLOCK_EVT_MODE_ONESHOT: + pr_info("set clock event to one shot mode!\n"); + cfg = hpet_read(HPET_T0_CFG); + /* set timer0 type + * 1 : periodic interrupt + * 0 : non-periodic(oneshot) interrupt + */ + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + hpet_write(HPET_T0_CFG, cfg); + break; + case CLOCK_EVT_MODE_RESUME: + hpet_enable_legacy_int(); + break; + } + spin_unlock(&hpet_lock); +} + +static int hpet_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + unsigned int cnt; + int res; + + cnt = hpet_read(HPET_COUNTER); + cnt += delta; + hpet_write(HPET_T0_CMP, cnt); + + res = ((int)(hpet_read(HPET_COUNTER) - cnt) > 0) ? -ETIME : 0; + return res; +} + +static irqreturn_t hpet_irq_handler(int irq, void *data) +{ + int is_irq; + struct clock_event_device *cd; + unsigned int cpu = smp_processor_id(); + + is_irq = hpet_read(HPET_STATUS); + if (is_irq & HPET_T0_IRS) { + /* clear the TIMER0 irq status register */ + hpet_write(HPET_STATUS, HPET_T0_IRS); + cd = &per_cpu(hpet_clockevent_device, cpu); + cd->event_handler(cd); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static struct irqaction hpet_irq = { + .handler = hpet_irq_handler, + .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, + .name = "hpet", +}; + +/* + * hpet address assignation and irq setting should be done in bios. + * but pmon don't do this, we just setup here directly. + * The operation under is normal. unfortunately, hpet_setup process + * is before pci initialize. + * + * { + * struct pci_dev *pdev; + * + * pdev = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); + * pci_write_config_word(pdev, SMBUS_PCI_REGB4, HPET_ADDR); + * + * ... + * } + */ +static void hpet_setup(void) +{ + /* set hpet base address */ + smbus_write(SMBUS_PCI_REGB4, HPET_ADDR); + + /* enable decodeing of access to HPET MMIO*/ + smbus_enable(SMBUS_PCI_REG40, (1 << 28)); + + /* HPET irq enable */ + smbus_enable(SMBUS_PCI_REG64, (1 << 10)); + + hpet_enable_legacy_int(); +} + +void __init setup_hpet_timer(void) +{ + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd; + + hpet_setup(); + + cd = &per_cpu(hpet_clockevent_device, cpu); + cd->name = "hpet"; + cd->rating = 320; + cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + cd->set_mode = hpet_set_mode; + cd->set_next_event = hpet_next_event; + cd->irq = HPET_T0_IRQ; + cd->cpumask = cpumask_of(cpu); + clockevent_set_clock(cd, HPET_FREQ); + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = 5000; + + clockevents_register_device(cd); + setup_irq(HPET_T0_IRQ, &hpet_irq); + pr_info("hpet clock event device register\n"); +} + +static cycle_t hpet_read_counter(struct clocksource *cs) +{ + return (cycle_t)hpet_read(HPET_COUNTER); +} + +static void hpet_suspend(struct clocksource *cs) +{ +} + +static void hpet_resume(struct clocksource *cs) +{ + hpet_setup(); + hpet_restart_counter(); +} + +static struct clocksource csrc_hpet = { + .name = "hpet", + /* mips clocksource rating is less than 300, so hpet is better. */ + .rating = 300, + .read = hpet_read_counter, + .mask = CLOCKSOURCE_MASK(32), + /* oneshot mode work normal with this flag */ + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .suspend = hpet_suspend, + .resume = hpet_resume, + .mult = 0, + .shift = 10, +}; + +int __init init_hpet_clocksource(void) +{ + csrc_hpet.mult = clocksource_hz2mult(HPET_FREQ, csrc_hpet.shift); + return clocksource_register_hz(&csrc_hpet, HPET_FREQ); +} + +arch_initcall(init_hpet_clocksource); diff --git a/arch/mips/loongson/loongson-3/irq.c b/arch/mips/loongson/loongson-3/irq.c index ca1c62a..21221ed 100644 --- a/arch/mips/loongson/loongson-3/irq.c +++ b/arch/mips/loongson/loongson-3/irq.c @@ -9,7 +9,7 @@ #include "smp.h" -unsigned int ht_irq[] = {1, 3, 4, 5, 6, 7, 8, 12, 14, 15}; +unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15}; static void ht_irqdispatch(void) { @@ -55,8 +55,8 @@ static inline void mask_loongson_irq(struct irq_data *d) /* Workaround: UART IRQ may deliver to any core */ if (d->irq == LOONGSON_UART_IRQ) { int cpu = smp_processor_id(); - int node_id = cpu / loongson_sysconf.cores_per_node; - int core_id = cpu % loongson_sysconf.cores_per_node; + int node_id = cpu_logical_map(cpu) / loongson_sysconf.cores_per_node; + int core_id = cpu_logical_map(cpu) % loongson_sysconf.cores_per_node; u64 intenclr_addr = smp_group[node_id] | (u64)(&LOONGSON_INT_ROUTER_INTENCLR); u64 introuter_lpc_addr = smp_group[node_id] | @@ -72,8 +72,8 @@ static inline void unmask_loongson_irq(struct irq_data *d) /* Workaround: UART IRQ may deliver to any core */ if (d->irq == LOONGSON_UART_IRQ) { int cpu = smp_processor_id(); - int node_id = cpu / loongson_sysconf.cores_per_node; - int core_id = cpu % loongson_sysconf.cores_per_node; + int node_id = cpu_logical_map(cpu) / loongson_sysconf.cores_per_node; + int core_id = cpu_logical_map(cpu) % loongson_sysconf.cores_per_node; u64 intenset_addr = smp_group[node_id] | (u64)(&LOONGSON_INT_ROUTER_INTENSET); u64 introuter_lpc_addr = smp_group[node_id] | @@ -102,10 +102,12 @@ void irq_router_init(void) int i; /* route LPC int to cpu core0 int 0 */ - LOONGSON_INT_ROUTER_LPC = LOONGSON_INT_CORE0_INT0; + LOONGSON_INT_ROUTER_LPC = + LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 0); /* route HT1 int0 ~ int7 to cpu core0 INT1*/ for (i = 0; i < 8; i++) - LOONGSON_INT_ROUTER_HT1(i) = LOONGSON_INT_CORE0_INT1; + LOONGSON_INT_ROUTER_HT1(i) = + LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 1); /* enable HT1 interrupt */ LOONGSON_HT1_INTN_EN(0) = 0xffffffff; /* enable router interrupt intenset */ diff --git a/arch/mips/loongson/loongson-3/numa.c b/arch/mips/loongson/loongson-3/numa.c index 42323bc..6cae0e7 100644 --- a/arch/mips/loongson/loongson-3/numa.c +++ b/arch/mips/loongson/loongson-3/numa.c @@ -224,7 +224,7 @@ static void __init node_mem_init(unsigned int node) static __init void prom_meminit(void) { - unsigned int node, cpu; + unsigned int node, cpu, active_cpu = 0; cpu_node_probe(); init_topology_matrix(); @@ -240,8 +240,14 @@ static __init void prom_meminit(void) node = cpu / loongson_sysconf.cores_per_node; if (node >= num_online_nodes()) node = 0; - pr_info("NUMA: set cpumask cpu %d on node %d\n", cpu, node); - cpu_set(cpu, __node_data[(node)]->cpumask); + + if (loongson_sysconf.reserved_cpus_mask & (1<<cpu)) + continue; + + cpu_set(active_cpu, __node_data[(node)]->cpumask); + pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu, node); + + active_cpu++; } } diff --git a/arch/mips/loongson/loongson-3/platform.c b/arch/mips/loongson/loongson-3/platform.c new file mode 100644 index 0000000..25a97cc --- /dev/null +++ b/arch/mips/loongson/loongson-3/platform.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Lemote Inc. + * Author: Wu Zhangjin, wuzhangjin@gmail.com + * Xiang Yu, xiangy@lemote.com + * Chen Huacai, chenhc@lemote.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <asm/bootinfo.h> +#include <boot_param.h> +#include <loongson_hwmon.h> +#include <workarounds.h> + +static int __init loongson3_platform_init(void) +{ + int i; + struct platform_device *pdev; + + if (loongson_sysconf.ecname[0] != '\0') + platform_device_register_simple(loongson_sysconf.ecname, -1, NULL, 0); + + for (i = 0; i < loongson_sysconf.nr_sensors; i++) { + if (loongson_sysconf.sensors[i].type > SENSOR_FAN) + continue; + + pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + pdev->name = loongson_sysconf.sensors[i].name; + pdev->id = loongson_sysconf.sensors[i].id; + pdev->dev.platform_data = &loongson_sysconf.sensors[i]; + platform_device_register(pdev); + } + + return 0; +} + +arch_initcall(loongson3_platform_init); diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c index d8c63af..e2eb688b 100644 --- a/arch/mips/loongson/loongson-3/smp.c +++ b/arch/mips/loongson/loongson-3/smp.c @@ -25,6 +25,7 @@ #include <asm/tlbflush.h> #include <asm/cacheflush.h> #include <loongson.h> +#include <workarounds.h> #include "smp.h" @@ -239,7 +240,7 @@ static void ipi_mailbox_buf_init(void) */ static void loongson3_send_ipi_single(int cpu, unsigned int action) { - loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]); + loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu_logical_map(cpu)]); } static void @@ -248,7 +249,7 @@ loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action) unsigned int i; for_each_cpu(i, mask) - loongson3_ipi_write32((u32)action, ipi_set0_regs[i]); + loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu_logical_map(i)]); } void loongson3_ipi_interrupt(struct pt_regs *regs) @@ -257,10 +258,10 @@ void loongson3_ipi_interrupt(struct pt_regs *regs) unsigned int action, c0count; /* Load the ipi register to figure out what we're supposed to do */ - action = loongson3_ipi_read32(ipi_status0_regs[cpu]); + action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]); /* Clear the ipi register to clear the interrupt */ - loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu]); + loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu_logical_map(cpu)]); if (action & SMP_RESCHEDULE_YOURSELF) scheduler_ipi(); @@ -291,12 +292,14 @@ static void loongson3_init_secondary(void) /* Set interrupt mask, but don't enable */ change_c0_status(ST0_IM, imask); - for (i = 0; i < loongson_sysconf.nr_cpus; i++) - loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]); + for (i = 0; i < num_possible_cpus(); i++) + loongson3_ipi_write32(0xffffffff, ipi_en0_regs[cpu_logical_map(i)]); - cpu_data[cpu].package = cpu / loongson_sysconf.cores_per_package; - cpu_data[cpu].core = cpu % loongson_sysconf.cores_per_package; per_cpu(cpu_state, cpu) = CPU_ONLINE; + cpu_data[cpu].core = + cpu_logical_map(cpu) % loongson_sysconf.cores_per_package; + cpu_data[cpu].package = + cpu_logical_map(cpu) / loongson_sysconf.cores_per_package; i = 0; __this_cpu_write(core0_c0count, 0); @@ -314,37 +317,50 @@ static void loongson3_init_secondary(void) static void loongson3_smp_finish(void) { + int cpu = smp_processor_id(); + write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ); local_irq_enable(); loongson3_ipi_write64(0, - (void *)(ipi_mailbox_buf[smp_processor_id()]+0x0)); + (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x0)); pr_info("CPU#%d finished, CP0_ST=%x\n", smp_processor_id(), read_c0_status()); } static void __init loongson3_smp_setup(void) { - int i, num; + int i = 0, num = 0; /* i: physical id, num: logical id */ init_cpu_possible(cpu_none_mask); - set_cpu_possible(0, true); - - __cpu_number_map[0] = 0; - __cpu_logical_map[0] = 0; /* For unified kernel, NR_CPUS is the maximum possible value, * loongson_sysconf.nr_cpus is the really present value */ - for (i = 1, num = 0; i < loongson_sysconf.nr_cpus; i++) { - set_cpu_possible(i, true); - __cpu_number_map[i] = ++num; - __cpu_logical_map[num] = i; + while (i < loongson_sysconf.nr_cpus) { + if (loongson_sysconf.reserved_cpus_mask & (1<<i)) { + /* Reserved physical CPU cores */ + __cpu_number_map[i] = -1; + } else { + __cpu_number_map[i] = num; + __cpu_logical_map[num] = i; + set_cpu_possible(num, true); + num++; + } + i++; } + pr_info("Detected %i available CPU(s)\n", num); + + while (num < loongson_sysconf.nr_cpus) { + __cpu_logical_map[num] = -1; + num++; + } + ipi_set0_regs_init(); ipi_clear0_regs_init(); ipi_status0_regs_init(); ipi_en0_regs_init(); ipi_mailbox_buf_init(); - pr_info("Detected %i available secondary CPU(s)\n", num); + cpu_data[0].core = cpu_logical_map(0) % loongson_sysconf.cores_per_package; + cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package; } static void __init loongson3_prepare_cpus(unsigned int max_cpus) @@ -371,10 +387,14 @@ static void loongson3_boot_secondary(int cpu, struct task_struct *idle) pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n", cpu, startargs[0], startargs[1], startargs[2]); - loongson3_ipi_write64(startargs[3], (void *)(ipi_mailbox_buf[cpu]+0x18)); - loongson3_ipi_write64(startargs[2], (void *)(ipi_mailbox_buf[cpu]+0x10)); - loongson3_ipi_write64(startargs[1], (void *)(ipi_mailbox_buf[cpu]+0x8)); - loongson3_ipi_write64(startargs[0], (void *)(ipi_mailbox_buf[cpu]+0x0)); + loongson3_ipi_write64(startargs[3], + (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x18)); + loongson3_ipi_write64(startargs[2], + (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x10)); + loongson3_ipi_write64(startargs[1], + (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x8)); + loongson3_ipi_write64(startargs[0], + (void *)(ipi_mailbox_buf[cpu_logical_map(cpu)]+0x0)); } #ifdef CONFIG_HOTPLUG_CPU @@ -568,7 +588,7 @@ void loongson3_disable_clock(int cpu) if (loongson_sysconf.cputype == Loongson_3A) { LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id)); } else if (loongson_sysconf.cputype == Loongson_3B) { - if (!cpuhotplug_workaround) + if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG)) LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3)); } } @@ -581,7 +601,7 @@ void loongson3_enable_clock(int cpu) if (loongson_sysconf.cputype == Loongson_3A) { LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id); } else if (loongson_sysconf.cputype == Loongson_3B) { - if (!cpuhotplug_workaround) + if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG)) LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3); } } diff --git a/arch/mips/loongson1/Kconfig b/arch/mips/loongson1/Kconfig index e23c25d..a2b796e 100644 --- a/arch/mips/loongson1/Kconfig +++ b/arch/mips/loongson1/Kconfig @@ -5,8 +5,8 @@ choice config LOONGSON1_LS1B bool "Loongson LS1B board" - select CEVT_R4K - select CSRC_R4K + select CEVT_R4K if !MIPS_EXTERNAL_TIMER + select CSRC_R4K if !MIPS_EXTERNAL_TIMER select SYS_HAS_CPU_LOONGSON1B select DMA_NONCOHERENT select BOOT_ELF32 @@ -16,8 +16,46 @@ config LOONGSON1_LS1B select SYS_SUPPORTS_HIGHMEM select SYS_SUPPORTS_MIPS16 select SYS_HAS_EARLY_PRINTK + select USE_GENERIC_EARLY_PRINTK_8250 select COMMON_CLK endchoice +menuconfig CEVT_CSRC_LS1X + bool "Use PWM Timer for clockevent/clocksource" + select MIPS_EXTERNAL_TIMER + depends on CPU_LOONGSON1 + help + This option changes the default clockevent/clocksource to PWM Timer, + and is required by Loongson1 CPUFreq support. + + If unsure, say N. + +choice + prompt "Select clockevent/clocksource" + depends on CEVT_CSRC_LS1X + default TIMER_USE_PWM0 + +config TIMER_USE_PWM0 + bool "Use PWM Timer 0" + help + Use PWM Timer 0 as the default clockevent/clocksourcer. + +config TIMER_USE_PWM1 + bool "Use PWM Timer 1" + help + Use PWM Timer 1 as the default clockevent/clocksourcer. + +config TIMER_USE_PWM2 + bool "Use PWM Timer 2" + help + Use PWM Timer 2 as the default clockevent/clocksourcer. + +config TIMER_USE_PWM3 + bool "Use PWM Timer 3" + help + Use PWM Timer 3 as the default clockevent/clocksourcer. + +endchoice + endif # MACH_LOONGSON1 diff --git a/arch/mips/loongson1/common/Makefile b/arch/mips/loongson1/common/Makefile index b279770..723b4ce 100644 --- a/arch/mips/loongson1/common/Makefile +++ b/arch/mips/loongson1/common/Makefile @@ -2,4 +2,4 @@ # Makefile for common code of loongson1 based machines. # -obj-y += clock.o irq.o platform.o prom.o reset.o setup.o +obj-y += time.o irq.o platform.o prom.o reset.o setup.o diff --git a/arch/mips/loongson1/common/clock.c b/arch/mips/loongson1/common/clock.c deleted file mode 100644 index b4437f1..0000000 --- a/arch/mips/loongson1/common/clock.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2011 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 - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/clk.h> -#include <linux/err.h> -#include <asm/time.h> -#include <platform.h> - -void __init plat_time_init(void) -{ - struct clk *clk; - - /* Initialize LS1X clocks */ - ls1x_clk_init(); - - /* setup mips r4k timer */ - clk = clk_get(NULL, "cpu"); - if (IS_ERR(clk)) - panic("unable to get cpu clock, err=%ld", PTR_ERR(clk)); - - mips_hpt_frequency = clk_get_rate(clk) / 2; -} diff --git a/arch/mips/loongson1/common/platform.c b/arch/mips/loongson1/common/platform.c index fdf8cb5..ddf1d4c 100644 --- a/arch/mips/loongson1/common/platform.c +++ b/arch/mips/loongson1/common/platform.c @@ -16,8 +16,10 @@ #include <linux/usb/ehci_pdriver.h> #include <asm-generic/sizes.h> +#include <cpufreq.h> #include <loongson1.h> +/* 8250/16550 compatible UART */ #define LS1X_UART(_id) \ { \ .mapbase = LS1X_UART ## _id ## _BASE, \ @@ -27,7 +29,7 @@ .type = PORT_16550A, \ } -static struct plat_serial8250_port ls1x_serial8250_port[] = { +static struct plat_serial8250_port ls1x_serial8250_pdata[] = { LS1X_UART(0), LS1X_UART(1), LS1X_UART(2), @@ -35,11 +37,11 @@ static struct plat_serial8250_port ls1x_serial8250_port[] = { {}, }; -struct platform_device ls1x_uart_device = { +struct platform_device ls1x_uart_pdev = { .name = "serial8250", .id = PLAT8250_DEV_PLATFORM, .dev = { - .platform_data = ls1x_serial8250_port, + .platform_data = ls1x_serial8250_pdata, }, }; @@ -48,16 +50,97 @@ void __init ls1x_serial_setup(struct platform_device *pdev) struct clk *clk; struct plat_serial8250_port *p; - clk = clk_get(NULL, pdev->name); - if (IS_ERR(clk)) - panic("unable to get %s clock, err=%ld", - pdev->name, PTR_ERR(clk)); + clk = clk_get(&pdev->dev, pdev->name); + if (IS_ERR(clk)) { + pr_err("unable to get %s clock, err=%ld", + pdev->name, PTR_ERR(clk)); + return; + } + clk_prepare_enable(clk); for (p = pdev->dev.platform_data; p->flags != 0; ++p) p->uartclk = clk_get_rate(clk); } +/* CPUFreq */ +static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = { + .clk_name = "cpu_clk", + .osc_clk_name = "osc_33m_clk", + .max_freq = 266 * 1000, + .min_freq = 33 * 1000, +}; + +struct platform_device ls1x_cpufreq_pdev = { + .name = "ls1x-cpufreq", + .dev = { + .platform_data = &ls1x_cpufreq_pdata, + }, +}; + /* Synopsys Ethernet GMAC */ +static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { + .phy_mask = 0, +}; + +static struct stmmac_dma_cfg ls1x_eth_dma_cfg = { + .pbl = 1, +}; + +int ls1x_eth_mux_init(struct platform_device *pdev, void *priv) +{ + struct plat_stmmacenet_data *plat_dat = NULL; + u32 val; + + val = __raw_readl(LS1X_MUX_CTRL1); + + plat_dat = dev_get_platdata(&pdev->dev); + if (plat_dat->bus_id) { + __raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 | + GMAC1_USE_UART0, LS1X_MUX_CTRL0); + switch (plat_dat->interface) { + case PHY_INTERFACE_MODE_RGMII: + val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23); + break; + case PHY_INTERFACE_MODE_MII: + val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23); + break; + default: + pr_err("unsupported mii mode %d\n", + plat_dat->interface); + return -ENOTSUPP; + } + val &= ~GMAC1_SHUT; + } else { + switch (plat_dat->interface) { + case PHY_INTERFACE_MODE_RGMII: + val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01); + break; + case PHY_INTERFACE_MODE_MII: + val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01); + break; + default: + pr_err("unsupported mii mode %d\n", + plat_dat->interface); + return -ENOTSUPP; + } + val &= ~GMAC0_SHUT; + } + __raw_writel(val, LS1X_MUX_CTRL1); + + return 0; +} + +static struct plat_stmmacenet_data ls1x_eth0_pdata = { + .bus_id = 0, + .phy_addr = -1, + .interface = PHY_INTERFACE_MODE_MII, + .mdio_bus_data = &ls1x_mdio_bus_data, + .dma_cfg = &ls1x_eth_dma_cfg, + .has_gmac = 1, + .tx_coe = 1, + .init = ls1x_eth_mux_init, +}; + static struct resource ls1x_eth0_resources[] = { [0] = { .start = LS1X_GMAC0_BASE, @@ -71,25 +154,47 @@ static struct resource ls1x_eth0_resources[] = { }, }; -static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { - .phy_mask = 0, +struct platform_device ls1x_eth0_pdev = { + .name = "stmmaceth", + .id = 0, + .num_resources = ARRAY_SIZE(ls1x_eth0_resources), + .resource = ls1x_eth0_resources, + .dev = { + .platform_data = &ls1x_eth0_pdata, + }, }; -static struct plat_stmmacenet_data ls1x_eth_data = { - .bus_id = 0, +static struct plat_stmmacenet_data ls1x_eth1_pdata = { + .bus_id = 1, .phy_addr = -1, + .interface = PHY_INTERFACE_MODE_MII, .mdio_bus_data = &ls1x_mdio_bus_data, + .dma_cfg = &ls1x_eth_dma_cfg, .has_gmac = 1, .tx_coe = 1, + .init = ls1x_eth_mux_init, }; -struct platform_device ls1x_eth0_device = { +static struct resource ls1x_eth1_resources[] = { + [0] = { + .start = LS1X_GMAC1_BASE, + .end = LS1X_GMAC1_BASE + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "macirq", + .start = LS1X_GMAC1_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device ls1x_eth1_pdev = { .name = "stmmaceth", - .id = 0, - .num_resources = ARRAY_SIZE(ls1x_eth0_resources), - .resource = ls1x_eth0_resources, + .id = 1, + .num_resources = ARRAY_SIZE(ls1x_eth1_resources), + .resource = ls1x_eth1_resources, .dev = { - .platform_data = &ls1x_eth_data, + .platform_data = &ls1x_eth1_pdata, }, }; @@ -111,7 +216,7 @@ static struct resource ls1x_ehci_resources[] = { static struct usb_ehci_pdata ls1x_ehci_pdata = { }; -struct platform_device ls1x_ehci_device = { +struct platform_device ls1x_ehci_pdev = { .name = "ehci-platform", .id = -1, .num_resources = ARRAY_SIZE(ls1x_ehci_resources), @@ -123,7 +228,7 @@ struct platform_device ls1x_ehci_device = { }; /* Real Time Clock */ -struct platform_device ls1x_rtc_device = { +struct platform_device ls1x_rtc_pdev = { .name = "ls1x-rtc", .id = -1, }; diff --git a/arch/mips/loongson1/common/prom.c b/arch/mips/loongson1/common/prom.c index 2a47af5..6860098 100644 --- a/arch/mips/loongson1/common/prom.c +++ b/arch/mips/loongson1/common/prom.c @@ -27,7 +27,7 @@ char *prom_getenv(char *envname) i = strlen(envname); while (*env) { - if (strncmp(envname, *env, i) == 0 && *(*env+i) == '=') + if (strncmp(envname, *env, i) == 0 && *(*env + i) == '=') return *env + i + 1; env++; } @@ -49,7 +49,7 @@ void __init prom_init_cmdline(void) for (i = 1; i < prom_argc; i++) { strcpy(c, prom_argv[i]); c += strlen(prom_argv[i]); - if (i < prom_argc-1) + if (i < prom_argc - 1) *c++ = ' '; } *c = 0; @@ -57,6 +57,7 @@ void __init prom_init_cmdline(void) void __init prom_init(void) { + void __iomem *uart_base; prom_argc = fw_arg0; prom_argv = (char **)fw_arg1; prom_envp = (char **)fw_arg2; @@ -65,23 +66,18 @@ void __init prom_init(void) memsize = env_or_default("memsize", DEFAULT_MEMSIZE); highmemsize = env_or_default("highmemsize", 0x0); -} -void __init prom_free_prom_memory(void) -{ + if (strstr(arcs_cmdline, "console=ttyS3")) + uart_base = ioremap_nocache(LS1X_UART3_BASE, 0x0f); + else if (strstr(arcs_cmdline, "console=ttyS2")) + uart_base = ioremap_nocache(LS1X_UART2_BASE, 0x0f); + else if (strstr(arcs_cmdline, "console=ttyS1")) + uart_base = ioremap_nocache(LS1X_UART1_BASE, 0x0f); + else + uart_base = ioremap_nocache(LS1X_UART0_BASE, 0x0f); + setup_8250_early_printk_port((unsigned long)uart_base, 0, 0); } -#define PORT(offset) (u8 *)(KSEG1ADDR(LS1X_UART0_BASE + offset)) - -void prom_putchar(char c) +void __init prom_free_prom_memory(void) { - int timeout; - - timeout = 1024; - - while (((readb(PORT(UART_LSR)) & UART_LSR_THRE) == 0) - && (timeout-- > 0)) - ; - - writeb(c, PORT(UART_TX)); } diff --git a/arch/mips/loongson1/common/reset.c b/arch/mips/loongson1/common/reset.c index 547f34b..c41e4ca 100644 --- a/arch/mips/loongson1/common/reset.c +++ b/arch/mips/loongson1/common/reset.c @@ -14,12 +14,7 @@ #include <loongson1.h> -static void ls1x_restart(char *command) -{ - __raw_writel(0x1, LS1X_WDT_EN); - __raw_writel(0x5000000, LS1X_WDT_TIMER); - __raw_writel(0x1, LS1X_WDT_SET); -} +static void __iomem *wdt_base; static void ls1x_halt(void) { @@ -29,6 +24,15 @@ 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); + + ls1x_halt(); +} + static void ls1x_power_off(void) { ls1x_halt(); @@ -36,6 +40,10 @@ static void ls1x_power_off(void) static int __init ls1x_reboot_setup(void) { + wdt_base = ioremap_nocache(LS1X_WDT_BASE, 0x0f); + if (!wdt_base) + panic("Failed to remap watchdog registers"); + _machine_restart = ls1x_restart; _machine_halt = ls1x_halt; pm_power_off = ls1x_power_off; diff --git a/arch/mips/loongson1/common/time.c b/arch/mips/loongson1/common/time.c new file mode 100644 index 0000000..df0f850 --- /dev/null +++ b/arch/mips/loongson1/common/time.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2014 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <asm/time.h> + +#include <loongson1.h> +#include <platform.h> + +#ifdef CONFIG_CEVT_CSRC_LS1X + +#if defined(CONFIG_TIMER_USE_PWM1) +#define LS1X_TIMER_BASE LS1X_PWM1_BASE +#define LS1X_TIMER_IRQ LS1X_PWM1_IRQ + +#elif defined(CONFIG_TIMER_USE_PWM2) +#define LS1X_TIMER_BASE LS1X_PWM2_BASE +#define LS1X_TIMER_IRQ LS1X_PWM2_IRQ + +#elif defined(CONFIG_TIMER_USE_PWM3) +#define LS1X_TIMER_BASE LS1X_PWM3_BASE +#define LS1X_TIMER_IRQ LS1X_PWM3_IRQ + +#else +#define LS1X_TIMER_BASE LS1X_PWM0_BASE +#define LS1X_TIMER_IRQ LS1X_PWM0_IRQ +#endif + +DEFINE_RAW_SPINLOCK(ls1x_timer_lock); + +static void __iomem *timer_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); +} + +static inline void ls1x_pwmtimer_restart(void) +{ + __raw_writel(0x0, timer_base + PWM_CNT); + __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); +} + +void __init ls1x_pwmtimer_init(void) +{ + timer_base = ioremap(LS1X_TIMER_BASE, 0xf); + if (!timer_base) + panic("Failed to remap timer registers"); + + ls1x_jiffies_per_tick = DIV_ROUND_CLOSEST(mips_hpt_frequency, HZ); + + ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); + ls1x_pwmtimer_restart(); +} + +static cycle_t ls1x_clocksource_read(struct clocksource *cs) +{ + unsigned long flags; + int count; + u32 jifs; + static int old_count; + static u32 old_jifs; + + raw_spin_lock_irqsave(&ls1x_timer_lock, flags); + /* + * Although our caller may have the read side of xtime_lock, + * this is now a seqlock, and we are cheating in this routine + * by having side effects on state that we cannot undo if + * there is a collision on the seqlock and our caller has to + * retry. (Namely, old_jifs and old_count.) So we must treat + * jiffies as volatile despite the lock. We read jiffies + * before latching the timer count to guarantee that although + * the jiffies value might be older than the count (that is, + * the counter may underflow between the last point where + * jiffies was incremented and the point where we latch the + * count), it cannot be newer. + */ + jifs = jiffies; + /* read the count */ + count = __raw_readl(timer_base + PWM_CNT); + + /* + * It's possible for count to appear to go the wrong way for this + * reason: + * + * The timer counter underflows, but we haven't handled the resulting + * interrupt and incremented jiffies yet. + * + * Previous attempts to handle these cases intelligently were buggy, so + * we just do the simple thing now. + */ + if (count < old_count && jifs == old_jifs) + count = old_count; + + old_count = count; + old_jifs = jifs; + + raw_spin_unlock_irqrestore(&ls1x_timer_lock, flags); + + return (cycle_t) (jifs * ls1x_jiffies_per_tick) + count; +} + +static struct clocksource ls1x_clocksource = { + .name = "ls1x-pwmtimer", + .read = ls1x_clocksource_read, + .mask = CLOCKSOURCE_MASK(24), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static irqreturn_t ls1x_clockevent_isr(int irq, void *devid) +{ + struct clock_event_device *cd = devid; + + ls1x_pwmtimer_restart(); + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static void ls1x_clockevent_set_mode(enum clock_event_mode mode, + struct clock_event_device *cd) +{ + raw_spin_lock(&ls1x_timer_lock); + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); + ls1x_pwmtimer_restart(); + case CLOCK_EVT_MODE_RESUME: + __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + break; + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_SHUTDOWN: + __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, + timer_base + PWM_CTRL); + break; + default: + break; + } + raw_spin_unlock(&ls1x_timer_lock); +} + +static int ls1x_clockevent_set_next(unsigned long evt, + struct clock_event_device *cd) +{ + raw_spin_lock(&ls1x_timer_lock); + ls1x_pwmtimer_set_period(evt); + ls1x_pwmtimer_restart(); + raw_spin_unlock(&ls1x_timer_lock); + + return 0; +} + +static struct clock_event_device ls1x_clockevent = { + .name = "ls1x-pwmtimer", + .features = CLOCK_EVT_FEAT_PERIODIC, + .rating = 300, + .irq = LS1X_TIMER_IRQ, + .set_next_event = ls1x_clockevent_set_next, + .set_mode = ls1x_clockevent_set_mode, +}; + +static struct irqaction ls1x_pwmtimer_irqaction = { + .name = "ls1x-pwmtimer", + .handler = ls1x_clockevent_isr, + .dev_id = &ls1x_clockevent, + .flags = IRQF_PERCPU | IRQF_TIMER, +}; + +static void __init ls1x_time_init(void) +{ + struct clock_event_device *cd = &ls1x_clockevent; + int ret; + + if (!mips_hpt_frequency) + panic("Invalid timer clock rate"); + + ls1x_pwmtimer_init(); + + clockevent_set_clock(cd, mips_hpt_frequency); + cd->max_delta_ns = clockevent_delta2ns(0xffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x000300, cd); + cd->cpumask = cpumask_of(smp_processor_id()); + clockevents_register_device(cd); + + ls1x_clocksource.rating = 200 + mips_hpt_frequency / 10000000; + ret = clocksource_register_hz(&ls1x_clocksource, mips_hpt_frequency); + if (ret) + panic(KERN_ERR "Failed to register clocksource: %d\n", ret); + + setup_irq(LS1X_TIMER_IRQ, &ls1x_pwmtimer_irqaction); +} +#endif /* CONFIG_CEVT_CSRC_LS1X */ + +void __init plat_time_init(void) +{ + struct clk *clk = NULL; + + /* initialize LS1X clocks */ + ls1x_clk_init(); + +#ifdef CONFIG_CEVT_CSRC_LS1X + /* setup LS1X PWM timer */ + clk = clk_get(NULL, "ls1x_pwmtimer"); + if (IS_ERR(clk)) + panic("unable to get timer clock, err=%ld", PTR_ERR(clk)); + + mips_hpt_frequency = clk_get_rate(clk); + ls1x_time_init(); +#else + /* setup mips r4k timer */ + clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(clk)) + panic("unable to get cpu clock, err=%ld", PTR_ERR(clk)); + + mips_hpt_frequency = clk_get_rate(clk) / 2; +#endif /* CONFIG_CEVT_CSRC_LS1X */ +} diff --git a/arch/mips/loongson1/ls1b/board.c b/arch/mips/loongson1/ls1b/board.c index b26b10d..58daeea 100644 --- a/arch/mips/loongson1/ls1b/board.c +++ b/arch/mips/loongson1/ls1b/board.c @@ -10,17 +10,19 @@ #include <platform.h> static struct platform_device *ls1b_platform_devices[] __initdata = { - &ls1x_uart_device, - &ls1x_eth0_device, - &ls1x_ehci_device, - &ls1x_rtc_device, + &ls1x_uart_pdev, + &ls1x_cpufreq_pdev, + &ls1x_eth0_pdev, + &ls1x_eth1_pdev, + &ls1x_ehci_pdev, + &ls1x_rtc_pdev, }; static int __init ls1b_platform_init(void) { int err; - ls1x_serial_setup(&ls1x_uart_device); + ls1x_serial_setup(&ls1x_uart_pdev); err = platform_add_devices(ls1b_platform_devices, ARRAY_SIZE(ls1b_platform_devices)); diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index cac529a..9dfcd7f 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -643,9 +643,14 @@ static inline int cop1_64bit(struct pt_regs *xcp) return !test_thread_flag(TIF_32BIT_FPREGS); } +static inline bool hybrid_fprs(void) +{ + return test_thread_flag(TIF_HYBRID_FPREGS); +} + #define SIFROMREG(si, x) \ do { \ - if (cop1_64bit(xcp)) \ + if (cop1_64bit(xcp) && !hybrid_fprs()) \ (si) = (int)get_fpr32(&ctx->fpr[x], 0); \ else \ (si) = (int)get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ @@ -653,7 +658,7 @@ do { \ #define SITOREG(si, x) \ do { \ - if (cop1_64bit(xcp)) { \ + if (cop1_64bit(xcp) && !hybrid_fprs()) { \ unsigned i; \ set_fpr32(&ctx->fpr[x], 0, si); \ for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ diff --git a/arch/mips/math-emu/ieee754dp.c b/arch/mips/math-emu/ieee754dp.c index fd13467..068f45a 100644 --- a/arch/mips/math-emu/ieee754dp.c +++ b/arch/mips/math-emu/ieee754dp.c @@ -38,7 +38,7 @@ int ieee754dp_isnan(union ieee754dp x) static inline int ieee754dp_issnan(union ieee754dp x) { assert(ieee754dp_isnan(x)); - return ((DPMANT(x) & DP_MBIT(DP_FBITS-1)) == DP_MBIT(DP_FBITS-1)); + return (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1); } diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c index d348efe..ba88301 100644 --- a/arch/mips/math-emu/ieee754sp.c +++ b/arch/mips/math-emu/ieee754sp.c @@ -38,7 +38,7 @@ int ieee754sp_isnan(union ieee754sp x) static inline int ieee754sp_issnan(union ieee754sp x) { assert(ieee754sp_isnan(x)); - return (SPMANT(x) & SP_MBIT(SP_FBITS-1)); + return SPMANT(x) & SP_MBIT(SP_FBITS - 1); } diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 7f4f93a..67ede4e 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -4,7 +4,13 @@ obj-y += cache.o dma-default.o extable.o fault.o \ gup.o init.o mmap.o page.o page-funcs.o \ - tlbex.o tlbex-fault.o tlb-funcs.o uasm-mips.o + tlbex.o tlbex-fault.o tlb-funcs.o + +ifdef CONFIG_CPU_MICROMIPS +obj-y += uasm-micromips.o +else +obj-y += uasm-mips.o +endif obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_64BIT) += pgtable-64.o @@ -22,5 +28,3 @@ obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o - -obj-$(CONFIG_SYS_SUPPORTS_MICROMIPS) += uasm-micromips.o diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index fbcd867..dd261df 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -917,6 +917,18 @@ static inline void alias_74k_erratum(struct cpuinfo_mips *c) } } +static void b5k_instruction_hazard(void) +{ + __sync(); + __sync(); + __asm__ __volatile__( + " nop; nop; nop; nop; nop; nop; nop; nop\n" + " nop; nop; nop; nop; nop; nop; nop; nop\n" + " nop; nop; nop; nop; nop; nop; nop; nop\n" + " nop; nop; nop; nop; nop; nop; nop; nop\n" + : : : "memory"); +} + static char *way_string[] = { NULL, "direct mapped", "2-way", "3-way", "4-way", "5-way", "6-way", "7-way", "8-way" }; @@ -1683,6 +1695,37 @@ void r4k_cache_init(void) coherency_setup(); board_cache_error_setup = r4k_cache_error_setup; + + /* + * Per-CPU overrides + */ + switch (current_cpu_type()) { + case CPU_BMIPS4350: + case CPU_BMIPS4380: + /* No IPI is needed because all CPUs share the same D$ */ + flush_data_cache_page = r4k_blast_dcache_page; + break; + case CPU_BMIPS5000: + /* We lose our superpowers if L2 is disabled */ + if (c->scache.flags & MIPS_CACHE_NOT_PRESENT) + break; + + /* I$ fills from D$ just by emptying the write buffers */ + flush_cache_page = (void *)b5k_instruction_hazard; + flush_cache_range = (void *)b5k_instruction_hazard; + flush_cache_sigtramp = (void *)b5k_instruction_hazard; + local_flush_data_cache_page = (void *)b5k_instruction_hazard; + flush_data_cache_page = (void *)b5k_instruction_hazard; + 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; + } } static int r4k_cache_pm_notifier(struct notifier_block *self, unsigned long cmd, diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 33ba3c5..af5f046 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -61,6 +61,11 @@ static inline struct page *dma_addr_to_page(struct device *dev, * Warning on the terminology - Linux calls an uncached area coherent; * MIPS terminology calls memory areas with hardware maintained coherency * coherent. + * + * Note that the R14000 and R16000 should also be checked for in this + * condition. However this function is only called on non-I/O-coherent + * systems and only the R10000 and R12000 are used in such systems, the + * SGI IP28 Indigo² rsp. SGI IP32 aka O2. */ static inline int cpu_needs_post_dma_flush(struct device *dev) { diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c index 06ce17c..7cba480 100644 --- a/arch/mips/mm/gup.c +++ b/arch/mips/mm/gup.c @@ -17,7 +17,7 @@ static inline pte_t gup_get_pte(pte_t *ptep) { -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) pte_t pte; retry: diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index f42e35e..448cde3 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -95,7 +95,7 @@ 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_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) entrylo = pte.pte_high; #else entrylo = pte_to_entrylo(pte_val(pte)); diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c index 7f840bc..8d5008c 100644 --- a/arch/mips/mm/ioremap.c +++ b/arch/mips/mm/ioremap.c @@ -17,9 +17,9 @@ #include <asm/tlbflush.h> static inline void remap_area_pte(pte_t * pte, unsigned long address, - phys_t size, phys_t phys_addr, unsigned long flags) + phys_addr_t size, phys_addr_t phys_addr, unsigned long flags) { - phys_t end; + phys_addr_t end; unsigned long pfn; pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE | __WRITEABLE | flags); @@ -43,9 +43,9 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address, } static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, - phys_t size, phys_t phys_addr, unsigned long flags) + phys_addr_t size, phys_addr_t phys_addr, unsigned long flags) { - phys_t end; + phys_addr_t end; address &= ~PGDIR_MASK; end = address + size; @@ -64,8 +64,8 @@ static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, return 0; } -static int remap_area_pages(unsigned long address, phys_t phys_addr, - phys_t size, unsigned long flags) +static int remap_area_pages(unsigned long address, phys_addr_t phys_addr, + phys_addr_t size, unsigned long flags) { int error; pgd_t * dir; @@ -111,13 +111,13 @@ static int remap_area_pages(unsigned long address, phys_t phys_addr, * caller shouldn't need to know that small detail. */ -#define IS_LOW512(addr) (!((phys_t)(addr) & (phys_t) ~0x1fffffffULL)) +#define IS_LOW512(addr) (!((phys_addr_t)(addr) & (phys_addr_t) ~0x1fffffffULL)) -void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags) +void __iomem * __ioremap(phys_addr_t phys_addr, phys_addr_t size, unsigned long flags) { struct vm_struct * area; unsigned long offset; - phys_t last_addr; + phys_addr_t last_addr; void * addr; phys_addr = fixup_bigphys_addr(phys_addr, size); diff --git a/arch/mips/mm/sc-r5k.c b/arch/mips/mm/sc-r5k.c index 0216ed6..751b5cd 100644 --- a/arch/mips/mm/sc-r5k.c +++ b/arch/mips/mm/sc-r5k.c @@ -81,7 +81,7 @@ static inline int __init r5k_sc_probe(void) unsigned long config = read_c0_config(); if (config & CONF_SC) - return(0); + return 0; scache_size = (512 * 1024) << ((config & R5K_CONF_SS) >> 20); diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index c3917e2..e90b2e8 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -332,7 +332,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) { ptep = pte_offset_map(pmdp, address); -#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) +#if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) write_c0_entrylo0(ptep->pte_high); ptep++; write_c0_entrylo1(ptep->pte_high); diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index e3328a9..3978a3d 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -637,7 +637,7 @@ static __maybe_unused void build_convert_pte_to_entrylo(u32 **p, if (cpu_has_rixi) { UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL)); } else { -#ifdef CONFIG_64BIT_PHYS_ADDR +#ifdef CONFIG_PHYS_ADDR_T_64BIT uasm_i_dsrl_safe(p, reg, reg, ilog2(_PAGE_GLOBAL)); #else UASM_i_SRL(p, reg, reg, ilog2(_PAGE_GLOBAL)); @@ -1009,7 +1009,7 @@ 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. */ -#ifdef CONFIG_64BIT_PHYS_ADDR +#ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits) { uasm_i_ld(p, tmp, 0, ptep); /* get even pte */ uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ @@ -1510,14 +1510,14 @@ static void iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) { #ifdef CONFIG_SMP -# ifdef CONFIG_64BIT_PHYS_ADDR +# ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits) uasm_i_lld(p, pte, 0, ptr); else # endif UASM_i_LL(p, pte, 0, ptr); #else -# ifdef CONFIG_64BIT_PHYS_ADDR +# ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits) uasm_i_ld(p, pte, 0, ptr); else @@ -1530,13 +1530,13 @@ static void iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, unsigned int mode) { -#ifdef CONFIG_64BIT_PHYS_ADDR +#ifdef CONFIG_PHYS_ADDR_T_64BIT unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY); #endif uasm_i_ori(p, pte, pte, mode); #ifdef CONFIG_SMP -# ifdef CONFIG_64BIT_PHYS_ADDR +# ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits) uasm_i_scd(p, pte, 0, ptr); else @@ -1548,7 +1548,7 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, else uasm_il_beqz(p, r, pte, label_smp_pgtable_change); -# ifdef CONFIG_64BIT_PHYS_ADDR +# ifdef CONFIG_PHYS_ADDR_T_64BIT if (!cpu_has_64bits) { /* no uasm_i_nop needed */ uasm_i_ll(p, pte, sizeof(pte_t) / 2, ptr); @@ -1563,14 +1563,14 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, uasm_i_nop(p); # endif #else -# ifdef CONFIG_64BIT_PHYS_ADDR +# ifdef CONFIG_PHYS_ADDR_T_64BIT if (cpu_has_64bits) uasm_i_sd(p, pte, 0, ptr); else # endif UASM_i_SW(p, pte, 0, ptr); -# ifdef CONFIG_64BIT_PHYS_ADDR +# ifdef CONFIG_PHYS_ADDR_T_64BIT if (!cpu_has_64bits) { uasm_i_lw(p, pte, sizeof(pte_t) / 2, ptr); uasm_i_ori(p, pte, pte, hwmode); diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c index 6708a2d..8e02291 100644 --- a/arch/mips/mm/uasm-mips.c +++ b/arch/mips/mm/uasm-mips.c @@ -96,9 +96,11 @@ static struct insn insn_table[] = { { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM }, { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD }, { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET}, + { insn_mfhc0, M(cop0_op, mfhc0_op, 0, 0, 0, 0), RT | RD | SET}, { insn_mfhi, M(spec_op, 0, 0, 0, 0, mfhi_op), RD }, { insn_mflo, M(spec_op, 0, 0, 0, 0, mflo_op), RD }, { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET}, + { insn_mthc0, M(cop0_op, mthc0_op, 0, 0, 0, 0), RT | RD | SET}, { insn_mul, M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD}, { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM }, { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD }, diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c index a01b0d6..4adf302 100644 --- a/arch/mips/mm/uasm.c +++ b/arch/mips/mm/uasm.c @@ -51,12 +51,12 @@ enum opcode { insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret, insn_ext, insn_ins, insn_j, insn_jal, insn_jalr, insn_jr, insn_lb, insn_ld, insn_ldx, insn_lh, insn_ll, insn_lld, insn_lui, insn_lw, - insn_lwx, insn_mfc0, insn_mfhi, insn_mflo, insn_mtc0, insn_mul, - insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, - insn_sd, insn_sll, insn_sllv, insn_slt, 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_lwx, insn_mfc0, insn_mfhc0, insn_mfhi, insn_mflo, insn_mtc0, + insn_mthc0, insn_mul, insn_or, insn_ori, insn_pref, insn_rfe, + insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll, insn_sllv, insn_slt, + 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, }; struct insn { @@ -284,9 +284,11 @@ I_u2s3u1(_lld) I_u1s2(_lui) I_u2s3u1(_lw) I_u1u2u3(_mfc0) +I_u1u2u3(_mfhc0) I_u1(_mfhi) I_u1(_mflo) I_u1u2u3(_mtc0) +I_u1u2u3(_mthc0) I_u3u1u2(_mul) I_u2u1u3(_ori) I_u3u1u2(_or) diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index 0f60256..6849f53 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -111,7 +111,7 @@ static void __init mips_ejtag_setup(void) flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); } -phys_t mips_cpc_default_phys_base(void) +phys_addr_t mips_cpc_default_phys_base(void) { return CPC_BASE_ADDR; } diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index e4f43ba..d1392f8 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -18,6 +18,7 @@ #include <linux/smp.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/irqchip/mips-gic.h> #include <linux/kernel_stat.h> #include <linux/kernel.h> #include <linux/random.h> @@ -33,19 +34,13 @@ #include <asm/mips-boards/generic.h> #include <asm/mips-boards/msc01_pci.h> #include <asm/msc01_ic.h> -#include <asm/gic.h> #include <asm/setup.h> #include <asm/rtlx.h> -static unsigned long _msc01_biu_base; -static unsigned int ipi_map[NR_CPUS]; +static void __iomem *_msc01_biu_base; static DEFINE_RAW_SPINLOCK(mips_irq_lock); -#ifdef CONFIG_MIPS_GIC_IPI -DECLARE_BITMAP(ipi_ints, GIC_NUM_INTRS); -#endif - static inline int mips_pcibios_iack(void) { int irq; @@ -127,24 +122,10 @@ static void malta_hw0_irqdispatch(void) #endif } -static void malta_ipi_irqdispatch(void) +static irqreturn_t i8259_handler(int irq, void *dev_id) { -#ifdef CONFIG_MIPS_GIC_IPI - unsigned long irq; - DECLARE_BITMAP(pending, GIC_NUM_INTRS); - - gic_get_int_mask(pending, ipi_ints); - - irq = find_first_bit(pending, GIC_NUM_INTRS); - - while (irq < GIC_NUM_INTRS) { - do_IRQ(MIPS_GIC_IRQ_BASE + irq); - - irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1); - } -#endif - if (gic_compare_int()) - do_IRQ(MIPS_GIC_IRQ_BASE); + malta_hw0_irqdispatch(); + return IRQ_HANDLED; } static void corehi_irqdispatch(void) @@ -203,95 +184,10 @@ static void corehi_irqdispatch(void) die("CoreHi interrupt", regs); } -static inline int clz(unsigned long x) -{ - __asm__( - " .set push \n" - " .set mips32 \n" - " clz %0, %1 \n" - " .set pop \n" - : "=r" (x) - : "r" (x)); - - return x; -} - -/* - * Version of ffs that only looks at bits 12..15. - */ -static inline unsigned int irq_ffs(unsigned int pending) -{ -#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) - return -clz(pending) + 31 - CAUSEB_IP; -#else - unsigned int a0 = 7; - unsigned int t0; - - t0 = pending & 0xf000; - t0 = t0 < 1; - t0 = t0 << 2; - a0 = a0 - t0; - pending = pending << t0; - - t0 = pending & 0xc000; - t0 = t0 < 1; - t0 = t0 << 1; - a0 = a0 - t0; - pending = pending << t0; - - t0 = pending & 0x8000; - t0 = t0 < 1; - /* t0 = t0 << 2; */ - a0 = a0 - t0; - /* pending = pending << t0; */ - - return a0; -#endif -} - -/* - * IRQs on the Malta board look basically (barring software IRQs which we - * don't use at all and all external interrupt sources are combined together - * on hardware interrupt 0 (MIPS IRQ 2)) like: - * - * MIPS IRQ Source - * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Combined hardware interrupt (hw0) - * 3 Hardware (ignored) - * 4 Hardware (ignored) - * 5 Hardware (ignored) - * 6 Hardware (ignored) - * 7 R4k timer (what we use) - * - * We handle the IRQ according to _our_ priority which is: - * - * Highest ---- R4k Timer - * Lowest ---- Combined hardware interrupt - * - * then we just return, if multiple IRQs are pending then we will just take - * another exception, big deal. - */ - -asmlinkage void plat_irq_dispatch(void) +static irqreturn_t corehi_handler(int irq, void *dev_id) { - unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; - int irq; - - if (unlikely(!pending)) { - spurious_interrupt(); - return; - } - - irq = irq_ffs(pending); - - if (irq == MIPSCPU_INT_I8259A) - malta_hw0_irqdispatch(); - else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()])) - malta_ipi_irqdispatch(); - else - do_IRQ(MIPS_CPU_IRQ_BASE + irq); + corehi_irqdispatch(); + return IRQ_HANDLED; } #ifdef CONFIG_MIPS_MT_SMP @@ -312,13 +208,6 @@ static void ipi_call_dispatch(void) do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); } -#endif /* CONFIG_MIPS_MT_SMP */ - -#ifdef CONFIG_MIPS_GIC_IPI - -#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3 -#define GIC_MIPS_CPU_IPI_CALL_IRQ 4 - static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) { #ifdef CONFIG_MIPS_VPE_APSP_API_CMP @@ -349,31 +238,16 @@ static struct irqaction irq_call = { .flags = IRQF_PERCPU, .name = "IPI_call" }; -#endif /* CONFIG_MIPS_GIC_IPI */ - -static int gic_resched_int_base; -static int gic_call_int_base; -#define GIC_RESCHED_INT(cpu) (gic_resched_int_base+(cpu)) -#define GIC_CALL_INT(cpu) (gic_call_int_base+(cpu)) - -unsigned int plat_ipi_call_int_xlate(unsigned int cpu) -{ - return GIC_CALL_INT(cpu); -} - -unsigned int plat_ipi_resched_int_xlate(unsigned int cpu) -{ - return GIC_RESCHED_INT(cpu); -} +#endif /* CONFIG_MIPS_MT_SMP */ static struct irqaction i8259irq = { - .handler = no_action, + .handler = i8259_handler, .name = "XT-PIC cascade", .flags = IRQF_NO_THREAD, }; static struct irqaction corehi_irqaction = { - .handler = no_action, + .handler = corehi_handler, .name = "CoreHi", .flags = IRQF_NO_THREAD, }; @@ -399,60 +273,6 @@ static msc_irqmap_t msc_eicirqmap[] __initdata = { static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap); -/* - * This GIC specific tabular array defines the association between External - * Interrupts and CPUs/Core Interrupts. The nature of the External - * Interrupts is also defined here - polarity/trigger. - */ - -#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK -#define X GIC_UNUSED - -static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = { - { X, X, X, X, 0 }, - { X, X, X, X, 0 }, - { X, X, X, X, 0 }, - { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { X, X, X, X, 0 }, - { X, X, X, X, 0 }, - { 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_NMI, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_NMI, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { X, X, X, X, 0 }, - /* The remainder of this table is initialised by fill_ipi_map */ -}; -#undef X - -#ifdef CONFIG_MIPS_GIC_IPI -static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin) -{ - int intr = baseintr + cpu; - gic_intr_map[intr].cpunum = cpu; - gic_intr_map[intr].pin = cpupin; - gic_intr_map[intr].polarity = GIC_POL_POS; - gic_intr_map[intr].trigtype = GIC_TRIG_EDGE; - gic_intr_map[intr].flags = 0; - ipi_map[cpu] |= (1 << (cpupin + 2)); - bitmap_set(ipi_ints, intr, 1); -} - -static void __init fill_ipi_map(void) -{ - int cpu; - - for (cpu = 0; cpu < nr_cpu_ids; cpu++) { - fill_ipi_map1(gic_resched_int_base, cpu, GIC_CPU_INT1); - fill_ipi_map1(gic_call_int_base, cpu, GIC_CPU_INT2); - } -} -#endif - void __init arch_init_ipiirq(int irq, struct irqaction *action) { setup_irq(irq, action); @@ -461,6 +281,8 @@ void __init arch_init_ipiirq(int irq, struct irqaction *action) void __init arch_init_irq(void) { + int corehi_irq, i8259_irq; + init_i8259_irqs(); if (!cpu_has_veic) @@ -471,12 +293,12 @@ void __init arch_init_irq(void) gic_present = 1; } else { if (mips_revision_sconid == MIPS_REVISION_SCON_ROCIT) { - _msc01_biu_base = (unsigned long) - ioremap_nocache(MSC01_BIU_REG_BASE, + _msc01_biu_base = ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ); - gic_present = (REG(_msc01_biu_base, MSC01_SC_CFG) & - MSC01_SC_CFG_GICPRES_MSK) >> - MSC01_SC_CFG_GICPRES_SHF; + gic_present = + (__raw_readl(_msc01_biu_base + MSC01_SC_CFG_OFS) & + MSC01_SC_CFG_GICPRES_MSK) >> + MSC01_SC_CFG_GICPRES_SHF; } } if (gic_present) @@ -507,63 +329,20 @@ void __init arch_init_irq(void) msc_nr_irqs); } - if (cpu_has_veic) { - set_vi_handler(MSC01E_INT_I8259A, malta_hw0_irqdispatch); - set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch); - setup_irq(MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq); - setup_irq(MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction); - } else if (cpu_has_vint) { - set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); - set_vi_handler(MIPSCPU_INT_COREHI, corehi_irqdispatch); - setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); - setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, - &corehi_irqaction); - } else { - setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq); - setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, - &corehi_irqaction); - } - if (gic_present) { - /* FIXME */ int i; -#if defined(CONFIG_MIPS_GIC_IPI) - gic_call_int_base = GIC_NUM_INTRS - - (NR_CPUS - nr_cpu_ids) * 2 - nr_cpu_ids; - gic_resched_int_base = gic_call_int_base - nr_cpu_ids; - fill_ipi_map(); -#endif - gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, - ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); + + gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, MIPSCPU_INT_GIC, + MIPS_GIC_IRQ_BASE); if (!mips_cm_present()) { /* Enable the GIC */ - i = REG(_msc01_biu_base, MSC01_SC_CFG); - REG(_msc01_biu_base, MSC01_SC_CFG) = - (i | (0x1 << MSC01_SC_CFG_GICENA_SHF)); + i = __raw_readl(_msc01_biu_base + MSC01_SC_CFG_OFS); + __raw_writel(i | (0x1 << MSC01_SC_CFG_GICENA_SHF), + _msc01_biu_base + MSC01_SC_CFG_OFS); pr_debug("GIC Enabled\n"); } -#if defined(CONFIG_MIPS_GIC_IPI) - /* set up ipi interrupts */ - if (cpu_has_vint) { - set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch); - set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch); - } - /* Argh.. this really needs sorting out.. */ - pr_info("CPU%d: status register was %08x\n", - smp_processor_id(), read_c0_status()); - write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4); - pr_info("CPU%d: status register now %08x\n", - smp_processor_id(), read_c0_status()); - write_c0_status(0x1100dc00); - pr_info("CPU%d: status register frc %08x\n", - smp_processor_id(), read_c0_status()); - for (i = 0; i < nr_cpu_ids; i++) { - arch_init_ipiirq(MIPS_GIC_IRQ_BASE + - GIC_RESCHED_INT(i), &irq_resched); - arch_init_ipiirq(MIPS_GIC_IRQ_BASE + - GIC_CALL_INT(i), &irq_call); - } -#endif + i8259_irq = MIPS_GIC_IRQ_BASE + GIC_INT_I8259A; + corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; } else { #if defined(CONFIG_MIPS_MT_SMP) /* set up ipi interrupts */ @@ -573,12 +352,6 @@ void __init arch_init_irq(void) cpu_ipi_resched_irq = MSC01E_INT_SW0; cpu_ipi_call_irq = MSC01E_INT_SW1; } else { - if (cpu_has_vint) { - set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, - ipi_resched_dispatch); - set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, - ipi_call_dispatch); - } cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + @@ -587,7 +360,21 @@ void __init arch_init_irq(void) arch_init_ipiirq(cpu_ipi_resched_irq, &irq_resched); arch_init_ipiirq(cpu_ipi_call_irq, &irq_call); #endif + if (cpu_has_veic) { + set_vi_handler(MSC01E_INT_I8259A, + malta_hw0_irqdispatch); + set_vi_handler(MSC01E_INT_COREHI, + corehi_irqdispatch); + i8259_irq = MSC01E_INT_BASE + MSC01E_INT_I8259A; + corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI; + } else { + i8259_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_I8259A; + corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; + } } + + setup_irq(i8259_irq, &i8259irq); + setup_irq(corehi_irq, &corehi_irqaction); } void malta_be_init(void) @@ -714,37 +501,3 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup) return retval; } - -void gic_enable_interrupt(int irq_vec) -{ - GIC_SET_INTR_MASK(irq_vec); -} - -void gic_disable_interrupt(int irq_vec) -{ - GIC_CLR_INTR_MASK(irq_vec); -} - -void gic_irq_ack(struct irq_data *d) -{ - int irq = (d->irq - gic_irq_base); - - GIC_CLR_INTR_MASK(irq); - - if (gic_irq_flags[irq] & GIC_TRIG_EDGE) - GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); -} - -void gic_finish_irq(struct irq_data *d) -{ - /* Enable interrupts. */ - GIC_SET_INTR_MASK(d->irq - gic_irq_base); -} - -void __init gic_platform_init(int irqs, struct irq_chip *irq_controller) -{ - int i; - - for (i = gic_irq_base; i < (gic_irq_base + irqs); i++) - irq_set_chip(i, irq_controller); -} diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 3778a35..ce02dbd 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -24,6 +24,7 @@ #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/interrupt.h> +#include <linux/irqchip/mips-gic.h> #include <linux/timex.h> #include <linux/mc146818rtc.h> @@ -37,7 +38,6 @@ #include <asm/time.h> #include <asm/mc146818-time.h> #include <asm/msc01_ic.h> -#include <asm/gic.h> #include <asm/mips-boards/generic.h> #include <asm/mips-boards/maltaint.h> @@ -46,6 +46,8 @@ static int mips_cpu_timer_irq; static int mips_cpu_perf_irq; extern int cp0_perfcount_irq; +static unsigned int gic_frequency; + static void mips_timer_dispatch(void) { do_IRQ(mips_cpu_timer_irq); @@ -70,9 +72,7 @@ static void __init estimate_frequencies(void) { unsigned long flags; unsigned int count, start; -#ifdef CONFIG_IRQ_GIC - unsigned int giccount = 0, gicstart = 0; -#endif + cycle_t giccount = 0, gicstart = 0; #if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ mips_hpt_frequency = CONFIG_KVM_GUEST_TIMER_FREQ * 1000000; @@ -87,32 +87,26 @@ static void __init estimate_frequencies(void) /* Initialize counters. */ start = read_c0_count(); -#ifdef CONFIG_IRQ_GIC if (gic_present) - GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart); -#endif + gicstart = gic_read_count(); /* Read counter exactly on falling edge of update flag. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); count = read_c0_count(); -#ifdef CONFIG_IRQ_GIC if (gic_present) - GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount); -#endif + giccount = gic_read_count(); local_irq_restore(flags); count -= start; mips_hpt_frequency = count; -#ifdef CONFIG_IRQ_GIC if (gic_present) { giccount -= gicstart; gic_frequency = giccount; } -#endif } void read_persistent_clock(struct timespec *ts) @@ -121,35 +115,30 @@ void read_persistent_clock(struct timespec *ts) ts->tv_nsec = 0; } -static void __init plat_perf_setup(void) +int get_c0_perfcount_int(void) { -#ifdef MSC01E_INT_BASE if (cpu_has_veic) { set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; - } else -#endif - if (cp0_perfcount_irq >= 0) { - if (cpu_has_vint) - set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); + } else if (gic_present) { + mips_cpu_perf_irq = gic_get_c0_perfcount_int(); + } else if (cp0_perfcount_irq >= 0) { mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; -#ifdef CONFIG_SMP - irq_set_handler(mips_cpu_perf_irq, handle_percpu_irq); -#endif + } else { + mips_cpu_perf_irq = -1; } + + return mips_cpu_perf_irq; } unsigned int get_c0_compare_int(void) { -#ifdef MSC01E_INT_BASE if (cpu_has_veic) { set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch); mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; - } else -#endif - { - if (cpu_has_vint) - set_vi_handler(cp0_compare_irq, mips_timer_dispatch); + } else if (gic_present) { + mips_cpu_timer_irq = gic_get_c0_compare_int(); + } else { mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; } @@ -191,16 +180,14 @@ void __init plat_time_init(void) setup_pit_timer(); #endif -#ifdef CONFIG_IRQ_GIC +#ifdef CONFIG_MIPS_GIC if (gic_present) { freq = freqround(gic_frequency, 5000); printk("GIC frequency %d.%02d MHz\n", freq/1000000, (freq%1000000)*100/1000000); -#ifdef CONFIG_CSRC_GIC +#ifdef CONFIG_CLKSRC_MIPS_GIC gic_clocksource_init(gic_frequency); #endif } #endif - - plat_perf_setup(); } diff --git a/arch/mips/mti-sead3/sead3-ehci.c b/arch/mips/mti-sead3/sead3-ehci.c index 772fc05..014dd7b 100644 --- a/arch/mips/mti-sead3/sead3-ehci.c +++ b/arch/mips/mti-sead3/sead3-ehci.c @@ -9,6 +9,9 @@ #include <linux/irq.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> +#include <linux/irqchip/mips-gic.h> + +#include <asm/mips-boards/sead3int.h> struct resource ehci_resources[] = { { @@ -17,7 +20,6 @@ struct resource ehci_resources[] = { .flags = IORESOURCE_MEM }, { - .start = MIPS_CPU_IRQ_BASE + 2, .flags = IORESOURCE_IRQ } }; @@ -37,6 +39,10 @@ static struct platform_device ehci_device = { static int __init ehci_init(void) { + if (gic_present) + ehci_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_EHCI; + else + ehci_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_EHCI; return platform_device_register(&ehci_device); } diff --git a/arch/mips/mti-sead3/sead3-int.c b/arch/mips/mti-sead3/sead3-int.c index 6a560ac..e31e17f 100644 --- a/arch/mips/mti-sead3/sead3-int.c +++ b/arch/mips/mti-sead3/sead3-int.c @@ -7,9 +7,9 @@ */ #include <linux/init.h> #include <linux/irq.h> +#include <linux/irqchip/mips-gic.h> #include <linux/io.h> -#include <asm/gic.h> #include <asm/irq_cpu.h> #include <asm/setup.h> @@ -20,138 +20,23 @@ #define SEAD_CONFIG_BASE 0x1b100110 #define SEAD_CONFIG_SIZE 4 -static unsigned long sead3_config_reg; - -/* - * This table defines the setup for each external GIC interrupt. It is - * indexed by interrupt number. - */ -#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK -static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = { - { 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, - { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, - { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, - { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, - { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, - { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, - { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, - { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED }, -}; - -asmlinkage void plat_irq_dispatch(void) -{ - unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; - int irq; - - irq = (fls(pending) - CAUSEB_IP - 1); - if (irq >= 0) - do_IRQ(MIPS_CPU_IRQ_BASE + irq); - else - spurious_interrupt(); -} +static void __iomem *sead3_config_reg; void __init arch_init_irq(void) { - int i; - - if (!cpu_has_veic) { + if (!cpu_has_veic) mips_cpu_irq_init(); - if (cpu_has_vint) { - /* install generic handler */ - for (i = 0; i < 8; i++) - set_vi_handler(i, plat_irq_dispatch); - } - } - - sead3_config_reg = (unsigned long)ioremap_nocache(SEAD_CONFIG_BASE, - SEAD_CONFIG_SIZE); - gic_present = (REG32(sead3_config_reg) & SEAD_CONFIG_GIC_PRESENT_MSK) >> + sead3_config_reg = ioremap_nocache(SEAD_CONFIG_BASE, SEAD_CONFIG_SIZE); + gic_present = (__raw_readl(sead3_config_reg) & + SEAD_CONFIG_GIC_PRESENT_MSK) >> SEAD_CONFIG_GIC_PRESENT_SHF; pr_info("GIC: %spresent\n", (gic_present) ? "" : "not "); pr_info("EIC: %s\n", (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off"); if (gic_present) - gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, - ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); -} - -void gic_enable_interrupt(int irq_vec) -{ - unsigned int i, irq_source; - - /* enable all the interrupts associated with this vector */ - for (i = 0; i < gic_shared_intr_map[irq_vec].num_shared_intr; i++) { - irq_source = gic_shared_intr_map[irq_vec].intr_list[i]; - GIC_SET_INTR_MASK(irq_source); - } - /* enable all local interrupts associated with this vector */ - if (gic_shared_intr_map[irq_vec].local_intr_mask) { - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0); - GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), - gic_shared_intr_map[irq_vec].local_intr_mask); - } + gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, CPU_INT_GIC, + MIPS_GIC_IRQ_BASE); } -void gic_disable_interrupt(int irq_vec) -{ - unsigned int i, irq_source; - - /* disable all the interrupts associated with this vector */ - for (i = 0; i < gic_shared_intr_map[irq_vec].num_shared_intr; i++) { - irq_source = gic_shared_intr_map[irq_vec].intr_list[i]; - GIC_CLR_INTR_MASK(irq_source); - } - /* disable all local interrupts associated with this vector */ - if (gic_shared_intr_map[irq_vec].local_intr_mask) { - GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0); - GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), - gic_shared_intr_map[irq_vec].local_intr_mask); - } -} - -void gic_irq_ack(struct irq_data *d) -{ - GIC_CLR_INTR_MASK(d->irq - gic_irq_base); -} - -void gic_finish_irq(struct irq_data *d) -{ - unsigned int irq = (d->irq - gic_irq_base); - unsigned int i, irq_source; - - /* Clear edge detectors. */ - for (i = 0; i < gic_shared_intr_map[irq].num_shared_intr; i++) { - irq_source = gic_shared_intr_map[irq].intr_list[i]; - if (gic_irq_flags[irq_source] & GIC_TRIG_EDGE) - GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq_source); - } - - /* Enable interrupts. */ - GIC_SET_INTR_MASK(irq); -} - -void __init gic_platform_init(int irqs, struct irq_chip *irq_controller) -{ - int i; - - /* - * For non-EIC mode, we want to setup the GIC in pass-through - * mode, as if the GIC didn't exist. Do not map any interrupts - * for an external interrupt controller. - */ - if (!cpu_has_veic) - return; - - for (i = gic_irq_base; i < (gic_irq_base + irqs); i++) - irq_set_chip_and_handler(i, irq_controller, handle_percpu_irq); -} diff --git a/arch/mips/mti-sead3/sead3-net.c b/arch/mips/mti-sead3/sead3-net.c index dd11e7e..46176b8 100644 --- a/arch/mips/mti-sead3/sead3-net.c +++ b/arch/mips/mti-sead3/sead3-net.c @@ -7,9 +7,12 @@ */ #include <linux/module.h> #include <linux/irq.h> +#include <linux/irqchip/mips-gic.h> #include <linux/platform_device.h> #include <linux/smsc911x.h> +#include <asm/mips-boards/sead3int.h> + static struct smsc911x_platform_config sead3_smsc911x_data = { .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, @@ -17,14 +20,13 @@ static struct smsc911x_platform_config sead3_smsc911x_data = { .phy_interface = PHY_INTERFACE_MODE_MII, }; -struct resource sead3_net_resourcess[] = { +struct resource sead3_net_resources[] = { { .start = 0x1f010000, .end = 0x1f01ffff, .flags = IORESOURCE_MEM }, { - .start = MIPS_CPU_IRQ_BASE + 6, .flags = IORESOURCE_IRQ } }; @@ -35,12 +37,16 @@ static struct platform_device sead3_net_device = { .dev = { .platform_data = &sead3_smsc911x_data, }, - .num_resources = ARRAY_SIZE(sead3_net_resourcess), - .resource = sead3_net_resourcess + .num_resources = ARRAY_SIZE(sead3_net_resources), + .resource = sead3_net_resources }; static int __init sead3_net_init(void) { + if (gic_present) + sead3_net_resources[1].start = MIPS_GIC_IRQ_BASE + GIC_INT_NET; + else + sead3_net_resources[1].start = MIPS_CPU_IRQ_BASE + CPU_INT_NET; return platform_device_register(&sead3_net_device); } diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c index 6c3b33d..53ee6f1 100644 --- a/arch/mips/mti-sead3/sead3-platform.c +++ b/arch/mips/mti-sead3/sead3-platform.c @@ -7,12 +7,15 @@ */ #include <linux/module.h> #include <linux/init.h> +#include <linux/irqchip/mips-gic.h> #include <linux/serial_8250.h> -#define UART(base, int) \ +#include <asm/mips-boards/sead3int.h> + +#define UART(base) \ { \ .mapbase = base, \ - .irq = int, \ + .irq = -1, \ .uartclk = 14745600, \ .iotype = UPIO_MEM32, \ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \ @@ -20,8 +23,8 @@ } static struct plat_serial8250_port uart8250_data[] = { - UART(0x1f000900, MIPS_CPU_IRQ_BASE + 4), /* ttyS0 = USB */ - UART(0x1f000800, MIPS_CPU_IRQ_BASE + 4), /* ttyS1 = RS232 */ + UART(0x1f000900), /* ttyS0 = USB */ + UART(0x1f000800), /* ttyS1 = RS232 */ { }, }; @@ -35,6 +38,13 @@ static struct platform_device uart8250_device = { static int __init uart8250_init(void) { + if (gic_present) { + uart8250_data[0].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART0; + uart8250_data[1].irq = MIPS_GIC_IRQ_BASE + GIC_INT_UART1; + } else { + uart8250_data[0].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART0; + uart8250_data[1].irq = MIPS_CPU_IRQ_BASE + CPU_INT_UART1; + } return platform_device_register(&uart8250_device); } diff --git a/arch/mips/mti-sead3/sead3-serial.c b/arch/mips/mti-sead3/sead3-serial.c deleted file mode 100644 index bc52705..0000000 --- a/arch/mips/mti-sead3/sead3-serial.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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) 2012 MIPS Technologies, Inc. All rights reserved. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/serial_8250.h> - -#define UART(base, int) \ -{ \ - .mapbase = base, \ - .irq = int, \ - .uartclk = 14745600, \ - .iotype = UPIO_MEM32, \ - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \ - .regshift = 2, \ -} - -static struct plat_serial8250_port uart8250_data[] = { - UART(0x1f000900, MIPS_CPU_IRQ_BASE + 4), /* ttyS0 = USB */ - UART(0x1f000800, MIPS_CPU_IRQ_BASE + 4), /* ttyS1 = RS232 */ - { }, -}; - -static struct platform_device uart8250_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = uart8250_data, - }, -}; - -static int __init uart8250_init(void) -{ - return platform_device_register(&uart8250_device); -} - -module_init(uart8250_init); - -MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("8250 UART probe driver for the SEAD-3 platform"); diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c index 678d03d..ec1dd24 100644 --- a/arch/mips/mti-sead3/sead3-time.c +++ b/arch/mips/mti-sead3/sead3-time.c @@ -6,6 +6,7 @@ * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ #include <linux/init.h> +#include <linux/irqchip/mips-gic.h> #include <asm/cpu.h> #include <asm/setup.h> @@ -13,19 +14,6 @@ #include <asm/irq.h> #include <asm/mips-boards/generic.h> -static int mips_cpu_timer_irq; -static int mips_cpu_perf_irq; - -static void mips_timer_dispatch(void) -{ - do_IRQ(mips_cpu_timer_irq); -} - -static void mips_perf_dispatch(void) -{ - do_IRQ(mips_cpu_perf_irq); -} - static void __iomem *status_reg = (void __iomem *)0xbf000410; /* @@ -81,21 +69,20 @@ void read_persistent_clock(struct timespec *ts) ts->tv_nsec = 0; } -static void __init plat_perf_setup(void) +int get_c0_perfcount_int(void) { - if (cp0_perfcount_irq >= 0) { - if (cpu_has_vint) - set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); - mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; - } + if (gic_present) + return gic_get_c0_compare_int(); + if (cp0_perfcount_irq >= 0) + return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + return -1; } unsigned int get_c0_compare_int(void) { - if (cpu_has_vint) - set_vi_handler(cp0_compare_irq, mips_timer_dispatch); - mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; - return mips_cpu_timer_irq; + if (gic_present) + return gic_get_c0_compare_int(); + return MIPS_CPU_IRQ_BASE + cp0_compare_irq; } void __init plat_time_init(void) @@ -108,6 +95,4 @@ void __init plat_time_init(void) (est_freq % 1000000) * 100 / 1000000); mips_scroll_message(); - - plat_perf_setup(); } diff --git a/arch/mips/oprofile/Makefile b/arch/mips/oprofile/Makefile index 9c0a678..070afdb 100644 --- a/arch/mips/oprofile/Makefile +++ b/arch/mips/oprofile/Makefile @@ -14,3 +14,4 @@ oprofile-$(CONFIG_CPU_R10000) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_SB1) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_XLR) += op_model_mipsxx.o oprofile-$(CONFIG_CPU_LOONGSON2) += op_model_loongson2.o +oprofile-$(CONFIG_CPU_LOONGSON3) += op_model_loongson3.o diff --git a/arch/mips/oprofile/backtrace.c b/arch/mips/oprofile/backtrace.c index 83a1dfd..5e645c9 100644 --- a/arch/mips/oprofile/backtrace.c +++ b/arch/mips/oprofile/backtrace.c @@ -65,7 +65,7 @@ static inline int is_end_of_function_marker(union mips_instruction *ip) * - handle cases where the stack is adjusted inside a function * (generally doesn't happen) * - find optimal value for max_instr_check - * - try to find a way to handle leaf functions + * - try to find a better way to handle leaf functions */ static inline int unwind_user_frame(struct stackframe *old_frame, @@ -104,7 +104,7 @@ static inline int unwind_user_frame(struct stackframe *old_frame, } if (!ra_offset || !stack_size) - return -1; + goto done; if (ra_offset) { new_frame.ra = old_frame->sp + ra_offset; @@ -121,6 +121,7 @@ static inline int unwind_user_frame(struct stackframe *old_frame, if (new_frame.sp > old_frame->sp) return -2; +done: new_frame.pc = old_frame->ra; *old_frame = new_frame; diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index e747324..a26cbe3 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -18,6 +18,7 @@ extern struct op_mips_model op_model_mipsxx_ops __weak; extern struct op_mips_model op_model_loongson2_ops __weak; +extern struct op_mips_model op_model_loongson3_ops __weak; static struct op_mips_model *model; @@ -104,8 +105,17 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) case CPU_LOONGSON2: lmodel = &op_model_loongson2_ops; break; + case CPU_LOONGSON3: + lmodel = &op_model_loongson3_ops; + break; }; + /* + * Always set the backtrace. This allows unsupported CPU types to still + * use timer-based oprofile. + */ + ops->backtrace = op_mips_backtrace; + if (!lmodel) return -ENODEV; @@ -121,7 +131,6 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ops->start = op_mips_start; ops->stop = op_mips_stop; ops->cpu_type = lmodel->cpu_type; - ops->backtrace = op_mips_backtrace; printk(KERN_INFO "oprofile: using %s performance monitoring.\n", lmodel->cpu_type); diff --git a/arch/mips/oprofile/op_model_loongson3.c b/arch/mips/oprofile/op_model_loongson3.c new file mode 100644 index 0000000..8bcf7fc --- /dev/null +++ b/arch/mips/oprofile/op_model_loongson3.c @@ -0,0 +1,220 @@ +/* + * 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. + * + */ +#include <linux/init.h> +#include <linux/cpu.h> +#include <linux/smp.h> +#include <linux/proc_fs.h> +#include <linux/oprofile.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#include <irq.h> +#include <loongson.h> +#include "op_impl.h" + +#define LOONGSON3_PERFCNT_OVERFLOW (1ULL << 63) + +#define LOONGSON3_PERFCTRL_EXL (1UL << 0) +#define LOONGSON3_PERFCTRL_KERNEL (1UL << 1) +#define LOONGSON3_PERFCTRL_SUPERVISOR (1UL << 2) +#define LOONGSON3_PERFCTRL_USER (1UL << 3) +#define LOONGSON3_PERFCTRL_ENABLE (1UL << 4) +#define LOONGSON3_PERFCTRL_W (1UL << 30) +#define LOONGSON3_PERFCTRL_M (1UL << 31) +#define LOONGSON3_PERFCTRL_EVENT(idx, event) \ + (((event) & (idx ? 0x0f : 0x3f)) << 5) + +/* Loongson-3 PerfCount performance counter1 register */ +#define read_c0_perflo1() __read_64bit_c0_register($25, 0) +#define write_c0_perflo1(val) __write_64bit_c0_register($25, 0, val) +#define read_c0_perfhi1() __read_64bit_c0_register($25, 1) +#define write_c0_perfhi1(val) __write_64bit_c0_register($25, 1, val) + +/* Loongson-3 PerfCount performance counter2 register */ +#define read_c0_perflo2() __read_64bit_c0_register($25, 2) +#define write_c0_perflo2(val) __write_64bit_c0_register($25, 2, val) +#define read_c0_perfhi2() __read_64bit_c0_register($25, 3) +#define write_c0_perfhi2(val) __write_64bit_c0_register($25, 3, val) + +static int (*save_perf_irq)(void); + +static struct loongson3_register_config { + unsigned int control1; + unsigned int control2; + unsigned long long reset_counter1; + unsigned long long reset_counter2; + int ctr1_enable, ctr2_enable; +} reg; + +static void reset_counters(void *arg) +{ + write_c0_perfhi1(0); + write_c0_perfhi2(0); + write_c0_perflo1(0xc0000000); + write_c0_perflo2(0x40000000); +} + +/* Compute all of the registers in preparation for enabling profiling. */ +static void loongson3_reg_setup(struct op_counter_config *ctr) +{ + unsigned int control1 = 0; + unsigned int control2 = 0; + + reg.reset_counter1 = 0; + reg.reset_counter2 = 0; + /* Compute the performance counter control word. */ + /* For now count kernel and user mode */ + if (ctr[0].enabled) { + control1 |= LOONGSON3_PERFCTRL_EVENT(0, ctr[0].event) | + LOONGSON3_PERFCTRL_ENABLE; + if (ctr[0].kernel) + control1 |= LOONGSON3_PERFCTRL_KERNEL; + if (ctr[0].user) + control1 |= LOONGSON3_PERFCTRL_USER; + reg.reset_counter1 = 0x8000000000000000ULL - ctr[0].count; + } + + if (ctr[1].enabled) { + control2 |= LOONGSON3_PERFCTRL_EVENT(1, ctr[1].event) | + LOONGSON3_PERFCTRL_ENABLE; + if (ctr[1].kernel) + control2 |= LOONGSON3_PERFCTRL_KERNEL; + if (ctr[1].user) + control2 |= LOONGSON3_PERFCTRL_USER; + reg.reset_counter2 = 0x8000000000000000ULL - ctr[1].count; + } + + if (ctr[0].enabled) + control1 |= LOONGSON3_PERFCTRL_EXL; + if (ctr[1].enabled) + control2 |= LOONGSON3_PERFCTRL_EXL; + + reg.control1 = control1; + reg.control2 = control2; + reg.ctr1_enable = ctr[0].enabled; + reg.ctr2_enable = ctr[1].enabled; +} + +/* Program all of the registers in preparation for enabling profiling. */ +static void loongson3_cpu_setup(void *args) +{ + uint64_t perfcount1, perfcount2; + + perfcount1 = reg.reset_counter1; + perfcount2 = reg.reset_counter2; + write_c0_perfhi1(perfcount1); + write_c0_perfhi2(perfcount2); +} + +static void loongson3_cpu_start(void *args) +{ + /* Start all counters on current CPU */ + reg.control1 |= (LOONGSON3_PERFCTRL_W|LOONGSON3_PERFCTRL_M); + reg.control2 |= (LOONGSON3_PERFCTRL_W|LOONGSON3_PERFCTRL_M); + + if (reg.ctr1_enable) + write_c0_perflo1(reg.control1); + if (reg.ctr2_enable) + write_c0_perflo2(reg.control2); +} + +static void loongson3_cpu_stop(void *args) +{ + /* Stop all counters on current CPU */ + write_c0_perflo1(0xc0000000); + write_c0_perflo2(0x40000000); + memset(®, 0, sizeof(reg)); +} + +static int loongson3_perfcount_handler(void) +{ + unsigned long flags; + uint64_t counter1, counter2; + uint32_t cause, handled = IRQ_NONE; + struct pt_regs *regs = get_irq_regs(); + + cause = read_c0_cause(); + if (!(cause & CAUSEF_PCI)) + return handled; + + counter1 = read_c0_perfhi1(); + counter2 = read_c0_perfhi2(); + + local_irq_save(flags); + + if (counter1 & LOONGSON3_PERFCNT_OVERFLOW) { + if (reg.ctr1_enable) + oprofile_add_sample(regs, 0); + counter1 = reg.reset_counter1; + } + if (counter2 & LOONGSON3_PERFCNT_OVERFLOW) { + if (reg.ctr2_enable) + oprofile_add_sample(regs, 1); + counter2 = reg.reset_counter2; + } + + local_irq_restore(flags); + + write_c0_perfhi1(counter1); + write_c0_perfhi2(counter2); + + if (!(cause & CAUSEF_TI)) + handled = IRQ_HANDLED; + + return handled; +} + +static int loongson3_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + switch (action) { + case CPU_STARTING: + case CPU_STARTING_FROZEN: + write_c0_perflo1(reg.control1); + write_c0_perflo2(reg.control2); + break; + case CPU_DYING: + case CPU_DYING_FROZEN: + write_c0_perflo1(0xc0000000); + write_c0_perflo2(0x40000000); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block loongson3_notifier_block = { + .notifier_call = loongson3_cpu_callback +}; + +static int __init loongson3_init(void) +{ + on_each_cpu(reset_counters, NULL, 1); + register_hotcpu_notifier(&loongson3_notifier_block); + save_perf_irq = perf_irq; + perf_irq = loongson3_perfcount_handler; + + return 0; +} + +static void loongson3_exit(void) +{ + on_each_cpu(reset_counters, NULL, 1); + unregister_hotcpu_notifier(&loongson3_notifier_block); + perf_irq = save_perf_irq; +} + +struct op_mips_model op_model_loongson3_ops = { + .reg_setup = loongson3_reg_setup, + .cpu_setup = loongson3_cpu_setup, + .init = loongson3_init, + .exit = loongson3_exit, + .cpu_start = loongson3_cpu_start, + .cpu_stop = loongson3_cpu_stop, + .cpu_type = "mips/loongson3", + .num_counters = 2 +}; diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 42821ae..01f721a 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -11,6 +11,7 @@ #include <linux/interrupt.h> #include <linux/smp.h> #include <asm/irq_regs.h> +#include <asm/time.h> #include "op_impl.h" @@ -35,6 +36,7 @@ #define M_PERFCTL_COUNT_ALL_THREADS (1UL << 13) static int (*save_perf_irq)(void); +static int perfcount_irq; /* * XLR has only one set of counters per core. Designate the @@ -431,8 +433,16 @@ static int __init mipsxx_init(void) save_perf_irq = perf_irq; perf_irq = mipsxx_perfcount_handler; - if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq)) - return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int, + if (get_c0_perfcount_int) + perfcount_irq = get_c0_perfcount_int(); + else if ((cp0_perfcount_irq >= 0) && + (cp0_compare_irq != cp0_perfcount_irq)) + perfcount_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + else + perfcount_irq = -1; + + if (perfcount_irq >= 0) + return request_irq(perfcount_irq, mipsxx_perfcount_int, 0, "Perfcounter", save_perf_irq); return 0; @@ -442,8 +452,8 @@ static void mipsxx_exit(void) { int counters = op_model_mipsxx_ops.num_counters; - if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq)) - free_irq(cp0_perfcount_irq, save_perf_irq); + if (perfcount_irq >= 0) + free_irq(perfcount_irq, save_perf_irq); counters = counters_per_cpu_to_total(counters); on_each_cpu(reset_counters, (void *)(long)counters, 1); diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 6523d55..300591c 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ ops-bcm63xx.o obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o +obj-$(CONFIG_PCI_AR2315) += pci-ar2315.o obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o obj-$(CONFIG_MIPS_PCI_VIRTIO) += pci-virtio-guest.o @@ -42,6 +43,7 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o obj-$(CONFIG_LANTIQ) += fixup-lantiq.o obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o +obj-$(CONFIG_SOC_RT2880) += pci-rt2880.o obj-$(CONFIG_SOC_RT3883) += pci-rt3883.o obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index 13eea69..d02eb9d 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c @@ -469,7 +469,7 @@ static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn) { switch (bus->number) { case PCIE_BUS_BRIDGE: - return (PCI_SLOT(devfn) == 0); + return PCI_SLOT(devfn) == 0; case PCIE_BUS_DEVICE: if (PCI_SLOT(devfn) == 0) return bcm_pcie_readl(PCIE_DLSTATUS_REG) diff --git a/arch/mips/pci/ops-nile4.c b/arch/mips/pci/ops-nile4.c index a1a7c9f..b9d1fd0 100644 --- a/arch/mips/pci/ops-nile4.c +++ b/arch/mips/pci/ops-nile4.c @@ -13,8 +13,6 @@ volatile unsigned long *const vrc_pciregs = (void *) Vrc5074_BASE; -static DEFINE_SPINLOCK(nile4_pci_lock); - static int nile4_pcibios_config_access(unsigned char access_type, struct pci_bus *bus, unsigned int devfn, int where, u32 *val) { @@ -76,7 +74,6 @@ static int nile4_pcibios_config_access(unsigned char access_type, static int nile4_pcibios_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - unsigned long flags; u32 data = 0; int err; @@ -85,11 +82,8 @@ static int nile4_pcibios_read(struct pci_bus *bus, unsigned int devfn, else if ((size == 4) && (where & 3)) return PCIBIOS_BAD_REGISTER_NUMBER; - spin_lock_irqsave(&nile4_pci_lock, flags); err = nile4_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, - &data); - spin_unlock_irqrestore(&nile4_pci_lock, flags); - + &data); if (err) return err; @@ -106,7 +100,6 @@ static int nile4_pcibios_read(struct pci_bus *bus, unsigned int devfn, static int nile4_pcibios_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - unsigned long flags; u32 data = 0; int err; @@ -115,11 +108,8 @@ static int nile4_pcibios_write(struct pci_bus *bus, unsigned int devfn, else if ((size == 4) && (where & 3)) return PCIBIOS_BAD_REGISTER_NUMBER; - spin_lock_irqsave(&nile4_pci_lock, flags); err = nile4_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, &data); - spin_unlock_irqrestore(&nile4_pci_lock, flags); - if (err) return err; diff --git a/arch/mips/pci/ops-pmcmsp.c b/arch/mips/pci/ops-pmcmsp.c index 50034f9..dd2d9f7 100644 --- a/arch/mips/pci/ops-pmcmsp.c +++ b/arch/mips/pci/ops-pmcmsp.c @@ -193,8 +193,6 @@ static void pci_proc_init(void) } #endif /* CONFIG_PROC_FS && PCI_COUNTERS */ -static DEFINE_SPINLOCK(bpci_lock); - /***************************************************************************** * * STRUCT: pci_io_resource @@ -368,7 +366,6 @@ int msp_pcibios_config_access(unsigned char access_type, struct msp_pci_regs *preg = (void *)PCI_BASE_REG; unsigned char bus_num = bus->number; unsigned char dev_fn = (unsigned char)devfn; - unsigned long flags; unsigned long intr; unsigned long value; static char pciirqflag; @@ -401,10 +398,7 @@ int msp_pcibios_config_access(unsigned char access_type, } #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) - local_irq_save(flags); vpe_status = dvpe(); -#else - spin_lock_irqsave(&bpci_lock, flags); #endif /* @@ -457,9 +451,6 @@ int msp_pcibios_config_access(unsigned char access_type, #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) evpe(vpe_status); - local_irq_restore(flags); -#else - spin_unlock_irqrestore(&bpci_lock, flags); #endif return -1; @@ -467,9 +458,6 @@ int msp_pcibios_config_access(unsigned char access_type, #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) evpe(vpe_status); - local_irq_restore(flags); -#else - spin_unlock_irqrestore(&bpci_lock, flags); #endif return PCIBIOS_SUCCESSFUL; diff --git a/arch/mips/pci/pci-ar2315.c b/arch/mips/pci/pci-ar2315.c new file mode 100644 index 0000000..bd2b3b6 --- /dev/null +++ b/arch/mips/pci/pci-ar2315.c @@ -0,0 +1,511 @@ +/* + * 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. + * + * This program is distributed in the hope that 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/** + * Both AR2315 and AR2316 chips have PCI interface unit, which supports DMA + * and interrupt. PCI interface supports MMIO access method, but does not + * seem to support I/O ports. + * + * Read/write operation in the region 0x80000000-0xBFFFFFFF causes + * a memory read/write command on the PCI bus. 30 LSBs of address on + * the bus are taken from memory read/write request and 2 MSBs are + * determined by PCI unit configuration. + * + * To work with the configuration space instead of memory is necessary set + * the CFG_SEL bit in the PCI_MISC_CONFIG register. + * + * Devices on the bus can perform DMA requests via chip BAR1. PCI host + * controller BARs are programmend as if an external device is programmed. + * Which means that during configuration, IDSEL pin of the chip should be + * asserted. + * + * We know (and support) only one board that uses the PCI interface - + * Fonera 2.0g (FON2202). It has a USB EHCI controller connected to the + * AR2315 PCI bus. IDSEL pin of USB controller is connected to AD[13] line + * and IDSEL pin of AR2315 is connected to AD[16] line. + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/delay.h> +#include <linux/bitops.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/io.h> +#include <asm/paccess.h> + +/* + * PCI Bus Interface Registers + */ +#define AR2315_PCI_1MS_REG 0x0008 + +#define AR2315_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */ + +#define AR2315_PCI_MISC_CONFIG 0x000c + +#define AR2315_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */ +#define AR2315_PCIMISC_CFG_SEL 0x00000002 /* Mem or Config cycles */ +#define AR2315_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */ +#define AR2315_PCIMISC_RST_MODE 0x00000030 +#define AR2315_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */ +#define AR2315_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */ +#define AR2315_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */ +#define AR2315_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */ +#define AR2315_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */ +#define AR2315_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */ +#define AR2315_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */ +#define AR2315_PCICACHE_DIS 0x00001000 /* PCI external access cache + * disable */ + +#define AR2315_PCI_OUT_TSTAMP 0x0010 + +#define AR2315_PCI_UNCACHE_CFG 0x0014 + +#define AR2315_PCI_IN_EN 0x0100 + +#define AR2315_PCI_IN_EN0 0x01 /* Enable chain 0 */ +#define AR2315_PCI_IN_EN1 0x02 /* Enable chain 1 */ +#define AR2315_PCI_IN_EN2 0x04 /* Enable chain 2 */ +#define AR2315_PCI_IN_EN3 0x08 /* Enable chain 3 */ + +#define AR2315_PCI_IN_DIS 0x0104 + +#define AR2315_PCI_IN_DIS0 0x01 /* Disable chain 0 */ +#define AR2315_PCI_IN_DIS1 0x02 /* Disable chain 1 */ +#define AR2315_PCI_IN_DIS2 0x04 /* Disable chain 2 */ +#define AR2315_PCI_IN_DIS3 0x08 /* Disable chain 3 */ + +#define AR2315_PCI_IN_PTR 0x0200 + +#define AR2315_PCI_OUT_EN 0x0400 + +#define AR2315_PCI_OUT_EN0 0x01 /* Enable chain 0 */ + +#define AR2315_PCI_OUT_DIS 0x0404 + +#define AR2315_PCI_OUT_DIS0 0x01 /* Disable chain 0 */ + +#define AR2315_PCI_OUT_PTR 0x0408 + +/* PCI interrupt status (write one to clear) */ +#define AR2315_PCI_ISR 0x0500 + +#define AR2315_PCI_INT_TX 0x00000001 /* Desc In Completed */ +#define AR2315_PCI_INT_TXOK 0x00000002 /* Desc In OK */ +#define AR2315_PCI_INT_TXERR 0x00000004 /* Desc In ERR */ +#define AR2315_PCI_INT_TXEOL 0x00000008 /* Desc In End-of-List */ +#define AR2315_PCI_INT_RX 0x00000010 /* Desc Out Completed */ +#define AR2315_PCI_INT_RXOK 0x00000020 /* Desc Out OK */ +#define AR2315_PCI_INT_RXERR 0x00000040 /* Desc Out ERR */ +#define AR2315_PCI_INT_RXEOL 0x00000080 /* Desc Out EOL */ +#define AR2315_PCI_INT_TXOOD 0x00000200 /* Desc In Out-of-Desc */ +#define AR2315_PCI_INT_DESCMASK 0x0000FFFF /* Desc Mask */ +#define AR2315_PCI_INT_EXT 0x02000000 /* Extern PCI INTA */ +#define AR2315_PCI_INT_ABORT 0x04000000 /* PCI bus abort event */ + +/* PCI interrupt mask */ +#define AR2315_PCI_IMR 0x0504 + +/* Global PCI interrupt enable */ +#define AR2315_PCI_IER 0x0508 + +#define AR2315_PCI_IER_DISABLE 0x00 /* disable pci interrupts */ +#define AR2315_PCI_IER_ENABLE 0x01 /* enable pci interrupts */ + +#define AR2315_PCI_HOST_IN_EN 0x0800 +#define AR2315_PCI_HOST_IN_DIS 0x0804 +#define AR2315_PCI_HOST_IN_PTR 0x0810 +#define AR2315_PCI_HOST_OUT_EN 0x0900 +#define AR2315_PCI_HOST_OUT_DIS 0x0904 +#define AR2315_PCI_HOST_OUT_PTR 0x0908 + +/* + * PCI interrupts, which share IP5 + * Keep ordered according to AR2315_PCI_INT_XXX bits + */ +#define AR2315_PCI_IRQ_EXT 25 +#define AR2315_PCI_IRQ_ABORT 26 +#define AR2315_PCI_IRQ_COUNT 27 + +/* Arbitrary size of memory region to access the configuration space */ +#define AR2315_PCI_CFG_SIZE 0x00100000 + +#define AR2315_PCI_HOST_SLOT 3 +#define AR2315_PCI_HOST_DEVID ((0xff18 << 16) | PCI_VENDOR_ID_ATHEROS) + +/* ??? access BAR */ +#define AR2315_PCI_HOST_MBAR0 0x10000000 +/* RAM access BAR */ +#define AR2315_PCI_HOST_MBAR1 AR2315_PCI_HOST_SDRAM_BASEADDR +/* ??? access BAR */ +#define AR2315_PCI_HOST_MBAR2 0x30000000 + +struct ar2315_pci_ctrl { + void __iomem *cfg_mem; + void __iomem *mmr_mem; + unsigned irq; + unsigned irq_ext; + struct irq_domain *domain; + struct pci_controller pci_ctrl; + struct resource mem_res; + struct resource io_res; +}; + +static inline struct ar2315_pci_ctrl *ar2315_pci_bus_to_apc(struct pci_bus *bus) +{ + struct pci_controller *hose = bus->sysdata; + + return container_of(hose, struct ar2315_pci_ctrl, pci_ctrl); +} + +static inline u32 ar2315_pci_reg_read(struct ar2315_pci_ctrl *apc, u32 reg) +{ + return __raw_readl(apc->mmr_mem + reg); +} + +static inline void ar2315_pci_reg_write(struct ar2315_pci_ctrl *apc, u32 reg, + u32 val) +{ + __raw_writel(val, apc->mmr_mem + reg); +} + +static inline void ar2315_pci_reg_mask(struct ar2315_pci_ctrl *apc, u32 reg, + u32 mask, u32 val) +{ + u32 ret = ar2315_pci_reg_read(apc, reg); + + ret &= ~mask; + ret |= val; + ar2315_pci_reg_write(apc, reg, ret); +} + +static int ar2315_pci_cfg_access(struct ar2315_pci_ctrl *apc, unsigned devfn, + int where, int size, u32 *ptr, bool write) +{ + int func = PCI_FUNC(devfn); + int dev = PCI_SLOT(devfn); + u32 addr = (1 << (13 + dev)) | (func << 8) | (where & ~3); + u32 mask = 0xffffffff >> 8 * (4 - size); + u32 sh = (where & 3) * 8; + u32 value, isr; + + /* Prevent access past the remapped area */ + if (addr >= AR2315_PCI_CFG_SIZE || dev > 18) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Clear pending errors */ + ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT); + /* Select Configuration access */ + ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG, 0, + AR2315_PCIMISC_CFG_SEL); + + mb(); /* PCI must see space change before we begin */ + + value = __raw_readl(apc->cfg_mem + addr); + + isr = ar2315_pci_reg_read(apc, AR2315_PCI_ISR); + + if (isr & AR2315_PCI_INT_ABORT) + goto exit_err; + + if (write) { + value = (value & ~(mask << sh)) | *ptr << sh; + __raw_writel(value, apc->cfg_mem + addr); + isr = ar2315_pci_reg_read(apc, AR2315_PCI_ISR); + if (isr & AR2315_PCI_INT_ABORT) + goto exit_err; + } else { + *ptr = (value >> sh) & mask; + } + + goto exit; + +exit_err: + ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT); + if (!write) + *ptr = 0xffffffff; + +exit: + /* Select Memory access */ + ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_CFG_SEL, + 0); + + return isr & AR2315_PCI_INT_ABORT ? PCIBIOS_DEVICE_NOT_FOUND : + PCIBIOS_SUCCESSFUL; +} + +static inline int ar2315_pci_local_cfg_rd(struct ar2315_pci_ctrl *apc, + unsigned devfn, int where, u32 *val) +{ + return ar2315_pci_cfg_access(apc, devfn, where, sizeof(u32), val, + false); +} + +static inline int ar2315_pci_local_cfg_wr(struct ar2315_pci_ctrl *apc, + unsigned devfn, int where, u32 val) +{ + return ar2315_pci_cfg_access(apc, devfn, where, sizeof(u32), &val, + true); +} + +static int ar2315_pci_cfg_read(struct pci_bus *bus, unsigned devfn, int where, + int size, u32 *value) +{ + struct ar2315_pci_ctrl *apc = ar2315_pci_bus_to_apc(bus); + + if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT) + return PCIBIOS_DEVICE_NOT_FOUND; + + return ar2315_pci_cfg_access(apc, devfn, where, size, value, false); +} + +static int ar2315_pci_cfg_write(struct pci_bus *bus, unsigned devfn, int where, + int size, u32 value) +{ + struct ar2315_pci_ctrl *apc = ar2315_pci_bus_to_apc(bus); + + if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT) + return PCIBIOS_DEVICE_NOT_FOUND; + + return ar2315_pci_cfg_access(apc, devfn, where, size, &value, true); +} + +static struct pci_ops ar2315_pci_ops = { + .read = ar2315_pci_cfg_read, + .write = ar2315_pci_cfg_write, +}; + +static int ar2315_pci_host_setup(struct ar2315_pci_ctrl *apc) +{ + unsigned devfn = PCI_DEVFN(AR2315_PCI_HOST_SLOT, 0); + int res; + u32 id; + + res = ar2315_pci_local_cfg_rd(apc, devfn, PCI_VENDOR_ID, &id); + if (res != PCIBIOS_SUCCESSFUL || id != AR2315_PCI_HOST_DEVID) + return -ENODEV; + + /* Program MBARs */ + ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_0, + AR2315_PCI_HOST_MBAR0); + ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_1, + AR2315_PCI_HOST_MBAR1); + ar2315_pci_local_cfg_wr(apc, devfn, PCI_BASE_ADDRESS_2, + AR2315_PCI_HOST_MBAR2); + + /* Run */ + ar2315_pci_local_cfg_wr(apc, devfn, PCI_COMMAND, PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL | + PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | + PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK); + + return 0; +} + +static void ar2315_pci_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct ar2315_pci_ctrl *apc = irq_get_handler_data(irq); + u32 pending = ar2315_pci_reg_read(apc, AR2315_PCI_ISR) & + ar2315_pci_reg_read(apc, AR2315_PCI_IMR); + unsigned pci_irq = 0; + + if (pending) + pci_irq = irq_find_mapping(apc->domain, __ffs(pending)); + + if (pci_irq) + generic_handle_irq(pci_irq); + else + spurious_interrupt(); +} + +static void ar2315_pci_irq_mask(struct irq_data *d) +{ + struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d); + + ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, BIT(d->hwirq), 0); +} + +static void ar2315_pci_irq_mask_ack(struct irq_data *d) +{ + struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d); + u32 m = BIT(d->hwirq); + + ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, m, 0); + ar2315_pci_reg_write(apc, AR2315_PCI_ISR, m); +} + +static void ar2315_pci_irq_unmask(struct irq_data *d) +{ + struct ar2315_pci_ctrl *apc = irq_data_get_irq_chip_data(d); + + ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, 0, BIT(d->hwirq)); +} + +static struct irq_chip ar2315_pci_irq_chip = { + .name = "AR2315-PCI", + .irq_mask = ar2315_pci_irq_mask, + .irq_mask_ack = ar2315_pci_irq_mask_ack, + .irq_unmask = ar2315_pci_irq_unmask, +}; + +static int ar2315_pci_irq_map(struct irq_domain *d, unsigned irq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &ar2315_pci_irq_chip, handle_level_irq); + irq_set_chip_data(irq, d->host_data); + return 0; +} + +static struct irq_domain_ops ar2315_pci_irq_domain_ops = { + .map = ar2315_pci_irq_map, +}; + +static void ar2315_pci_irq_init(struct ar2315_pci_ctrl *apc) +{ + ar2315_pci_reg_mask(apc, AR2315_PCI_IER, AR2315_PCI_IER_ENABLE, 0); + ar2315_pci_reg_mask(apc, AR2315_PCI_IMR, (AR2315_PCI_INT_ABORT | + AR2315_PCI_INT_EXT), 0); + + apc->irq_ext = irq_create_mapping(apc->domain, AR2315_PCI_IRQ_EXT); + + irq_set_chained_handler(apc->irq, ar2315_pci_irq_handler); + irq_set_handler_data(apc->irq, apc); + + /* Clear any pending Abort or external Interrupts + * and enable interrupt processing */ + ar2315_pci_reg_write(apc, AR2315_PCI_ISR, AR2315_PCI_INT_ABORT | + AR2315_PCI_INT_EXT); + ar2315_pci_reg_mask(apc, AR2315_PCI_IER, 0, AR2315_PCI_IER_ENABLE); +} + +static int ar2315_pci_probe(struct platform_device *pdev) +{ + struct ar2315_pci_ctrl *apc; + struct device *dev = &pdev->dev; + struct resource *res; + int irq, err; + + apc = devm_kzalloc(dev, sizeof(*apc), GFP_KERNEL); + if (!apc) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + apc->irq = irq; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "ar2315-pci-ctrl"); + apc->mmr_mem = devm_ioremap_resource(dev, res); + if (IS_ERR(apc->mmr_mem)) + return PTR_ERR(apc->mmr_mem); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "ar2315-pci-ext"); + if (!res) + return -EINVAL; + + apc->mem_res.name = "AR2315 PCI mem space"; + apc->mem_res.parent = res; + apc->mem_res.start = res->start; + apc->mem_res.end = res->end; + apc->mem_res.flags = IORESOURCE_MEM; + + /* Remap PCI config space */ + apc->cfg_mem = devm_ioremap_nocache(dev, res->start, + AR2315_PCI_CFG_SIZE); + if (!apc->cfg_mem) { + dev_err(dev, "failed to remap PCI config space\n"); + return -ENOMEM; + } + + /* Reset the PCI bus by setting bits 5-4 in PCI_MCFG */ + ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG, + AR2315_PCIMISC_RST_MODE, + AR2315_PCIRST_LOW); + msleep(100); + + /* Bring the PCI out of reset */ + ar2315_pci_reg_mask(apc, AR2315_PCI_MISC_CONFIG, + AR2315_PCIMISC_RST_MODE, + AR2315_PCIRST_HIGH | AR2315_PCICACHE_DIS | 0x8); + + ar2315_pci_reg_write(apc, AR2315_PCI_UNCACHE_CFG, + 0x1E | /* 1GB uncached */ + (1 << 5) | /* Enable uncached */ + (0x2 << 30) /* Base: 0x80000000 */); + ar2315_pci_reg_read(apc, AR2315_PCI_UNCACHE_CFG); + + msleep(500); + + err = ar2315_pci_host_setup(apc); + if (err) + return err; + + apc->domain = irq_domain_add_linear(NULL, AR2315_PCI_IRQ_COUNT, + &ar2315_pci_irq_domain_ops, apc); + if (!apc->domain) { + dev_err(dev, "failed to add IRQ domain\n"); + return -ENOMEM; + } + + ar2315_pci_irq_init(apc); + + /* PCI controller does not support I/O ports */ + apc->io_res.name = "AR2315 IO space"; + apc->io_res.start = 0; + apc->io_res.end = 0; + apc->io_res.flags = IORESOURCE_IO, + + apc->pci_ctrl.pci_ops = &ar2315_pci_ops; + apc->pci_ctrl.mem_resource = &apc->mem_res, + apc->pci_ctrl.io_resource = &apc->io_res, + + register_pci_controller(&apc->pci_ctrl); + + dev_info(dev, "register PCI controller\n"); + + return 0; +} + +static struct platform_driver ar2315_pci_driver = { + .probe = ar2315_pci_probe, + .driver = { + .name = "ar2315-pci", + .owner = THIS_MODULE, + }, +}; + +static int __init ar2315_pci_init(void) +{ + return platform_driver_register(&ar2315_pci_driver); +} +arch_initcall(ar2315_pci_init); + +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + struct ar2315_pci_ctrl *apc = ar2315_pci_bus_to_apc(dev->bus); + + return slot ? 0 : apc->irq_ext; +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index d471a26..2b534ae 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -50,7 +50,6 @@ struct ar71xx_pci_controller { void __iomem *cfg_base; - spinlock_t lock; int irq; int irq_base; struct pci_controller pci_ctrl; @@ -182,7 +181,6 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, { struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); void __iomem *base = apc->cfg_base; - unsigned long flags; u32 data; int err; int ret; @@ -190,8 +188,6 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, ret = PCIBIOS_SUCCESSFUL; data = ~0; - spin_lock_irqsave(&apc->lock, flags); - err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, AR71XX_PCI_CFG_CMD_READ); if (err) @@ -199,8 +195,6 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, else data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA); - spin_unlock_irqrestore(&apc->lock, flags); - *value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7]; return ret; @@ -211,15 +205,12 @@ static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, { struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); void __iomem *base = apc->cfg_base; - unsigned long flags; int err; int ret; value = value << (8 * (where & 3)); ret = PCIBIOS_SUCCESSFUL; - spin_lock_irqsave(&apc->lock, flags); - err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, AR71XX_PCI_CFG_CMD_WRITE); if (err) @@ -227,8 +218,6 @@ static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, else __raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA); - spin_unlock_irqrestore(&apc->lock, flags); - return ret; } @@ -360,8 +349,6 @@ static int ar71xx_pci_probe(struct platform_device *pdev) if (!apc) return -ENOMEM; - spin_lock_init(&apc->lock); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); apc->cfg_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(apc->cfg_base)) diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 785b265..b7a6fcb 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -9,7 +9,6 @@ * by the Free Software Foundation. */ -#include <linux/spinlock.h> #include <linux/irq.h> #include <linux/pci.h> #include <linux/module.h> @@ -48,8 +47,6 @@ struct ar724x_pci_controller { bool bar0_is_cached; u32 bar0_value; - spinlock_t lock; - struct pci_controller pci_controller; struct resource io_res; struct resource mem_res; @@ -75,7 +72,6 @@ pci_bus_to_ar724x_controller(struct pci_bus *bus) static int ar724x_pci_local_write(struct ar724x_pci_controller *apc, int where, int size, u32 value) { - unsigned long flags; void __iomem *base; u32 data; int s; @@ -86,8 +82,6 @@ static int ar724x_pci_local_write(struct ar724x_pci_controller *apc, return PCIBIOS_DEVICE_NOT_FOUND; base = apc->crp_base; - - spin_lock_irqsave(&apc->lock, flags); data = __raw_readl(base + (where & ~3)); switch (size) { @@ -105,14 +99,12 @@ static int ar724x_pci_local_write(struct ar724x_pci_controller *apc, data = value; break; default: - spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_BAD_REGISTER_NUMBER; } __raw_writel(data, base + (where & ~3)); /* flush write */ __raw_readl(base + (where & ~3)); - spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_SUCCESSFUL; } @@ -121,7 +113,6 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, uint32_t *value) { struct ar724x_pci_controller *apc; - unsigned long flags; void __iomem *base; u32 data; @@ -133,8 +124,6 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, return PCIBIOS_DEVICE_NOT_FOUND; base = apc->devcfg_base; - - spin_lock_irqsave(&apc->lock, flags); data = __raw_readl(base + (where & ~3)); switch (size) { @@ -153,13 +142,9 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, case 4: break; default: - spin_unlock_irqrestore(&apc->lock, flags); - return PCIBIOS_BAD_REGISTER_NUMBER; } - spin_unlock_irqrestore(&apc->lock, flags); - if (where == PCI_BASE_ADDRESS_0 && size == 4 && apc->bar0_is_cached) { /* use the cached value */ @@ -175,7 +160,6 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, uint32_t value) { struct ar724x_pci_controller *apc; - unsigned long flags; void __iomem *base; u32 data; int s; @@ -209,8 +193,6 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, } base = apc->devcfg_base; - - spin_lock_irqsave(&apc->lock, flags); data = __raw_readl(base + (where & ~3)); switch (size) { @@ -228,15 +210,12 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, data = value; break; default: - spin_unlock_irqrestore(&apc->lock, flags); - return PCIBIOS_BAD_REGISTER_NUMBER; } __raw_writel(data, base + (where & ~3)); /* flush write */ __raw_readl(base + (where & ~3)); - spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_SUCCESSFUL; } @@ -380,8 +359,6 @@ static int ar724x_pci_probe(struct platform_device *pdev) if (apc->irq < 0) return -EINVAL; - spin_lock_init(&apc->lock); - res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base"); if (!res) return -EINVAL; diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c new file mode 100644 index 0000000..a457494 --- /dev/null +++ b/arch/mips/pci/pci-rt2880.c @@ -0,0 +1,285 @@ +/* + * Ralink RT288x SoC PCI register definitions + * + * Copyright (C) 2009 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> + * + * Parts of this file are based on Ralink's 2.6.21 BSP + * + * 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 <linux/types.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> +#include <linux/of_pci.h> + +#include <asm/mach-ralink/rt288x.h> + +#define RT2880_PCI_BASE 0x00440000 +#define RT288X_CPU_IRQ_PCI 4 + +#define RT2880_PCI_MEM_BASE 0x20000000 +#define RT2880_PCI_MEM_SIZE 0x10000000 +#define RT2880_PCI_IO_BASE 0x00460000 +#define RT2880_PCI_IO_SIZE 0x00010000 + +#define RT2880_PCI_REG_PCICFG_ADDR 0x00 +#define RT2880_PCI_REG_PCIMSK_ADDR 0x0c +#define RT2880_PCI_REG_BAR0SETUP_ADDR 0x10 +#define RT2880_PCI_REG_IMBASEBAR0_ADDR 0x18 +#define RT2880_PCI_REG_CONFIG_ADDR 0x20 +#define RT2880_PCI_REG_CONFIG_DATA 0x24 +#define RT2880_PCI_REG_MEMBASE 0x28 +#define RT2880_PCI_REG_IOBASE 0x2c +#define RT2880_PCI_REG_ID 0x30 +#define RT2880_PCI_REG_CLASS 0x34 +#define RT2880_PCI_REG_SUBID 0x38 +#define RT2880_PCI_REG_ARBCTL 0x80 + +static void __iomem *rt2880_pci_base; +static DEFINE_SPINLOCK(rt2880_pci_lock); + +static u32 rt2880_pci_reg_read(u32 reg) +{ + return readl(rt2880_pci_base + reg); +} + +static void rt2880_pci_reg_write(u32 val, u32 reg) +{ + writel(val, rt2880_pci_base + reg); +} + +static inline u32 rt2880_pci_get_cfgaddr(unsigned int bus, unsigned int slot, + unsigned int func, unsigned int where) +{ + return ((bus << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | + 0x80000000); +} + +static int rt2880_pci_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + unsigned long flags; + u32 address; + u32 data; + + address = rt2880_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where); + + spin_lock_irqsave(&rt2880_pci_lock, flags); + rt2880_pci_reg_write(address, RT2880_PCI_REG_CONFIG_ADDR); + data = rt2880_pci_reg_read(RT2880_PCI_REG_CONFIG_DATA); + spin_unlock_irqrestore(&rt2880_pci_lock, flags); + + switch (size) { + case 1: + *val = (data >> ((where & 3) << 3)) & 0xff; + break; + case 2: + *val = (data >> ((where & 3) << 3)) & 0xffff; + break; + case 4: + *val = data; + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int rt2880_pci_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + unsigned long flags; + u32 address; + u32 data; + + address = rt2880_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where); + + spin_lock_irqsave(&rt2880_pci_lock, flags); + rt2880_pci_reg_write(address, RT2880_PCI_REG_CONFIG_ADDR); + data = rt2880_pci_reg_read(RT2880_PCI_REG_CONFIG_DATA); + + switch (size) { + case 1: + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + break; + case 2: + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + break; + case 4: + data = val; + break; + } + + rt2880_pci_reg_write(data, RT2880_PCI_REG_CONFIG_DATA); + spin_unlock_irqrestore(&rt2880_pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops rt2880_pci_ops = { + .read = rt2880_pci_config_read, + .write = rt2880_pci_config_write, +}; + +static struct resource rt2880_pci_mem_resource = { + .name = "PCI MEM space", + .start = RT2880_PCI_MEM_BASE, + .end = RT2880_PCI_MEM_BASE + RT2880_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource rt2880_pci_io_resource = { + .name = "PCI IO space", + .start = RT2880_PCI_IO_BASE, + .end = RT2880_PCI_IO_BASE + RT2880_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO, +}; + +static struct pci_controller rt2880_pci_controller = { + .pci_ops = &rt2880_pci_ops, + .mem_resource = &rt2880_pci_mem_resource, + .io_resource = &rt2880_pci_io_resource, +}; + +static inline u32 rt2880_pci_read_u32(unsigned long reg) +{ + unsigned long flags; + u32 address; + u32 ret; + + address = rt2880_pci_get_cfgaddr(0, 0, 0, reg); + + spin_lock_irqsave(&rt2880_pci_lock, flags); + rt2880_pci_reg_write(address, RT2880_PCI_REG_CONFIG_ADDR); + ret = rt2880_pci_reg_read(RT2880_PCI_REG_CONFIG_DATA); + spin_unlock_irqrestore(&rt2880_pci_lock, flags); + + return ret; +} + +static inline void rt2880_pci_write_u32(unsigned long reg, u32 val) +{ + unsigned long flags; + u32 address; + + address = rt2880_pci_get_cfgaddr(0, 0, 0, reg); + + spin_lock_irqsave(&rt2880_pci_lock, flags); + rt2880_pci_reg_write(address, RT2880_PCI_REG_CONFIG_ADDR); + rt2880_pci_reg_write(val, RT2880_PCI_REG_CONFIG_DATA); + spin_unlock_irqrestore(&rt2880_pci_lock, flags); +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + u16 cmd; + int irq = -1; + + if (dev->bus->number != 0) + return irq; + + switch (PCI_SLOT(dev->devfn)) { + case 0x00: + rt2880_pci_write_u32(PCI_BASE_ADDRESS_0, 0x08000000); + (void) rt2880_pci_read_u32(PCI_BASE_ADDRESS_0); + break; + case 0x11: + irq = RT288X_CPU_IRQ_PCI; + break; + default: + pr_err("%s:%s[%d] trying to alloc unknown pci irq\n", + __FILE__, __func__, __LINE__); + BUG(); + break; + } + + pci_write_config_byte((struct pci_dev *) dev, + PCI_CACHE_LINE_SIZE, 0x14); + pci_write_config_byte((struct pci_dev *) dev, PCI_LATENCY_TIMER, 0xFF); + pci_read_config_word((struct pci_dev *) dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK | + PCI_COMMAND_SERR | PCI_COMMAND_WAIT | PCI_COMMAND_PARITY; + pci_write_config_word((struct pci_dev *) dev, PCI_COMMAND, cmd); + pci_write_config_byte((struct pci_dev *) dev, PCI_INTERRUPT_LINE, + dev->irq); + return irq; +} + +static int rt288x_pci_probe(struct platform_device *pdev) +{ + void __iomem *io_map_base; + int i; + + rt2880_pci_base = ioremap_nocache(RT2880_PCI_BASE, PAGE_SIZE); + + io_map_base = ioremap(RT2880_PCI_IO_BASE, RT2880_PCI_IO_SIZE); + rt2880_pci_controller.io_map_base = (unsigned long) io_map_base; + set_io_port_base((unsigned long) io_map_base); + + ioport_resource.start = RT2880_PCI_IO_BASE; + ioport_resource.end = RT2880_PCI_IO_BASE + RT2880_PCI_IO_SIZE - 1; + + rt2880_pci_reg_write(0, RT2880_PCI_REG_PCICFG_ADDR); + for (i = 0; i < 0xfffff; i++) + ; + + rt2880_pci_reg_write(0x79, RT2880_PCI_REG_ARBCTL); + rt2880_pci_reg_write(0x07FF0001, RT2880_PCI_REG_BAR0SETUP_ADDR); + rt2880_pci_reg_write(RT2880_PCI_MEM_BASE, RT2880_PCI_REG_MEMBASE); + rt2880_pci_reg_write(RT2880_PCI_IO_BASE, RT2880_PCI_REG_IOBASE); + rt2880_pci_reg_write(0x08000000, RT2880_PCI_REG_IMBASEBAR0_ADDR); + rt2880_pci_reg_write(0x08021814, RT2880_PCI_REG_ID); + rt2880_pci_reg_write(0x00800001, RT2880_PCI_REG_CLASS); + rt2880_pci_reg_write(0x28801814, RT2880_PCI_REG_SUBID); + rt2880_pci_reg_write(0x000c0000, RT2880_PCI_REG_PCIMSK_ADDR); + + rt2880_pci_write_u32(PCI_BASE_ADDRESS_0, 0x08000000); + (void) rt2880_pci_read_u32(PCI_BASE_ADDRESS_0); + + register_pci_controller(&rt2880_pci_controller); + return 0; +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + +static const struct of_device_id rt288x_pci_match[] = { + { .compatible = "ralink,rt288x-pci" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt288x_pci_match); + +static struct platform_driver rt288x_pci_driver = { + .probe = rt288x_pci_probe, + .driver = { + .name = "rt288x-pci", + .owner = THIS_MODULE, + .of_match_table = rt288x_pci_match, + }, +}; + +int __init pcibios_init(void) +{ + int ret = platform_driver_register(&rt288x_pci_driver); + + if (ret) + pr_info("rt288x-pci: Error registering platform driver!"); + + return ret; +} + +arch_initcall(pcibios_init); diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index 72919ae..0bcc0b1 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -61,7 +61,6 @@ struct rt3883_pci_controller { void __iomem *base; - spinlock_t lock; struct device_node *intc_of_node; struct irq_domain *irq_domain; @@ -111,10 +110,8 @@ static u32 rt3883_pci_read_cfg32(struct rt3883_pci_controller *rpc, address = rt3883_pci_get_cfgaddr(bus, slot, func, reg); - spin_lock_irqsave(&rpc->lock, flags); rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); ret = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); - spin_unlock_irqrestore(&rpc->lock, flags); return ret; } @@ -128,10 +125,8 @@ static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc, address = rt3883_pci_get_cfgaddr(bus, slot, func, reg); - spin_lock_irqsave(&rpc->lock, flags); rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA); - spin_unlock_irqrestore(&rpc->lock, flags); } static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) @@ -252,10 +247,8 @@ static int rt3883_pci_config_read(struct pci_bus *bus, unsigned int devfn, address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where); - spin_lock_irqsave(&rpc->lock, flags); rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); - spin_unlock_irqrestore(&rpc->lock, flags); switch (size) { case 1: @@ -288,7 +281,6 @@ static int rt3883_pci_config_write(struct pci_bus *bus, unsigned int devfn, address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where); - spin_lock_irqsave(&rpc->lock, flags); rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); @@ -307,7 +299,6 @@ static int rt3883_pci_config_write(struct pci_bus *bus, unsigned int devfn, } rt3883_pci_w32(rpc, data, RT3883_PCI_REG_CFGDATA); - spin_unlock_irqrestore(&rpc->lock, flags); return PCIBIOS_SUCCESSFUL; } diff --git a/arch/mips/pci/pci-tx4939.c b/arch/mips/pci/pci-tx4939.c index c10fbf2..cd8ed09 100644 --- a/arch/mips/pci/pci-tx4939.c +++ b/arch/mips/pci/pci-tx4939.c @@ -103,5 +103,5 @@ void __init tx4939_setup_pcierr_irq(void) tx4927_pcierr_interrupt, 0, "PCI error", (void *)TX4939_PCIC_REG)) - pr_warning("Failed to request irq for PCIERR\n"); + pr_warn("Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pmcs-msp71xx/msp_prom.c b/arch/mips/pmcs-msp71xx/msp_prom.c index 1c98975..ef620a4 100644 --- a/arch/mips/pmcs-msp71xx/msp_prom.c +++ b/arch/mips/pmcs-msp71xx/msp_prom.c @@ -295,7 +295,7 @@ char *prom_getenv(char *env_name) while (*var) { if (strncmp(env_name, *var, i) == 0) { - return (*var + strlen(env_name) + 1); + return *var + strlen(env_name) + 1; } var++; } diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 77e8a96..b1c52ca 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -16,6 +16,7 @@ choice config SOC_RT288X bool "RT288x" select MIPS_L1_CACHE_SHIFT_4 + select HW_HAS_PCI config SOC_RT305X bool "RT305x" @@ -26,7 +27,7 @@ choice select HW_HAS_PCI config SOC_MT7620 - bool "MT7620" + bool "MT7620/8" endchoice diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile index 2c09c8a..a6c9d00 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -10,9 +10,13 @@ obj-y := prom.o of.o reset.o clk.o irq.o timer.o obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o +obj-$(CONFIG_RALINK_ILL_ACC) += ill_acc.o + obj-$(CONFIG_SOC_RT288X) += rt288x.o obj-$(CONFIG_SOC_RT305X) += rt305x.o obj-$(CONFIG_SOC_RT3883) += rt3883.o obj-$(CONFIG_SOC_MT7620) += mt7620.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +obj-$(CONFIG_DEBUG_FS) += bootrom.o diff --git a/arch/mips/ralink/bootrom.c b/arch/mips/ralink/bootrom.c new file mode 100644 index 0000000..5403468 --- /dev/null +++ b/arch/mips/ralink/bootrom.c @@ -0,0 +1,48 @@ +/* + * 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. + * + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#define BOOTROM_OFFSET 0x10118000 +#define BOOTROM_SIZE 0x8000 + +static void __iomem *membase = (void __iomem *) KSEG1ADDR(BOOTROM_OFFSET); + +static int bootrom_show(struct seq_file *s, void *unused) +{ + seq_write(s, membase, BOOTROM_SIZE); + + return 0; +} + +static int bootrom_open(struct inode *inode, struct file *file) +{ + return single_open(file, bootrom_show, NULL); +} + +static const struct file_operations bootrom_file_ops = { + .open = bootrom_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int bootrom_setup(void) +{ + if (!debugfs_create_file("bootrom", 0444, + NULL, NULL, &bootrom_file_ops)) { + pr_err("Failed to create bootrom debugfs file\n"); + + return -EINVAL; + } + + return 0; +} + +postcore_initcall(bootrom_setup); diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c index 5d0983d..feb5a9b 100644 --- a/arch/mips/ralink/clk.c +++ b/arch/mips/ralink/clk.c @@ -56,6 +56,12 @@ unsigned long clk_get_rate(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_get_rate); +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return -1; +} +EXPORT_SYMBOL_GPL(clk_set_rate); + void __init plat_time_init(void) { struct clk *clk; diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h index 42dfd61..8e7d8e6 100644 --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h @@ -11,25 +11,6 @@ #define RAMIPS_SYS_TYPE_LEN 32 -struct ralink_pinmux_grp { - const char *name; - u32 mask; - int gpio_first; - int gpio_last; -}; - -struct ralink_pinmux { - struct ralink_pinmux_grp *mode; - struct ralink_pinmux_grp *uart; - int uart_shift; - u32 uart_mask; - void (*wdt_reset)(void); - struct ralink_pinmux_grp *pci; - int pci_shift; - u32 pci_mask; -}; -extern struct ralink_pinmux rt_gpio_pinmux; - struct ralink_soc_info { unsigned char sys_type[RAMIPS_SYS_TYPE_LEN]; unsigned char *compatible; diff --git a/arch/mips/ralink/early_printk.c b/arch/mips/ralink/early_printk.c index b46d041..255d695 100644 --- a/arch/mips/ralink/early_printk.c +++ b/arch/mips/ralink/early_printk.c @@ -12,21 +12,24 @@ #include <asm/addrspace.h> #ifdef CONFIG_SOC_RT288X -#define EARLY_UART_BASE 0x300c00 +#define EARLY_UART_BASE 0x300c00 +#define CHIPID_BASE 0x300004 +#elif defined(CONFIG_SOC_MT7621) +#define EARLY_UART_BASE 0x1E000c00 +#define CHIPID_BASE 0x1E000004 #else -#define EARLY_UART_BASE 0x10000c00 +#define EARLY_UART_BASE 0x10000c00 +#define CHIPID_BASE 0x10000004 #endif -#define UART_REG_RX 0x00 -#define UART_REG_TX 0x04 -#define UART_REG_IER 0x08 -#define UART_REG_IIR 0x0c -#define UART_REG_FCR 0x10 -#define UART_REG_LCR 0x14 -#define UART_REG_MCR 0x18 -#define UART_REG_LSR 0x1c +#define MT7628_CHIP_NAME1 0x20203832 + +#define UART_REG_TX 0x04 +#define UART_REG_LSR 0x14 +#define UART_REG_LSR_RT2880 0x1c static __iomem void *uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE); +static __iomem void *chipid_membase = (__iomem void *) KSEG1ADDR(CHIPID_BASE); static inline void uart_w32(u32 val, unsigned reg) { @@ -38,11 +41,23 @@ static inline u32 uart_r32(unsigned reg) return __raw_readl(uart_membase + reg); } +static inline int soc_is_mt7628(void) +{ + return IS_ENABLED(CONFIG_SOC_MT7620) && + (__raw_readl(chipid_membase) == MT7628_CHIP_NAME1); +} + void prom_putchar(unsigned char ch) { - while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0) - ; - uart_w32(ch, UART_REG_TX); - while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0) - ; + if (IS_ENABLED(CONFIG_SOC_MT7621) || soc_is_mt7628()) { + uart_w32(ch, UART_TX); + while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0) + ; + } else { + while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0) + ; + uart_w32(ch, UART_REG_TX); + while ((uart_r32(UART_REG_LSR_RT2880) & UART_LSR_THRE) == 0) + ; + } } diff --git a/arch/mips/ralink/ill_acc.c b/arch/mips/ralink/ill_acc.c new file mode 100644 index 0000000..e20b02e --- /dev/null +++ b/arch/mips/ralink/ill_acc.c @@ -0,0 +1,87 @@ +/* + * 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. + * + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/interrupt.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> + +#include <asm/mach-ralink/ralink_regs.h> + +#define REG_ILL_ACC_ADDR 0x10 +#define REG_ILL_ACC_TYPE 0x14 + +#define ILL_INT_STATUS BIT(31) +#define ILL_ACC_WRITE BIT(30) +#define ILL_ACC_LEN_M 0xff +#define ILL_ACC_OFF_M 0xf +#define ILL_ACC_OFF_S 16 +#define ILL_ACC_ID_M 0x7 +#define ILL_ACC_ID_S 8 + +#define DRV_NAME "ill_acc" + +static const char * const ill_acc_ids[] = { + "cpu", "dma", "ppe", "pdma rx", "pdma tx", "pci/e", "wmac", "usb", +}; + +static irqreturn_t ill_acc_irq_handler(int irq, void *_priv) +{ + struct device *dev = (struct device *) _priv; + u32 addr = rt_memc_r32(REG_ILL_ACC_ADDR); + u32 type = rt_memc_r32(REG_ILL_ACC_TYPE); + + dev_err(dev, "illegal %s access from %s - addr:0x%08x offset:%d len:%d\n", + (type & ILL_ACC_WRITE) ? ("write") : ("read"), + ill_acc_ids[(type >> ILL_ACC_ID_S) & ILL_ACC_ID_M], + addr, (type >> ILL_ACC_OFF_S) & ILL_ACC_OFF_M, + type & ILL_ACC_LEN_M); + + rt_memc_w32(REG_ILL_ACC_TYPE, REG_ILL_ACC_TYPE); + + return IRQ_HANDLED; +} + +static int __init ill_acc_of_setup(void) +{ + struct platform_device *pdev; + struct device_node *np; + int irq; + + /* somehow this driver breaks on RT5350 */ + if (of_machine_is_compatible("ralink,rt5350-soc")) + return -EINVAL; + + np = of_find_compatible_node(NULL, NULL, "ralink,rt3050-memc"); + if (!np) + return -EINVAL; + + pdev = of_find_device_by_node(np); + if (!pdev) { + pr_err("%s: failed to lookup pdev\n", np->name); + return -EINVAL; + } + + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + dev_err(&pdev->dev, "failed to get irq\n"); + return -EINVAL; + } + + if (request_irq(irq, ill_acc_irq_handler, 0, "ill_acc", &pdev->dev)) { + dev_err(&pdev->dev, "failed to request irq\n"); + return -EINVAL; + } + + rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); + + dev_info(&pdev->dev, "irq registered\n"); + + return 0; +} + +arch_initcall(ill_acc_of_setup); diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c index 781b3d1..7cf91b9 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c @@ -20,14 +20,6 @@ #include "common.h" -/* INTC register offsets */ -#define INTC_REG_STATUS0 0x00 -#define INTC_REG_STATUS1 0x04 -#define INTC_REG_TYPE 0x20 -#define INTC_REG_RAW_STATUS 0x30 -#define INTC_REG_ENABLE 0x34 -#define INTC_REG_DISABLE 0x38 - #define INTC_INT_GLOBAL BIT(31) #define RALINK_CPU_IRQ_INTC (MIPS_CPU_IRQ_BASE + 2) @@ -44,16 +36,36 @@ #define RALINK_INTC_IRQ_PERFC (RALINK_INTC_IRQ_BASE + 9) +enum rt_intc_regs_enum { + INTC_REG_STATUS0 = 0, + INTC_REG_STATUS1, + INTC_REG_TYPE, + INTC_REG_RAW_STATUS, + INTC_REG_ENABLE, + INTC_REG_DISABLE, +}; + +static u32 rt_intc_regs[] = { + [INTC_REG_STATUS0] = 0x00, + [INTC_REG_STATUS1] = 0x04, + [INTC_REG_TYPE] = 0x20, + [INTC_REG_RAW_STATUS] = 0x30, + [INTC_REG_ENABLE] = 0x34, + [INTC_REG_DISABLE] = 0x38, +}; + static void __iomem *rt_intc_membase; +static int rt_perfcount_irq; + static inline void rt_intc_w32(u32 val, unsigned reg) { - __raw_writel(val, rt_intc_membase + reg); + __raw_writel(val, rt_intc_membase + rt_intc_regs[reg]); } static inline u32 rt_intc_r32(unsigned reg) { - return __raw_readl(rt_intc_membase + reg); + return __raw_readl(rt_intc_membase + rt_intc_regs[reg]); } static void ralink_intc_irq_unmask(struct irq_data *d) @@ -73,6 +85,11 @@ static struct irq_chip ralink_intc_irq_chip = { .irq_mask_ack = ralink_intc_irq_mask, }; +int get_c0_perfcount_int(void) +{ + return rt_perfcount_irq; +} + unsigned int get_c0_compare_int(void) { return CP0_LEGACY_COMPARE_IRQ; @@ -134,6 +151,10 @@ static int __init intc_of_init(struct device_node *node, struct irq_domain *domain; int irq; + if (!of_property_read_u32_array(node, "ralink,intc-registers", + rt_intc_regs, 6)) + pr_info("intc: using register map from devicetree\n"); + irq = irq_of_parse_and_map(node, 0); if (!irq) panic("Failed to get INTC IRQ"); @@ -167,13 +188,13 @@ static int __init intc_of_init(struct device_node *node, irq_set_handler_data(irq, domain); /* tell the kernel which irq is used for performance monitoring */ - cp0_perfcount_irq = irq_create_mapping(domain, 9); + rt_perfcount_irq = irq_create_mapping(domain, 9); return 0; } static struct of_device_id __initdata of_irq_ids[] = { - { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_intc_init }, + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, {}, }; diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c index a3ad56c..2ea5ff6 100644 --- a/arch/mips/ralink/mt7620.c +++ b/arch/mips/ralink/mt7620.c @@ -17,124 +17,214 @@ #include <asm/mipsregs.h> #include <asm/mach-ralink/ralink_regs.h> #include <asm/mach-ralink/mt7620.h> +#include <asm/mach-ralink/pinmux.h> #include "common.h" +/* analog */ +#define PMU0_CFG 0x88 +#define PMU_SW_SET BIT(28) +#define A_DCDC_EN BIT(24) +#define A_SSC_PERI BIT(19) +#define A_SSC_GEN BIT(18) +#define A_SSC_M 0x3 +#define A_SSC_S 16 +#define A_DLY_M 0x7 +#define A_DLY_S 8 +#define A_VTUNE_M 0xff + +/* digital */ +#define PMU1_CFG 0x8C +#define DIG_SW_SEL BIT(25) + +/* is this a MT7620 or a MT7628 */ +enum mt762x_soc_type mt762x_soc; + /* does the board have sdram or ddram */ static int dram_type; -static struct ralink_pinmux_grp mode_mux[] = { - { - .name = "i2c", - .mask = MT7620_GPIO_MODE_I2C, - .gpio_first = 1, - .gpio_last = 2, - }, { - .name = "spi", - .mask = MT7620_GPIO_MODE_SPI, - .gpio_first = 3, - .gpio_last = 6, - }, { - .name = "uartlite", - .mask = MT7620_GPIO_MODE_UART1, - .gpio_first = 15, - .gpio_last = 16, - }, { - .name = "wdt", - .mask = MT7620_GPIO_MODE_WDT, - .gpio_first = 17, - .gpio_last = 17, - }, { - .name = "mdio", - .mask = MT7620_GPIO_MODE_MDIO, - .gpio_first = 22, - .gpio_last = 23, - }, { - .name = "rgmii1", - .mask = MT7620_GPIO_MODE_RGMII1, - .gpio_first = 24, - .gpio_last = 35, - }, { - .name = "spi refclk", - .mask = MT7620_GPIO_MODE_SPI_REF_CLK, - .gpio_first = 37, - .gpio_last = 39, - }, { - .name = "jtag", - .mask = MT7620_GPIO_MODE_JTAG, - .gpio_first = 40, - .gpio_last = 44, - }, { - /* shared lines with jtag */ - .name = "ephy", - .mask = MT7620_GPIO_MODE_EPHY, - .gpio_first = 40, - .gpio_last = 44, - }, { - .name = "nand", - .mask = MT7620_GPIO_MODE_JTAG, - .gpio_first = 45, - .gpio_last = 59, - }, { - .name = "rgmii2", - .mask = MT7620_GPIO_MODE_RGMII2, - .gpio_first = 60, - .gpio_last = 71, - }, { - .name = "wled", - .mask = MT7620_GPIO_MODE_WLED, - .gpio_first = 72, - .gpio_last = 72, - }, {0} +static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) }; +static struct rt2880_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) }; +static struct rt2880_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) }; +static struct rt2880_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) }; +static struct rt2880_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) }; +static struct rt2880_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) }; +static struct rt2880_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 60, 12) }; +static struct rt2880_pmx_func wled_grp[] = { FUNC("wled", 0, 72, 1) }; +static struct rt2880_pmx_func pa_grp[] = { FUNC("pa", 0, 18, 4) }; +static struct rt2880_pmx_func uartf_grp[] = { + FUNC("uartf", MT7620_GPIO_MODE_UARTF, 7, 8), + FUNC("pcm uartf", MT7620_GPIO_MODE_PCM_UARTF, 7, 8), + FUNC("pcm i2s", MT7620_GPIO_MODE_PCM_I2S, 7, 8), + FUNC("i2s uartf", MT7620_GPIO_MODE_I2S_UARTF, 7, 8), + FUNC("pcm gpio", MT7620_GPIO_MODE_PCM_GPIO, 11, 4), + FUNC("gpio uartf", MT7620_GPIO_MODE_GPIO_UARTF, 7, 4), + FUNC("gpio i2s", MT7620_GPIO_MODE_GPIO_I2S, 7, 4), +}; +static struct rt2880_pmx_func wdt_grp[] = { + FUNC("wdt rst", 0, 17, 1), + FUNC("wdt refclk", 0, 17, 1), + }; +static struct rt2880_pmx_func pcie_rst_grp[] = { + FUNC("pcie rst", MT7620_GPIO_MODE_PCIE_RST, 36, 1), + FUNC("pcie refclk", MT7620_GPIO_MODE_PCIE_REF, 36, 1) +}; +static struct rt2880_pmx_func nd_sd_grp[] = { + FUNC("nand", MT7620_GPIO_MODE_NAND, 45, 15), + FUNC("sd", MT7620_GPIO_MODE_SD, 45, 15) +}; + +static struct rt2880_pmx_group mt7620a_pinmux_data[] = { + GRP("i2c", i2c_grp, 1, MT7620_GPIO_MODE_I2C), + GRP("uartf", uartf_grp, MT7620_GPIO_MODE_UART0_MASK, + MT7620_GPIO_MODE_UART0_SHIFT), + GRP("spi", spi_grp, 1, MT7620_GPIO_MODE_SPI), + GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1), + GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK, + MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT), + GRP("mdio", mdio_grp, 1, MT7620_GPIO_MODE_MDIO), + GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1), + GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK), + GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK, + MT7620_GPIO_MODE_PCIE_GPIO, MT7620_GPIO_MODE_PCIE_SHIFT), + GRP_G("nd_sd", nd_sd_grp, MT7620_GPIO_MODE_ND_SD_MASK, + MT7620_GPIO_MODE_ND_SD_GPIO, MT7620_GPIO_MODE_ND_SD_SHIFT), + GRP("rgmii2", rgmii2_grp, 1, MT7620_GPIO_MODE_RGMII2), + GRP("wled", wled_grp, 1, MT7620_GPIO_MODE_WLED), + GRP("ephy", ephy_grp, 1, MT7620_GPIO_MODE_EPHY), + GRP("pa", pa_grp, 1, MT7620_GPIO_MODE_PA), + { 0 } +}; + +static struct rt2880_pmx_func pwm1_grp_mt7628[] = { + FUNC("sdcx", 3, 19, 1), + FUNC("utif", 2, 19, 1), + FUNC("gpio", 1, 19, 1), + FUNC("pwm", 0, 19, 1), +}; + +static struct rt2880_pmx_func pwm0_grp_mt7628[] = { + FUNC("sdcx", 3, 18, 1), + FUNC("utif", 2, 18, 1), + FUNC("gpio", 1, 18, 1), + FUNC("pwm", 0, 18, 1), +}; + +static struct rt2880_pmx_func uart2_grp_mt7628[] = { + FUNC("sdcx", 3, 20, 2), + FUNC("pwm", 2, 20, 2), + FUNC("gpio", 1, 20, 2), + FUNC("uart", 0, 20, 2), +}; + +static struct rt2880_pmx_func uart1_grp_mt7628[] = { + FUNC("sdcx", 3, 45, 2), + FUNC("pwm", 2, 45, 2), + FUNC("gpio", 1, 45, 2), + FUNC("uart", 0, 45, 2), +}; + +static struct rt2880_pmx_func i2c_grp_mt7628[] = { + FUNC("-", 3, 4, 2), + FUNC("debug", 2, 4, 2), + FUNC("gpio", 1, 4, 2), + FUNC("i2c", 0, 4, 2), +}; + +static struct rt2880_pmx_func refclk_grp_mt7628[] = { FUNC("reclk", 0, 36, 1) }; +static struct rt2880_pmx_func perst_grp_mt7628[] = { FUNC("perst", 0, 37, 1) }; +static struct rt2880_pmx_func wdt_grp_mt7628[] = { FUNC("wdt", 0, 15, 38) }; +static struct rt2880_pmx_func spi_grp_mt7628[] = { FUNC("spi", 0, 7, 4) }; + +static struct rt2880_pmx_func sd_mode_grp_mt7628[] = { + FUNC("jtag", 3, 22, 8), + FUNC("utif", 2, 22, 8), + FUNC("gpio", 1, 22, 8), + FUNC("sdcx", 0, 22, 8), +}; + +static struct rt2880_pmx_func uart0_grp_mt7628[] = { + FUNC("-", 3, 12, 2), + FUNC("-", 2, 12, 2), + FUNC("gpio", 1, 12, 2), + FUNC("uart", 0, 12, 2), +}; + +static struct rt2880_pmx_func i2s_grp_mt7628[] = { + FUNC("antenna", 3, 0, 4), + FUNC("pcm", 2, 0, 4), + FUNC("gpio", 1, 0, 4), + FUNC("i2s", 0, 0, 4), +}; + +static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = { + FUNC("-", 3, 6, 1), + FUNC("refclk", 2, 6, 1), + FUNC("gpio", 1, 6, 1), + FUNC("spi", 0, 6, 1), +}; + +static struct rt2880_pmx_func spis_grp_mt7628[] = { + FUNC("pwm", 3, 14, 4), + FUNC("util", 2, 14, 4), + FUNC("gpio", 1, 14, 4), + FUNC("spis", 0, 14, 4), }; -static struct ralink_pinmux_grp uart_mux[] = { - { - .name = "uartf", - .mask = MT7620_GPIO_MODE_UARTF, - .gpio_first = 7, - .gpio_last = 14, - }, { - .name = "pcm uartf", - .mask = MT7620_GPIO_MODE_PCM_UARTF, - .gpio_first = 7, - .gpio_last = 14, - }, { - .name = "pcm i2s", - .mask = MT7620_GPIO_MODE_PCM_I2S, - .gpio_first = 7, - .gpio_last = 14, - }, { - .name = "i2s uartf", - .mask = MT7620_GPIO_MODE_I2S_UARTF, - .gpio_first = 7, - .gpio_last = 14, - }, { - .name = "pcm gpio", - .mask = MT7620_GPIO_MODE_PCM_GPIO, - .gpio_first = 11, - .gpio_last = 14, - }, { - .name = "gpio uartf", - .mask = MT7620_GPIO_MODE_GPIO_UARTF, - .gpio_first = 7, - .gpio_last = 10, - }, { - .name = "gpio i2s", - .mask = MT7620_GPIO_MODE_GPIO_I2S, - .gpio_first = 7, - .gpio_last = 10, - }, { - .name = "gpio", - .mask = MT7620_GPIO_MODE_GPIO, - }, {0} +static struct rt2880_pmx_func gpio_grp_mt7628[] = { + FUNC("pcie", 3, 11, 1), + FUNC("refclk", 2, 11, 1), + FUNC("gpio", 1, 11, 1), + FUNC("gpio", 0, 11, 1), }; -struct ralink_pinmux rt_gpio_pinmux = { - .mode = mode_mux, - .uart = uart_mux, - .uart_shift = MT7620_GPIO_MODE_UART0_SHIFT, - .uart_mask = MT7620_GPIO_MODE_UART0_MASK, +#define MT7628_GPIO_MODE_MASK 0x3 + +#define MT7628_GPIO_MODE_PWM1 30 +#define MT7628_GPIO_MODE_PWM0 28 +#define MT7628_GPIO_MODE_UART2 26 +#define MT7628_GPIO_MODE_UART1 24 +#define MT7628_GPIO_MODE_I2C 20 +#define MT7628_GPIO_MODE_REFCLK 18 +#define MT7628_GPIO_MODE_PERST 16 +#define MT7628_GPIO_MODE_WDT 14 +#define MT7628_GPIO_MODE_SPI 12 +#define MT7628_GPIO_MODE_SDMODE 10 +#define MT7628_GPIO_MODE_UART0 8 +#define MT7628_GPIO_MODE_I2S 6 +#define MT7628_GPIO_MODE_CS1 4 +#define MT7628_GPIO_MODE_SPIS 2 +#define MT7628_GPIO_MODE_GPIO 0 + +static struct rt2880_pmx_group mt7628an_pinmux_data[] = { + GRP_G("pmw1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_PWM1), + GRP_G("pmw1", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_PWM0), + GRP_G("uart2", uart2_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_UART2), + GRP_G("uart1", uart1_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_UART1), + GRP_G("i2c", i2c_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_I2C), + GRP("refclk", refclk_grp_mt7628, 1, MT7628_GPIO_MODE_REFCLK), + GRP("perst", perst_grp_mt7628, 1, MT7628_GPIO_MODE_PERST), + GRP("wdt", wdt_grp_mt7628, 1, MT7628_GPIO_MODE_WDT), + GRP("spi", spi_grp_mt7628, 1, MT7628_GPIO_MODE_SPI), + GRP_G("sdmode", sd_mode_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_SDMODE), + GRP_G("uart0", uart0_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_UART0), + GRP_G("i2s", i2s_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_I2S), + GRP_G("spi cs1", spi_cs1_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_CS1), + GRP_G("spis", spis_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_SPIS), + GRP_G("gpio", gpio_grp_mt7628, MT7628_GPIO_MODE_MASK, + 1, MT7628_GPIO_MODE_GPIO), + { 0 } }; static __init u32 @@ -287,29 +377,42 @@ void __init ralink_clk_init(void) xtal_rate = mt7620_get_xtal_rate(); - cpu_pll_rate = mt7620_get_cpu_pll_rate(xtal_rate); - pll_rate = mt7620_get_pll_rate(xtal_rate, cpu_pll_rate); - - cpu_rate = mt7620_get_cpu_rate(pll_rate); - dram_rate = mt7620_get_dram_rate(pll_rate); - sys_rate = mt7620_get_sys_rate(cpu_rate); - periph_rate = mt7620_get_periph_rate(xtal_rate); - #define RFMT(label) label ":%lu.%03luMHz " #define RINT(x) ((x) / 1000000) #define RFRAC(x) (((x) / 1000) % 1000) - pr_debug(RFMT("XTAL") RFMT("CPU_PLL") RFMT("PLL"), - RINT(xtal_rate), RFRAC(xtal_rate), - RINT(cpu_pll_rate), RFRAC(cpu_pll_rate), - RINT(pll_rate), RFRAC(pll_rate)); + if (mt762x_soc == MT762X_SOC_MT7628AN) { + if (xtal_rate == MHZ(40)) + cpu_rate = MHZ(580); + else + cpu_rate = MHZ(575); + dram_rate = sys_rate = cpu_rate / 3; + periph_rate = MHZ(40); + + ralink_clk_add("10000d00.uartlite", periph_rate); + ralink_clk_add("10000e00.uartlite", periph_rate); + } else { + cpu_pll_rate = mt7620_get_cpu_pll_rate(xtal_rate); + pll_rate = mt7620_get_pll_rate(xtal_rate, cpu_pll_rate); + + cpu_rate = mt7620_get_cpu_rate(pll_rate); + dram_rate = mt7620_get_dram_rate(pll_rate); + sys_rate = mt7620_get_sys_rate(cpu_rate); + periph_rate = mt7620_get_periph_rate(xtal_rate); + + pr_debug(RFMT("XTAL") RFMT("CPU_PLL") RFMT("PLL"), + RINT(xtal_rate), RFRAC(xtal_rate), + RINT(cpu_pll_rate), RFRAC(cpu_pll_rate), + RINT(pll_rate), RFRAC(pll_rate)); + + ralink_clk_add("10000500.uart", periph_rate); + } pr_debug(RFMT("CPU") RFMT("DRAM") RFMT("SYS") RFMT("PERIPH"), RINT(cpu_rate), RFRAC(cpu_rate), RINT(dram_rate), RFRAC(dram_rate), RINT(sys_rate), RFRAC(sys_rate), RINT(periph_rate), RFRAC(periph_rate)); - #undef RFRAC #undef RINT #undef RFMT @@ -317,9 +420,9 @@ void __init ralink_clk_init(void) ralink_clk_add("cpu", cpu_rate); ralink_clk_add("10000100.timer", periph_rate); ralink_clk_add("10000120.watchdog", periph_rate); - ralink_clk_add("10000500.uart", periph_rate); ralink_clk_add("10000b00.spi", sys_rate); ralink_clk_add("10000c00.uartlite", periph_rate); + ralink_clk_add("10180000.wmac", xtal_rate); } void __init ralink_of_remap(void) @@ -331,6 +434,52 @@ void __init ralink_of_remap(void) panic("Failed to remap core resources"); } +static __init void +mt7620_dram_init(struct ralink_soc_info *soc_info) +{ + switch (dram_type) { + case SYSCFG0_DRAM_TYPE_SDRAM: + pr_info("Board has SDRAM\n"); + soc_info->mem_size_min = MT7620_SDRAM_SIZE_MIN; + soc_info->mem_size_max = MT7620_SDRAM_SIZE_MAX; + break; + + case SYSCFG0_DRAM_TYPE_DDR1: + pr_info("Board has DDR1\n"); + soc_info->mem_size_min = MT7620_DDR1_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR1_SIZE_MAX; + break; + + case SYSCFG0_DRAM_TYPE_DDR2: + pr_info("Board has DDR2\n"); + soc_info->mem_size_min = MT7620_DDR2_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR2_SIZE_MAX; + break; + default: + BUG(); + } +} + +static __init void +mt7628_dram_init(struct ralink_soc_info *soc_info) +{ + switch (dram_type) { + case SYSCFG0_DRAM_TYPE_DDR1_MT7628: + pr_info("Board has DDR1\n"); + soc_info->mem_size_min = MT7620_DDR1_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR1_SIZE_MAX; + break; + + case SYSCFG0_DRAM_TYPE_DDR2_MT7628: + pr_info("Board has DDR2\n"); + soc_info->mem_size_min = MT7620_DDR2_SIZE_MIN; + soc_info->mem_size_max = MT7620_DDR2_SIZE_MAX; + break; + default: + BUG(); + } +} + void prom_soc_init(struct ralink_soc_info *soc_info) { void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7620_SYSC_BASE); @@ -339,22 +488,36 @@ void prom_soc_init(struct ralink_soc_info *soc_info) u32 n1; u32 rev; u32 cfg0; + u32 pmu0; + u32 pmu1; + u32 bga; n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0); n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1); - - if (n0 == MT7620N_CHIP_NAME0 && n1 == MT7620N_CHIP_NAME1) { - name = "MT7620N"; - soc_info->compatible = "ralink,mt7620n-soc"; - } else if (n0 == MT7620A_CHIP_NAME0 && n1 == MT7620A_CHIP_NAME1) { - name = "MT7620A"; - soc_info->compatible = "ralink,mt7620a-soc"; + rev = __raw_readl(sysc + SYSC_REG_CHIP_REV); + bga = (rev >> CHIP_REV_PKG_SHIFT) & CHIP_REV_PKG_MASK; + + if (n0 == MT7620_CHIP_NAME0 && n1 == MT7620_CHIP_NAME1) { + if (bga) { + mt762x_soc = MT762X_SOC_MT7620A; + name = "MT7620A"; + soc_info->compatible = "ralink,mt7620a-soc"; + } else { + mt762x_soc = MT762X_SOC_MT7620N; + name = "MT7620N"; + soc_info->compatible = "ralink,mt7620n-soc"; +#ifdef CONFIG_PCI + panic("mt7620n is only supported for non pci kernels"); +#endif + } + } else if (n0 == MT7620_CHIP_NAME0 && n1 == MT7628_CHIP_NAME1) { + mt762x_soc = MT762X_SOC_MT7628AN; + name = "MT7628AN"; + soc_info->compatible = "ralink,mt7628an-soc"; } else { - panic("mt7620: unknown SoC, n0:%08x n1:%08x", n0, n1); + panic("mt762x: unknown SoC, n0:%08x n1:%08x\n", n0, n1); } - rev = __raw_readl(sysc + SYSC_REG_CHIP_REV); - snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN, "Ralink %s ver:%u eco:%u", name, @@ -364,26 +527,22 @@ void prom_soc_init(struct ralink_soc_info *soc_info) cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0); dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) & SYSCFG0_DRAM_TYPE_MASK; - switch (dram_type) { - case SYSCFG0_DRAM_TYPE_SDRAM: - pr_info("Board has SDRAM\n"); - soc_info->mem_size_min = MT7620_SDRAM_SIZE_MIN; - soc_info->mem_size_max = MT7620_SDRAM_SIZE_MAX; - break; - - case SYSCFG0_DRAM_TYPE_DDR1: - pr_info("Board has DDR1\n"); - soc_info->mem_size_min = MT7620_DDR1_SIZE_MIN; - soc_info->mem_size_max = MT7620_DDR1_SIZE_MAX; - break; - - case SYSCFG0_DRAM_TYPE_DDR2: - pr_info("Board has DDR2\n"); - soc_info->mem_size_min = MT7620_DDR2_SIZE_MIN; - soc_info->mem_size_max = MT7620_DDR2_SIZE_MAX; - break; - default: - BUG(); - } soc_info->mem_base = MT7620_DRAM_BASE; + if (mt762x_soc == MT762X_SOC_MT7628AN) + mt7628_dram_init(soc_info); + else + mt7620_dram_init(soc_info); + + pmu0 = __raw_readl(sysc + PMU0_CFG); + pmu1 = __raw_readl(sysc + PMU1_CFG); + + pr_info("Analog PMU set to %s control\n", + (pmu0 & PMU_SW_SET) ? ("sw") : ("hw")); + pr_info("Digital PMU set to %s control\n", + (pmu1 & DIG_SW_SEL) ? ("sw") : ("hw")); + + if (mt762x_soc == MT762X_SOC_MT7628AN) + rt2880_pinmux_data = mt7628an_pinmux_data; + else + rt2880_pinmux_data = mt7620a_pinmux_data; } diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c index 7c4598c..0d30dcd 100644 --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c @@ -53,6 +53,17 @@ void __init device_tree_init(void) unflatten_and_copy_device_tree(); } +static int memory_dtb; + +static int __init early_init_dt_find_memory(unsigned long node, + const char *uname, int depth, void *data) +{ + if (depth == 1 && !strcmp(uname, "memory@0")) + memory_dtb = 1; + + return 0; +} + void __init plat_mem_setup(void) { set_io_port_base(KSEG1); @@ -63,7 +74,12 @@ void __init plat_mem_setup(void) */ __dt_setup_arch(__dtb_start); - if (soc_info.mem_size) + strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); + + of_scan_flat_dt(early_init_dt_find_memory, NULL); + if (memory_dtb) + of_scan_flat_dt(early_init_dt_scan_memory, NULL); + else if (soc_info.mem_size) add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M, BOOT_MEM_RAM); else @@ -74,19 +90,9 @@ void __init plat_mem_setup(void) static int __init plat_of_setup(void) { - static struct of_device_id of_ids[3]; - int len = sizeof(of_ids[0].compatible); - - if (!of_have_populated_dt()) - panic("device tree not present"); - - strlcpy(of_ids[0].compatible, soc_info.compatible, len); - strlcpy(of_ids[1].compatible, "palmbus", len); - - if (of_platform_populate(NULL, of_ids, NULL, NULL)) - panic("failed to populate DT"); + __dt_register_buses(soc_info.compatible, "palmbus"); - /* make sure ithat the reset controller is setup early */ + /* make sure that the reset controller is setup early */ ralink_rst_init(); return 0; diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c index 9c64f02..09419f6 100644 --- a/arch/mips/ralink/prom.c +++ b/arch/mips/ralink/prom.c @@ -18,6 +18,7 @@ #include "common.h" struct ralink_soc_info soc_info; +struct rt2880_pmx_group *rt2880_pinmux_data = NULL; const char *get_system_type(void) { diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c index f87de1a..738cec8 100644 --- a/arch/mips/ralink/rt288x.c +++ b/arch/mips/ralink/rt288x.c @@ -17,46 +17,27 @@ #include <asm/mipsregs.h> #include <asm/mach-ralink/ralink_regs.h> #include <asm/mach-ralink/rt288x.h> +#include <asm/mach-ralink/pinmux.h> #include "common.h" -static struct ralink_pinmux_grp mode_mux[] = { - { - .name = "i2c", - .mask = RT2880_GPIO_MODE_I2C, - .gpio_first = 1, - .gpio_last = 2, - }, { - .name = "spi", - .mask = RT2880_GPIO_MODE_SPI, - .gpio_first = 3, - .gpio_last = 6, - }, { - .name = "uartlite", - .mask = RT2880_GPIO_MODE_UART0, - .gpio_first = 7, - .gpio_last = 14, - }, { - .name = "jtag", - .mask = RT2880_GPIO_MODE_JTAG, - .gpio_first = 17, - .gpio_last = 21, - }, { - .name = "mdio", - .mask = RT2880_GPIO_MODE_MDIO, - .gpio_first = 22, - .gpio_last = 23, - }, { - .name = "sdram", - .mask = RT2880_GPIO_MODE_SDRAM, - .gpio_first = 24, - .gpio_last = 39, - }, { - .name = "pci", - .mask = RT2880_GPIO_MODE_PCI, - .gpio_first = 40, - .gpio_last = 71, - }, {0} +static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) }; +static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) }; +static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 7, 8) }; +static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) }; +static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func sdram_func[] = { FUNC("sdram", 0, 24, 16) }; +static struct rt2880_pmx_func pci_func[] = { FUNC("pci", 0, 40, 32) }; + +static struct rt2880_pmx_group rt2880_pinmux_data_act[] = { + GRP("i2c", i2c_func, 1, RT2880_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT2880_GPIO_MODE_SPI), + GRP("uartlite", uartlite_func, 1, RT2880_GPIO_MODE_UART0), + GRP("jtag", jtag_func, 1, RT2880_GPIO_MODE_JTAG), + GRP("mdio", mdio_func, 1, RT2880_GPIO_MODE_MDIO), + GRP("sdram", sdram_func, 1, RT2880_GPIO_MODE_SDRAM), + GRP("pci", pci_func, 1, RT2880_GPIO_MODE_PCI), + { 0 } }; static void rt288x_wdt_reset(void) @@ -69,14 +50,9 @@ static void rt288x_wdt_reset(void) rt_sysc_w32(t, SYSC_REG_CLKCFG); } -struct ralink_pinmux rt_gpio_pinmux = { - .mode = mode_mux, - .wdt_reset = rt288x_wdt_reset, -}; - void __init ralink_clk_init(void) { - unsigned long cpu_rate; + unsigned long cpu_rate, wmac_rate = 40000000; u32 t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG); t = ((t >> SYSTEM_CONFIG_CPUCLK_SHIFT) & SYSTEM_CONFIG_CPUCLK_MASK); @@ -101,6 +77,7 @@ void __init ralink_clk_init(void) ralink_clk_add("300500.uart", cpu_rate / 2); ralink_clk_add("300c00.uartlite", cpu_rate / 2); ralink_clk_add("400000.ethernet", cpu_rate / 2); + ralink_clk_add("480000.wmac", wmac_rate); } void __init ralink_of_remap(void) @@ -140,4 +117,6 @@ void prom_soc_init(struct ralink_soc_info *soc_info) soc_info->mem_base = RT2880_SDRAM_BASE; soc_info->mem_size_min = RT2880_MEM_SIZE_MIN; soc_info->mem_size_max = RT2880_MEM_SIZE_MAX; + + rt2880_pinmux_data = rt2880_pinmux_data_act; } diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c index bb82a82..c40776a 100644 --- a/arch/mips/ralink/rt305x.c +++ b/arch/mips/ralink/rt305x.c @@ -17,90 +17,78 @@ #include <asm/mipsregs.h> #include <asm/mach-ralink/ralink_regs.h> #include <asm/mach-ralink/rt305x.h> +#include <asm/mach-ralink/pinmux.h> #include "common.h" enum rt305x_soc_type rt305x_soc; -static struct ralink_pinmux_grp mode_mux[] = { - { - .name = "i2c", - .mask = RT305X_GPIO_MODE_I2C, - .gpio_first = RT305X_GPIO_I2C_SD, - .gpio_last = RT305X_GPIO_I2C_SCLK, - }, { - .name = "spi", - .mask = RT305X_GPIO_MODE_SPI, - .gpio_first = RT305X_GPIO_SPI_EN, - .gpio_last = RT305X_GPIO_SPI_CLK, - }, { - .name = "uartlite", - .mask = RT305X_GPIO_MODE_UART1, - .gpio_first = RT305X_GPIO_UART1_TXD, - .gpio_last = RT305X_GPIO_UART1_RXD, - }, { - .name = "jtag", - .mask = RT305X_GPIO_MODE_JTAG, - .gpio_first = RT305X_GPIO_JTAG_TDO, - .gpio_last = RT305X_GPIO_JTAG_TDI, - }, { - .name = "mdio", - .mask = RT305X_GPIO_MODE_MDIO, - .gpio_first = RT305X_GPIO_MDIO_MDC, - .gpio_last = RT305X_GPIO_MDIO_MDIO, - }, { - .name = "sdram", - .mask = RT305X_GPIO_MODE_SDRAM, - .gpio_first = RT305X_GPIO_SDRAM_MD16, - .gpio_last = RT305X_GPIO_SDRAM_MD31, - }, { - .name = "rgmii", - .mask = RT305X_GPIO_MODE_RGMII, - .gpio_first = RT305X_GPIO_GE0_TXD0, - .gpio_last = RT305X_GPIO_GE0_RXCLK, - }, {0} +static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) }; +static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) }; +static struct rt2880_pmx_func uartf_func[] = { + FUNC("uartf", RT305X_GPIO_MODE_UARTF, 7, 8), + FUNC("pcm uartf", RT305X_GPIO_MODE_PCM_UARTF, 7, 8), + FUNC("pcm i2s", RT305X_GPIO_MODE_PCM_I2S, 7, 8), + FUNC("i2s uartf", RT305X_GPIO_MODE_I2S_UARTF, 7, 8), + FUNC("pcm gpio", RT305X_GPIO_MODE_PCM_GPIO, 11, 4), + FUNC("gpio uartf", RT305X_GPIO_MODE_GPIO_UARTF, 7, 4), + FUNC("gpio i2s", RT305X_GPIO_MODE_GPIO_I2S, 7, 4), +}; +static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) }; +static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) }; +static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func rt5350_led_func[] = { FUNC("led", 0, 22, 5) }; +static struct rt2880_pmx_func rt5350_cs1_func[] = { + FUNC("spi_cs1", 0, 27, 1), + FUNC("wdg_cs1", 1, 27, 1), +}; +static struct rt2880_pmx_func sdram_func[] = { FUNC("sdram", 0, 24, 16) }; +static struct rt2880_pmx_func rt3352_rgmii_func[] = { + FUNC("rgmii", 0, 24, 12) +}; +static struct rt2880_pmx_func rgmii_func[] = { FUNC("rgmii", 0, 40, 12) }; +static struct rt2880_pmx_func rt3352_lna_func[] = { FUNC("lna", 0, 36, 2) }; +static struct rt2880_pmx_func rt3352_pa_func[] = { FUNC("pa", 0, 38, 2) }; +static struct rt2880_pmx_func rt3352_led_func[] = { FUNC("led", 0, 40, 5) }; + +static struct rt2880_pmx_group rt3050_pinmux_data[] = { + GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI), + GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK, + RT305X_GPIO_MODE_UART0_SHIFT), + GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1), + GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG), + GRP("mdio", mdio_func, 1, RT305X_GPIO_MODE_MDIO), + GRP("rgmii", rgmii_func, 1, RT305X_GPIO_MODE_RGMII), + GRP("sdram", sdram_func, 1, RT305X_GPIO_MODE_SDRAM), + { 0 } }; -static struct ralink_pinmux_grp uart_mux[] = { - { - .name = "uartf", - .mask = RT305X_GPIO_MODE_UARTF, - .gpio_first = RT305X_GPIO_7, - .gpio_last = RT305X_GPIO_14, - }, { - .name = "pcm uartf", - .mask = RT305X_GPIO_MODE_PCM_UARTF, - .gpio_first = RT305X_GPIO_7, - .gpio_last = RT305X_GPIO_14, - }, { - .name = "pcm i2s", - .mask = RT305X_GPIO_MODE_PCM_I2S, - .gpio_first = RT305X_GPIO_7, - .gpio_last = RT305X_GPIO_14, - }, { - .name = "i2s uartf", - .mask = RT305X_GPIO_MODE_I2S_UARTF, - .gpio_first = RT305X_GPIO_7, - .gpio_last = RT305X_GPIO_14, - }, { - .name = "pcm gpio", - .mask = RT305X_GPIO_MODE_PCM_GPIO, - .gpio_first = RT305X_GPIO_10, - .gpio_last = RT305X_GPIO_14, - }, { - .name = "gpio uartf", - .mask = RT305X_GPIO_MODE_GPIO_UARTF, - .gpio_first = RT305X_GPIO_7, - .gpio_last = RT305X_GPIO_10, - }, { - .name = "gpio i2s", - .mask = RT305X_GPIO_MODE_GPIO_I2S, - .gpio_first = RT305X_GPIO_7, - .gpio_last = RT305X_GPIO_10, - }, { - .name = "gpio", - .mask = RT305X_GPIO_MODE_GPIO, - }, {0} +static struct rt2880_pmx_group rt3352_pinmux_data[] = { + GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI), + GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK, + RT305X_GPIO_MODE_UART0_SHIFT), + GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1), + GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG), + GRP("mdio", mdio_func, 1, RT305X_GPIO_MODE_MDIO), + GRP("rgmii", rt3352_rgmii_func, 1, RT305X_GPIO_MODE_RGMII), + GRP("lna", rt3352_lna_func, 1, RT3352_GPIO_MODE_LNA), + GRP("pa", rt3352_pa_func, 1, RT3352_GPIO_MODE_PA), + GRP("led", rt3352_led_func, 1, RT5350_GPIO_MODE_PHY_LED), + { 0 } +}; + +static struct rt2880_pmx_group rt5350_pinmux_data[] = { + GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI), + GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK, + RT305X_GPIO_MODE_UART0_SHIFT), + GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1), + GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG), + GRP("led", rt5350_led_func, 1, RT5350_GPIO_MODE_PHY_LED), + GRP("spi_cs1", rt5350_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1), + { 0 } }; static void rt305x_wdt_reset(void) @@ -114,14 +102,6 @@ static void rt305x_wdt_reset(void) rt_sysc_w32(t, SYSC_REG_SYSTEM_CONFIG); } -struct ralink_pinmux rt_gpio_pinmux = { - .mode = mode_mux, - .uart = uart_mux, - .uart_shift = RT305X_GPIO_MODE_UART0_SHIFT, - .uart_mask = RT305X_GPIO_MODE_UART0_MASK, - .wdt_reset = rt305x_wdt_reset, -}; - static unsigned long rt5350_get_mem_size(void) { void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE); @@ -290,11 +270,14 @@ void prom_soc_init(struct ralink_soc_info *soc_info) soc_info->mem_base = RT305X_SDRAM_BASE; if (soc_is_rt5350()) { soc_info->mem_size = rt5350_get_mem_size(); + rt2880_pinmux_data = rt5350_pinmux_data; } else if (soc_is_rt305x() || soc_is_rt3350()) { soc_info->mem_size_min = RT305X_MEM_SIZE_MIN; soc_info->mem_size_max = RT305X_MEM_SIZE_MAX; + rt2880_pinmux_data = rt3050_pinmux_data; } else if (soc_is_rt3352()) { soc_info->mem_size_min = RT3352_MEM_SIZE_MIN; soc_info->mem_size_max = RT3352_MEM_SIZE_MAX; + rt2880_pinmux_data = rt3352_pinmux_data; } } diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c index b474ac2..86a535c 100644 --- a/arch/mips/ralink/rt3883.c +++ b/arch/mips/ralink/rt3883.c @@ -17,132 +17,50 @@ #include <asm/mipsregs.h> #include <asm/mach-ralink/ralink_regs.h> #include <asm/mach-ralink/rt3883.h> +#include <asm/mach-ralink/pinmux.h> #include "common.h" -static struct ralink_pinmux_grp mode_mux[] = { - { - .name = "i2c", - .mask = RT3883_GPIO_MODE_I2C, - .gpio_first = RT3883_GPIO_I2C_SD, - .gpio_last = RT3883_GPIO_I2C_SCLK, - }, { - .name = "spi", - .mask = RT3883_GPIO_MODE_SPI, - .gpio_first = RT3883_GPIO_SPI_CS0, - .gpio_last = RT3883_GPIO_SPI_MISO, - }, { - .name = "uartlite", - .mask = RT3883_GPIO_MODE_UART1, - .gpio_first = RT3883_GPIO_UART1_TXD, - .gpio_last = RT3883_GPIO_UART1_RXD, - }, { - .name = "jtag", - .mask = RT3883_GPIO_MODE_JTAG, - .gpio_first = RT3883_GPIO_JTAG_TDO, - .gpio_last = RT3883_GPIO_JTAG_TCLK, - }, { - .name = "mdio", - .mask = RT3883_GPIO_MODE_MDIO, - .gpio_first = RT3883_GPIO_MDIO_MDC, - .gpio_last = RT3883_GPIO_MDIO_MDIO, - }, { - .name = "ge1", - .mask = RT3883_GPIO_MODE_GE1, - .gpio_first = RT3883_GPIO_GE1_TXD0, - .gpio_last = RT3883_GPIO_GE1_RXCLK, - }, { - .name = "ge2", - .mask = RT3883_GPIO_MODE_GE2, - .gpio_first = RT3883_GPIO_GE2_TXD0, - .gpio_last = RT3883_GPIO_GE2_RXCLK, - }, { - .name = "pci", - .mask = RT3883_GPIO_MODE_PCI, - .gpio_first = RT3883_GPIO_PCI_AD0, - .gpio_last = RT3883_GPIO_PCI_AD31, - }, { - .name = "lna a", - .mask = RT3883_GPIO_MODE_LNA_A, - .gpio_first = RT3883_GPIO_LNA_PE_A0, - .gpio_last = RT3883_GPIO_LNA_PE_A2, - }, { - .name = "lna g", - .mask = RT3883_GPIO_MODE_LNA_G, - .gpio_first = RT3883_GPIO_LNA_PE_G0, - .gpio_last = RT3883_GPIO_LNA_PE_G2, - }, {0} +static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) }; +static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) }; +static struct rt2880_pmx_func uartf_func[] = { + FUNC("uartf", RT3883_GPIO_MODE_UARTF, 7, 8), + FUNC("pcm uartf", RT3883_GPIO_MODE_PCM_UARTF, 7, 8), + FUNC("pcm i2s", RT3883_GPIO_MODE_PCM_I2S, 7, 8), + FUNC("i2s uartf", RT3883_GPIO_MODE_I2S_UARTF, 7, 8), + FUNC("pcm gpio", RT3883_GPIO_MODE_PCM_GPIO, 11, 4), + FUNC("gpio uartf", RT3883_GPIO_MODE_GPIO_UARTF, 7, 4), + FUNC("gpio i2s", RT3883_GPIO_MODE_GPIO_I2S, 7, 4), }; - -static struct ralink_pinmux_grp uart_mux[] = { - { - .name = "uartf", - .mask = RT3883_GPIO_MODE_UARTF, - .gpio_first = RT3883_GPIO_7, - .gpio_last = RT3883_GPIO_14, - }, { - .name = "pcm uartf", - .mask = RT3883_GPIO_MODE_PCM_UARTF, - .gpio_first = RT3883_GPIO_7, - .gpio_last = RT3883_GPIO_14, - }, { - .name = "pcm i2s", - .mask = RT3883_GPIO_MODE_PCM_I2S, - .gpio_first = RT3883_GPIO_7, - .gpio_last = RT3883_GPIO_14, - }, { - .name = "i2s uartf", - .mask = RT3883_GPIO_MODE_I2S_UARTF, - .gpio_first = RT3883_GPIO_7, - .gpio_last = RT3883_GPIO_14, - }, { - .name = "pcm gpio", - .mask = RT3883_GPIO_MODE_PCM_GPIO, - .gpio_first = RT3883_GPIO_11, - .gpio_last = RT3883_GPIO_14, - }, { - .name = "gpio uartf", - .mask = RT3883_GPIO_MODE_GPIO_UARTF, - .gpio_first = RT3883_GPIO_7, - .gpio_last = RT3883_GPIO_10, - }, { - .name = "gpio i2s", - .mask = RT3883_GPIO_MODE_GPIO_I2S, - .gpio_first = RT3883_GPIO_7, - .gpio_last = RT3883_GPIO_10, - }, { - .name = "gpio", - .mask = RT3883_GPIO_MODE_GPIO, - }, {0} +static struct rt2880_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) }; +static struct rt2880_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) }; +static struct rt2880_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) }; +static struct rt2880_pmx_func lna_a_func[] = { FUNC("lna a", 0, 32, 3) }; +static struct rt2880_pmx_func lna_g_func[] = { FUNC("lna a", 0, 35, 3) }; +static struct rt2880_pmx_func pci_func[] = { + FUNC("pci-dev", 0, 40, 32), + FUNC("pci-host2", 1, 40, 32), + FUNC("pci-host1", 2, 40, 32), + FUNC("pci-fnc", 3, 40, 32) }; - -static struct ralink_pinmux_grp pci_mux[] = { - { - .name = "pci-dev", - .mask = 0, - .gpio_first = RT3883_GPIO_PCI_AD0, - .gpio_last = RT3883_GPIO_PCI_AD31, - }, { - .name = "pci-host2", - .mask = 1, - .gpio_first = RT3883_GPIO_PCI_AD0, - .gpio_last = RT3883_GPIO_PCI_AD31, - }, { - .name = "pci-host1", - .mask = 2, - .gpio_first = RT3883_GPIO_PCI_AD0, - .gpio_last = RT3883_GPIO_PCI_AD31, - }, { - .name = "pci-fnc", - .mask = 3, - .gpio_first = RT3883_GPIO_PCI_AD0, - .gpio_last = RT3883_GPIO_PCI_AD31, - }, { - .name = "pci-gpio", - .mask = 7, - .gpio_first = RT3883_GPIO_PCI_AD0, - .gpio_last = RT3883_GPIO_PCI_AD31, - }, {0} +static struct rt2880_pmx_func ge1_func[] = { FUNC("ge1", 0, 72, 12) }; +static struct rt2880_pmx_func ge2_func[] = { FUNC("ge1", 0, 84, 12) }; + +static struct rt2880_pmx_group rt3883_pinmux_data[] = { + GRP("i2c", i2c_func, 1, RT3883_GPIO_MODE_I2C), + GRP("spi", spi_func, 1, RT3883_GPIO_MODE_SPI), + GRP("uartf", uartf_func, RT3883_GPIO_MODE_UART0_MASK, + RT3883_GPIO_MODE_UART0_SHIFT), + GRP("uartlite", uartlite_func, 1, RT3883_GPIO_MODE_UART1), + GRP("jtag", jtag_func, 1, RT3883_GPIO_MODE_JTAG), + GRP("mdio", mdio_func, 1, RT3883_GPIO_MODE_MDIO), + GRP("lna a", lna_a_func, 1, RT3883_GPIO_MODE_LNA_A), + GRP("lna g", lna_g_func, 1, RT3883_GPIO_MODE_LNA_G), + GRP("pci", pci_func, RT3883_GPIO_MODE_PCI_MASK, + RT3883_GPIO_MODE_PCI_SHIFT), + GRP("ge1", ge1_func, 1, RT3883_GPIO_MODE_GE1), + GRP("ge2", ge2_func, 1, RT3883_GPIO_MODE_GE2), + { 0 } }; static void rt3883_wdt_reset(void) @@ -155,17 +73,6 @@ static void rt3883_wdt_reset(void) rt_sysc_w32(t, RT3883_SYSC_REG_SYSCFG1); } -struct ralink_pinmux rt_gpio_pinmux = { - .mode = mode_mux, - .uart = uart_mux, - .uart_shift = RT3883_GPIO_MODE_UART0_SHIFT, - .uart_mask = RT3883_GPIO_MODE_UART0_MASK, - .wdt_reset = rt3883_wdt_reset, - .pci = pci_mux, - .pci_shift = RT3883_GPIO_MODE_PCI_SHIFT, - .pci_mask = RT3883_GPIO_MODE_PCI_MASK, -}; - void __init ralink_clk_init(void) { unsigned long cpu_rate, sys_rate; @@ -204,6 +111,7 @@ void __init ralink_clk_init(void) ralink_clk_add("10000b00.spi", sys_rate); ralink_clk_add("10000c00.uartlite", 40000000); ralink_clk_add("10100000.ethernet", sys_rate); + ralink_clk_add("10180000.wmac", 40000000); } void __init ralink_of_remap(void) @@ -243,4 +151,6 @@ void prom_soc_init(struct ralink_soc_info *soc_info) soc_info->mem_base = RT3883_SDRAM_BASE; soc_info->mem_size_min = RT3883_MEM_SIZE_MIN; soc_info->mem_size_max = RT3883_MEM_SIZE_MAX; + + rt2880_pinmux_data = rt3883_pinmux_data; } diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c index a180076..5aa3df8 100644 --- a/arch/mips/rb532/gpio.c +++ b/arch/mips/rb532/gpio.c @@ -79,7 +79,7 @@ static inline void rb532_set_bit(unsigned bitval, */ static inline int rb532_get_bit(unsigned offset, void __iomem *ioaddr) { - return (readl(ioaddr) & (1 << offset)); + return readl(ioaddr) & (1 << offset); } /* diff --git a/arch/mips/rb532/prom.c b/arch/mips/rb532/prom.c index a757ded..657210e 100644 --- a/arch/mips/rb532/prom.c +++ b/arch/mips/rb532/prom.c @@ -122,8 +122,8 @@ void __init prom_setup_cmdline(void) void __init prom_init(void) { struct ddr_ram __iomem *ddr; - phys_t memsize; - phys_t ddrbase; + phys_addr_t memsize; + phys_addr_t ddrbase; ddr = ioremap_nocache(ddr_reg[0].start, ddr_reg[0].end - ddr_reg[0].start); @@ -133,8 +133,8 @@ void __init prom_init(void) return; } - ddrbase = (phys_t)&ddr->ddrbase; - memsize = (phys_t)&ddr->ddrmask; + ddrbase = (phys_addr_t)&ddr->ddrbase; + memsize = (phys_addr_t)&ddr->ddrmask; memsize = 0 - memsize; prom_setup_cmdline(); diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c index 7cec0a4..6b009c4 100644 --- a/arch/mips/sgi-ip22/ip22-mc.c +++ b/arch/mips/sgi-ip22/ip22-mc.c @@ -24,14 +24,12 @@ EXPORT_SYMBOL(sgimc); static inline unsigned long get_bank_addr(unsigned int memconfig) { - return ((memconfig & SGIMC_MCONFIG_BASEADDR) << - ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 24 : 22)); + return (memconfig & SGIMC_MCONFIG_BASEADDR) << ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 24 : 22); } static inline unsigned long get_bank_size(unsigned int memconfig) { - return ((memconfig & SGIMC_MCONFIG_RMASK) + 0x0100) << - ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 16 : 14); + return ((memconfig & SGIMC_MCONFIG_RMASK) + 0x0100) << ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 16 : 14); } static inline unsigned int get_bank_config(int bank) diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c index 3f47346..712cc0f 100644 --- a/arch/mips/sgi-ip22/ip28-berr.c +++ b/arch/mips/sgi-ip22/ip28-berr.c @@ -338,7 +338,7 @@ static int check_microtlb(u32 hi, u32 lo, unsigned long vaddr) PHYS_TO_XKSEG_UNCACHED(pte); a = (a & 0x3f) << 6; /* PFN */ a += vaddr & ((1 << pgsz) - 1); - return (cpu_err_addr == a); + return cpu_err_addr == a; } } } @@ -351,7 +351,7 @@ static int check_vdma_memaddr(void) u32 a = sgimc->maddronly; if (!(sgimc->dma_ctrl & 0x100)) /* Xlate-bit clear ? */ - return (cpu_err_addr == a); + return cpu_err_addr == a; if (check_microtlb(sgimc->dtlb_hi0, sgimc->dtlb_lo0, a) || check_microtlb(sgimc->dtlb_hi1, sgimc->dtlb_lo1, a) || @@ -367,7 +367,7 @@ static int check_vdma_gioaddr(void) if (gio_err_stat & GIO_ERRMASK) { u32 a = sgimc->gio_dma_trans; a = (sgimc->gmaddronly & ~a) | (sgimc->gio_dma_sbits & a); - return (gio_err_addr == a); + return gio_err_addr == a; } return 0; } diff --git a/arch/mips/sgi-ip27/ip27-klnuma.c b/arch/mips/sgi-ip27/ip27-klnuma.c index 7a53b1e..ecbb62f 100644 --- a/arch/mips/sgi-ip27/ip27-klnuma.c +++ b/arch/mips/sgi-ip27/ip27-klnuma.c @@ -125,8 +125,7 @@ unsigned long node_getfirstfree(cnodeid_t cnode) #endif offset = PAGE_ALIGN((unsigned long)(&_end)) - loadbase; if ((cnode == 0) || (cpu_isset(cnode, ktext_repmask))) - return (TO_NODE(nasid, offset) >> PAGE_SHIFT); + return TO_NODE(nasid, offset) >> PAGE_SHIFT; else - return (KDM_TO_PHYS(PAGE_ALIGN(SYMMON_STK_ADDR(nasid, 0))) >> - PAGE_SHIFT); + return KDM_TO_PHYS(PAGE_ALIGN(SYMMON_STK_ADDR(nasid, 0))) >> PAGE_SHIFT; } diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index a304bcc..0b68469 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -42,8 +42,7 @@ static int fine_mode; static int is_fine_dirmode(void) { - return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) - >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE); + return ((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE; } static hubreg_t get_region(cnodeid_t cnode) @@ -288,7 +287,7 @@ static unsigned long __init slot_psize_compute(cnodeid_t node, int slot) if (size <= 128) { if (slot % 4 == 0) { size <<= 20; /* size in bytes */ - return(size >> PAGE_SHIFT); + return size >> PAGE_SHIFT; } else return 0; } else { diff --git a/arch/mips/sibyte/common/cfe.c b/arch/mips/sibyte/common/cfe.c index 588e180..c1a11a1 100644 --- a/arch/mips/sibyte/common/cfe.c +++ b/arch/mips/sibyte/common/cfe.c @@ -38,7 +38,7 @@ #define MAX_RAM_SIZE (~0ULL) #else #ifdef CONFIG_HIGHMEM -#ifdef CONFIG_64BIT_PHYS_ADDR +#ifdef CONFIG_PHYS_ADDR_T_64BIT #define MAX_RAM_SIZE (~0ULL) #else #define MAX_RAM_SIZE (0xffffffffULL) @@ -49,8 +49,8 @@ #endif #define SIBYTE_MAX_MEM_REGIONS 8 -phys_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS]; -phys_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS]; +phys_addr_t board_mem_region_addrs[SIBYTE_MAX_MEM_REGIONS]; +phys_addr_t board_mem_region_sizes[SIBYTE_MAX_MEM_REGIONS]; unsigned int board_mem_region_count; int cfe_cons_handle; @@ -96,7 +96,7 @@ static void __noreturn cfe_linux_halt(void) static __init void prom_meminit(void) { - u64 addr, size, type; /* regardless of 64BIT_PHYS_ADDR */ + u64 addr, size, type; /* regardless of PHYS_ADDR_T_64BIT */ int mem_flags = 0; unsigned int idx; int rd_flag; diff --git a/arch/mips/sibyte/swarm/platform.c b/arch/mips/sibyte/swarm/platform.c index 9480c14..1cecdcf 100644 --- a/arch/mips/sibyte/swarm/platform.c +++ b/arch/mips/sibyte/swarm/platform.c @@ -50,7 +50,7 @@ static struct platform_device swarm_pata_device = { static int __init swarm_pata_init(void) { u8 __iomem *base; - phys_t offset, size; + phys_addr_t offset, size; struct resource *r; if (!SIBYTE_HAVE_IDE) diff --git a/arch/mips/sibyte/swarm/rtc_m41t81.c b/arch/mips/sibyte/swarm/rtc_m41t81.c index b732600..e624664 100644 --- a/arch/mips/sibyte/swarm/rtc_m41t81.c +++ b/arch/mips/sibyte/swarm/rtc_m41t81.c @@ -109,7 +109,7 @@ static int m41t81_read(uint8_t addr) return -1; } - return (__raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff); + return __raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff; } static int m41t81_write(uint8_t addr, int b) @@ -229,5 +229,5 @@ int m41t81_probe(void) tmp = m41t81_read(M41T81REG_SC); m41t81_write(M41T81REG_SC, tmp & 0x7f); - return (m41t81_read(M41T81REG_SC) != -1); + return m41t81_read(M41T81REG_SC) != -1; } diff --git a/arch/mips/sibyte/swarm/rtc_xicor1241.c b/arch/mips/sibyte/swarm/rtc_xicor1241.c index 178a824..50a82c4 100644 --- a/arch/mips/sibyte/swarm/rtc_xicor1241.c +++ b/arch/mips/sibyte/swarm/rtc_xicor1241.c @@ -84,7 +84,7 @@ static int xicor_read(uint8_t addr) return -1; } - return (__raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff); + return __raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff; } static int xicor_write(uint8_t addr, int b) @@ -206,5 +206,5 @@ unsigned long xicor_get_time(void) int xicor_probe(void) { - return (xicor_read(X1241REG_SC) != -1); + return xicor_read(X1241REG_SC) != -1; } diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index 3462c83..494fb0a 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c @@ -76,7 +76,7 @@ int swarm_be_handler(struct pt_regs *regs, int is_fixup) printk("DBE physical address: %010Lx\n", __read_64bit_c0_register($26, 1)); } - return (is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL); + return is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; } enum swarm_rtc_type { diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c index e714d6c..a4664cb 100644 --- a/arch/mips/txx9/generic/setup_tx4927.c +++ b/arch/mips/txx9/generic/setup_tx4927.c @@ -29,8 +29,8 @@ static void __init tx4927_wdr_init(void) { /* report watchdog reset status */ if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_WDRST) - pr_warning("Watchdog reset detected at 0x%lx\n", - read_c0_errorepc()); + pr_warn("Watchdog reset detected at 0x%lx\n", + read_c0_errorepc()); /* clear WatchDogReset (W1C) */ tx4927_ccfg_set(TX4927_CCFG_WDRST); /* do reset on watchdog */ diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c index 0a3bf2d..58cdb2a 100644 --- a/arch/mips/txx9/generic/setup_tx4938.c +++ b/arch/mips/txx9/generic/setup_tx4938.c @@ -31,8 +31,8 @@ static void __init tx4938_wdr_init(void) { /* report watchdog reset status */ if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_WDRST) - pr_warning("Watchdog reset detected at 0x%lx\n", - read_c0_errorepc()); + pr_warn("Watchdog reset detected at 0x%lx\n", + read_c0_errorepc()); /* clear WatchDogReset (W1C) */ tx4938_ccfg_set(TX4938_CCFG_WDRST); /* do reset on watchdog */ diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c index b7eccbd..e3733cd 100644 --- a/arch/mips/txx9/generic/setup_tx4939.c +++ b/arch/mips/txx9/generic/setup_tx4939.c @@ -35,8 +35,8 @@ static void __init tx4939_wdr_init(void) { /* report watchdog reset status */ if (____raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_WDRST) - pr_warning("Watchdog reset detected at 0x%lx\n", - read_c0_errorepc()); + pr_warn("Watchdog reset detected at 0x%lx\n", + read_c0_errorepc()); /* clear WatchDogReset (W1C) */ tx4939_ccfg_set(TX4939_CCFG_WDRST); /* do reset on watchdog */ diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index 5ec69c3..04faf6d 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -20,6 +20,9 @@ #include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/time.h> +#ifdef CONFIG_BCM47XX +#include <bcm47xx_nvram.h> +#endif enum bcma_boot_dev { BCMA_BOOT_DEV_UNK = 0, @@ -316,10 +319,16 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) switch (boot_dev) { case BCMA_BOOT_DEV_PARALLEL: case BCMA_BOOT_DEV_SERIAL: - /* TODO: Init NVRAM using BCMA_SOC_FLASH2 window */ +#ifdef CONFIG_BCM47XX + bcm47xx_nvram_init_from_mem(BCMA_SOC_FLASH2, + BCMA_SOC_FLASH2_SZ); +#endif break; case BCMA_BOOT_DEV_NAND: - /* TODO: Init NVRAM using BCMA_SOC_FLASH1 window */ +#ifdef CONFIG_BCM47XX + bcm47xx_nvram_init_from_mem(BCMA_SOC_FLASH1, + BCMA_SOC_FLASH1_SZ); +#endif break; default: break; diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c index f20b750..ca80103 100644 --- a/drivers/clk/clk-ls1x.c +++ b/drivers/clk/clk-ls1x.c @@ -15,7 +15,8 @@ #include <loongson1.h> -#define OSC 33 +#define OSC (33 * 1000000) +#define DIV_APB 2 static DEFINE_SPINLOCK(_lock); @@ -29,13 +30,12 @@ static void ls1x_pll_clk_disable(struct clk_hw *hw) } static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) + unsigned long parent_rate) { u32 pll, rate; pll = __raw_readl(LS1X_CLK_PLL_FREQ); - rate = ((12 + (pll & 0x3f)) * 1000000) + - ((((pll >> 8) & 0x3ff) * 1000000) >> 10); + rate = 12 + (pll & 0x3f) + (((pll >> 8) & 0x3ff) >> 10); rate *= OSC; rate >>= 1; @@ -48,8 +48,10 @@ static const struct clk_ops ls1x_pll_clk_ops = { .recalc_rate = ls1x_pll_recalc_rate, }; -static struct clk * __init clk_register_pll(struct device *dev, - const char *name, const char *parent_name, unsigned long flags) +static struct clk *__init clk_register_pll(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags) { struct clk_hw *hw; struct clk *clk; @@ -78,34 +80,83 @@ static struct clk * __init clk_register_pll(struct device *dev, return clk; } +static const char const *cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", }; +static const char const *ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", }; +static const char const *dc_parents[] = { "dc_clk_div", "osc_33m_clk", }; + void __init ls1x_clk_init(void) { struct clk *clk; - clk = clk_register_pll(NULL, "pll_clk", NULL, CLK_IS_ROOT); - clk_prepare_enable(clk); - - clk = clk_register_divider(NULL, "cpu_clk", "pll_clk", - CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT, - DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_prepare_enable(clk); - clk_register_clkdev(clk, "cpu", NULL); - - clk = clk_register_divider(NULL, "dc_clk", "pll_clk", - CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, - DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_prepare_enable(clk); - clk_register_clkdev(clk, "dc", NULL); - - clk = clk_register_divider(NULL, "ahb_clk", "pll_clk", - CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, - DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); - clk_prepare_enable(clk); - clk_register_clkdev(clk, "ahb", NULL); + clk = clk_register_fixed_rate(NULL, "osc_33m_clk", NULL, CLK_IS_ROOT, + OSC); + clk_register_clkdev(clk, "osc_33m_clk", NULL); + + /* clock derived from 33 MHz OSC clk */ + clk = clk_register_pll(NULL, "pll_clk", "osc_33m_clk", 0); + clk_register_clkdev(clk, "pll_clk", NULL); + + /* clock derived from PLL clk */ + /* _____ + * _______________________| | + * OSC ___/ | MUX |___ CPU CLK + * \___ PLL ___ CPU DIV ___| | + * |_____| + */ + clk = clk_register_divider(NULL, "cpu_clk_div", "pll_clk", + CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, + DIV_CPU_SHIFT, DIV_CPU_WIDTH, + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ROUND_CLOSEST, &_lock); + clk_register_clkdev(clk, "cpu_clk_div", NULL); + clk = clk_register_mux(NULL, "cpu_clk", cpu_parents, + ARRAY_SIZE(cpu_parents), + CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, + BYPASS_CPU_SHIFT, BYPASS_CPU_WIDTH, 0, &_lock); + clk_register_clkdev(clk, "cpu_clk", NULL); + + /* _____ + * _______________________| | + * OSC ___/ | MUX |___ DC CLK + * \___ PLL ___ DC DIV ___| | + * |_____| + */ + clk = clk_register_divider(NULL, "dc_clk_div", "pll_clk", + 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, + DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); + clk_register_clkdev(clk, "dc_clk_div", NULL); + clk = clk_register_mux(NULL, "dc_clk", dc_parents, + ARRAY_SIZE(dc_parents), + CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, + BYPASS_DC_SHIFT, BYPASS_DC_WIDTH, 0, &_lock); + clk_register_clkdev(clk, "dc_clk", NULL); + + /* _____ + * _______________________| | + * OSC ___/ | MUX |___ DDR CLK + * \___ PLL ___ DDR DIV ___| | + * |_____| + */ + clk = clk_register_divider(NULL, "ahb_clk_div", "pll_clk", + 0, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT, + DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, + &_lock); + clk_register_clkdev(clk, "ahb_clk_div", NULL); + clk = clk_register_mux(NULL, "ahb_clk", ahb_parents, + ARRAY_SIZE(ahb_parents), + CLK_SET_RATE_NO_REPARENT, LS1X_CLK_PLL_DIV, + BYPASS_DDR_SHIFT, BYPASS_DDR_WIDTH, 0, &_lock); + clk_register_clkdev(clk, "ahb_clk", NULL); clk_register_clkdev(clk, "stmmaceth", NULL); - clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 2); - clk_prepare_enable(clk); - clk_register_clkdev(clk, "apb", NULL); + /* clock derived from AHB clk */ + /* APB clk is always half of the AHB clk */ + clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, + DIV_APB); + clk_register_clkdev(clk, "apb_clk", NULL); + clk_register_clkdev(clk, "ls1x_i2c", NULL); + clk_register_clkdev(clk, "ls1x_pwmtimer", NULL); + clk_register_clkdev(clk, "ls1x_spi", NULL); + clk_register_clkdev(clk, "ls1x_wdt", NULL); clk_register_clkdev(clk, "serial8250", NULL); } diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index f657a48..fc01ec2 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -224,4 +224,9 @@ config CLKSRC_VERSATILE ARM Versatile, RealView and Versatile Express reference platforms. +config CLKSRC_MIPS_GIC + bool + depends on MIPS_GIC + select CLKSRC_OF + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index fae0435..94d90b2 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -47,3 +47,4 @@ obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o +obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c new file mode 100644 index 0000000..3bd31b1 --- /dev/null +++ b/drivers/clocksource/mips-gic-timer.c @@ -0,0 +1,166 @@ +/* + * 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) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/clockchips.h> +#include <linux/cpu.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irqchip/mips-gic.h> +#include <linux/notifier.h> +#include <linux/of_irq.h> +#include <linux/percpu.h> +#include <linux/smp.h> +#include <linux/time.h> + +static DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device); +static int gic_timer_irq; +static unsigned int gic_frequency; + +static int gic_next_event(unsigned long delta, struct clock_event_device *evt) +{ + u64 cnt; + int res; + + cnt = gic_read_count(); + cnt += (u64)delta; + gic_write_cpu_compare(cnt, cpumask_first(evt->cpumask)); + res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0; + return res; +} + +static void gic_set_clock_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + /* Nothing to do ... */ +} + +static irqreturn_t gic_compare_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *cd = dev_id; + + gic_write_compare(gic_read_compare()); + cd->event_handler(cd); + return IRQ_HANDLED; +} + +struct irqaction gic_compare_irqaction = { + .handler = gic_compare_interrupt, + .percpu_dev_id = &gic_clockevent_device, + .flags = IRQF_PERCPU | IRQF_TIMER, + .name = "timer", +}; + +static void gic_clockevent_cpu_init(struct clock_event_device *cd) +{ + unsigned int cpu = smp_processor_id(); + + cd->name = "MIPS GIC"; + cd->features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_C3STOP; + + cd->rating = 350; + cd->irq = gic_timer_irq; + cd->cpumask = cpumask_of(cpu); + cd->set_next_event = gic_next_event; + cd->set_mode = gic_set_clock_mode; + + clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff); + + enable_percpu_irq(gic_timer_irq, IRQ_TYPE_NONE); +} + +static void gic_clockevent_cpu_exit(struct clock_event_device *cd) +{ + disable_percpu_irq(gic_timer_irq); +} + +static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); + break; + case CPU_DYING: + gic_clockevent_cpu_exit(this_cpu_ptr(&gic_clockevent_device)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block gic_cpu_nb = { + .notifier_call = gic_cpu_notifier, +}; + +static int gic_clockevent_init(void) +{ + if (!cpu_has_counter || !gic_frequency) + return -ENXIO; + + setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + + register_cpu_notifier(&gic_cpu_nb); + + gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); + + return 0; +} + +static cycle_t gic_hpt_read(struct clocksource *cs) +{ + return gic_read_count(); +} + +static struct clocksource gic_clocksource = { + .name = "GIC", + .read = gic_hpt_read, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init __gic_clocksource_init(void) +{ + /* Set clocksource mask. */ + gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); + + /* Calculate a somewhat reasonable rating value. */ + gic_clocksource.rating = 200 + gic_frequency / 10000000; + + clocksource_register_hz(&gic_clocksource, gic_frequency); + + gic_clockevent_init(); +} + +void __init gic_clocksource_init(unsigned int frequency) +{ + gic_frequency = frequency; + gic_timer_irq = MIPS_GIC_IRQ_BASE + + GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); + + __gic_clocksource_init(); +} + +static void __init gic_clocksource_of_init(struct device_node *node) +{ + if (WARN_ON(!gic_present || !node->parent || + !of_device_is_compatible(node->parent, "mti,gic"))) + return; + + if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { + pr_err("GIC frequency not specified.\n"); + return; + } + gic_timer_irq = irq_of_parse_and_map(node, 0); + if (!gic_timer_irq) { + pr_err("GIC timer IRQ not specified.\n"); + return; + } + + __gic_clocksource_init(); +} +CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", + gic_clocksource_of_init); diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c index 17686ca..0659ec9 100644 --- a/drivers/dma/txx9dmac.c +++ b/drivers/dma/txx9dmac.c @@ -76,7 +76,7 @@ static void channel64_write_CHAR(const struct txx9dmac_chan *dc, dma_addr_t val) static void channel64_clear_CHAR(const struct txx9dmac_chan *dc) { -#if defined(CONFIG_32BIT) && !defined(CONFIG_64BIT_PHYS_ADDR) +#if defined(CONFIG_32BIT) && !defined(CONFIG_PHYS_ADDR_T_64BIT) channel64_writel(dc, CHAR, 0); channel64_writel(dc, __pad_CHAR, 0); #else diff --git a/drivers/dma/txx9dmac.h b/drivers/dma/txx9dmac.h index f5a7605..f6517b9 100644 --- a/drivers/dma/txx9dmac.h +++ b/drivers/dma/txx9dmac.h @@ -67,7 +67,7 @@ static inline bool txx9_dma_have_SMPCHN(void) /* Hardware register definitions. */ struct txx9dmac_cregs { -#if defined(CONFIG_32BIT) && !defined(CONFIG_64BIT_PHYS_ADDR) +#if defined(CONFIG_32BIT) && !defined(CONFIG_PHYS_ADDR_T_64BIT) TXX9_DMA_REG32(CHAR); /* Chain Address Register */ #else u64 CHAR; /* Chain Address Register */ @@ -201,7 +201,7 @@ static inline bool is_dmac64(const struct txx9dmac_chan *dc) #ifdef TXX9_DMA_USE_SIMPLE_CHAIN /* Hardware descriptor definition. (for simple-chain) */ struct txx9dmac_hwdesc { -#if defined(CONFIG_32BIT) && !defined(CONFIG_64BIT_PHYS_ADDR) +#if defined(CONFIG_32BIT) && !defined(CONFIG_PHYS_ADDR_T_64BIT) TXX9_DMA_REG32(CHAR); #else u64 CHAR; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 9efe5f1..e12cb23 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -130,3 +130,7 @@ config KEYSTONE_IRQ help Support for Texas Instruments Keystone 2 IRQ controller IP which is part of the Keystone 2 IPC mechanism + +config MIPS_GIC + bool + select MIPS_CM diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index f0909d0..4954a31 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o +obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c new file mode 100644 index 0000000..2b0468e --- /dev/null +++ b/drivers/irqchip/irq-mips-gic.c @@ -0,0 +1,789 @@ +/* + * 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) 2008 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/bitmap.h> +#include <linux/clocksource.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip/mips-gic.h> +#include <linux/of_address.h> +#include <linux/sched.h> +#include <linux/smp.h> + +#include <asm/mips-cm.h> +#include <asm/setup.h> +#include <asm/traps.h> + +#include <dt-bindings/interrupt-controller/mips-gic.h> + +#include "irqchip.h" + +unsigned int gic_present; + +struct gic_pcpu_mask { + DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS); +}; + +static void __iomem *gic_base; +static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; +static DEFINE_SPINLOCK(gic_lock); +static struct irq_domain *gic_irq_domain; +static int gic_shared_intrs; +static int gic_vpes; +static unsigned int gic_cpu_pin; +static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; + +static void __gic_irq_dispatch(void); + +static inline unsigned int gic_read(unsigned int reg) +{ + return __raw_readl(gic_base + reg); +} + +static inline void gic_write(unsigned int reg, unsigned int val) +{ + __raw_writel(val, gic_base + reg); +} + +static inline void gic_update_bits(unsigned int reg, unsigned int mask, + unsigned int val) +{ + unsigned int regval; + + regval = gic_read(reg); + regval &= ~mask; + regval |= val; + gic_write(reg, regval); +} + +static inline void gic_reset_mask(unsigned int intr) +{ + gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr), + 1 << GIC_INTR_BIT(intr)); +} + +static inline void gic_set_mask(unsigned int intr) +{ + gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr), + 1 << GIC_INTR_BIT(intr)); +} + +static inline void gic_set_polarity(unsigned int intr, unsigned int pol) +{ + gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) + + GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), + pol << GIC_INTR_BIT(intr)); +} + +static inline void gic_set_trigger(unsigned int intr, unsigned int trig) +{ + gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) + + GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), + trig << GIC_INTR_BIT(intr)); +} + +static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual) +{ + gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr), + 1 << GIC_INTR_BIT(intr), + dual << GIC_INTR_BIT(intr)); +} + +static inline void gic_map_to_pin(unsigned int intr, unsigned int pin) +{ + gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + + GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); +} + +static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe) +{ + gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_VPE_BASE) + + GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe), + GIC_SH_MAP_TO_VPE_REG_BIT(vpe)); +} + +#ifdef CONFIG_CLKSRC_MIPS_GIC +cycle_t gic_read_count(void) +{ + unsigned int hi, hi2, lo; + + do { + hi = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); + lo = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); + hi2 = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); + } while (hi2 != hi); + + return (((cycle_t) hi) << 32) + lo; +} + +unsigned int gic_get_count_width(void) +{ + unsigned int bits, config; + + config = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG)); + bits = 32 + 4 * ((config & GIC_SH_CONFIG_COUNTBITS_MSK) >> + GIC_SH_CONFIG_COUNTBITS_SHF); + + return bits; +} + +void gic_write_compare(cycle_t cnt) +{ + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), + (int)(cnt >> 32)); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), + (int)(cnt & 0xffffffff)); +} + +void gic_write_cpu_compare(cycle_t cnt, int cpu) +{ + unsigned long flags; + + local_irq_save(flags); + + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), + (int)(cnt >> 32)); + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), + (int)(cnt & 0xffffffff)); + + local_irq_restore(flags); +} + +cycle_t gic_read_compare(void) +{ + unsigned int hi, lo; + + hi = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); + lo = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); + + return (((cycle_t) hi) << 32) + lo; +} +#endif + +static bool gic_local_irq_is_routable(int intr) +{ + u32 vpe_ctl; + + /* All local interrupts are routable in EIC mode. */ + if (cpu_has_veic) + return true; + + vpe_ctl = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); + switch (intr) { + case GIC_LOCAL_INT_TIMER: + return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK; + case GIC_LOCAL_INT_PERFCTR: + return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK; + case GIC_LOCAL_INT_FDC: + return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK; + case GIC_LOCAL_INT_SWINT0: + case GIC_LOCAL_INT_SWINT1: + return vpe_ctl & GIC_VPE_CTL_SWINT_RTBL_MSK; + default: + return true; + } +} + +unsigned int gic_get_timer_pending(void) +{ + unsigned int vpe_pending; + + vpe_pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); + return vpe_pending & GIC_VPE_PEND_TIMER_MSK; +} + +static void gic_bind_eic_interrupt(int irq, int set) +{ + /* Convert irq vector # to hw int # */ + irq -= GIC_PIN_TO_VEC_OFFSET; + + /* Set irq to use shadow set */ + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_EIC_SHADOW_SET_BASE) + + GIC_VPE_EIC_SS(irq), set); +} + +void gic_send_ipi(unsigned int intr) +{ + gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_SET(intr)); +} + +int gic_get_c0_compare_int(void) +{ + if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) + return MIPS_CPU_IRQ_BASE + cp0_compare_irq; + return irq_create_mapping(gic_irq_domain, + GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER)); +} + +int gic_get_c0_perfcount_int(void) +{ + if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) { + /* Is the erformance counter shared with the timer? */ + if (cp0_perfcount_irq < 0) + return -1; + return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + } + return irq_create_mapping(gic_irq_domain, + GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR)); +} + +static unsigned int gic_get_int(void) +{ + unsigned int i; + unsigned long *pcpu_mask; + unsigned long pending_reg, intrmask_reg; + DECLARE_BITMAP(pending, GIC_MAX_INTRS); + DECLARE_BITMAP(intrmask, GIC_MAX_INTRS); + + /* Get per-cpu bitmaps */ + pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask; + + pending_reg = GIC_REG(SHARED, GIC_SH_PEND); + intrmask_reg = GIC_REG(SHARED, GIC_SH_MASK); + + for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) { + pending[i] = gic_read(pending_reg); + intrmask[i] = gic_read(intrmask_reg); + pending_reg += 0x4; + intrmask_reg += 0x4; + } + + bitmap_and(pending, pending, intrmask, gic_shared_intrs); + bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs); + + return find_first_bit(pending, gic_shared_intrs); +} + +static void gic_mask_irq(struct irq_data *d) +{ + gic_reset_mask(GIC_HWIRQ_TO_SHARED(d->hwirq)); +} + +static void gic_unmask_irq(struct irq_data *d) +{ + gic_set_mask(GIC_HWIRQ_TO_SHARED(d->hwirq)); +} + +static void gic_ack_irq(struct irq_data *d) +{ + unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); + + gic_write(GIC_REG(SHARED, GIC_SH_WEDGE), GIC_SH_WEDGE_CLR(irq)); +} + +static int gic_set_type(struct irq_data *d, unsigned int type) +{ + unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); + unsigned long flags; + bool is_edge; + + spin_lock_irqsave(&gic_lock, flags); + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_FALLING: + gic_set_polarity(irq, GIC_POL_NEG); + gic_set_trigger(irq, GIC_TRIG_EDGE); + gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE); + is_edge = true; + break; + case IRQ_TYPE_EDGE_RISING: + gic_set_polarity(irq, GIC_POL_POS); + gic_set_trigger(irq, GIC_TRIG_EDGE); + gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE); + is_edge = true; + break; + case IRQ_TYPE_EDGE_BOTH: + /* polarity is irrelevant in this case */ + gic_set_trigger(irq, GIC_TRIG_EDGE); + gic_set_dual_edge(irq, GIC_TRIG_DUAL_ENABLE); + is_edge = true; + break; + case IRQ_TYPE_LEVEL_LOW: + gic_set_polarity(irq, GIC_POL_NEG); + gic_set_trigger(irq, GIC_TRIG_LEVEL); + gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE); + is_edge = false; + break; + case IRQ_TYPE_LEVEL_HIGH: + default: + gic_set_polarity(irq, GIC_POL_POS); + gic_set_trigger(irq, GIC_TRIG_LEVEL); + gic_set_dual_edge(irq, GIC_TRIG_DUAL_DISABLE); + is_edge = false; + break; + } + + if (is_edge) { + __irq_set_chip_handler_name_locked(d->irq, + &gic_edge_irq_controller, + handle_edge_irq, NULL); + } else { + __irq_set_chip_handler_name_locked(d->irq, + &gic_level_irq_controller, + handle_level_irq, NULL); + } + spin_unlock_irqrestore(&gic_lock, flags); + + return 0; +} + +#ifdef CONFIG_SMP +static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, + bool force) +{ + unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); + cpumask_t tmp = CPU_MASK_NONE; + unsigned long flags; + int i; + + cpumask_and(&tmp, cpumask, cpu_online_mask); + if (cpus_empty(tmp)) + return -EINVAL; + + /* Assumption : cpumask refers to a single CPU */ + spin_lock_irqsave(&gic_lock, flags); + + /* Re-route this IRQ */ + gic_map_to_vpe(irq, first_cpu(tmp)); + + /* Update the pcpu_masks */ + for (i = 0; i < NR_CPUS; i++) + clear_bit(irq, pcpu_masks[i].pcpu_mask); + set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); + + cpumask_copy(d->affinity, cpumask); + spin_unlock_irqrestore(&gic_lock, flags); + + return IRQ_SET_MASK_OK_NOCOPY; +} +#endif + +static struct irq_chip gic_level_irq_controller = { + .name = "MIPS GIC", + .irq_mask = gic_mask_irq, + .irq_unmask = gic_unmask_irq, + .irq_set_type = gic_set_type, +#ifdef CONFIG_SMP + .irq_set_affinity = gic_set_affinity, +#endif +}; + +static struct irq_chip gic_edge_irq_controller = { + .name = "MIPS GIC", + .irq_ack = gic_ack_irq, + .irq_mask = gic_mask_irq, + .irq_unmask = gic_unmask_irq, + .irq_set_type = gic_set_type, +#ifdef CONFIG_SMP + .irq_set_affinity = gic_set_affinity, +#endif +}; + +static unsigned int gic_get_local_int(void) +{ + unsigned long pending, masked; + + pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); + masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); + + bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); + + return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS); +} + +static void gic_mask_local_irq(struct irq_data *d) +{ + int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); + + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); +} + +static void gic_unmask_local_irq(struct irq_data *d) +{ + int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); + + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); +} + +static struct irq_chip gic_local_irq_controller = { + .name = "MIPS GIC Local", + .irq_mask = gic_mask_local_irq, + .irq_unmask = gic_unmask_local_irq, +}; + +static void gic_mask_local_irq_all_vpes(struct irq_data *d) +{ + int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); + int i; + unsigned long flags; + + 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_OTHER, GIC_VPE_RMASK), 1 << intr); + } + spin_unlock_irqrestore(&gic_lock, flags); +} + +static void gic_unmask_local_irq_all_vpes(struct irq_data *d) +{ + int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); + int i; + unsigned long flags; + + 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_OTHER, GIC_VPE_SMASK), 1 << intr); + } + spin_unlock_irqrestore(&gic_lock, flags); +} + +static struct irq_chip gic_all_vpes_local_irq_controller = { + .name = "MIPS GIC Local", + .irq_mask = gic_mask_local_irq_all_vpes, + .irq_unmask = gic_unmask_local_irq_all_vpes, +}; + +static void __gic_irq_dispatch(void) +{ + unsigned int intr, virq; + + while ((intr = gic_get_local_int()) != GIC_NUM_LOCAL_INTRS) { + virq = irq_linear_revmap(gic_irq_domain, + GIC_LOCAL_TO_HWIRQ(intr)); + do_IRQ(virq); + } + + while ((intr = gic_get_int()) != gic_shared_intrs) { + virq = irq_linear_revmap(gic_irq_domain, + GIC_SHARED_TO_HWIRQ(intr)); + do_IRQ(virq); + } +} + +static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc) +{ + __gic_irq_dispatch(); +} + +#ifdef CONFIG_MIPS_GIC_IPI +static int gic_resched_int_base; +static int gic_call_int_base; + +unsigned int plat_ipi_resched_int_xlate(unsigned int cpu) +{ + return gic_resched_int_base + cpu; +} + +unsigned int plat_ipi_call_int_xlate(unsigned int cpu) +{ + return gic_call_int_base + cpu; +} + +static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) +{ + scheduler_ipi(); + + return IRQ_HANDLED; +} + +static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) +{ + smp_call_function_interrupt(); + + return IRQ_HANDLED; +} + +static struct irqaction irq_resched = { + .handler = ipi_resched_interrupt, + .flags = IRQF_PERCPU, + .name = "IPI resched" +}; + +static struct irqaction irq_call = { + .handler = ipi_call_interrupt, + .flags = IRQF_PERCPU, + .name = "IPI call" +}; + +static __init void gic_ipi_init_one(unsigned int intr, int cpu, + struct irqaction *action) +{ + int virq = irq_create_mapping(gic_irq_domain, + GIC_SHARED_TO_HWIRQ(intr)); + int i; + + gic_map_to_vpe(intr, cpu); + for (i = 0; i < NR_CPUS; i++) + clear_bit(intr, pcpu_masks[i].pcpu_mask); + set_bit(intr, pcpu_masks[cpu].pcpu_mask); + + irq_set_irq_type(virq, IRQ_TYPE_EDGE_RISING); + + irq_set_handler(virq, handle_percpu_irq); + setup_irq(virq, action); +} + +static __init void gic_ipi_init(void) +{ + int i; + + /* Use last 2 * NR_CPUS interrupts as IPIs */ + gic_resched_int_base = gic_shared_intrs - nr_cpu_ids; + gic_call_int_base = gic_resched_int_base - nr_cpu_ids; + + for (i = 0; i < nr_cpu_ids; i++) { + gic_ipi_init_one(gic_call_int_base + i, i, &irq_call); + gic_ipi_init_one(gic_resched_int_base + i, i, &irq_resched); + } +} +#else +static inline void gic_ipi_init(void) +{ +} +#endif + +static void __init gic_basic_init(void) +{ + unsigned int i; + + board_bind_eic_interrupt = &gic_bind_eic_interrupt; + + /* Setup defaults */ + for (i = 0; i < gic_shared_intrs; i++) { + gic_set_polarity(i, GIC_POL_POS); + gic_set_trigger(i, GIC_TRIG_LEVEL); + gic_reset_mask(i); + } + + for (i = 0; i < gic_vpes; i++) { + unsigned int j; + + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); + for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { + if (!gic_local_irq_is_routable(j)) + continue; + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); + } + } +} + +static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + int intr = GIC_HWIRQ_TO_LOCAL(hw); + int ret = 0; + int i; + unsigned long flags; + + if (!gic_local_irq_is_routable(intr)) + return -EPERM; + + /* + * HACK: These are all really percpu interrupts, but the rest + * of the MIPS kernel code does not use the percpu IRQ API for + * the CP0 timer and performance counter interrupts. + */ + if (intr != GIC_LOCAL_INT_TIMER && intr != GIC_LOCAL_INT_PERFCTR) { + irq_set_chip_and_handler(virq, + &gic_local_irq_controller, + handle_percpu_devid_irq); + irq_set_percpu_devid(virq); + } else { + irq_set_chip_and_handler(virq, + &gic_all_vpes_local_irq_controller, + handle_percpu_irq); + } + + spin_lock_irqsave(&gic_lock, flags); + 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); + + switch (intr) { + case GIC_LOCAL_INT_WD: + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); + break; + case GIC_LOCAL_INT_COMPARE: + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val); + break; + case GIC_LOCAL_INT_TIMER: + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val); + break; + case GIC_LOCAL_INT_PERFCTR: + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val); + break; + case GIC_LOCAL_INT_SWINT0: + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val); + break; + case GIC_LOCAL_INT_SWINT1: + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val); + break; + case GIC_LOCAL_INT_FDC: + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); + break; + default: + pr_err("Invalid local IRQ %d\n", intr); + ret = -EINVAL; + break; + } + } + spin_unlock_irqrestore(&gic_lock, flags); + + return ret; +} + +static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + int intr = GIC_HWIRQ_TO_SHARED(hw); + unsigned long flags; + + irq_set_chip_and_handler(virq, &gic_level_irq_controller, + handle_level_irq); + + spin_lock_irqsave(&gic_lock, flags); + gic_map_to_pin(intr, gic_cpu_pin); + /* Map to VPE 0 by default */ + gic_map_to_vpe(intr, 0); + set_bit(intr, pcpu_masks[0].pcpu_mask); + spin_unlock_irqrestore(&gic_lock, flags); + + return 0; +} + +static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + if (GIC_HWIRQ_TO_LOCAL(hw) < GIC_NUM_LOCAL_INTRS) + return gic_local_irq_domain_map(d, virq, hw); + return gic_shared_irq_domain_map(d, virq, hw); +} + +static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, + unsigned int *out_type) +{ + if (intsize != 3) + return -EINVAL; + + if (intspec[0] == GIC_SHARED) + *out_hwirq = GIC_SHARED_TO_HWIRQ(intspec[1]); + else if (intspec[0] == GIC_LOCAL) + *out_hwirq = GIC_LOCAL_TO_HWIRQ(intspec[1]); + else + return -EINVAL; + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + + return 0; +} + +static struct irq_domain_ops gic_irq_domain_ops = { + .map = gic_irq_domain_map, + .xlate = gic_irq_domain_xlate, +}; + +static void __init __gic_init(unsigned long gic_base_addr, + unsigned long gic_addrspace_size, + unsigned int cpu_vec, unsigned int irqbase, + struct device_node *node) +{ + unsigned int gicconfig; + + gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size); + + gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG)); + gic_shared_intrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> + GIC_SH_CONFIG_NUMINTRS_SHF; + gic_shared_intrs = ((gic_shared_intrs + 1) * 8); + + gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> + GIC_SH_CONFIG_NUMVPES_SHF; + gic_vpes = gic_vpes + 1; + + if (cpu_has_veic) { + /* Always use vector 1 in EIC mode */ + gic_cpu_pin = 0; + set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET, + __gic_irq_dispatch); + } else { + gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET; + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec, + gic_irq_dispatch); + } + + gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + + gic_shared_intrs, irqbase, + &gic_irq_domain_ops, NULL); + if (!gic_irq_domain) + panic("Failed to add GIC IRQ domain"); + + gic_basic_init(); + + gic_ipi_init(); +} + +void __init gic_init(unsigned long gic_base_addr, + unsigned long gic_addrspace_size, + unsigned int cpu_vec, unsigned int irqbase) +{ + __gic_init(gic_base_addr, gic_addrspace_size, cpu_vec, irqbase, NULL); +} + +static int __init gic_of_init(struct device_node *node, + struct device_node *parent) +{ + struct resource res; + unsigned int cpu_vec, i = 0, reserved = 0; + phys_addr_t gic_base; + size_t gic_len; + + /* Find the first available CPU vector. */ + while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors", + i++, &cpu_vec)) + reserved |= BIT(cpu_vec); + for (cpu_vec = 2; cpu_vec < 8; cpu_vec++) { + if (!(reserved & BIT(cpu_vec))) + break; + } + if (cpu_vec == 8) { + pr_err("No CPU vectors available for GIC\n"); + return -ENODEV; + } + + if (of_address_to_resource(node, 0, &res)) { + /* + * Probe the CM for the GIC base address if not specified + * in the device-tree. + */ + if (mips_cm_present()) { + gic_base = read_gcr_gic_base() & + ~CM_GCR_GIC_BASE_GICEN_MSK; + gic_len = 0x20000; + } else { + pr_err("Failed to get GIC memory range\n"); + return -ENODEV; + } + } else { + gic_base = res.start; + gic_len = resource_size(&res); + } + + if (mips_cm_present()) + write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN_MSK); + gic_present = true; + + __gic_init(gic_base, gic_len, cpu_vec, 0, node); + + return 0; +} +IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init); diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 93caf8e68..2399a39 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,12 +1,13 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" - depends on PCI && MAC80211 + depends on (PCI || ATH25) && MAC80211 select ATH_COMMON select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS select AVERAGE - select ATH5K_PCI + select ATH5K_AHB if ATH25 + select ATH5K_PCI if !ATH25 ---help--- This module adds support for wireless adapters based on Atheros 5xxx chipset. @@ -51,9 +52,16 @@ config ATH5K_TRACER If unsure, say N. +config ATH5K_AHB + bool "Atheros 5xxx AHB bus support" + depends on ATH25 + ---help--- + This adds support for WiSoC type chipsets of the 5xxx Atheros + family. + config ATH5K_PCI bool "Atheros 5xxx PCI bus support" - depends on PCI + depends on (!ATH25 && PCI) ---help--- This adds support for PCI type chipsets of the 5xxx Atheros family. diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index 51e2d86..1b3a34f 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -17,5 +17,6 @@ ath5k-y += ani.o ath5k-y += sysfs.o ath5k-y += mac80211-ops.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o +ath5k-$(CONFIG_ATH5K_AHB) += ahb.o ath5k-$(CONFIG_ATH5K_PCI) += pci.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c new file mode 100644 index 0000000..8f387cf --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2008-2009 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org> + * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/nl80211.h> +#include <linux/platform_device.h> +#include <linux/etherdevice.h> +#include <linux/export.h> +#include <ath25_platform.h> +#include "ath5k.h" +#include "debug.h" +#include "base.h" +#include "reg.h" + +/* return bus cachesize in 4B word units */ +static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz) +{ + *csz = L1_CACHE_BYTES >> 2; +} + +static bool +ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) +{ + struct ath5k_hw *ah = common->priv; + struct platform_device *pdev = to_platform_device(ah->dev); + struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev); + u16 *eeprom, *eeprom_end; + + eeprom = (u16 *) bcfg->radio; + eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ; + + eeprom += off; + if (eeprom > eeprom_end) + return false; + + *data = *eeprom; + return true; +} + +int ath5k_hw_read_srev(struct ath5k_hw *ah) +{ + struct platform_device *pdev = to_platform_device(ah->dev); + struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev); + ah->ah_mac_srev = bcfg->devid; + return 0; +} + +static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + struct platform_device *pdev = to_platform_device(ah->dev); + struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev); + u8 *cfg_mac; + + if (to_platform_device(ah->dev)->id == 0) + cfg_mac = bcfg->config->wlan0_mac; + else + cfg_mac = bcfg->config->wlan1_mac; + + memcpy(mac, cfg_mac, ETH_ALEN); + return 0; +} + +static const struct ath_bus_ops ath_ahb_bus_ops = { + .ath_bus_type = ATH_AHB, + .read_cachesize = ath5k_ahb_read_cachesize, + .eeprom_read = ath5k_ahb_eeprom_read, + .eeprom_read_mac = ath5k_ahb_eeprom_read_mac, +}; + +/*Initialization*/ +static int ath_ahb_probe(struct platform_device *pdev) +{ + struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev); + struct ath5k_hw *ah; + struct ieee80211_hw *hw; + struct resource *res; + void __iomem *mem; + int irq; + int ret = 0; + u32 reg; + + if (!dev_get_platdata(&pdev->dev)) { + dev_err(&pdev->dev, "no platform data specified\n"); + ret = -EINVAL; + goto err_out; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no memory resource found\n"); + ret = -ENXIO; + goto err_out; + } + + mem = ioremap_nocache(res->start, resource_size(res)); + if (mem == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err_out; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no IRQ resource found\n"); + ret = -ENXIO; + goto err_iounmap; + } + + irq = res->start; + + hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops); + if (hw == NULL) { + dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); + ret = -ENOMEM; + goto err_iounmap; + } + + ah = hw->priv; + ah->hw = hw; + ah->dev = &pdev->dev; + ah->iobase = mem; + ah->irq = irq; + ah->devid = bcfg->devid; + + if (bcfg->devid >= AR5K_SREV_AR2315_R6) { + /* Enable WMAC AHB arbitration */ + reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN; + iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + + /* Enable global WMAC swapping */ + reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP); + reg |= AR5K_AR2315_BYTESWAP_WMAC; + iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP); + } else { + /* Enable WMAC DMA access (assuming 5312 or 231x*/ + /* TODO: check other platforms */ + reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE); + if (to_platform_device(ah->dev)->id == 0) + reg |= AR5K_AR5312_ENABLE_WLAN0; + else + reg |= AR5K_AR5312_ENABLE_WLAN1; + iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE); + + /* + * On a dual-band AR5312, the multiband radio is only + * used as pass-through. Disable 2 GHz support in the + * driver for it + */ + if (to_platform_device(ah->dev)->id == 0 && + (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) == + (BD_WLAN1 | BD_WLAN0)) + ah->ah_capabilities.cap_needs_2GHz_ovr = true; + else + ah->ah_capabilities.cap_needs_2GHz_ovr = false; + } + + ret = ath5k_init_ah(ah, &ath_ahb_bus_ops); + if (ret != 0) { + dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); + ret = -ENODEV; + goto err_free_hw; + } + + platform_set_drvdata(pdev, hw); + + return 0; + + err_free_hw: + ieee80211_free_hw(hw); + err_iounmap: + iounmap(mem); + err_out: + return ret; +} + +static int ath_ahb_remove(struct platform_device *pdev) +{ + struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev); + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct ath5k_hw *ah; + u32 reg; + + if (!hw) + return 0; + + ah = hw->priv; + + if (bcfg->devid >= AR5K_SREV_AR2315_R6) { + /* Disable WMAC AHB arbitration */ + reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN; + iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL); + } else { + /*Stop DMA access */ + reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE); + if (to_platform_device(ah->dev)->id == 0) + reg &= ~AR5K_AR5312_ENABLE_WLAN0; + else + reg &= ~AR5K_AR5312_ENABLE_WLAN1; + iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE); + } + + ath5k_deinit_ah(ah); + iounmap(ah->iobase); + ieee80211_free_hw(hw); + + return 0; +} + +static struct platform_driver ath_ahb_driver = { + .probe = ath_ahb_probe, + .remove = ath_ahb_remove, + .driver = { + .name = "ar231x-wmac", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(ath_ahb_driver); diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index ed24682..1ed7a88 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1647,6 +1647,32 @@ static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah) return &(ath5k_hw_common(ah)->regulatory); } +#ifdef CONFIG_ATH5K_AHB +#define AR5K_AR2315_PCI_BASE ((void __iomem *)0xb0100000) + +static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg) +{ + /* On AR2315 and AR2317 the PCI clock domain registers + * are outside of the WMAC register space */ + if (unlikely((reg >= 0x4000) && (reg < 0x5000) && + (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6))) + return AR5K_AR2315_PCI_BASE + reg; + + return ah->iobase + reg; +} + +static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) +{ + return ioread32(ath5k_ahb_reg(ah, reg)); +} + +static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) +{ + iowrite32(val, ath5k_ahb_reg(ah, reg)); +} + +#else + static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) { return ioread32(ah->iobase + reg); @@ -1657,6 +1683,8 @@ static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) iowrite32(val, ah->iobase + reg); } +#endif + static inline enum ath_bus_type ath5k_get_bus_type(struct ath5k_hw *ah) { return ath5k_hw_common(ah)->bus_ops->ath_bus_type; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a4a09bb..bc9cb35 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -99,6 +99,15 @@ static int ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, /* Known SREVs */ static const struct ath5k_srev_name srev_names[] = { +#ifdef CONFIG_ATH5K_AHB + { "5312", AR5K_VERSION_MAC, AR5K_SREV_AR5312_R2 }, + { "5312", AR5K_VERSION_MAC, AR5K_SREV_AR5312_R7 }, + { "2313", AR5K_VERSION_MAC, AR5K_SREV_AR2313_R8 }, + { "2315", AR5K_VERSION_MAC, AR5K_SREV_AR2315_R6 }, + { "2315", AR5K_VERSION_MAC, AR5K_SREV_AR2315_R7 }, + { "2317", AR5K_VERSION_MAC, AR5K_SREV_AR2317_R1 }, + { "2317", AR5K_VERSION_MAC, AR5K_SREV_AR2317_R2 }, +#else { "5210", AR5K_VERSION_MAC, AR5K_SREV_AR5210 }, { "5311", AR5K_VERSION_MAC, AR5K_SREV_AR5311 }, { "5311A", AR5K_VERSION_MAC, AR5K_SREV_AR5311A }, @@ -117,6 +126,7 @@ static const struct ath5k_srev_name srev_names[] = { { "5418", AR5K_VERSION_MAC, AR5K_SREV_AR5418 }, { "2425", AR5K_VERSION_MAC, AR5K_SREV_AR2425 }, { "2417", AR5K_VERSION_MAC, AR5K_SREV_AR2417 }, +#endif { "xxxxx", AR5K_VERSION_MAC, AR5K_SREV_UNKNOWN }, { "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 }, { "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 }, @@ -132,6 +142,10 @@ static const struct ath5k_srev_name srev_names[] = { { "5413", AR5K_VERSION_RAD, AR5K_SREV_RAD_5413 }, { "5424", AR5K_VERSION_RAD, AR5K_SREV_RAD_5424 }, { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, +#ifdef CONFIG_ATH5K_AHB + { "2316", AR5K_VERSION_RAD, AR5K_SREV_RAD_2316 }, + { "2317", AR5K_VERSION_RAD, AR5K_SREV_RAD_2317 }, +#endif { "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, }; diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 0beb7e7..ca4b7cc 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -163,14 +163,20 @@ int ath5k_init_leds(struct ath5k_hw *ah) { int ret = 0; struct ieee80211_hw *hw = ah->hw; +#ifndef CONFIG_ATH5K_AHB struct pci_dev *pdev = ah->pdev; +#endif char name[ATH5K_LED_MAX_NAME_LEN + 1]; const struct pci_device_id *match; if (!ah->pdev) return 0; +#ifdef CONFIG_ATH5K_AHB + match = NULL; +#else match = pci_match_id(&ath5k_led_devices[0], pdev); +#endif if (match) { __set_bit(ATH_STAT_LEDSOFT, ah->status); ah->led_pin = ATH_PIN(match->driver_data); diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index b0ce7cd..910e90b 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -147,7 +147,6 @@ config TCIC config PCMCIA_ALCHEMY_DEVBOARD tristate "Alchemy Db/Pb1xxx PCMCIA socket services" depends on MIPS_ALCHEMY && PCMCIA - select 64BIT_PHYS_ADDR help Enable this driver of you want PCMCIA support on your Alchemy Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200, DB1300 @@ -158,7 +157,6 @@ config PCMCIA_ALCHEMY_DEVBOARD config PCMCIA_XXS1500 tristate "MyCable XXS1500 PCMCIA socket support" depends on PCMCIA && MIPS_XXS1500 - select 64BIT_PHYS_ADDR help Support for the PCMCIA/CF socket interface on MyCable XXS1500 systems. diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 0907706..7b986f9 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c @@ -15,6 +15,9 @@ #include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/time.h> +#ifdef CONFIG_BCM47XX +#include <bcm47xx_nvram.h> +#endif #include "ssb_private.h" @@ -210,6 +213,7 @@ static void ssb_mips_serial_init(struct ssb_mipscore *mcore) static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) { struct ssb_bus *bus = mcore->dev->bus; + struct ssb_sflash *sflash = &mcore->sflash; struct ssb_pflash *pflash = &mcore->pflash; /* When there is no chipcommon on the bus there is 4MB flash */ @@ -242,7 +246,15 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore) } ssb_pflash: - if (pflash->present) { + if (sflash->present) { +#ifdef CONFIG_BCM47XX + bcm47xx_nvram_init_from_mem(sflash->window, sflash->size); +#endif + } else if (pflash->present) { +#ifdef CONFIG_BCM47XX + bcm47xx_nvram_init_from_mem(pflash->window, pflash->window_size); +#endif + ssb_pflash_data.width = pflash->buswidth; ssb_pflash_resource.start = pflash->window; ssb_pflash_resource.end = pflash->window + pflash->window_size; diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c index 9465623..3be9519 100644 --- a/drivers/tc/tc.c +++ b/drivers/tc/tc.c @@ -83,8 +83,7 @@ static void __init tc_bus_add_devices(struct tc_bus *tbus) /* Found a board, allocate it an entry in the list */ tdev = kzalloc(sizeof(*tdev), GFP_KERNEL); if (!tdev) { - printk(KERN_ERR "tc%x: unable to allocate tc_dev\n", - slot); + pr_err("tc%x: unable to allocate tc_dev\n", slot); goto out_err; } dev_set_name(&tdev->dev, "tc%x", slot); @@ -117,10 +116,10 @@ static void __init tc_bus_add_devices(struct tc_bus *tbus) tdev->resource.start = extslotaddr; tdev->resource.end = extslotaddr + devsize - 1; } else { - printk(KERN_ERR "%s: Cannot provide slot space " - "(%dMiB required, up to %dMiB supported)\n", - dev_name(&tdev->dev), devsize >> 20, - max(slotsize, extslotsize) >> 20); + pr_err("%s: Cannot provide slot space " + "(%ldMiB required, up to %ldMiB supported)\n", + dev_name(&tdev->dev), (long)(devsize >> 20), + (long)(max(slotsize, extslotsize) >> 20)); kfree(tdev); goto out_err; } @@ -147,14 +146,12 @@ static int __init tc_init(void) { /* Initialize the TURBOchannel bus */ if (tc_bus_get_info(&tc_bus)) - return 0; + goto out_err; INIT_LIST_HEAD(&tc_bus.devices); dev_set_name(&tc_bus.dev, "tc"); - if (device_register(&tc_bus.dev)) { - put_device(&tc_bus.dev); - return 0; - } + if (device_register(&tc_bus.dev)) + goto out_err_device; if (tc_bus.info.slot_size) { unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000; @@ -172,8 +169,8 @@ static int __init tc_init(void) tc_bus.resource[0].flags = IORESOURCE_MEM; if (request_resource(&iomem_resource, &tc_bus.resource[0]) < 0) { - printk(KERN_ERR "tc: Cannot reserve resource\n"); - return 0; + pr_err("tc: Cannot reserve resource\n"); + goto out_err_device; } if (tc_bus.ext_slot_size) { tc_bus.resource[1].start = tc_bus.ext_slot_base; @@ -184,10 +181,8 @@ static int __init tc_init(void) tc_bus.resource[1].flags = IORESOURCE_MEM; if (request_resource(&iomem_resource, &tc_bus.resource[1]) < 0) { - printk(KERN_ERR - "tc: Cannot reserve resource\n"); - release_resource(&tc_bus.resource[0]); - return 0; + pr_err("tc: Cannot reserve resource\n"); + goto out_err_resource; } } @@ -195,6 +190,13 @@ static int __init tc_init(void) } return 0; + +out_err_resource: + release_resource(&tc_bus.resource[0]); +out_err_device: + put_device(&tc_bus.dev); +out_err: + return 0; } subsys_initcall(tc_init); diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 370b24c..c055d56 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -30,6 +30,9 @@ config COMPAT_BINFMT_ELF config ARCH_BINFMT_ELF_RANDOMIZE_PIE bool +config ARCH_BINFMT_ELF_STATE + bool + config BINFMT_ELF_FDPIC bool "Kernel support for FDPIC ELF binaries" default y diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 3a6175f..02b1691 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -386,6 +386,127 @@ static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) ELF_PAGESTART(cmds[first_idx].p_vaddr); } +/** + * load_elf_phdrs() - load ELF program headers + * @elf_ex: ELF header of the binary whose program headers should be loaded + * @elf_file: the opened ELF binary file + * + * Loads ELF program headers from the binary file elf_file, which has the ELF + * header pointed to by elf_ex, into a newly allocated array. The caller is + * responsible for freeing the allocated data. Returns an ERR_PTR upon failure. + */ +static struct elf_phdr *load_elf_phdrs(struct elfhdr *elf_ex, + struct file *elf_file) +{ + struct elf_phdr *elf_phdata = NULL; + int retval, size, err = -1; + + /* + * If the size of this structure has changed, then punt, since + * we will be doing the wrong thing. + */ + if (elf_ex->e_phentsize != sizeof(struct elf_phdr)) + goto out; + + /* Sanity check the number of program headers... */ + if (elf_ex->e_phnum < 1 || + elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) + goto out; + + /* ...and their total size. */ + size = sizeof(struct elf_phdr) * elf_ex->e_phnum; + if (size > ELF_MIN_ALIGN) + goto out; + + elf_phdata = kmalloc(size, GFP_KERNEL); + if (!elf_phdata) + goto out; + + /* Read in the program headers */ + retval = kernel_read(elf_file, elf_ex->e_phoff, + (char *)elf_phdata, size); + if (retval != size) { + err = (retval < 0) ? retval : -EIO; + goto out; + } + + /* Success! */ + err = 0; +out: + if (err) { + kfree(elf_phdata); + elf_phdata = NULL; + } + return elf_phdata; +} + +#ifndef CONFIG_ARCH_BINFMT_ELF_STATE + +/** + * struct arch_elf_state - arch-specific ELF loading state + * + * This structure is used to preserve architecture specific data during + * the loading of an ELF file, throughout the checking of architecture + * specific ELF headers & through to the point where the ELF load is + * known to be proceeding (ie. SET_PERSONALITY). + * + * This implementation is a dummy for architectures which require no + * specific state. + */ +struct arch_elf_state { +}; + +#define INIT_ARCH_ELF_STATE {} + +/** + * arch_elf_pt_proc() - check a PT_LOPROC..PT_HIPROC ELF program header + * @ehdr: The main ELF header + * @phdr: The program header to check + * @elf: The open ELF file + * @is_interp: True if the phdr is from the interpreter of the ELF being + * loaded, else false. + * @state: Architecture-specific state preserved throughout the process + * of loading the ELF. + * + * Inspects the program header phdr to validate its correctness and/or + * suitability for the system. Called once per ELF program header in the + * range PT_LOPROC to PT_HIPROC, for both the ELF being loaded and its + * interpreter. + * + * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load + * with that return code. + */ +static inline int arch_elf_pt_proc(struct elfhdr *ehdr, + struct elf_phdr *phdr, + struct file *elf, bool is_interp, + struct arch_elf_state *state) +{ + /* Dummy implementation, always proceed */ + return 0; +} + +/** + * arch_check_elf() - check a PT_LOPROC..PT_HIPROC ELF program header + * @ehdr: The main ELF header + * @has_interp: True if the ELF has an interpreter, else false. + * @state: Architecture-specific state preserved throughout the process + * of loading the ELF. + * + * Provides a final opportunity for architecture code to reject the loading + * of the ELF & cause an exec syscall to return an error. This is called after + * all program headers to be checked by arch_elf_pt_proc have been. + * + * Return: Zero to proceed with the ELF load, non-zero to fail the ELF load + * with that return code. + */ +static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp, + struct arch_elf_state *state) +{ + /* Dummy implementation, always proceed */ + return 0; +} + +#endif /* !CONFIG_ARCH_BINFMT_ELF_STATE */ /* This is much more generalized than the library routine read function, so we keep this separate. Technically the library read function @@ -394,16 +515,15 @@ static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr) static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, struct file *interpreter, unsigned long *interp_map_addr, - unsigned long no_base) + unsigned long no_base, struct elf_phdr *interp_elf_phdata) { - struct elf_phdr *elf_phdata; struct elf_phdr *eppnt; unsigned long load_addr = 0; int load_addr_set = 0; unsigned long last_bss = 0, elf_bss = 0; unsigned long error = ~0UL; unsigned long total_size; - int retval, i, size; + int i; /* First of all, some simple consistency checks */ if (interp_elf_ex->e_type != ET_EXEC && @@ -414,40 +534,14 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, if (!interpreter->f_op->mmap) goto out; - /* - * If the size of this structure has changed, then punt, since - * we will be doing the wrong thing. - */ - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) - goto out; - if (interp_elf_ex->e_phnum < 1 || - interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) - goto out; - - /* Now read in all of the header information */ - size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum; - if (size > ELF_MIN_ALIGN) - goto out; - elf_phdata = kmalloc(size, GFP_KERNEL); - if (!elf_phdata) - goto out; - - retval = kernel_read(interpreter, interp_elf_ex->e_phoff, - (char *)elf_phdata, size); - error = -EIO; - if (retval != size) { - if (retval < 0) - error = retval; - goto out_close; - } - - total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum); + total_size = total_mapping_size(interp_elf_phdata, + interp_elf_ex->e_phnum); if (!total_size) { error = -EINVAL; - goto out_close; + goto out; } - eppnt = elf_phdata; + eppnt = interp_elf_phdata; for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; @@ -474,7 +568,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, *interp_map_addr = map_addr; error = map_addr; if (BAD_ADDR(map_addr)) - goto out_close; + goto out; if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { @@ -493,7 +587,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, eppnt->p_memsz > TASK_SIZE || TASK_SIZE - eppnt->p_memsz < k) { error = -ENOMEM; - goto out_close; + goto out; } /* @@ -523,7 +617,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, */ if (padzero(elf_bss)) { error = -EFAULT; - goto out_close; + goto out; } /* What we have mapped so far */ @@ -532,13 +626,10 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, /* Map the last of the bss segment */ error = vm_brk(elf_bss, last_bss - elf_bss); if (BAD_ADDR(error)) - goto out_close; + goto out; } error = load_addr; - -out_close: - kfree(elf_phdata); out: return error; } @@ -575,10 +666,9 @@ static int load_elf_binary(struct linux_binprm *bprm) int load_addr_set = 0; char * elf_interpreter = NULL; unsigned long error; - struct elf_phdr *elf_ppnt, *elf_phdata; + struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; unsigned long elf_bss, elf_brk; int retval, i; - unsigned int size; unsigned long elf_entry; unsigned long interp_load_addr = 0; unsigned long start_code, end_code, start_data, end_data; @@ -589,6 +679,7 @@ static int load_elf_binary(struct linux_binprm *bprm) struct elfhdr elf_ex; struct elfhdr interp_elf_ex; } *loc; + struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE; loc = kmalloc(sizeof(*loc), GFP_KERNEL); if (!loc) { @@ -611,26 +702,10 @@ static int load_elf_binary(struct linux_binprm *bprm) if (!bprm->file->f_op->mmap) goto out; - /* Now read in all of the header information */ - if (loc->elf_ex.e_phentsize != sizeof(struct elf_phdr)) - goto out; - if (loc->elf_ex.e_phnum < 1 || - loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr)) - goto out; - size = loc->elf_ex.e_phnum * sizeof(struct elf_phdr); - retval = -ENOMEM; - elf_phdata = kmalloc(size, GFP_KERNEL); + elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file); if (!elf_phdata) goto out; - retval = kernel_read(bprm->file, loc->elf_ex.e_phoff, - (char *)elf_phdata, size); - if (retval != size) { - if (retval >= 0) - retval = -EIO; - goto out_free_ph; - } - elf_ppnt = elf_phdata; elf_bss = 0; elf_brk = 0; @@ -699,12 +774,21 @@ static int load_elf_binary(struct linux_binprm *bprm) elf_ppnt = elf_phdata; for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) - if (elf_ppnt->p_type == PT_GNU_STACK) { + switch (elf_ppnt->p_type) { + case PT_GNU_STACK: if (elf_ppnt->p_flags & PF_X) executable_stack = EXSTACK_ENABLE_X; else executable_stack = EXSTACK_DISABLE_X; break; + + case PT_LOPROC ... PT_HIPROC: + retval = arch_elf_pt_proc(&loc->elf_ex, elf_ppnt, + bprm->file, false, + &arch_state); + if (retval) + goto out_free_dentry; + break; } /* Some simple consistency checks for the interpreter */ @@ -716,8 +800,36 @@ static int load_elf_binary(struct linux_binprm *bprm) /* Verify the interpreter has a valid arch */ if (!elf_check_arch(&loc->interp_elf_ex)) goto out_free_dentry; + + /* Load the interpreter program headers */ + interp_elf_phdata = load_elf_phdrs(&loc->interp_elf_ex, + interpreter); + if (!interp_elf_phdata) + goto out_free_dentry; + + /* Pass PT_LOPROC..PT_HIPROC headers to arch code */ + elf_ppnt = interp_elf_phdata; + for (i = 0; i < loc->interp_elf_ex.e_phnum; i++, elf_ppnt++) + switch (elf_ppnt->p_type) { + case PT_LOPROC ... PT_HIPROC: + retval = arch_elf_pt_proc(&loc->interp_elf_ex, + elf_ppnt, interpreter, + true, &arch_state); + if (retval) + goto out_free_dentry; + break; + } } + /* + * Allow arch code to reject the ELF at this point, whilst it's + * still possible to return an error to the code that invoked + * the exec syscall. + */ + retval = arch_check_elf(&loc->elf_ex, !!interpreter, &arch_state); + if (retval) + goto out_free_dentry; + /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) @@ -725,7 +837,7 @@ static int load_elf_binary(struct linux_binprm *bprm) /* Do this immediately, since STACK_TOP as used in setup_arg_pages may depend on the personality. */ - SET_PERSONALITY(loc->elf_ex); + SET_PERSONALITY2(loc->elf_ex, &arch_state); if (elf_read_implies_exec(loc->elf_ex, executable_stack)) current->personality |= READ_IMPLIES_EXEC; @@ -890,7 +1002,7 @@ static int load_elf_binary(struct linux_binprm *bprm) elf_entry = load_elf_interp(&loc->interp_elf_ex, interpreter, &interp_map_addr, - load_bias); + load_bias, interp_elf_phdata); if (!IS_ERR((void *)elf_entry)) { /* * load_elf_interp() returns relocation @@ -917,6 +1029,7 @@ static int load_elf_binary(struct linux_binprm *bprm) } } + kfree(interp_elf_phdata); kfree(elf_phdata); set_binfmt(&elf_format); @@ -981,6 +1094,7 @@ out_ret: /* error cleanup */ out_free_dentry: + kfree(interp_elf_phdata); allow_write_access(interpreter); if (interpreter) fput(interpreter); diff --git a/include/dt-bindings/interrupt-controller/mips-gic.h b/include/dt-bindings/interrupt-controller/mips-gic.h new file mode 100644 index 0000000..cf35a57 --- /dev/null +++ b/include/dt-bindings/interrupt-controller/mips-gic.h @@ -0,0 +1,9 @@ +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_GIC_H +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_GIC_H + +#include <dt-bindings/interrupt-controller/irq.h> + +#define GIC_SHARED 0 +#define GIC_LOCAL 1 + +#endif diff --git a/include/linux/elf.h b/include/linux/elf.h index 67a5fa7..20fa8d8 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -15,6 +15,11 @@ set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif +#ifndef SET_PERSONALITY2 +#define SET_PERSONALITY2(ex, state) \ + SET_PERSONALITY(ex) +#endif + #if ELF_CLASS == ELFCLASS32 extern Elf32_Dyn _DYNAMIC []; diff --git a/arch/mips/include/asm/gic.h b/include/linux/irqchip/mips-gic.h index d7699cf..420f77b 100644 --- a/arch/mips/include/asm/gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -4,57 +4,26 @@ * for more details. * * Copyright (C) 2000, 07 MIPS Technologies, Inc. - * - * GIC Register Definitions - * */ -#ifndef _ASM_GICREGS_H -#define _ASM_GICREGS_H - -#include <linux/bitmap.h> -#include <linux/threads.h> +#ifndef __LINUX_IRQCHIP_MIPS_GIC_H +#define __LINUX_IRQCHIP_MIPS_GIC_H -#include <irq.h> +#include <linux/clocksource.h> -#undef GICISBYTELITTLEENDIAN +#define GIC_MAX_INTRS 256 /* Constants */ #define GIC_POL_POS 1 #define GIC_POL_NEG 0 #define GIC_TRIG_EDGE 1 #define GIC_TRIG_LEVEL 0 +#define GIC_TRIG_DUAL_ENABLE 1 +#define GIC_TRIG_DUAL_DISABLE 0 #define MSK(n) ((1 << (n)) - 1) -#define REG32(addr) (*(volatile unsigned int *) (addr)) -#define REG(base, offs) REG32((unsigned long)(base) + offs##_##OFS) -#define REGP(base, phys) REG32((unsigned long)(base) + (phys)) /* Accessors */ -#define GIC_REG(segment, offset) \ - REG32(_gic_base + segment##_##SECTION_OFS + offset##_##OFS) -#define GIC_REG_ADDR(segment, offset) \ - REG32(_gic_base + segment##_##SECTION_OFS + offset) - -#define GIC_ABS_REG(segment, offset) \ - (_gic_base + segment##_##SECTION_OFS + offset##_##OFS) -#define GIC_REG_ABS_ADDR(segment, offset) \ - (_gic_base + segment##_##SECTION_OFS + offset) - -#ifdef GICISBYTELITTLEENDIAN -#define GICREAD(reg, data) ((data) = (reg), (data) = le32_to_cpu(data)) -#define GICWRITE(reg, data) ((reg) = cpu_to_le32(data)) -#else -#define GICREAD(reg, data) ((data) = (reg)) -#define GICWRITE(reg, data) ((reg) = (data)) -#endif -#define GICBIS(reg, mask, bits) \ - do { u32 data; \ - GICREAD(reg, data); \ - data &= ~(mask); \ - data |= ((bits) & (mask)); \ - GICWRITE((reg), data); \ - } while (0) - +#define GIC_REG(segment, offset) (segment##_##SECTION_OFS + offset##_##OFS) /* GIC Address Space */ #define SHARED_SECTION_OFS 0x0000 @@ -75,120 +44,42 @@ #define GIC_SH_COUNTER_63_32_OFS 0x0014 #define GIC_SH_REVISIONID_OFS 0x0020 -/* Interrupt Polarity */ -#define GIC_SH_POL_31_0_OFS 0x0100 -#define GIC_SH_POL_63_32_OFS 0x0104 -#define GIC_SH_POL_95_64_OFS 0x0108 -#define GIC_SH_POL_127_96_OFS 0x010c -#define GIC_SH_POL_159_128_OFS 0x0110 -#define GIC_SH_POL_191_160_OFS 0x0114 -#define GIC_SH_POL_223_192_OFS 0x0118 -#define GIC_SH_POL_255_224_OFS 0x011c - -/* Edge/Level Triggering */ -#define GIC_SH_TRIG_31_0_OFS 0x0180 -#define GIC_SH_TRIG_63_32_OFS 0x0184 -#define GIC_SH_TRIG_95_64_OFS 0x0188 -#define GIC_SH_TRIG_127_96_OFS 0x018c -#define GIC_SH_TRIG_159_128_OFS 0x0190 -#define GIC_SH_TRIG_191_160_OFS 0x0194 -#define GIC_SH_TRIG_223_192_OFS 0x0198 -#define GIC_SH_TRIG_255_224_OFS 0x019c - -/* Dual Edge Triggering */ -#define GIC_SH_DUAL_31_0_OFS 0x0200 -#define GIC_SH_DUAL_63_32_OFS 0x0204 -#define GIC_SH_DUAL_95_64_OFS 0x0208 -#define GIC_SH_DUAL_127_96_OFS 0x020c -#define GIC_SH_DUAL_159_128_OFS 0x0210 -#define GIC_SH_DUAL_191_160_OFS 0x0214 -#define GIC_SH_DUAL_223_192_OFS 0x0218 -#define GIC_SH_DUAL_255_224_OFS 0x021c +/* Convert an interrupt number to a byte offset/bit for multi-word registers */ +#define GIC_INTR_OFS(intr) (((intr) / 32) * 4) +#define GIC_INTR_BIT(intr) ((intr) % 32) + +/* Polarity : Reset Value is always 0 */ +#define GIC_SH_SET_POLARITY_OFS 0x0100 + +/* Triggering : Reset Value is always 0 */ +#define GIC_SH_SET_TRIGGER_OFS 0x0180 + +/* Dual edge triggering : Reset Value is always 0 */ +#define GIC_SH_SET_DUAL_OFS 0x0200 /* Set/Clear corresponding bit in Edge Detect Register */ #define GIC_SH_WEDGE_OFS 0x0280 -/* Reset Mask - Disables Interrupt */ -#define GIC_SH_RMASK_31_0_OFS 0x0300 -#define GIC_SH_RMASK_63_32_OFS 0x0304 -#define GIC_SH_RMASK_95_64_OFS 0x0308 -#define GIC_SH_RMASK_127_96_OFS 0x030c -#define GIC_SH_RMASK_159_128_OFS 0x0310 -#define GIC_SH_RMASK_191_160_OFS 0x0314 -#define GIC_SH_RMASK_223_192_OFS 0x0318 -#define GIC_SH_RMASK_255_224_OFS 0x031c - -/* Set Mask (WO) - Enables Interrupt */ -#define GIC_SH_SMASK_31_0_OFS 0x0380 -#define GIC_SH_SMASK_63_32_OFS 0x0384 -#define GIC_SH_SMASK_95_64_OFS 0x0388 -#define GIC_SH_SMASK_127_96_OFS 0x038c -#define GIC_SH_SMASK_159_128_OFS 0x0390 -#define GIC_SH_SMASK_191_160_OFS 0x0394 -#define GIC_SH_SMASK_223_192_OFS 0x0398 -#define GIC_SH_SMASK_255_224_OFS 0x039c +/* Mask manipulation */ +#define GIC_SH_RMASK_OFS 0x0300 +#define GIC_SH_SMASK_OFS 0x0380 /* Global Interrupt Mask Register (RO) - Bit Set == Interrupt enabled */ -#define GIC_SH_MASK_31_0_OFS 0x0400 -#define GIC_SH_MASK_63_32_OFS 0x0404 -#define GIC_SH_MASK_95_64_OFS 0x0408 -#define GIC_SH_MASK_127_96_OFS 0x040c -#define GIC_SH_MASK_159_128_OFS 0x0410 -#define GIC_SH_MASK_191_160_OFS 0x0414 -#define GIC_SH_MASK_223_192_OFS 0x0418 -#define GIC_SH_MASK_255_224_OFS 0x041c +#define GIC_SH_MASK_OFS 0x0400 /* Pending Global Interrupts (RO) */ -#define GIC_SH_PEND_31_0_OFS 0x0480 -#define GIC_SH_PEND_63_32_OFS 0x0484 -#define GIC_SH_PEND_95_64_OFS 0x0488 -#define GIC_SH_PEND_127_96_OFS 0x048c -#define GIC_SH_PEND_159_128_OFS 0x0490 -#define GIC_SH_PEND_191_160_OFS 0x0494 -#define GIC_SH_PEND_223_192_OFS 0x0498 -#define GIC_SH_PEND_255_224_OFS 0x049c - -#define GIC_SH_INTR_MAP_TO_PIN_BASE_OFS 0x0500 +#define GIC_SH_PEND_OFS 0x0480 /* Maps Interrupt X to a Pin */ -#define GIC_SH_MAP_TO_PIN(intr) \ - (GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + (4 * intr)) - -#define GIC_SH_INTR_MAP_TO_VPE_BASE_OFS 0x2000 +#define GIC_SH_INTR_MAP_TO_PIN_BASE_OFS 0x0500 +#define GIC_SH_MAP_TO_PIN(intr) (4 * (intr)) /* Maps Interrupt X to a VPE */ +#define GIC_SH_INTR_MAP_TO_VPE_BASE_OFS 0x2000 #define GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe) \ - (GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + (32 * (intr)) + (((vpe) / 32) * 4)) + ((32 * (intr)) + (((vpe) / 32) * 4)) #define GIC_SH_MAP_TO_VPE_REG_BIT(vpe) (1 << ((vpe) % 32)) -/* Convert an interrupt number to a byte offset/bit for multi-word registers */ -#define GIC_INTR_OFS(intr) (((intr) / 32)*4) -#define GIC_INTR_BIT(intr) ((intr) % 32) - -/* Polarity : Reset Value is always 0 */ -#define GIC_SH_SET_POLARITY_OFS 0x0100 -#define GIC_SET_POLARITY(intr, pol) \ - GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_POLARITY_OFS + \ - GIC_INTR_OFS(intr)), (1 << GIC_INTR_BIT(intr)), \ - (pol) << GIC_INTR_BIT(intr)) - -/* Triggering : Reset Value is always 0 */ -#define GIC_SH_SET_TRIGGER_OFS 0x0180 -#define GIC_SET_TRIGGER(intr, trig) \ - GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_TRIGGER_OFS + \ - GIC_INTR_OFS(intr)), (1 << GIC_INTR_BIT(intr)), \ - (trig) << GIC_INTR_BIT(intr)) - -/* Mask manipulation */ -#define GIC_SH_SMASK_OFS 0x0380 -#define GIC_SET_INTR_MASK(intr) \ - GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_SMASK_OFS + \ - GIC_INTR_OFS(intr)), 1 << GIC_INTR_BIT(intr)) -#define GIC_SH_RMASK_OFS 0x0300 -#define GIC_CLR_INTR_MASK(intr) \ - GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_RMASK_OFS + \ - GIC_INTR_OFS(intr)), 1 << GIC_INTR_BIT(intr)) - /* Register Map for Local Section */ #define GIC_VPE_CTL_OFS 0x0000 #define GIC_VPE_PEND_OFS 0x0004 @@ -198,6 +89,7 @@ #define GIC_VPE_WD_MAP_OFS 0x0040 #define GIC_VPE_COMPARE_MAP_OFS 0x0044 #define GIC_VPE_TIMER_MAP_OFS 0x0048 +#define GIC_VPE_FDC_MAP_OFS 0x004c #define GIC_VPE_PERFCTR_MAP_OFS 0x0050 #define GIC_VPE_SWINT0_MAP_OFS 0x0054 #define GIC_VPE_SWINT1_MAP_OFS 0x0058 @@ -208,13 +100,11 @@ #define GIC_VPE_COMPARE_LO_OFS 0x00a0 #define GIC_VPE_COMPARE_HI_OFS 0x00a4 -#define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100 -#define GIC_VPE_EIC_SS(intr) \ - (GIC_VPE_EIC_SHADOW_SET_BASE + (4 * intr)) +#define GIC_VPE_EIC_SHADOW_SET_BASE_OFS 0x0100 +#define GIC_VPE_EIC_SS(intr) (4 * (intr)) -#define GIC_VPE_EIC_VEC_BASE 0x0800 -#define GIC_VPE_EIC_VEC(intr) \ - (GIC_VPE_EIC_VEC_BASE + (4 * intr)) +#define GIC_VPE_EIC_VEC_BASE_OFS 0x0800 +#define GIC_VPE_EIC_VEC(intr) (4 * (intr)) #define GIC_VPE_TENABLE_NMI_OFS 0x1000 #define GIC_VPE_TENABLE_YQ_OFS 0x1004 @@ -238,8 +128,8 @@ #define GIC_SH_CONFIG_NUMVPES_SHF 0 #define GIC_SH_CONFIG_NUMVPES_MSK (MSK(8) << GIC_SH_CONFIG_NUMVPES_SHF) -#define GIC_SH_WEDGE_SET(intr) (intr | (0x1 << 31)) -#define GIC_SH_WEDGE_CLR(intr) (intr & ~(0x1 << 31)) +#define GIC_SH_WEDGE_SET(intr) ((intr) | (0x1 << 31)) +#define GIC_SH_WEDGE_CLR(intr) ((intr) & ~(0x1 << 31)) #define GIC_MAP_TO_PIN_SHF 31 #define GIC_MAP_TO_PIN_MSK (MSK(1) << GIC_MAP_TO_PIN_SHF) @@ -251,6 +141,10 @@ #define GIC_MAP_MSK (MSK(6) << GIC_MAP_SHF) /* GIC_VPE_CTL Masks */ +#define GIC_VPE_CTL_FDC_RTBL_SHF 4 +#define GIC_VPE_CTL_FDC_RTBL_MSK (MSK(1) << GIC_VPE_CTL_FDC_RTBL_SHF) +#define GIC_VPE_CTL_SWINT_RTBL_SHF 3 +#define GIC_VPE_CTL_SWINT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_SWINT_RTBL_SHF) #define GIC_VPE_CTL_PERFCNT_RTBL_SHF 2 #define GIC_VPE_CTL_PERFCNT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF) #define GIC_VPE_CTL_TIMER_RTBL_SHF 1 @@ -300,38 +194,6 @@ #define GIC_VPE_SMASK_SWINT1_SHF 5 #define GIC_VPE_SMASK_SWINT1_MSK (MSK(1) << GIC_VPE_SMASK_SWINT1_SHF) -/* - * Set the Mapping of Interrupt X to a VPE. - */ -#define GIC_SH_MAP_TO_VPE_SMASK(intr, vpe) \ - GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe)), \ - GIC_SH_MAP_TO_VPE_REG_BIT(vpe)) - -/* - * Interrupt Meta-data specification. The ipiflag helps - * in building ipi_map. - */ -struct gic_intr_map { - unsigned int cpunum; /* Directed to this CPU */ -#define GIC_UNUSED 0xdead /* Dummy data */ - unsigned int pin; /* Directed to this Pin */ - unsigned int polarity; /* Polarity : +/- */ - unsigned int trigtype; /* Trigger : Edge/Levl */ - unsigned int flags; /* Misc flags */ -#define GIC_FLAG_TRANSPARENT 0x01 -}; - -/* - * This is only used in EIC mode. This helps to figure out which - * shared interrupts we need to process when we get a vector interrupt. - */ -#define GIC_MAX_SHARED_INTR 0x5 -struct gic_shared_intr_map { - unsigned int num_shared_intr; - unsigned int intr_list[GIC_MAX_SHARED_INTR]; - unsigned int local_intr_mask; -}; - /* GIC nomenclature for Core Interrupt Pins. */ #define GIC_CPU_INT0 0 /* Core Interrupt 2 */ #define GIC_CPU_INT1 1 /* . */ @@ -340,45 +202,48 @@ struct gic_shared_intr_map { #define GIC_CPU_INT4 4 /* . */ #define GIC_CPU_INT5 5 /* Core Interrupt 7 */ -/* Local GIC interrupts. */ -#define GIC_INT_TMR (GIC_CPU_INT5) -#define GIC_INT_PERFCTR (GIC_CPU_INT5) +/* Add 2 to convert GIC CPU pin to core interrupt */ +#define GIC_CPU_PIN_OFFSET 2 /* Add 2 to convert non-EIC hardware interrupt to EIC vector number. */ -#define GIC_CPU_TO_VEC_OFFSET (2) +#define GIC_CPU_TO_VEC_OFFSET 2 /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */ -#define GIC_PIN_TO_VEC_OFFSET (1) +#define GIC_PIN_TO_VEC_OFFSET 1 -#include <linux/clocksource.h> -#include <linux/irq.h> +/* Local GIC interrupts. */ +#define GIC_LOCAL_INT_WD 0 /* GIC watchdog */ +#define GIC_LOCAL_INT_COMPARE 1 /* GIC count and compare timer */ +#define GIC_LOCAL_INT_TIMER 2 /* CPU timer interrupt */ +#define GIC_LOCAL_INT_PERFCTR 3 /* CPU performance counter */ +#define GIC_LOCAL_INT_SWINT0 4 /* CPU software interrupt 0 */ +#define GIC_LOCAL_INT_SWINT1 5 /* CPU software interrupt 1 */ +#define GIC_LOCAL_INT_FDC 6 /* CPU fast debug channel */ +#define GIC_NUM_LOCAL_INTRS 7 + +/* Convert between local/shared IRQ number and GIC HW IRQ number. */ +#define GIC_LOCAL_HWIRQ_BASE 0 +#define GIC_LOCAL_TO_HWIRQ(x) (GIC_LOCAL_HWIRQ_BASE + (x)) +#define GIC_HWIRQ_TO_LOCAL(x) ((x) - GIC_LOCAL_HWIRQ_BASE) +#define GIC_SHARED_HWIRQ_BASE GIC_NUM_LOCAL_INTRS +#define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x)) +#define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE) extern unsigned int gic_present; -extern unsigned int gic_frequency; -extern unsigned long _gic_base; -extern unsigned int gic_irq_base; -extern unsigned int gic_irq_flags[]; -extern struct gic_shared_intr_map gic_shared_intr_map[]; extern void gic_init(unsigned long gic_base_addr, - unsigned long gic_addrspace_size, struct gic_intr_map *intrmap, - unsigned int intrmap_size, unsigned int irqbase); + unsigned long gic_addrspace_size, unsigned int cpu_vec, + unsigned int irqbase); extern void gic_clocksource_init(unsigned int); -extern unsigned int gic_compare_int (void); extern cycle_t gic_read_count(void); +extern unsigned int gic_get_count_width(void); extern cycle_t gic_read_compare(void); extern void gic_write_compare(cycle_t cnt); extern void gic_write_cpu_compare(cycle_t cnt, int cpu); extern void gic_send_ipi(unsigned int intr); extern unsigned int plat_ipi_call_int_xlate(unsigned int); extern unsigned int plat_ipi_resched_int_xlate(unsigned int); -extern void gic_bind_eic_interrupt(int irq, int set); extern unsigned int gic_get_timer_pending(void); -extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src); -extern unsigned int gic_get_int(void); -extern void gic_enable_interrupt(int irq_vec); -extern void gic_disable_interrupt(int irq_vec); -extern void gic_irq_ack(struct irq_data *d); -extern void gic_finish_irq(struct irq_data *d); -extern void gic_platform_init(int irqs, struct irq_chip *irq_controller); -#endif /* _ASM_GICREGS_H */ +extern int gic_get_c0_compare_int(void); +extern int gic_get_c0_perfcount_int(void); +#endif /* __LINUX_IRQCHIP_MIPS_GIC_H */ |