Commit 6e207b88 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arm-soc-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc

Pull ARM SoC updates from Olof Johansson:
 "A few SoC (code) changes have queued up this cycle, mostly for minor
  changes and some refactoring and cleanup of legacy platforms. This
  branch also contains a few of the fixes that weren't sent in by the
  end of the release (all fairly minor).

   - Adding an additional maintainer for the TEE subsystem (Sumit Garg)

   - Quite a significant modernization of the IXP4xx platforms by Linus
     Walleij, revisiting with a new PCI host driver/binding, removing
     legacy mach/* include dependencies and moving platform
     detection/config to drivers/soc. Also some updates/cleanup of
     platform data.

   - Core power domain support for Tegra platforms, and some
     improvements in build test coverage by adding stubs for compile
     test targets.

   - A handful of updates to i.MX platforms, adding legacy (non-PSCI)
     SMP support on i.MX7D, SoC ID setup for i.MX50, removal of platform
     data and board fixups for iMX6/7.

  ... and a few smaller changes and fixes for Samsung, OMAP, Allwinner,
  Rockchip"

* tag 'arm-soc-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (53 commits)
  MAINTAINERS: Add myself as TEE subsystem reviewer
  ixp4xx: fix spelling mistake in Kconfig "Devce" -> "Device"
  hw_random: ixp4xx: Add OF support
  hw_random: ixp4xx: Add DT bindings
  hw_random: ixp4xx: Turn into a module
  hw_random: ixp4xx: Use SPDX license tag
  hw_random: ixp4xx: enable compile-testing
  pata: ixp4xx: split platform data to its own header
  soc: ixp4xx: move cpu detection to linux/soc/ixp4xx/cpu.h
  PCI: ixp4xx: Add a new driver for IXP4xx
  PCI: ixp4xx: Add device tree bindings for IXP4xx
  ARM/ixp4xx: Make NEED_MACH_IO_H optional
  ARM/ixp4xx: Move the virtual IObases
  MAINTAINERS: ARM/MStar/Sigmastar SoCs: Add a link to the MStar tree
  ARM: debug: add UART early console support for MSTAR SoCs
  ARM: dts: ux500: Fix LED probing
  ARM: imx: add smp support for imx7d
  ARM: imx6q: drop of_platform_default_populate() from init_machine
  arm64: dts: rockchip: Update RK3399 PCI host bridge window to 32-bit address memory
  soc/tegra: fuse: Fix Tegra234-only builds
  ...
parents b6fd9e25 42accadb
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/intel,ixp4xx-pci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel IXP4xx PCI controller
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description: PCI host controller found in the Intel IXP4xx SoC series.
allOf:
- $ref: /schemas/pci/pci-bus.yaml#
properties:
compatible:
items:
- enum:
- intel,ixp42x-pci
- intel,ixp43x-pci
description: The two supported variants are ixp42x and ixp43x,
though more variants may exist.
reg:
items:
- description: IXP4xx-specific registers
interrupts:
items:
- description: Main PCI interrupt
- description: PCI DMA interrupt 1
- description: PCI DMA interrupt 2
ranges:
maxItems: 2
description: Typically one memory range of 64MB and one IO
space range of 64KB.
dma-ranges:
maxItems: 1
description: The DMA range tells the PCI host which addresses
the RAM is at. It can map only 64MB so if the RAM is bigger
than 64MB the DMA access has to be restricted to these
addresses.
"#interrupt-cells": true
interrupt-map: true
interrupt-map-mask:
items:
- const: 0xf800
- const: 0
- const: 0
- const: 7
required:
- compatible
- reg
- dma-ranges
- "#interrupt-cells"
- interrupt-map
- interrupt-map-mask
unevaluatedProperties: false
examples:
- |
pci@c0000000 {
compatible = "intel,ixp43x-pci";
reg = <0xc0000000 0x1000>;
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
bus-range = <0x00 0xff>;
ranges =
<0x02000000 0 0x48000000 0x48000000 0 0x04000000>,
<0x01000000 0 0x00000000 0x4c000000 0 0x00010000>;
dma-ranges =
<0x02000000 0 0x00000000 0x00000000 0 0x04000000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map =
<0x0800 0 0 1 &gpio0 11 3>, /* INT A on slot 1 is irq 11 */
<0x0800 0 0 2 &gpio0 10 3>, /* INT B on slot 1 is irq 10 */
<0x0800 0 0 3 &gpio0 9 3>, /* INT C on slot 1 is irq 9 */
<0x0800 0 0 4 &gpio0 8 3>, /* INT D on slot 1 is irq 8 */
<0x1000 0 0 1 &gpio0 10 3>, /* INT A on slot 2 is irq 10 */
<0x1000 0 0 2 &gpio0 9 3>, /* INT B on slot 2 is irq 9 */
<0x1000 0 0 3 &gpio0 8 3>, /* INT C on slot 2 is irq 8 */
<0x1000 0 0 4 &gpio0 11 3>, /* INT D on slot 2 is irq 11 */
<0x1800 0 0 1 &gpio0 9 3>, /* INT A on slot 3 is irq 9 */
<0x1800 0 0 2 &gpio0 8 3>, /* INT B on slot 3 is irq 8 */
<0x1800 0 0 3 &gpio0 11 3>, /* INT C on slot 3 is irq 11 */
<0x1800 0 0 4 &gpio0 10 3>; /* INT D on slot 3 is irq 10 */
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rng/intel,ixp46x-rng.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel IXP46x RNG bindings
description: |
The Intel IXP46x has a random number generator at a fixed physical
location in memory. Each read is guaranteed to provide a unique
32 bit random number.
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
properties:
compatible:
const: intel,ixp46x-rng
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
rng@70002100 {
compatible = "intel,ixp46x-rng";
reg = <0x70002100 4>;
};
......@@ -2210,6 +2210,7 @@ M: Daniel Palmer <daniel@thingy.jp>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
W: http://linux-chenxing.org/
T: git git://github.com/linux-chenxing/linux.git
F: Documentation/devicetree/bindings/arm/mstar/*
F: Documentation/devicetree/bindings/clock/mstar,msc313-mpll.yaml
F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml
......@@ -2479,9 +2480,12 @@ F: drivers/*/*/*s3c24*
F: drivers/*/*s3c24*
F: drivers/*/*s3c64xx*
F: drivers/*/*s5pv210*
F: drivers/clocksource/samsung_pwm_timer.c
F: drivers/memory/samsung/
F: drivers/pwm/pwm-samsung.c
F: drivers/soc/samsung/
F: drivers/tty/serial/samsung*
F: include/clocksource/samsung_pwm.h
F: include/linux/platform_data/*s3c*
F: include/linux/serial_s3c.h
F: include/linux/soc/samsung/
......@@ -9381,6 +9385,7 @@ F: include/linux/soc/ixp4xx/qmgr.h
INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
M: Deepak Saxena <dsaxena@plexity.net>
S: Maintained
F: Documentation/devicetree/bindings/display/intel,ixp46x-rng.yaml
F: drivers/char/hw_random/ixp4xx-rng.c
INTEL KEEM BAY DRM DRIVER
......@@ -13510,12 +13515,6 @@ L: linux-omap@vger.kernel.org
S: Maintained
F: arch/arm/mach-omap2/omap_hwmod*data*
OMAP HWMOD DATA FOR OMAP4-BASED DEVICES
M: Benoît Cousson <bcousson@baylibre.com>
L: linux-omap@vger.kernel.org
S: Maintained
F: arch/arm/mach-omap2/omap_hwmod_44xx_data.c
OMAP HWMOD SUPPORT
M: Benoît Cousson <bcousson@baylibre.com>
M: Paul Walmsley <paul@pwsan.com>
......@@ -14179,6 +14178,12 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
F: drivers/pci/controller/dwc/pcie-fu740.c
PCI DRIVER FOR INTEL IXP4XX
M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
F: Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml
F: drivers/pci/controller/pci-ixp4xx.c
PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
M: Jonathan Derrick <jonathan.derrick@intel.com>
L: linux-pci@vger.kernel.org
......@@ -18126,6 +18131,7 @@ F: include/media/i2c/tw9910.h
TEE SUBSYSTEM
M: Jens Wiklander <jens.wiklander@linaro.org>
R: Sumit Garg <sumit.garg@linaro.org>
L: op-tee@lists.trustedfirmware.org
S: Maintained
F: Documentation/staging/tee.rst
......
......@@ -394,7 +394,8 @@ config ARCH_IXP4XX
select HAVE_PCI
select IXP4XX_IRQ
select IXP4XX_TIMER
select NEED_MACH_IO_H
# With the new PCI driver this is not needed
select NEED_MACH_IO_H if PCI_IXP4XX_LEGACY
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
help
......
......@@ -609,6 +609,14 @@ choice
when u-boot hands over to the kernel, the system
silently crashes, with no serial output at all.
config DEBUG_MSTARV7_PMUART
bool "Kernel low-level debugging messages via MSTARV7 PM UART"
depends on ARCH_MSTARV7
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
for MSTAR ARMv7-based platforms on PM UART.
config DEBUG_MT6589_UART0
bool "Mediatek mt6589 UART0"
depends on ARCH_MEDIATEK
......@@ -1607,6 +1615,7 @@ config DEBUG_UART_PHYS
default 0x18000400 if DEBUG_BCM_HR2
default 0x18023000 if DEBUG_BCM_IPROC_UART3
default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1
default 0x1f221000 if DEBUG_MSTARV7_PMUART
default 0x20001000 if DEBUG_HIP01_UART
default 0x20060000 if DEBUG_RK29_UART0
default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2
......@@ -1724,6 +1733,7 @@ config DEBUG_UART_VIRT
default 0xf0100000 if DEBUG_DIGICOLOR_UA0
default 0xf01fb000 if DEBUG_NOMADIK_UART
default 0xf0201000 if DEBUG_BCM2835 || DEBUG_BCM2836
default 0xf0221000 if DEBUG_MSTARV7_PMUART
default 0xf1000300 if DEBUG_BCM_5301X
default 0xf1000400 if DEBUG_BCM_HR2
default 0xf1002000 if DEBUG_MT8127_UART0
......@@ -1805,8 +1815,8 @@ config DEBUG_UART_VIRT
default 0xfedc0000 if DEBUG_EP93XX
default 0xfee003f8 if DEBUG_FOOTBRIDGE_COM1
default 0xfee20000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART
default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
default 0xfec00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
default 0xfec00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
default 0xfef36000 if DEBUG_HIGHBANK_UART
default 0xfefb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1
default 0xfefb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2
......@@ -1829,6 +1839,7 @@ config DEBUG_UART_8250_SHIFT
default 0 if DEBUG_FOOTBRIDGE_COM1 || ARCH_IOP32X || DEBUG_BCM_5301X || \
DEBUG_BCM_HR2 || DEBUG_OMAP7XXUART1 || DEBUG_OMAP7XXUART2 || \
DEBUG_OMAP7XXUART3
default 3 if DEBUG_MSTARV7_PMUART
default 2
config DEBUG_UART_8250_WORD
......
......@@ -17,17 +17,13 @@ / {
* VCP1, VCP2
* MLB
* ISS
* USB3, USB4
* USB3
*/
&usb3_tm {
status = "disabled";
};
&usb4_tm {
status = "disabled";
};
&atl_tm {
status = "disabled";
};
......@@ -4129,28 +4129,6 @@ usb3: usb@10000 {
};
};
usb4_tm: target-module@140000 { /* 0x48940000, ap 75 3c.0 */
compatible = "ti,sysc-omap4", "ti,sysc";
reg = <0x140000 0x4>,
<0x140010 0x4>;
reg-names = "rev", "sysc";
ti,sysc-mask = <SYSC_OMAP4_DMADISABLE>;
ti,sysc-midle = <SYSC_IDLE_FORCE>,
<SYSC_IDLE_NO>,
<SYSC_IDLE_SMART>,
<SYSC_IDLE_SMART_WKUP>;
ti,sysc-sidle = <SYSC_IDLE_FORCE>,
<SYSC_IDLE_NO>,
<SYSC_IDLE_SMART>,
<SYSC_IDLE_SMART_WKUP>;
/* Domains (P, C): l3init_pwrdm, l3init_clkdm */
clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>;
clock-names = "fck";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x140000 0x20000>;
};
target-module@170000 { /* 0x48970000, ap 21 0a.0 */
compatible = "ti,sysc-omap4", "ti,sysc";
reg = <0x170010 0x4>;
......
......@@ -11,7 +11,3 @@
&rtctarget {
status = "disabled";
};
&usb4_tm {
status = "disabled";
};
......@@ -108,7 +108,3 @@ &pcie1_ep {
&pcie2_rc {
compatible = "ti,dra726-pcie-rc", "ti,dra7-pcie";
};
&usb4_tm {
status = "disabled";
};
......@@ -49,49 +49,6 @@ dsp2_system: dsp_system@41500000 {
reg = <0x41500000 0x100>;
};
target-module@48940000 {
compatible = "ti,sysc-omap4", "ti,sysc";
reg = <0x48940000 0x4>,
<0x48940010 0x4>;
reg-names = "rev", "sysc";
ti,sysc-mask = <SYSC_OMAP4_DMADISABLE>;
ti,sysc-midle = <SYSC_IDLE_FORCE>,
<SYSC_IDLE_NO>,
<SYSC_IDLE_SMART>,
<SYSC_IDLE_SMART_WKUP>;
ti,sysc-sidle = <SYSC_IDLE_FORCE>,
<SYSC_IDLE_NO>,
<SYSC_IDLE_SMART>,
<SYSC_IDLE_SMART_WKUP>;
clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>;
clock-names = "fck";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x48940000 0x20000>;
omap_dwc3_4: omap_dwc3_4@0 {
compatible = "ti,dwc3";
reg = <0 0x10000>;
interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <1>;
utmi-mode = <2>;
ranges;
status = "disabled";
usb4: usb@10000 {
compatible = "snps,dwc3";
reg = <0x10000 0x17000>;
interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "peripheral",
"host",
"otg";
maximum-speed = "high-speed";
dr_mode = "otg";
};
};
};
target-module@41501000 {
compatible = "ti,sysc-omap2", "ti,sysc";
......@@ -224,3 +181,52 @@ &pcie1_ep {
&pcie2_rc {
compatible = "ti,dra746-pcie-rc", "ti,dra7-pcie";
};
&l4_per3 {
segment@0 {
usb4_tm: target-module@140000 { /* 0x48940000, ap 75 3c.0 */
compatible = "ti,sysc-omap4", "ti,sysc";
reg = <0x140000 0x4>,
<0x140010 0x4>;
reg-names = "rev", "sysc";
ti,sysc-mask = <SYSC_OMAP4_DMADISABLE>;
ti,sysc-midle = <SYSC_IDLE_FORCE>,
<SYSC_IDLE_NO>,
<SYSC_IDLE_SMART>,
<SYSC_IDLE_SMART_WKUP>;
ti,sysc-sidle = <SYSC_IDLE_FORCE>,
<SYSC_IDLE_NO>,
<SYSC_IDLE_SMART>,
<SYSC_IDLE_SMART_WKUP>;
/* Domains (P, C): l3init_pwrdm, l3init_clkdm */
clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>;
clock-names = "fck";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x140000 0x20000>;
omap_dwc3_4: omap_dwc3_4@0 {
compatible = "ti,dwc3";
reg = <0 0x10000>;
interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <1>;
utmi-mode = <2>;
ranges;
status = "disabled";
usb4: usb@10000 {
compatible = "snps,dwc3";
reg = <0x10000 0x17000>;
interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "peripheral",
"host",
"otg";
maximum-speed = "high-speed";
dr_mode = "otg";
};
};
};
};
};
......@@ -250,7 +250,7 @@ nand@0 {
nand-ecc-step-size = <512>;
nand-bus-width = <8>;
/* efs2 partition is secured */
secure-regions = <0x500000 0xb00000>;
secure-regions = /bits/ 64 <0x500000 0xb00000>;
};
};
......
......@@ -250,7 +250,7 @@ nand@0 {
nand-ecc-step-size = <512>;
nand-bus-width = <8>;
/* ico and efs2 partitions are secured */
secure-regions = <0x500000 0x500000
secure-regions = /bits/ 64 <0x500000 0x500000
0xa00000 0xb00000>;
};
};
......
......@@ -4,6 +4,7 @@
*/
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/leds/common.h>
#include "ste-href-family-pinctrl.dtsi"
/ {
......@@ -64,17 +65,20 @@ chan@0 {
reg = <0>;
led-cur = /bits/ 8 <0x2f>;
max-cur = /bits/ 8 <0x5f>;
color = <LED_COLOR_ID_BLUE>;
linux,default-trigger = "heartbeat";
};
chan@1 {
reg = <1>;
led-cur = /bits/ 8 <0x2f>;
max-cur = /bits/ 8 <0x5f>;
color = <LED_COLOR_ID_BLUE>;
};
chan@2 {
reg = <2>;
led-cur = /bits/ 8 <0x2f>;
max-cur = /bits/ 8 <0x5f>;
color = <LED_COLOR_ID_BLUE>;
};
};
lp5521@34 {
......@@ -88,16 +92,19 @@ chan@0 {
reg = <0>;
led-cur = /bits/ 8 <0x2f>;
max-cur = /bits/ 8 <0x5f>;
color = <LED_COLOR_ID_BLUE>;
};
chan@1 {
reg = <1>;
led-cur = /bits/ 8 <0x2f>;
max-cur = /bits/ 8 <0x5f>;
color = <LED_COLOR_ID_BLUE>;
};
chan@2 {
reg = <2>;
led-cur = /bits/ 8 <0x2f>;
max-cur = /bits/ 8 <0x5f>;
color = <LED_COLOR_ID_BLUE>;
};
};
bh1780@29 {
......
......@@ -85,7 +85,7 @@ &emac {
pinctrl-0 = <&emac_rgmii_pins>;
phy-supply = <&reg_gmac_3v3>;
phy-handle = <&ext_rgmii_phy>;
phy-mode = "rgmii";
phy-mode = "rgmii-id";
status = "okay";
};
......
......@@ -55,6 +55,7 @@ void __init exynos_sysram_init(void)
sysram_base_addr = of_iomap(node, 0);
sysram_base_phys = of_translate_address(node,
of_get_address(node, 0, NULL, NULL));
of_node_put(node);
break;
}
......@@ -62,6 +63,7 @@ void __init exynos_sysram_init(void)
if (!of_device_is_available(node))
continue;
sysram_ns_base_addr = of_iomap(node, 0);
of_node_put(node);
break;
}
}
......
......@@ -35,7 +35,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
obj-$(CONFIG_HAVE_IMX_SRC) += src.o
ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_IMX7D_CA7)$(CONFIG_SOC_LS1021A),)
AFLAGS_headsmp.o :=-Wa,-march=armv7-a
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
......
......@@ -68,11 +68,13 @@ void imx_set_cpu_arg(int cpu, u32 arg);
void v7_secondary_startup(void);
void imx_scu_map_io(void);
void imx_smp_prepare(void);
void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn);
#else
static inline void imx_scu_map_io(void) {}
static inline void imx_smp_prepare(void) {}
#endif
void imx_src_init(void);
void imx7_src_init(void);
void imx_gpc_pre_suspend(bool arm_power_off);
void imx_gpc_post_resume(void);
void imx_gpc_mask_all(void);
......@@ -131,6 +133,7 @@ static inline void imx_init_l2cache(void) {}
#endif
extern const struct smp_operations imx_smp_ops;
extern const struct smp_operations imx7_smp_ops;
extern const struct smp_operations ls1021a_smp_ops;
#endif
......@@ -21,6 +21,15 @@ diag_reg_offset:
ENTRY(v7_secondary_startup)
ARM_BE8(setend be) @ go BE8 if entered LE
mrc p15, 0, r0, c0, c0, 0
lsl r0, r0, #16
lsr r0, r0, #20
/* 0xc07 is cortex A7's ID */
mov r1, #0xc00
orr r1, #0x7
cmp r0, r1
beq secondary_startup
set_diag_reg
b secondary_startup
ENDPROC(v7_secondary_startup)
......@@ -11,6 +11,7 @@
#include <asm/proc-fns.h>
#include "common.h"
#include "hardware.h"
/*
* platform-specific code to shutdown a CPU
......@@ -40,5 +41,7 @@ int imx_cpu_kill(unsigned int cpu)
return 0;
imx_enable_cpu(cpu, false);
imx_set_cpu_arg(cpu, 0);
if (cpu_is_imx7d())
imx_gpcv2_set_core1_pdn_pup_by_software(true);
return 1;
}
......@@ -9,6 +9,12 @@
#include <asm/mach/arch.h>
#include "common.h"
#include "hardware.h"
static void __init imx50_init_early(void)
{
mxc_set_cpu_type(MXC_CPU_MX50);
}
static const char * const imx50_dt_board_compat[] __initconst = {
"fsl,imx50",
......@@ -16,5 +22,6 @@ static const char * const imx50_dt_board_compat[] __initconst = {
};
DT_MACHINE_START(IMX50_DT, "Freescale i.MX50 (Device Tree Support)")
.init_early = imx50_init_early,
.dt_compat = imx50_dt_board_compat,
MACHINE_END
......@@ -40,27 +40,6 @@ static int ksz9021rn_phy_fixup(struct phy_device *phydev)
return 0;
}
static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val)
{
phy_write(dev, 0x0d, device);
phy_write(dev, 0x0e, reg);
phy_write(dev, 0x0d, (1 << 14) | device);
phy_write(dev, 0x0e, val);
}
static int ksz9031rn_phy_fixup(struct phy_device *dev)
{
/*
* min rx data delay, max rx/tx clock delay,
* min rx/tx control delay
*/
mmd_write_reg(dev, 2, 4, 0);
mmd_write_reg(dev, 2, 5, 0);
mmd_write_reg(dev, 2, 8, 0x003ff);
return 0;
}
/*
* fixup for PLX PEX8909 bridge to configure GPIO1-7 as output High
* as they are used for slots1-7 PERST#
......@@ -89,75 +68,11 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8609, ventana_pciesw_early_fixup);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8606, ventana_pciesw_early_fixup);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8604, ventana_pciesw_early_fixup);
static int ar8031_phy_fixup(struct phy_device *dev)
{
u16 val;
/* To enable AR8031 output a 125MHz clk from CLK_25M */
phy_write(dev, 0xd, 0x7);
phy_write(dev, 0xe, 0x8016);
phy_write(dev, 0xd, 0x4007);
val = phy_read(dev, 0xe);
val &= 0xffe3;
val |= 0x18;
phy_write(dev, 0xe, val);
/* introduce tx clock delay */
phy_write(dev, 0x1d, 0x5);
val = phy_read(dev, 0x1e);
val |= 0x0100;
phy_write(dev, 0x1e, val);
return 0;
}
#define PHY_ID_AR8031 0x004dd074
static int ar8035_phy_fixup(struct phy_device *dev)
{
u16 val;
/* Ar803x phy SmartEEE feature cause link status generates glitch,
* which cause ethernet link down/up issue, so disable SmartEEE
*/
phy_write(dev, 0xd, 0x3);
phy_write(dev, 0xe, 0x805d);
phy_write(dev, 0xd, 0x4003);
val = phy_read(dev, 0xe);
phy_write(dev, 0xe, val & ~(1 << 8));
/*
* Enable 125MHz clock from CLK_25M on the AR8031. This
* is fed in to the IMX6 on the ENET_REF_CLK (V22) pad.
* Also, introduce a tx clock delay.
*
* This is the same as is the AR8031 fixup.
*/
ar8031_phy_fixup(dev);
/*check phy power*/
val = phy_read(dev, 0x0);
if (val & BMCR_PDOWN)
phy_write(dev, 0x0, val & ~BMCR_PDOWN);
return 0;
}
#define PHY_ID_AR8035 0x004dd072
static void __init imx6q_enet_phy_init(void)
{
if (IS_BUILTIN(CONFIG_PHYLIB)) {
phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
ksz9021rn_phy_fixup);
phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,
ksz9031rn_phy_fixup);
phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffef,
ar8031_phy_fixup);
phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef,
ar8035_phy_fixup);
}
}
......@@ -257,9 +172,6 @@ static void __init imx6q_init_machine(void)
imx_get_soc_revision());
imx6q_enet_phy_init();
of_platform_default_populate(NULL, NULL, NULL);
imx_anatop_init();
cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init();
imx6q_1588_init();
......
......@@ -15,31 +15,6 @@
#include "common.h"
#include "cpuidle.h"
static int ar8031_phy_fixup(struct phy_device *dev)
{
u16 val;
/* Set RGMII IO voltage to 1.8V */
phy_write(dev, 0x1d, 0x1f);
phy_write(dev, 0x1e, 0x8);
/* introduce tx clock delay */
phy_write(dev, 0x1d, 0x5);
val = phy_read(dev, 0x1e);
val |= 0x0100;
phy_write(dev, 0x1e, val);
return 0;
}
#define PHY_ID_AR8031 0x004dd074
static void __init imx6sx_enet_phy_init(void)
{
if (IS_BUILTIN(CONFIG_PHYLIB))
phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
ar8031_phy_fixup);
}
static void __init imx6sx_enet_clk_sel(void)
{
struct regmap *gpr;
......@@ -57,7 +32,6 @@ static void __init imx6sx_enet_clk_sel(void)
static inline void imx6sx_enet_init(void)
{
imx6sx_enet_phy_init();
imx6sx_enet_clk_sel();
}
......
......@@ -14,25 +14,6 @@
#include "common.h"
static int ar8031_phy_fixup(struct phy_device *dev)
{
u16 val;
/* Set RGMII IO voltage to 1.8V */
phy_write(dev, 0x1d, 0x1f);
phy_write(dev, 0x1e, 0x8);
/* disable phy AR8031 SmartEEE function. */
phy_write(dev, 0xd, 0x3);
phy_write(dev, 0xe, 0x805d);
phy_write(dev, 0xd, 0x4003);
val = phy_read(dev, 0xe);
val &= ~(0x1 << 8);
phy_write(dev, 0xe, val);
return 0;
}
static int bcm54220_phy_fixup(struct phy_device *dev)
{
/* enable RXC skew select RGMII copper mode */
......@@ -44,14 +25,11 @@ static int bcm54220_phy_fixup(struct phy_device *dev)
return 0;
}
#define PHY_ID_AR8031 0x004dd074
#define PHY_ID_BCM54220 0x600d8589
static void __init imx7d_enet_phy_init(void)
{
if (IS_BUILTIN(CONFIG_PHYLIB)) {
phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
ar8031_phy_fixup);
phy_register_fixup_for_uid(PHY_ID_BCM54220, 0xffffffff,
bcm54220_phy_fixup);
}
......@@ -91,7 +69,7 @@ static void __init imx7d_init_late(void)
static void __init imx7d_init_irq(void)
{
imx_init_revision_from_anatop();
imx_src_init();
imx7_src_init();
irqchip_init();
}
......@@ -102,6 +80,7 @@ static const char *const imx7d_dt_compat[] __initconst = {
};
DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
.smp = smp_ops(imx7_smp_ops),
.init_irq = imx7d_init_irq,
.init_machine = imx7d_init_machine,
.init_late = imx7d_init_late,
......
......@@ -92,6 +92,32 @@ const struct smp_operations imx_smp_ops __initconst = {
#endif
};
/*
* Initialise the CPU possible map early - this describes the CPUs
* which may be present or become present in the system.
*/
static void __init imx7_smp_init_cpus(void)
{
struct device_node *np;
int i, ncores = 0;
/* The iMX7D SCU does not report core count, get it from DT */
for_each_of_cpu_node(np)
ncores++;
for (i = ncores; i < NR_CPUS; i++)
set_cpu_possible(i, false);
}
const struct smp_operations imx7_smp_ops __initconst = {
.smp_init_cpus = imx7_smp_init_cpus,
.smp_boot_secondary = imx_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = imx_cpu_die,
.cpu_kill = imx_cpu_kill,
#endif
};
#define DCFG_CCSR_SCRATCHRW1 0x200
static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle)
......
......@@ -6,15 +6,19 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/smp.h>
#include <asm/smp_plat.h>
#include "common.h"
#include "hardware.h"
#define SRC_SCR 0x000
#define SRC_GPR1 0x020
#define SRC_GPR1_V1 0x020
#define SRC_GPR1_V2 0x074
#define SRC_GPR1(gpr_v2) ((gpr_v2) ? SRC_GPR1_V2 : SRC_GPR1_V1)
#define BP_SRC_SCR_WARM_RESET_ENABLE 0
#define BP_SRC_SCR_SW_GPU_RST 1
#define BP_SRC_SCR_SW_VPU_RST 2
......@@ -23,9 +27,18 @@
#define BP_SRC_SCR_SW_IPU2_RST 12
#define BP_SRC_SCR_CORE1_RST 14
#define BP_SRC_SCR_CORE1_ENABLE 22
/* below is for i.MX7D */
#define SRC_A7RCR1 0x008
#define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1
#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
#define GPC_CPU_PGC_SW_PDN_REQ 0xfc
#define GPC_PGC_C1 0x840
#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2
static void __iomem *src_base;
static DEFINE_SPINLOCK(scr_lock);
static bool gpr_v2;
static void __iomem *gpc_base;
static const int sw_reset_bits[5] = {
BP_SRC_SCR_SW_GPU_RST,
......@@ -73,17 +86,64 @@ static struct reset_controller_dev imx_reset_controller = {
.nr_resets = ARRAY_SIZE(sw_reset_bits),
};
static void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset)
{
writel_relaxed(enable, gpc_base + offset);
}
/*
* The motivation for bringing up the second i.MX7D core inside the kernel
* is that legacy vendor bootloaders usually do not implement PSCI support.
* This is a significant blocker for systems in the field that are running old
* bootloader versions to upgrade to a modern mainline kernel version, as only
* one CPU of the i.MX7D would be brought up.
* Bring up the second i.MX7D core inside the kernel to make the migration
* path to mainline kernel easier for the existing iMX7D users.
*/
void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn)
{
u32 reg = pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ;
u32 val, pup;
int ret;
imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1);
val = readl_relaxed(gpc_base + reg);
val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
writel_relaxed(val, gpc_base + reg);
ret = readl_relaxed_poll_timeout_atomic(gpc_base + reg, pup,
!(pup & BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7),
5, 1000000);
if (ret < 0) {
pr_err("i.MX7D: CORE1_A7 power up timeout\n");
val &= ~BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
writel_relaxed(val, gpc_base + reg);
}
imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1);
}
void imx_enable_cpu(int cpu, bool enable)
{
u32 mask, val;
cpu = cpu_logical_map(cpu);
mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
spin_lock(&scr_lock);
if (gpr_v2) {
if (enable)
imx_gpcv2_set_core1_pdn_pup_by_software(false);
mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1);
val = readl_relaxed(src_base + SRC_A7RCR1);
val = enable ? val | mask : val & ~mask;
writel_relaxed(val, src_base + SRC_A7RCR1);
} else {
mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
val = readl_relaxed(src_base + SRC_SCR);
val = enable ? val | mask : val & ~mask;
val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1);
writel_relaxed(val, src_base + SRC_SCR);
}
spin_unlock(&scr_lock);
}
......@@ -91,19 +151,19 @@ void imx_set_cpu_jump(int cpu, void *jump_addr)
{
cpu = cpu_logical_map(cpu);
writel_relaxed(__pa_symbol(jump_addr),
src_base + SRC_GPR1 + cpu * 8);
src_base + SRC_GPR1(gpr_v2) + cpu * 8);
}
u32 imx_get_cpu_arg(int cpu)
{
cpu = cpu_logical_map(cpu);
return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4);
return readl_relaxed(src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4);
}
void imx_set_cpu_arg(int cpu, u32 arg)
{
cpu = cpu_logical_map(cpu);
writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4);
writel_relaxed(arg, src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4);
}
void __init imx_src_init(void)
......@@ -131,3 +191,26 @@ void __init imx_src_init(void)
writel_relaxed(val, src_base + SRC_SCR);
spin_unlock(&scr_lock);
}
void __init imx7_src_init(void)
{
struct device_node *np;
gpr_v2 = true;
np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-src");
if (!np)
return;
src_base = of_iomap(np, 0);
if (!src_base)
return;
np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc");
if (!np)
return;
gpc_base = of_iomap(np, 0);
if (!gpc_base)
return;
}
......@@ -28,11 +28,11 @@
* ^
* ^
* imx53_suspend code
* PM_INFO structure(imx53_suspend_info)
* PM_INFO structure(imx5_cpu_suspend_info)
* ======================== low address =======================
*/
/* Offsets of members of struct imx53_suspend_info */
/* Offsets of members of struct imx5_cpu_suspend_info */
#define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0
#define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4
#define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8
......
......@@ -7,7 +7,7 @@ comment "IXP4xx Platforms"
config MACH_IXP4XX_OF
bool
prompt "Devce Tree IXP4xx boards"
prompt "Device Tree IXP4xx boards"
default y
select ARM_APPENDED_DTB # Old Redboot bootloaders deployed
select I2C
......@@ -20,7 +20,7 @@ config MACH_IXP4XX_OF
config MACH_NSLU2
bool
prompt "Linksys NSLU2"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Linksys's
NSLU2 NAS device. For more information on this platform,
......@@ -28,7 +28,7 @@ config MACH_NSLU2
config MACH_AVILA
bool "Avila"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support the Gateworks
Avila Network Platform. For more information on this platform,
......@@ -44,7 +44,7 @@ config MACH_LOFT
config ARCH_ADI_COYOTE
bool "Coyote"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support the ADI
Engineering Coyote Gateway Reference Platform. For more
......@@ -52,7 +52,7 @@ config ARCH_ADI_COYOTE
config MACH_GATEWAY7001
bool "Gateway 7001"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Gateway's
7001 Access Point. For more information on this platform,
......@@ -60,7 +60,7 @@ config MACH_GATEWAY7001
config MACH_WG302V2
bool "Netgear WG302 v2 / WAG302 v2"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Netgear's
WG302 v2 or WAG302 v2 Access Points. For more information
......@@ -68,6 +68,7 @@ config MACH_WG302V2
config ARCH_IXDP425
bool "IXDP425"
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Intel's
IXDP425 Development Platform (Also known as Richfield).
......@@ -75,6 +76,7 @@ config ARCH_IXDP425
config MACH_IXDPG425
bool "IXDPG425"
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Intel's
IXDPG425 Development Platform (Also known as Montajade).
......@@ -120,7 +122,7 @@ config ARCH_PRPMC1100
config MACH_NAS100D
bool
prompt "NAS100D"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Iomega's
NAS 100d device. For more information on this platform,
......@@ -129,7 +131,7 @@ config MACH_NAS100D
config MACH_DSMG600
bool
prompt "D-Link DSM-G600 RevA"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support D-Link's
DSM-G600 RevA device. For more information on this platform,
......@@ -143,7 +145,7 @@ config ARCH_IXDP4XX
config MACH_FSG
bool
prompt "Freecom FSG-3"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Freecom's
FSG-3 device. For more information on this platform,
......@@ -152,7 +154,7 @@ config MACH_FSG
config MACH_ARCOM_VULCAN
bool
prompt "Arcom/Eurotech Vulcan"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support Arcom's
Vulcan board.
......@@ -173,7 +175,7 @@ config CPU_IXP43X
config MACH_GTWX5715
bool "Gemtek WX5715 (Linksys WRV54G)"
depends on ARCH_IXP4XX
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
This board is currently inside the Linksys WRV54G Gateways.
......@@ -196,7 +198,7 @@ config MACH_DEVIXP
config MACH_MICCPT
bool "Omicron MICCPT"
select FORCE_PCI
depends on IXP4XX_PCI_LEGACY
help
Say 'Y' here if you want your kernel to support the MICCPT
board from OMICRON electronics GmbH.
......@@ -209,9 +211,16 @@ config MACH_MIC256
comment "IXP4xx Options"
config IXP4XX_PCI_LEGACY
bool "IXP4xx legacy PCI driver support"
depends on PCI
help
Selects legacy PCI driver.
Not recommended for new development.
config IXP4XX_INDIRECT_PCI
bool "Use indirect PCI memory access"
depends on PCI
depends on IXP4XX_PCI_LEGACY
help
IXP4xx provides two methods of accessing PCI memory space:
......
......@@ -19,6 +19,7 @@
#include <linux/tty.h>
#include <linux/serial_8250.h>
#include <linux/gpio/machine.h>
#include <linux/platform_data/pata_ixp4xx_cf.h>
#include <asm/types.h>
#include <asm/setup.h>
#include <asm/memory.h>
......
......@@ -27,12 +27,12 @@
#include <linux/cpu.h>
#include <linux/pci.h>
#include <linux/sched_clock.h>
#include <linux/soc/ixp4xx/cpu.h>
#include <linux/irqchip/irq-ixp4xx.h>
#include <linux/platform_data/timer-ixp4xx.h>
#include <linux/dma-map-ops.h>
#include <mach/udc.h>
#include <mach/hardware.h>
#include <mach/io.h>
#include <linux/uaccess.h>
#include <asm/page.h>
#include <asm/exception.h>
......@@ -44,6 +44,27 @@
#include "irqs.h"
u32 ixp4xx_read_feature_bits(void)
{
u32 val = ~__raw_readl(IXP4XX_EXP_CFG2);
if (cpu_is_ixp42x_rev_a0())
return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
IXP4XX_FEATURE_AES);
if (cpu_is_ixp42x())
return val & IXP42X_FEATURE_MASK;
if (cpu_is_ixp43x())
return val & IXP43X_FEATURE_MASK;
return val & IXP46X_FEATURE_MASK;
}
EXPORT_SYMBOL(ixp4xx_read_feature_bits);
void ixp4xx_write_feature_bits(u32 value)
{
__raw_writel(~value, IXP4XX_EXP_CFG2);
}
EXPORT_SYMBOL(ixp4xx_write_feature_bits);
#define IXP4XX_TIMER_FREQ 66666000
/*************************************************************************
......@@ -215,6 +236,27 @@ static struct resource ixp46x_i2c_resources[] = {
}
};
/* A single 32-bit register on IXP46x */
#define IXP4XX_HWRANDOM_BASE_PHYS 0x70002100
static struct resource ixp46x_hwrandom_resource[] = {
{
.start = IXP4XX_HWRANDOM_BASE_PHYS,
.end = IXP4XX_HWRANDOM_BASE_PHYS + 0x3,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device ixp46x_hwrandom_device = {
.name = "ixp4xx-hwrandom",
.id = -1,
.dev = {
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.resource = ixp46x_hwrandom_resource,
.num_resources = ARRAY_SIZE(ixp46x_hwrandom_resource),
};
/*
* I2C controller. The IXP46x uses the same block as the IOP3xx, so
* we just use the same device name.
......@@ -227,7 +269,8 @@ static struct platform_device ixp46x_i2c_controller = {
};
static struct platform_device *ixp46x_devices[] __initdata = {
&ixp46x_i2c_controller
&ixp46x_hwrandom_device,
&ixp46x_i2c_controller,
};
unsigned long ixp4xx_exp_bus_size;
......
......@@ -28,6 +28,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <mach/hardware.h>
#include "irqs.h"
......
......@@ -23,7 +23,7 @@
#include "ixp4xx-regs.h"
#ifndef __ASSEMBLER__
#include <mach/cpu.h>
#include <linux/soc/ixp4xx/cpu.h>
#endif
/* Platform helper functions and definitions */
......
......@@ -45,21 +45,21 @@
* it can be used with the low-level debug code.
*/
#define IXP4XX_PERIPHERAL_BASE_PHYS 0xC8000000
#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEF00000)
#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEC00000)
#define IXP4XX_PERIPHERAL_REGION_SIZE 0x00013000
/*
* PCI Config registers
*/
#define IXP4XX_PCI_CFG_BASE_PHYS 0xC0000000
#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEF13000)
#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEC13000)
#define IXP4XX_PCI_CFG_REGION_SIZE 0x00001000
/*
* Expansion BUS Configuration registers
*/
#define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000
#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEF14000
#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000
#define IXP4XX_EXP_CFG_REGION_SIZE 0x00001000
#define IXP4XX_EXP_CS0_OFFSET 0x00
......@@ -120,6 +120,7 @@
#define IXP4XX_SSP_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x12000)
/* The UART is explicitly put in the beginning of fixmap */
#define IXP4XX_UART1_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x0000)
#define IXP4XX_UART2_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x1000)
#define IXP4XX_PMU_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x2000)
......@@ -299,58 +300,4 @@
#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
/* "fuse" bits of IXP_EXP_CFG2 */
/* All IXP4xx CPUs */
#define IXP4XX_FEATURE_RCOMP (1 << 0)
#define IXP4XX_FEATURE_USB_DEVICE (1 << 1)
#define IXP4XX_FEATURE_HASH (1 << 2)
#define IXP4XX_FEATURE_AES (1 << 3)
#define IXP4XX_FEATURE_DES (1 << 4)
#define IXP4XX_FEATURE_HDLC (1 << 5)
#define IXP4XX_FEATURE_AAL (1 << 6)
#define IXP4XX_FEATURE_HSS (1 << 7)
#define IXP4XX_FEATURE_UTOPIA (1 << 8)
#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9)
#define IXP4XX_FEATURE_NPEC_ETH (1 << 10)
#define IXP4XX_FEATURE_RESET_NPEA (1 << 11)
#define IXP4XX_FEATURE_RESET_NPEB (1 << 12)
#define IXP4XX_FEATURE_RESET_NPEC (1 << 13)
#define IXP4XX_FEATURE_PCI (1 << 14)
#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \
IXP4XX_FEATURE_USB_DEVICE | \
IXP4XX_FEATURE_HASH | \
IXP4XX_FEATURE_AES | \
IXP4XX_FEATURE_DES | \
IXP4XX_FEATURE_HDLC | \
IXP4XX_FEATURE_AAL | \
IXP4XX_FEATURE_HSS | \
IXP4XX_FEATURE_UTOPIA | \
IXP4XX_FEATURE_NPEB_ETH0 | \
IXP4XX_FEATURE_NPEC_ETH | \
IXP4XX_FEATURE_RESET_NPEA | \
IXP4XX_FEATURE_RESET_NPEB | \
IXP4XX_FEATURE_RESET_NPEC | \
IXP4XX_FEATURE_PCI | \
IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
IXP4XX_FEATURE_XSCALE_MAX_FREQ)
/* IXP43x/46x CPUs */
#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15)
#define IXP4XX_FEATURE_USB_HOST (1 << 18)
#define IXP4XX_FEATURE_NPEA_ETH (1 << 19)
#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \
IXP4XX_FEATURE_ECC_TIMESYNC | \
IXP4XX_FEATURE_USB_HOST | \
IXP4XX_FEATURE_NPEA_ETH)
/* IXP46x CPU (including IXP455) only */
#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
#define IXP4XX_FEATURE_RSA (1 << 21)
#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \
IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \
IXP4XX_FEATURE_RSA)
#endif
......@@ -79,20 +79,6 @@ extern unsigned long ixp4xx_exp_bus_size;
#define IXP4XX_PERIPHERAL_BUS_CLOCK (66) /* 66MHzi APB BUS */
#define IXP4XX_UART_XTAL 14745600
/*
* This structure provide a means for the board setup code
* to give information to th pata_ixp4xx driver. It is
* passed as platform_data.
*/
struct ixp4xx_pata_data {
volatile u32 *cs0_cfg;
volatile u32 *cs1_cfg;
unsigned long cs0_bits;
unsigned long cs1_bits;
void __iomem *cs0;
void __iomem *cs1;
};
/*
* Frequency of clock used for primary clocksource
*/
......
......@@ -9,8 +9,12 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include <mach/ixp4xx-regs.h>
/*
* These are the only fixed phys to virt mappings we ever need
* we put it right after the UART mapping at 0xffc80000-0xffc81fff
*/
#define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000
#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000
static struct map_desc ixp4xx_of_io_desc[] __initdata = {
/*
......
......@@ -33,6 +33,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <mach/hardware.h>
#include "irqs.h"
......
......@@ -31,6 +31,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
#include <mach/hardware.h>
#include "irqs.h"
......
......@@ -26,7 +26,6 @@
extern struct omap_domain_base cm_base;
extern struct omap_domain_base cm2_base;
extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2);
# endif
/*
......
......@@ -37,19 +37,6 @@ struct omap_domain_base cm2_base;
#define CM_NO_CLOCKS 0x1
#define CM_SINGLE_INSTANCE 0x2
/**
* omap2_set_globals_cm - set the CM/CM2 base addresses (for early use)
* @cm: CM base virtual address
* @cm2: CM2 base virtual address (if present on the booted SoC)
*
* XXX Will be replaced when the PRM/CM drivers are completed.
*/
void __init omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2)
{
cm_base.va = cm;
cm2_base.va = cm2;
}
/**
* cm_split_idlest_reg - split CM_IDLEST reg addr into its components
* @idlest_reg: CM_IDLEST* virtual address
......
......@@ -130,7 +130,6 @@ void am33xx_init_early(void);
void am35xx_init_early(void);
void ti814x_init_early(void);
void ti816x_init_early(void);
void am33xx_init_early(void);
void am43xx_init_early(void);
void am43xx_init_late(void);
void omap4430_init_early(void);
......
......@@ -136,11 +136,6 @@ struct omap3_control_regs {
static struct omap3_control_regs control_context;
#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
void __init omap2_set_globals_control(void __iomem *ctrl)
{
omap2_ctrl_base = ctrl;
}
u8 omap_ctrl_readb(u16 offset)
{
u32 val;
......
......@@ -528,7 +528,6 @@ extern int omap3_ctrl_save_padconf(void);
void omap3_ctrl_init(void);
int omap2_control_base_init(void);
int omap_control_init(void);
void omap2_set_globals_control(void __iomem *ctrl);
void __init omap3_control_legacy_iomap_init(void);
#else
#define omap_ctrl_readb(x) 0
......
......@@ -8,6 +8,7 @@
#include <linux/cpuidle.h>
#include <linux/platform_data/pm33xx.h>
#include <linux/suspend.h>
#include <asm/cpuidle.h>
#include <asm/smp_scu.h>
#include <asm/suspend.h>
......@@ -324,6 +325,44 @@ static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void)
return NULL;
}
#ifdef CONFIG_SUSPEND
/*
* Block system suspend initially. Later on pm33xx sets up it's own
* platform_suspend_ops after probe. That depends also on loaded
* wkup_m3_ipc and booted am335x-pm-firmware.elf.
*/
static int amx3_suspend_block(suspend_state_t state)
{
pr_warn("PM not initialized for pm33xx, wkup_m3_ipc, or am335x-pm-firmware.elf\n");
return -EINVAL;
}
static int amx3_pm_valid(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_STANDBY:
return 1;
default:
return 0;
}
}
static const struct platform_suspend_ops amx3_blocked_pm_ops = {
.begin = amx3_suspend_block,
.valid = amx3_pm_valid,
};
static void __init amx3_block_suspend(void)
{
suspend_set_ops(&amx3_blocked_pm_ops);
}
#else
static inline void amx3_block_suspend(void)
{
}
#endif /* CONFIG_SUSPEND */
int __init amx3_common_pm_init(void)
{
struct am33xx_pm_platform_data *pdata;
......@@ -337,6 +376,7 @@ int __init amx3_common_pm_init(void)
devinfo.size_data = sizeof(*pdata);
devinfo.id = -1;
platform_device_register_full(&devinfo);
amx3_block_suspend();
return 0;
}
......
......@@ -271,7 +271,6 @@ static int rx1950_led_blink_set(struct gpio_desc *desc, int state,
break;
default:
return -EINVAL;
break;
}
if (delay_on && delay_off && !*delay_on && !*delay_off)
......
......@@ -16,6 +16,7 @@ config ARCH_SUNXI
select IRQ_FASTEOI_HIERARCHY_HANDLERS
select PINCTRL
select RESET_CONTROLLER
select SUN4I_TIMER
help
This enables support for Allwinner sunxi based SoCs like the A64.
......
......@@ -79,7 +79,7 @@ &ehci1 {
&emac {
pinctrl-names = "default";
pinctrl-0 = <&rgmii_pins>;
phy-mode = "rgmii-id";
phy-mode = "rgmii-txid";
phy-handle = <&ext_rgmii_phy>;
phy-supply = <&reg_dc1sw>;
status = "okay";
......
......@@ -227,7 +227,7 @@ pcie0: pcie@f8000000 {
<&pcie_phy 2>, <&pcie_phy 3>;
phy-names = "pcie-phy-0", "pcie-phy-1",
"pcie-phy-2", "pcie-phy-3";
ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x1e00000>,
ranges = <0x82000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x1e00000>,
<0x81000000 0x0 0xfbe00000 0x0 0xfbe00000 0x0 0x100000>;
resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
<&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>,
......
......@@ -1058,7 +1058,7 @@ config PATA_ISAPNP
config PATA_IXP4XX_CF
tristate "IXP4XX Compact Flash support"
depends on ARCH_IXP4XX
depends on ARCH_IXP4XX || COMPILE_TEST
help
This option enables support for a Compact Flash connected on
the ixp4xx expansion bus. This driver had been written for
......
......@@ -17,6 +17,7 @@
#include <linux/libata.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/platform_data/pata_ixp4xx_cf.h>
#include <scsi/scsi_host.h>
#define DRV_NAME "pata_ixp4xx_cf"
......
......@@ -152,7 +152,7 @@ config HW_RANDOM_VIA
config HW_RANDOM_IXP4XX
tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support"
depends on ARCH_IXP4XX
depends on ARCH_IXP4XX || COMPILE_TEST
default HW_RANDOM
help
This driver provides kernel-side support for the Pseudo-Random
......
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/char/hw_random/ixp4xx-rng.c
*
......@@ -8,23 +9,20 @@
* Copyright 2005 (c) MontaVista Software, Inc.
*
* Fixes by Michael Buesch
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/hw_random.h>
#include <linux/of.h>
#include <linux/soc/ixp4xx/cpu.h>
#include <asm/io.h>
#include <mach/hardware.h>
static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer)
{
......@@ -40,35 +38,40 @@ static struct hwrng ixp4xx_rng_ops = {
.data_read = ixp4xx_rng_data_read,
};
static int __init ixp4xx_rng_init(void)
static int ixp4xx_rng_probe(struct platform_device *pdev)
{
void __iomem * rng_base;
int err;
struct device *dev = &pdev->dev;
struct resource *res;
if (!cpu_is_ixp46x()) /* includes IXP455 */
return -ENOSYS;
rng_base = ioremap(0x70002100, 4);
if (!rng_base)
return -ENOMEM;
ixp4xx_rng_ops.priv = (unsigned long)rng_base;
err = hwrng_register(&ixp4xx_rng_ops);
if (err)
iounmap(rng_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rng_base = devm_ioremap_resource(dev, res);
if (IS_ERR(rng_base))
return PTR_ERR(rng_base);
return err;
ixp4xx_rng_ops.priv = (unsigned long)rng_base;
return devm_hwrng_register(dev, &ixp4xx_rng_ops);
}
static void __exit ixp4xx_rng_exit(void)
{
void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv;
hwrng_unregister(&ixp4xx_rng_ops);
iounmap(rng_base);
}
static const struct of_device_id ixp4xx_rng_of_match[] = {
{
.compatible = "intel,ixp46x-rng",
},
{},
};
MODULE_DEVICE_TABLE(of, ixp4xx_rng_of_match);
module_init(ixp4xx_rng_init);
module_exit(ixp4xx_rng_exit);
static struct platform_driver ixp4xx_rng_driver = {
.driver = {
.name = "ixp4xx-hwrandom",
.of_match_table = ixp4xx_rng_of_match,
},
.probe = ixp4xx_rng_probe,
};
module_platform_driver(ixp4xx_rng_driver);
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
MODULE_DESCRIPTION("H/W Pseudo-Random Number Generator (RNG) driver for IXP45x/46x");
......
......@@ -31,6 +31,10 @@
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
/* Intermittent includes, delete this after v5.14-rc1 */
#include <linux/soc/ixp4xx/cpu.h>
#include <mach/ixp4xx-regs.h>
#define MAX_KEYLEN 32
/* hash: cfgword + 2 * digestlen; crypt: keylen + cfgword */
......
......@@ -37,6 +37,8 @@
#include <linux/module.h>
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
#include <mach/hardware.h>
#include <linux/soc/ixp4xx/cpu.h>
#include "ixp46x_ts.h"
......
......@@ -12,9 +12,8 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/soc/ixp4xx/cpu.h>
#include "ixp46x_ts.h"
......
......@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/soc/ixp4xx/npe.h>
#include <linux/soc/ixp4xx/qmgr.h>
#include <linux/soc/ixp4xx/cpu.h>
#define DEBUG_DESC 0
#define DEBUG_RX 0
......
......@@ -37,6 +37,14 @@ config PCI_FTPCI100
depends on OF
default ARCH_GEMINI
config PCI_IXP4XX
bool "Intel IXP4xx PCI controller"
depends on ARM && OF
default ARCH_IXP4XX
help
Say Y here if you want support for the PCI host controller found
in the Intel IXP4xx XScale-based network processor SoC.
config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
depends on ARCH_TEGRA || COMPILE_TEST
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PCIE_CADENCE) += cadence/
obj-$(CONFIG_PCI_FTPCI100) += pci-ftpci100.o
obj-$(CONFIG_PCI_IXP4XX) += pci-ixp4xx.o
obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o
obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Support for Intel IXP4xx PCI host controller
*
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*
* Based on the IXP4xx arch/arm/mach-ixp4xx/common-pci.c driver
* Copyright (C) 2002 Intel Corporation
* Copyright (C) 2003 Greg Ungerer <gerg@linux-m68k.org>
* Copyright (C) 2003-2004 MontaVista Software, Inc.
* Copyright (C) 2005 Deepak Saxena <dsaxena@plexity.net>
* Copyright (C) 2005 Alessandro Zummo <a.zummo@towertech.it>
*
* TODO:
* - Test IO-space access
* - DMA support
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/bits.h>
/* Register offsets */
#define IXP4XX_PCI_NP_AD 0x00
#define IXP4XX_PCI_NP_CBE 0x04
#define IXP4XX_PCI_NP_WDATA 0x08
#define IXP4XX_PCI_NP_RDATA 0x0c
#define IXP4XX_PCI_CRP_AD_CBE 0x10
#define IXP4XX_PCI_CRP_WDATA 0x14
#define IXP4XX_PCI_CRP_RDATA 0x18
#define IXP4XX_PCI_CSR 0x1c
#define IXP4XX_PCI_ISR 0x20
#define IXP4XX_PCI_INTEN 0x24
#define IXP4XX_PCI_DMACTRL 0x28
#define IXP4XX_PCI_AHBMEMBASE 0x2c
#define IXP4XX_PCI_AHBIOBASE 0x30
#define IXP4XX_PCI_PCIMEMBASE 0x34
#define IXP4XX_PCI_AHBDOORBELL 0x38
#define IXP4XX_PCI_PCIDOORBELL 0x3c
#define IXP4XX_PCI_ATPDMA0_AHBADDR 0x40
#define IXP4XX_PCI_ATPDMA0_PCIADDR 0x44
#define IXP4XX_PCI_ATPDMA0_LENADDR 0x48
#define IXP4XX_PCI_ATPDMA1_AHBADDR 0x4c
#define IXP4XX_PCI_ATPDMA1_PCIADDR 0x50
#define IXP4XX_PCI_ATPDMA1_LENADDR 0x54
/* CSR bit definitions */
#define IXP4XX_PCI_CSR_HOST BIT(0)
#define IXP4XX_PCI_CSR_ARBEN BIT(1)
#define IXP4XX_PCI_CSR_ADS BIT(2)
#define IXP4XX_PCI_CSR_PDS BIT(3)
#define IXP4XX_PCI_CSR_ABE BIT(4)
#define IXP4XX_PCI_CSR_DBT BIT(5)
#define IXP4XX_PCI_CSR_ASE BIT(8)
#define IXP4XX_PCI_CSR_IC BIT(15)
#define IXP4XX_PCI_CSR_PRST BIT(16)
/* ISR (Interrupt status) Register bit definitions */
#define IXP4XX_PCI_ISR_PSE BIT(0)
#define IXP4XX_PCI_ISR_PFE BIT(1)
#define IXP4XX_PCI_ISR_PPE BIT(2)
#define IXP4XX_PCI_ISR_AHBE BIT(3)
#define IXP4XX_PCI_ISR_APDC BIT(4)
#define IXP4XX_PCI_ISR_PADC BIT(5)
#define IXP4XX_PCI_ISR_ADB BIT(6)
#define IXP4XX_PCI_ISR_PDB BIT(7)
/* INTEN (Interrupt Enable) Register bit definitions */
#define IXP4XX_PCI_INTEN_PSE BIT(0)
#define IXP4XX_PCI_INTEN_PFE BIT(1)
#define IXP4XX_PCI_INTEN_PPE BIT(2)
#define IXP4XX_PCI_INTEN_AHBE BIT(3)
#define IXP4XX_PCI_INTEN_APDC BIT(4)
#define IXP4XX_PCI_INTEN_PADC BIT(5)
#define IXP4XX_PCI_INTEN_ADB BIT(6)
#define IXP4XX_PCI_INTEN_PDB BIT(7)
/* Shift value for byte enable on NP cmd/byte enable register */
#define IXP4XX_PCI_NP_CBE_BESL 4
/* PCI commands supported by NP access unit */
#define NP_CMD_IOREAD 0x2
#define NP_CMD_IOWRITE 0x3
#define NP_CMD_CONFIGREAD 0xa
#define NP_CMD_CONFIGWRITE 0xb
#define NP_CMD_MEMREAD 0x6
#define NP_CMD_MEMWRITE 0x7
/* Constants for CRP access into local config space */
#define CRP_AD_CBE_BESL 20
#define CRP_AD_CBE_WRITE 0x00010000
/* Special PCI configuration space registers for this controller */
#define IXP4XX_PCI_RTOTTO 0x40
struct ixp4xx_pci {
struct device *dev;
void __iomem *base;
bool errata_hammer;
bool host_mode;
};
/*
* The IXP4xx has a peculiar address bus that will change the
* byte order on SoC peripherals depending on whether the device
* operates in big-endian or little-endian mode. That means that
* readl() and writel() that always use little-endian access
* will not work for SoC peripherals such as the PCI controller
* when used in big-endian mode. The accesses to the individual
* PCI devices on the other hand, are always little-endian and
* can use readl() and writel().
*
* For local AHB bus access we need to use __raw_[readl|writel]()
* to make sure that we access the SoC devices in the CPU native
* endianness.
*/
static inline u32 ixp4xx_readl(struct ixp4xx_pci *p, u32 reg)
{
return __raw_readl(p->base + reg);
}
static inline void ixp4xx_writel(struct ixp4xx_pci *p, u32 reg, u32 val)
{
__raw_writel(val, p->base + reg);
}
static int ixp4xx_pci_check_master_abort(struct ixp4xx_pci *p)
{
u32 isr = ixp4xx_readl(p, IXP4XX_PCI_ISR);
if (isr & IXP4XX_PCI_ISR_PFE) {
/* Make sure the master abort bit is reset */
ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE);
dev_dbg(p->dev, "master abort detected\n");
return -EINVAL;
}
return 0;
}
static int ixp4xx_pci_read(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 *data)
{
ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr);
if (p->errata_hammer) {
int i;
/*
* PCI workaround - only works if NP PCI space reads have
* no side effects. Hammer the register and read twice 8
* times. last one will be good.
*/
for (i = 0; i < 8; i++) {
ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
*data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
*data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
}
} else {
ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
*data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA);
}
return ixp4xx_pci_check_master_abort(p);
}
static int ixp4xx_pci_write(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 data)
{
ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr);
/* Set up the write */
ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd);
/* Execute the write by writing to NP_WDATA */
ixp4xx_writel(p, IXP4XX_PCI_NP_WDATA, data);
return ixp4xx_pci_check_master_abort(p);
}
static u32 ixp4xx_config_addr(u8 bus_num, u16 devfn, int where)
{
/* Root bus is always 0 in this hardware */
if (bus_num == 0) {
/* type 0 */
return BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) |
(where & ~3);
} else {
/* type 1 */
return (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) |
((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1;
}
}
/*
* CRP functions are "Controller Configuration Port" accesses
* initiated from within this driver itself to read/write PCI
* control information in the config space.
*/
static u32 ixp4xx_crp_byte_lane_enable_bits(u32 n, int size)
{
if (size == 1)
return (0xf & ~BIT(n)) << CRP_AD_CBE_BESL;
if (size == 2)
return (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL;
if (size == 4)
return 0;
return 0xffffffff;
}
static int ixp4xx_crp_read_config(struct ixp4xx_pci *p, int where, int size,
u32 *value)
{
u32 n, cmd, val;
n = where % 4;
cmd = where & ~3;
dev_dbg(p->dev, "%s from %d size %d cmd %08x\n",
__func__, where, size, cmd);
ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd);
val = ixp4xx_readl(p, IXP4XX_PCI_CRP_RDATA);
val >>= (8*n);
switch (size) {
case 1:
val &= U8_MAX;
dev_dbg(p->dev, "%s read byte %02x\n", __func__, val);
break;
case 2:
val &= U16_MAX;
dev_dbg(p->dev, "%s read word %04x\n", __func__, val);
break;
case 4:
val &= U32_MAX;
dev_dbg(p->dev, "%s read long %08x\n", __func__, val);
break;
default:
/* Should not happen */
dev_err(p->dev, "%s illegal size\n", __func__);
return PCIBIOS_DEVICE_NOT_FOUND;
}
*value = val;
return PCIBIOS_SUCCESSFUL;
}
static int ixp4xx_crp_write_config(struct ixp4xx_pci *p, int where, int size,
u32 value)
{
u32 n, cmd, val;
n = where % 4;
cmd = ixp4xx_crp_byte_lane_enable_bits(n, size);
if (cmd == 0xffffffff)
return PCIBIOS_BAD_REGISTER_NUMBER;
cmd |= where & ~3;
cmd |= CRP_AD_CBE_WRITE;
val = value << (8*n);
dev_dbg(p->dev, "%s to %d size %d cmd %08x val %08x\n",
__func__, where, size, cmd, val);
ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd);
ixp4xx_writel(p, IXP4XX_PCI_CRP_WDATA, val);
return PCIBIOS_SUCCESSFUL;
}
/*
* Then follows the functions that read and write from the common PCI
* configuration space.
*/
static u32 ixp4xx_byte_lane_enable_bits(u32 n, int size)
{
if (size == 1)
return (0xf & ~BIT(n)) << 4;
if (size == 2)
return (0xf & ~(BIT(n) | BIT(n+1))) << 4;
if (size == 4)
return 0;
return 0xffffffff;
}
static int ixp4xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *value)
{
struct ixp4xx_pci *p = bus->sysdata;
u32 n, addr, val, cmd;
u8 bus_num = bus->number;
int ret;
*value = 0xffffffff;
n = where % 4;
cmd = ixp4xx_byte_lane_enable_bits(n, size);
if (cmd == 0xffffffff)
return PCIBIOS_BAD_REGISTER_NUMBER;
addr = ixp4xx_config_addr(bus_num, devfn, where);
cmd |= NP_CMD_CONFIGREAD;
dev_dbg(p->dev, "read_config from %d size %d dev %d:%d:%d address: %08x cmd: %08x\n",
where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd);
ret = ixp4xx_pci_read(p, addr, cmd, &val);
if (ret)
return PCIBIOS_DEVICE_NOT_FOUND;
val >>= (8*n);
switch (size) {
case 1:
val &= U8_MAX;
dev_dbg(p->dev, "%s read byte %02x\n", __func__, val);
break;
case 2:
val &= U16_MAX;
dev_dbg(p->dev, "%s read word %04x\n", __func__, val);
break;
case 4:
val &= U32_MAX;
dev_dbg(p->dev, "%s read long %08x\n", __func__, val);
break;
default:
/* Should not happen */
dev_err(p->dev, "%s illegal size\n", __func__);
return PCIBIOS_DEVICE_NOT_FOUND;
}
*value = val;
return PCIBIOS_SUCCESSFUL;
}
static int ixp4xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 value)
{
struct ixp4xx_pci *p = bus->sysdata;
u32 n, addr, val, cmd;
u8 bus_num = bus->number;
int ret;
n = where % 4;
cmd = ixp4xx_byte_lane_enable_bits(n, size);
if (cmd == 0xffffffff)
return PCIBIOS_BAD_REGISTER_NUMBER;
addr = ixp4xx_config_addr(bus_num, devfn, where);
cmd |= NP_CMD_CONFIGWRITE;
val = value << (8*n);
dev_dbg(p->dev, "write_config_byte %#x to %d size %d dev %d:%d:%d addr: %08x cmd %08x\n",
value, where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd);
ret = ixp4xx_pci_write(p, addr, cmd, val);
if (ret)
return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops ixp4xx_pci_ops = {
.read = ixp4xx_pci_read_config,
.write = ixp4xx_pci_write_config,
};
static u32 ixp4xx_pci_addr_to_64mconf(phys_addr_t addr)
{
u8 base;
base = ((addr & 0xff000000) >> 24);
return (base << 24) | ((base + 1) << 16)
| ((base + 2) << 8) | (base + 3);
}
static int ixp4xx_pci_parse_map_ranges(struct ixp4xx_pci *p)
{
struct device *dev = p->dev;
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p);
struct resource_entry *win;
struct resource *res;
phys_addr_t addr;
win = resource_list_first_type(&bridge->windows, IORESOURCE_MEM);
if (win) {
u32 pcimembase;
res = win->res;
addr = res->start - win->offset;
if (res->flags & IORESOURCE_PREFETCH)
res->name = "IXP4xx PCI PRE-MEM";
else
res->name = "IXP4xx PCI NON-PRE-MEM";
dev_dbg(dev, "%s window %pR, bus addr %pa\n",
res->name, res, &addr);
if (resource_size(res) != SZ_64M) {
dev_err(dev, "memory range is not 64MB\n");
return -EINVAL;
}
pcimembase = ixp4xx_pci_addr_to_64mconf(addr);
/* Commit configuration */
ixp4xx_writel(p, IXP4XX_PCI_PCIMEMBASE, pcimembase);
} else {
dev_err(dev, "no AHB memory mapping defined\n");
}
win = resource_list_first_type(&bridge->windows, IORESOURCE_IO);
if (win) {
res = win->res;
addr = pci_pio_to_address(res->start);
if (addr & 0xff) {
dev_err(dev, "IO mem at uneven address: %pa\n", &addr);
return -EINVAL;
}
res->name = "IXP4xx PCI IO MEM";
/*
* Setup I/O space location for PCI->AHB access, the
* upper 24 bits of the address goes into the lower
* 24 bits of this register.
*/
ixp4xx_writel(p, IXP4XX_PCI_AHBIOBASE, (addr >> 8));
} else {
dev_info(dev, "no IO space AHB memory mapping defined\n");
}
return 0;
}
static int ixp4xx_pci_parse_map_dma_ranges(struct ixp4xx_pci *p)
{
struct device *dev = p->dev;
struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p);
struct resource_entry *win;
struct resource *res;
phys_addr_t addr;
u32 ahbmembase;
win = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM);
if (win) {
res = win->res;
addr = res->start - win->offset;
if (resource_size(res) != SZ_64M) {
dev_err(dev, "DMA memory range is not 64MB\n");
return -EINVAL;
}
dev_dbg(dev, "DMA MEM BASE: %pa\n", &addr);
/*
* 4 PCI-to-AHB windows of 16 MB each, write the 8 high bits
* into each byte of the PCI_AHBMEMBASE register.
*/
ahbmembase = ixp4xx_pci_addr_to_64mconf(addr);
/* Commit AHB membase */
ixp4xx_writel(p, IXP4XX_PCI_AHBMEMBASE, ahbmembase);
} else {
dev_err(dev, "no DMA memory range defined\n");
}
return 0;
}
/* Only used to get context for abort handling */
static struct ixp4xx_pci *ixp4xx_pci_abort_singleton;
static int ixp4xx_pci_abort_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
struct ixp4xx_pci *p = ixp4xx_pci_abort_singleton;
u32 isr, status;
int ret;
isr = ixp4xx_readl(p, IXP4XX_PCI_ISR);
ret = ixp4xx_crp_read_config(p, PCI_STATUS, 2, &status);
if (ret) {
dev_err(p->dev, "unable to read abort status\n");
return -EINVAL;
}
dev_err(p->dev,
"PCI: abort_handler addr = %#lx, isr = %#x, status = %#x\n",
addr, isr, status);
/* Make sure the Master Abort bit is reset */
ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE);
status |= PCI_STATUS_REC_MASTER_ABORT;
ret = ixp4xx_crp_write_config(p, PCI_STATUS, 2, status);
if (ret)
dev_err(p->dev, "unable to clear abort status bit\n");
/*
* If it was an imprecise abort, then we need to correct the
* return address to be _after_ the instruction.
*/
if (fsr & (1 << 10)) {
dev_err(p->dev, "imprecise abort\n");
regs->ARM_pc += 4;
}
return 0;
}
static int __init ixp4xx_pci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct ixp4xx_pci *p;
struct pci_host_bridge *host;
int ret;
u32 val;
phys_addr_t addr;
u32 basereg[4] = {
PCI_BASE_ADDRESS_0,
PCI_BASE_ADDRESS_1,
PCI_BASE_ADDRESS_2,
PCI_BASE_ADDRESS_3,
};
int i;
host = devm_pci_alloc_host_bridge(dev, sizeof(*p));
if (!host)
return -ENOMEM;
host->ops = &ixp4xx_pci_ops;
p = pci_host_bridge_priv(host);
host->sysdata = p;
p->dev = dev;
dev_set_drvdata(dev, p);
/*
* Set up quirk for erratic behaviour in the 42x variant
* when accessing config space.
*/
if (of_device_is_compatible(np, "intel,ixp42x-pci")) {
p->errata_hammer = true;
dev_info(dev, "activate hammering errata\n");
}
p->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(p->base))
return PTR_ERR(p->base);
val = ixp4xx_readl(p, IXP4XX_PCI_CSR);
p->host_mode = !!(val & IXP4XX_PCI_CSR_HOST);
dev_info(dev, "controller is in %s mode\n",
p->host_mode ? "host" : "option");
/* Hook in our fault handler for PCI errors */
ixp4xx_pci_abort_singleton = p;
hook_fault_code(16+6, ixp4xx_pci_abort_handler, SIGBUS, 0,
"imprecise external abort");
ret = ixp4xx_pci_parse_map_ranges(p);
if (ret)
return ret;
ret = ixp4xx_pci_parse_map_dma_ranges(p);
if (ret)
return ret;
/* This is only configured in host mode */
if (p->host_mode) {
addr = __pa(PAGE_OFFSET);
/* This is a noop (0x00) but explains what is going on */
addr |= PCI_BASE_ADDRESS_SPACE_MEMORY;
for (i = 0; i < 4; i++) {
/* Write this directly into the config space */
ret = ixp4xx_crp_write_config(p, basereg[i], 4, addr);
if (ret)
dev_err(dev, "failed to set up PCI_BASE_ADDRESS_%d\n", i);
else
dev_info(dev, "set PCI_BASE_ADDR_%d to %pa\n", i, &addr);
addr += SZ_16M;
}
/*
* Enable CSR window at 64 MiB to allow PCI masters to continue
* prefetching past the 64 MiB boundary, if all AHB to PCI
* windows are consecutive.
*/
ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_4, 4, addr);
if (ret)
dev_err(dev, "failed to set up PCI_BASE_ADDRESS_4\n");
else
dev_info(dev, "set PCI_BASE_ADDR_4 to %pa\n", &addr);
/*
* Put the IO memory window at the very end of physical memory
* at 0xfffffc00. This is when the system is trying to access IO
* memory over AHB.
*/
addr = 0xfffffc00;
addr |= PCI_BASE_ADDRESS_SPACE_IO;
ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_5, 4, addr);
if (ret)
dev_err(dev, "failed to set up PCI_BASE_ADDRESS_5\n");
else
dev_info(dev, "set PCI_BASE_ADDR_5 to %pa\n", &addr);
/*
* Retry timeout to 0x80
* Transfer ready timeout to 0xff
*/
ret = ixp4xx_crp_write_config(p, IXP4XX_PCI_RTOTTO, 4,
0x000080ff);
if (ret)
dev_err(dev, "failed to set up TRDY limit\n");
else
dev_info(dev, "set TRDY limit to 0x80ff\n");
}
/* Clear interrupts */
val = IXP4XX_PCI_ISR_PSE | IXP4XX_PCI_ISR_PFE | IXP4XX_PCI_ISR_PPE | IXP4XX_PCI_ISR_AHBE;
ixp4xx_writel(p, IXP4XX_PCI_ISR, val);
/*
* Set Initialize Complete in PCI Control Register: allow IXP4XX to
* generate PCI configuration cycles. Specify that the AHB bus is
* operating in big-endian mode. Set up byte lane swapping between
* little-endian PCI and the big-endian AHB bus.
*/
val = IXP4XX_PCI_CSR_IC | IXP4XX_PCI_CSR_ABE;
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
val |= (IXP4XX_PCI_CSR_PDS | IXP4XX_PCI_CSR_ADS);
ixp4xx_writel(p, IXP4XX_PCI_CSR, val);
ret = ixp4xx_crp_write_config(p, PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
if (ret)
dev_err(dev, "unable to initialize master and command memory\n");
else
dev_info(dev, "initialized as master\n");
pci_host_probe(host);
return 0;
}
static const struct of_device_id ixp4xx_pci_of_match[] = {
{
.compatible = "intel,ixp42x-pci",
},
{
.compatible = "intel,ixp43x-pci",
},
{},
};
/*
* This driver needs to be a builtin module with suppressed bind
* attributes since the probe() is initializing a hard exception
* handler and this can only be done from __init-tagged code
* sections. This module cannot be removed and inserted at all.
*/
static struct platform_driver ixp4xx_pci_driver = {
.driver = {
.name = "ixp4xx-pci",
.suppress_bind_attrs = true,
.of_match_table = ixp4xx_pci_of_match,
},
};
builtin_platform_driver_probe(ixp4xx_pci_driver, ixp4xx_pci_probe);
......@@ -70,6 +70,9 @@ static int __init imx_soc_device_init(void)
case MXC_CPU_MX35:
soc_id = "i.MX35";
break;
case MXC_CPU_MX50:
soc_id = "i.MX50";
break;
case MXC_CPU_MX51:
ocotp_compat = "fsl,imx51-iim";
soc_id = "i.MX51";
......
......@@ -21,6 +21,8 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/soc/ixp4xx/npe.h>
#include <mach/hardware.h>
#include <linux/soc/ixp4xx/cpu.h>
#define DEBUG_MSG 0
#define DEBUG_FW 0
......
......@@ -12,6 +12,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/soc/ixp4xx/qmgr.h>
#include <mach/hardware.h>
#include <linux/soc/ixp4xx/cpu.h>
static struct qmgr_regs __iomem *qmgr_regs;
static int qmgr_irq_1;
......
......@@ -144,6 +144,8 @@ config SOC_TEGRA_FLOWCTRL
config SOC_TEGRA_PMC
bool
select GENERIC_PINCONF
select PM_OPP
select PM_GENERIC_DOMAINS
config SOC_TEGRA_POWERGATE_BPMP
def_bool y
......
......@@ -3,9 +3,16 @@
* Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
*/
#define dev_fmt(fmt) "tegra-soc: " fmt
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/of.h>
#include <linux/pm_opp.h>
#include <soc/tegra/common.h>
#include <soc/tegra/fuse.h>
static const struct of_device_id tegra_machine_match[] = {
{ .compatible = "nvidia,tegra20", },
......@@ -31,3 +38,93 @@ bool soc_is_tegra(void)
return match != NULL;
}
static int tegra_core_dev_init_opp_state(struct device *dev)
{
unsigned long rate;
struct clk *clk;
int err;
clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk)) {
dev_err(dev, "failed to get clk: %pe\n", clk);
return PTR_ERR(clk);
}
rate = clk_get_rate(clk);
if (!rate) {
dev_err(dev, "failed to get clk rate\n");
return -EINVAL;
}
/* first dummy rate-setting initializes voltage vote */
err = dev_pm_opp_set_rate(dev, rate);
if (err) {
dev_err(dev, "failed to initialize OPP clock: %d\n", err);
return err;
}
return 0;
}
/**
* devm_tegra_core_dev_init_opp_table() - initialize OPP table
* @dev: device for which OPP table is initialized
* @params: pointer to the OPP table configuration
*
* This function will initialize OPP table and sync OPP state of a Tegra SoC
* core device.
*
* Return: 0 on success or errorno.
*/
int devm_tegra_core_dev_init_opp_table(struct device *dev,
struct tegra_core_opp_params *params)
{
u32 hw_version;
int err;
err = devm_pm_opp_set_clkname(dev, NULL);
if (err) {
dev_err(dev, "failed to set OPP clk: %d\n", err);
return err;
}
/* Tegra114+ doesn't support OPP yet */
if (!of_machine_is_compatible("nvidia,tegra20") &&
!of_machine_is_compatible("nvidia,tegra30"))
return -ENODEV;
if (of_machine_is_compatible("nvidia,tegra20"))
hw_version = BIT(tegra_sku_info.soc_process_id);
else
hw_version = BIT(tegra_sku_info.soc_speedo_id);
err = devm_pm_opp_set_supported_hw(dev, &hw_version, 1);
if (err) {
dev_err(dev, "failed to set OPP supported HW: %d\n", err);
return err;
}
/*
* Older device-trees have an empty OPP table, we will get
* -ENODEV from devm_pm_opp_of_add_table() in this case.
*/
err = devm_pm_opp_of_add_table(dev);
if (err) {
if (err == -ENODEV)
dev_err_once(dev, "OPP table not found, please update device-tree\n");
else
dev_err(dev, "failed to add OPP table: %d\n", err);
return err;
}
if (params->init_state) {
err = tegra_core_dev_init_opp_state(dev);
if (err)
return err;
}
return 0;
}
EXPORT_SYMBOL_GPL(devm_tegra_core_dev_init_opp_table);
......@@ -489,9 +489,7 @@ static int __init tegra_init_fuse(void)
size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups;
fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL);
if (!fuse->lookups)
return -ENOMEM;
if (fuse->lookups)
nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups);
}
......
......@@ -37,7 +37,8 @@
defined(CONFIG_ARCH_TEGRA_132_SOC) || \
defined(CONFIG_ARCH_TEGRA_210_SOC) || \
defined(CONFIG_ARCH_TEGRA_186_SOC) || \
defined(CONFIG_ARCH_TEGRA_194_SOC)
defined(CONFIG_ARCH_TEGRA_194_SOC) || \
defined(CONFIG_ARCH_TEGRA_234_SOC)
static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
{
if (WARN_ON(!fuse->base))
......
......@@ -38,6 +38,7 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/reset.h>
......@@ -428,6 +429,9 @@ struct tegra_pmc {
struct irq_chip irq;
struct notifier_block clk_nb;
bool core_domain_state_synced;
bool core_domain_registered;
};
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
......@@ -1297,12 +1301,107 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
return err;
}
bool tegra_pmc_core_domain_state_synced(void)
{
return pmc->core_domain_state_synced;
}
static int
tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd,
unsigned int level)
{
struct dev_pm_opp *opp;
int err;
opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level);
if (IS_ERR(opp)) {
dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n",
level, opp);
return PTR_ERR(opp);
}
mutex_lock(&pmc->powergates_lock);
err = dev_pm_opp_set_opp(pmc->dev, opp);
mutex_unlock(&pmc->powergates_lock);
dev_pm_opp_put(opp);
if (err) {
dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n",
level, err);
return err;
}
return 0;
}
static unsigned int
tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd,
struct dev_pm_opp *opp)
{
return dev_pm_opp_get_level(opp);
}
static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np)
{
struct generic_pm_domain *genpd;
const char *rname = "core";
int err;
genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL);
if (!genpd)
return -ENOMEM;
genpd->name = np->name;
genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state;
genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state;
err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1);
if (err)
return dev_err_probe(pmc->dev, err,
"failed to set core OPP regulator\n");
err = pm_genpd_init(genpd, NULL, false);
if (err) {
dev_err(pmc->dev, "failed to init core genpd: %d\n", err);
return err;
}
err = of_genpd_add_provider_simple(np, genpd);
if (err) {
dev_err(pmc->dev, "failed to add core genpd: %d\n", err);
goto remove_genpd;
}
pmc->core_domain_registered = true;
return 0;
remove_genpd:
pm_genpd_remove(genpd);
return err;
}
static int tegra_powergate_init(struct tegra_pmc *pmc,
struct device_node *parent)
{
struct of_phandle_args child_args, parent_args;
struct device_node *np, *child;
int err = 0;
/*
* Core power domain is the parent of powergate domains, hence it
* should be registered first.
*/
np = of_get_child_by_name(parent, "core-domain");
if (np) {
err = tegra_pmc_core_pd_add(pmc, np);
of_node_put(np);
if (err)
return err;
}
np = of_get_child_by_name(parent, "powergates");
if (!np)
return 0;
......@@ -1313,6 +1412,21 @@ static int tegra_powergate_init(struct tegra_pmc *pmc,
of_node_put(child);
break;
}
if (of_parse_phandle_with_args(child, "power-domains",
"#power-domain-cells",
0, &parent_args))
continue;
child_args.np = child;
child_args.args_count = 0;
err = of_genpd_add_subdomain(&parent_args, &child_args);
of_node_put(parent_args.np);
if (err) {
of_node_put(child);
break;
}
}
of_node_put(np);
......@@ -1356,6 +1470,12 @@ static void tegra_powergate_remove_all(struct device_node *parent)
}
of_node_put(np);
np = of_get_child_by_name(parent, "core-domain");
if (np) {
of_genpd_del_provider(np);
of_genpd_remove_last(np);
}
}
static const struct tegra_io_pad_soc *
......@@ -3667,6 +3787,29 @@ static const struct of_device_id tegra_pmc_match[] = {
{ }
};
static void tegra_pmc_sync_state(struct device *dev)
{
int err;
/*
* Older device-trees don't have core PD, and thus, there are
* no dependencies that will block the state syncing. We shouldn't
* mark the domain as synced in this case.
*/
if (!pmc->core_domain_registered)
return;
pmc->core_domain_state_synced = true;
/* this is a no-op if core regulator isn't used */
mutex_lock(&pmc->powergates_lock);
err = dev_pm_opp_sync_regulators(dev);
mutex_unlock(&pmc->powergates_lock);
if (err)
dev_err(dev, "failed to sync regulators: %d\n", err);
}
static struct platform_driver tegra_pmc_driver = {
.driver = {
.name = "tegra-pmc",
......@@ -3675,6 +3818,7 @@ static struct platform_driver tegra_pmc_driver = {
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
.pm = &tegra_pmc_pm_ops,
#endif
.sync_state = tegra_pmc_sync_state,
},
.probe = tegra_pmc_probe,
};
......
......@@ -12,16 +12,22 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/reboot.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <soc/tegra/pmc.h>
struct tegra_regulator_coupler {
struct regulator_coupler coupler;
struct regulator_dev *core_rdev;
struct regulator_dev *cpu_rdev;
struct regulator_dev *rtc_rdev;
int core_min_uV;
struct notifier_block reboot_notifier;
int core_min_uV, cpu_min_uV;
bool sys_reboot_mode_req;
bool sys_reboot_mode;
};
static inline struct tegra_regulator_coupler *
......@@ -38,6 +44,21 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
int core_cur_uV;
int err;
/*
* Tegra20 SoC has critical DVFS-capable devices that are
* permanently-active or active at a boot time, like EMC
* (DRAM controller) or Display controller for example.
*
* The voltage of a CORE SoC power domain shall not be dropped below
* a minimum level, which is determined by device's clock rate.
* This means that we can't fully allow CORE voltage scaling until
* the state of all DVFS-critical CORE devices is synced.
*/
if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) {
pr_info_once("voltage state synced\n");
return 0;
}
if (tegra->core_min_uV > 0)
return tegra->core_min_uV;
......@@ -58,7 +79,7 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
*/
tegra->core_min_uV = core_max_uV;
pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
pr_info("core voltage initialized to %duV\n", tegra->core_min_uV);
return tegra->core_min_uV;
}
......@@ -242,6 +263,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
if (cpu_uV < 0)
return cpu_uV;
/* store boot voltage level */
if (!tegra->cpu_min_uV)
tegra->cpu_min_uV = cpu_uV;
/*
* CPU's regulator may not have any consumers, hence the voltage
* must not be changed in that case because CPU simply won't
......@@ -250,6 +275,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
if (!cpu_min_uV_consumers)
cpu_min_uV = cpu_uV;
/* restore boot voltage level */
if (tegra->sys_reboot_mode)
cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV);
if (cpu_min_uV > cpu_uV) {
err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
cpu_uV, cpu_min_uV);
......@@ -290,6 +319,8 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
return -EINVAL;
}
tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req);
if (rdev == cpu_rdev)
return tegra20_cpu_voltage_update(tegra, cpu_rdev,
core_rdev, rtc_rdev);
......@@ -303,6 +334,51 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
return -EPERM;
}
static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra,
bool sys_reboot_mode)
{
int err;
if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev)
return 0;
WRITE_ONCE(tegra->sys_reboot_mode_req, true);
/*
* Some devices use CPU soft-reboot method and in this case we
* should ensure that voltages are sane for the reboot by restoring
* the minimum boot levels.
*/
err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
if (err)
return err;
err = regulator_sync_voltage_rdev(tegra->core_rdev);
if (err)
return err;
WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode);
return 0;
}
static int tegra20_regulator_reboot(struct notifier_block *notifier,
unsigned long event, void *cmd)
{
struct tegra_regulator_coupler *tegra;
int ret;
if (event != SYS_RESTART)
return NOTIFY_DONE;
tegra = container_of(notifier, struct tegra_regulator_coupler,
reboot_notifier);
ret = tegra20_regulator_prepare_reboot(tegra, true);
return notifier_from_errno(ret);
}
static int tegra20_regulator_attach(struct regulator_coupler *coupler,
struct regulator_dev *rdev)
{
......@@ -335,6 +411,14 @@ static int tegra20_regulator_detach(struct regulator_coupler *coupler,
{
struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
/*
* We don't expect regulators to be decoupled during reboot,
* this may race with the reboot handler and shouldn't ever
* happen in practice.
*/
if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING))
return -EPERM;
if (tegra->core_rdev == rdev) {
tegra->core_rdev = NULL;
return 0;
......@@ -359,13 +443,19 @@ static struct tegra_regulator_coupler tegra20_coupler = {
.detach_regulator = tegra20_regulator_detach,
.balance_voltage = tegra20_regulator_balance_voltage,
},
.reboot_notifier.notifier_call = tegra20_regulator_reboot,
};
static int __init tegra_regulator_coupler_init(void)
{
int err;
if (!of_machine_is_compatible("nvidia,tegra20"))
return 0;
err = register_reboot_notifier(&tegra20_coupler.reboot_notifier);
WARN_ON(err);
return regulator_coupler_register(&tegra20_coupler.coupler);
}
arch_initcall(tegra_regulator_coupler_init);
......@@ -12,17 +12,22 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/reboot.h>
#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/pmc.h>
struct tegra_regulator_coupler {
struct regulator_coupler coupler;
struct regulator_dev *core_rdev;
struct regulator_dev *cpu_rdev;
int core_min_uV;
struct notifier_block reboot_notifier;
int core_min_uV, cpu_min_uV;
bool sys_reboot_mode_req;
bool sys_reboot_mode;
};
static inline struct tegra_regulator_coupler *
......@@ -39,6 +44,21 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra,
int core_cur_uV;
int err;
/*
* Tegra30 SoC has critical DVFS-capable devices that are
* permanently-active or active at a boot time, like EMC
* (DRAM controller) or Display controller for example.
*
* The voltage of a CORE SoC power domain shall not be dropped below
* a minimum level, which is determined by device's clock rate.
* This means that we can't fully allow CORE voltage scaling until
* the state of all DVFS-critical CORE devices is synced.
*/
if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) {
pr_info_once("voltage state synced\n");
return 0;
}
if (tegra->core_min_uV > 0)
return tegra->core_min_uV;
......@@ -59,7 +79,7 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra,
*/
tegra->core_min_uV = core_max_uV;
pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
pr_info("core voltage initialized to %duV\n", tegra->core_min_uV);
return tegra->core_min_uV;
}
......@@ -172,6 +192,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
if (cpu_uV < 0)
return cpu_uV;
/* store boot voltage level */
if (!tegra->cpu_min_uV)
tegra->cpu_min_uV = cpu_uV;
/*
* CPU's regulator may not have any consumers, hence the voltage
* must not be changed in that case because CPU simply won't
......@@ -195,6 +219,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
if (err)
return err;
/* restore boot voltage level */
if (tegra->sys_reboot_mode)
cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV);
if (core_min_limited_uV > core_uV) {
pr_err("core voltage constraint violated: %d %d %d\n",
core_uV, core_min_limited_uV, cpu_uV);
......@@ -263,9 +291,56 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler,
return -EINVAL;
}
tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req);
return tegra30_voltage_update(tegra, cpu_rdev, core_rdev);
}
static int tegra30_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra,
bool sys_reboot_mode)
{
int err;
if (!tegra->core_rdev || !tegra->cpu_rdev)
return 0;
WRITE_ONCE(tegra->sys_reboot_mode_req, true);
/*
* Some devices use CPU soft-reboot method and in this case we
* should ensure that voltages are sane for the reboot by restoring
* the minimum boot levels.
*/
err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
if (err)
return err;
err = regulator_sync_voltage_rdev(tegra->core_rdev);
if (err)
return err;
WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode);
return 0;
}
static int tegra30_regulator_reboot(struct notifier_block *notifier,
unsigned long event, void *cmd)
{
struct tegra_regulator_coupler *tegra;
int ret;
if (event != SYS_RESTART)
return NOTIFY_DONE;
tegra = container_of(notifier, struct tegra_regulator_coupler,
reboot_notifier);
ret = tegra30_regulator_prepare_reboot(tegra, true);
return notifier_from_errno(ret);
}
static int tegra30_regulator_attach(struct regulator_coupler *coupler,
struct regulator_dev *rdev)
{
......@@ -292,6 +367,14 @@ static int tegra30_regulator_detach(struct regulator_coupler *coupler,
{
struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
/*
* We don't expect regulators to be decoupled during reboot,
* this may race with the reboot handler and shouldn't ever
* happen in practice.
*/
if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING))
return -EPERM;
if (tegra->core_rdev == rdev) {
tegra->core_rdev = NULL;
return 0;
......@@ -311,13 +394,19 @@ static struct tegra_regulator_coupler tegra30_coupler = {
.detach_regulator = tegra30_regulator_detach,
.balance_voltage = tegra30_regulator_balance_voltage,
},
.reboot_notifier.notifier_call = tegra30_regulator_reboot,
};
static int __init tegra_regulator_coupler_init(void)
{
int err;
if (!of_machine_is_compatible("nvidia,tegra30"))
return 0;
err = register_reboot_notifier(&tegra30_coupler.reboot_notifier);
WARN_ON(err);
return regulator_coupler_register(&tegra30_coupler.coupler);
}
arch_initcall(tegra_regulator_coupler_init);
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PLATFORM_DATA_PATA_IXP4XX_H
#define __PLATFORM_DATA_PATA_IXP4XX_H
#include <linux/types.h>
/*
* This structure provide a means for the board setup code
* to give information to th pata_ixp4xx driver. It is
* passed as platform_data.
*/
struct ixp4xx_pata_data {
volatile u32 *cs0_cfg;
volatile u32 *cs1_cfg;
unsigned long cs0_bits;
unsigned long cs1_bits;
void __iomem *cs0;
void __iomem *cs1;
};
#endif
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* arch/arm/mach-ixp4xx/include/mach/cpu.h
*
* IXP4XX cpu type detection
*
* Copyright (C) 2007 MontaVista Software, Inc.
*/
#ifndef __ASM_ARCH_CPU_H__
#define __ASM_ARCH_CPU_H__
#ifndef __SOC_IXP4XX_CPU_H__
#define __SOC_IXP4XX_CPU_H__
#include <linux/io.h>
#ifdef CONFIG_ARM
#include <asm/cputype.h>
#endif
/* Processor id value in CP15 Register 0 */
#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
......@@ -23,6 +23,61 @@
#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0
/* "fuse" bits of IXP_EXP_CFG2 */
/* All IXP4xx CPUs */
#define IXP4XX_FEATURE_RCOMP (1 << 0)
#define IXP4XX_FEATURE_USB_DEVICE (1 << 1)
#define IXP4XX_FEATURE_HASH (1 << 2)
#define IXP4XX_FEATURE_AES (1 << 3)
#define IXP4XX_FEATURE_DES (1 << 4)
#define IXP4XX_FEATURE_HDLC (1 << 5)
#define IXP4XX_FEATURE_AAL (1 << 6)
#define IXP4XX_FEATURE_HSS (1 << 7)
#define IXP4XX_FEATURE_UTOPIA (1 << 8)
#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9)
#define IXP4XX_FEATURE_NPEC_ETH (1 << 10)
#define IXP4XX_FEATURE_RESET_NPEA (1 << 11)
#define IXP4XX_FEATURE_RESET_NPEB (1 << 12)
#define IXP4XX_FEATURE_RESET_NPEC (1 << 13)
#define IXP4XX_FEATURE_PCI (1 << 14)
#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \
IXP4XX_FEATURE_USB_DEVICE | \
IXP4XX_FEATURE_HASH | \
IXP4XX_FEATURE_AES | \
IXP4XX_FEATURE_DES | \
IXP4XX_FEATURE_HDLC | \
IXP4XX_FEATURE_AAL | \
IXP4XX_FEATURE_HSS | \
IXP4XX_FEATURE_UTOPIA | \
IXP4XX_FEATURE_NPEB_ETH0 | \
IXP4XX_FEATURE_NPEC_ETH | \
IXP4XX_FEATURE_RESET_NPEA | \
IXP4XX_FEATURE_RESET_NPEB | \
IXP4XX_FEATURE_RESET_NPEC | \
IXP4XX_FEATURE_PCI | \
IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
IXP4XX_FEATURE_XSCALE_MAX_FREQ)
/* IXP43x/46x CPUs */
#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15)
#define IXP4XX_FEATURE_USB_HOST (1 << 18)
#define IXP4XX_FEATURE_NPEA_ETH (1 << 19)
#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \
IXP4XX_FEATURE_ECC_TIMESYNC | \
IXP4XX_FEATURE_USB_HOST | \
IXP4XX_FEATURE_NPEA_ETH)
/* IXP46x CPU (including IXP455) only */
#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
#define IXP4XX_FEATURE_RSA (1 << 21)
#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \
IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \
IXP4XX_FEATURE_RSA)
#ifdef CONFIG_ARCH_IXP4XX
#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
IXP42X_PROCESSOR_ID_VALUE)
#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
......@@ -32,23 +87,20 @@
#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
IXP46X_PROCESSOR_ID_VALUE)
u32 ixp4xx_read_feature_bits(void);
void ixp4xx_write_feature_bits(u32 value);
#else
#define cpu_is_ixp42x_rev_a0() 0
#define cpu_is_ixp42x() 0
#define cpu_is_ixp43x() 0
#define cpu_is_ixp46x() 0
static inline u32 ixp4xx_read_feature_bits(void)
{
u32 val = ~__raw_readl(IXP4XX_EXP_CFG2);
if (cpu_is_ixp42x_rev_a0())
return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
IXP4XX_FEATURE_AES);
if (cpu_is_ixp42x())
return val & IXP42X_FEATURE_MASK;
if (cpu_is_ixp43x())
return val & IXP43X_FEATURE_MASK;
return val & IXP46X_FEATURE_MASK;
return 0;
}
static inline void ixp4xx_write_feature_bits(u32 value)
{
__raw_writel(~value, IXP4XX_EXP_CFG2);
}
#endif
#endif /* _ASM_ARCH_CPU_H */
......@@ -611,12 +611,6 @@
#define EXYNOS5420_FSYS2_OPTION 0x4168
#define EXYNOS5420_PSGEN_OPTION 0x4188
/* For EXYNOS_CENTRAL_SEQ_OPTION */
#define EXYNOS5_USE_STANDBYWFI_ARM_CORE0 BIT(16)
#define EXYNOS5_USE_STANDBYWFI_ARM_CORE1 BUT(17)
#define EXYNOS5_USE_STANDBYWFE_ARM_CORE0 BIT(24)
#define EXYNOS5_USE_STANDBYWFE_ARM_CORE1 BIT(25)
#define EXYNOS5420_ARM_USE_STANDBY_WFI0 BIT(4)
#define EXYNOS5420_ARM_USE_STANDBY_WFI1 BIT(5)
#define EXYNOS5420_ARM_USE_STANDBY_WFI2 BIT(6)
......
......@@ -9,6 +9,7 @@
#define MXC_CPU_MX27 27
#define MXC_CPU_MX31 31
#define MXC_CPU_MX35 35
#define MXC_CPU_MX50 50
#define MXC_CPU_MX51 51
#define MXC_CPU_MX53 53
#define MXC_CPU_IMX6SL 0x60
......
......@@ -6,6 +6,37 @@
#ifndef __SOC_TEGRA_COMMON_H__
#define __SOC_TEGRA_COMMON_H__
#include <linux/errno.h>
#include <linux/types.h>
struct device;
/**
* Tegra SoC core device OPP table configuration
*
* @init_state: pre-initialize OPP state of a device
*/
struct tegra_core_opp_params {
bool init_state;
};
#ifdef CONFIG_ARCH_TEGRA
bool soc_is_tegra(void);
int devm_tegra_core_dev_init_opp_table(struct device *dev,
struct tegra_core_opp_params *params);
#else
static inline bool soc_is_tegra(void)
{
return false;
}
static inline int
devm_tegra_core_dev_init_opp_table(struct device *dev,
struct tegra_core_opp_params *params)
{
return -ENODEV;
}
#endif
#endif /* __SOC_TEGRA_COMMON_H__ */
......@@ -52,14 +52,28 @@ struct tegra_sku_info {
enum tegra_revision revision;
};
#ifdef CONFIG_ARCH_TEGRA
extern struct tegra_sku_info tegra_sku_info;
u32 tegra_read_straps(void);
u32 tegra_read_ram_code(void);
int tegra_fuse_readl(unsigned long offset, u32 *value);
#ifdef CONFIG_ARCH_TEGRA
extern struct tegra_sku_info tegra_sku_info;
#else
static struct tegra_sku_info tegra_sku_info __maybe_unused;
static inline u32 tegra_read_straps(void)
{
return 0;
}
static inline u32 tegra_read_ram_code(void)
{
return 0;
}
static inline int tegra_fuse_readl(unsigned long offset, u32 *value)
{
return -ENODEV;
}
#endif
struct device *tegra_soc_device_register(void);
......
......@@ -171,6 +171,8 @@ int tegra_io_rail_power_off(unsigned int id);
void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode);
void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
bool tegra_pmc_core_domain_state_synced(void);
#else
static inline int tegra_powergate_power_on(unsigned int id)
{
......@@ -227,6 +229,11 @@ static inline void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode)
{
}
static inline bool tegra_pmc_core_domain_state_synced(void)
{
return false;
}
#endif /* CONFIG_SOC_TEGRA_PMC */
#if defined(CONFIG_SOC_TEGRA_PMC) && defined(CONFIG_PM_SLEEP)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment